Skip to content

Commit

Permalink
feat: apply minor changes to SparseMerkleProof lib
Browse files Browse the repository at this point in the history
  • Loading branch information
Julink-eth committed May 2, 2024
1 parent ab293aa commit b34c12c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ library SparseMerkleProof {
error WrongBytesLength(uint256 expectedLength, uint256 bytesLength);

uint256 internal constant TREE_DEPTH = 40;
bytes32 internal constant ZERO_HASH = 0x0;

/**
* @notice Format input and verify sparse merkle proof
Expand Down Expand Up @@ -162,23 +163,24 @@ library SparseMerkleProof {
bytes[] calldata _rawProof
) private pure returns (bytes32, bytes32, bytes32[] memory) {
uint256 rawProofLength = _rawProof.length;
uint256 formattedProofLength = rawProofLength - 2;

bytes32[] memory proof = new bytes32[](rawProofLength - 2);
bytes32[] memory proof = new bytes32[](formattedProofLength);
bytes32 nextFreeNode = bytes32(_rawProof[0][:32]);
bytes32 leafHash = Mimc.hash(_rawProof[rawProofLength - 1]);

for (uint256 i = 1; i < rawProofLength - 2; ) {
proof[rawProofLength - 2 - i] = Mimc.hash(_rawProof[i]);
for (uint256 i = 1; i < formattedProofLength; ) {
proof[formattedProofLength - i] = Mimc.hash(_rawProof[i]);
unchecked {
++i;
}
}

// If the neighboring leaf is equal to zero bytes we don't hash it
if (_isZeroBytes(_rawProof[rawProofLength - 2])) {
proof[0] = bytes32(0);
// If the sibling leaf (_rawProof[formattedProofLength]) is equal to zero bytes we don't hash it
if (_isZeroBytes(_rawProof[formattedProofLength])) {
proof[0] = ZERO_HASH;
} else {
proof[0] = Mimc.hash(_rawProof[rawProofLength - 2]);
proof[0] = Mimc.hash(_rawProof[formattedProofLength]);
}

return (nextFreeNode, leafHash, proof);
Expand All @@ -187,29 +189,28 @@ library SparseMerkleProof {
/**
* @notice Check if bytes contain only zero byte elements
* @param _data Bytes to be checked
* @return {bool} true if bytes contain only zero byte elements, false otherwise
* @return isZeroBytes true if bytes contain only zero byte elements, false otherwise
*/
function _isZeroBytes(bytes calldata _data) private pure returns (bool) {
bool allZero = true;
function _isZeroBytes(
bytes calldata _data
) private pure returns (bool isZeroBytes) {
isZeroBytes = true;
assembly {
let dataLength := _data.length
let dataStart := _data.offset
let dataEnd := add(dataStart, dataLength)

for {
let currentPtr := dataStart
} lt(currentPtr, dataEnd) {
} lt(currentPtr, add(dataStart, _data.length)) {
currentPtr := add(currentPtr, 0x20)
} {
let dataWord := calldataload(currentPtr)

if eq(iszero(dataWord), 0) {
allZero := 0
isZeroBytes := 0
break
}
}
}
return allZero;
}

/**
Expand All @@ -230,7 +231,7 @@ library SparseMerkleProof {
bytes32 computedHash = _leafHash;
uint256 currentIndex = _leafIndex;

for (uint256 height; height < TREE_DEPTH; ) {
for (uint256 height; height < TREE_DEPTH; ++height) {
if ((currentIndex >> height) & 1 == 1)
computedHash = Mimc.hash(
abi.encodePacked(_proof[height], computedHash)
Expand All @@ -239,10 +240,6 @@ library SparseMerkleProof {
computedHash = Mimc.hash(
abi.encodePacked(computedHash, _proof[height])
);

unchecked {
++height;
}
}

return
Expand Down
37 changes: 17 additions & 20 deletions packages/linea-verifier/contracts/lib/SparseMerkleProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ library SparseMerkleProof {
error WrongBytesLength(uint256 expectedLength, uint256 bytesLength);

uint256 internal constant TREE_DEPTH = 40;
bytes32 internal constant ZERO_HASH = 0x0;

/**
* @notice Format input and verify sparse merkle proof
Expand Down Expand Up @@ -162,23 +163,24 @@ library SparseMerkleProof {
bytes[] calldata _rawProof
) private pure returns (bytes32, bytes32, bytes32[] memory) {
uint256 rawProofLength = _rawProof.length;
uint256 formattedProofLength = rawProofLength - 2;

bytes32[] memory proof = new bytes32[](rawProofLength - 2);
bytes32[] memory proof = new bytes32[](formattedProofLength);
bytes32 nextFreeNode = bytes32(_rawProof[0][:32]);
bytes32 leafHash = Mimc.hash(_rawProof[rawProofLength - 1]);

for (uint256 i = 1; i < rawProofLength - 2; ) {
proof[rawProofLength - 2 - i] = Mimc.hash(_rawProof[i]);
for (uint256 i = 1; i < formattedProofLength; ) {
proof[formattedProofLength - i] = Mimc.hash(_rawProof[i]);
unchecked {
++i;
}
}

// If the neighboring leaf is equal to zero bytes we don't hash it
if (_isZeroBytes(_rawProof[rawProofLength - 2])) {
proof[0] = bytes32(0);
// If the sibling leaf (_rawProof[formattedProofLength]) is equal to zero bytes we don't hash it
if (_isZeroBytes(_rawProof[formattedProofLength])) {
proof[0] = ZERO_HASH;
} else {
proof[0] = Mimc.hash(_rawProof[rawProofLength - 2]);
proof[0] = Mimc.hash(_rawProof[formattedProofLength]);
}

return (nextFreeNode, leafHash, proof);
Expand All @@ -187,29 +189,28 @@ library SparseMerkleProof {
/**
* @notice Check if bytes contain only zero byte elements
* @param _data Bytes to be checked
* @return {bool} true if bytes contain only zero byte elements, false otherwise
* @return isZeroBytes true if bytes contain only zero byte elements, false otherwise
*/
function _isZeroBytes(bytes calldata _data) private pure returns (bool) {
bool allZero = true;
function _isZeroBytes(
bytes calldata _data
) private pure returns (bool isZeroBytes) {
isZeroBytes = true;
assembly {
let dataLength := _data.length
let dataStart := _data.offset
let dataEnd := add(dataStart, dataLength)

for {
let currentPtr := dataStart
} lt(currentPtr, dataEnd) {
} lt(currentPtr, add(dataStart, _data.length)) {
currentPtr := add(currentPtr, 0x20)
} {
let dataWord := calldataload(currentPtr)

if eq(iszero(dataWord), 0) {
allZero := 0
isZeroBytes := 0
break
}
}
}
return allZero;
}

/**
Expand All @@ -230,7 +231,7 @@ library SparseMerkleProof {
bytes32 computedHash = _leafHash;
uint256 currentIndex = _leafIndex;

for (uint256 height; height < TREE_DEPTH; ) {
for (uint256 height; height < TREE_DEPTH; ++height) {
if ((currentIndex >> height) & 1 == 1)
computedHash = Mimc.hash(
abi.encodePacked(_proof[height], computedHash)
Expand All @@ -239,10 +240,6 @@ library SparseMerkleProof {
computedHash = Mimc.hash(
abi.encodePacked(computedHash, _proof[height])
);

unchecked {
++height;
}
}

return
Expand Down

0 comments on commit b34c12c

Please sign in to comment.