1
1
use alloc:: vec:: Vec ;
2
- use core:: ops:: { Add , AddAssign , Mul } ;
2
+ use core:: ops:: { Add , Mul } ;
3
3
4
4
use ecdsa_core:: {
5
5
self ,
@@ -12,10 +12,11 @@ use ecdsa_core::{
12
12
EncodedPoint , Error , RecoveryId , Result , Signature , SignatureSize ,
13
13
} ;
14
14
use elliptic_curve:: {
15
- generic_array:: ArrayLength ,
15
+ bigint:: CheckedAdd ,
16
+ generic_array:: { typenum:: Unsigned , ArrayLength } ,
16
17
sec1:: { FromEncodedPoint , ModulusSize , Tag , ToEncodedPoint } ,
17
18
subtle:: { Choice , ConditionallySelectable , CtOption } ,
18
- CurveArithmetic , FieldBytesSize , PrimeCurve ,
19
+ CurveArithmetic , FieldBytes , FieldBytesEncoding , FieldBytesSize , PrimeCurve ,
19
20
} ;
20
21
use openvm_algebra_guest:: { DivUnsafe , IntMod , Reduce } ;
21
22
@@ -378,12 +379,14 @@ where
378
379
Coordinate < C > : IntMod ,
379
380
C :: Scalar : IntMod + Reduce ,
380
381
{
382
+ /// ## Assumption
383
+ /// To use this implementation, the `Signature<C>`, `Coordinate<C>`, and `FieldBytes<C>` should
384
+ /// all be encoded in big endian bytes. The implementation also assumes that
385
+ /// `Scalar::<C>::NUM_LIMBS <= FieldBytesSize::<C>::USIZE <= Coordinate::<C>::NUM_LIMBS`.
386
+ ///
381
387
/// Ref: <https://github.com/RustCrypto/signatures/blob/85c984bcc9927c2ce70c7e15cbfe9c6936dd3521/ecdsa/src/recovery.rs#L297>
382
388
///
383
389
/// Recovery does not require additional signature verification: <https://github.com/RustCrypto/signatures/pull/831>
384
- ///
385
- /// ## Panics
386
- /// If the signature is invalid or public key cannot be recovered from the given input.
387
390
#[ allow( non_snake_case) ]
388
391
pub fn recover_from_prehash_noverify (
389
392
prehash : & [ u8 ] ,
@@ -411,16 +414,37 @@ where
411
414
}
412
415
413
416
// Perf: don't use bits2field from ::ecdsa
414
- let z = Scalar :: < C > :: from_be_bytes ( bits2field :: < C > ( prehash) . unwrap ( ) . as_ref ( ) ) ;
417
+ let prehash_bytes = bits2field :: < C > ( prehash) ?;
418
+ // If prehash is longer than Scalar::NUM_LIMBS, take leftmost bytes
419
+ let trim = prehash_bytes. len ( ) . saturating_sub ( Scalar :: < C > :: NUM_LIMBS ) ;
420
+ // from_be_bytes still works if len < Scalar::NUM_LIMBS
421
+ // we don't need to reduce because IntMod is up to modular equivalence
422
+ let z = Scalar :: < C > :: from_be_bytes ( & prehash_bytes[ ..prehash_bytes. len ( ) - trim] ) ;
415
423
416
424
// `r` is in the Scalar field, we now possibly add C::ORDER to it to get `x`
417
425
// in the Coordinate field.
418
- let mut x = Coordinate :: < C > :: from_le_bytes ( r. as_le_bytes ( ) ) ;
426
+ // We take some extra care for the case when FieldBytesSize<C> may be larger than
427
+ // Scalar::<C>::NUM_LIMBS.
428
+ let mut r_bytes = {
429
+ let mut r_bytes = FieldBytes :: < C > :: default ( ) ;
430
+ assert ! ( FieldBytesSize :: <C >:: USIZE >= Scalar :: <C >:: NUM_LIMBS ) ;
431
+ let offset = r_bytes. len ( ) . saturating_sub ( r_be. len ( ) ) ;
432
+ r_bytes[ offset..] . copy_from_slice ( r_be) ;
433
+ r_bytes
434
+ } ;
419
435
if recovery_id. is_x_reduced ( ) {
420
- // Copy from slice in case Coordinate has more bytes than Scalar
421
- let order = Coordinate :: < C > :: from_le_bytes ( Scalar :: < C > :: MODULUS . as_ref ( ) ) ;
422
- x. add_assign ( order) ;
436
+ match Option :: < C :: Uint > :: from (
437
+ C :: Uint :: decode_field_bytes ( & r_bytes) . checked_add ( & C :: ORDER ) ,
438
+ ) {
439
+ Some ( restored) => r_bytes = restored. encode_field_bytes ( ) ,
440
+ // No reduction should happen here if r was reduced
441
+ None => {
442
+ return Err ( Error :: new ( ) ) ;
443
+ }
444
+ } ;
423
445
}
446
+ assert ! ( FieldBytesSize :: <C >:: USIZE <= Coordinate :: <C >:: NUM_LIMBS ) ;
447
+ let x = Coordinate :: < C > :: from_be_bytes ( & r_bytes) ;
424
448
let rec_id = recovery_id. to_byte ( ) ;
425
449
// The point R decompressed from x-coordinate `r`
426
450
let R : C :: Point = FromCompressed :: decompress ( x, & rec_id) . ok_or_else ( Error :: new) ?;
@@ -463,8 +487,12 @@ where
463
487
}
464
488
465
489
// Perf: don't use bits2field from ::ecdsa
466
- let z =
467
- <C as IntrinsicCurve >:: Scalar :: from_be_bytes ( bits2field :: < C > ( prehash) . unwrap ( ) . as_ref ( ) ) ;
490
+ let prehash_bytes = bits2field :: < C > ( prehash) ?;
491
+ // If prehash is longer than Scalar::NUM_LIMBS, take leftmost bytes
492
+ let trim = prehash_bytes. len ( ) . saturating_sub ( Scalar :: < C > :: NUM_LIMBS ) ;
493
+ // from_be_bytes still works if len < Scalar::NUM_LIMBS
494
+ // we don't need to reduce because IntMod is up to modular equivalence
495
+ let z = Scalar :: < C > :: from_be_bytes ( & prehash_bytes[ ..prehash_bytes. len ( ) - trim] ) ;
468
496
469
497
let u1 = z. div_unsafe ( & s) ;
470
498
let u2 = ( & r) . div_unsafe ( & s) ;
0 commit comments