@@ -375,6 +375,23 @@ pub(crate) fn fill_with_zeros(calldata: &Bytes, target_len: usize) -> Bytes {
375375 padded_calldata. into ( )
376376}
377377
378+ #[ expect( clippy:: arithmetic_side_effects, clippy:: indexing_slicing) ]
379+ #[ cfg( all(
380+ not( feature = "sp1" ) ,
381+ not( feature = "risc0" ) ,
382+ not( feature = "zisk" ) ,
383+ feature = "secp256k1"
384+ ) ) ]
385+ #[ inline( always) ]
386+ fn copy_segment ( calldata : & Bytes , dst : & mut [ u8 ] , start : usize ) {
387+ if start >= calldata. len ( ) {
388+ return ;
389+ }
390+ let end = ( start + dst. len ( ) ) . min ( calldata. len ( ) ) ;
391+ let src = & calldata[ start..end] ;
392+ dst[ ..src. len ( ) ] . copy_from_slice ( src) ;
393+ }
394+
378395#[ cfg( all(
379396 not( feature = "sp1" ) ,
380397 not( feature = "risc0" ) ,
@@ -386,19 +403,25 @@ pub fn ecrecover(calldata: &Bytes, gas_remaining: &mut u64, _fork: Fork) -> Resu
386403
387404 increase_precompile_consumed_gas ( ECRECOVER_COST , gas_remaining) ?;
388405
389- const INPUT_LEN : usize = 128 ;
390406 const WORD : usize = 32 ;
407+ const SIG_LEN : usize = 64 ;
391408
392- let input = fill_with_zeros ( calldata, INPUT_LEN ) ;
409+ // Total input size = 128
410+ let mut raw_hash = [ 0u8 ; WORD ] ;
411+ let mut raw_v = [ 0u8 ; WORD ] ;
412+ let mut raw_sig = [ 0u8 ; SIG_LEN ] ;
393413
394- // len(raw_hash) == 32, len(raw_v) == 32, len(raw_sig) == 64
395- let ( raw_hash , tail ) = input . split_at ( WORD ) ;
396- let ( raw_v , raw_sig) = tail . split_at ( WORD ) ;
414+ copy_segment ( calldata , & mut raw_hash , 0 ) ;
415+ copy_segment ( calldata , & mut raw_v , WORD ) ;
416+ copy_segment ( calldata , & mut raw_sig, WORD * 2 ) ;
397417
398418 // EVM expects v ∈ {27, 28}. Anything else is invalid → empty return.
399- let recovery_id_byte = match u8:: try_from ( u256_from_big_endian ( raw_v) ) {
400- Ok ( 27 ) => 0_i32 ,
401- Ok ( 28 ) => 1_i32 ,
419+ if raw_v[ ..( WORD - 1 ) ] . iter ( ) . any ( |& b| b != 0 ) {
420+ return Ok ( Bytes :: new ( ) ) ;
421+ }
422+ let recovery_id_byte = match raw_v[ WORD - 1 ] {
423+ 27 => 0_i32 ,
424+ 28 => 1_i32 ,
402425 _ => return Ok ( Bytes :: new ( ) ) ,
403426 } ;
404427
@@ -408,16 +431,12 @@ pub fn ecrecover(calldata: &Bytes, gas_remaining: &mut u64, _fork: Fork) -> Resu
408431 } ;
409432
410433 let Ok ( recoverable_signature) =
411- secp256k1:: ecdsa:: RecoverableSignature :: from_compact ( raw_sig, recovery_id)
434+ secp256k1:: ecdsa:: RecoverableSignature :: from_compact ( & raw_sig, recovery_id)
412435 else {
413436 return Ok ( Bytes :: new ( ) ) ;
414437 } ;
415438
416- let message = secp256k1:: Message :: from_digest (
417- raw_hash
418- . try_into ( )
419- . map_err ( |_err| InternalError :: msg ( "Invalid message length for ecrecover" ) ) ?,
420- ) ;
439+ let message = secp256k1:: Message :: from_digest ( raw_hash) ;
421440
422441 let Ok ( public_key) = recoverable_signature. recover ( & message) else {
423442 return Ok ( Bytes :: new ( ) ) ;
0 commit comments