The Zcash ArboretumWallet Guide PDF

5 The light-client service

This section states the server from which a light wallet obtains chain data. It fixes the architecture and the one assumption on the server that the volume uses, states which checks a light client can make on the server’s responses and what the server can fabricate or omit undetected, and defines the service as an abstract interface of typed queries on the chain, the note commitment trees, transactions, submission and transparent addresses.

5.1 Architecture and authority

Definition 5.1 (Light-client architecture).

A light-client system has three components:

  1. 1.

    a full node, which validates the chain and is the root of trust for chain state;

  2. 2.

    a proxy, which extracts from the node’s view of the best chain the data of compact blocks (Definition 4.2) and answers queries;

  3. 3.

    a light client, which holds keys and no copy of the chain, queries the proxy, and maintains its own view of chain state and of its notes.

This volume calls the node and the proxy together the server. The wallet of “Parties, pools, and classifications” (§1.2) is the light client. The best chain is that of the Consensus Guide, §“Work, and the best chain” (ZIP 307, “High-Level Design”).

Assumption 5.2 (Honest-but-curious server).

The server satisfies two clauses.

  1. (a)

    Integrity. It answers every query from a correct view of the current best chain, each response being the value that the interface of “The query interface” (§5.2) assigns to the query on that chain, and it transmits queries and responses faithfully.

  2. (b)

    Curiosity. It records every query with its arguments, order and timing, every response, and the transport metadata of every connection, and computes arbitrarily on that record.

Every correctness result of this volume that relies on the server cites clause (a); the privacy results of §8 take clause (b) as the power of the adversary. No other server model is used. ZIP 307, “Security Model”, states the same model: the node and proxy together are honest but curious, and are trusted to provide a correct view of the current best chain and to transmit queries and responses faithfully. Its goal is payment-detection privacy: the proxy does not learn which transactions are addressed to a given wallet and, given network privacy provided separately, does not link different connections or queries to one wallet; the goal is defined in “Payment-detection privacy” (§8.1). The ZIP does not address private spending.

Proposition 5.3 (Light-client checks).

Let a wallet receive responses of the service (§5.2), with compact blocks that carry no header, which the abstract format does not guarantee (Definition 4.2). Then every check the wallet can make compares two responses, or a response with a value the wallet computes from responses. The relations among response fields that the format fixes are the following:

  1. (i)

    height continuity and 𝗉𝗋𝖾𝗏𝖧𝖺𝗌𝗁 linkage of consecutive compact blocks, and of the first block of a range with the block the wallet has stored, the checks of ZIP 307, “Client-server interaction”, phases B and D, and “Block header validation”;

  2. (ii)

    consistency of the per-block tree sizes with the commitments served (Lemma 4.12);

  3. (iii)

    recomputation of the note commitment of each accepted candidate (Definition 4.9, Proposition 4.10);

  4. (iv)

    agreement of a served tree node (a frontier, a subtree root, a root) with its recomputation from commitments the wallet has scanned;

  5. (v)

    agreement of a fetched transaction with its queried identifier and with the compact records of that identifier (Remark “Checks of a fetched transaction”);

  6. (vi)

    equality of a height, block hash or transaction identifier that several responses report.

No check relates a response to a block header or to proof of work: the wallet verifies no tree root, nullifier, transaction identifier or block hash against a header.

Proof.

The fields of a compact block and of its elements (Definitions 4.2, 4.3 and 4.5) and the responses of the service are values of the chain or tree data derived from it; without 𝗁𝖽𝗋 no response carries a header, so no field, not even 𝗁𝖺𝗌𝗁 or 𝗉𝗋𝖾𝗏𝖧𝖺𝗌𝗁, which the header determines, can be checked against one. A check is a predicate on the wallet’s inputs, which are these responses and its keys, so it compares responses with one another or with values computed from them. Items (i) to (vi) relate pairs of fields that the format makes functions of one another: the heights and hashes of adjacent blocks; a block’s commitment count and its sizes; a record’s commitment and its plaintext; a tree node and the leaves below it; a fetched transaction and its identifier and compact records; and a height, hash or identifier repeated across responses. Proof of work is a relation between a header and its solution and target (Consensus Guide, §“Equihash and the memoryless model”), which no response carries. □

