aztec-nr - noir_aztec::state_vars::single_use_claim

Struct SingleUseClaim

pub struct SingleUseClaim<Context>
{ /* private fields */ }

A private state variable type that represents a right each user can exercise at most once.

Because it is owned, you must wrap a SingleUseClaim inside an crate::state_vars::owned::Owned state variable when using it in storage.

Example

The right to vote at most once can be implemented using SingleUseClaim as a primitive.

#[derive(Serialize, Deserialize)]
struct ElectionId { id: Field }

#[storage]
struct Storage<Context> {
    // election => candidate => number of votes
    tally: Map<ElectionId, Map<Field, PublicMutable<Field, Context>, Context>, Context>,
    // track right to vote at most once per election
    vote_claims: Map<ElectionId, Owned<SingleUseClaim<Context>, Context>, Context>,
}

#[external("private")]
fn cast_vote(election_id: ElectionId, candidate: Field) {
    let voter = self.msg_sender().unwrap();

    // `claim` will only succeed if `voter` hasn't already claimed for this `election_id` before.
    self.storage.vote_claims.at(election_id).at(voter).claim();

    // Now that we checked that the voter is entitled to vote,
    // we can enqueue the corresponding public effect
    self.enqueue_self.add_to_tally_public(election_id, candidate);
}

For more details on what owned means, see the documentation for the OwnedStateVariable trait.

Cost

Exercising a claim (via the SingleUseClaim::claim function) emits one nullifier.

Privacy considerations

The SingleUseClaim::claim function emits a public nullifier per owner: it's fully private, hidden behind the owner's app-siloed nullifier secret key (aka nsk).

Public effects you emit alongside a claim (e.g. a public function call to update a tally) may still let observers infer who likely exercised the claim, so consider that when designing flows.

Implementations

impl SingleUseClaim<UtilityContext>

pub unconstrained fn has_claimed(self) -> bool

Returns whether an owner has claimed this single use claim.

impl<Context> SingleUseClaim<Context>

impl SingleUseClaim<&mut PrivateContext>

pub fn claim(self)

Records the fact that the owner in scope has claimed this single use claim.

This function succeeds at most once for a given owner. Any subsequent calls with same owner are guaranteed to fail.

Note that, by itself, calling this function doesn't do anything other than prevent it being called again with the same owner. Its invocation is typically accompanied by other contract actions, e.g. minting tokens, casting a vote, etc.

Advanced

The implementation of this function emits a nullifier derived from the owner's nullifier secret key and the storage slot of the underlying state variable.

pub fn assert_claimed(self)

Asserts that the owner has already claimed this single use claim (i.e. that SingleUseClaim::claim has been called).

Advanced

This function generates a kernel nullifier read request, so it can even assert the existence of pending claims, i.e. when SingleUseClaim::claim was called in the same transaction as SingleUseClaim::assert_claimed.

Trait implementations

impl<Context> OwnedStateVariable<Context> for SingleUseClaim<Context>

pub fn new(context: Context, storage_slot: Field, owner: AztecAddress) -> Self