nullifiers leave the client: spent checks look up UsedNullifiers by key #68
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent: #9
The leak (shipped in 0.1.0 and 0.2.0)
wormhole_summary(crates/wallet-app/src/commands.rs) computes the nullifier of every unspent leaf that pays the wallet's wormhole address and asks the node about each one withsubstrate::wormhole::nullifier_spent, aWormhole::UsedNullifierslookup by key. That map isBlake2_128Concat, so the key isblake2_128(n) ‖ n: the request hands the node the nullifier itself. Exits publish their nullifiers on chain, so whoever runs the node can later match an exit to the connection that asked about it, and that connection also asked for the balances of the wallet's transparent accounts. The accounts page runs this automatically for every open wallet that carries a phrase, as soon as the chain connects, so any 0.2.0 install that opened mainnet has sent its unspent nullifiers towss://quantus.blackbeard.observer(bob), and on Planck through the proxy to Quantus's nodes.quantus/extension hit the same thing and fixed it (
packages/extension-base/src/background/Wormhole.ts,NULLIFIER_BUCKETS_MIN): read whole buckets of the map by the first byte ofblake2_128(n)withstate_getKeysPaged, pad the set of buckets with random ones to at least 16, ask in shuffled order, and check membership locally. The node learns which buckets were read, never which entry mattered; one deposit hides among a sixteenth of all spends.The rest of the shielded read is already clean:
leaves_payingreadsZkTree::Leavesby index across the whole range, so the node never learns which leaves are the wallet's, and no observer is asked about wormhole addresses.Scope
nullifier_spentwith a bucket read ofWormhole::UsedNullifiers(the extension's rule: at least 16 buckets, random padding, shuffled), membership checked in Rust.doc/threat-model.mdunder the wormhole: nullifiers, secrets and the leaf indices being spent never leave the client.Acceptance
On mainnet, the spent check for a wallet with leaves sends only
state_getKeysPagedrequests on bucket prefixes (logged request list in the test), the shielded balance is unchanged from 0.2.0's answer, and the leak test above passes.