ZIP 307, “Block header validation”, proposes checks against a header when a compact block carries one; the abstract format does not guarantee a header, and no result of this volume uses them.

Corollary 5.4 (Fabrication of compact outputs).
  1. (a)

    Under clause (a) of Assumption 5.2, every compact candidate accepted by Definition 4.9 is a note of the best chain: its commitment is a leaf of its pool’s note commitment tree at the position that Definition 4.11 assigns. The fields a compact record omits (proofs, signatures, value commitments, anchors, full ciphertexts) are checked by consensus for every transaction of the best chain, so delegating their verification to the server loses no check a light client could make.

  2. (b)

    Without clause (a), no check authenticates the compact fields against the chain. A server that knows one of the wallet’s addresses can construct a note to it, compute its commitment and note ciphertext, choose the remaining compact fields (𝗇𝖿 of an Action, which is ρ of the note), and serve the result as a compact output or Action, with tree sizes consistent with it; the result passes Definition 4.9. Unless a transaction of the chain appends the same commitment, no authentication path from it to an anchor of the chain can be found except with negligible probability, so the wallet displays a note whose every spend is rejected.

Proof.

(a) By Proposition 4.10(a) an accepted candidate opens the commitment of its compact record. By clause (a) that record is the corresponding field of a transaction of the best chain, whose commitments are appended to the pool’s tree in the order that fixes the position (Ironwood Guide, §“The Merkle hash and the tree”, Definition “Note commitment tree”; Lemma 4.12(a)). The omitted fields are validated by the consensus rules for every transaction of the chain (Ironwood Guide, §“Transaction digests and signatures” and §“Anchors”).

(b) Acceptance checks only the lead byte, the field ranges, the commitment recomputed from the plaintext and 𝖾𝗉𝗄=[𝖾𝗌𝗄]⁢𝗀𝖽 (Definition 4.9), and an honestly constructed note to an address of the wallet satisfies all of them; the tree-size checks of Lemma 4.12 pass on sizes the server chooses consistently, by part (d) of that lemma. A spend proves a valid path from the commitment to an anchor of the chain (Ironwood Guide, §“Authentication paths”), and a valid path from a value that is not the leaf at its position yields a collision of the Merkle hash, found with at most negligible probability (Ironwood Guide, §“Anchors”, Proposition “Membership soundness”; protocol specification, §“Merkle Path Validity”, for Sapling). ZIP 307, “Output Compression”, grounds the commitment check on the same trust, in the entity that assembles transactions. □

Remark 5.5 (Omission is undetected).

Completeness of the served data is trusted, not verified. The size check of Lemma 4.12 detects the omission of a commitment only while the served sizes are correct. A server that omits compact outputs or Actions and serves tree sizes, frontiers, subtree roots and roots consistent with the omission, or omits or alters revealed nullifiers, of which a compact block carries no count, passes every check of Proposition 5.3. Omitted outputs hide receipts. Omitted nullifiers hide spends: the wallet shows spent notes as spendable, and a re-spend of such a note is rejected for a repeated nullifier (Ironwood Guide, §“Nullifier sets”) while it discloses to every party that receives it that it spends what an earlier transaction spent, the leak of repeated spends of ZIP 315, “Obtaining user consent for information leakage”. Only clause (a) of Assumption 5.2 excludes omission (ZIP 307, “Security Model”).

Remark 5.6 (Malformed responses).

A response with a field outside its type (a nullifier not of 32 bytes, a non-canonical encoding of a field element, a malformed compact output or Action, a block outside the requested range) is an error of the response: the results of the query are not applied, and the query may be repeated. It is not a continuity error and triggers no rollback (“Reorganisation detection and recovery”, §7.6). This rule is designed but unspecified (Definition 1.1).

Remark 5.7 (Checks of a fetched transaction).

