@@ -2,7 +2,7 @@ use crate::CenoCryptoError;
22use ceno_keccak:: { Hasher , Keccak } ;
33use ceno_rt:: syscalls:: { syscall_secp256k1_add, syscall_secp256k1_double} ;
44use k256:: {
5- AffinePoint , EncodedPoint , Scalar , Secp256k1 , U256 ,
5+ AffinePoint , EncodedPoint , FieldBytes , NonZeroScalar , Scalar , Secp256k1 , U256 ,
66 ecdsa:: { Error , RecoveryId , Signature , hazmat:: bits2field} ,
77 elliptic_curve:: {
88 Curve , Field , FieldBytesEncoding , PrimeField ,
@@ -36,7 +36,7 @@ pub fn secp256k1_ecrecover(
3636 let recid = RecoveryId :: from_byte ( recid) . expect ( "recovery ID is valid" ) ;
3737
3838 // recover key
39- let recovered_key = recover_from_prehash_unchecked ( & msg[ ..] , & signature, recid) ?;
39+ let recovered_key = recover_from_prehash ( & msg[ ..] , & signature, recid) ?;
4040
4141 let mut hasher = Keccak :: v256 ( ) ;
4242 hasher. update ( & recovered_key) ;
@@ -49,13 +49,14 @@ pub fn secp256k1_ecrecover(
4949
5050/// Copied from <https://github.com/RustCrypto/signatures/blob/89232d6a962a199fd8211a117db74408353e4383/ecdsa/src/recovery.rs#L278-L316>
5151/// Modified to use ceno syscalls
52- fn recover_from_prehash_unchecked (
52+ fn recover_from_prehash (
5353 prehash : & [ u8 ] ,
5454 signature : & Signature ,
5555 recovery_id : RecoveryId ,
56- ) -> k256 :: ecdsa :: signature :: Result < UntaggedUncompressedPoint > {
56+ ) -> Result < UntaggedUncompressedPoint , Error > {
5757 let ( r, s) = signature. split_scalars ( ) ;
58- let z = <Scalar as Reduce < U256 > >:: reduce_bytes ( & bits2field :: < Secp256k1 > ( prehash) ?) ;
58+ let prehash: FieldBytes = bits2field :: < Secp256k1 > ( prehash) ?;
59+ let z = <Scalar as Reduce < U256 > >:: reduce_bytes ( & prehash) ;
5960
6061 let mut r_bytes = r. to_repr ( ) ;
6162 if recovery_id. is_x_reduced ( ) {
@@ -98,25 +99,63 @@ fn recover_from_prehash_unchecked(
9899 // Original:
99100 // ProjectivePoint::lincomb(&ProjectivePoint::GENERATOR, &u1, &r_point, &u2)
100101 // Equivalent to: G * u1 + R * u2
101- let pk_words = match ( u1 == Scalar :: ZERO , u2 == Scalar :: ZERO ) {
102- ( true , true ) => return Err ( Error :: new ( ) ) ,
103- ( true , false ) => secp256k1_mul ( & r_point, u2) ,
104- ( false , true ) => secp256k1_mul ( & AffinePoint :: GENERATOR , u1) ,
105- ( false , false ) => {
106- let mut p1 = secp256k1_mul ( & AffinePoint :: GENERATOR , u1) ;
107- let p2 = secp256k1_mul ( & r_point, u2) ;
108- syscall_secp256k1_add ( & mut p1, & p2) ;
109- p1
110- }
111- } ;
102+ let pk_words = lincomb ( u1, & r_point, u2) ?;
103+
104+ let bytes = words_to_untagged_bytes ( pk_words) ;
112105
113- // FIXME: do we really need to verify the signature again here?
114106 // Original:
115107 // let vk = VerifyingKey::from_affine(pk.to_affine())?;
116108 // // Ensure signature verifies with the recovered key
117109 // vk.verify_prehash(prehash, signature)?;
110+ verify_prehash ( & z, ( & r, & s) , & bytes) ?;
111+
112+ Ok ( bytes)
113+ }
114+
115+ /// Copied from <https://github.com/RustCrypto/signatures/blob/89232d6a962a199fd8211a117db74408353e4383/ecdsa/src/hazmat.rs#L261-L293>
116+ fn verify_prehash (
117+ z : & Scalar ,
118+ ( r, s) : ( & NonZeroScalar , & NonZeroScalar ) ,
119+ bytes : & UntaggedUncompressedPoint ,
120+ ) -> Result < ( ) , Error > {
121+ let q = EncodedPoint :: from_untagged_bytes ( bytes. into ( ) ) ;
122+ let q = AffinePoint :: from_encoded_point ( & q)
123+ . into_option ( )
124+ . ok_or ( Error :: new ( ) ) ?;
125+
126+ let s_inv = * s. invert_vartime ( ) ;
127+ let u1 = z * & s_inv;
128+ let u2 = * * r * s_inv;
118129
119- Ok ( words_to_untagged_bytes ( pk_words) )
130+ // Original:
131+ // let x = ProjectivePoint::lincomb(&ProjectivePoint::GENERATOR, &u1, &q, &u2)
132+ // .to_affine()
133+ // .x();
134+ // Equivalent to: G * u1 + q * u2
135+ let p = lincomb ( u1, & q, u2) ?;
136+ let p_bytes = words_to_untagged_bytes ( p) ;
137+ let x = FieldBytes :: from_slice ( & p_bytes[ ..32 ] ) ;
138+
139+ if * * r == <Scalar as Reduce < U256 > >:: reduce_bytes ( & x) {
140+ Ok ( ( ) )
141+ } else {
142+ Err ( Error :: new ( ) )
143+ }
144+ }
145+
146+ #[ inline]
147+ fn lincomb ( u1 : Scalar , p : & AffinePoint , u2 : Scalar ) -> Result < [ u32 ; 16 ] , Error > {
148+ Ok ( match ( u1 == Scalar :: ZERO , u2 == Scalar :: ZERO ) {
149+ ( false , false ) => {
150+ let mut p1 = secp256k1_mul ( & AffinePoint :: GENERATOR , u1) ;
151+ let p2 = secp256k1_mul ( & p, u2) ;
152+ syscall_secp256k1_add ( & mut p1, & p2) ;
153+ p1
154+ }
155+ ( true , false ) => secp256k1_mul ( & p, u2) ,
156+ ( false , true ) => secp256k1_mul ( & AffinePoint :: GENERATOR , u1) ,
157+ ( true , true ) => return Err ( Error :: new ( ) ) ,
158+ } )
120159}
121160
122161fn secp256k1_mul ( point : & AffinePoint , scalar : Scalar ) -> [ u32 ; 16 ] {
0 commit comments