1212//! FULL PRIVATE KEY RECOVERY!
1313//! </div>
1414
15- use crate :: { EcdsaCurve , Error , Result } ;
16- use core:: cmp;
17- use elliptic_curve:: { FieldBytes , array:: typenum:: Unsigned } ;
18-
19- #[ cfg( feature = "algorithm" ) ]
20- use {
21- crate :: { RecoveryId , Signature , SignatureSize } ,
22- elliptic_curve:: {
23- CurveArithmetic , NonZeroScalar , ProjectivePoint , Scalar ,
24- array:: ArraySize ,
25- ff:: PrimeField ,
26- field,
27- group:: { Curve as _, Group } ,
28- ops:: { Invert , MulByGeneratorVartime , Reduce } ,
29- point:: AffineCoordinates ,
30- scalar:: IsHigh ,
31- } ,
15+ use crate :: { EcdsaCurve , Error , RecoveryId , Result , Signature , SignatureSize } ;
16+ use elliptic_curve:: {
17+ CurveArithmetic , FieldBytes , NonZeroScalar , ProjectivePoint , Scalar ,
18+ array:: ArraySize ,
19+ bigint:: { BitOps , Encoding } ,
20+ ff:: PrimeField ,
21+ group:: { Curve as _, Group } ,
22+ ops:: { Invert , MulByGeneratorVartime , Reduce } ,
23+ point:: AffineCoordinates ,
24+ scalar:: IsHigh ,
3225} ;
3326
3427#[ cfg( feature = "digest" ) ]
35- use digest:: { Digest , FixedOutput , FixedOutputReset , common:: BlockSizeUser } ;
36-
37- /// Bind a preferred [`Digest`] algorithm to an elliptic curve type.
38- ///
39- /// Generally there is a preferred variety of the SHA-2 family used with ECDSA
40- /// for a particular elliptic curve.
41- #[ cfg( feature = "digest" ) ]
42- pub trait DigestAlgorithm : EcdsaCurve {
43- /// Preferred digest to use when computing ECDSA signatures for this
44- /// elliptic curve. This is typically a member of the SHA-2 family.
45- type Digest : BlockSizeUser + Digest + FixedOutput + FixedOutputReset ;
46- }
47-
48- /// Partial implementation of the `bits2int` function as defined in
49- /// [RFC6979 § 2.3.2] as well as [SEC1] § 2.3.8.
50- ///
51- /// This is used to convert a message digest whose size may be smaller or
52- /// larger than the size of the curve's scalar field into a serialized
53- /// (unreduced) field element.
54- ///
55- /// [RFC6979 § 2.3.2]: https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2
56- /// [SEC1]: https://www.secg.org/sec1-v2.pdf
57- pub fn bits2field < C : EcdsaCurve > ( bits : & [ u8 ] ) -> Result < FieldBytes < C > > {
58- // Absolute 128-bit / 16-byte minimum to catch egregious digest misuse
59- // without rejecting legitimate combinations like SHA-256 with P-521
60- // (see e.g. XML Signature, which permits such pairings).
61- if bits. len ( ) < 16 {
62- return Err ( Error :: new ( ) ) ;
63- }
64-
65- let mut field_bytes = FieldBytes :: < C > :: default ( ) ;
66-
67- match bits. len ( ) . cmp ( & C :: FieldBytesSize :: USIZE ) {
68- cmp:: Ordering :: Equal => field_bytes. copy_from_slice ( bits) ,
69- cmp:: Ordering :: Less => {
70- // If bits is smaller than the field size, pad with zeroes on the left
71- field_bytes[ ( C :: FieldBytesSize :: USIZE - bits. len ( ) ) ..] . copy_from_slice ( bits) ;
72- }
73- cmp:: Ordering :: Greater => {
74- // If bits is larger than the field size, truncate
75- field_bytes. copy_from_slice ( & bits[ ..C :: FieldBytesSize :: USIZE ] ) ;
76- }
77- }
78-
79- Ok ( field_bytes)
80- }
28+ use digest:: { Digest , FixedOutputReset , block_api:: BlockSizeUser } ;
8129
8230/// Sign a prehashed message digest using the provided secret scalar and
8331/// ephemeral scalar, returning an ECDSA signature.
@@ -102,18 +50,17 @@ pub fn bits2field<C: EcdsaCurve>(bits: &[u8]) -> Result<FieldBytes<C>> {
10250///
10351/// This will return an error if a zero-scalar was generated. It can be tried again with a
10452/// different `k`.
105- #[ cfg( feature = "algorithm" ) ]
10653#[ allow( non_snake_case) ]
10754pub fn sign_prehashed < C > (
10855 d : & NonZeroScalar < C > ,
10956 k : & NonZeroScalar < C > ,
110- z : & FieldBytes < C > ,
57+ z : & [ u8 ] ,
11158) -> Result < ( Signature < C > , RecoveryId ) >
11259where
11360 C : EcdsaCurve + CurveArithmetic ,
11461 SignatureSize < C > : ArraySize ,
11562{
116- let z = Scalar :: < C > :: reduce ( z) ;
63+ let z = bytes2scalar :: < C > ( z) ;
11764
11865 // Compute scalar inversion of 𝑘.
11966 let k_inv = k. invert ( ) ;
12370
12471 // Lift x-coordinate of 𝑹 (element of base field) into a serialized big
12572 // integer, then reduce it into an element of the scalar field.
126- let r = Scalar :: < C > :: reduce ( & R . x ( ) ) ;
73+ let r = bytes2scalar :: < C > ( & R . x ( ) ) ;
12774
12875 // Compute 𝒔 as a signature over 𝒓 and 𝒛.
12976 let s = * k_inv * ( z + ( r * d. as_ref ( ) ) ) ;
@@ -153,40 +100,30 @@ where
153100/// - `z`: message digest to be signed, i.e. `H(m)`. Does not have to be reduced in advance.
154101/// - `ad`: optional additional data, e.g. added entropy from an RNG
155102///
156- /// # Errors
157- ///
158- /// This will return an error if a zero-scalar was generated. It can be tried again with different
159- /// entropy `ad`.
160- ///
161103/// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
162- #[ cfg( feature = "algorithm" ) ]
163104pub fn sign_prehashed_rfc6979 < C , D > (
164105 d : & NonZeroScalar < C > ,
165- z : & FieldBytes < C > ,
106+ z : & [ u8 ] ,
166107 ad : & [ u8 ] ,
167- ) -> Result < ( Signature < C > , RecoveryId ) >
108+ ) -> ( Signature < C > , RecoveryId )
168109where
169110 C : EcdsaCurve + CurveArithmetic ,
170- D : Digest + BlockSizeUser + FixedOutput + FixedOutputReset ,
111+ D : Digest + BlockSizeUser + FixedOutputReset ,
171112 SignatureSize < C > : ArraySize ,
172113{
173- // From RFC6979 § 2.4:
174- //
175- // H(m) is transformed into an integer modulo q using the bits2int
176- // transform and an extra modular reduction:
177- //
178- // h = bits2int(H(m)) mod q
179- let z2 = Scalar :: < C > :: reduce ( z) ;
114+ let order = C :: ORDER ;
115+ let mut kgen = rfc6979:: KGenerator :: < D , C :: Uint > :: new ( & d. to_repr ( ) , z, ad, & order) ;
180116
181- let k = NonZeroScalar :: < C > :: from_repr ( rfc6979:: generate_k :: < D , _ > (
182- & d. to_repr ( ) ,
183- & field:: uint_to_bytes :: < C > ( & C :: ORDER ) ,
184- & z2. to_repr ( ) ,
185- ad,
186- ) )
187- . unwrap ( ) ;
117+ loop {
118+ let mut k_bytes = FieldBytes :: < C > :: default ( ) ;
119+ kgen. fill_next_k ( & mut k_bytes) ;
188120
189- sign_prehashed ( d, & k, z)
121+ if let Some ( k) = NonZeroScalar :: < C > :: from_repr ( k_bytes) . into_option ( ) {
122+ if let Ok ( ret) = sign_prehashed ( d, & k, z) {
123+ return ret;
124+ }
125+ }
126+ }
190127}
191128
192129/// Verify the prehashed message against the provided ECDSA signature.
@@ -197,12 +134,7 @@ where
197134/// - `z`: message digest to be verified. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY SECURE DIGEST
198135/// ALGORITHM!!!
199136/// - `sig`: signature to be verified against the key and message.
200- #[ cfg( feature = "algorithm" ) ]
201- pub fn verify_prehashed < C > (
202- q : & ProjectivePoint < C > ,
203- z : & FieldBytes < C > ,
204- sig : & Signature < C > ,
205- ) -> Result < ( ) >
137+ pub fn verify_prehashed < C > ( q : & ProjectivePoint < C > , z : & [ u8 ] , sig : & Signature < C > ) -> Result < ( ) >
206138where
207139 C : EcdsaCurve + CurveArithmetic ,
208140 SignatureSize < C > : ArraySize ,
@@ -211,7 +143,7 @@ where
211143 return Err ( Error :: new ( ) ) ;
212144 }
213145
214- let z = Scalar :: < C > :: reduce ( z) ;
146+ let z = bytes2scalar :: < C > ( z) ;
215147 let ( r, s) = sig. split_scalars ( ) ;
216148 let s_inv = * s. invert_vartime ( ) ;
217149 let u1 = z * s_inv;
@@ -220,53 +152,23 @@ where
220152 . to_affine ( )
221153 . x ( ) ;
222154
223- if * r == Scalar :: < C > :: reduce ( & x) {
155+ if * r == bytes2scalar :: < C > ( & x) {
224156 Ok ( ( ) )
225157 } else {
226158 Err ( Error :: new ( ) )
227159 }
228160}
229161
230- #[ cfg( all( test, feature = "dev" ) ) ]
231- mod tests {
232- use super :: bits2field;
233- use elliptic_curve:: dev:: MockCurve ;
234- use hex_literal:: hex;
235-
236- #[ test]
237- fn bits2field_too_small ( ) {
238- assert ! ( bits2field:: <MockCurve >( b"" ) . is_err( ) ) ;
239- // 15 bytes is one short of the 128-bit absolute floor.
240- let prehash = hex ! ( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ) ;
241- assert ! ( bits2field:: <MockCurve >( & prehash) . is_err( ) ) ;
242- }
243-
244- #[ test]
245- fn bits2field_size_less ( ) {
246- let prehash = hex ! ( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ) ;
247- let field_bytes = bits2field :: < MockCurve > ( & prehash) . expect ( "field bytes" ) ;
248- assert_eq ! (
249- field_bytes. as_slice( ) ,
250- & hex!( "00000000000000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" )
251- ) ;
162+ /// Convert the provided bytestring into a `Scalar` for the given curve, interpreting it as big
163+ /// endian, zero-padding or truncating it to the bit length of `n` (curve order) if necessary,
164+ /// and then reducing it mod `n`.
165+ pub ( crate ) fn bytes2scalar < C : EcdsaCurve + CurveArithmetic > ( mut bytes : & [ u8 ] ) -> Scalar < C > {
166+ // Compute number of bytes in `n` (curve order)
167+ let n_bits = C :: ORDER . bits ( ) ;
168+ let n_bytes = n_bits. div_ceil ( 8 ) as usize ;
169+ if bytes. len ( ) > n_bytes {
170+ bytes = & bytes[ ..n_bytes] ;
252171 }
253172
254- #[ test]
255- fn bits2field_size_eq ( ) {
256- let prehash = hex ! ( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ) ;
257- let field_bytes = bits2field :: < MockCurve > ( & prehash) . expect ( "field bytes" ) ;
258- assert_eq ! ( field_bytes. as_slice( ) , & prehash) ;
259- }
260-
261- #[ test]
262- fn bits2field_size_greater ( ) {
263- let prehash = hex ! (
264- "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
265- ) ;
266- let field_bytes = bits2field :: < MockCurve > ( & prehash) . expect ( "field bytes" ) ;
267- assert_eq ! (
268- field_bytes. as_slice( ) ,
269- & hex!( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" )
270- ) ;
271- }
173+ <Scalar < C > as Reduce < C :: Uint > >:: reduce ( & C :: Uint :: from_be_slice_truncated ( bytes, n_bits) )
272174}
0 commit comments