@ -1,5 +1,6 @@
/ / SPDX - License - Identifier : MIT
/ / SPDX - License - Identifier : MIT
/ / OpenZeppelin Contracts ( last updated v5 . 0 . 0 ) ( utils / cryptography / MerkleProof . sol )
/ / OpenZeppelin Contracts ( last updated v5 . 0 . 0 ) ( utils / cryptography / MerkleProof . sol )
/ / This file was procedurally generated from scripts / generate / templates / MerkleProof . js .
pragma solidity ^ 0 . 8 . 20 ;
pragma solidity ^ 0 . 8 . 20 ;
@ -18,6 +19,11 @@ import {Hashes} from "./Hashes.sol";
* the Merkle tree could be reinterpreted as a leaf value .
* the Merkle tree could be reinterpreted as a leaf value .
* OpenZeppelin ' s JavaScript library generates Merkle trees that are safe
* OpenZeppelin ' s JavaScript library generates Merkle trees that are safe
* against this attack out of the box .
* against this attack out of the box .
*
* NOTE : This library supports proof verification for merkle trees built using
* custom _commutative_ hashing functions ( i . e . ` H ( a , b ) == H ( b , a ) ` ) . Proving
* leaf inclusion in trees built using non - commutative hashing functions requires
* additional logic that is not supported by this library .
* /
* /
library MerkleProof {
library MerkleProof {
/**
/**
@ -30,16 +36,44 @@ library MerkleProof {
* defined by ` root ` . For this , a ` proof ` must be provided , containing
* defined by ` root ` . For this , a ` proof ` must be provided , containing
* sibling hashes on the branch from the leaf to the root of the tree . Each
* sibling hashes on the branch from the leaf to the root of the tree . Each
* pair of leaves and each pair of pre - images are assumed to be sorted .
* pair of leaves and each pair of pre - images are assumed to be sorted .
*
* This version handles proofs in memory with the default hashing function .
* /
* /
function verify ( bytes32 [ ] memory proof , bytes32 root , bytes32 leaf ) internal pure returns ( bool ) {
function verify ( bytes32 [ ] memory proof , bytes32 root , bytes32 leaf ) internal pure returns ( bool ) {
return processProof ( proof , leaf ) == root ;
return processProof ( proof , leaf ) == root ;
}
}
/**
/**
* @ dev Calldata version of { verify }
* @ dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from ` leaf ` using ` proof ` . A ` proof ` is valid if and only if the rebuilt
* hash matches the root of the tree . When processing the proof , the pairs
* of leafs & pre - images are assumed to be sorted .
*
* This version handles proofs in memory with the default hashing function .
* /
* /
function verifyCalldata ( bytes32 [ ] calldata proof , bytes32 root , bytes32 leaf ) internal pure returns ( bool ) {
function processProof ( bytes32 [ ] memory proof , bytes32 leaf ) internal pure returns ( bytes32 ) {
return processProofCalldata ( proof , leaf ) == root ;
bytes32 computedHash = leaf ;
for ( uint256 i = 0 ; i < proof . length ; i ++ ) {
computedHash = Hashes . commutativeKeccak256 ( computedHash , proof [ i ] ) ;
}
return computedHash ;
}
/**
* @ dev Returns true if a ` leaf ` can be proved to be a part of a Merkle tree
* defined by ` root ` . For this , a ` proof ` must be provided , containing
* sibling hashes on the branch from the leaf to the root of the tree . Each
* pair of leaves and each pair of pre - images are assumed to be sorted .
*
* This version handles proofs in memory with a custom hashing function .
* /
function verify (
bytes32 [ ] memory proof ,
bytes32 root ,
bytes32 leaf ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bool ) {
return processProof ( proof , leaf , hasher ) == root ;
}
}
/**
/**
@ -47,17 +81,40 @@ library MerkleProof {
* from ` leaf ` using ` proof ` . A ` proof ` is valid if and only if the rebuilt
* from ` leaf ` using ` proof ` . A ` proof ` is valid if and only if the rebuilt
* hash matches the root of the tree . When processing the proof , the pairs
* hash matches the root of the tree . When processing the proof , the pairs
* of leafs & pre - images are assumed to be sorted .
* of leafs & pre - images are assumed to be sorted .
*
* This version handles proofs in memory with a custom hashing function .
* /
* /
function processProof ( bytes32 [ ] memory proof , bytes32 leaf ) internal pure returns ( bytes32 ) {
function processProof (
bytes32 [ ] memory proof ,
bytes32 leaf ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bytes32 ) {
bytes32 computedHash = leaf ;
bytes32 computedHash = leaf ;
for ( uint256 i = 0 ; i < proof . length ; i ++ ) {
for ( uint256 i = 0 ; i < proof . length ; i ++ ) {
computedHash = Hashes . commutativeKeccak256 ( computedHash , proof [ i ] ) ;
computedHash = hasher ( computedHash , proof [ i ] ) ;
}
}
return computedHash ;
return computedHash ;
}
}
/**
/**
* @ dev Calldata version of { processProof }
* @ dev Returns true if a ` leaf ` can be proved to be a part of a Merkle tree
* defined by ` root ` . For this , a ` proof ` must be provided , containing
* sibling hashes on the branch from the leaf to the root of the tree . Each
* pair of leaves and each pair of pre - images are assumed to be sorted .
*
* This version handles proofs in calldata with the default hashing function .
* /
function verifyCalldata ( bytes32 [ ] calldata proof , bytes32 root , bytes32 leaf ) internal pure returns ( bool ) {
return processProof ( proof , leaf ) == root ;
}
/**
* @ dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from ` leaf ` using ` proof ` . A ` proof ` is valid if and only if the rebuilt
* hash matches the root of the tree . When processing the proof , the pairs
* of leafs & pre - images are assumed to be sorted .
*
* This version handles proofs in calldata with the default hashing function .
* /
* /
function processProofCalldata ( bytes32 [ ] calldata proof , bytes32 leaf ) internal pure returns ( bytes32 ) {
function processProofCalldata ( bytes32 [ ] calldata proof , bytes32 leaf ) internal pure returns ( bytes32 ) {
bytes32 computedHash = leaf ;
bytes32 computedHash = leaf ;
@ -67,10 +124,49 @@ library MerkleProof {
return computedHash ;
return computedHash ;
}
}
/**
* @ dev Returns true if a ` leaf ` can be proved to be a part of a Merkle tree
* defined by ` root ` . For this , a ` proof ` must be provided , containing
* sibling hashes on the branch from the leaf to the root of the tree . Each
* pair of leaves and each pair of pre - images are assumed to be sorted .
*
* This version handles proofs in calldata with a custom hashing function .
* /
function verifyCalldata (
bytes32 [ ] calldata proof ,
bytes32 root ,
bytes32 leaf ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bool ) {
return processProof ( proof , leaf , hasher ) == root ;
}
/**
* @ dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from ` leaf ` using ` proof ` . A ` proof ` is valid if and only if the rebuilt
* hash matches the root of the tree . When processing the proof , the pairs
* of leafs & pre - images are assumed to be sorted .
*
* This version handles proofs in calldata with a custom hashing function .
* /
function processProofCalldata (
bytes32 [ ] calldata proof ,
bytes32 leaf ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bytes32 ) {
bytes32 computedHash = leaf ;
for ( uint256 i = 0 ; i < proof . length ; i ++ ) {
computedHash = hasher ( computedHash , proof [ i ] ) ;
}
return computedHash ;
}
/**
/**
* @ dev Returns true if the ` leaves ` can be simultaneously proven to be a part of a Merkle tree defined by
* @ dev Returns true if the ` leaves ` can be simultaneously proven to be a part of a Merkle tree defined by
* ` root ` , according to ` proof ` and ` proofFlags ` as described in { processMultiProof } .
* ` root ` , according to ` proof ` and ` proofFlags ` as described in { processMultiProof } .
*
*
* This version handles multiproofs in memory with the default hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* /
* /
function multiProofVerify (
function multiProofVerify (
@ -83,7 +179,151 @@ library MerkleProof {
}
}
/**
/**
* @ dev Calldata version of { multiProofVerify }
* @ dev Returns the root of a tree reconstructed from ` leaves ` and sibling nodes in ` proof ` . The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf / inner node with either another
* leaf / inner node or a proof sibling node , depending on whether each ` proofFlags ` item is true or false
* respectively .
*
* This version handles multiproofs in memory with the default hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . To use multiproofs , it is sufficient to ensure that : 1 ) the tree
* is complete ( but not necessarily perfect ) , 2 ) the leaves to be proven are in the opposite order they are in the
* tree ( i . e . , as seen from right to left starting at the deepest layer and continuing at the next layer ) .
* /
function processMultiProof (
bytes32 [ ] memory proof ,
bool [ ] memory proofFlags ,
bytes32 [ ] memory leaves
) internal pure returns ( bytes32 merkleRoot ) {
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / the Merkle tree .
uint256 leavesLen = leaves . length ;
/ / Check proof validity .
if ( leavesLen + proof . length != proofFlags . length + 1 ) {
revert MerkleProofInvalidMultiproof ( ) ;
}
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
bytes32 [ ] memory hashes = new bytes32 [ ] ( proofFlags . length ) ;
uint256 leafPos = 0 ;
uint256 hashPos = 0 ;
uint256 proofPos = 0 ;
/ / At each step , we compute the next hash using two values :
/ / - a value from the " main queue " . If not all leaves have been consumed , we get the next leaf , otherwise we
/ / get the next hash .
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / ` proof ` array .
for ( uint256 i = 0 ; i < proofFlags . length ; i ++ ) {
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 b = proofFlags [ i ]
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
: proof [ proofPos ++ ] ;
hashes [ i ] = Hashes . commutativeKeccak256 ( a , b ) ;
}
if ( proofFlags . length > 0 ) {
if ( proofPos != proof . length ) {
revert MerkleProofInvalidMultiproof ( ) ;
}
unchecked {
return hashes [ proofFlags . length - 1 ] ;
}
} else if ( leavesLen > 0 ) {
return leaves [ 0 ] ;
} else {
return proof [ 0 ] ;
}
}
/**
* @ dev Returns true if the ` leaves ` can be simultaneously proven to be a part of a Merkle tree defined by
* ` root ` , according to ` proof ` and ` proofFlags ` as described in { processMultiProof } .
*
* This version handles multiproofs in memory with a custom hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* /
function multiProofVerify (
bytes32 [ ] memory proof ,
bool [ ] memory proofFlags ,
bytes32 root ,
bytes32 [ ] memory leaves ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bool ) {
return processMultiProof ( proof , proofFlags , leaves , hasher ) == root ;
}
/**
* @ dev Returns the root of a tree reconstructed from ` leaves ` and sibling nodes in ` proof ` . The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf / inner node with either another
* leaf / inner node or a proof sibling node , depending on whether each ` proofFlags ` item is true or false
* respectively .
*
* This version handles multiproofs in memory with a custom hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . To use multiproofs , it is sufficient to ensure that : 1 ) the tree
* is complete ( but not necessarily perfect ) , 2 ) the leaves to be proven are in the opposite order they are in the
* tree ( i . e . , as seen from right to left starting at the deepest layer and continuing at the next layer ) .
* /
function processMultiProof (
bytes32 [ ] memory proof ,
bool [ ] memory proofFlags ,
bytes32 [ ] memory leaves ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bytes32 merkleRoot ) {
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / the Merkle tree .
uint256 leavesLen = leaves . length ;
/ / Check proof validity .
if ( leavesLen + proof . length != proofFlags . length + 1 ) {
revert MerkleProofInvalidMultiproof ( ) ;
}
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
bytes32 [ ] memory hashes = new bytes32 [ ] ( proofFlags . length ) ;
uint256 leafPos = 0 ;
uint256 hashPos = 0 ;
uint256 proofPos = 0 ;
/ / At each step , we compute the next hash using two values :
/ / - a value from the " main queue " . If not all leaves have been consumed , we get the next leaf , otherwise we
/ / get the next hash .
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / ` proof ` array .
for ( uint256 i = 0 ; i < proofFlags . length ; i ++ ) {
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 b = proofFlags [ i ]
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
: proof [ proofPos ++ ] ;
hashes [ i ] = hasher ( a , b ) ;
}
if ( proofFlags . length > 0 ) {
if ( proofPos != proof . length ) {
revert MerkleProofInvalidMultiproof ( ) ;
}
unchecked {
return hashes [ proofFlags . length - 1 ] ;
}
} else if ( leavesLen > 0 ) {
return leaves [ 0 ] ;
} else {
return proof [ 0 ] ;
}
}
/**
* @ dev Returns true if the ` leaves ` can be simultaneously proven to be a part of a Merkle tree defined by
* ` root ` , according to ` proof ` and ` proofFlags ` as described in { processMultiProof } .
*
* This version handles multiproofs in calldata with the default hashing function .
*
*
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* /
* /
@ -91,9 +331,9 @@ library MerkleProof {
bytes32 [ ] calldata proof ,
bytes32 [ ] calldata proof ,
bool [ ] calldata proofFlags ,
bool [ ] calldata proofFlags ,
bytes32 root ,
bytes32 root ,
bytes32 [ ] memory leaves
bytes32 [ ] calldata leaves
) internal pure returns ( bool ) {
) internal pure returns ( bool ) {
return processMultiProofCalldata ( proof , proofFlags , leaves ) == root ;
return processMultiProof ( proof , proofFlags , leaves ) == root ;
}
}
/**
/**
@ -102,31 +342,31 @@ library MerkleProof {
* leaf / inner node or a proof sibling node , depending on whether each ` proofFlags ` item is true or false
* leaf / inner node or a proof sibling node , depending on whether each ` proofFlags ` item is true or false
* respectively .
* respectively .
*
*
* This version handles multiproofs in calldata with the default hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . To use multiproofs , it is sufficient to ensure that : 1 ) the tree
* CAUTION : Not all Merkle trees admit multiproofs . To use multiproofs , it is sufficient to ensure that : 1 ) the tree
* is complete ( but not necessarily perfect ) , 2 ) the leaves to be proven are in the opposite order they are in the
* is complete ( but not necessarily perfect ) , 2 ) the leaves to be proven are in the opposite order they are in the
* tree ( i . e . , as seen from right to left starting at the deepest layer and continuing at the next layer ) .
* tree ( i . e . , as seen from right to left starting at the deepest layer and continuing at the next layer ) .
* /
* /
function processMultiProof (
function processMultiProofCalldata (
bytes32 [ ] memory proof ,
bytes32 [ ] calldata proof ,
bool [ ] memory proofFlags ,
bool [ ] calldata proofFlags ,
bytes32 [ ] memory leaves
bytes32 [ ] calldata leaves
) internal pure returns ( bytes32 merkleRoot ) {
) internal pure returns ( bytes32 merkleRoot ) {
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / the Merkle tree .
/ / the Merkle tree .
uint256 leavesLen = leaves . length ;
uint256 leavesLen = leaves . length ;
uint256 proofLen = proof . length ;
uint256 totalHashes = proofFlags . length ;
/ / Check proof validity .
/ / Check proof validity .
if ( leavesLen + proofLen != totalHashes + 1 ) {
if ( leavesLen + proof . length != proofFlags . length + 1 ) {
revert MerkleProofInvalidMultiproof ( ) ;
revert MerkleProofInvalidMultiproof ( ) ;
}
}
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
bytes32 [ ] memory hashes = new bytes32 [ ] ( totalHashes ) ;
bytes32 [ ] memory hashes = new bytes32 [ ] ( proofFlags . length ) ;
uint256 leafPos = 0 ;
uint256 leafPos = 0 ;
uint256 hashPos = 0 ;
uint256 hashPos = 0 ;
uint256 proofPos = 0 ;
uint256 proofPos = 0 ;
@ -135,7 +375,7 @@ library MerkleProof {
/ / get the next hash .
/ / get the next hash .
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / ` proof ` array .
/ / ` proof ` array .
for ( uint256 i = 0 ; i < totalHashes ; i ++ ) {
for ( uint256 i = 0 ; i < proofFlags . length ; i ++ ) {
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 b = proofFlags [ i ]
bytes32 b = proofFlags [ i ]
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
@ -143,12 +383,12 @@ library MerkleProof {
hashes [ i ] = Hashes . commutativeKeccak256 ( a , b ) ;
hashes [ i ] = Hashes . commutativeKeccak256 ( a , b ) ;
}
}
if ( totalHashes > 0 ) {
if ( proofFlags . length > 0 ) {
if ( proofPos != proofLen ) {
if ( proofPos != proof . length ) {
revert MerkleProofInvalidMultiproof ( ) ;
revert MerkleProofInvalidMultiproof ( ) ;
}
}
unchecked {
unchecked {
return hashes [ totalHashes - 1 ] ;
return hashes [ proofFlags . length - 1 ] ;
}
}
} else if ( leavesLen > 0 ) {
} else if ( leavesLen > 0 ) {
return leaves [ 0 ] ;
return leaves [ 0 ] ;
@ -158,31 +398,55 @@ library MerkleProof {
}
}
/**
/**
* @ dev Calldata version of { processMultiProof } .
* @ dev Returns true if the ` leaves ` can be simultaneously proven to be a part of a Merkle tree defined by
* ` root ` , according to ` proof ` and ` proofFlags ` as described in { processMultiProof } .
*
* This version handles multiproofs in calldata with a custom hashing function .
*
*
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* CAUTION : Not all Merkle trees admit multiproofs . See { processMultiProof } for details .
* /
* /
function multiProofVerifyCalldata (
bytes32 [ ] calldata proof ,
bool [ ] calldata proofFlags ,
bytes32 root ,
bytes32 [ ] calldata leaves ,
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bool ) {
return processMultiProof ( proof , proofFlags , leaves , hasher ) == root ;
}
/**
* @ dev Returns the root of a tree reconstructed from ` leaves ` and sibling nodes in ` proof ` . The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf / inner node with either another
* leaf / inner node or a proof sibling node , depending on whether each ` proofFlags ` item is true or false
* respectively .
*
* This version handles multiproofs in calldata with a custom hashing function .
*
* CAUTION : Not all Merkle trees admit multiproofs . To use multiproofs , it is sufficient to ensure that : 1 ) the tree
* is complete ( but not necessarily perfect ) , 2 ) the leaves to be proven are in the opposite order they are in the
* tree ( i . e . , as seen from right to left starting at the deepest layer and continuing at the next layer ) .
* /
function processMultiProofCalldata (
function processMultiProofCalldata (
bytes32 [ ] calldata proof ,
bytes32 [ ] calldata proof ,
bool [ ] calldata proofFlags ,
bool [ ] calldata proofFlags ,
bytes32 [ ] memory leaves
bytes32 [ ] calldata leaves ,
) internal pure returns ( bytes32 merkleRoot ) {
function ( bytes32 , bytes32 ) view returns ( bytes32 ) hasher
) internal view returns ( bytes32 merkleRoot ) {
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / This function rebuilds the root hash by traversing the tree up from the leaves . The root is rebuilt by
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / consuming and producing values on a queue . The queue starts with the ` leaves ` array , then goes onto the
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / ` hashes ` array . At the end of the process , the last hash in the ` hashes ` array should contain the root of
/ / the Merkle tree .
/ / the Merkle tree .
uint256 leavesLen = leaves . length ;
uint256 leavesLen = leaves . length ;
uint256 proofLen = proof . length ;
uint256 totalHashes = proofFlags . length ;
/ / Check proof validity .
/ / Check proof validity .
if ( leavesLen + proofLen != totalHashes + 1 ) {
if ( leavesLen + proof . length != proofFlags . length + 1 ) {
revert MerkleProofInvalidMultiproof ( ) ;
revert MerkleProofInvalidMultiproof ( ) ;
}
}
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / The xxxPos values are " pointers " to the next value to consume in each array . All accesses are done using
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
/ / ` xxx [ xxxPos ++ ] ` , which return the current value and increment the pointer , thus mimicking a queue ' s " pop " .
bytes32 [ ] memory hashes = new bytes32 [ ] ( totalHashes ) ;
bytes32 [ ] memory hashes = new bytes32 [ ] ( proofFlags . length ) ;
uint256 leafPos = 0 ;
uint256 leafPos = 0 ;
uint256 hashPos = 0 ;
uint256 hashPos = 0 ;
uint256 proofPos = 0 ;
uint256 proofPos = 0 ;
@ -191,20 +455,20 @@ library MerkleProof {
/ / get the next hash .
/ / get the next hash .
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / - depending on the flag , either another value from the " main queue " ( merging branches ) or an element from the
/ / ` proof ` array .
/ / ` proof ` array .
for ( uint256 i = 0 ; i < totalHashes ; i ++ ) {
for ( uint256 i = 0 ; i < proofFlags . length ; i ++ ) {
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 a = leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] ;
bytes32 b = proofFlags [ i ]
bytes32 b = proofFlags [ i ]
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
? ( leafPos < leavesLen ? leaves [ leafPos ++ ] : hashes [ hashPos ++ ] )
: proof [ proofPos ++ ] ;
: proof [ proofPos ++ ] ;
hashes [ i ] = Hashes . commutativeKeccak256 ( a , b ) ;
hashes [ i ] = hasher ( a , b ) ;
}
}
if ( totalHashes > 0 ) {
if ( proofFlags . length > 0 ) {
if ( proofPos != proofLen ) {
if ( proofPos != proof . length ) {
revert MerkleProofInvalidMultiproof ( ) ;
revert MerkleProofInvalidMultiproof ( ) ;
}
}
unchecked {
unchecked {
return hashes [ totalHashes - 1 ] ;
return hashes [ proofFlags . length - 1 ] ;
}
}
} else if ( leavesLen > 0 ) {
} else if ( leavesLen > 0 ) {
return leaves [ 0 ] ;
return leaves [ 0 ] ;