root: root hash of the Merkle tree committing to column datacolumn_log_sizes: a vector containing log size values of all the columnsn_columns_per_log_size: a map that associates each column log size with the number of columns of that size
Verifying the decommitment
Theverify function is the main function defined for the MerkleVerifier. It takes the following input:
queries_per_log_size: A map from log size to a vector of query indices for columns of that size.queried_values: The queried column values, which is one of the outputs of thedecommitfunction.decommitment:MerkleDecommitmentcontaining thehash_witnessandcolumn_witnessrequired to check inclusion of thequeried_valuesin the Merkle tree. This is also one of the outputs of thedecommitfunction.
verify function:
-
Initialize Variables:
- Convert
queried_valuesinto an iterator for consumption during verification. - Create iterators for
hash_witnessandcolumn_witnessfrom thedecommitment. - Initialize
last_layer_hashesto track computed hashes from the previous layer.
- Convert
-
Layer-by-Layer Verification:
- For each layer (from largest to smallest):
- Get the number of columns in the current layer (
n_columns_in_layer) from the mapn_columns_per_log_size. - Prepare iterators for previous layer queries (
prev_layer_queries), previous layer hashes (prev_layer_hashes) and current layer column queries (layer_column_queries). - For each node index:
- Reconstruct
node_hashes: Use computed hashes from theprev_layer_hashesor read missing sibling hashes fromhash_witness. - Get Node Values: If the node is queried, read column values from
queried_values; otherwise, read fromcolumn_witness. - Compute Hash: Use the hash function to compute the hash of the current node from its children hashes and column values.
- Store the computed hash for propagation to the next layer.
- Reconstruct
- Get the number of columns in the current layer (
- For each layer (from largest to smallest):
-
Final Verification:
- Check that all witnesses and queried values have been fully consumed (no excess data).
- Verify that the computed root matches the expected root stored in the verifier.
- Return
Ok(())if verification succeeds, or an appropriate error otherwise.
Example: Verify the decommitment
The same example from the decommit process is used to verify the output of thedecommit function. The input to the verify function is as follows:
queries_per_log_size:queried_values:decommitment:hash_witness:column_witness:
verify function, showing how the verifier reconstructs the Merkle root:
-
layer_log_size = 2 (columns of size 4):
n_columns_in_layer: 2 (for and )last_layer_hashes:None(first layer)prev_layer_queries: emptylayer_column_queries:- For
node_index = 0:node_hashes:None(no previous layer)node_values: Read fromqueried_values→- Compute hash:
- Add to
layer_total_queries:
- At this stage:
last_layer_hashes=
-
layer_log_size = 1 (columns of size 2):
n_columns_in_layer: 1 (for )last_layer_hashes:prev_layer_queries:layer_column_queries:- For
node_index = 0:node_hashes: Left child is (computed fromlast_layer_hashes), right child read fromhash_witnessnode_values: Read fromcolumn_witness→- Compute hash:
- Add to
layer_total_queries:
- For
node_index = 1:node_hashes: Both children read fromhash_witnessnode_values: Read fromqueried_values→- Compute hash:
- Add to
layer_total_queries:
- At this stage:
last_layer_hashes=
-
layer_log_size = 0 (root):
n_columns_in_layer: 0 (no columns of size 1)last_layer_hashes:prev_layer_queries:layer_column_queries: empty- For
node_index = 0:node_hashes: Left child is , right child is (both computed fromlast_layer_hashes)node_values: empty (no columns)- Compute hash:
- Add to
layer_total_queries:
- At this stage:
last_layer_hashes=
- Check that all iterators are exhausted:
hash_witness,queried_values, andcolumn_witnessshould all be empty. - Compare the computed
rootwith the expected root stored in theMerkleVerifier. - If they match, return
Ok(()); otherwise, returnErr(MerkleVerificationError::RootMismatch).