diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f5a08d..aabd1d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ and this library adheres to Rust's notion of ## Unreleased +### Added +- `service.MMRNode` +- `service.BlockInclusionProof` +- `service.BlockInclusionProof.tip_height`: height of the block whose header + commits to `mmr_root` and `auth_data_root`. The client should fetch this + block's header (via `GetBlock`) and verify `hashBlockCommitments` against it. +- `service.CompactTxStreamer.GetBlockInclusionProof`: returns an MMR inclusion + proof for a specific block (ZIP-221), enabling light clients to verify that + a block is included in the committed chain history. The proof includes the + MMR root, auth data root (ZIP-244), the MMR leaf entry for the requested + block, sibling nodes along the Merkle path from leaf to root, and the + `tip_height` identifying the committing block. For FlyClient verification + (ZIP-307), the client selects blocks to challenge using the sampling + distribution from https://eprint.iacr.org/2019/226. + ## [v0.4.1] - 2026-02-20 ### Added diff --git a/walletrpc/service.proto b/walletrpc/service.proto index 2f30f67..bc2843a 100644 --- a/walletrpc/service.proto +++ b/walletrpc/service.proto @@ -218,6 +218,42 @@ message GetAddressUtxosReplyList { repeated GetAddressUtxosReply addressUtxos = 1; } +// A node in the MMR tree, identified by its position in the +// flat array representation of the tree (see ZIP-221). +message MMRNode { + // Position in the MMR flat array representation + uint32 position = 1; + // Serialized zcash_history::Entry bytes for this node + bytes data = 2; +} + +// An MMR inclusion proof for a block in the chain history tree (ZIP-221). +// +// Contains the MMR root and auth data root for a specific chain tip, +// plus the Merkle path proving the requested block is in the committed chain. +// The client can verify: +// hashBlockCommitments = BLAKE2b-256("ZcashBlockCommit" || mmr_root || auth_data_root || [0u8;32]) +// against the block header at `tip_height` (obtainable via GetBlock) to +// authenticate the MMR root, then verify the inclusion proof against it. +// +// Future optimization: a range variant could batch multiple proofs sharing +// common MMR subtree nodes. +message BlockInclusionProof { + // hashLightClientRoot: the MMR root committed in the block at tip_height (32 bytes). + bytes mmr_root = 1; + // hashAuthDataRoot: the transaction auth data commitment from ZIP-244 + // for the block at tip_height (32 bytes). + bytes auth_data_root = 2; + // The MMR leaf entry for the requested block. + MMRNode leaf = 3; + // Sibling nodes along the path from leaf to root (bottom-up order). + repeated MMRNode siblings = 4; + // Height of the block whose header commits to mmr_root and auth_data_root. + // The client should fetch this block's header (via GetBlock) and verify + // hashBlockCommitments against the returned mmr_root and auth_data_root. + uint32 tip_height = 5; +} + service CompactTxStreamer { // Return the BlockID of the block at the tip of the best chain rpc GetLatestBlock(ChainSpec) returns (BlockID) {} @@ -323,4 +359,18 @@ service CompactTxStreamer { // Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production) rpc Ping(Duration) returns (PingResponse) {} + + // Get an MMR inclusion proof for a specific block (ZIP-221). + // + // Returns the MMR root, auth data root, and a Merkle path proving + // the block is included in the current chain tip's committed history. + // The client should: + // 1. Get the tip block header via GetBlock. + // 2. Call this RPC to get the MMR root and inclusion proof. + // 3. Verify hashBlockCommitments in the header against mmr_root + auth_data_root. + // 4. Verify the Merkle path against the MMR root. + // + // For FlyClient verification, the client selects blocks to challenge + // using the sampling distribution from https://eprint.iacr.org/2019/226. + rpc GetBlockInclusionProof(BlockID) returns (BlockInclusionProof) {} }