- Claims. One claim per wallet in an airdrop, grant round or vote.
- Distinct payers. A donation round counts wallets, so one donor splitting a gift into ten payments is one donor.
The tag
A tag isPoseidon(nk, domain), where nk is the note’s nullifier deriving key and domain is
the round’s name. In the circuit the same nk cell feeds both the address check
(ivk = CommitIvk(ak, nk, rivk)) and the tag hash. So:
- Every claim one key makes in one domain carries one tag, whatever note it uses. Every
address and both scopes of an account share
nk. - Finding a second tag for a key would need a
CommitIvkcollision. - Tags in different domains are unrelated values, as Poseidon keyed by
nkis a PRF. - A claim and a payer tag hash the domain under different personalizations, so a key’s tag in “drop” as a claim and as a payer tag don’t match. (They once did: a round named after someone else’s airdrop could have matched donors to claimants.)
Claim tags
Shows a note of at leastfloor was held in the tree at a snapshot block, and carries the tag.
--min
(the API takes min_floor_zatoshis). Without it a note of one zatoshi would prove “at least 1”
and verify.
Against a chain snapshot the claim reveals the note’s nullifier, and the verifier checks it was
not published up to the snapshot block. The tree keeps spent notes, so without that check a balance
could claim from each key it moved through.
Two claims from one wallet in one domain carry the same tag, which is how the second is caught.
The regtest end-to-end run does exactly this, and checks a claim is refused for another domain
or another snapshot block.
Payer tags
A payer tag is the same proof on a note a payment spent: its nullifier is one of the payment’s, its anchor is the payment’s.Combining with income
Proof of income accepts payer tags: a lender can require that a total came from at least k different wallets.--siblings @sib.txt and the two count as one wallet.
Limits
- Tags count wallets at most, never at least. A person with two accounts of one wallet gets two tags, and a sibling-account proof merges them only if the payer chooses to show it: you can’t make anyone show one. Nothing at all catches independent wallets.
- Claims against a published list (not a chain snapshot) use a second key mode where the nullifier stays private, since there is no chain to check it against.
crates/zceipt-core/src/claim.rs, circuit in vendor/orchard/src/circuit/claim.rs.
Tests: roundtrip.rs::claims_are_one_per_key_per_domain, ::payer_tags_tell_wallets_apart.