Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/contracts/interfaces/IBN254CertificateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,18 @@ interface IBN254CertificateVerifierEvents is IBN254CertificateVerifierTypes {
event TableUpdated(OperatorSet operatorSet, uint32 referenceTimestamp, BN254OperatorSetInfo operatorSetInfo);
}

interface IBN254CertificateVerifierErrors {
///@notice thrown when operator index provided in certificate is invalid
error InvalidOperatorIndex();
}

/// @notice An interface for verifying BN254 certificates
/// @notice This implements the base `IBaseCertificateVerifier` interface
interface IBN254CertificateVerifier is IBN254CertificateVerifierEvents, IBaseCertificateVerifier {
interface IBN254CertificateVerifier is
IBN254CertificateVerifierEvents,
IBaseCertificateVerifier,
IBN254CertificateVerifierErrors
{
/**
* @notice updates the operator table
* @param operatorSet the operatorSet to update the operator table for
Expand Down
66 changes: 66 additions & 0 deletions src/contracts/libraries/Merkle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,70 @@ library Merkle {
//the first node in the layer is the root
return layer[0];
}

/**
* @notice this function returns the merkle root of a tree created from a set of leaves using keccak as its hash function
* @param leaves the leaves of the merkle tree
* @return The computed Merkle root of the tree.
*/
function merkleizeKeccak(
bytes32[] memory leaves
) internal pure returns (bytes32) {
// TODO: very inefficient, use ZERO_HASHES
// pad to the next power of 2
uint256 numNodesInLayer = 1;
while (numNodesInLayer < leaves.length) {
numNodesInLayer *= 2;
}
bytes32[] memory layer = new bytes32[](numNodesInLayer);
for (uint256 i = 0; i < leaves.length; i++) {
layer[i] = leaves[i];
}

//while we haven't computed the root
while (numNodesInLayer != 1) {
uint256 numNodesInNextLayer = numNodesInLayer / 2;
//overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < numNodesInNextLayer; i++) {
layer[i] = keccak256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
}
//the next layer above has half as many nodes
numNodesInLayer = numNodesInNextLayer;
}
//the first node in the layer is the root
return layer[0];
}

function getProofKeccak(bytes32[] memory leaves, uint256 index) internal pure returns (bytes memory proof) {
// TODO: very inefficient, use ZERO_HASHES
// pad to the next power of 2
uint256 numNodesInLayer = 1;
while (numNodesInLayer < leaves.length) {
numNodesInLayer *= 2;
}
bytes32[] memory layer = new bytes32[](numNodesInLayer);
for (uint256 i = 0; i < leaves.length; i++) {
layer[i] = leaves[i];
}

//while we haven't computed the root
while (numNodesInLayer != 1) {
//overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < layer.length; i++) {
if (i == index) {
uint256 siblingIndex = i + 1 - 2 * (i % 2);
proof = abi.encodePacked(proof, layer[siblingIndex]);
index /= 2;
}
}

uint256 numNodesInNextLayer = numNodesInLayer / 2;
//overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < numNodesInNextLayer; i++) {
layer[i] = keccak256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
}
//the next layer above has half as many nodes
numNodesInLayer = numNodesInNextLayer;
}
}
}
Loading
Loading