Skip to content

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

Closed
midexol wants to merge 1 commit into
mainfrom
fix/issue-254-nullifier-archival
Closed

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

Conversation

@midexol

@midexol midexol commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Summary

Resolves crackedstudio#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 commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

Closing PR created in fork repo; official PR opened upstream at crackedstudio#360

@midexol midexol closed this Aug 31, 2026
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