Secure Turnstile: Application State Migration Pattern | Cardinal Cryptography

Summary

This proposal presents a reusable pattern for application-level state migration during Aztec rollup upgrades. Users migrate private state (token balances, NFT ownership, identity attestations) to new rollup instances without per-user L1 transactions.

The mechanism uses Aztec’s existing infrastructure: archive roots published to L1 become the trust anchor for proving historic state on the new rollup. For identity binding, users prove ownership via knowledge of the master nullifier secret key (nskm), which persists across rollup instances.

Prototype scope: Token migration via both Mode A (routine upgrade) and Mode B (emergency). Mode B is scoped to native (non-bridged) assets; researching and specifying a solution for L1-collateralized assets is part of the work, though some trade-offs are expected.

About Us

About Us We’re the team behind Blanksquare, bringing privacy to EVM via shielded pools and zk-SNARKs. Previously, we were core maintainers of Aleph Zero, a Substrate-based L1.

Relevant experience:

  • ZK Engineering: Production Halo2 circuits, browser/mobile provers.

  • Aztec/Noir: 6 weeks hands-on experience (rewriting our shielded pool circuits from Halo2 to Noir for testing).

  • Research: Published papers on private order books, threshold ECDSA, and compliance (e.g. https://eprint.iacr.org/2023/1868, https://eprint.iacr.org/2020/498).

Grant Execution Team

  • Damian Straszak: PhD Computer Science; Cryptography & Development

  • Adam Gągol: PhD Mathematics; Cryptography & Development

  • Jan Kuczma: Core Developer; Noir, Solidity

Architecture Overview

Applications implement two contracts:

  1. Lock Contract (old rollup): Nullifies user notes, creates MigrationLockNote

  2. Claim Contract (new rollup): Verifies proofs against synced archive root, validates ownership, mints equivalent notes

The L1 portal relays archive roots to the new rollup via Inbox messaging. The L2 root registry stores trusted roots and enforces the turnstile in emergency mode.

Note: Archive root relay between rollup instances is not currently standard Aztec infrastructure. This proposal includes deploying an L1 portal contract that reads archive roots from the old rollup contract and relays them to the new rollup’s Inbox.

Migration Modes

Critical design principle: Mode A and Mode B are mutually exclusive. For any given migration, governance activates exactly one mode based on whether the old rollup’s prover is trusted.

  • Mode A (Routine): Old prover is trusted. Users lock notes on old rollup, then claim on new rollup.

  • Mode B (Emergency): Old prover cannot be trusted. Users prove note validity at a safe snapshot height H; no pre-locking required. Mode A is disabled to prevent migration of potentially corrupted state.

Why mutual exclusivity matters: If a bug is discovered, any state created via the compromised prover is suspect. Allowing Mode A claims during an emergency would let attackers migrate notes created through the exploit.

Identity Binding

Proving “I own this note” to the new rollup requires a mechanism independent of the old rollup’s execution proofs. If the old prover has bugs, we can’t trust those proofs.

Users prove ownership by demonstrating knowledge of nskm (master nullifier secret key) that derives to the note’s npkm(master nullifier public key). Since nskm is derived from user-controlled seeds independent of any rollup, it persists across rollup instances even as addresses differ.

The MigrationLockNote stores the npkm in its owner field. At claim time, the user proves knowledge of the corresponding nskm.

Mode A: Routine Migration

Locking (Old Rollup)

User calls lock_for_migration(note, destination_rollup_id):

  1. Verify ownership, emit nullifier for original note

  2. Create MigrationLockNote:

MigrationLockNote {
    owner: Field,                      // npkm
    original_note_hash: Field,         // poseidon2(original_note.serialize())
    destination_rollup: Field,
    lock_block: Field,
}


The lock note is application-agnostic—it stores only the hash of the original note. Application-specific data (amount, asset_id) is provided as witness during claim and verified against original_note_hash.

Claiming (New Rollup)

User submits a claim transaction with:

  1. Original note: Witness data, verified against original_note_hash

  2. Archive proof: Merkle path showing block header in synced archive root

  3. Note proof: Merkle path showing lock note in that block’s note hash tree

  4. Ownership proof: Proof of nskm knowledge

The claim contract:

  1. Checks migration mode is A (reverts if emergency mode active)

  2. Verifies Merkle proofs against synced archive root

  3. Verifies poseidon2(original_note.serialize()) == lock_note.original_note_hash

  4. Verifies ownership proof

  5. Checks lock_note.destination_rollup == CURRENT_ROLLUP_ID

  6. Emits nullifier poseidon2(MIGRATION_DOMAIN, original_note_hash, owner)

  7. Mints equivalent note


Mode B: Emergency Migration

When the old prover cannot be trusted, governance activates emergency mode by setting SAFE_SNAPSHOT_HEIGHT = Hand disabling Mode A. Users migrate by proving their original note was valid at H—no pre-locking required.

Scope: Mode B applies to native (non-bridged) assets. Handling L1-collateralized assets in emergency mode requires additional L1-side coordination; researching and specifying this solution is part of the deliverables.

Claiming (New Rollup)

User proves:

  1. Original note was included in note hash tree at block ≤ H

  2. Original note was not nullified at block H (IMT non-membership proof)

  3. Valid ownership proof (nskm knowledge)

Aztec provides history proof primitives (prove_note_inclusion, prove_note_not_nullified, etc.) for proving against anchor blocks. Our implementation adapts these for cross-rollup verification against a governance-specified snapshot height H, which requires archive nodes to maintain nullifier tree state at that height.

The claim contract verifies these proofs against the archive root at H and mints equivalent notes.

Why pre-locked notes are rejected: During emergency mode, even lock notes created before the bug was discovered are suspect—the lock note itself may encode inflated amounts or invalid ownership. Users who locked notes can still migrate by proving their original note was valid at H; the lock note is ignored.

Nullifier Consistency

Both modes emit the same nullifier: poseidon2(MIGRATION_DOMAIN, original_note_hash, owner). This prevents double-claims across mode transitions (in a very unlikely scenario that they ever happen).

Archive Root Synchronization

The L1 portal contract reads archive roots from the old rollup contract and relays them to the new rollup’s Inbox. Anyone can call this relay function, making root syncing permissionless in routine mode.

The L2 registry contract stores roots as trusted anchors. In emergency mode, the registry only accepts roots at or before the safe snapshot height. Governance activates emergency mode by calling a restricted function that sets the snapshot height and switches the migration mode.

Threat Model

Threat Mitigation
Attacker inflation via prover bug Mode B: prove note validity at pre-bug snapshot height
Cross-rollup replay destination_rollup field verified at claim
Claim front-running Ownership proof binds to recipient address

Accepted risks: User error on destination selection (no unlock mechanism); nskm theft (standard key-security model); exploits before snapshot height (inherent to any turnstile).


Milestones

All milestones below reflect the full Tier 1 scope.

Milestone Date Deliverables
M1: Specification & Setup Feb 3, 2026 Type definitions, migration mode enum, Aztec version pinning, dev environment, skeleton contracts
M2: Lock Contract & L1 Infrastructure Feb 12, 2026 Lock contract on old rollup, L1 portal with Inbox relay, L2 root registry with mode enforcement
M3: Mode A Claim Feb 20, 2026 Claim contract with archive + note proof verification, ownership validation, end-to-end Mode A flow with batching support
M4: Mode B Claim Feb 27, 2026 Mode B claim circuits adapting Aztec’s history proof primitives for cross-rollup verification, Mode B claim path for native assets, bridged asset handling specification
M5: Integration & Documentation Mar 6, 2026 Cross-chain integration tests, example token contract with migration hooks, gas and proving time benchmarks, user documentation, deployment guide

Funding Request

We offer two tiers depending on grant pool allocation.

Tier 1: Secure Turnstile: $30,000

The complete architecture with both migration modes and production-ready L1 integration.

Deliverables:

  • Full Mode A (Lock & Claim) implementation with batching

  • Full Mode B (Emergency) implementation adapting Aztec’s history proof primitives for cross-rollup verification

  • Bridged asset handling specification for Mode B

  • L1 portal and Inbox relay contracts

  • L2 root registry with governance-controlled mode switching

  • Example token contract with migration hooks

  • Gas and proving time benchmarks

  • End-to-end cross-chain integration tests

  • Technical documentation and user guides

Tier 2: Migration Foundation: $20,000

Production-ready routine migration path with emergency mode deferred.

Deliverables:

  • Full Mode A (Lock & Claim) implementation with batching

  • L1 portal and Inbox relay contracts

  • L2 root registry with mode enforcement

  • Mode B design specification (implementation deferred)

  • Integration tests for Mode A flow

  • Documentation

Trade-off: Mode B is fully specified but not implemented. However, even in the event of a proof system bug, Mode B can be implemented post-factum with no harm to migration safety.