@@ -90,10 +90,48 @@ library P256 {
9090 ) private view returns (bool valid , bool supported ) {
9191 if (! _isProperSignature (r, s) || ! isValidPublicKey (qx, qy)) {
9292 return (false , true ); // signature is invalid, and its not because the precompile is missing
93+ } else if (_rip7212 (h, r, s, qx, qy)) {
94+ return (true , true ); // precompile is present, signature is valid
95+ } else if (
96+ // Given precompiles have no bytecode (i.e. `address(0x100).code.length == 0`), we use
97+ // a valid signature with small `r` and `s` values to check if the precompile is present. Taken from
98+ // https://github.com/C2SP/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/ecdsa_secp256r1_sha256_p1363_test.json#L1173-L1204
99+ _rip7212 (
100+ 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023 , // sha256("123400")
101+ 0x0000000000000000000000000000000000000000000000000000000000000005 ,
102+ 0x0000000000000000000000000000000000000000000000000000000000000001 ,
103+ 0xa71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957 ,
104+ 0x5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b
105+ )
106+ ) {
107+ return (false , true ); // precompile is present, signature is invalid
108+ } else {
109+ return (false , false ); // precompile is absent
93110 }
111+ }
94112
95- (bool success , bytes memory returndata ) = address (0x100 ).staticcall (abi.encode (h, r, s, qx, qy));
96- return (success && returndata.length == 0x20 ) ? (abi.decode (returndata, (bool )), true ) : (false , false );
113+ /**
114+ * @dev Low level helper for {_tryVerifyNative}. Calls the precompile and checks if there is a return value.
115+ */
116+ function _rip7212 (bytes32 h , bytes32 r , bytes32 s , bytes32 qx , bytes32 qy ) private view returns (bool isValid ) {
117+ assembly ("memory-safe" ) {
118+ // Use the free memory pointer without updating it at the end of the function
119+ let ptr := mload (0x40 )
120+ mstore (ptr, h)
121+ mstore (add (ptr, 0x20 ), r)
122+ mstore (add (ptr, 0x40 ), s)
123+ mstore (add (ptr, 0x60 ), qx)
124+ mstore (add (ptr, 0x80 ), qy)
125+ // RIP-7212 precompiles return empty bytes when an invalid signature is passed, making it impossible
126+ // to distinguish the presence of the precompile. Custom precompile implementations may decide to
127+ // return `bytes32(0)` (i.e. false) without developers noticing, so we decide to evaluate the return value
128+ // without expanding memory using scratch space.
129+ mstore (0x00 , 0 ) // zero out scratch space in case the precompile doesn't return anything
130+ if iszero (staticcall (gas (), 0x100 , ptr, 0xa0 , 0x00 , 0x20 )) {
131+ invalid ()
132+ }
133+ isValid := mload (0x00 )
134+ }
97135 }
98136
99137 /**
0 commit comments