1use big_number::Uint;
2
3use crate::{EllipticCurveError, Hasher, hmac::Hmac, sha2::Sha256};
4
5pub const SECRET_KEY_SIZE: usize = 28;
7pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 29;
9pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 57;
11pub const SIGNATURE_SIZE: usize = 56;
13pub const ECDH_SHARED_SECRET_SIZE: usize = 28;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub struct SecretKey {
50 scalar: Scalar,
51 public_point: AffinePoint,
52}
53
54impl SecretKey {
55 #[cfg(feature = "random")]
56 pub fn generate() -> Result<SecretKey, EllipticCurveError> {
57 let key: [u8; SECRET_KEY_SIZE] = crate::random::random_bytes();
58 Self::from_bytes(&key)
59 }
60
61 pub fn from_bytes(key: &[u8; SECRET_KEY_SIZE]) -> Result<SecretKey, EllipticCurveError> {
62 let scalar = Scalar::from_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
63 let public_point = scalar_mul_generator(&scalar)
64 .to_affine()
65 .ok_or(EllipticCurveError::Unspecified)?;
66 Ok(SecretKey {
67 scalar,
68 public_point,
69 })
70 }
71
72 pub fn public_key(&self) -> PublicKey {
73 PublicKey {
74 point: self.public_point,
75 }
76 }
77
78 pub fn sign(&self, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
79 ecdsa_sign_inner(&self.scalar, message)
80 }
81
82 pub fn ecdh(&self, peer_public: &PublicKey) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
83 ecdh_inner(&self.scalar, &peer_public.point)
84 }
85
86 pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE] {
87 self.scalar.to_bytes()
88 }
89}
90
91#[derive(Clone, Copy, Debug, PartialEq, Eq)]
108pub struct PublicKey {
109 point: AffinePoint,
110}
111
112impl PublicKey {
113 #[inline]
114 pub fn from_bytes(key: &[u8]) -> Result<PublicKey, EllipticCurveError> {
115 let point = AffinePoint::from_sec1_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
116 Ok(PublicKey {
117 point,
118 })
119 }
120
121 #[inline]
128 pub fn from_x_y(x_bytes: &[u8; 28], y_bytes: &[u8; 28]) -> Result<PublicKey, EllipticCurveError> {
129 let x = FieldElement::from_bytes(x_bytes).ok_or(EllipticCurveError::InvalidKey)?;
130 let y = FieldElement::from_bytes(y_bytes).ok_or(EllipticCurveError::InvalidKey)?;
131 let point = AffinePoint::new(x, y).ok_or(EllipticCurveError::InvalidKey)?;
132 Ok(PublicKey {
133 point,
134 })
135 }
136
137 pub fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
138 ecdsa_verify_inner(&self.point, message, signature)
139 }
140
141 #[inline]
142 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
143 self.point.to_uncompressed_bytes()
144 }
145
146 #[inline]
153 pub fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
154 self.point.to_compressed_bytes()
155 }
156
157 #[inline]
159 pub fn x_y(&self) -> ([u8; 28], [u8; 28]) {
160 (self.point.x.to_bytes(), self.point.y.to_bytes())
161 }
162}
163
164type U224 = Uint<224, 4>;
165
166#[inline]
170fn u224_from_be(bytes: &[u8; 28]) -> U224 {
171 U224::from_limbs([
172 u64::from_be_bytes(bytes[20..28].try_into().unwrap()),
173 u64::from_be_bytes(bytes[12..20].try_into().unwrap()),
174 u64::from_be_bytes(bytes[4..12].try_into().unwrap()),
175 u32::from_be_bytes(bytes[0..4].try_into().unwrap()) as u64,
176 ])
177}
178
179#[inline]
180fn u224_to_be(value: U224) -> [u8; 28] {
181 let mut out = [0u8; 28];
182 out[20..28].copy_from_slice(&value.limbs[0].to_be_bytes());
183 out[12..20].copy_from_slice(&value.limbs[1].to_be_bytes());
184 out[4..12].copy_from_slice(&value.limbs[2].to_be_bytes());
185 out[0..4].copy_from_slice(&(value.limbs[3] as u32).to_be_bytes());
186 out
187}
188
189const MODULUS_P: U224 = U224::from_limbs([
190 0x0000_0000_0000_0001,
191 0xffff_ffff_0000_0000,
192 0xffff_ffff_ffff_ffff,
193 0x0000_0000_ffff_ffff,
194]);
195
196const MODULUS_N: U224 = U224::from_limbs([
197 0x13dd_2945_5c5c_2a3d,
198 0xffff_16a2_e0b8_f03e,
199 0xffff_ffff_ffff_ffff,
200 0x0000_0000_ffff_ffff,
201]);
202
203const P_MINUS_TWO: U224 = U224::from_limbs([
204 0xffff_ffff_ffff_ffff,
205 0xffff_fffe_ffff_ffff,
206 0xffff_ffff_ffff_ffff,
207 0x0000_0000_ffff_ffff,
208]);
209
210const N_MINUS_TWO: U224 = U224::from_limbs([
211 0x13dd_2945_5c5c_2a3b,
212 0xffff_16a2_e0b8_f03e,
213 0xffff_ffff_ffff_ffff,
214 0x0000_0000_ffff_ffff,
215]);
216
217const P_MINUS_ONE_OVER_TWO: U224 = U224::from_limbs([
219 0x0000_0000_0000_0000,
220 0xffff_ffff_8000_0000,
221 0xffff_ffff_ffff_ffff,
222 0x0000_0000_7fff_ffff,
223]);
224
225const TONELLI_S: usize = 96;
228const TONELLI_D: U224 = U224::from_limbs([
229 0xffff_ffff_ffff_ffff,
230 0xffff_ffff_ffff_ffff,
231 0x0000_0000_0000_0000,
232 0x0000_0000_0000_0000,
233]);
234const TONELLI_D_PLUS_ONE_OVER_TWO: U224 = U224::from_limbs([
235 0x0000_0000_0000_0000,
236 0x8000_0000_0000_0000,
237 0x0000_0000_0000_0000,
238 0x0000_0000_0000_0000,
239]);
240const TONELLI_NON_RESIDUE: FieldElement = FieldElement(U224::from_u64(11));
242
243const P_MU: [u64; 5] = [
246 0x0000_0000_ffff_ffff,
247 0xffff_ffff_ffff_ffff,
248 0x0000_0000_ffff_ffff,
249 0x0000_0000_0000_0000,
250 0x0000_0001_0000_0000,
251];
252
253const N_MU: [u64; 5] = [
254 0xd4ba_a4cf_1822_bc47,
255 0xec22_d6ba_a3a3_d5c3,
256 0x0000_e95d_1f47_0fc1,
257 0x0000_0000_0000_0000,
258 0x0000_0001_0000_0000,
259];
260
261const CURVE_B: FieldElement = FieldElement(U224::from_limbs([
262 0x270b_3943_2355_ffb4,
263 0x5044_b0b7_d7bf_d8ba,
264 0x0c04_b3ab_f541_3256,
265 0x0000_0000_b405_0a85,
266]));
267
268const GENERATOR_X: FieldElement = FieldElement(U224::from_limbs([
269 0x3432_80d6_115c_1d21,
270 0x4a03_c1d3_56c2_1122,
271 0x6bb4_bf7f_3213_90b9,
272 0x0000_0000_b70e_0cbd,
273]));
274
275const GENERATOR_Y: FieldElement = FieldElement(U224::from_limbs([
276 0x44d5_8199_8500_7e34,
277 0xcd43_75a0_5a07_4764,
278 0xb5f7_23fb_4c22_dfe6,
279 0x0000_0000_bd37_6388,
280]));
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283struct FieldElement(U224);
284
285impl FieldElement {
286 const ZERO: Self = Self(U224::ZERO);
287 const ONE: Self = Self(U224::ONE);
288
289 #[inline]
290 fn from_bytes(bytes: &[u8; 28]) -> Option<Self> {
291 let value = u224_from_be(bytes);
292 if value.ct_ge(&MODULUS_P) {
293 None
294 } else {
295 Some(Self(value))
296 }
297 }
298
299 #[inline]
300 fn to_bytes(self) -> [u8; 28] {
301 u224_to_be(self.0)
302 }
303
304 #[inline]
305 fn is_zero(&self) -> bool {
306 self.0.is_zero()
307 }
308
309 #[inline]
310 fn is_odd(&self) -> bool {
311 self.0.is_odd()
312 }
313
314 #[inline]
315 fn add(self, rhs: Self) -> Self {
316 Self(self.0.add_mod(&rhs.0, &MODULUS_P))
317 }
318
319 #[inline]
320 fn sub(self, rhs: Self) -> Self {
321 Self(self.0.sub_mod(&rhs.0, &MODULUS_P))
322 }
323
324 #[inline]
325 fn double(self) -> Self {
326 Self(self.0.double_mod(&MODULUS_P))
327 }
328
329 #[inline]
330 fn square(self) -> Self {
331 self.mul(self)
332 }
333
334 #[inline]
335 fn mul(self, rhs: Self) -> Self {
336 Self(self.0.mul_mod_barrett(&rhs.0, &MODULUS_P, &P_MU))
337 }
338
339 #[inline]
340 fn triple(self) -> Self {
341 self.double().add(self)
342 }
343
344 #[inline]
345 fn negate(self) -> Self {
346 let (diff, _) = MODULUS_P.sub_raw(&self.0);
347 Self(U224::ct_select(&U224::ZERO, &diff, self.is_zero()))
348 }
349
350 #[inline]
351 fn pow(self, exponent: &U224) -> Self {
352 let mut result = Self::ONE;
353 let mut i = 224usize;
354 while i > 0 {
355 i -= 1;
356 result = result.square();
357 let product = result.mul(self);
358 result = Self::select(&product, &result, exponent.bit(i));
359 }
360 result
361 }
362
363 #[inline]
364 fn invert(self) -> Option<Self> {
365 Some(self.pow(&P_MINUS_TWO))
366 }
367
368 #[inline]
376 fn sqrt(self) -> Option<Self> {
377 if self.is_zero() {
378 return Some(Self::ZERO);
379 }
380 if self.pow(&P_MINUS_ONE_OVER_TWO) != Self::ONE {
381 return None;
382 }
383
384 let mut m = TONELLI_S;
385 let mut c = TONELLI_NON_RESIDUE.pow(&TONELLI_D);
386 let mut t = self.pow(&TONELLI_D);
387 let mut r = self.pow(&TONELLI_D_PLUS_ONE_OVER_TWO);
388
389 while t != Self::ONE {
390 let mut i = 0usize;
392 let mut probe = t;
393 while probe != Self::ONE {
394 probe = probe.square();
395 i += 1;
396 if i >= m {
397 return None;
398 }
399 }
400
401 let mut b = c;
402 for _ in 0..(m - i - 1) {
403 b = b.square();
404 }
405
406 m = i;
407 c = b.square();
408 t = t.mul(c);
409 r = r.mul(b);
410 }
411
412 if r.square() == self { Some(r) } else { None }
413 }
414
415 #[inline]
416 fn select(a: &Self, b: &Self, choice: bool) -> Self {
417 Self(U224::ct_select(&a.0, &b.0, choice))
418 }
419}
420
421#[derive(Clone, Copy, Debug, PartialEq, Eq)]
422struct Scalar(U224);
423
424impl Scalar {
425 const ZERO: Self = Self(U224::ZERO);
426 const ONE: Self = Self(U224::ONE);
427
428 #[inline]
429 fn from_bytes(bytes: &[u8; 28]) -> Option<Self> {
430 let value = u224_from_be(bytes);
431 if value.is_zero() || value.ct_ge(&MODULUS_N) {
432 None
433 } else {
434 Some(Self(value))
435 }
436 }
437
438 #[inline]
441 fn from_reduced_bytes(bytes: &[u8; 28]) -> Self {
442 let value = u224_from_be(bytes);
443 let (sub_value, _) = value.sub_raw(&MODULUS_N);
444 let reduced = U224::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N));
445 Self(reduced)
446 }
447
448 #[inline]
451 fn from_hash(hash: &[u8; 32]) -> Self {
452 Self::from_reduced_bytes(&hash[..28].try_into().unwrap())
453 }
454
455 #[inline]
456 fn to_bytes(self) -> [u8; 28] {
457 u224_to_be(self.0)
458 }
459
460 #[inline]
461 fn is_zero(&self) -> bool {
462 self.0.is_zero()
463 }
464
465 #[inline]
466 fn bit(&self, index: usize) -> bool {
467 self.0.bit(index)
468 }
469
470 #[inline]
471 fn add(self, rhs: Self) -> Self {
472 Self(self.0.add_mod(&rhs.0, &MODULUS_N))
473 }
474
475 #[cfg(test)]
476 #[inline]
477 fn sub(self, rhs: Self) -> Self {
478 Self(self.0.sub_mod(&rhs.0, &MODULUS_N))
479 }
480
481 #[inline]
482 fn mul(self, rhs: Self) -> Self {
483 Self(self.0.mul_mod_barrett(&rhs.0, &MODULUS_N, &N_MU))
484 }
485
486 #[inline]
487 fn invert(self) -> Option<Self> {
488 Some(Self(self.scalar_pow(&N_MINUS_TWO)))
489 }
490
491 #[inline]
492 fn scalar_pow(self, exponent: &U224) -> U224 {
493 let mut result = Scalar::ONE;
494 let mut i = 224usize;
495 while i > 0 {
496 i -= 1;
497 result = result.mul(result);
498 let product = result.mul(self);
499 result = Scalar::select(&product, &result, exponent.bit(i));
500 }
501 result.0
502 }
503
504 #[inline]
505 fn select(a: &Self, b: &Self, choice: bool) -> Self {
506 Self(U224::ct_select(&a.0, &b.0, choice))
507 }
508}
509
510#[derive(Clone, Copy, Debug, PartialEq, Eq)]
511struct AffinePoint {
512 x: FieldElement,
513 y: FieldElement,
514 infinity: bool,
515}
516
517impl AffinePoint {
518 const GENERATOR: Self = Self {
519 x: GENERATOR_X,
520 y: GENERATOR_Y,
521 infinity: false,
522 };
523
524 #[inline]
525 fn new(x: FieldElement, y: FieldElement) -> Option<Self> {
526 let point = Self {
527 x,
528 y,
529 infinity: false,
530 };
531 if point.is_on_curve() { Some(point) } else { None }
532 }
533
534 #[inline]
535 fn is_on_curve(&self) -> bool {
536 if self.infinity {
537 return false;
538 }
539 let x2 = self.x.square();
540 let x3 = x2.mul(self.x);
541 let rhs = x3.sub(self.x.triple()).add(CURVE_B);
542 self.y.square() == rhs
543 }
544
545 #[inline]
546 fn to_uncompressed_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
547 let mut out = [0u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
548 out[0] = 0x04;
549 out[1..29].copy_from_slice(&self.x.to_bytes());
550 out[29..57].copy_from_slice(&self.y.to_bytes());
551 out
552 }
553
554 #[inline]
557 fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
558 let mut out = [0u8; PUBLIC_KEY_COMPRESSED_SIZE];
559 out[0] = if self.y.is_odd() { 0x03 } else { 0x02 };
560 out[1..29].copy_from_slice(&self.x.to_bytes());
561 out
562 }
563
564 fn from_sec1_bytes(bytes: &[u8]) -> Option<Self> {
565 match bytes.len() {
566 PUBLIC_KEY_UNCOMPRESSED_SIZE if bytes[0] == 0x04 => {
567 let x = FieldElement::from_bytes(bytes[1..29].try_into().unwrap())?;
568 let y = FieldElement::from_bytes(bytes[29..57].try_into().unwrap())?;
569 Self::new(x, y)
570 }
571 PUBLIC_KEY_COMPRESSED_SIZE if bytes[0] == 0x02 || bytes[0] == 0x03 => {
572 let x = FieldElement::from_bytes(bytes[1..29].try_into().unwrap())?;
573 let rhs = x.square().mul(x).sub(x.triple()).add(CURVE_B);
574 let y = rhs.sqrt()?;
575 let y_is_odd = y.is_odd();
576 let select_neg = y_is_odd != (bytes[0] == 0x03);
577 let y = FieldElement::select(&y.negate(), &y, select_neg);
578 Self::new(x, y)
579 }
580 _ => None,
581 }
582 }
583}
584
585#[derive(Clone, Copy, Debug, PartialEq, Eq)]
586struct ProjectivePoint {
587 x: FieldElement,
588 y: FieldElement,
589 z: FieldElement,
590}
591
592impl ProjectivePoint {
593 const IDENTITY: Self = Self {
594 x: FieldElement::ZERO,
595 y: FieldElement::ONE,
596 z: FieldElement::ZERO,
597 };
598
599 #[cfg(test)]
600 #[inline]
601 fn from_affine(point: &AffinePoint) -> Self {
602 if point.infinity {
603 Self::IDENTITY
604 } else {
605 Self {
606 x: point.x,
607 y: point.y,
608 z: FieldElement::ONE,
609 }
610 }
611 }
612
613 #[inline]
614 fn is_identity(&self) -> bool {
615 self.z.is_zero()
616 }
617
618 #[inline]
619 fn select(a: &Self, b: &Self, choice: bool) -> Self {
620 Self {
621 x: FieldElement::select(&a.x, &b.x, choice),
622 y: FieldElement::select(&a.y, &b.y, choice),
623 z: FieldElement::select(&a.z, &b.z, choice),
624 }
625 }
626
627 #[inline]
628 fn to_affine(&self) -> Option<AffinePoint> {
629 if self.is_identity() {
630 return None;
631 }
632 let z_inv = self.z.invert()?;
633 AffinePoint::new(self.x.mul(z_inv), self.y.mul(z_inv))
634 }
635
636 fn add(&self, rhs: &Self) -> Self {
637 let xx = self.x.mul(rhs.x);
638 let yy = self.y.mul(rhs.y);
639 let zz = self.z.mul(rhs.z);
640 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
641 let yz_pairs = self.y.add(self.z).mul(rhs.y.add(rhs.z)).sub(yy.add(zz));
642 let xz_pairs = self.x.add(self.z).mul(rhs.x.add(rhs.z)).sub(xx.add(zz));
643
644 let bzz_part = xz_pairs.sub(CURVE_B.mul(zz));
645 let bzz3_part = bzz_part.triple();
646 let yy_m_bzz3 = yy.sub(bzz3_part);
647 let yy_p_bzz3 = yy.add(bzz3_part);
648
649 let zz3 = zz.triple();
650 let bxz_part = CURVE_B.mul(xz_pairs).sub(zz3.add(xx));
651 let bxz3_part = bxz_part.triple();
652 let xx3_m_zz3 = xx.triple().sub(zz3);
653
654 Self {
655 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
656 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
657 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
658 }
659 }
660
661 fn add_mixed(&self, rhs: &AffinePoint) -> Self {
662 if rhs.infinity {
663 return *self;
664 }
665
666 let xx = self.x.mul(rhs.x);
667 let yy = self.y.mul(rhs.y);
668 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
669 let yz_pairs = rhs.y.mul(self.z).add(self.y);
670 let xz_pairs = rhs.x.mul(self.z).add(self.x);
671
672 let bz_part = xz_pairs.sub(CURVE_B.mul(self.z));
673 let bz3_part = bz_part.triple();
674 let yy_m_bzz3 = yy.sub(bz3_part);
675 let yy_p_bzz3 = yy.add(bz3_part);
676
677 let z3 = self.z.triple();
678 let bxz_part = CURVE_B.mul(xz_pairs).sub(z3.add(xx));
679 let bxz3_part = bxz_part.triple();
680 let xx3_m_zz3 = xx.triple().sub(z3);
681
682 Self {
683 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
684 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
685 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
686 }
687 }
688
689 fn double(&self) -> Self {
690 let xx = self.x.square();
691 let yy = self.y.square();
692 let zz = self.z.square();
693 let xy2 = self.x.mul(self.y).double();
694 let xz2 = self.x.mul(self.z).double();
695
696 let bzz_part = CURVE_B.mul(zz).sub(xz2);
697 let bzz3_part = bzz_part.triple();
698 let yy_m_bzz3 = yy.sub(bzz3_part);
699 let yy_p_bzz3 = yy.add(bzz3_part);
700 let y_frag = yy_p_bzz3.mul(yy_m_bzz3);
701 let x_frag = yy_m_bzz3.mul(xy2);
702
703 let zz3 = zz.triple();
704 let bxz2_part = CURVE_B.mul(xz2).sub(zz3.add(xx));
705 let bxz6_part = bxz2_part.triple();
706 let xx3_m_zz3 = xx.triple().sub(zz3);
707
708 let y = y_frag.add(xx3_m_zz3.mul(bxz6_part));
709 let yz2 = self.y.mul(self.z).double();
710 let x = x_frag.sub(bxz6_part.mul(yz2));
711 let z = yz2.mul(yy).double().double();
712
713 Self {
714 x,
715 y,
716 z,
717 }
718 }
719}
720
721fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
722 scalar_mul_affine(&AffinePoint::GENERATOR, scalar)
723}
724
725fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
726 let mut acc = ProjectivePoint::IDENTITY;
727 let mut bit = 224usize;
728 while bit > 0 {
729 bit -= 1;
730 acc = acc.double();
731 let candidate = acc.add_mixed(base);
732 acc = ProjectivePoint::select(&candidate, &acc, scalar.bit(bit));
733 }
734 acc
735}
736
737#[inline]
738fn hash_message(message: &[u8]) -> [u8; 32] {
739 let digest = Sha256::hash(message);
740 return digest.as_ref().try_into().unwrap();
741}
742
743#[inline]
744fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] {
745 let mac = Hmac::<Sha256>::mac(key, data);
746 return mac.as_ref().try_into().unwrap();
747}
748
749fn bits2octets(hash: &[u8; 32]) -> [u8; 28] {
752 Scalar::from_hash(hash).to_bytes()
753}
754
755fn rfc6979_init_state(private_key: &Scalar, message_hash: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
758 let x = private_key.to_bytes();
759 let h1 = bits2octets(message_hash);
760
761 let mut v = [0x01u8; 32];
762 let mut k = [0u8; 32];
763
764 let mut buf = [0u8; 89];
765 buf[..32].copy_from_slice(&v);
766 buf[32] = 0x00;
767 buf[33..61].copy_from_slice(&x);
768 buf[61..89].copy_from_slice(&h1);
769 k = hmac_sha256(&k, &buf);
770 v = hmac_sha256(&k, &v);
771
772 buf[..32].copy_from_slice(&v);
773 buf[32] = 0x01;
774 k = hmac_sha256(&k, &buf);
775 v = hmac_sha256(&k, &v);
776
777 (k, v)
778}
779
780fn rfc6979_retry(k: &mut [u8; 32], v: &mut [u8; 32]) {
781 let mut retry_buf = [0u8; 33];
782 retry_buf[..32].copy_from_slice(v);
783 retry_buf[32] = 0x00;
784 *k = hmac_sha256(k, &retry_buf);
785 *v = hmac_sha256(k, v);
786}
787
788fn rfc6979_retry_clone(k: &[u8; 32], v: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
789 let mut retry_buf = [0u8; 33];
790 retry_buf[..32].copy_from_slice(v);
791 retry_buf[32] = 0x00;
792 let k_new = hmac_sha256(k, &retry_buf);
793 let v_new = hmac_sha256(&k_new, v);
794 (k_new, v_new)
795}
796
797fn ct_select_bytes<const N: usize>(a: &[u8; N], b: &[u8; N], choice: bool) -> [u8; N] {
799 let mask = (choice as u8).wrapping_neg();
800 let mut out = [0u8; N];
801 for i in 0..N {
802 out[i] = (a[i] & mask) | (b[i] & !mask);
803 }
804 out
805}
806
807fn rfc6979_generate_k(private_key: &Scalar, message_hash: &[u8; 32]) -> Scalar {
808 let (mut k, mut v) = rfc6979_init_state(private_key, message_hash);
809
810 let mut candidate = [0u8; 28];
813 let mut found = false;
814
815 for _ in 0..3 {
816 v = hmac_sha256(&k, &v);
817 let candidate_bytes: [u8; 28] = v[..28].try_into().unwrap();
818 let val = u224_from_be(&candidate_bytes);
819 let is_valid = !val.is_zero() && !val.ct_ge(&MODULUS_N);
820
821 let take = is_valid && !found;
822 candidate = ct_select_bytes(&candidate_bytes, &candidate, take);
823 found = found || is_valid;
824
825 let (k_retry, v_retry) = rfc6979_retry_clone(&k, &v);
826 k = ct_select_bytes(&k, &k_retry, !is_valid);
827 v = ct_select_bytes(&v, &v_retry, !is_valid);
828 }
829
830 if found {
831 return Scalar::from_bytes(&candidate).unwrap_or(Scalar::ZERO);
832 }
833
834 v = hmac_sha256(&k, &v);
836 if let Some(sc) = Scalar::from_bytes(&v[..28].try_into().unwrap()) {
837 return sc;
838 }
839
840 loop {
841 v = hmac_sha256(&k, &v);
842 if let Some(sc) = Scalar::from_bytes(&v[..28].try_into().unwrap()) {
843 return sc;
844 }
845 rfc6979_retry(&mut k, &mut v);
846 }
847}
848
849fn parse_private_key(private_key: &[u8; SECRET_KEY_SIZE]) -> Result<Scalar, EllipticCurveError> {
850 Scalar::from_bytes(private_key).ok_or(EllipticCurveError::InvalidKey)
851}
852
853fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, EllipticCurveError> {
854 AffinePoint::from_sec1_bytes(public_key).ok_or(EllipticCurveError::InvalidKey)
855}
856
857#[cfg(test)]
858fn derive_public_key_uncompressed(
859 private_key: &[u8; SECRET_KEY_SIZE],
860) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], EllipticCurveError> {
861 let scalar = parse_private_key(private_key)?;
862 let point = scalar_mul_generator(&scalar)
863 .to_affine()
864 .ok_or(EllipticCurveError::Unspecified)?;
865 Ok(point.to_uncompressed_bytes())
866}
867
868#[cfg(test)]
869fn derive_public_key_compressed(
870 private_key: &[u8; SECRET_KEY_SIZE],
871) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], EllipticCurveError> {
872 let scalar = parse_private_key(private_key)?;
873 let point = scalar_mul_generator(&scalar)
874 .to_affine()
875 .ok_or(EllipticCurveError::Unspecified)?;
876 Ok(point.to_compressed_bytes())
877}
878
879fn ecdh_inner(scalar: &Scalar, peer_point: &AffinePoint) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
880 let shared_point = scalar_mul_affine(peer_point, scalar)
881 .to_affine()
882 .ok_or(EllipticCurveError::Unspecified)?;
883 Ok(shared_point.x.to_bytes())
884}
885
886pub fn ecdh(
887 secret_key: &[u8; SECRET_KEY_SIZE],
888 peer_public_key: &[u8],
889) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
890 let scalar = parse_private_key(secret_key)?;
891 let peer_point = parse_public_key(peer_public_key)?;
892 ecdh_inner(&scalar, &peer_point)
893}
894
895fn ecdsa_sign_inner(scalar: &Scalar, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
896 let message_hash = hash_message(message);
897 let z = Scalar::from_hash(&message_hash);
898
899 for _ in 0..2 {
901 let k = rfc6979_generate_k(scalar, &message_hash);
902
903 let r_point = scalar_mul_generator(&k)
904 .to_affine()
905 .ok_or(EllipticCurveError::Unspecified)?;
906 let r = Scalar::from_reduced_bytes(&r_point.x.to_bytes());
907 if r.is_zero() {
908 continue;
909 }
910
911 let kinv = k.invert().ok_or(EllipticCurveError::Unspecified)?;
912 let s = kinv.mul(z.add(r.mul(*scalar)));
913 if s.is_zero() {
914 continue;
915 }
916
917 let mut out = [0u8; SIGNATURE_SIZE];
918 out[..28].copy_from_slice(&r.to_bytes());
919 out[28..].copy_from_slice(&s.to_bytes());
920 return Ok(out);
921 }
922
923 Err(EllipticCurveError::Unspecified)
924}
925
926fn ecdsa_verify_inner(
927 public_point: &AffinePoint,
928 message: &[u8],
929 signature: &[u8; SIGNATURE_SIZE],
930) -> Result<(), EllipticCurveError> {
931 let r = Scalar::from_bytes(signature[..28].try_into().unwrap()).ok_or(EllipticCurveError::Unspecified)?;
932 let s = Scalar::from_bytes(signature[28..].try_into().unwrap()).ok_or(EllipticCurveError::Unspecified)?;
933 let z = Scalar::from_hash(&hash_message(message));
934
935 let w = s.invert().ok_or(EllipticCurveError::Unspecified)?;
936 let u1 = z.mul(w);
937 let u2 = r.mul(w);
938
939 let point = scalar_mul_generator(&u1).add(&scalar_mul_affine(public_point, &u2));
940 let affine = point.to_affine().ok_or(EllipticCurveError::Unspecified)?;
941 let x_mod_n = Scalar::from_reduced_bytes(&affine.x.to_bytes());
942
943 if x_mod_n == r {
944 Ok(())
945 } else {
946 Err(EllipticCurveError::Unspecified)
947 }
948}
949
950pub fn is_valid_public_key(public_key: &[u8]) -> bool {
951 AffinePoint::from_sec1_bytes(public_key).is_some()
952}
953
954#[cfg(test)]
955mod tests {
956 use super::*;
957
958 fn decode_hex<const N: usize>(hex_bytes: &str) -> [u8; N] {
959 let bytes = hex::decode(hex_bytes).unwrap();
960 assert_eq!(bytes.len(), N);
961 let mut out = [0u8; N];
962 out.copy_from_slice(&bytes);
963 out
964 }
965
966 fn der_read_tlv<'a>(data: &'a [u8], offset: &mut usize) -> Option<(u8, &'a [u8])> {
968 if *offset >= data.len() {
969 return None;
970 }
971 let tag = data[*offset];
972 *offset += 1;
973 if *offset >= data.len() {
974 return None;
975 }
976 let len_byte = data[*offset];
977 *offset += 1;
978 let (len, _) = if len_byte & 0x80 != 0 {
979 let num_bytes = (len_byte & 0x7f) as usize;
980 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
981 return None;
982 }
983 if num_bytes > 1 && data[*offset] == 0 {
984 return None;
985 }
986 let mut l = 0usize;
987 for i in 0..num_bytes {
988 l = (l << 8) | data[*offset + i] as usize;
989 }
990 if l < 128 {
991 return None;
992 }
993 *offset += num_bytes;
994 (l, num_bytes + 1)
995 } else {
996 (len_byte as usize, 1)
997 };
998 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
999 return None;
1000 }
1001 let value = &data[*offset..*offset + len];
1002 *offset = (*offset).checked_add(len)?;
1003 Some((tag, value))
1004 }
1005
1006 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; 56]> {
1009 let mut offset = 0;
1010 let (tag, inner) = der_read_tlv(der, &mut offset)?;
1011 if tag != 0x30 {
1012 return None;
1013 }
1014 if offset != der.len() {
1015 return None;
1016 }
1017 let mut inner_offset = 0;
1018 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
1019 if rtag != 0x02 || rval.is_empty() || rval.len() > 29 {
1020 return None;
1021 }
1022 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
1023 if stag != 0x02 || sval.is_empty() || sval.len() > 29 {
1024 return None;
1025 }
1026 if inner_offset != inner.len() {
1027 return None;
1028 }
1029 let r_valid = if rval.len() == 28 && rval[0] >= 0x80 {
1030 false
1031 } else if rval.len() == 29 && rval[0] != 0 {
1032 false
1033 } else if rval.len() == 29 && rval[0] == 0 && rval[1] < 0x80 {
1034 false
1035 } else {
1036 rval.len() <= 29
1037 };
1038 let s_valid = if sval.len() == 28 && sval[0] >= 0x80 {
1039 false
1040 } else if sval.len() == 29 && sval[0] != 0 {
1041 false
1042 } else if sval.len() == 29 && sval[0] == 0 && sval[1] < 0x80 {
1043 false
1044 } else {
1045 sval.len() <= 29
1046 };
1047 if !r_valid || !s_valid {
1048 return None;
1049 }
1050
1051 let r_trimmed = if rval.len() == 29 && rval[0] == 0 {
1052 &rval[1..]
1053 } else {
1054 rval
1055 };
1056 let s_trimmed = if sval.len() == 29 && sval[0] == 0 {
1057 &sval[1..]
1058 } else {
1059 sval
1060 };
1061 if r_trimmed.len() > 28 || s_trimmed.len() > 28 {
1062 return None;
1063 }
1064 let mut sig = [0u8; 56];
1065 sig[28 - r_trimmed.len()..28].copy_from_slice(r_trimmed);
1066 sig[56 - s_trimmed.len()..56].copy_from_slice(s_trimmed);
1067 Some(sig)
1068 }
1069
1070 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
1073 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
1074 let secp224r1_oid: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x21];
1075 let mut offset = 0;
1076 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
1077 let mut inner = 0;
1078 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
1079 if _alg_tag != 0x30 {
1080 return None;
1081 }
1082 let mut ai = 0;
1083 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
1084 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
1085 return None;
1086 }
1087 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
1088 if oid2_tag != 0x06 || oid2 != secp224r1_oid {
1089 return None;
1090 }
1091 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
1092 if _bs_tag != 0x03 || bs_val.is_empty() {
1093 return None;
1094 }
1095 Some(bs_val[1..].to_vec())
1096 }
1097
1098 const RFC6979_PRIVATE_KEY: &str = "f220266e1105bfe3083e03ec7a3a654651f45e37167e88600bf257c1";
1100 const RFC6979_PUBLIC_X: &str = "00cf08da5ad719e42707fa431292dea11244d64fc51610d94b130d6c";
1101 const RFC6979_PUBLIC_Y: &str = "eeab6f3debe455e3dbf85416f7030cbd94f34f2d6f232c69f3c1385a";
1102
1103 #[test]
1104 fn derive_public_key_generator_matches_sec1_base_point() {
1105 let mut private_key = [0u8; SECRET_KEY_SIZE];
1106 private_key[27] = 1;
1107 let derived = derive_public_key_uncompressed(&private_key).unwrap();
1108 let expected = decode_hex::<57>(
1109 "04b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21\
1110 bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
1111 );
1112 assert_eq!(derived, expected);
1113 }
1114
1115 #[test]
1116 fn derive_public_key_matches_rfc6979_vector() {
1117 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1118 let expected = decode_hex::<57>(
1119 "0400cf08da5ad719e42707fa431292dea11244d64fc51610d94b130d6c\
1120 eeab6f3debe455e3dbf85416f7030cbd94f34f2d6f232c69f3c1385a",
1121 );
1122 assert_eq!(derive_public_key_uncompressed(&private_key).unwrap(), expected);
1123 assert_eq!(
1124 PublicKey::from_x_y(&decode_hex::<28>(RFC6979_PUBLIC_X), &decode_hex::<28>(RFC6979_PUBLIC_Y),)
1125 .unwrap()
1126 .to_bytes(),
1127 expected,
1128 );
1129
1130 let compressed = derive_public_key_compressed(&private_key).unwrap();
1132 assert_eq!(&compressed[1..], &decode_hex::<28>(RFC6979_PUBLIC_X));
1133 }
1134
1135 #[test]
1136 fn ecdsa_sign_matches_rfc6979_vectors() {
1137 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1138 let key = SecretKey::from_bytes(&private_key).unwrap();
1139
1140 let sample_signature = key.sign(b"sample").unwrap();
1141 let expected_sample = decode_hex::<56>(
1142 "61aa3da010e8e8406c656bc477a7a7189895e7e840cdfe8ff42307ba\
1143 bc814050dab5d23770879494f9e0a680dc1af7161991bde692b10101",
1144 );
1145 assert_eq!(sample_signature, expected_sample);
1146
1147 let test_signature = key.sign(b"test").unwrap();
1148 let expected_test = decode_hex::<56>(
1149 "ad04dde87b84747a243a631ea47a1ba6d1faa059149ad2440de6fba6\
1150 178d49b1ae90e3d8b629be3db5683915f4e8c99fdf6e666cf37adcfd",
1151 );
1152 assert_eq!(test_signature, expected_test);
1153 }
1154
1155 #[test]
1156 fn rfc6979_nonce_generation_matches_known_value() {
1157 let private_key = Scalar::from_bytes(&decode_hex::<28>(RFC6979_PRIVATE_KEY)).unwrap();
1158 let hash = hash_message(b"sample");
1159 assert_eq!(
1160 rfc6979_generate_k(&private_key, &hash).to_bytes(),
1161 decode_hex::<28>("ad3029e0278f80643de33917ce6908c70a8ff50a411f06e41dedfcdc")
1162 );
1163 }
1164
1165 #[test]
1166 fn rfc6979_test_message_nonce_matches_known_value() {
1167 let private_key = Scalar::from_bytes(&decode_hex::<28>(RFC6979_PRIVATE_KEY)).unwrap();
1168 let hash = hash_message(b"test");
1169 assert_eq!(
1170 rfc6979_generate_k(&private_key, &hash).to_bytes(),
1171 decode_hex::<28>("ff86f57924da248d6e44e8154eb69f0ae2aebaee9931d0b5a969f904")
1172 );
1173 }
1174
1175 #[test]
1176 fn rfc6979_bits2octets_truncates_and_reduces() {
1177 let hash = hash_message(b"sample");
1179 let expected = decode_hex::<28>("af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a");
1180 assert_eq!(bits2octets(&hash), expected);
1181
1182 let n_times = decode_hex::<32>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d00000000");
1185 assert_eq!(bits2octets(&n_times), [0u8; 28]);
1186 let n_plus_one = decode_hex::<32>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3e00000000");
1187 assert_eq!(
1188 bits2octets(&n_plus_one),
1189 decode_hex::<28>("00000000000000000000000000000000000000000000000000000001")
1190 );
1191 }
1192
1193 #[test]
1194 fn ecdsa_verify_accepts_compressed_and_uncompressed_public_keys() {
1195 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1196 let key = SecretKey::from_bytes(&private_key).unwrap();
1197 let uncompressed = key.public_key();
1198 let compressed = derive_public_key_compressed(&private_key).unwrap();
1199 let signature = key.sign(b"sample").unwrap();
1200
1201 assert!(uncompressed.verify(b"sample", &signature).is_ok());
1202 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1203 assert!(ecdsa_verify_inner(&point, b"sample", &signature).is_ok());
1204 }
1205
1206 #[test]
1207 fn verify_rejects_tampering_and_invalid_points() {
1208 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1209 let key = SecretKey::from_bytes(&private_key).unwrap();
1210 let pub_key = key.public_key();
1211 let mut off_curve = [0u8; 57];
1212 off_curve.copy_from_slice(&pub_key.to_bytes());
1213 let signature = key.sign(b"sample").unwrap();
1214
1215 assert!(pub_key.verify(b"tampered", &signature).is_err());
1216
1217 let mut bad_signature = signature;
1218 bad_signature[10] ^= 0x80;
1219 assert!(pub_key.verify(b"sample", &bad_signature).is_err());
1220
1221 off_curve[56] ^= 0x01;
1222 assert!(!is_valid_public_key(&off_curve));
1223 assert!(PublicKey::from_bytes(&off_curve).is_err());
1224 }
1225
1226 #[test]
1227 fn invalid_inputs_are_rejected() {
1228 let invalid_private_key = [0u8; SECRET_KEY_SIZE];
1229 assert!(SecretKey::from_bytes(&invalid_private_key).is_err());
1230 assert!(derive_public_key_uncompressed(&invalid_private_key).is_err());
1231 assert!(derive_public_key_compressed(&invalid_private_key).is_err());
1232
1233 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1234 let key = SecretKey::from_bytes(&private_key).unwrap();
1235 let signature = key.sign(b"msg").unwrap();
1236 let mut zero_r = signature;
1237 zero_r[..28].fill(0);
1238 assert!(key.public_key().verify(b"msg", &zero_r).is_err());
1239 }
1240
1241 #[test]
1242 fn public_key_validation_accepts_known_good_points() {
1243 assert!(is_valid_public_key(&decode_hex::<57>(
1244 "04b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21\
1245 bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
1246 )));
1247 }
1248
1249 #[test]
1250 fn scalar_from_bytes_rejects_boundary_values() {
1251 assert!(Scalar::from_bytes(&[0u8; 28]).is_none());
1252
1253 let n_bytes = decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d");
1255 assert!(Scalar::from_bytes(&n_bytes).is_none());
1256
1257 let n_minus_1 = decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3c");
1259 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1260
1261 let one = decode_hex::<28>("00000000000000000000000000000000000000000000000000000001");
1262 assert!(Scalar::from_bytes(&one).is_some());
1263 }
1264
1265 #[test]
1266 fn field_element_from_bytes_rejects_boundary_values() {
1267 let p_bytes = decode_hex::<28>("ffffffffffffffffffffffffffffffff000000000000000000000001");
1269 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1270
1271 let p_minus_1 = decode_hex::<28>("ffffffffffffffffffffffffffffffff000000000000000000000000");
1273 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1274
1275 assert!(FieldElement::from_bytes(&[0u8; 28]).is_some());
1276 }
1277
1278 #[test]
1279 fn point_decompression_round_trip() {
1280 let keys: &[&str] = &[
1281 "00000000000000000000000000000000000000000000000000000001",
1282 "00000000000000000000000000000000000000000000000000000002",
1283 RFC6979_PRIVATE_KEY,
1284 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7",
1285 ];
1286
1287 for key_hex in keys {
1288 let private_key = decode_hex::<28>(key_hex);
1289 let key = SecretKey::from_bytes(&private_key).unwrap();
1290 let uncompressed = key.public_key();
1291 let compressed = derive_public_key_compressed(&private_key).unwrap();
1292
1293 let sig = key.sign(b"round-trip").unwrap();
1294 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
1295 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1296 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
1297
1298 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1299 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
1300 }
1301 }
1302
1303 #[test]
1304 fn compressed_public_key_has_correct_prefix() {
1305 for _ in 0..5 {
1306 let key = SecretKey::generate().unwrap();
1307 let compressed = key.public_key().to_compressed_bytes();
1308 let prefix = compressed[0];
1309 assert!(prefix == 0x02 || prefix == 0x03, "invalid compressed prefix: {prefix:#x}");
1310
1311 let (_, y) = key.public_key().x_y();
1313 let expected_prefix = if y[27] & 1 == 1 { 0x03 } else { 0x02 };
1314 assert_eq!(prefix, expected_prefix);
1315
1316 assert_eq!(compressed, derive_public_key_compressed(&key.to_bytes()).unwrap());
1318 }
1319 }
1320
1321 #[test]
1322 fn public_key_compressed_round_trip() {
1323 for _ in 0..5 {
1324 let key = SecretKey::generate().unwrap();
1325 let pub_key = key.public_key();
1326 let compressed = pub_key.to_compressed_bytes();
1327 assert_eq!(compressed.len(), PUBLIC_KEY_COMPRESSED_SIZE);
1328
1329 let decoded = PublicKey::from_bytes(&compressed).unwrap();
1330 assert_eq!(decoded, pub_key);
1331 assert_eq!(decoded.to_bytes(), pub_key.to_bytes());
1332 }
1333 }
1334
1335 #[test]
1336 fn sqrt_matches_squares_and_rejects_non_residues() {
1337 for _ in 0..200 {
1339 let bytes: [u8; 28] = rand::random();
1340 let Some(x) = FieldElement::from_bytes(&bytes) else {
1341 continue;
1342 };
1343 let square = x.square();
1344 let root = square.sqrt().expect("square should have a square root");
1345 assert_eq!(root.square(), square);
1346 }
1347
1348 let non_residue = FieldElement(U224::from_u64(11));
1350 assert!(non_residue.sqrt().is_none());
1351 }
1352
1353 #[test]
1354 fn scalar_inversion_correctness() {
1355 let k =
1356 Scalar::from_bytes(&decode_hex::<28>("ad3029e0278f80643de33917ce6908c70a8ff50a411f06e41dedfcdc")).unwrap();
1357 let k_inv = k.invert().unwrap();
1358 assert_eq!(k.mul(k_inv), Scalar::ONE);
1359 }
1360
1361 #[test]
1362 fn field_element_inversion_correctness() {
1363 let x = FieldElement::from_bytes(&decode_hex::<28>("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"))
1364 .unwrap();
1365 let x_inv = x.invert().unwrap();
1366 assert_eq!(x.mul(x_inv), FieldElement::ONE);
1367 }
1368
1369 #[test]
1370 fn generator_point_is_on_curve() {
1371 assert!(AffinePoint::GENERATOR.is_on_curve());
1372 }
1373
1374 #[test]
1375 fn barrett_mul_matches_generic() {
1376 for _ in 0..1000 {
1379 let a_bytes: [u8; 28] = rand::random();
1380 let b_bytes: [u8; 28] = rand::random();
1381 let (Some(a), Some(b)) = (FieldElement::from_bytes(&a_bytes), FieldElement::from_bytes(&b_bytes)) else {
1382 continue;
1383 };
1384 assert_eq!(a.mul(b).0, a.0.mul_mod(&b.0, &MODULUS_P), "field mul mismatch");
1385
1386 let (Some(c), Some(d)) = (Scalar::from_bytes(&a_bytes), Scalar::from_bytes(&b_bytes)) else {
1387 continue;
1388 };
1389 assert_eq!(c.mul(d).0, c.0.mul_mod(&d.0, &MODULUS_N), "scalar mul mismatch");
1390 }
1391 }
1392
1393 #[test]
1394 fn scalar_mul_generator_n_gives_identity() {
1395 let n_minus_1 =
1397 Scalar::from_bytes(&decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3c")).unwrap();
1398 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
1399 assert_eq!(result.x, GENERATOR_X);
1400 assert_eq!(result.y, GENERATOR_Y.negate());
1401 }
1402
1403 #[test]
1404 fn ecdh_deterministic_vector_against_generator() {
1405 let private_key = decode_hex::<28>(RFC6979_PRIVATE_KEY);
1408 let generator = decode_hex::<57>(
1409 "04b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21\
1410 bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
1411 );
1412
1413 let key = SecretKey::from_bytes(&private_key).unwrap();
1414 let shared = ecdh(&private_key, &generator).unwrap();
1415 assert_eq!(shared, key.public_key().x_y().0);
1416 assert_eq!(shared, decode_hex::<28>(RFC6979_PUBLIC_X));
1417 }
1418
1419 #[test]
1420 fn ecdh_with_compressed_public_key() {
1421 let alice = SecretKey::generate().unwrap();
1422 let bob = SecretKey::generate().unwrap();
1423 let bob_compressed = derive_public_key_compressed(&bob.to_bytes()).unwrap();
1424
1425 assert!(is_valid_public_key(&bob_compressed));
1426 let shared = alice.ecdh(&PublicKey::from_bytes(&bob_compressed).unwrap()).unwrap();
1427 let expected = bob.ecdh(&alice.public_key()).unwrap();
1428 assert_eq!(shared, expected);
1429 }
1430
1431 #[test]
1432 fn ecdh_round_trip_alice_bob() {
1433 let alice = SecretKey::generate().unwrap();
1434 let bob = SecretKey::generate().unwrap();
1435
1436 let alice_shared = alice.ecdh(&bob.public_key()).unwrap();
1437 let bob_shared = bob.ecdh(&alice.public_key()).unwrap();
1438
1439 assert_eq!(alice_shared, bob_shared);
1440 assert_eq!(alice_shared.len(), ECDH_SHARED_SECRET_SIZE);
1441 }
1442
1443 #[test]
1444 fn ecdh_rejects_off_curve_peer_public_key() {
1445 let alice = SecretKey::generate().unwrap();
1446 let mut bad_pub = alice.public_key().to_bytes().to_vec();
1447 bad_pub[56] ^= 0x01;
1448 assert!(!is_valid_public_key(&bad_pub));
1449 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1450 }
1451
1452 #[test]
1453 fn ecdh_rejects_infinity_peer_public_key() {
1454 let alice = SecretKey::generate().unwrap();
1455 assert!(ecdh(&alice.to_bytes(), &[0x00u8]).is_err());
1456 }
1457
1458 #[test]
1459 fn ecdh_rejects_bad_length_peer_public_key() {
1460 let alice = SecretKey::generate().unwrap();
1461 assert!(ecdh(&alice.to_bytes(), &[]).is_err());
1462 assert!(ecdh(&alice.to_bytes(), &[0x04, 0x00]).is_err());
1463 let long = [0x04u8; 200];
1464 assert!(ecdh(&alice.to_bytes(), &long).is_err());
1465 }
1466
1467 #[test]
1468 fn ecdh_rejects_invalid_private_key_zero_and_order() {
1469 let zero_key = [0u8; 28];
1470 assert!(SecretKey::from_bytes(&zero_key).is_err());
1471 let bob = SecretKey::generate().unwrap();
1472 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1473
1474 let n_bytes = decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d");
1475 assert!(SecretKey::from_bytes(&n_bytes).is_err());
1476 }
1477
1478 #[test]
1479 fn ecdh_multiple_exchanges_consistency() {
1480 let alice = SecretKey::generate().unwrap();
1481 let bob = SecretKey::generate().unwrap();
1482 let charlie = SecretKey::generate().unwrap();
1483
1484 let alice_bob = alice.ecdh(&bob.public_key()).unwrap();
1485 let bob_alice = bob.ecdh(&alice.public_key()).unwrap();
1486 assert_eq!(alice_bob, bob_alice);
1487
1488 let alice_charlie = alice.ecdh(&charlie.public_key()).unwrap();
1489 let charlie_alice = charlie.ecdh(&alice.public_key()).unwrap();
1490 assert_eq!(alice_charlie, charlie_alice);
1491
1492 assert_ne!(alice_bob, alice_charlie);
1493 }
1494
1495 #[test]
1496 fn ecdh_standalone_function_matches_method() {
1497 let alice = SecretKey::generate().unwrap();
1498 let bob = SecretKey::generate().unwrap();
1499
1500 let method_result = alice.ecdh(&bob.public_key()).unwrap();
1501 let standalone_result = ecdh(&alice.to_bytes(), &bob.public_key().to_bytes()).unwrap();
1502 assert_eq!(method_result, standalone_result);
1503 }
1504
1505 #[test]
1506 fn ecdsa_sign_verify_round_trip_multiple_messages() {
1507 let key = SecretKey::generate().unwrap();
1508 let pub_key = key.public_key();
1509
1510 let messages: &[&[u8]] = &[
1511 b"",
1512 b"hello world",
1513 b"The quick brown fox jumps over the lazy dog",
1514 &[0xffu8; 100],
1515 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1516 ];
1517
1518 for msg in messages {
1519 let sig = key.sign(msg).unwrap();
1520 assert!(pub_key.verify(msg, &sig).is_ok(), "round-trip failed for message {msg:?}");
1521 let mut wrong_msg = msg.to_vec();
1522 wrong_msg.push(0x42);
1523 assert!(pub_key.verify(&wrong_msg, &sig).is_err());
1524 }
1525 }
1526
1527 #[test]
1528 fn ecdsa_verify_wrong_public_key_rejects() {
1529 let key1 = SecretKey::generate().unwrap();
1530 let key2 = SecretKey::generate().unwrap();
1531
1532 let sig = key1.sign(b"message").unwrap();
1533 assert!(key2.public_key().verify(b"message", &sig).is_err());
1534 }
1535
1536 #[test]
1537 fn ecdsa_rejects_non_canonical_r_and_s() {
1538 let key = SecretKey::generate().unwrap();
1539 let mut bad_r = key.sign(b"msg").unwrap();
1540 bad_r[..28].copy_from_slice(&decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3e"));
1541 assert!(key.public_key().verify(b"msg", &bad_r).is_err());
1542
1543 let mut bad_s = key.sign(b"msg").unwrap();
1544 bad_s[28..].copy_from_slice(&decode_hex::<28>("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3e"));
1545 assert!(key.public_key().verify(b"msg", &bad_s).is_err());
1546 }
1547
1548 #[test]
1549 fn from_x_y_matches_generator() {
1550 let key = PublicKey::from_x_y(
1551 &decode_hex::<28>("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"),
1552 &decode_hex::<28>("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
1553 )
1554 .unwrap();
1555 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
1556 assert_eq!(key, from_sec1);
1557 }
1558
1559 #[test]
1560 fn from_x_y_rejects_off_curve() {
1561 assert!(PublicKey::from_x_y(&[0u8; 28], &[0u8; 28]).is_err());
1562 }
1563
1564 #[test]
1565 fn private_key_round_trip_bytes() {
1566 let key = SecretKey::generate().unwrap();
1567 let bytes = key.to_bytes();
1568 let key2 = SecretKey::from_bytes(&bytes).unwrap();
1569 assert_eq!(key.to_bytes(), key2.to_bytes());
1570 assert_eq!(key.public_key().to_bytes(), key2.public_key().to_bytes());
1571 }
1572
1573 #[test]
1574 fn public_key_round_trip_bytes() {
1575 let key = SecretKey::generate().unwrap();
1576 let pub_key = key.public_key();
1577 let pub_key2 = PublicKey::from_bytes(&pub_key.to_bytes()).unwrap();
1578 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1579 }
1580
1581 #[test]
1582 fn x_y_round_trip() {
1583 let key = SecretKey::generate().unwrap();
1584 let pub_key = key.public_key();
1585 let (x, y) = pub_key.x_y();
1586 let pub_key2 = PublicKey::from_x_y(&x, &y).unwrap();
1587 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1588 }
1589
1590 #[test]
1591 fn field_element_add_sub_mul_consistency() {
1592 let a = FieldElement::from_bytes(&decode_hex::<28>("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"))
1593 .unwrap();
1594 let b = FieldElement::from_bytes(&decode_hex::<28>("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"))
1595 .unwrap();
1596
1597 assert_eq!(a.add(b).sub(b), a);
1598 assert_eq!(a.add(b), b.add(a));
1599 assert_eq!(a.mul(b), b.mul(a));
1600
1601 let c = FieldElement::from_bytes(&decode_hex::<28>("270b39432355ffb45044b0b7d7bfd8ba0c04b3abf5413256b4050a85"))
1602 .unwrap();
1603 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
1604 }
1605
1606 #[test]
1607 fn scalar_add_sub_mul_consistency() {
1608 let a =
1609 Scalar::from_bytes(&decode_hex::<28>("ad3029e0278f80643de33917ce6908c70a8ff50a411f06e41dedfcdc")).unwrap();
1610 let one =
1611 Scalar::from_bytes(&decode_hex::<28>("00000000000000000000000000000000000000000000000000000001")).unwrap();
1612
1613 assert_eq!(a.add(one).sub(one), a);
1614 assert_eq!(a.mul(one), a);
1615
1616 let b =
1617 Scalar::from_bytes(&decode_hex::<28>("178d49b1ae90e3d8b629be3db5683915f4e8c99fdf6e666cf37adcfd")).unwrap();
1618 assert_eq!(a.mul(b), b.mul(a));
1619 assert_eq!(a.add(b), b.add(a));
1620 }
1621
1622 #[test]
1623 fn field_element_negate_round_trip() {
1624 let x = FieldElement::from_bytes(&decode_hex::<28>("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"))
1625 .unwrap();
1626 let neg = x.negate();
1627 assert_eq!(neg.negate(), x);
1628 assert_eq!(x.add(neg), FieldElement::ZERO);
1629 }
1630
1631 #[test]
1632 fn point_double_and_add_consistency() {
1633 let g = AffinePoint::GENERATOR;
1634 let proj_g = ProjectivePoint::from_affine(&g);
1635 assert_eq!(
1636 proj_g.double().to_affine().unwrap().to_uncompressed_bytes(),
1637 proj_g.add(&proj_g).to_affine().unwrap().to_uncompressed_bytes(),
1638 );
1639 }
1640
1641 #[test]
1642 fn field_element_pow_correctness() {
1643 let x = FieldElement::from_bytes(&decode_hex::<28>("00000000000000000000000000000000000000000000000000000002"))
1644 .unwrap();
1645 assert_eq!(x.pow(&U224::from_u64(3)), x.mul(x).mul(x));
1646 assert_eq!(x.pow(&U224::ZERO), FieldElement::ONE);
1647 }
1648
1649 #[test]
1650 fn wycheproof_ecdsa_p224_sha256_p1363() {
1651 let data: serde_json::Value = serde_json::from_str(include_str!(
1652 "../testdata/wycheproof/testvectors_v1/ecdsa_secp224r1_sha256_p1363_test.json"
1653 ))
1654 .unwrap();
1655 let mut valid_tested = 0u64;
1656 let mut invalid_tested = 0u64;
1657 for group in data["testGroups"].as_array().unwrap() {
1658 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1659 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1660 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1661
1662 for test in group["tests"].as_array().unwrap() {
1663 let msg = hex::decode(test["msg"].as_str().unwrap()).unwrap();
1664 let sig_hex = test["sig"].as_str().unwrap();
1665 let result = test["result"].as_str().unwrap();
1666
1667 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1668 continue;
1669 }
1670 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1671 let verify_result = pk.verify(&msg, &sig);
1672
1673 if result == "valid" {
1674 assert!(verify_result.is_ok(), "wycheproof ECDSA P1363 tcId={}", test["tcId"]);
1675 valid_tested += 1;
1676 } else {
1677 assert!(verify_result.is_err(), "wycheproof ECDSA P1363 tcId={}", test["tcId"]);
1678 invalid_tested += 1;
1679 }
1680 }
1681 }
1682 assert!(valid_tested > 0, "no valid ECDSA P1363 wycheproof tests were run");
1683 assert!(invalid_tested > 0, "no invalid ECDSA P1363 wycheproof tests were run");
1684 }
1685
1686 #[test]
1687 fn wycheproof_ecdsa_p224_sha256_der() {
1688 let data: serde_json::Value = serde_json::from_str(include_str!(
1689 "../testdata/wycheproof/testvectors_v1/ecdsa_secp224r1_sha256_test.json"
1690 ))
1691 .unwrap();
1692 let mut valid_tested = 0u64;
1693 let mut invalid_tested = 0u64;
1694 for group in data["testGroups"].as_array().unwrap() {
1695 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1696 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1697 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1698
1699 for test in group["tests"].as_array().unwrap() {
1700 let msg = hex::decode(test["msg"].as_str().unwrap()).unwrap();
1701 let der_sig = hex::decode(test["sig"].as_str().unwrap()).unwrap();
1702 let result = test["result"].as_str().unwrap();
1703
1704 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
1705 continue;
1706 };
1707
1708 let verify_result = pk.verify(&msg, &sig);
1709 if result == "valid" {
1710 assert!(
1711 verify_result.is_ok(),
1712 "wycheproof ECDSA DER tcId={} expected valid but failed",
1713 test["tcId"]
1714 );
1715 valid_tested += 1;
1716 } else {
1717 assert!(
1718 verify_result.is_err(),
1719 "wycheproof ECDSA DER tcId={} expected invalid but passed",
1720 test["tcId"]
1721 );
1722 invalid_tested += 1;
1723 }
1724 }
1725 }
1726 assert!(valid_tested > 0, "no valid ECDSA DER wycheproof tests were run");
1727 assert!(invalid_tested > 0, "no invalid ECDSA DER wycheproof tests were run");
1728 }
1729
1730 fn wycheproof_ecdh_case(file: &str, asn: bool) {
1731 let data: serde_json::Value = serde_json::from_str(file).unwrap();
1732 let mut valid_tested = 0u64;
1733 let mut invalid_tested = 0u64;
1734 for group in data["testGroups"].as_array().unwrap() {
1735 for test in group["tests"].as_array().unwrap() {
1736 let public_hex = test["public"].as_str().unwrap();
1737 let private_hex = test["private"].as_str().unwrap();
1738 let expected_shared_hex = test["shared"].as_str().unwrap();
1739 let result = test["result"].as_str().unwrap();
1740
1741 let public_bytes = hex::decode(public_hex).unwrap();
1742 let public_key = if asn {
1743 match spki_to_sec1_point(&public_bytes) {
1744 Some(point) => point,
1745 None => {
1746 if result == "valid" {
1747 panic!("wycheproof ECDH ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
1748 }
1749 invalid_tested += 1;
1750 continue;
1751 }
1752 }
1753 } else {
1754 public_bytes
1755 };
1756
1757 let private_bytes = hex::decode(private_hex).unwrap();
1759 let mut private_key = [0u8; SECRET_KEY_SIZE];
1760 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1761 let skip = private_bytes.len().saturating_sub(SECRET_KEY_SIZE);
1762 private_key[SECRET_KEY_SIZE - effective_len..]
1763 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1764
1765 let shared = ecdh(&private_key, &public_key);
1766
1767 if result == "valid" {
1768 let shared = shared.unwrap();
1769 assert_eq!(
1770 hex::encode(shared),
1771 expected_shared_hex,
1772 "wycheproof ECDH tcId={}",
1773 test["tcId"]
1774 );
1775 valid_tested += 1;
1776 } else if result == "invalid" {
1777 assert!(
1778 shared.is_err(),
1779 "wycheproof ECDH tcId={} expected invalid but passed",
1780 test["tcId"]
1781 );
1782 invalid_tested += 1;
1783 }
1784 }
1785 }
1786 assert!(valid_tested > 0, "no valid ECDH wycheproof tests were run");
1787 assert!(invalid_tested > 0, "no invalid ECDH wycheproof tests were run");
1788 }
1789
1790 #[test]
1791 fn wycheproof_ecdh_p224_ecpoint() {
1792 wycheproof_ecdh_case(
1793 include_str!("../testdata/wycheproof/testvectors_v1/ecdh_secp224r1_ecpoint_test.json"),
1794 false,
1795 );
1796 }
1797
1798 #[test]
1799 fn wycheproof_ecdh_p224_asn() {
1800 wycheproof_ecdh_case(
1801 include_str!("../testdata/wycheproof/testvectors_v1/ecdh_secp224r1_test.json"),
1802 true,
1803 );
1804 }
1805}