18
18
//!
19
19
//! // Signing
20
20
//! let signing_key = SigningKey::generate(&mut OsRng); // Serialize with `::to_bytes()`
21
- //! let public_key = EncodedPoint::from(& signing_key.verify_key() );
21
+ //! let verify_key = signing_key.verify_key();
22
22
//! let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
23
23
//!
24
24
//! // Note: the signature type must be annotated or otherwise inferrable as
25
25
//! // `Signer` has many impls of the `Signer` trait (for both regular and
26
26
//! // recoverable signature types).
27
27
//! let signature: recoverable::Signature = signing_key.sign(message);
28
- //! let recovered_pubkey = signature.recover_public_key (message).expect("couldn't recover pubkey");
28
+ //! let recovered_key = signature.recover_verify_key (message).expect("couldn't recover pubkey");
29
29
//!
30
- //! assert_eq!(&public_key , &recovered_pubkey );
30
+ //! assert_eq!(&verify_key , &recovered_key );
31
31
//! # }
32
32
//! ```
33
33
@@ -39,12 +39,10 @@ use ecdsa_core::{signature::Signature as _, Error};
39
39
40
40
#[ cfg( feature = "ecdsa" ) ]
41
41
use crate :: {
42
- arithmetic :: { FieldElement , CURVE_EQUATION_B } ,
42
+ ecdsa :: VerifyKey ,
43
43
elliptic_curve:: {
44
- consts:: U32 ,
45
- ops:: Invert ,
46
- subtle:: { Choice , ConditionallySelectable } ,
47
- Digest , FromBytes , FromDigest ,
44
+ consts:: U32 , ops:: Invert , subtle:: Choice , weierstrass:: point:: Decompress , Digest ,
45
+ FromBytes , FromDigest ,
48
46
} ,
49
47
AffinePoint , NonZeroScalar , ProjectivePoint , Scalar ,
50
48
} ;
@@ -108,8 +106,8 @@ impl Signature {
108
106
109
107
for recovery_id in 0 ..=1 {
110
108
if let Ok ( recoverable_signature) = Signature :: new ( & signature, Id ( recovery_id) ) {
111
- if let Ok ( recovered_key) = recoverable_signature. recover_public_key ( msg) {
112
- if public_key == & recovered_key {
109
+ if let Ok ( recovered_key) = recoverable_signature. recover_verify_key ( msg) {
110
+ if public_key == & EncodedPoint :: from ( & recovered_key) {
113
111
return Ok ( recoverable_signature) ;
114
112
}
115
113
}
@@ -123,52 +121,38 @@ impl Signature {
123
121
/// [`EncodedPoint`].
124
122
#[ cfg( all( feature = "ecdsa" , feature = "keccak256" ) ) ]
125
123
#[ cfg_attr( docsrs, doc( cfg( feature = "ecdsa" ) ) , doc( cfg( feature = "keccak256" ) ) ) ]
126
- pub fn recover_public_key ( & self , msg : & [ u8 ] ) -> Result < EncodedPoint , Error > {
127
- self . recover_public_key_from_prehash ( Keccak256 :: new ( ) . chain ( msg) )
124
+ pub fn recover_verify_key ( & self , msg : & [ u8 ] ) -> Result < VerifyKey , Error > {
125
+ self . recover_verify_key_from_digest ( Keccak256 :: new ( ) . chain ( msg) )
128
126
}
129
127
130
128
/// Recover the public key used to create the given signature as an
131
129
/// [`EncodedPoint`] from the provided precomputed [`Digest`].
132
130
#[ cfg( feature = "ecdsa" ) ]
133
131
#[ cfg_attr( docsrs, doc( cfg( feature = "ecdsa" ) ) ) ]
134
132
#[ allow( non_snake_case, clippy:: many_single_char_names) ]
135
- pub fn recover_public_key_from_prehash < D > ( & self , msg_prehash : D ) -> Result < EncodedPoint , Error >
133
+ pub fn recover_verify_key_from_digest < D > ( & self , msg_prehash : D ) -> Result < VerifyKey , Error >
136
134
where
137
135
D : Digest < OutputSize = U32 > ,
138
136
{
139
137
let r = self . r ( ) ;
140
138
let s = self . s ( ) ;
141
139
let z = Scalar :: from_digest ( msg_prehash) ;
142
- let x = FieldElement :: from_bytes ( & r. to_bytes ( ) ) ;
143
-
144
- let pk = x. and_then ( |x| {
145
- let alpha = ( x * & x * & x) + & CURVE_EQUATION_B ;
146
- let beta = alpha. sqrt ( ) . unwrap ( ) ;
147
-
148
- let y = FieldElement :: conditional_select (
149
- & beta. negate ( 1 ) ,
150
- & beta,
151
- // beta.is_odd() == recovery_id.is_y_odd()
152
- !( beta. normalize ( ) . is_odd ( ) ^ self . recovery_id ( ) . is_y_odd ( ) ) ,
153
- ) ;
154
-
155
- let R = ProjectivePoint :: from ( AffinePoint {
156
- x,
157
- y : y. normalize ( ) ,
158
- } ) ;
140
+ let R = AffinePoint :: decompress ( & r. to_bytes ( ) , self . recovery_id ( ) . is_y_odd ( ) ) ;
159
141
142
+ // TODO(tarcieri): replace with into conversion when available (see subtle#73)
143
+ if R . is_some ( ) . into ( ) {
144
+ let R = ProjectivePoint :: from ( R . unwrap ( ) ) ;
160
145
let r_inv = r. invert ( ) . unwrap ( ) ;
161
146
let u1 = -( r_inv * & z) ;
162
- let u2 = r_inv * s. as_ref ( ) ;
163
- ( ( & ProjectivePoint :: generator ( ) * & u1) + & ( R * & u2) ) . to_affine ( )
164
- } ) ;
147
+ let u2 = r_inv * & * s;
148
+ let pk = ( ( & ProjectivePoint :: generator ( ) * & u1) + & ( R * & u2) ) . to_affine ( ) ;
165
149
166
- // TODO(tarcieri): replace with into conversion when available (see subtle#73)
167
- if pk. is_some ( ) . into ( ) {
168
- Ok ( pk. unwrap ( ) . into ( ) )
169
- } else {
170
- Err ( Error :: new ( ) )
150
+ if pk. is_some ( ) . into ( ) {
151
+ return Ok ( VerifyKey :: from ( & pk. unwrap ( ) ) ) ;
152
+ }
171
153
}
154
+
155
+ Err ( Error :: new ( ) )
172
156
}
173
157
174
158
/// Parse the `r` component of this signature to a [`Scalar`]
@@ -298,6 +282,7 @@ impl From<Id> for u8 {
298
282
#[ cfg( all( test, feature = "ecdsa" , feature = "sha256" ) ) ]
299
283
mod tests {
300
284
use super :: Signature ;
285
+ use crate :: EncodedPoint ;
301
286
use core:: convert:: TryFrom ;
302
287
use hex_literal:: hex;
303
288
use sha2:: { Digest , Sha256 } ;
@@ -335,8 +320,8 @@ mod tests {
335
320
for vector in VECTORS {
336
321
let sig = Signature :: try_from ( & vector. sig [ ..] ) . unwrap ( ) ;
337
322
let prehash = Sha256 :: new ( ) . chain ( vector. msg ) ;
338
- let pk = sig. recover_public_key_from_prehash ( prehash) . unwrap ( ) ;
339
- assert_eq ! ( & vector. pk[ ..] , pk . as_bytes( ) ) ;
323
+ let pk = sig. recover_verify_key_from_digest ( prehash) . unwrap ( ) ;
324
+ assert_eq ! ( & vector. pk[ ..] , EncodedPoint :: from ( & pk ) . as_bytes( ) ) ;
340
325
}
341
326
}
342
327
}
0 commit comments