Consume a Mina nullifier once per election

A valid nullifier proves a relation to a message, while a spent-nullifier map records prior use. Both checks are required for a one-vote rule.

Choose the election message

Define one canonical field encoding for the election domain and identifier. Every voter in election 17 should use that same election context when producing a nullifier. If the message includes a freely chosen random nonce, the same participant can derive additional nullifiers by changing the nonce. Validate voter eligibility separately under the application's rules.

nullifier.verify(electionMessage);
nullifier.assertUnused(witness, currentRoot);
const nextRoot = nullifier.setUsed(witness);

Persist the spent mark

Bind currentRoot to the on-chain spent map, verify the nullifier and assert its key is unused at that root. Persist nextRoot together with the vote effect. Replaying the same authorization against the new root should fail. Without the state transition a valid proof could be submitted repeatedly.

Sources