1use crate::k256::{
2 elliptic_curve::{
3 bigint::{CheckedAdd, U256},
4 Curve, FieldBytesEncoding,
5 },
6 Secp256k1,
7};
8
9use super::{
10 context::{
11 ECMultContext, ECMULT_TABLE_SIZE_A, ECMULT_TABLE_SIZE_G, WINDOW_A, WINDOW_G, WNAF_BITS,
12 },
13 field::FieldElement,
14 points::{Affine, AffineStorage, Jacobian},
15 scalars::Scalar,
16 Secp256k1Err,
17};
18
19#[cfg(feature = "secp256k1-static-context")]
20pub fn recover(
21 message: &crate::k256::Scalar,
22 signature: &crate::k256::ecdsa::Signature,
23 recovery_id: &crate::k256::ecdsa::RecoveryId,
24) -> Result<Affine, Secp256k1Err> {
25 use super::context::ECRECOVER_CONTEXT;
26
27 recover_with_context(message, signature, recovery_id, &ECRECOVER_CONTEXT)
28}
29
30pub fn recover_with_context(
31 message: &crate::k256::Scalar,
32 signature: &crate::k256::ecdsa::Signature,
33 recovery_id: &crate::k256::ecdsa::RecoveryId,
34 context: &ECMultContext,
35) -> Result<Affine, Secp256k1Err> {
36 recover_with_context_and_hooks(
37 message,
38 signature,
39 recovery_id,
40 context,
41 &mut super::hooks::DefaultSecp256k1Hooks,
42 )
43}
44
45#[cfg(feature = "secp256k1-static-context")]
46pub fn recover_with_hooks<H: super::hooks::Secp256k1Hooks>(
47 message: &crate::k256::Scalar,
48 signature: &crate::k256::ecdsa::Signature,
49 recovery_id: &crate::k256::ecdsa::RecoveryId,
50 hooks: &mut H,
51) -> Result<Affine, Secp256k1Err> {
52 use super::context::ECRECOVER_CONTEXT;
53
54 recover_with_context_and_hooks(message, signature, recovery_id, &ECRECOVER_CONTEXT, hooks)
55}
56
57pub fn recover_with_context_and_hooks<H: super::hooks::Secp256k1Hooks>(
58 message: &crate::k256::Scalar,
59 signature: &crate::k256::ecdsa::Signature,
60 recovery_id: &crate::k256::ecdsa::RecoveryId,
61 context: &ECMultContext,
62 hooks: &mut H,
63) -> Result<Affine, Secp256k1Err> {
64 let (mut sigr, mut sigs) = Scalar::from_signature(signature);
65 let message = Scalar::from_k256_scalar(*message);
66
67 let mut brx = sigr.to_repr();
69
70 if recovery_id.is_x_reduced() {
71 match <U256 as FieldBytesEncoding<Secp256k1>>::decode_field_bytes(&brx)
72 .checked_add(&Secp256k1::ORDER)
73 .into_option()
74 {
75 Some(restored) => {
76 brx = <U256 as FieldBytesEncoding<Secp256k1>>::encode_field_bytes(&restored);
77 }
78 None => return Err(Secp256k1Err::OperationOverflow),
79 }
80 }
81
82 let is_odd = recovery_id.is_y_odd();
83 let x =
84 Affine::decompress_with_hooks(&brx, is_odd, hooks).ok_or(Secp256k1Err::InvalidParams)?;
85
86 let xj = x.to_jacobian();
87
88 hooks.scalar_invert_and_assign(&mut sigr);
89 sigs *= sigr;
90
91 sigr *= message;
92 sigr.negate_in_place();
93
94 let mut pk = ecmult(&xj, &sigs, &sigr, context).to_affine_with_hooks(hooks);
95 pk.normalize_in_place();
96
97 if pk.is_infinity() {
98 return Err(Secp256k1Err::RecoveredInfinity);
99 }
100
101 Ok(pk)
102}
103
104fn ecmult(a: &Jacobian, na: &Scalar, ng: &Scalar, context: &ECMultContext) -> Jacobian {
107 let mut z = FieldElement::ONE;
108
109 let mut prea: [Affine; ECMULT_TABLE_SIZE_A] = [Affine::DEFAULT; ECMULT_TABLE_SIZE_A];
110 let mut aux: [FieldElement; ECMULT_TABLE_SIZE_A] = [FieldElement::ZERO; ECMULT_TABLE_SIZE_A];
111
112 let mut bits_na_1 = 0;
113 let mut bits_na_lam = 0;
114
115 let mut bits_ng_1 = 0;
116 let mut bits_ng_128 = 0;
117
118 let mut wnaf_na_1 = [0i32; WNAF_BITS];
119 let mut wnaf_na_lam = [0i32; WNAF_BITS];
120
121 let mut wnaf_ng_1 = [0i32; WNAF_BITS];
122 let mut wnaf_ng_128 = [0i32; WNAF_BITS];
123
124 let mut bits = 0;
125
126 if !na.is_zero() && !a.is_infinity() {
127 let (na_1, na_lam) = na.decompose();
132
133 bits_na_1 = wnaf(&mut wnaf_na_1, &na_1, WINDOW_A);
135 bits_na_lam = wnaf(&mut wnaf_na_lam, &na_lam, WINDOW_A);
136
137 debug_assert!(bits_na_1 <= WNAF_BITS as i32);
138 debug_assert!(bits_na_lam <= WNAF_BITS as i32);
139
140 if bits_na_1 > bits_na_lam {
141 bits = bits_na_1;
142 } else {
143 bits = bits_na_lam;
144 }
145
146 odd_multiples_table_windowa(&mut prea, &mut aux, &mut z, a);
151 table_set_globalz_windowa(&mut prea, &aux);
152
153 for i in 0..ECMULT_TABLE_SIZE_A {
154 aux[i] = FieldElement::BETA;
155 aux[i] *= prea[i].x;
156 }
157 }
158
159 if !ng.is_zero() {
160 let (ng_1, ng_128) = ng.decompose_128(); bits_ng_1 = wnaf(&mut wnaf_ng_1, &ng_1, WINDOW_G);
169 bits_ng_128 = wnaf(&mut wnaf_ng_128, &ng_128, WINDOW_G);
170
171 if bits_ng_1 > bits {
172 bits = bits_ng_1;
173 }
174 if bits_ng_128 > bits {
175 bits = bits_ng_128;
176 }
177 }
178
179 let mut r = Jacobian::INFINITY;
180
181 for i in (0..bits).rev() {
182 r.double_in_place(None);
183
184 let n = wnaf_na_1[i as usize];
185 if i < bits_na_1 && n != 0 {
186 r.add_ge_in_place(table_get_ge(&prea, n, WINDOW_A), None);
187 }
188
189 let n = wnaf_na_lam[i as usize];
190 if i < bits_na_lam && n != 0 {
191 r.add_ge_in_place(table_get_ge_lambda(&prea, &aux, n, WINDOW_A), None);
192 }
193
194 let n = wnaf_ng_1[i as usize];
195 if i < bits_ng_1 && n != 0 {
196 r.add_zinv_in_place(table_get_ge_storage(&context.pre_g, n, WINDOW_G), &z);
197 }
198
199 let n = wnaf_ng_128[i as usize];
200 if i < bits_ng_128 && n != 0 {
201 r.add_zinv_in_place(table_get_ge_storage(&context.pre_g_128, n, WINDOW_G), &z);
202 }
203 }
204
205 if !r.is_infinity() {
206 r.z *= z
207 }
208
209 r
210}
211
212fn odd_multiples_table_windowa(
222 pre_a: &mut [Affine; ECMULT_TABLE_SIZE_A],
223 zr: &mut [FieldElement; ECMULT_TABLE_SIZE_A],
224 z: &mut FieldElement,
225 a: &Jacobian,
226) {
227 debug_assert!(!a.is_infinity());
228
229 let mut d = *a;
230 d.double_in_place(None);
231
232 let d_ge = Affine {
241 x: d.x,
242 y: d.y,
243 infinity: false,
244 };
245
246 pre_a[0].set_gej_zinv(a, &d.z);
247
248 let mut ai = Jacobian {
249 x: pre_a[0].x,
250 y: pre_a[0].y,
251 z: a.z,
252 };
253
254 zr[0] = d.z;
257
258 for i in 1..ECMULT_TABLE_SIZE_A {
259 ai.add_ge_in_place(d_ge, Some(&mut zr[i]));
260 pre_a[i] = Affine {
261 x: ai.x,
262 y: ai.y,
263 infinity: false,
264 };
265 }
266
267 *z = ai.z;
271 *z *= d.z;
272}
273
274fn table_set_globalz_windowa(
275 pre_a: &mut [Affine; ECMULT_TABLE_SIZE_A],
276 zr: &[FieldElement; ECMULT_TABLE_SIZE_A],
277) {
278 let mut i = ECMULT_TABLE_SIZE_A - 1;
279
280 pre_a[i].y.normalize_in_place();
281
282 let mut zs = zr[i];
283
284 i -= 1;
285
286 let mut ai = pre_a[i];
287 pre_a[i].set_ge_zinv(&ai, &zs);
288
289 while i > 0 {
290 zs *= zr[i];
291 i -= 1;
292
293 ai = pre_a[i];
294 pre_a[i].set_ge_zinv(&ai, &zs);
295 }
296}
297
298fn wnaf(wnaf: &mut [i32], s: &Scalar, w: usize) -> i32 {
306 debug_assert!(wnaf.len() <= 256);
307 debug_assert!((2..=31).contains(&w));
308 debug_assert!(wnaf.iter().all(|&x| x == 0));
309
310 let mut s = *s;
311
312 let mut last_set_bit: i32 = -1;
313 let mut bit = 0;
314 let mut sign = 1;
315 let mut carry = 0;
316
317 if s.bits(255, 1) > 0 {
318 s.negate_in_place();
320 sign = -1;
321 }
322
323 while bit < wnaf.len() {
324 if s.bits(bit, 1) == carry as u32 {
325 bit += 1;
326 continue;
327 }
328
329 let mut now = w;
330 if now > wnaf.len() - bit {
331 now = wnaf.len() - bit;
332 }
333
334 let mut word = (s.bits_var(bit, now) as i32) + carry;
335
336 carry = (word >> (w - 1)) & 1;
337 word -= carry << w;
338
339 wnaf[bit] = sign * word;
340 last_set_bit = bit as i32;
341
342 bit += now;
343 }
344 debug_assert_eq!(carry, 0);
345 debug_assert!({
346 let mut t = true;
347 while bit < 256 {
348 t = t && (s.bits(bit, 1) == 0);
349 bit += 1;
350 }
351 t
352 });
353
354 last_set_bit + 1
355}
356
357fn table_get_ge(pre: &[Affine], n: i32, w: usize) -> Affine {
358 debug_assert!(table_verify(n, w));
359
360 if n > 0 {
361 pre[(n - 1) as usize / 2]
362 } else {
363 let mut r = pre[(-n - 1) as usize / 2];
364 r.y.negate_in_place(1);
365 r
366 }
367}
368
369fn table_get_ge_lambda(pre: &[Affine], aux: &[FieldElement], n: i32, w: usize) -> Affine {
370 debug_assert!(table_verify(n, w));
371
372 if n > 0 {
373 Affine {
374 x: aux[(n - 1) as usize / 2],
375 y: pre[(n - 1) as usize / 2].y,
376 infinity: false,
377 }
378 } else {
379 let mut y = pre[(-n - 1) as usize / 2].y;
380 y.negate_in_place(1);
381
382 Affine {
383 x: aux[(-n - 1) as usize / 2],
384 y,
385 infinity: false,
386 }
387 }
388}
389
390fn table_get_ge_storage(pre: &[AffineStorage; ECMULT_TABLE_SIZE_G], n: i32, w: usize) -> Affine {
391 debug_assert!(table_verify(n, w));
392
393 if n > 0 {
394 pre[(n - 1) as usize / 2].to_affine()
395 } else {
396 let mut r = pre[(-n - 1) as usize / 2].to_affine();
397 r.y.negate_in_place(1);
398 r
399 }
400}
401
402fn table_verify(n: i32, w: usize) -> bool {
403 (2..=31).contains(&w) && ((n & 1) == 1) && (n >= -((1 << (w - 1)) - 1)) && (n < (1 << (w - 1)))
404}
405
406#[cfg(test)]
407mod tests {
408 #![allow(non_snake_case)]
409
410 use super::ecmult;
411 use crate::secp256k1::scalars::Scalar;
412 use crate::secp256k1::{context::ECRECOVER_CONTEXT, test_vectors::MUL_TEST_VECTORS};
413 use crate::secp256k1::{
414 field::FieldElement,
415 points::{Affine, Jacobian},
416 };
417
418 use proptest::{prop_assert_eq, proptest};
419
420 #[cfg(feature = "secp256k1-static-context")]
421 #[test]
422 fn ecmult_0I_0G() {
423 assert_eq!(ECRECOVER_CONTEXT.pre_g[0].to_affine(), Affine::GENERATOR);
424
425 let res = ecmult(
427 &Jacobian::INFINITY,
428 &Scalar::ZERO,
429 &Scalar::ZERO,
430 &ECRECOVER_CONTEXT,
431 )
432 .to_affine();
433
434 assert!(res.is_infinity());
435 }
436
437 #[cfg(feature = "secp256k1-static-context")]
438 #[test]
439 fn ecmult_0I_1G() {
440 let mut res = ecmult(
442 &Jacobian::INFINITY,
443 &Scalar::ZERO,
444 &Scalar::ONE,
445 &ECRECOVER_CONTEXT,
446 )
447 .to_affine();
448
449 res.normalize_in_place();
450
451 assert_eq!(res, Affine::GENERATOR);
452 }
453
454 #[cfg(feature = "secp256k1-static-context")]
455 #[test]
456 fn ecmult_0I_3G() {
457 let res = ecmult(
459 &Jacobian::INFINITY,
460 &Scalar::ZERO,
461 &Scalar::from_u128(3),
462 &ECRECOVER_CONTEXT,
463 )
464 .to_affine();
465
466 assert_eq!(res, ECRECOVER_CONTEXT.pre_g[1].to_affine())
467 }
468
469 #[cfg(feature = "secp256k1-static-context")]
470 #[test]
471 fn ecmult_0I_5G() {
472 let res = ecmult(
473 &Jacobian::INFINITY,
474 &Scalar::ZERO,
475 &Scalar::from_u128(5),
476 &ECRECOVER_CONTEXT,
477 )
478 .to_affine();
479
480 assert_eq!(res, ECRECOVER_CONTEXT.pre_g[2].to_affine());
481 }
482
483 #[cfg(feature = "secp256k1-static-context")]
484 #[test]
485 fn ecmult_0I_8G() {
486 let mut t = ECRECOVER_CONTEXT.pre_g[2].to_affine().to_jacobian();
488 t.add_ge_in_place(ECRECOVER_CONTEXT.pre_g[1].to_affine(), None);
489
490 let t = t.to_affine();
491
492 let res = ecmult(
494 &Jacobian::INFINITY,
495 &Scalar::ZERO,
496 &Scalar::from_u128(8),
497 &ECRECOVER_CONTEXT,
498 )
499 .to_affine();
500
501 assert_eq!(res, t);
502 }
503
504 #[cfg(feature = "secp256k1-static-context")]
505 #[test]
506 fn ecmult_1G_0G() {
507 let res = ecmult(
508 &Affine::GENERATOR.to_jacobian(),
509 &Scalar::ONE,
510 &Scalar::ZERO,
511 &ECRECOVER_CONTEXT,
512 )
513 .to_affine();
514
515 assert_eq!(res, Affine::GENERATOR);
516 }
517
518 #[cfg(feature = "secp256k1-static-context")]
519 #[test]
520 fn ecmult_1G_1G() {
521 let res = ecmult(
522 &Affine::GENERATOR.to_jacobian(),
523 &Scalar::ONE,
524 &Scalar::ONE,
525 &ECRECOVER_CONTEXT,
526 )
527 .to_affine();
528
529 let mut expected = Affine::GENERATOR.to_jacobian();
530 expected.double_in_place(None);
531
532 assert_eq!(res, expected.to_affine())
533 }
534
535 #[cfg(feature = "secp256k1-static-context")]
536 #[test]
537 fn ecmult_1G_2G() {
538 let res = ecmult(
539 &Affine::GENERATOR.to_jacobian(),
540 &Scalar::ONE,
541 &Scalar::from_u128(2),
542 &ECRECOVER_CONTEXT,
543 )
544 .to_affine();
545
546 assert_eq!(res, ECRECOVER_CONTEXT.pre_g[1].to_affine());
547 }
548
549 #[cfg(feature = "secp256k1-static-context")]
550 #[test]
551 fn ecmult_2G_1G() {
552 let mut res = ecmult(
553 &Affine::GENERATOR.to_jacobian(),
554 &Scalar::from_u128(2),
555 &Scalar::ONE,
556 &ECRECOVER_CONTEXT,
557 )
558 .to_affine();
559
560 res.normalize_in_place();
561
562 assert_eq!(res, ECRECOVER_CONTEXT.pre_g[1].to_affine());
563 }
564
565 #[cfg(feature = "secp256k1-static-context")]
566 #[test]
567 fn compare_ecmult() {
568 proptest!(|(k: Scalar)| {
569 let res1 = ecmult(
570 &Jacobian::INFINITY,
571 &Scalar::ZERO,
572 &k,
573 &ECRECOVER_CONTEXT
574 ).to_affine();
575
576 let res2 = ecmult(
577 &Affine::GENERATOR.to_jacobian(),
578 &k,
579 &Scalar::ZERO,
580 &ECRECOVER_CONTEXT
581 ).to_affine();
582
583 prop_assert_eq!(res1, res2);
584 })
585 }
586
587 #[cfg(feature = "secp256k1-static-context")]
588 #[test]
589 fn test_generator_multipules() {
590 for (k, x, y) in MUL_TEST_VECTORS {
591 let k = Scalar::from_repr((*k).into());
592
593 let computed_ctx =
594 ecmult(&Jacobian::INFINITY, &Scalar::ZERO, &k, &ECRECOVER_CONTEXT).to_affine();
595
596 let computed = ecmult(
597 &Affine::GENERATOR.to_jacobian(),
598 &k,
599 &Scalar::ZERO,
600 &ECRECOVER_CONTEXT,
601 )
602 .to_affine();
603
604 let expected = Affine {
605 x: FieldElement::from_bytes_unchecked(x),
606 y: FieldElement::from_bytes_unchecked(y),
607 infinity: false,
608 };
609
610 assert_eq!(computed_ctx, computed);
611 assert_eq!(computed_ctx, expected);
612 }
613 }
614
615 #[cfg(feature = "secp256k1-static-context")]
616 #[test]
617 fn test_regressions() {
618 assert_eq!(
620 recover_from_digest(
621 [
622 107, 141, 44, 129, 177, 27, 45, 105, 149, 40, 221, 228, 136, 219, 223, 47, 148,
623 41, 61, 13, 51, 195, 46, 52, 127, 37, 95, 164, 166, 193, 240, 169
624 ],
625 [
626 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2,
627 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152
628 ],
629 [
630 107, 141, 44, 129, 177, 27, 45, 105, 149, 40, 221, 228, 136, 219, 223, 47, 148,
631 41, 61, 13, 51, 195, 46, 52, 127, 37, 95, 164, 166, 193, 240, 169
632 ],
633 0
634 )
635 .unwrap_err(),
636 super::Secp256k1Err::RecoveredInfinity
637 );
638
639 assert_eq!(
641 recover_from_digest(
642 [
643 56, 209, 138, 203, 103, 210, 92, 139, 185, 148, 39, 100, 182, 47, 24, 225, 112,
644 84, 246, 106, 129, 123, 212, 41, 84, 35, 173, 249, 237, 152, 135, 62
645 ],
646 [
647 56, 209, 138, 203, 103, 210, 92, 139, 185, 148, 39, 100, 182, 47, 24, 225, 112,
648 84, 246, 106, 129, 123, 212, 41, 84, 35, 173, 249, 237, 152, 135, 62
649 ],
650 [
651 120, 157, 29, 212, 35, 210, 95, 7, 114, 210, 116, 141, 96, 247, 228, 184, 27,
652 177, 77, 8, 110, 186, 142, 142, 142, 251, 109, 207, 248, 164, 174, 2
653 ],
654 0
655 ),
656 Ok(Affine {
657 x: FieldElement::from_bytes_unchecked(&[
658 134, 18, 84, 164, 207, 141, 253, 45, 96, 226, 163, 62, 49, 67, 234, 198, 40,
659 88, 134, 240, 174, 217, 23, 17, 171, 126, 44, 1, 63, 38, 92, 85
660 ]),
661 y: FieldElement::from_bytes_unchecked(&[
662 253, 69, 102, 103, 243, 176, 134, 87, 121, 95, 230, 117, 75, 111, 188, 17, 24,
663 103, 20, 196, 228, 244, 141, 91, 133, 104, 0, 227, 232, 28, 48, 200
664 ]),
665 infinity: false
666 })
667 )
668 }
669
670 #[cfg(feature = "secp256k1-static-context")]
671 fn recover_from_digest(
672 digest: [u8; 32],
673 r: [u8; 32],
674 s: [u8; 32],
675 rec_id: u8,
676 ) -> Result<Affine, super::Secp256k1Err> {
677 use k256::ecdsa::{RecoveryId, Signature};
678 use {
679 k256::elliptic_curve::ops::Reduce,
680 k256::{ecdsa::hazmat::bits2field, Scalar},
681 };
682
683 let signature = Signature::from_scalars(r, s).unwrap();
684 let recovery_id = RecoveryId::try_from(rec_id).unwrap();
685
686 let message = <Scalar as Reduce<k256::U256>>::reduce_bytes(
687 &bits2field::<k256::Secp256k1>(&digest).unwrap(),
688 );
689
690 super::recover(&message, &signature, &recovery_id)
691 }
692
693 #[cfg(feature = "secp256k1-static-context")]
694 #[test]
695 fn recover_with_default_hooks_matches_recover() {
696 use crate::secp256k1::hooks::DefaultSecp256k1Hooks;
697 use k256::ecdsa::{RecoveryId, Signature};
698 use {
699 k256::elliptic_curve::ops::Reduce,
700 k256::{ecdsa::hazmat::bits2field, Scalar},
701 };
702
703 let digest = [
704 56, 209, 138, 203, 103, 210, 92, 139, 185, 148, 39, 100, 182, 47, 24, 225, 112, 84,
705 246, 106, 129, 123, 212, 41, 84, 35, 173, 249, 237, 152, 135, 62,
706 ];
707 let r = digest;
708 let s = [
709 120, 157, 29, 212, 35, 210, 95, 7, 114, 210, 116, 141, 96, 247, 228, 184, 27, 177, 77,
710 8, 110, 186, 142, 142, 142, 251, 109, 207, 248, 164, 174, 2,
711 ];
712
713 let signature = Signature::from_scalars(r, s).unwrap();
714 let recovery_id = RecoveryId::try_from(0u8).unwrap();
715 let message = <Scalar as Reduce<k256::U256>>::reduce_bytes(
716 &bits2field::<k256::Secp256k1>(&digest).unwrap(),
717 );
718
719 let without_hooks = super::recover(&message, &signature, &recovery_id).unwrap();
720 let with_hooks = super::recover_with_hooks(
721 &message,
722 &signature,
723 &recovery_id,
724 &mut DefaultSecp256k1Hooks,
725 )
726 .unwrap();
727
728 assert_eq!(without_hooks, with_hooks);
729 }
730}