A full transaction fetched by its identifier SHOULD be checked against the corresponding compact outputs, in addition to verification of its signatures (ZIP 307, “Block header validation”). The checks are: the identifier computed from the fetched transaction equals the queried one (Ironwood Guide, §“Transaction digests and signatures”, Definition “Transaction identifier”; protocol specification, §“Transaction Identifiers”); its outputs and Actions agree with the compact records; and its signatures verify over its signature digest (Ironwood Guide, §“Transaction digests and signatures”, Definition “Signature digest”). They bind the full transaction to the compact data and its authorisation to its effects. They bind neither to the chain: compact blocks carry too little to check an identifier against the block’s transaction tree, and that binding rests on clause (a) of Assumption 5.2.

5.2 The query interface

A wallet holds keys and no chain state (Definition 5.1), so the interface delivers what the protocols below consume: every compact output and Action of every shielded pool, for trial decryption (Ironwood Guide, §“Trial decryption and note acceptance”); every revealed nullifier, for spend detection (Ironwood Guide, §“Nullifier sets”); for each pool, tree sizes, frontiers and the roots of complete subtrees, for positions and authentication paths (Ironwood Guide, §“Authentication paths”); the full transactions that concern the wallet; submission of its transactions and their status; and, for transparent receivers, the transparent outputs paid to its addresses.

Definition 5.8 (Subtree root and completing height).

Let 𝗉𝗈𝗈𝗅∈{𝖲𝖺𝗉𝗅𝗂𝗇𝗀,𝖮𝗋𝖼𝗁𝖺𝗋𝖽,𝖨𝗋𝗈𝗇𝗐𝗈𝗈𝖽}, whose note commitment tree has depth 32 and layers numbered from layer 0, the root, to layer 32, the leaves (Ironwood Guide, §“The Merkle hash and the tree”, Definition “Note commitment tree”; protocol specification, §“Note Commitment Trees”, for Sapling). For 0≤i<216, subtree i of the tree is the subtree whose leaves are the positions [i⋅216,(i+1)⋅216); its root is the node Mi16, sixteen layers above the leaves. When the tree holds n leaves, subtree i is complete if n≥(i+1)⋅216, after which its root no longer changes; the complete subtrees are those with i<⌊n/216⌋. The completing height of a complete subtree i is the height of the block whose transactions append position (i+1)⋅216−1.

Definition 5.9 (Transaction status).

The status of a transaction identifier 𝗍𝗑𝗂𝖽 on the server’s best chain, with tip height T, is one of:

  1. 1.

    𝗎𝗇𝗄𝗇𝗈𝗐𝗇: the server knows no transaction with identifier 𝗍𝗑𝗂𝖽;

  2. 2.

    𝗎𝗇𝗆𝗂𝗇𝖾𝖽: the server knows the transaction, in its mempool or in a block off the best chain, and no block of the best chain contains it;

  3. 3.

    𝗆𝗂𝗇𝖾𝖽⁢(h): the block of the best chain at height h≤T contains it.

The encoding of the status lies outside the abstract interface. The status is designed but unspecified (Definition 1.1).

Definition 5.10 (Light-client query interface).

The light-client service is the set of typed queries of Table 4, each answered from the server’s best chain under clause (a) of Assumption 5.2. A block identifier is a height or a 32-byte block hash. A pool set is a set 𝒫 of the pool selection of “The compact block and the compact transaction” (§4.1): shielded pools, with transparent data selectable alongside. The service serves every pool set and transparent data. A query whose argument names no block of the best chain, or a transaction that the server does not know, is answered with ⊥. Queries of the mempool and of server metadata are not part of the interface.

