Module 5 · Research case studies
One note, one spend: deniability at the wallet
Because any second spendable identifier on the spend path breaks value safety (Lesson 2), the paper places deniability at the wallet instead. The user derives two economically independent notes — a real note and a smaller decoy note — from independent passphrases and salts, and deposits each as an ordinary single-nullifier deposit. On-chain they are two unrelated deposits; the real-decoy link exists only as a local wallet label. Under coercion the user surrenders the decoy passphrase and spends the decoy note, which holds real funds, while the real note stays untouched. The paper separates the three linkages the protocol rules out from the operational metadata it does not, and is explicit that the guarantee is plausible deniability, bounded by anonymity-set size and metadata — not unconditional unlinkability.
Learning objective
Understand the paper's positive construction — two economically independent single-nullifier notes derived from independent secrets — how it behaves under coercion, exactly which linkages the protocol rules out versus leaves open, and the honest scope of the whole result.
- Track
- Research
- Module
- 5 · Research case studies
- Prerequisites
- Why in-protocol decoys break value safety (case study, part 2) · Public-key cryptography
The placement rule
Lesson 2 established that under spend-identifier accounting, anything on the spend path that yields a second identifier is a value-safety hazard. The construction follows that rule literally: plausible deniability is the wallet's responsibility, while the protocol spend path stays a strict one-note-one-spend boundary. There is no second nullifier inside a note. Instead there are two economically independent notes, each with its own deposit and its own single nullifier; the wallet — not the protocol — knows which one is the decoy. The protocol treats both as ordinary deposits and cannot tell them apart.
Using two notes is not itself the contribution — hidden/decoy wallets are known. The contribution is the placement rule it instantiates: the wallet may manage plausible deniability, but the protocol spend path must remain a one-note-one-spend boundary. That is a design rule for privacy-pool architectures, not a new cryptographic gadget.
Independent derivation
A user wanting to shield a target amount derives a real note for that amount from a real passphrase and a smaller decoy note from a decoy passphrase, then submits two separate ordinary deposits. On-chain these are two unrelated single-nullifier notes; the link between them exists only as a local label in the wallet. Key derivation uses a memory-hard stretch followed by a key-derivation function:
per-role key derivations_role = HKDF( scrypt( passphrase_role, salt_role ) ), role in { real, decoy } For each role: s_role -> note_role -> C_role -> nullifierHash_role (the chain is independent across roles: disjoint salts, no shared seed)
With independent salts, knowledge of one passphrase yields neither the other passphrase nor the other note — a stronger separation than a standard BIP-39 hidden wallet, where the decoy and hidden accounts share a single root seed. The scrypt stretch is memory-hard, so possession of the device alone is insufficient without the passphrase. Crucially, the decoy note holds real funds, not a simulated balance, so a coerced withdrawal is an ordinary, credible transaction that neither reveals nor weakens the real note.
Each note remains single-nullifier, so the one-note-one-spend invariant of Lesson 2 still holds and no double-withdrawal is introduced. Deniability is added without touching value safety — that is the entire point of moving it off the spend path.
Behavior under coercion
Confronted by a physical adversary, the user surrenders the decoy passphrase. The wallet derives s_decoy, locates the decoy note, and performs an ordinary withdrawal: the adversary receives a real, non-trivial amount and observes a valid, unremarkable transaction. The real note is untouched. Because the protocol introduces no on-chain datum relating the two notes, the adversary obtains no protocol-introduced evidence that a second note exists.
This is why the decoy must hold real value: a credible surrender has to look exactly like a genuine withdrawal, which it does precisely because it is one.
Cryptographic vs operational linkage
The paper is careful to separate the linkage the protocol rules out from the linkage it does not. It guarantees three things and explicitly leaves a fourth open:
- 1. No explicit cryptographic linkage
- No on-chain value emitted for one note is a function of the other; the commitments, nullifiers and proofs of the two notes are computed from disjoint inputs. (structural)
- 2. No derivation path between secrets
- With independent passphrases and salts, the decoy secret does not derive the real secret or vice versa; compromising one yields nothing about the other. (structural)
- 3. No shared protocol handle
- The two notes share no commitment, nullifier, root-membership witness, or stored handle that an on-chain observer could use to relate them. (structural)
- 4. Operational correlation may remain (OPEN)
- An observer may still infer a link from metadata — deposit timing, funding source, relayer, amount, or network fingerprint. This is NOT a protocol property; mitigating it is the wallet's responsibility and the residual gap a deployment must manage.
The claim is therefore narrow and exact: absence of protocol-introduced cryptographic linkage, up to anonymity-set size and operational metadata — NOT unconditional unlinkability. Items 1–3 are structural; item 4 is the residual gap. Reading this as "the two notes are unlinkable" would overstate the result.
Evidence as a negative-test matrix (TESTED)
The paper establishes each security property by the case that must fail, labeling the assurance level. Read these as the paper's reported results under its development setup, not as independent benchmarks.
- ▸Three withdrawal-path properties — single-nullifier (double-spend reverts), proof-of-innocence binding (PoI reuse and tampered public input revert), and replay (a pool/chain-swapped proof returns false) — are reported verified at level [V]: on the real on-chain Groth16 verifier under Foundry, where a violating proof must revert or return false.
- ▸Value conservation, selective disclosure, and shielded transfer are reported verified at level [C]: in-circuit, where a violating witness admits no valid proof. The paper states these have verifier contracts but are NOT yet wired on-chain — a weaker claim than the [V] withdrawal-path results.
- ▸A relayer-binding argument (Theorem 2): the relayer address and fee are public inputs to the verifier, so an accepted proof does not verify for a different relayer or fee — a proof is non-transferable, giving front-running resistance.
- ▸[M] mock-verifier results are EXCLUDED from all soundness claims: in the deployed testnet pools the live verifiers are mocks, so an [M] test attests the contract state machine only, never a zero-knowledge property.
Honest scope and limitations
The paper states its own boundaries plainly; this case study preserves them.
- ▸LIMITATION — plausible, not unconditional: the guarantee is plausible deniability bounded by anonymity-set size and operational metadata, not unconditional unlinkability.
- ▸LIMITATION — degradation conditions: deniability degrades if the adversary compels all passphrases, inspects the full device derivation state, correlates the two deposits via metadata, or controls the funding source. Avoiding the last two is a wallet requirement, not a protocol property.
- ▸LIMITATION — trusted setup: Theorem 1 is conditional on a deployed verifier that uses a development powers-of-tau; a production guarantee additionally requires a multi-party Phase-2 ceremony with a published transcript.
- ▸LIMITATION — deployment status: the [V] results hold against the real verifier under Foundry, but the current testnet pools use mock verifiers and predate the corrected circuits, so reaching a live pool is a redeployment step. The current testnet set does not provide a meaningful anonymity set.
- ▸OPEN — empirical anonymity: the paper reports no classifier-based indistinguishability experiment; the relevant metric is anonymity-set size on a populated deployment, which the testnet does not yet provide.
- ▸INDICATIVE only — performance: the paper reports component-level estimates (e.g., proof generation around one-and-a-half to two seconds, on the order of 10^5 gas for a single-nullifier withdrawal) but EXPLICITLY disclaims them as not from a benchmark harness and "not used to support any security or performance contribution." It does report circuit sizes (a partial-withdrawal circuit of ~13,600 constraints and a selective-disclosure circuit of ~22,500 constraints) as engineering context, not as results.
- ▸Production prerequisites named by the paper: wire the remaining facets to real verifiers, run a multi-party trusted-setup ceremony, publish the anonymity-set size, and pass an independent professional audit before mainnet.
Takeaway: the paper's real contribution is a placement rule backed by a value-safety argument — coercion deniability must not be bought by breaking value safety, so it belongs off the spend path, at the wallet. The construction is a correct instantiation of that rule under stated, limited assumptions, not a finished, audited production system.
Exercise
The wallet-layer construction gives a coerced user a credible decoy to surrender. List two reasons the decoy note must hold real funds rather than a simulated balance, and name one linkage the protocol does NOT rule out.
Expected direction: The decoy must hold real funds because (1) the withdrawal must be an ordinary, credible transaction that the adversary can actually execute and observe as valid, and (2) a simulated or empty balance would fail or look anomalous on-chain, revealing it as a decoy and defeating deniability. A linkage the protocol does not rule out is operational/metadata correlation — deposit timing, funding source, relayer, amount, or network fingerprint — which is the wallet's responsibility to manage, not a protocol guarantee.
Check your understanding
- Why does the construction use two separate notes instead of a decoy path inside the circuit?
- Because any second spendable identifier on the spend path reintroduces the k ≥ 2 double-withdrawal of Proposition 1 and breaks value safety. Two independent single-nullifier notes keep one note, one spend intact while placing deniability at the wallet.
- How is this stronger than a BIP-39 hidden wallet, and where does it stop being stronger?
- The two notes are derived from independent passphrases and salts with no shared seed, so one passphrase yields nothing about the other note — unlike BIP-39, where decoy and hidden accounts share one root seed. It stops at operational metadata, which the protocol does not hide.
- What does the distinction between [V], [C] and [M] mean for how much is actually established?
- [V] is the strongest: verified on the real on-chain Groth16 verifier (the three withdrawal-path properties). [C] is in-circuit only, with contracts not yet wired on-chain (value conservation, selective disclosure, shielded transfer). [M] mock results are excluded from soundness claims entirely, as they attest only the contract state machine.
- Should the reported proof-time and gas figures be read as benchmarks?
- No. The paper explicitly labels them indicative component-level estimates, not from a benchmark harness, and states they are not used to support any security or performance contribution.
References
- [1]J. Groth — On the Size of Pairing-Based Non-Interactive Arguments (Groth16), EUROCRYPT 2016
- [2]RFC 5869 — HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
- [3]RFC 7914 — The scrypt Password-Based Key Derivation Function
- [4]BIP-39 — Mnemonic code for generating deterministic keys
- [5]EIP-5564 — Stealth Addresses
References point to public, well-known technical sources for further study.
Related articles
