Assessment reports>Blobstream X>Critical findings>Data hash in return value of ,prove_next_header_data_commitment, underconstrained
Category: Coding Mistakes

Data hash in return value of prove_next_header_data_commitment underconstrained

Critical Severity
Critical Impact
High Likelihood

Description

The prove_next_header_data_commitment takes trusted inputs prev_header_hash and prev_block_number and assumes that prev_header_hash is the Merkle root hash of the block at height prev_block_number. It is intended to return the Merkle root hash of a Merkle tree containing a sole leaf abi.encode(prev_block_number, DataHash), where the second argument is the DataHash field of the block with header Merkle-root hash prev_header_hash.

However, while the DataHash field associated to prev_header_hash is constrained to be the protobuf-decoding of data_comm_proof.data_hash_proofs[0].leaf, an unconstrained witness data_comm_proof.data_hashes[0] is instead used when constructing the return value.

A similar oversight is also present in prove_subchain.

The prove_subchain function returns a MapReduceSubchainVariable containing the Merkle-root hash of the batches' data commitments, calculated as follows:

let data_merkle_root = self.get_data_commitment::<BATCH_SIZE>(
    &data_comm_proof.data_hashes,
    batch_start_block,
    end_block_num,
);

The leaf data used here is data_comm_proof.data_hashes, which is, however, completely unconstrained.

Elsewhere in the function, a Merkle inclusion proof for the DataHash field of the enabled Tendermint blocks is checked:

let data_hash_proof_root = self
    .get_root_from_merkle_proof::<HEADER_PROOF_DEPTH, PROTOBUF_HASH_SIZE_BYTES>(
        &data_comm_proof.data_hash_proofs[i],
        &data_hash_path,
    );

Later verification of data_hash_proof_root for enabled blocks shows that data_comm_proof.data_hash_proofs[i].leaf is the protobuf encoding of the DataHash field of the associated Tendermint block. However, there is no check to ensure that data_comm_proof.data_hashes[i] is the protobuf decoding of data_comm_proof.data_hash_proofs[i].leaf.

Impact

An attacker could generate a proof with arbitrary data hashes of their choosing in the data commitments.

Recommendations

Consider using data_comm_proof.data_hash_proofs[i].leaf instead of data_comm_proof.data_hashes[i] to construct the data commitments. Note that data_comm_proof.data_hash_proofs[i].leaf is the protobuf encoding of the DataHash field, so it consists of two bytes of protobuf header followed by the actual 32 bytes of the DataHash field.

Remediation

This issue has been acknowledged by Succinct, and a fix was implemented in the following commit: .

Zellic © 2024Back to top ↑