Query Arguments Response
Chain
𝖳𝗂𝗉⁢() none (h,𝗁𝖺𝗌𝗁) of the tip of the best chain; the tip input of every confirmation count (§9)
𝖡𝗅𝗈𝖼𝗄⁢(b) block identifier b the compact block of b, with all shielded pools and transparent data
𝖡𝗅𝗈𝖼𝗄𝗌⁢(s,e,𝒫) heights s≤e;
pool set 𝒫
the compact blocks at heights s,s+1,…,e in ascending order, restricted to 𝒫; every height of [s,e] present, a block left with no transaction carrying an empty list
Trees
𝖳𝗋𝖾𝖾𝖲𝗍𝖺𝗍𝖾⁢(b) block identifier b height and hash of b, and for each shielded pool the size n and the frontier of its tree in the final treestate of b; an empty frontier denotes the empty tree
𝖲𝗎𝖻𝗍𝗋𝖾𝖾𝖱𝗈𝗈𝗍𝗌⁢(𝗉𝗈𝗈𝗅,i) shielded pool 𝗉𝗈𝗈𝗅;
start index i
in index order, the pair (root, completing height) of every complete subtree of the tree of 𝗉𝗈𝗈𝗅 with index at least i
Transactions
𝖳𝗑⁢(𝗍𝗑𝗂𝖽) 32-byte identifier the full serialised transaction
𝖲𝗎𝖻𝗆𝗂𝗍⁢(𝑏𝑦𝑡𝑒𝑠) serialised transaction 𝖺𝖼𝖼𝖾𝗉𝗍𝖾𝖽⁢(𝗍𝗑𝗂𝖽) if the server’s node admits it to its mempool, else 𝗋𝖾𝗃𝖾𝖼𝗍𝖾𝖽
𝖲𝗍𝖺𝗍𝗎𝗌⁢(𝗍𝗑𝗂𝖽) 32-byte identifier the status of Definition 5.9
Transparent
𝖴𝗍𝗑𝗈𝗌⁢(A) set A of transparent addresses the unspent outputs of the best chain paying to A, each with outpoint, value, script and height
Table 4: Queries, arguments, and responses of the light-client service (Definition 5.10). Each response is the value on the server’s best chain; ⊥ answers an argument that names nothing on it.

The frontier in a response of 𝖳𝗋𝖾𝖾𝖲𝗍𝖺𝗍𝖾 is that of the Crypto Guide, §“Append-only and incrementally updatable trees”, Definition “Frontier”: for a tree of n leaves, the left-sibling nodes along the path of the next leaf, one for each set bit of n, from which the root and every later append are computed. The empty frontier is the state before the pool’s first commitment. The final treestate of a block is that of the protocol specification, §“Transactions and Treestates” (Ironwood Guide, §“Anchors”, Definition “Treestate and anchor”). The serialisation of the frontier is fixed by no ZIP and is not restated. ZIP 307, “Proxy operation”, also identifies a transaction by its block and its index in the block; the interface uses the identifier alone.

Remark 5.11 (Classification of the queries).

ZIP 307, “Proxy operation”, specifies the queries 𝖳𝗂𝗉, 𝖡𝗅𝗈𝖼𝗄, 𝖡𝗅𝗈𝖼𝗄𝗌 and 𝖳𝗑. No ZIP specifies 𝖳𝗋𝖾𝖾𝖲𝗍𝖺𝗍𝖾, 𝖲𝗎𝖻𝗍𝗋𝖾𝖾𝖱𝗈𝗈𝗍𝗌, 𝖲𝗎𝖻𝗆𝗂𝗍, 𝖲𝗍𝖺𝗍𝗎𝗌 or the transparent query 𝖴𝗍𝗑𝗈𝗌, and ZIP 307, “Client-server interaction”, leaves the acquisition of a starting tree state open: “Or, it has to set X to the block height at which Sapling activated, so as to be sent the entire commitment tree. [TODO: Decide which to specify.]” These queries, and pool selection in 𝖡𝗅𝗈𝖼𝗄𝗌, are designed but unspecified (Definition 1.1).

Remark 5.12 (Minimal query set).

A shielded synchronisation uses 𝖳𝗂𝗉, 𝖲𝗎𝖻𝗍𝗋𝖾𝖾𝖱𝗈𝗈𝗍𝗌 for each shielded pool, 𝖡𝗅𝗈𝖼𝗄𝗌 and 𝖳𝗋𝖾𝖾𝖲𝗍𝖺𝗍𝖾; the full transactions that concern the wallet add 𝖳𝗑. A wallet that watches transparent receivers adds 𝖴𝗍𝗑𝗈𝗌, whose argument names its addresses in the clear (“Key independence of queries”, §8.2). This set is the requirement of the synchronisation protocols of “Note discovery” (§6) and “Commitment-tree synchronisation” (§7), not a deployed fact.