The 0x01 ecRecover precompile at ecrecover.rs checks v in {27,28} but never checks that r and s are in [1, N-1]. It calls sp_io::crypto::secp256k1_ecdsa_recover, whose v1 impl (lib.rs) uses parse_overflowing_slice and reduces s mod N instead of rejecting it, whereas go-ethereum returns empty output (Solidity address(0)) for r,s >= N.
Repro: submit any valid (r, s, v) as s' = s + N (still < 2^256). Ethereum yields address(0), pallet-revive recovers the same non zero signer.
Impact: consensus divergence, and malleability for any contract using ecrecover output for replay or uniqueness protection. The same class exists in the tx path (missing low s / EIP-2, unchecked y_parity/v, RLP decoders never asserting item_count()).
Fix: reject r == 0, s == 0, r >= N, s >= N before recovery, matching ValidateSignatureValues.
The
0x01ecRecoverprecompile at ecrecover.rs checksv in {27,28}but never checks thatrandsare in[1, N-1]. It callssp_io::crypto::secp256k1_ecdsa_recover, whose v1 impl (lib.rs) usesparse_overflowing_sliceand reducessmod N instead of rejecting it, whereas go-ethereum returns empty output (Solidityaddress(0)) forr,s >= N.Repro: submit any valid
(r, s, v)ass' = s + N(still< 2^256). Ethereum yieldsaddress(0),pallet-reviverecovers the same non zero signer.Impact: consensus divergence, and malleability for any contract using
ecrecoveroutput for replay or uniqueness protection. The same class exists in the tx path (missing lows/ EIP-2, uncheckedy_parity/v, RLP decoders never assertingitem_count()).Fix: reject
r == 0,s == 0,r >= N,s >= Nbefore recovery, matchingValidateSignatureValues.