@@ -134,6 +134,10 @@ contract TaskMailbox is
134134 // Calculate the AVS fee using the task hook
135135 uint96 avsFee = taskConfig.taskHook.calculateTaskFee (taskParams);
136136
137+ // Get the operator table reference timestamp
138+ uint32 operatorTableReferenceTimestamp = IBaseCertificateVerifier (_getCertificateVerifier (taskConfig.curveType))
139+ .latestReferenceTimestamp (taskParams.executorOperatorSet);
140+
137141 bytes32 taskHash = keccak256 (abi.encode (_globalTaskCount, address (this ), block .chainid , taskParams));
138142 _globalTaskCount = _globalTaskCount + 1 ;
139143
@@ -147,6 +151,7 @@ contract TaskMailbox is
147151 feeSplit,
148152 TaskStatus.CREATED,
149153 false , // isFeeRefunded
154+ operatorTableReferenceTimestamp,
150155 taskConfig,
151156 taskParams.payload,
152157 bytes ("" ),
@@ -168,6 +173,7 @@ contract TaskMailbox is
168173 taskHash,
169174 taskParams.executorOperatorSet.avs,
170175 taskParams.executorOperatorSet.id,
176+ operatorTableReferenceTimestamp,
171177 taskParams.refundCollector,
172178 avsFee,
173179 block .timestamp + taskConfig.taskSLA,
@@ -194,6 +200,8 @@ contract TaskMailbox is
194200 task.executorOperatorSetTaskConfig.curveType,
195201 task.executorOperatorSetTaskConfig.consensus,
196202 executorOperatorSet,
203+ task.operatorTableReferenceTimestamp,
204+ keccak256 (result),
197205 executorCert
198206 );
199207 require (isCertificateValid, CertificateVerificationFailed ());
@@ -320,6 +328,23 @@ contract TaskMailbox is
320328 emit ExecutorOperatorSetRegistered (msg .sender , operatorSet.avs, operatorSet.id, isRegistered);
321329 }
322330
331+ /**
332+ * @notice Gets the certificate verifier for a given curve type
333+ * @param curveType The curve type to get the certificate verifier for
334+ * @return The address of the certificate verifier
335+ */
336+ function _getCertificateVerifier (
337+ IKeyRegistrarTypes.CurveType curveType
338+ ) internal view returns (address ) {
339+ if (curveType == IKeyRegistrarTypes.CurveType.BN254) {
340+ return BN254_CERTIFICATE_VERIFIER;
341+ } else if (curveType == IKeyRegistrarTypes.CurveType.ECDSA) {
342+ return ECDSA_CERTIFICATE_VERIFIER;
343+ } else {
344+ revert InvalidCurveType ();
345+ }
346+ }
347+
323348 /**
324349 * @notice Validates that the caller is the owner of the operator set
325350 * @param operatorSet The operator set to validate ownership for
@@ -329,14 +354,7 @@ contract TaskMailbox is
329354 OperatorSet memory operatorSet ,
330355 IKeyRegistrarTypes.CurveType curveType
331356 ) internal view {
332- address certificateVerifier;
333- if (curveType == IKeyRegistrarTypes.CurveType.BN254) {
334- certificateVerifier = BN254_CERTIFICATE_VERIFIER;
335- } else if (curveType == IKeyRegistrarTypes.CurveType.ECDSA) {
336- certificateVerifier = ECDSA_CERTIFICATE_VERIFIER;
337- } else {
338- revert InvalidCurveType ();
339- }
357+ address certificateVerifier = _getCertificateVerifier (curveType);
340358
341359 require (
342360 IBaseCertificateVerifier (certificateVerifier).getOperatorSetOwner (operatorSet) == msg .sender ,
@@ -366,13 +384,17 @@ contract TaskMailbox is
366384 * @param curveType The curve type used for signature verification
367385 * @param consensus The consensus configuration
368386 * @param executorOperatorSet The executor operator set
387+ * @param operatorTableReferenceTimestamp The reference timestamp of the operator table
388+ * @param resultHash The hash of the result of the task
369389 * @param executorCert The executor certificate to verify
370390 * @return isCertificateValid Whether the certificate is valid
371391 */
372392 function _verifyExecutorCertificate (
373393 IKeyRegistrarTypes.CurveType curveType ,
374394 Consensus memory consensus ,
375395 OperatorSet memory executorOperatorSet ,
396+ uint32 operatorTableReferenceTimestamp ,
397+ bytes32 resultHash ,
376398 bytes memory executorCert
377399 ) internal returns (bool isCertificateValid ) {
378400 if (consensus.consensusType == ConsensusType.STAKE_PROPORTION_THRESHOLD) {
@@ -387,7 +409,9 @@ contract TaskMailbox is
387409 IBN254CertificateVerifierTypes.BN254Certificate memory bn254Cert =
388410 abi.decode (executorCert, (IBN254CertificateVerifierTypes.BN254Certificate));
389411
390- // Validate that the certificate has a non-empty signature
412+ // Validate the certificate
413+ require (bn254Cert.referenceTimestamp == operatorTableReferenceTimestamp, InvalidReferenceTimestamp ());
414+ require (bn254Cert.messageHash == resultHash, InvalidMessageHash ());
391415 require (bn254Cert.signature.X != 0 && bn254Cert.signature.Y != 0 , EmptyCertificateSignature ());
392416
393417 isCertificateValid = IBN254CertificateVerifier (BN254_CERTIFICATE_VERIFIER).verifyCertificateProportion (
@@ -398,7 +422,15 @@ contract TaskMailbox is
398422 IECDSACertificateVerifierTypes.ECDSACertificate memory ecdsaCert =
399423 abi.decode (executorCert, (IECDSACertificateVerifierTypes.ECDSACertificate));
400424
401- // Validate that the certificate has a non-empty signature
425+ // Validate the certificate
426+ require (ecdsaCert.referenceTimestamp == operatorTableReferenceTimestamp, InvalidReferenceTimestamp ());
427+ require (
428+ ecdsaCert.messageHash
429+ == IECDSACertificateVerifier (ECDSA_CERTIFICATE_VERIFIER).calculateCertificateDigest (
430+ ecdsaCert.referenceTimestamp, resultHash
431+ ),
432+ InvalidMessageHash ()
433+ );
402434 require (ecdsaCert.sig.length > 0 , EmptyCertificateSignature ());
403435
404436 (isCertificateValid,) = IECDSACertificateVerifier (ECDSA_CERTIFICATE_VERIFIER)
@@ -439,6 +471,7 @@ contract TaskMailbox is
439471 task.feeSplit,
440472 _getTaskStatus (task),
441473 task.isFeeRefunded,
474+ task.operatorTableReferenceTimestamp,
442475 task.executorOperatorSetTaskConfig,
443476 task.payload,
444477 task.executorCert,
0 commit comments