@@ -19,6 +19,12 @@ contract CertManager is ICertManager {
1919 using LibBytes for bytes ;
2020
2121 event CertVerified (bytes32 indexed certHash );
22+ event CertHashCached (bytes32 indexed certHash );
23+
24+ // Cached SHA-384 hashes for certificate TBS data, keyed by keccak256(cert).
25+ // Allows splitting the expensive SHA-384 + ECDSA384.verify across two transactions
26+ // to stay within the EIP-7825 per-transaction gas limit (2^24 gas).
27+ mapping (bytes32 => bytes ) public certSha384Cache;
2228
2329 // root CA certificate constants (don't store it to reduce contract size)
2430 bytes32 public constant ROOT_CA_CERT_HASH = 0x311d96fcd5c5e0ccf72ef548e2ea7d4c0cd53ad7c4cc49e67471aed41d61f185 ;
@@ -61,6 +67,21 @@ contract CertManager is ICertManager {
6167 );
6268 }
6369
70+ /// @notice Pre-computes and caches the SHA-384 hash of a certificate's TBS (to-be-signed) data.
71+ /// @dev Call this in a separate transaction before verifyCACert/verifyClientCert to split
72+ /// the gas cost. Necessary on networks with per-transaction gas limits (e.g. EIP-7825).
73+ /// @param cert The DER-encoded certificate.
74+ function cacheCertHash (bytes memory cert ) external {
75+ bytes32 key = keccak256 (cert);
76+ require (certSha384Cache[key].length == 0 , "cert hash already cached " );
77+
78+ Asn1Ptr root = cert.root ();
79+ Asn1Ptr tbsCertPtr = cert.firstChildOf (root);
80+ certSha384Cache[key] = Sha2Ext.sha384 (cert, tbsCertPtr.header (), tbsCertPtr.totalLength ());
81+
82+ emit CertHashCached (key);
83+ }
84+
6485 function verifyCACert (bytes memory cert , bytes32 parentCertHash ) external returns (bytes32 ) {
6586 bytes32 certHash = keccak256 (cert);
6687 _verifyCert (cert, certHash, true , _loadVerified (parentCertHash));
@@ -271,11 +292,11 @@ contract CertManager is ICertManager {
271292 }
272293 }
273294
274- function _verifyCertSignature (bytes memory certificate , Asn1Ptr ptr , bytes memory pubKey ) internal view {
295+ function _verifyCertSignature (bytes memory certificate , Asn1Ptr ptr , bytes memory pubKey ) internal {
275296 Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (ptr);
276297 require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
277298
278- bytes memory hash = Sha2Ext. sha384 (certificate, ptr. header (), ptr. totalLength () );
299+ bytes memory hash = _getOrComputeCertHash (certificate, ptr);
279300
280301 Asn1Ptr sigPtr = certificate.nextSiblingOf (sigAlgoPtr);
281302 Asn1Ptr sigBPtr = certificate.bitstring (sigPtr);
@@ -289,6 +310,18 @@ contract CertManager is ICertManager {
289310 _verifySignature (pubKey, hash, sigPacked);
290311 }
291312
313+ /// @dev Returns the cached SHA-384 hash if available, otherwise computes it inline.
314+ /// Deletes the cache entry after use to reclaim storage and prevent stale entries.
315+ function _getOrComputeCertHash (bytes memory certificate , Asn1Ptr ptr ) internal returns (bytes memory ) {
316+ bytes32 key = keccak256 (certificate);
317+ bytes memory cached = certSha384Cache[key];
318+ if (cached.length != 0 ) {
319+ delete certSha384Cache[key];
320+ return cached;
321+ }
322+ return Sha2Ext.sha384 (certificate, ptr.header (), ptr.totalLength ());
323+ }
324+
292325 function _verifySignature (bytes memory pubKey , bytes memory hash , bytes memory sig ) internal view {
293326 require (ECDSA384.verify (ECDSA384Curve.p384 (), hash, sig, pubKey), "invalid sig " );
294327 }
0 commit comments