This section states the protocol by which a wallet reconstructs its notes from the chain. It fixes the chain state and the account birthday that bound the scan, the keys an account is scanned with under the rules of ZIP 326, the note state of a wallet and the scan of one compact block that updates it, the continuity predicate and the conditions under which a scan in any order is correct, the theorems of sound and complete discovery and of recovery from the seed, and the work that scanning costs. The tree information a wallet retains for its witnesses is the subject of “Commitment-tree synchronisation” (§7).
Throughout, ranges over the shielded pools , and ; is the Sapling activation height, and the NU6.3 activation height of ZIP 258. For a compact block , and are the commitment count and the end size of Definition 4.11.
For a height , the chain state at is
where is the -byte hash of block ; is the number of leaves of the note commitment tree of pool in the final treestate of block ; and is the frontier of that tree (Crypto Guide, §“Append-only and incrementally updatable trees”, Definition “Frontier”): for each set bit of , the root of the completed left subtree of height on the rightmost filled path. The empty tree has and the empty frontier, and the full tree, , has its root as frontier. The three trees are distinct trees of depth (; protocol specification, §“Constants” and §“Note Commitment Trees”): the Sapling tree of the specification, and the Orchard-pool and Ironwood-pool trees, each built with the Orchard Merkle hash (Ironwood Guide, §“The Merkle hash and the tree”, Definition “Note commitment tree”). The chain state is the response of (Table 4).
By the Crypto Guide’s Definition “Frontier” (§“Append-only and incrementally updatable trees”), the pair determines the root of the tree of after block and suffices to append every later leaf without any leaf appended before block . That it also yields every later authentication path is shown in “Frontiers as scan seeds” (§7.3).
The birthday of an account is a height , known to the wallet, that is a lower bound on the height of the first block in which the account could have received funds (ZIP 326, “Terminology”). With the birthday the wallet stores the chain state , which summarises every note commitment of every pool before . The scan of the account starts at block , and no block below is scanned for it. The birthday of a wallet is the minimum of the birthdays of its accounts.
Added accounts. Let an account with birthday be added while the greatest height of a block the wallet has scanned exceeds . Every block of is then scanned again with the scanning keys of the new account (§6.2), since earlier scans did not try them; the results of the other accounts are unchanged.
No recorded birthday. A wallet that restores a seed without a recorded birthday takes : no shielded address of a light client can have received a relevant transaction before Sapling activation (ZIP 307, “Client-server interaction”, “Importing a pre-existing seed”). The bound concerns shielded receipts only; the transparent history of the account’s addresses may lie below it.
Let the tip be at height when an account is created, and let be at least the wallet’s assumed maximum reorganisation depth. The birthday of the new account is taken as , with stored chain state at height or below. A reorganisation that replaces at most blocks re-mines no transaction below height ; with closer to the tip, such a reorganisation could re-mine a transaction paying the account at a height below , which the wallet never scans, and the payment would be missed. Consensus imposes no maximum reorganisation depth (Consensus Guide, §“Reorg rails, maturity, and the finality floor”), so is a wallet parameter, not a guarantee. The rollback window of blocks that ZIP 218, “Block-count-based constants”, recommends concerns nodes and bounds no wallet’s choice of . An earlier birthday is always safe for discovery and costs scanning work (§6.5).
Let an account have Sapling keys and Orchard-protocol keys derived as in “Hierarchical key derivation (ZIP 32)” (§2), the latter with the flag of Construction 2.10. Scopes are .
Sapling. For each scope , the pair of incoming viewing key and nullifier deriving key (ZIP 32, “Sapling internal key derivation”). Sapling outputs are scanned from .
A receiver and its are scoped to the Orchard protocol, not to a pool: the same trial-decrypts Orchard-pool and Ironwood-pool note ciphertexts (ZIP 326, “Scanning for Ironwood-pool and Orchard-pool notes”); the pool of an Action is that of the bundle that carries it, and Definition 4.9 admits lead byte in the Orchard pool and in the Ironwood pool. The use_qsk set is when the wallet knows the account’s value and when it does not.
The following rules of ZIP 326, with their normative levels, fix which is tried on which output.
Restoration. A wallet restoring from a seed MUST take and scan with both values until rule (R2) narrows it, because is not part of the recovery information (“Scanning when restoring from seed”).
Narrowing. Once the wallet sees funds received in either Orchard-protocol pool under a value , it SHOULD stop scanning with the other value, . The evidence stands if the transaction that provided it is later reorganised away, since it was valid on some chain (“Scan ranges”).
Ironwood pool. The Ironwood pool is scanned from to the tip with for , hence with up to four keys () while is unknown, subject to rule (R4). The value is kept for an account whose birthday precedes NU6.3 activation, since a recorded birthday may be conservatively early (“Scan ranges”).
First funds. ZIP 326 describes this rule as an optimisation and does not require it (“First-funds scanning in the Ironwood pool”). While the wallet knows that the account has received no Ironwood-pool funds in any block below the one scanned, only the external keys are needed for an output, except in a transaction whose is negative, where both scopes are used. The knowledge is kept only for the contiguous prefix of heights from scanned without a receipt, and a reorganisation whose last unchanged block is at height cuts the prefix back to . A compact transaction carries no value balance (Definition 4.3), so a scan of compact blocks applies the exception only where it obtains otherwise; without it, both scopes are used.
Orchard pool (“Scan ranges”). Orchard-pool note ciphertexts SHOULD NOT be scanned with keys. For an account with birthday after NU6.3 activation they SHOULD NOT be scanned at all. For an account with birthday before NU6.3 activation they SHOULD NOT be scanned with the external key after NU6.3 activation. If the account’s Orchard-pool balance is known to be zero at a block at or after NU6.3 activation, they SHOULD NOT be scanned in any block that descends from it.
Order. A wallet MAY scan blocks in any order (“First-funds scanning in the Ironwood pool”).
Outgoing notes. Outgoing notes are detected with the of the same value, which adds no key dimension (“Outgoing-note detection”).
Under (R5) the Orchard pool is scanned with only: with from until the Orchard-pool balance is known to be zero after NU6.3 activation, and with from to . The scanning keys of account for pool , block and transaction are the triples that items (i) and (ii) and rules (R1) to (R5) select. Every is labelled , which attributes each accepted note to its account and scope.
Transparent receipts are detected at the transparent addresses the wallet watches, which MUST include index of each account (“Deriving unified addresses”, §3.6; ZIP 316, “Deriving a Unified Address from a UIVK”). The Ironwood pool is scanned as a pool of its own: its outputs are accepted under its lead byte, its revealed nullifiers are matched only against nullifiers of Ironwood-pool notes, and its tree is its own (Ironwood Guide, §“Nullifier sets”, Remark “Pool locality”).
Rules (R2), (R4) and (R5) omit a key only where the restrictions of ZIP 326, “Wallet key-generation restrictions”, exclude an output of the account under it. Every key of an account has one value (MUST). No wallet sends Orchard-pool funds to keys, or to any external receiver after NU6.3 activation (MUST NOT). Internal receivers are exposed to no party outside the wallet (ZIP 326, “Scanning for Ironwood-pool and Orchard-pool notes”), so before the account’s first Ironwood-pool funds a note at its internal Ironwood receiver arises only from the account’s own transaction, funded by a negative (“First-funds scanning in the Ironwood pool”). No value enters the Orchard pool after NU6.3 activation, so a zero Orchard-pool balance stays zero (“Scan ranges”). An output created in violation of these restrictions by a non-conformant sender may be missed; this is the cost of the SHOULD NOT rules, and it is part of the statement of Theorem 6.14.
The nullifier of an Orchard-protocol note is (Ironwood Guide, §“The nullifier”, Definition “Nullifier”), and that of a Sapling note is with , a function of the nullifier deriving key and of the note’s position (protocol specification, §“Computing values and Nullifiers”).
Let an Orchard-protocol account key have . No efficient algorithm that receives the incoming viewing key of one scope and , but not , and is then given notes of its choice with pairwise distinct outputs the nullifier of one of them, except with negligible probability.
Assume that , keyed by of a Sapling key generated as the specification prescribes, is pseudorandom to an efficient algorithm that holds the incoming viewing key and the spend validating key of that key: the specification’s requirement that be a pseudorandom function (§“Pseudo Random Functions”), applied to this key distribution. Then the statement of (a) holds for the Sapling key.
A holder of therefore detects receipts, since trial decryption needs only (Construction 4.8), and cannot recognise a revealed nullifier as that of its note. A wallet that holds only incoming viewing keys has an empty tracked-nullifier set, and the set of notes it considers unspent is a superset of the true set. Links through other public data are outside the statement (Ironwood Guide, §“Nullifier uniqueness and unlinkability”, Remark “Limits”). For no claim is made (Remark 2.11).
(a) Let be an algorithm that outputs the nullifier of a submitted note with probability . It yields a distinguisher for the Ironwood Guide’s Proposition “Nullifier unlinkability” (§“Nullifier uniqueness and unlinkability”): the distinguisher runs on its inputs and , submits the notes is given, and outputs exactly when an answer equals the value outputs for that note. In the real game it outputs with probability at least . In the ideal game each answer is of a point uniform on , independent of the notes, except with probability ; it equals a given value with probability at most , since is at most two-to-one. Hence is bounded by the advantage bound of that proposition plus a negligible term, under the assumptions it names. For the internal scope the proof of that proposition applies with its hybrid changed: the pair is replaced by by Assumption 2.16, whose reduction, like that of , draws and itself and passes on the fourth and fifth components of its tuple. The cost is the advantage against that assumption in place of the term for the Ironwood Guide’s Assumption “Joint hiding of the viewing keys” (§“Viewing keys”), and the later hybrids are unchanged, since the game after the hop is that of . That proposition concerns a key generated from a uniform spending key; for an account key the bound holds up to the loss of Lemma 2.9. (b) An algorithm that outputs for a submitted not queried before distinguishes the function from a random function, which outputs that value with probability , contradicting the assumption. □
The note state of a wallet consists of:
per account and pool , the set of detected notes, each with its value, scope, position (Definition 4.11), creating transaction, its nullifier when derivable, its memo once fetched, and a spent mark: either or the triple (height, index in block, ) of the transaction that revealed its nullifier;
per pool , the tracked set of the nullifiers of detected notes of not marked spent, and the set of retained unlinked nullifiers, each with its revealing transaction;
for each wallet-relevant transaction, its mined height, or if it is unmined;
the chain state (Definition 6.1) of the last block of each maximal interval of scanned heights; for a scan in increasing height, that of the last scanned block.
A transaction is wallet-relevant if and only if it creates a detected note or reveals the nullifier of one. A light wallet stores no copy of the chain; its note state is reconstructed from compact blocks (Definition 4.2) and fetched full transactions alone, supplied by a server that the wallet does not trust for privacy (Assumption 5.2, clause (b)). The information retained for witnesses is adjoined in “The information a wallet retains” (§7.4).
Let be a compact block that continues the wallet’s chain, in the sense fixed in “Scan order” (§6.4), scanned for a set of accounts. For each pool , in block, transaction and description order, the start size of in (Lemma 4.12) and Definition 4.11 give each compact output or Action its position.
Receipts. For each compact Sapling output (for ) and each compact Action of (for an Orchard-protocol pool), in transaction , and each account , run Construction 4.8 and Definition 4.9 under every (Definition 6.4). Record an accepted note with its value, scope , position and transaction. When is held, compute its nullifier (for Sapling from its position), and: if , mark the note spent at the retained transaction and remove from ; otherwise add to .
Spends. For each nullifier revealed in by (each compact Sapling spend, and the of each compact Action of ): if it lies in , mark the matching note spent at and remove the nullifier from ; otherwise retain it in with its revealing transaction.
Chain state. Compute from the stored and : the hash of , and for each pool the size and the frontier obtained by appending the commitments of in , in order, to . It replaces in the note state.
Step 1 precedes step 2, so a receipt and its spend in one block, or in one range scanned in increasing height, are both found in one pass. A nullifier is compared only with nullifiers of its own pool (Ironwood Guide, §“Nullifier sets”). The retention period of is fixed by Lemma 6.12 (§6.4).
Enhancement. For each wallet-relevant transaction the wallet may fetch the full transaction by (phase C of ZIP 307, “Client-server interaction”), which yields the memo, by decryption of the full , and the outgoing plaintexts recoverable under the account’s , at the privacy cost stated in “Leakage of transaction queries” (§8.4).
Class (Definition 1.1). Trial decryption, nullifier matching in increasing height and enhancement are specified (ZIP 307, “Local processing”, “Detecting spends” and “Client-server interaction”); the scanning keys are those of ZIP 326. The retained set and the chain state of step 3 are designed but unspecified.
ZIP 307, “Client-server interaction”, divides the interaction between client and server into four phases.
First start. The client obtains the tip height and the commitment tree state at , or sets ; the ZIP leaves the choice open. For an imported seed (“Importing a pre-existing seed”).
First update. The client obtains the tip and the compact blocks . It checks that the hash of block equals its stored copy, a mismatch meaning that was orphaned by a reorganisation, and discards block without further processing. For each later block it validates the header if one is present, trial-decrypts for its notes, creates and updates witnesses of detected notes, and scans for their nullifiers.
Transactions. At user direction, the client fetches full transactions.
Later updates. The client obtains the tip and the blocks , rechecks block as in (B), updates witnesses, marks the notes whose nullifiers appear as spent at that height, and scans for new notes as in (B).
In the queries of Table 4 the phases use , or , and .
Scanning a range requires the chain state : its hash for the continuity check of block , and each pool’s size and frontier for positions and authentication paths. The wallet holds it after scanning block , or obtains it by ; a server-supplied frontier is accepted under clause (a) of Assumption 5.2 and is checked against no header (Proposition 5.3).
Let the wallet hold the chain state . A compact block continues the wallet’s chain at if and only if
;
; and
for every pool , the start size of in , (Lemma 4.12), equals .
Within a range each block is checked against the chain state computed from its predecessor, and the first block against the stored chain state. When a range is scanned directly below an already scanned block , that block is checked again against the chain state that the new range computes. This extends ZIP 307’s single hash comparison at the start of each phase to every block and to both sides of every range boundary.
Rule (verify first). The scan results of a block are applied to the note state only after the block is checked to continue the wallet’s chain, and the results of a range only after each of its blocks is. Failure of the predicate is a continuity error, handled by rollback (“Reorganisation detection and recovery”, §7.6). A malformed or insufficient field is an error of the response, not a continuity error (“Architecture and authority”, §5.1). The predicate beyond ZIP 307’s comparison is designed but unspecified (Definition 1.1).
For a wallet with birthday , the maximum scanned height is the greatest height of a scanned block, and the fully scanned height is the greatest such that every block of has been scanned. Under out-of-order scanning may lie below the maximum scanned height.
Fix a chain. Let a note of an account in pool be created at height and its nullifier revealed at height , and let the wallet hold the note’s nullifier deriving key. If each nullifier retained in (Construction 6.8) that was revealed at height is kept until the fully scanned height is at least , the note is marked spent at the revealing transaction whichever of the blocks and is scanned first. The retention bound is the least that guarantees this: if a nullifier revealed at is discarded while , some block below is unscanned, and a note of the account created there and spent at is never marked spent.
If block is scanned no later than block , the note’s nullifier is in when block is scanned (steps 1 and 2 of Construction 6.8, in that order when ), and it is matched on arrival. Otherwise block is scanned first; the nullifier matches no tracked note and is retained in . Since (Definition 6.2), reaches only after block is scanned, so the nullifier is still in when step 1 finds the note, and the note is marked spent. Minimality: block has been scanned, since it revealed the nullifier, so means that some is unscanned; a note created at and spent at has then lost the only record of its spend. □
Fix a chain and a range . Let a schedule scan every block of once, in any order and in ranges of any lengths, each block with key sets , and let
the results of each range be applied only after continuity is verified (Definition 6.10), and
unlinked nullifiers be retained as Lemma 6.12 requires.
Then the resulting notes, positions, nullifiers and spent marks equal those of a scan of in increasing height that applies to each block the same key sets, and the chain state held for height is . The key sets of Definition 6.4 depend on the order only through rules (R2), (R4) and the last clause of (R5), whose omitted keys accept no output of the account under the restrictions of ZIP 326; under those restrictions every order of Definition 6.4 yields the note state of the scan in increasing height. The witness half of order independence is stated in “Witness readiness” (§7.5).
Receipt detection of an output is local to its block: it depends only on the compact output and the key set (Construction 4.8, Definition 4.9). Positions are local: by Lemma 4.12 the start size of each pool in follows from the compact block alone, and (a) makes it agree with the end size of the predecessor. Nullifiers are functions of the note, the key and, for Sapling, the position. Spent marks follow from Lemma 6.12 in either order. The chain state at is computed by step 3 of Construction 6.8 from the chain state below the last range that ends at , which (a) makes the true one, by induction over the ranges. For the last clause, a key omitted by (R2), (R4) or the last clause of (R5) in one order and tried in another accepts no output of the account (the Remark on omitted keys above; for (R5), no value enters the Orchard pool after NU6.3 activation, so a zero Orchard-pool balance stays zero), so both orders accept the same outputs. □
Assume clause (a) of Assumption 5.2, and let the server’s best chain be unchanged while an account with birthday is scanned by Construction 6.8 with the scanning keys of Definition 6.4, under conditions (a) and (b) of Lemma 6.13. Let be the fully scanned height. For every , restricted to notes created at heights at most and to spent marks set by nullifiers revealed at heights at most :
the note state holds a note of in pool at position if and only if the best chain has, at or below , an output of at position that Definition 4.9 accepts under a key of for its block and transaction ;
when the wallet holds the note’s nullifier deriving key, the note is marked spent if and only if its nullifier is revealed in pool of the best chain at or below , and, except with negligible probability, a revealed nullifier equal to it marks a spend of that note and of no other.
Completeness is over accepted outputs under the keys that Definition 6.4 applies, not over all outputs addressed to the account: an output that its sender encrypted malformed, one that acceptance rejects, and one that a non-conformant sender created under a key omitted by the rules of ZIP 326 are excluded. Ranges scanned out of order above add notes and spent marks above , which the statement does not cover. A holder of incoming viewing keys alone obtains (i) only (Proposition 6.6). The assumptions of (ii) are those named in the results cited in the proof.
By clause (a) the scanned compact blocks are those of the best chain, and every output of each is trial-decrypted under the applicable keys (Construction 6.8). Soundness of acceptance is Proposition 4.10, and membership of the accepted note in the best chain is Corollary 5.4(a). Positions are exact by Lemma 4.12(a) and Definition 6.10. The result does not depend on the order, by Lemma 6.13; this gives (i).
For (ii), spent status is nullifier matching within , with spends found in either order by Lemma 6.12. For Orchard-protocol notes, one nullifier per note and distinct nullifiers for distinct notes are the Ironwood Guide’s Lemma “One nullifier per note” (§“Double-spend resistance”) and Proposition “Nullifier uniqueness” (§“Nullifier uniqueness and unlinkability”), under the assumptions they name. For Sapling notes they are the Spend statement, which fixes the nullifier of the consumed note (protocol specification, §“Spend Statement (Sapling)”), and the requirement that be collision-resistant across all keys (§“Pseudo Random Functions”), with distinct for distinct positions (§“Computing values and Nullifiers”). Without clause (a), Remark 5.5 defeats completeness and Corollary 5.4(b) defeats soundness. □
Let an account have and a valid account key (“Valid account keys”, §2.6), so that its keys are determined by the seed and the account index (Proposition 2.12). Under clause (a) of Assumption 5.2, scanning the best chain from a lower bound on the account’s birthday, or from when none is recorded (Definition 6.2), with the scanning keys of Definition 6.4, in particular with by (R1) until (R2) narrows it, reconstructs the note state of the account up to the fully scanned height, as characterised by Theorem 6.14. Memos, and the outgoing plaintexts of outputs that the account encrypted under its , are recovered once the wallet-relevant transactions are fetched. Transparent funds are recovered at the addresses the wallet watches: index of each account by obligation (§3.6); how far beyond index a wallet looks is fixed by no ZIP and is designed but unspecified (Definition 1.1). Data that never reached the chain, such as the memos of transactions never mined, is not recoverable. An account with , whose keys does not determine, is outside the theorem, although Definition 6.4 scans with both values when restoring.
Proposition 2.12 gives the keys, hence the scanning keys. Definition 6.2 makes the scan start at or below the first receipt. Theorem 6.14 gives the note state. Memos and outgoing plaintexts are functions of the fetched full transactions and the keys, and under clause (a) returns the transactions of the best chain. □
The following interaction of a wallet that synchronises by ranges out of order is designed but unspecified (Definition 1.1). Per synchronisation the wallet runs:
for each pool, storing the roots of the complete subtrees;
;
selection of ranges: those near the tip, and those completing the subtrees of found notes (§7.5), before historic ranges;
for each range : unless is held, then , the continuity check and the scan;
a return to step 2 when a scan changes the selection: a newly found note, or a rollback after a continuity error.
The order is a wallet policy fixed by no ZIP, and it is observable by the server (“Leakage of range queries”, §8.3).
Trial decryption costs one key agreement per compact output or Action per candidate , for every block from the birthday to the tip, independently of the wallet’s own activity. Compaction (Definition 4.5) reduces the bandwidth, not the number of trials. Restoring an account repeats this work from its birthday. Retrieval of full transactions and the maintenance of authentication paths scale with the wallet’s own notes, the latter linearly in its unspent notes.
At NU7’s target spacing of seconds (ZIP 218, “Block target spacing”; Consensus Guide, §“Zcash time: 25-second blocks”), a target day of seconds holds blocks. A block holds at most Orchard-pool Actions (ZIP 218, “Shielded pool action limits”), so a target day holds at most compact Orchard-pool Actions, with at most bytes of their compact payload at bytes each (Definition 4.5), and requires at most trial decryptions of Orchard-pool Actions per candidate ; the number of candidate keys of an account is fixed by Definition 6.4. The same bounds hold for Orchard-pool Actions, Sapling spends and Sapling outputs together, since the shared budget of the same section limits their sum to per block, and a compact Sapling output ( bytes) or spend ( bytes) is smaller than a compact Action. The figures count target blocks: the number of blocks mined in a day varies, and the target spacing is not a rate limit.
The bound covers no Ironwood-pool Action: ZIP 218 counts none against any limit, so the specified text bounds neither their number nor the trial decryptions they cost. A proposed amendment would charge them to the shared budget of units, under which the same figures would bound the Orchard-protocol total (Consensus Guide, §“A block budget for shielded work”). The Ironwood term is an open problem (Definition 1.1).
The counts are , and . The per-block limits are and of ZIP 218, “Shielded pool action limits”. Each compact Action, and each compact Sapling output, costs one trial decryption per candidate key (Construction 4.8); a compact Sapling spend costs none. □