Assessment reports>Blobstream X>Low findings>Enabled leaves in ,get_data_commitment, can underflow
Category: Coding Mistakes

Enabled leaves in get_data_commitment can underflow

Low Severity
Low Impact
High Likelihood

Description

The following assumption in get_data_commitment is wrong.

// If end_block < start_block, then this data commitment will be marked as disabled, and the
// output of this function is not used. Therefore, the logic assumes
// nb_blocks is always positive.

The batch is disabled if and only if start_block >= global_end_block, but this function is actually called with batch_end, which can still be lower. This means you can end up with a case where end_block > start_block.

While this implicit assumption has no significant impact by itself, it can be chained with another unenforced assumption in get_data_commitment:

let nb_blocks_in_batch = self.sub(end_block, start_block);
// Note: nb_blocks_in_batch is assumed to be less than 2^32 (which is a reasonable
// assumption for any data commitment as in practice, the number of blocks in a data
// commitment range will be much smaller than 2^32). This is fine as
// nb_blocks_in_batch.limbs[1] is unused.
let nb_enabled_leaves = nb_blocks_in_batch.limbs[0].variable;

The number of enabled leaves is directly taken from the first limb, assuming the second to be zero. However, in the case where end_block > start_block, nb_blocks_in_batch can have an integer underflow.

Impact

A malicous prover can supply an arbitrary value for batch_end_block that is less than batch_start_block, which causes nb_enabled_leaves to underflow and lead to undefined behavior.

This vulnerability is however only exploitable when combined with another vulnerability such as finding ref or finding ref, and is therefore marked as low impact.

Recommendations

Consider checking that end_block > start_block explicitly in get_data_commitment:

let is_valid = self.gt(end_block, start_block);
self.assert_is_equal(is_valid, true_bool);

Additionally, we recommend explicitly constraining the second limb to 0 as a sanity check

self.assert_is_equal(nb_blocks_in_batch.limbs[1].variable, self.constant::<U64Variable>(0u64));

Remediation

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

Zellic © 2024Back to top ↑