-
Notifications
You must be signed in to change notification settings - Fork 206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CertVerifier updates #1207
base: master
Are you sure you want to change the base?
CertVerifier updates #1207
Changes from 1 commit
531be14
ac3d33b
ca5fa9d
1067a70
325d9bd
9ee648b
f89d714
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,11 +32,13 @@ interface IEigenDACertVerifier is IEigenDAThresholdRegistry { | |
* @param batchHeader The batch header of the blob | ||
* @param blobInclusionInfo The inclusion proof for the blob cert | ||
* @param nonSignerStakesAndSignature The nonSignerStakesAndSignature to verify the blob cert against | ||
* @param signedQuorumNumbers The signed quorum numbers corresponding to the nonSignerStakesAndSignature | ||
*/ | ||
function verifyDACertV2( | ||
BatchHeaderV2 calldata batchHeader, | ||
BlobInclusionInfo calldata blobInclusionInfo, | ||
NonSignerStakesAndSignature calldata nonSignerStakesAndSignature | ||
NonSignerStakesAndSignature calldata nonSignerStakesAndSignature, | ||
bytes memory signedQuorumNumbers | ||
) external view; | ||
|
||
/** | ||
|
@@ -49,13 +51,29 @@ interface IEigenDACertVerifier is IEigenDAThresholdRegistry { | |
BlobInclusionInfo calldata blobInclusionInfo | ||
) external view; | ||
|
||
/** | ||
* @notice Thin try/catch wrapper around verifyDACertV2 that returns false instead of panicing | ||
* @dev The Steel library (https://github.com/risc0/risc0-ethereum/tree/main/crates/steel) | ||
* currently has a limitation that it can only create zk proofs for functions that return a value | ||
* @param batchHeader The batch header of the blob | ||
* @param blobInclusionInfo The inclusion proof for the blob cert | ||
* @param nonSignerStakesAndSignature The nonSignerStakesAndSignature to verify the blob cert against | ||
* @param signedQuorumNumbers The signed quorum numbers corresponding to the nonSignerStakesAndSignature | ||
*/ | ||
function verifyDACertV2ForZKProof( | ||
BatchHeaderV2 calldata batchHeader, | ||
BlobInclusionInfo calldata blobInclusionInfo, | ||
NonSignerStakesAndSignature calldata nonSignerStakesAndSignature, | ||
bytes memory signedQuorumNumbers | ||
) external view returns (bool); | ||
|
||
/** | ||
* @notice Returns the nonSignerStakesAndSignature for a given blob cert and signed batch | ||
* @param signedBatch The signed batch to get the nonSignerStakesAndSignature for | ||
*/ | ||
function getNonSignerStakesAndSignature( | ||
SignedBatch calldata signedBatch | ||
) external view returns (NonSignerStakesAndSignature memory); | ||
) external view returns (NonSignerStakesAndSignature memory, bytes memory); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you document what the second bytes param is being returned is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally by giving it a name here (can we do this?) |
||
|
||
/** | ||
* @notice Verifies the security parameters for a blob cert | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,7 +167,8 @@ library EigenDACertVerificationUtils { | |
BlobInclusionInfo memory blobInclusionInfo, | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature, | ||
SecurityThresholds memory securityThresholds, | ||
bytes memory requiredQuorumNumbers | ||
bytes memory requiredQuorumNumbers, | ||
bytes memory signedQuorumNumbers | ||
) internal view { | ||
require( | ||
Merkle.verifyInclusionKeccak( | ||
|
@@ -184,7 +185,7 @@ library EigenDACertVerificationUtils { | |
bytes32 signatoryRecordHash | ||
) = signatureVerifier.checkSignatures( | ||
EigenDAHasher.hashBatchHeaderV2(batchHeader), | ||
blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers, | ||
signedQuorumNumbers, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what was the issue exactly when quorumNumbers of the blob is strict subset of those in the batch? Guessing the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it right that signedQuorumNumber is based on quorum's from a batch, which contains all quorum for all blobs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be good to put a comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now yes, but doesn't necessarily have to be that way. sigma and this sigmaQuorumNumbers could be a subset of the actual batch signers, as long as it contains the quorums that the blob requested. see #1207 (comment) |
||
batchHeader.referenceBlockNumber, | ||
nonSignerStakesAndSignature | ||
); | ||
|
@@ -201,7 +202,7 @@ library EigenDACertVerificationUtils { | |
|
||
uint256 confirmedQuorumsBitmap; | ||
|
||
for (uint i = 0; i < blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers.length; i++) { | ||
for (uint i = 0; i < signedQuorumNumbers.length; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think we still only want to check the ones in the blobHeader here? Since those are the only quorums that the requester paid for and cares about |
||
require( | ||
quorumStakeTotals.signedStakeForQuorum[i] * THRESHOLD_DENOMINATOR >= | ||
quorumStakeTotals.totalStakeForQuorum[i] * securityThresholds.confirmationThreshold, | ||
|
@@ -210,16 +211,24 @@ library EigenDACertVerificationUtils { | |
|
||
confirmedQuorumsBitmap = BitmapUtils.setBit( | ||
confirmedQuorumsBitmap, | ||
uint8(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers[i]) | ||
uint8(signedQuorumNumbers[i]) | ||
); | ||
} | ||
|
||
require( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment above this saying something like: |
||
BitmapUtils.isSubsetOf( | ||
BitmapUtils.orderedBytesArrayToBitmap(requiredQuorumNumbers), | ||
BitmapUtils.orderedBytesArrayToBitmap(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers), | ||
confirmedQuorumsBitmap | ||
), | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: required quorums are not a subset of the confirmed quorums" | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: blob quorums are not a subset of the confirmed quorums" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message would be a lot more informative if it contained the actual quorum numbers that have not been signed. Is it possible to check each quorum one by one instead of checking the subset and having a generic error msg? |
||
); | ||
|
||
require( | ||
BitmapUtils.isSubsetOf( | ||
BitmapUtils.orderedBytesArrayToBitmap(requiredQuorumNumbers), | ||
BitmapUtils.orderedBytesArrayToBitmap(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers) | ||
), | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: required quorums are not a subset of the blob quorums" | ||
); | ||
} | ||
|
||
|
@@ -232,7 +241,8 @@ library EigenDACertVerificationUtils { | |
BlobInclusionInfo memory _blobInclusionInfo, | ||
NonSignerStakesAndSignature memory _nonSignerStakesAndSignature, | ||
SecurityThresholds memory _securityThresholds, | ||
bytes memory _requiredQuorumNumbers | ||
bytes memory _requiredQuorumNumbers, | ||
bytes memory _signedQuorumNumbers | ||
) external view { | ||
EigenDACertVerificationUtils._verifyDACertV2ForQuorums( | ||
_eigenDAThresholdRegistry, | ||
|
@@ -242,7 +252,8 @@ library EigenDACertVerificationUtils { | |
_blobInclusionInfo, | ||
_nonSignerStakesAndSignature, | ||
_securityThresholds, | ||
_requiredQuorumNumbers | ||
_requiredQuorumNumbers, | ||
_signedQuorumNumbers | ||
); | ||
} | ||
|
||
|
@@ -254,7 +265,8 @@ library EigenDACertVerificationUtils { | |
BlobInclusionInfo memory blobInclusionInfo, | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature, | ||
SecurityThresholds[] memory securityThresholds, | ||
bytes memory requiredQuorumNumbers | ||
bytes memory requiredQuorumNumbers, | ||
bytes memory signedQuorumNumbers | ||
) internal view { | ||
require( | ||
securityThresholds.length == blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers.length, | ||
|
@@ -276,7 +288,7 @@ library EigenDACertVerificationUtils { | |
bytes32 signatoryRecordHash | ||
) = signatureVerifier.checkSignatures( | ||
EigenDAHasher.hashBatchHeaderV2(batchHeader), | ||
blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers, | ||
signedQuorumNumbers, | ||
batchHeader.referenceBlockNumber, | ||
nonSignerStakesAndSignature | ||
); | ||
|
@@ -289,7 +301,7 @@ library EigenDACertVerificationUtils { | |
uint256 confirmedQuorumsBitmap; | ||
VersionedBlobParams memory blobParams = eigenDAThresholdRegistry.getBlobParams(blobInclusionInfo.blobCertificate.blobHeader.version); | ||
|
||
for (uint i = 0; i < blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers.length; i++) { | ||
for (uint i = 0; i < signedQuorumNumbers.length; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as above. Why do we have this same code duplicated in both functions btw? Can we refactor into an internal function shared by both? Otherwise someone might update one and forget to update the other one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also do we still need the function |
||
_verifyDACertSecurityParams( | ||
blobParams, | ||
securityThresholds[i] | ||
|
@@ -303,16 +315,24 @@ library EigenDACertVerificationUtils { | |
|
||
confirmedQuorumsBitmap = BitmapUtils.setBit( | ||
confirmedQuorumsBitmap, | ||
uint8(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers[i]) | ||
uint8(signedQuorumNumbers[i]) | ||
); | ||
} | ||
|
||
require( | ||
BitmapUtils.isSubsetOf( | ||
BitmapUtils.orderedBytesArrayToBitmap(requiredQuorumNumbers), | ||
BitmapUtils.orderedBytesArrayToBitmap(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers), | ||
confirmedQuorumsBitmap | ||
), | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: required quorums are not a subset of the confirmed quorums" | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: blob quorums are not a subset of the confirmed quorums" | ||
); | ||
|
||
require( | ||
BitmapUtils.isSubsetOf( | ||
BitmapUtils.orderedBytesArrayToBitmap(requiredQuorumNumbers), | ||
BitmapUtils.orderedBytesArrayToBitmap(blobInclusionInfo.blobCertificate.blobHeader.quorumNumbers) | ||
), | ||
"EigenDACertVerificationUtils._verifyDACertV2ForQuorums: required quorums are not a subset of the blob quorums" | ||
); | ||
} | ||
|
||
|
@@ -327,7 +347,10 @@ library EigenDACertVerificationUtils { | |
SecurityThresholds memory securityThresholds, | ||
bytes memory requiredQuorumNumbers | ||
) internal view { | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature = _getNonSignerStakesAndSignature( | ||
( | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature, | ||
bytes memory signedQuorumNumbers | ||
) = _getNonSignerStakesAndSignature( | ||
operatorStateRetriever, | ||
registryCoordinator, | ||
signedBatch | ||
|
@@ -341,7 +364,8 @@ library EigenDACertVerificationUtils { | |
blobInclusionInfo, | ||
nonSignerStakesAndSignature, | ||
securityThresholds, | ||
requiredQuorumNumbers | ||
requiredQuorumNumbers, | ||
signedQuorumNumbers | ||
); | ||
} | ||
|
||
|
@@ -356,7 +380,10 @@ library EigenDACertVerificationUtils { | |
SecurityThresholds[] memory securityThresholds, | ||
bytes memory requiredQuorumNumbers | ||
) internal view { | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature = _getNonSignerStakesAndSignature( | ||
( | ||
NonSignerStakesAndSignature memory nonSignerStakesAndSignature, | ||
bytes memory signedQuorumNumbers | ||
) = _getNonSignerStakesAndSignature( | ||
operatorStateRetriever, | ||
registryCoordinator, | ||
signedBatch | ||
|
@@ -370,29 +397,29 @@ library EigenDACertVerificationUtils { | |
blobInclusionInfo, | ||
nonSignerStakesAndSignature, | ||
securityThresholds, | ||
requiredQuorumNumbers | ||
requiredQuorumNumbers, | ||
signedQuorumNumbers | ||
); | ||
} | ||
|
||
function _getNonSignerStakesAndSignature( | ||
OperatorStateRetriever operatorStateRetriever, | ||
IRegistryCoordinator registryCoordinator, | ||
SignedBatch memory signedBatch | ||
) internal view returns (NonSignerStakesAndSignature memory nonSignerStakesAndSignature) { | ||
) internal view returns (NonSignerStakesAndSignature memory nonSignerStakesAndSignature, bytes memory signedQuorumNumbers) { | ||
bytes32[] memory nonSignerOperatorIds = new bytes32[](signedBatch.attestation.nonSignerPubkeys.length); | ||
for (uint i = 0; i < signedBatch.attestation.nonSignerPubkeys.length; ++i) { | ||
nonSignerOperatorIds[i] = BN254.hashG1Point(signedBatch.attestation.nonSignerPubkeys[i]); | ||
} | ||
|
||
bytes memory quorumNumbers; | ||
for (uint i = 0; i < signedBatch.attestation.quorumNumbers.length; ++i) { | ||
quorumNumbers = abi.encodePacked(quorumNumbers, uint8(signedBatch.attestation.quorumNumbers[i])); | ||
signedQuorumNumbers = abi.encodePacked(signedQuorumNumbers, uint8(signedBatch.attestation.quorumNumbers[i])); | ||
} | ||
|
||
OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( | ||
registryCoordinator, | ||
signedBatch.batchHeader.referenceBlockNumber, | ||
quorumNumbers, | ||
signedQuorumNumbers, | ||
nonSignerOperatorIds | ||
); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
intention is to let proxy to set those value for now, and later pulled from rollup config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like it is not the case, the signedQuorumNumbers is actually the all quorum for all blobs a batch, I think it makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what it currently is, but it doesn't NEED to be. As we discussed with Robert the GetBlobStatus endpoint could eventually be optimized to return a different signature for each blob request. I vote to rename
signedQuorumNumbers
tosigmaQuorumNumbers
so that the sigma name matches the sigma inside the NonSignerStakesAndSignature (sigma = signature)