TOB-FUEL-5: compactProof
function gives incorrect result whenever there are more than one non-empty side nodes
#29
Labels
audit-report
Related to the audit report
Description
A missing increment operation leads to the
compactProof
function giving an incorrect result for any case where there are more than one non-zero side nodes.The
compactProof
function is used to compact a full Sparse Merkle Proof into a compact version. In a compact version all of the empty side nodes are not stored, but a bitmask is used to indicate which side nodes are empty. The accompanying decompactProof function can be used to convert the compact version back to the full version, where also empty side nodes are present.The sideNodesCount variable is used as an index at which to store each non-empty side node. However, there is no increment of the sideNodesCount variable. As a result each non-empty side node will overwrite the previous one, and is stored at index zero in the compactedSideNodes array.
Figure 5.1: The
compactProof
function in fuel-merkle-sol/contracts/tree/sparse/Proofs.solThe Fuel frontend might make use of the Solidity
compactProof
function to compact a proof, which would lead to an incorrect result. However, it seems more likely that the Fuel Typescript SDK is used instead, which also contains acompactProof
function, and that does function correctly.Figure 5.2: The compactProof function in fuels-ts/packages/merkle/src/sparse/proofs.ts
Exploit Scenario
The Fuel frontend makes use of the Solidity compactProof function to compact a Sparse Merkle Proof. Alice uses the UI to generate a compact proof. Alice then calls a contract operation that requires the proof. The transaction fails since the proof is incorrect.
Recommendations
Short term, increment the sideNodesCount variable inside the else case (figure 5.1, line 91) in the Solidity compactProof function. This will mitigate the bug and correctly store all of the non-empty side nodes in a compact Sparse Merkle Proof.
Long term, implement differential unit tests for the Merkle Tree-related functions across the Solidity and Typescript SDK (and possibly the Rust implementation) that verifies that they all behave identically for a given set of inputs. An improvement upon these tests would be to implement differential fuzzing tests across these three languages to test that they behave identically for all given inputs.
The text was updated successfully, but these errors were encountered: