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
46 changes: 46 additions & 0 deletions src/contracts/interfaces/IECDSACertificateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,50 @@ interface IECDSACertificateVerifier is IECDSACertificateVerifierEvents, IBaseCer
ECDSACertificate memory cert,
uint256[] memory totalStakeNominalThresholds
) external returns (bool);

/**
* @notice Get operator infos for a timestamp
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @return The operator infos
*/
function getOperatorInfos(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp
) external view returns (ECDSAOperatorInfo[] memory);

/**
* @notice Get a single operator info by index
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @param operatorIndex The index of the operator
* @return The operator info
*/
function getOperatorInfo(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp,
uint32 operatorIndex
) external view returns (ECDSAOperatorInfo memory);

/**
* @notice Get the total number of operators for a given reference timestamp
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @return The number of operators
*/
function getOperatorCount(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp
) external view returns (uint32);

/**
* @notice Get the total stakes for all operators at a given reference timestamp
* @param operatorSet The operator set to calculate stakes for
* @param referenceTimestamp The reference timestamp
* @return totalStakes The total stakes for all operators
*/
function getTotalStakes(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp
) external view returns (uint256[] memory);
}
188 changes: 99 additions & 89 deletions src/contracts/multichain/ECDSACertificateVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,104 @@ contract ECDSACertificateVerifier is Initializable, ECDSACertificateVerifierStor
emit TableUpdated(operatorSet, referenceTimestamp, operatorInfos);
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificate(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert
) external view returns (uint256[] memory) {
return _verifyECDSACertificate(operatorSet, cert);
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificateProportion(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert,
uint16[] calldata totalStakeProportionThresholds
) external view returns (bool) {
uint256[] memory signedStakes = _verifyECDSACertificate(operatorSet, cert);
uint256[] memory totalStakes = getTotalStakes(operatorSet, cert.referenceTimestamp);
require(signedStakes.length == totalStakeProportionThresholds.length, ArrayLengthMismatch());
for (uint256 i = 0; i < signedStakes.length; i++) {
uint256 threshold = (totalStakes[i] * totalStakeProportionThresholds[i]) / 10_000;
if (signedStakes[i] < threshold) {
return false;
}
}
return true;
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificateNominal(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert,
uint256[] memory totalStakeNominalThresholds
) external view returns (bool) {
uint256[] memory signedStakes = _verifyECDSACertificate(operatorSet, cert);
if (signedStakes.length != totalStakeNominalThresholds.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < signedStakes.length; i++) {
if (signedStakes[i] < totalStakeNominalThresholds[i]) {
return false;
}
}
return true;
}

/// @inheritdoc IECDSACertificateVerifier
function getOperatorInfos(
OperatorSet memory operatorSet,
uint32 referenceTimestamp
) external view returns (ECDSAOperatorInfo[] memory) {
bytes32 operatorSetKey = operatorSet.key();
uint32 numOperators = uint32(_numOperators[operatorSetKey][referenceTimestamp]);
ECDSAOperatorInfo[] memory operatorInfos = new ECDSAOperatorInfo[](numOperators);

for (uint32 i = 0; i < numOperators; i++) {
operatorInfos[i] = _operatorInfos[operatorSetKey][referenceTimestamp][i];
}

return operatorInfos;
}

/// @inheritdoc IECDSACertificateVerifier
function getOperatorInfo(
OperatorSet memory operatorSet,
uint32 referenceTimestamp,
uint32 operatorIndex
) external view returns (ECDSAOperatorInfo memory) {
bytes32 operatorSetKey = operatorSet.key();
require(operatorIndex < _numOperators[operatorSetKey][referenceTimestamp], "Operator index out of bounds");
return _operatorInfos[operatorSetKey][referenceTimestamp][operatorIndex];
}

/// @inheritdoc IECDSACertificateVerifier
function getOperatorCount(
OperatorSet memory operatorSet,
uint32 referenceTimestamp
) external view returns (uint32) {
bytes32 operatorSetKey = operatorSet.key();
return uint32(_numOperators[operatorSetKey][referenceTimestamp]);
}

/// @inheritdoc IECDSACertificateVerifier
function getTotalStakes(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp
) public view returns (uint256[] memory) {
bytes32 operatorSetKey = operatorSet.key();
require(_latestReferenceTimestamps[operatorSetKey] == referenceTimestamp, ReferenceTimestampDoesNotExist());
uint256 operatorCount = _numOperators[operatorSetKey][referenceTimestamp];
require(operatorCount > 0, ReferenceTimestampDoesNotExist());
uint256 stakeTypesCount = _operatorInfos[operatorSetKey][referenceTimestamp][0].weights.length;
uint256[] memory totalStakes = new uint256[](stakeTypesCount);
for (uint256 i = 0; i < operatorCount; i++) {
uint256[] memory weights = _operatorInfos[operatorSetKey][referenceTimestamp][uint32(i)].weights;
for (uint256 j = 0; j < weights.length && j < stakeTypesCount; j++) {
totalStakes[j] += weights[j];
}
}
return totalStakes;
}

/**
* @notice Internal function to verify a certificate
* @param cert The certificate to verify
Expand All @@ -134,7 +232,7 @@ contract ECDSACertificateVerifier is Initializable, ECDSACertificateVerifierStor
require(_latestReferenceTimestamps[operatorSetKey] == cert.referenceTimestamp, ReferenceTimestampDoesNotExist());

// Get the total stakes
uint256[] memory totalStakes = _getTotalStakes(operatorSet, cert.referenceTimestamp);
uint256[] memory totalStakes = getTotalStakes(operatorSet, cert.referenceTimestamp);
uint256[] memory signedStakes = new uint256[](totalStakes.length);

// Compute the EIP-712 digest for signature recovery
Expand Down Expand Up @@ -175,48 +273,6 @@ contract ECDSACertificateVerifier is Initializable, ECDSACertificateVerifierStor
return signedStakes;
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificate(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert
) external view returns (uint256[] memory) {
return _verifyECDSACertificate(operatorSet, cert);
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificateProportion(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert,
uint16[] calldata totalStakeProportionThresholds
) external view returns (bool) {
uint256[] memory signedStakes = _verifyECDSACertificate(operatorSet, cert);
uint256[] memory totalStakes = _getTotalStakes(operatorSet, cert.referenceTimestamp);
require(signedStakes.length == totalStakeProportionThresholds.length, ArrayLengthMismatch());
for (uint256 i = 0; i < signedStakes.length; i++) {
uint256 threshold = (totalStakes[i] * totalStakeProportionThresholds[i]) / 10_000;
if (signedStakes[i] < threshold) {
return false;
}
}
return true;
}

///@inheritdoc IECDSACertificateVerifier
function verifyCertificateNominal(
OperatorSet calldata operatorSet,
ECDSACertificate calldata cert,
uint256[] memory totalStakeNominalThresholds
) external view returns (bool) {
uint256[] memory signedStakes = _verifyECDSACertificate(operatorSet, cert);
if (signedStakes.length != totalStakeNominalThresholds.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < signedStakes.length; i++) {
if (signedStakes[i] < totalStakeNominalThresholds[i]) {
return false;
}
}
return true;
}

/**
* @notice Parse signatures from the concatenated signature bytes
* @param messageHash The message hash that was signed
Expand Down Expand Up @@ -261,50 +317,4 @@ contract ECDSACertificateVerifier is Initializable, ECDSACertificateVerifierStor

return (signers, true);
}

/**
* @notice Get operator infos for a timestamp
* @param operatorSet The operator set
* @param referenceTimestamp The reference timestamp
* @return The operator infos
*/
function getOperatorInfos(
OperatorSet memory operatorSet,
uint32 referenceTimestamp
) external view returns (ECDSAOperatorInfo[] memory) {
bytes32 operatorSetKey = operatorSet.key();
uint32 numOperators = uint32(_numOperators[operatorSetKey][referenceTimestamp]);
ECDSAOperatorInfo[] memory operatorInfos = new ECDSAOperatorInfo[](numOperators);

for (uint32 i = 0; i < numOperators; i++) {
operatorInfos[i] = _operatorInfos[operatorSetKey][referenceTimestamp][i];
}

return operatorInfos;
}

/**
* @notice Calculate the total stakes for all operators at a given reference timestamp
* @param operatorSet The operator set to calculate stakes for
* @param referenceTimestamp The reference timestamp
* @return totalStakes The total stakes for all operators
*/
function _getTotalStakes(
OperatorSet calldata operatorSet,
uint32 referenceTimestamp
) internal view returns (uint256[] memory totalStakes) {
bytes32 operatorSetKey = operatorSet.key();
require(_latestReferenceTimestamps[operatorSetKey] == referenceTimestamp, ReferenceTimestampDoesNotExist());
uint256 operatorCount = _numOperators[operatorSetKey][referenceTimestamp];
require(operatorCount > 0, ReferenceTimestampDoesNotExist());
uint256 stakeTypesCount = _operatorInfos[operatorSetKey][referenceTimestamp][0].weights.length;
totalStakes = new uint256[](stakeTypesCount);
for (uint256 i = 0; i < operatorCount; i++) {
uint256[] memory weights = _operatorInfos[operatorSetKey][referenceTimestamp][uint32(i)].weights;
for (uint256 j = 0; j < weights.length && j < stakeTypesCount; j++) {
totalStakes[j] += weights[j];
}
}
return totalStakes;
}
}