1616//! # FFI of the recovery module
1717
1818use :: types:: * ;
19- #[ cfg( not( rust_secp_fuzz) ) ]
20- use :: { Context , Signature , NonceFn , PublicKey } ;
19+ use { Context , Signature , NonceFn , PublicKey } ;
2120
2221/// Library-internal representation of a Secp256k1 signature + recovery ID
2322#[ repr( C ) ]
@@ -36,7 +35,6 @@ impl Default for RecoverableSignature {
3635 }
3736}
3837
39- #[ cfg( not( rust_secp_fuzz) ) ]
4038extern "C" {
4139 #[ cfg_attr( not( rust_secp_no_symbol_renaming) , link_name = "rustsecp256k1_v0_3_1_ecdsa_recoverable_signature_parse_compact" ) ]
4240 pub fn secp256k1_ecdsa_recoverable_signature_parse_compact ( cx : * const Context , sig : * mut RecoverableSignature ,
@@ -52,6 +50,10 @@ extern "C" {
5250 pub fn secp256k1_ecdsa_recoverable_signature_convert ( cx : * const Context , sig : * mut Signature ,
5351 input : * const RecoverableSignature )
5452 -> c_int ;
53+ }
54+
55+ #[ cfg( not( rust_secp_fuzz) ) ]
56+ extern "C" {
5557 #[ cfg_attr( not( rust_secp_no_symbol_renaming) , link_name = "rustsecp256k1_v0_3_1_ecdsa_sign_recoverable" ) ]
5658 pub fn secp256k1_ecdsa_sign_recoverable ( cx : * const Context ,
5759 sig : * mut RecoverableSignature ,
@@ -72,58 +74,77 @@ extern "C" {
7274
7375#[ cfg( rust_secp_fuzz) ]
7476mod fuzz_dummy {
75- extern crate std;
76- use self :: std:: ptr;
77- use super :: RecoverableSignature ;
78- use types:: * ;
79- use :: { Signature , Context , PublicKey , NonceFn , secp256k1_ec_seckey_verify,
80- SECP256K1_START_NONE , SECP256K1_START_VERIFY , SECP256K1_START_SIGN } ;
81-
82- pub unsafe fn secp256k1_ecdsa_recoverable_signature_parse_compact ( _cx : * const Context , _sig : * mut RecoverableSignature ,
83- _input64 : * const c_uchar , _recid : c_int )
84- -> c_int {
85- unimplemented ! ( ) ;
86- }
87-
88- pub unsafe fn secp256k1_ecdsa_recoverable_signature_serialize_compact ( _cx : * const Context , _output64 : * mut c_uchar ,
89- _recid : * mut c_int , _sig : * const RecoverableSignature )
90- -> c_int {
91- unimplemented ! ( ) ;
92- }
93-
94- pub unsafe fn secp256k1_ecdsa_recoverable_signature_convert ( _cx : * const Context , _sig : * mut Signature ,
95- _input : * const RecoverableSignature )
96- -> c_int {
97- unimplemented ! ( ) ;
98- }
99-
100- /// Sets sig to (2|3)||msg32||sk
101- pub unsafe fn secp256k1_ecdsa_sign_recoverable ( cx : * const Context ,
102- sig : * mut RecoverableSignature ,
103- msg32 : * const c_uchar ,
104- sk : * const c_uchar ,
105- _noncefn : NonceFn ,
106- _noncedata : * const c_void )
107- -> c_int {
108- assert ! ( !cx. is_null( ) && ( * cx) . flags( ) & !( SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN ) == 0 ) ;
109- assert ! ( ( * cx) . flags( ) & SECP256K1_START_SIGN == SECP256K1_START_SIGN ) ;
110- if secp256k1_ec_seckey_verify ( cx, sk) != 1 { return 0 ; }
111- if * sk. offset ( 0 ) > 0x7f {
112- ( * sig) . 0 [ 0 ] = 2 ;
113- } else {
114- ( * sig) . 0 [ 0 ] = 3 ;
77+ use super :: * ;
78+ use std:: slice;
79+
80+ use secp256k1_ec_pubkey_create;
81+ use secp256k1_ec_pubkey_parse;
82+ use secp256k1_ec_pubkey_serialize;
83+ use SECP256K1_SER_COMPRESSED ;
84+
85+ /// Sets sig to msg32||full pk
86+ pub unsafe fn secp256k1_ecdsa_sign_recoverable (
87+ cx : * const Context ,
88+ sig : * mut RecoverableSignature ,
89+ msg32 : * const c_uchar ,
90+ sk : * const c_uchar ,
91+ _noncefn : NonceFn ,
92+ _noncedata : * const c_void ,
93+ ) -> c_int {
94+ // Check context is built for signing (and compute pk)
95+ let mut new_pk = PublicKey :: new ( ) ;
96+ if secp256k1_ec_pubkey_create ( cx, & mut new_pk, sk) != 1 {
97+ return 0 ;
11598 }
116- ptr:: copy ( msg32, ( * sig) . 0 [ 1 ..33 ] . as_mut_ptr ( ) , 32 ) ;
117- ptr:: copy ( sk, ( * sig) . 0 [ 33 ..65 ] . as_mut_ptr ( ) , 32 ) ;
99+ // Sign
100+ let sig_sl = slice:: from_raw_parts_mut ( sig as * mut u8 , 65 ) ;
101+ let msg_sl = slice:: from_raw_parts ( msg32 as * const u8 , 32 ) ;
102+ sig_sl[ ..32 ] . copy_from_slice ( msg_sl) ;
103+ let mut out_len: size_t = 33 ;
104+ secp256k1_ec_pubkey_serialize ( cx, sig_sl[ 32 ..] . as_mut_ptr ( ) , & mut out_len, & new_pk, SECP256K1_SER_COMPRESSED ) ;
105+ // Encode the parity of the pubkey in the final byte as 0/1,
106+ // which is the same encoding (though the parity is computed
107+ // differently) as real recoverable signatures.
108+ sig_sl. swap ( 32 , 64 ) ;
109+ sig_sl[ 64 ] -= 2 ;
118110 1
119111 }
120112
121- pub unsafe fn secp256k1_ecdsa_recover ( _cx : * const Context ,
122- _pk : * mut PublicKey ,
123- _sig : * const RecoverableSignature ,
124- _msg32 : * const c_uchar )
125- -> c_int {
126- unimplemented ! ( ) ;
113+ pub unsafe fn secp256k1_ecdsa_recover (
114+ cx : * const Context ,
115+ pk : * mut PublicKey ,
116+ sig : * const RecoverableSignature ,
117+ msg32 : * const c_uchar
118+ ) -> c_int {
119+ let sig_sl = slice:: from_raw_parts ( sig as * const u8 , 65 ) ;
120+ let msg_sl = slice:: from_raw_parts ( msg32 as * const u8 , 32 ) ;
121+ println ! ( "HMM0" ) ;
122+
123+ if sig_sl[ 64 ] > 4 {
124+ return 0 ;
125+ }
126+ // Pull the original pk out of the siganture
127+ let mut pk_ser = [ 0 ; 33 ] ;
128+ pk_ser. copy_from_slice ( & sig_sl[ 32 ..] ) ;
129+ pk_ser. swap ( 0 , 32 ) ;
130+ pk_ser[ 0 ] += 2 ;
131+ // Check that it parses (in a real sig, this would be the R value,
132+ // so it is actually required to be a valid point)
133+ if secp256k1_ec_pubkey_parse ( cx, pk, pk_ser. as_ptr ( ) , 33 ) == 0 {
134+ return 0 ;
135+ }
136+ // Munge it up so that a different message will give a different pk
137+ for i in 0 ..32 {
138+ pk_ser[ i + 1 ] ^= sig_sl[ i] ^ msg_sl[ i] ;
139+ }
140+ // If any munging happened, this will fail parsing half the time, so
141+ // tweak-and-loop until we find a key that works.
142+ let mut idx = 0 ;
143+ while secp256k1_ec_pubkey_parse ( cx, pk, pk_ser. as_ptr ( ) , 33 ) == 0 {
144+ pk_ser[ 1 + idx / 8 ] ^= 1 << ( idx % 8 ) ;
145+ idx += 1 ;
146+ }
147+ 1
127148 }
128149}
129150#[ cfg( rust_secp_fuzz) ]
0 commit comments