Skip to content

fix(contracts): embed nullifiers vector in Circle state to prevent archival replays (#254) - #360

Open
midexol wants to merge 1 commit into
crackedstudio:mainfrom
midexol:fix/issue-254-nullifier-archival
Open

fix(contracts): embed nullifiers vector in Circle state to prevent archival replays (#254)#360
midexol wants to merge 1 commit into
crackedstudio:mainfrom
midexol:fix/issue-254-nullifier-archival

Conversation

@midexol

@midexol midexol commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Resolves #254

Previously, the contract stored nullifiers as standalone persistent storage entries (\DataKey::Nullifier(circle_id, nullifier_hash)). While \Circle\ persistent entries are re-extended on every \ und\ or \claim, write-once nullifier entries were only extended once at creation time (\LEDGER_EXTEND_TO = 500_000\ ledgers). Once archived, \env.storage().persistent().has(&nullifier_key)\ would return \ alse, opening a security vulnerability where a claim could be replayed after TTL expiry.

Solution

  1. Embedded Nullifiers Vector: Added \pub nullifiers: Vec\ to \pub struct Circle. Storing nullifiers inside the \Circle\ persistent entry ensures nullifiers share the circle's continuously-extended TTL lifecycle and cannot be archived independently while the circle is active.
  2. ADR 004: Created \docs/adr/004-storage-archival.md\ analyzing the trade-offs of storage archival options and documenting the decision to embed a bounded \Vec\ in \Circle.
  3. Tests & Threat Model: Added
    ullifier_fence_survives_ttl_expiry\ test in \contracts/sharibo/src/test.rs\ to verify the fence after ledger advancement, and updated \docs/threat-model.md.

@midexol
midexol force-pushed the fix/issue-254-nullifier-archival branch from 57f12a2 to 14dce73 Compare September 1, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nullifier entries can be archived — a claim could be replayed after TTL expiry

1 participant