Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
142 changes: 114 additions & 28 deletions pkg/bindings/BN254CertificateVerifier/binding.go

Large diffs are not rendered by default.

140 changes: 139 additions & 1 deletion pkg/bindings/BN254CertificateVerifierStorage/binding.go

Large diffs are not rendered by default.

97 changes: 95 additions & 2 deletions pkg/bindings/ECDSACertificateVerifier/binding.go

Large diffs are not rendered by default.

126 changes: 125 additions & 1 deletion pkg/bindings/ECDSACertificateVerifierStorage/binding.go

Large diffs are not rendered by default.

580 changes: 580 additions & 0 deletions pkg/bindings/ECDSATableCalculator/binding.go

Large diffs are not rendered by default.

496 changes: 496 additions & 0 deletions pkg/bindings/ECDSATableCalculatorBase/binding.go

Large diffs are not rendered by default.

140 changes: 139 additions & 1 deletion pkg/bindings/IBN254CertificateVerifier/binding.go

Large diffs are not rendered by default.

126 changes: 125 additions & 1 deletion pkg/bindings/IECDSACertificateVerifier/binding.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/bindings/OperatorTableUpdater/binding.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion script/deploy/devnet/mutlichain/deploy_multichain_l2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract DeployMultichain_L2 is Script, Test {
operatorTableUpdaterImplementation = new OperatorTableUpdater(
bn254CertificateVerifier, IECDSACertificateVerifier(address(emptyContract)), "0.0.1"
);
bn254CertificateVerifierImplementation = new BN254CertificateVerifier(operatorTableUpdater);
bn254CertificateVerifierImplementation = new BN254CertificateVerifier(operatorTableUpdater, "1.0.0");

// Third, upgrade the proxies to point to the new implementations
proxyAdmin.upgrade(
Expand Down
56 changes: 55 additions & 1 deletion src/contracts/interfaces/IBN254CertificateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IBN254CertificateVerifierTypes is IBN254TableCalculatorTypes {
* @notice A witness for an operator
* @param operatorIndex the index of the nonsigner in the `BN254OperatorInfo` tree
* @param operatorInfoProofs merkle proofs of the nonsigner at the index. Empty if operator is in cache.
* @param operatorInfo the `BN254OperatorInfo` for the operator
* @param operatorInfo the `BN254OperatorInfo` for the operator. Empty if operator is in cache
*/
struct BN254OperatorInfoWitness {
uint32 operatorIndex;
Expand Down Expand Up @@ -110,4 +110,58 @@ interface IBN254CertificateVerifier is
BN254Certificate memory cert,
uint256[] memory totalStakeNominalThresholds
) external returns (bool);

/**
* @notice Attempts signature verification with gas limit for safety
* @param msgHash The message hash that was signed
* @param aggPubkey The aggregate public key of signers
* @param apkG2 The G2 point representation of the aggregate public key
* @param signature The BLS signature to verify
* @return pairingSuccessful Whether the pairing operation completed successfully
* @return signatureValid Whether the signature is valid
*/
function trySignatureVerification(
bytes32 msgHash,
BN254.G1Point memory aggPubkey,
BN254.G2Point memory apkG2,
BN254.G1Point memory signature
) external view returns (bool pairingSuccessful, bool signatureValid);

/**
* @notice Get cached nonsigner operator info
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @param operatorIndex The operator index
* @return The cached operator info
* @dev If the operator is not in the cache, the operator info will be empty
*/
function getNonsignerOperatorInfo(
OperatorSet memory operatorSet,
uint32 referenceTimestamp,
uint256 operatorIndex
) external view returns (BN254OperatorInfo memory);

/**
* @notice Check if a nonsigner is cached
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @param operatorIndex The operator index
* @return Whether the operator is cached
*/
function isNonsignerCached(
OperatorSet memory operatorSet,
uint32 referenceTimestamp,
uint256 operatorIndex
) external view returns (bool);

/**
* @notice Get operator set info for a timestamp
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @return The operator set info
*/
function getOperatorSetInfo(
OperatorSet memory operatorSet,
uint32 referenceTimestamp
) external view returns (BN254OperatorSetInfo memory);
}
125 changes: 66 additions & 59 deletions src/contracts/multichain/BN254CertificateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ pragma solidity ^0.8.27;

import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";

import {BN254} from "../libraries/BN254.sol";
import {BN254SignatureVerifier} from "../libraries/BN254SignatureVerifier.sol";
import {Merkle} from "../libraries/Merkle.sol";
import {OperatorSet} from "../libraries/OperatorSetLib.sol";

import "../libraries/BN254.sol";
import "../libraries/BN254SignatureVerifier.sol";
import "../libraries/Merkle.sol";
import "../libraries/OperatorSetLib.sol";
import "../mixins/SemVerMixin.sol";
import "./BN254CertificateVerifierStorage.sol";

/**
Expand All @@ -16,7 +16,7 @@ import "./BN254CertificateVerifierStorage.sol";
* @dev This contract uses BN254 curves for signature verification and
* caches operator information for efficient verification
*/
contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStorage {
contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStorage, SemVerMixin {
using Merkle for bytes;
using BN254 for BN254.G1Point;

Expand All @@ -42,36 +42,20 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
* @notice Constructor for the certificate verifier
* @dev Disables initializers to prevent implementation initialization
* @param _operatorTableUpdater Address authorized to update operator tables
* @param _version The semantic version of the contract
*/
constructor(
IOperatorTableUpdater _operatorTableUpdater
) BN254CertificateVerifierStorage(_operatorTableUpdater) {
IOperatorTableUpdater _operatorTableUpdater,
string memory _version
) BN254CertificateVerifierStorage(_operatorTableUpdater) SemVerMixin(_version) {
_disableInitializers();
}

///@inheritdoc IBaseCertificateVerifier
function getOperatorSetOwner(
OperatorSet memory operatorSet
) external view returns (address) {
bytes32 operatorSetKey = operatorSet.key();
return _operatorSetOwners[operatorSetKey];
}

///@inheritdoc IBaseCertificateVerifier
function maxOperatorTableStaleness(
OperatorSet memory operatorSet
) external view returns (uint32) {
bytes32 operatorSetKey = operatorSet.key();
return _maxStalenessPeriods[operatorSetKey];
}

///@inheritdoc IBaseCertificateVerifier
function latestReferenceTimestamp(
OperatorSet memory operatorSet
) external view returns (uint32) {
bytes32 operatorSetKey = operatorSet.key();
return _latestReferenceTimestamps[operatorSetKey];
}
/**
*
* EXTERNAL FUNCTIONS
*
*/

///@inheritdoc IBN254CertificateVerifier
function updateOperatorTable(
Expand Down Expand Up @@ -148,21 +132,13 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
return true;
}

/**
* @notice Attempts signature verification with gas limit for safety
* @param msgHash The message hash that was signed
* @param aggPubkey The aggregate public key of signers
* @param apkG2 The G2 point representation of the aggregate public key
* @param signature The BLS signature to verify
* @return pairingSuccessful Whether the pairing operation completed successfully
* @return signatureValid Whether the signature is valid
*/
///@inheritdoc IBN254CertificateVerifier
function trySignatureVerification(
bytes32 msgHash,
BN254.G1Point memory aggPubkey,
BN254.G2Point memory apkG2,
BN254.G1Point memory signature
) internal view returns (bool pairingSuccessful, bool signatureValid) {
) public view returns (bool pairingSuccessful, bool signatureValid) {
return BN254SignatureVerifier.verifySignature(
msgHash,
signature,
Expand All @@ -173,6 +149,12 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
);
}

/**
*
* INTERNAL FUNCTIONS
*
*/

/**
* @notice Internal function to verify a certificate
* @param operatorSet The operator set the certificate is for
Expand Down Expand Up @@ -232,7 +214,7 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
require(witness.operatorIndex < ctx.operatorSetInfo.numOperators, InvalidOperatorIndex());

BN254OperatorInfo memory operatorInfo =
_getOrCacheOperatorInfo(ctx.operatorSetKey, cert.referenceTimestamp, witness);
_getOrCacheNonsignerOperatorInfo(ctx.operatorSetKey, cert.referenceTimestamp, witness);

nonSignerApk = nonSignerApk.plus(operatorInfo.pubkey);

Expand All @@ -252,12 +234,12 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
* @param witness The operator info witness containing proof data
* @return operatorInfo The verified operator information
*/
function _getOrCacheOperatorInfo(
function _getOrCacheNonsignerOperatorInfo(
bytes32 operatorSetKey,
uint32 referenceTimestamp,
BN254OperatorInfoWitness memory witness
) internal returns (BN254OperatorInfo memory operatorInfo) {
BN254OperatorInfo storage cachedInfo = _operatorInfos[operatorSetKey][referenceTimestamp][witness.operatorIndex];
BN254OperatorInfo memory cachedInfo = _operatorInfos[operatorSetKey][referenceTimestamp][witness.operatorIndex];

// Check if operator info is cached using pubkey existence (weights can be 0)
bool isInfoCached = (cachedInfo.pubkey.X != 0 || cachedInfo.pubkey.Y != 0);
Expand Down Expand Up @@ -317,13 +299,13 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
}

/**
* @notice Get cached operator info
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @param operatorIndex The operator index
* @return The cached operator info
*
* VIEW FUNCTIONS
*
*/
function getOperatorInfo(

///@inheritdoc IBN254CertificateVerifier
function getNonsignerOperatorInfo(
OperatorSet memory operatorSet,
uint32 referenceTimestamp,
uint256 operatorIndex
Expand All @@ -332,12 +314,19 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
return _operatorInfos[operatorSetKey][referenceTimestamp][operatorIndex];
}

/**
* @notice Get operator set info for a timestamp
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @return The operator set info
*/
///@inheritdoc IBN254CertificateVerifier
function isNonsignerCached(
OperatorSet memory operatorSet,
uint32 referenceTimestamp,
uint256 operatorIndex
) external view returns (bool) {
bytes32 operatorSetKey = operatorSet.key();
BN254OperatorInfo memory operatorInfo = _operatorInfos[operatorSetKey][referenceTimestamp][operatorIndex];
// Check if operator info is cached using pubkey existence (weights can be 0)
return operatorInfo.pubkey.X != 0 && operatorInfo.pubkey.Y != 0;
}

///@inheritdoc IBN254CertificateVerifier
function getOperatorSetInfo(
OperatorSet memory operatorSet,
uint32 referenceTimestamp
Expand All @@ -346,9 +335,27 @@ contract BN254CertificateVerifier is Initializable, BN254CertificateVerifierStor
return _operatorSetInfos[operatorSetKey][referenceTimestamp];
}

/// @dev Only used in a test environment
function setMaxStalenessPeriod(OperatorSet memory operatorSet, uint32 maxStalenessPeriod) external {
///@inheritdoc IBaseCertificateVerifier
function getOperatorSetOwner(
OperatorSet memory operatorSet
) external view returns (address) {
bytes32 operatorSetKey = operatorSet.key();
return _operatorSetOwners[operatorSetKey];
}

///@inheritdoc IBaseCertificateVerifier
function maxOperatorTableStaleness(
OperatorSet memory operatorSet
) external view returns (uint32) {
bytes32 operatorSetKey = operatorSet.key();
_maxStalenessPeriods[operatorSetKey] = maxStalenessPeriod;
return _maxStalenessPeriods[operatorSetKey];
}

///@inheritdoc IBaseCertificateVerifier
function latestReferenceTimestamp(
OperatorSet memory operatorSet
) external view returns (uint32) {
bytes32 operatorSetKey = operatorSet.key();
return _latestReferenceTimestamps[operatorSetKey];
}
}
13 changes: 13 additions & 0 deletions src/test/mocks/CrossChainRegistryMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import "forge-std/Test.sol";

import "src/contracts/multichain/CrossChainRegistry.sol";

contract CrossChainRegistryMock is Test, ICrossChainRegistryTypes {
using OperatorSetLib for OperatorSet;

receive() external payable {}
fallback() external payable {}
}
10 changes: 10 additions & 0 deletions src/test/mocks/OperatorTableUpdaterMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import "forge-std/Test.sol";
import "src/contracts/interfaces/IOperatorTableUpdater.sol";

contract OperatorTableUpdaterMock is Test {
receive() external payable {}
fallback() external payable {}
}
56 changes: 56 additions & 0 deletions src/test/tree/BN254CertificateVerifier.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.
└── BN254CertificateVerifier (**** denotes that integration tests are needed to fully validate path)
├── when updateOperatorTable is called
│ ├── given that the caller is not the table updater
│ │ └── it should revert
│ ├── given that the reference timestamp is not greater than the latest
│ │ └── it should revert
│ └── given that all parameters are valid
│ └── it should update operator set info, timestamp, owner, and staleness period & emit event
├── when verifyCertificate is called
│ ├── given that the reference timestamp does not exist
│ │ └── it should revert
│ ├── given that the certificate is stale
│ │ └── it should revert
│ ├── given that a non-signer witness has invalid operator index
│ │ └── it should revert
│ ├── given that a non-signer witness has invalid merkle proof
│ │ └── it should revert
│ ├── given that the signature is invalid
│ │ └── it should revert
│ ├── given that all operators are signers
│ │ └── it should return full stake amounts
│ ├── given that some operators are non-signers
│ │ └── it should deduct non-signer stakes from total
│ └── given that operator info is not cached
│ └── it should cache operator info after verification
├── when verifyCertificateProportion is called
│ ├── given that array lengths mismatch
│ │ └── it should revert
│ ├── given that the certificate meets thresholds
│ │ └── it should return true
│ └── given that the certificate does not meet thresholds
│ └── it should return false
├── when verifyCertificateNominal is called
│ ├── given that array lengths mismatch
│ │ └── it should revert
│ ├── given that the certificate meets thresholds
│ │ └── it should return true
│ └── given that the certificate does not meet thresholds
│ └── it should return false
├── when trySignatureVerification is called
│ ├── given a valid signature
│ │ └── it should return pairing successful and signature valid
│ └── given an invalid signature
│ └── it should return pairing successful and signature invalid
└── when view functions are called
├── getOperatorSetOwner
│ └── it should return the correct owner address
├── maxOperatorTableStaleness
│ └── it should return the correct staleness period
├── latestReferenceTimestamp
│ └── it should return the latest timestamp
├── getOperatorSetInfo
│ └── it should return the correct operator set info
└── getOperatorInfo
└── it should return the cached operator info
Loading
Loading