1use big_number::{Uint, mac};
2
3use crate::{EllipticCurveError, Hasher, hmac::Hmac, sha2::Sha256};
4
5pub const SECRET_KEY_SIZE: usize = 32;
7pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 33;
9pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 65;
11pub const SIGNATURE_SIZE: usize = 64;
13pub const ECDH_SHARED_SECRET_SIZE: usize = 32;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub struct SecretKey {
49 scalar: Scalar,
50 public_point: AffinePoint,
51}
52
53impl SecretKey {
54 #[cfg(feature = "random")]
55 pub fn generate() -> Result<SecretKey, EllipticCurveError> {
56 let key: [u8; SECRET_KEY_SIZE] = crate::random::random_bytes();
57 Self::from_bytes(&key)
58 }
59
60 pub fn from_bytes(key: &[u8; SECRET_KEY_SIZE]) -> Result<SecretKey, EllipticCurveError> {
61 let scalar = Scalar::from_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
62 let public_point = scalar_mul_generator(&scalar)
63 .to_affine()
64 .ok_or(EllipticCurveError::Unspecified)?;
65 Ok(SecretKey {
66 scalar,
67 public_point,
68 })
69 }
70
71 pub fn public_key(&self) -> PublicKey {
72 PublicKey {
73 point: self.public_point,
74 }
75 }
76
77 pub fn sign(&self, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
78 ecdsa_sign_inner(&self.scalar, message)
79 }
80
81 pub fn ecdh(&self, peer_public: &PublicKey) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
82 ecdh_inner(&self.scalar, &peer_public.point)
83 }
84
85 pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE] {
86 self.scalar.to_bytes()
87 }
88}
89
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub struct PublicKey {
105 point: AffinePoint,
106}
107
108impl PublicKey {
109 #[inline]
110 pub fn from_bytes(key: &[u8]) -> Result<PublicKey, EllipticCurveError> {
111 let point = AffinePoint::from_sec1_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
112 Ok(PublicKey {
113 point,
114 })
115 }
116
117 #[inline]
124 pub fn from_x_y(x_bytes: &[u8; 32], y_bytes: &[u8; 32]) -> Result<PublicKey, EllipticCurveError> {
125 let x = FieldElement::from_bytes(x_bytes).ok_or(EllipticCurveError::InvalidKey)?;
126 let y = FieldElement::from_bytes(y_bytes).ok_or(EllipticCurveError::InvalidKey)?;
127 let point = AffinePoint::new(x, y).ok_or(EllipticCurveError::InvalidKey)?;
128 Ok(PublicKey {
129 point,
130 })
131 }
132
133 pub fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
134 ecdsa_verify_inner(&self.point, message, signature)
135 }
136
137 #[inline]
138 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
139 self.point.to_uncompressed_bytes()
140 }
141
142 #[inline]
144 pub fn x_y(&self) -> ([u8; 32], [u8; 32]) {
145 (self.point.x.to_bytes(), self.point.y.to_bytes())
146 }
147}
148
149type U256 = Uint<256, 4>;
150
151const MODULUS_P: U256 = U256::from_limbs([
152 0xffff_ffff_ffff_ffff,
153 0x0000_0000_ffff_ffff,
154 0x0000_0000_0000_0000,
155 0xffff_ffff_0000_0001,
156]);
157
158const MODULUS_N: U256 = U256::from_limbs([
159 0xf3b9_cac2_fc63_2551,
160 0xbce6_faad_a717_9e84,
161 0xffff_ffff_ffff_ffff,
162 0xffff_ffff_0000_0000,
163]);
164
165const P_MINUS_TWO: U256 = U256::from_limbs([
166 0xffff_ffff_ffff_fffd,
167 0x0000_0000_ffff_ffff,
168 0x0000_0000_0000_0000,
169 0xffff_ffff_0000_0001,
170]);
171
172const P_PLUS_ONE_OVER_FOUR: U256 = U256::from_limbs([
173 0x0000_0000_0000_0000,
174 0x0000_0000_4000_0000,
175 0x4000_0000_0000_0000,
176 0x3fff_ffff_c000_0000,
177]);
178
179const N_MINUS_TWO: U256 = U256::from_limbs([
180 0xf3b9_cac2_fc63_254f,
181 0xbce6_faad_a717_9e84,
182 0xffff_ffff_ffff_ffff,
183 0xffff_ffff_0000_0000,
184]);
185
186const CURVE_B: FieldElement = FieldElement(U256::from_limbs([
187 0x3bce_3c3e_27d2_604b,
188 0x651d_06b0_cc53_b0f6,
189 0xb3eb_bd55_7698_86bc,
190 0x5ac6_35d8_aa3a_93e7,
191]));
192
193const GENERATOR_X: FieldElement = FieldElement(U256::from_limbs([
194 0xf4a1_3945_d898_c296,
195 0x7703_7d81_2deb_33a0,
196 0xf8bc_e6e5_63a4_40f2,
197 0x6b17_d1f2_e12c_4247,
198]));
199
200const GENERATOR_Y: FieldElement = FieldElement(U256::from_limbs([
201 0xcbb6_4068_37bf_51f5,
202 0x2bce_3357_6b31_5ece,
203 0x8ee7_eb4a_7c0f_9e16,
204 0x4fe3_42e2_fe1a_7f9b,
205]));
206
207const S4: [u64; 4] = [
210 0x0000000000000001,
211 0xffffffff00000000,
212 0xffffffffffffffff,
213 0x00000000fffffffe,
214];
215
216const S5: [u64; 4] = [
217 0x00000000ffffffff,
218 0x0000000100000001,
219 0xfffffffeffffffff,
220 0xfffffffe00000000,
221];
222
223const S6: [u64; 4] = [
224 0xfffffffefffffffe,
225 0x00000002ffffffff,
226 0x0000000000000002,
227 0xfffffffe00000001,
228];
229
230const S7: [u64; 4] = [
231 0xfffffffeffffffff,
232 0xfffffffffffffffe,
233 0x0000000200000000,
234 0x0000000000000003,
235];
236
237#[inline]
239fn ct_select_u128(a: u128, b: u128, choice: bool) -> u128 {
240 let mask = (choice as u128).wrapping_neg();
241 (a & mask) | (b & !mask)
242}
243
244fn p256_fast_mul_mod(a: &U256, b: &U256) -> U256 {
247 let al = a.limbs;
248 let bl = b.limbs;
249
250 let mut prod = [0u64; 8];
251 for i in 0..4 {
252 let mut carry = 0u64;
253 for j in 0..4 {
254 let (v, cc) = mac(prod[i + j], al[i], bl[j], carry);
255 prod[i + j] = v;
256 carry = cc;
257 }
258 prod[i + 4] = carry;
259 }
260
261 const MASK: u128 = 0xffffffffffffffff;
262 let c0 = [S4[0] as u128, S4[1] as u128, S4[2] as u128, S4[3] as u128];
263 let c1 = [S5[0] as u128, S5[1] as u128, S5[2] as u128, S5[3] as u128];
264 let c2 = [S6[0] as u128, S6[1] as u128, S6[2] as u128, S6[3] as u128];
265 let c3 = [S7[0] as u128, S7[1] as u128, S7[2] as u128, S7[3] as u128];
266 let coeffs = [c0, c1, c2, c3];
267
268 let mut r0 = prod[0] as u128;
269 let mut r1 = prod[1] as u128;
270 let mut r2 = prod[2] as u128;
271 let mut r3 = prod[3] as u128;
272
273 for i in 0..4 {
274 let w = prod[4 + i] as u128;
275 let c = coeffs[i];
276
277 r0 = r0.wrapping_add(w.wrapping_mul(c[0]));
278 r1 = r1.wrapping_add(w.wrapping_mul(c[1]));
279 r2 = r2.wrapping_add(w.wrapping_mul(c[2]));
280 r3 = r3.wrapping_add(w.wrapping_mul(c[3]));
281
282 for _ in 0..4 {
284 let carry = r0 >> 64;
285 r1 = r1.wrapping_add(carry);
286 r0 &= MASK;
287 let carry = r1 >> 64;
288 r2 = r2.wrapping_add(carry);
289 r1 &= MASK;
290 let carry = r2 >> 64;
291 r3 = r3.wrapping_add(carry);
292 r2 &= MASK;
293
294 let residual = r3 >> 64;
295 let need_reduce = residual != 0;
296
297 let rr3 = r3 & MASK;
299 let rr0 = r0.wrapping_add(residual.wrapping_mul(c0[0]));
300 let rr1 = r1.wrapping_add(residual.wrapping_mul(c0[1]));
301 let rr2 = r2.wrapping_add(residual.wrapping_mul(c0[2]));
302 let rr3r = rr3.wrapping_add(residual.wrapping_mul(c0[3]));
303
304 r0 = ct_select_u128(rr0, r0, need_reduce);
306 r1 = ct_select_u128(rr1, r1, need_reduce);
307 r2 = ct_select_u128(rr2, r2, need_reduce);
308 r3 = ct_select_u128(rr3r, r3, need_reduce);
309 }
310 }
311
312 let mut result = U256::from_limbs([r0 as u64, r1 as u64, r2 as u64, r3 as u64]);
314 for _ in 0..8 {
315 let (sub, borrow) = result.sub_raw(&MODULUS_P);
316 result = U256::ct_select(&sub, &result, borrow == 0);
317 }
318 result
319}
320
321#[derive(Clone, Copy, Debug, PartialEq, Eq)]
322struct FieldElement(U256);
323
324impl FieldElement {
325 const ZERO: Self = Self(U256::ZERO);
326 const ONE: Self = Self(U256::ONE);
327
328 #[inline]
329 fn from_bytes(bytes: &[u8; 32]) -> Option<Self> {
330 let value = U256::from_be_slice(bytes);
331 if value.ct_ge(&MODULUS_P) {
332 None
333 } else {
334 Some(Self(value))
335 }
336 }
337
338 #[inline]
339 fn to_bytes(self) -> [u8; 32] {
340 self.0.to_be_bytes_fixed::<32>()
341 }
342
343 #[inline]
344 fn is_zero(&self) -> bool {
345 self.0.is_zero()
346 }
347
348 #[inline]
349 fn is_odd(&self) -> bool {
350 self.0.is_odd()
351 }
352
353 #[inline]
354 fn add(self, rhs: Self) -> Self {
355 Self(self.0.add_mod(&rhs.0, &MODULUS_P))
356 }
357
358 #[inline]
359 fn sub(self, rhs: Self) -> Self {
360 Self(self.0.sub_mod(&rhs.0, &MODULUS_P))
361 }
362
363 #[inline]
364 fn double(self) -> Self {
365 Self(self.0.double_mod(&MODULUS_P))
366 }
367
368 #[inline]
369 fn square(self) -> Self {
370 self.mul(self)
371 }
372
373 #[inline]
374 fn mul(self, rhs: Self) -> Self {
375 Self(p256_fast_mul_mod(&self.0, &rhs.0))
376 }
377
378 #[inline]
379 fn triple(self) -> Self {
380 self.double().add(self)
381 }
382
383 #[inline]
384 fn negate(self) -> Self {
385 let (diff, _) = MODULUS_P.sub_raw(&self.0);
386 Self(U256::ct_select(&U256::ZERO, &diff, self.is_zero()))
387 }
388
389 #[inline]
390 fn pow(self, exponent: &U256) -> Self {
391 let mut result = Self::ONE;
392 let mut i = 256usize;
393 while i > 0 {
394 i -= 1;
395 result = result.square();
396 let product = result.mul(self);
397 result = Self::select(&product, &result, exponent.bit(i));
398 }
399 result
400 }
401
402 #[inline]
403 fn invert(self) -> Option<Self> {
404 Some(self.pow(&P_MINUS_TWO))
405 }
406
407 #[inline]
408 fn sqrt(self) -> Option<Self> {
409 let candidate = self.pow(&P_PLUS_ONE_OVER_FOUR);
410 if U256::ct_eq(&self.0, &candidate.square().0) {
411 Some(candidate)
412 } else {
413 None
414 }
415 }
416
417 #[inline]
418 fn select(a: &Self, b: &Self, choice: bool) -> Self {
419 Self(U256::ct_select(&a.0, &b.0, choice))
420 }
421}
422
423#[derive(Clone, Copy, Debug, PartialEq, Eq)]
424struct Scalar(U256);
425
426impl Scalar {
427 const ZERO: Self = Self(U256::ZERO);
428 const ONE: Self = Self(U256::ONE);
429
430 #[inline]
431 fn from_bytes(bytes: &[u8; 32]) -> Option<Self> {
432 let value = U256::from_be_slice(bytes);
433 if value.is_zero() || value.ct_ge(&MODULUS_N) {
434 None
435 } else {
436 Some(Self(value))
437 }
438 }
439
440 #[inline]
441 fn from_hash(hash: &[u8; 32]) -> Self {
442 let value = U256::from_be_slice(hash);
443 let (sub_value, _) = value.sub_raw(&MODULUS_N);
444 let reduced = U256::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N));
445 Self(reduced)
446 }
447
448 #[inline]
449 fn to_bytes(self) -> [u8; 32] {
450 self.0.to_be_bytes_fixed::<32>()
451 }
452
453 #[inline]
454 fn is_zero(&self) -> bool {
455 self.0.is_zero()
456 }
457
458 #[inline]
459 fn bit(&self, index: usize) -> bool {
460 self.0.bit(index)
461 }
462
463 #[inline]
464 fn add(self, rhs: Self) -> Self {
465 Self(self.0.add_mod(&rhs.0, &MODULUS_N))
466 }
467
468 #[cfg(test)]
469 #[inline]
470 fn sub(self, rhs: Self) -> Self {
471 Self(self.0.sub_mod(&rhs.0, &MODULUS_N))
472 }
473
474 #[inline]
475 fn mul(self, rhs: Self) -> Self {
476 Self(self.0.mul_mod(&rhs.0, &MODULUS_N))
477 }
478
479 #[inline]
480 fn invert(self) -> Option<Self> {
481 Some(Self(self.scalar_pow(&N_MINUS_TWO)))
482 }
483
484 #[inline]
485 fn scalar_pow(self, exponent: &U256) -> U256 {
486 let mut result = Scalar::ONE;
487 let mut i = 256usize;
488 while i > 0 {
489 i -= 1;
490 result = result.mul(result);
491 let product = result.mul(self);
492 result = Scalar::select(&product, &result, exponent.bit(i));
493 }
494 result.0
495 }
496
497 #[inline]
498 fn select(a: &Self, b: &Self, choice: bool) -> Self {
499 Self(U256::ct_select(&a.0, &b.0, choice))
500 }
501}
502
503#[derive(Clone, Copy, Debug, PartialEq, Eq)]
504struct AffinePoint {
505 x: FieldElement,
506 y: FieldElement,
507 infinity: bool,
508}
509
510impl AffinePoint {
511 const GENERATOR: Self = Self {
512 x: GENERATOR_X,
513 y: GENERATOR_Y,
514 infinity: false,
515 };
516
517 #[inline]
518 fn new(x: FieldElement, y: FieldElement) -> Option<Self> {
519 let point = Self {
520 x,
521 y,
522 infinity: false,
523 };
524 if point.is_on_curve() { Some(point) } else { None }
525 }
526
527 #[inline]
528 fn is_on_curve(&self) -> bool {
529 if self.infinity {
530 return false;
531 }
532 let x2 = self.x.square();
533 let x3 = x2.mul(self.x);
534 let rhs = x3.sub(self.x.triple()).add(CURVE_B);
535 self.y.square() == rhs
536 }
537
538 #[inline]
539 fn to_uncompressed_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
540 let mut out = [0u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
541 out[0] = 0x04;
542 out[1..33].copy_from_slice(&self.x.to_bytes());
543 out[33..65].copy_from_slice(&self.y.to_bytes());
544 out
545 }
546
547 #[cfg(test)]
548 #[inline]
549 fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
550 let mut out = [0u8; PUBLIC_KEY_COMPRESSED_SIZE];
551 out[0] = if self.y.is_odd() { 0x03 } else { 0x02 };
552 out[1..33].copy_from_slice(&self.x.to_bytes());
553 out
554 }
555
556 fn from_sec1_bytes(bytes: &[u8]) -> Option<Self> {
557 match bytes.len() {
558 PUBLIC_KEY_UNCOMPRESSED_SIZE if bytes[0] == 0x04 => {
559 let x = FieldElement::from_bytes(bytes[1..33].try_into().unwrap())?;
560 let y = FieldElement::from_bytes(bytes[33..65].try_into().unwrap())?;
561 Self::new(x, y)
562 }
563 PUBLIC_KEY_COMPRESSED_SIZE if bytes[0] == 0x02 || bytes[0] == 0x03 => {
564 let x = FieldElement::from_bytes(bytes[1..33].try_into().unwrap())?;
565 let rhs = x.square().mul(x).sub(x.triple()).add(CURVE_B);
566 let y = rhs.sqrt()?;
567 let y_is_odd = y.is_odd();
568 let select_neg = y_is_odd != (bytes[0] == 0x03);
569 let y = FieldElement::select(&y.negate(), &y, select_neg);
570 Self::new(x, y)
571 }
572 _ => None,
573 }
574 }
575}
576
577#[derive(Clone, Copy, Debug, PartialEq, Eq)]
578struct ProjectivePoint {
579 x: FieldElement,
580 y: FieldElement,
581 z: FieldElement,
582}
583
584impl ProjectivePoint {
585 const IDENTITY: Self = Self {
586 x: FieldElement::ZERO,
587 y: FieldElement::ONE,
588 z: FieldElement::ZERO,
589 };
590
591 #[cfg(test)]
592 #[inline]
593 fn from_affine(point: &AffinePoint) -> Self {
594 if point.infinity {
595 Self::IDENTITY
596 } else {
597 Self {
598 x: point.x,
599 y: point.y,
600 z: FieldElement::ONE,
601 }
602 }
603 }
604
605 #[inline]
606 fn is_identity(&self) -> bool {
607 self.z.is_zero()
608 }
609
610 #[inline]
611 fn select(a: &Self, b: &Self, choice: bool) -> Self {
612 Self {
613 x: FieldElement::select(&a.x, &b.x, choice),
614 y: FieldElement::select(&a.y, &b.y, choice),
615 z: FieldElement::select(&a.z, &b.z, choice),
616 }
617 }
618
619 #[inline]
620 fn to_affine(&self) -> Option<AffinePoint> {
621 if self.is_identity() {
622 return None;
623 }
624 let z_inv = self.z.invert()?;
625 AffinePoint::new(self.x.mul(z_inv), self.y.mul(z_inv))
626 }
627
628 fn add(&self, rhs: &Self) -> Self {
629 let xx = self.x.mul(rhs.x);
630 let yy = self.y.mul(rhs.y);
631 let zz = self.z.mul(rhs.z);
632 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
633 let yz_pairs = self.y.add(self.z).mul(rhs.y.add(rhs.z)).sub(yy.add(zz));
634 let xz_pairs = self.x.add(self.z).mul(rhs.x.add(rhs.z)).sub(xx.add(zz));
635
636 let bzz_part = xz_pairs.sub(CURVE_B.mul(zz));
637 let bzz3_part = bzz_part.triple();
638 let yy_m_bzz3 = yy.sub(bzz3_part);
639 let yy_p_bzz3 = yy.add(bzz3_part);
640
641 let zz3 = zz.triple();
642 let bxz_part = CURVE_B.mul(xz_pairs).sub(zz3.add(xx));
643 let bxz3_part = bxz_part.triple();
644 let xx3_m_zz3 = xx.triple().sub(zz3);
645
646 Self {
647 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
648 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
649 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
650 }
651 }
652
653 fn add_mixed(&self, rhs: &AffinePoint) -> Self {
654 if rhs.infinity {
655 return *self;
656 }
657
658 let xx = self.x.mul(rhs.x);
659 let yy = self.y.mul(rhs.y);
660 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
661 let yz_pairs = rhs.y.mul(self.z).add(self.y);
662 let xz_pairs = rhs.x.mul(self.z).add(self.x);
663
664 let bz_part = xz_pairs.sub(CURVE_B.mul(self.z));
665 let bz3_part = bz_part.triple();
666 let yy_m_bzz3 = yy.sub(bz3_part);
667 let yy_p_bzz3 = yy.add(bz3_part);
668
669 let z3 = self.z.triple();
670 let bxz_part = CURVE_B.mul(xz_pairs).sub(z3.add(xx));
671 let bxz3_part = bxz_part.triple();
672 let xx3_m_zz3 = xx.triple().sub(z3);
673
674 Self {
675 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
676 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
677 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
678 }
679 }
680
681 fn double(&self) -> Self {
682 let xx = self.x.square();
683 let yy = self.y.square();
684 let zz = self.z.square();
685 let xy2 = self.x.mul(self.y).double();
686 let xz2 = self.x.mul(self.z).double();
687
688 let bzz_part = CURVE_B.mul(zz).sub(xz2);
689 let bzz3_part = bzz_part.triple();
690 let yy_m_bzz3 = yy.sub(bzz3_part);
691 let yy_p_bzz3 = yy.add(bzz3_part);
692 let y_frag = yy_p_bzz3.mul(yy_m_bzz3);
693 let x_frag = yy_m_bzz3.mul(xy2);
694
695 let zz3 = zz.triple();
696 let bxz2_part = CURVE_B.mul(xz2).sub(zz3.add(xx));
697 let bxz6_part = bxz2_part.triple();
698 let xx3_m_zz3 = xx.triple().sub(zz3);
699
700 let y = y_frag.add(xx3_m_zz3.mul(bxz6_part));
701 let yz2 = self.y.mul(self.z).double();
702 let x = x_frag.sub(bxz6_part.mul(yz2));
703 let z = yz2.mul(yy).double().double();
704
705 Self {
706 x,
707 y,
708 z,
709 }
710 }
711}
712
713fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
714 scalar_mul_affine(&AffinePoint::GENERATOR, scalar)
715}
716
717fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
718 let mut acc = ProjectivePoint::IDENTITY;
719 let mut bit = 256usize;
720 while bit > 0 {
721 bit -= 1;
722 acc = acc.double();
723 let candidate = acc.add_mixed(base);
724 acc = ProjectivePoint::select(&candidate, &acc, scalar.bit(bit));
725 }
726 acc
727}
728
729#[inline]
730fn hash_message(message: &[u8]) -> [u8; 32] {
731 let digest = Sha256::hash(message);
732 return digest.as_ref().try_into().unwrap();
733}
734
735#[inline]
736fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] {
737 let mac = Hmac::<Sha256>::mac(key, data);
738 return mac.as_ref().try_into().unwrap();
739}
740
741fn bits2octets(hash: &[u8; 32]) -> [u8; 32] {
742 Scalar::from_hash(hash).to_bytes()
743}
744
745fn rfc6979_init_state(private_key: &Scalar, message_hash: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
746 let x = private_key.to_bytes();
747 let h1 = bits2octets(message_hash);
748
749 let mut v = [0x01u8; 32];
750 let mut k = [0u8; 32];
751
752 let mut buf = [0u8; 97];
753 buf[..32].copy_from_slice(&v);
754 buf[32] = 0x00;
755 buf[33..65].copy_from_slice(&x);
756 buf[65..97].copy_from_slice(&h1);
757 k = hmac_sha256(&k, &buf);
758 v = hmac_sha256(&k, &v);
759
760 buf[..32].copy_from_slice(&v);
761 buf[32] = 0x01;
762 k = hmac_sha256(&k, &buf);
763 v = hmac_sha256(&k, &v);
764
765 (k, v)
766}
767
768fn rfc6979_retry(k: &mut [u8; 32], v: &mut [u8; 32]) {
769 let mut retry_buf = [0u8; 33];
770 retry_buf[..32].copy_from_slice(v);
771 retry_buf[32] = 0x00;
772 *k = hmac_sha256(k, &retry_buf);
773 *v = hmac_sha256(k, v);
774}
775
776fn rfc6979_retry_clone(k: &[u8; 32], v: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
778 let mut retry_buf = [0u8; 33];
779 retry_buf[..32].copy_from_slice(v);
780 retry_buf[32] = 0x00;
781 let k_new = hmac_sha256(k, &retry_buf);
782 let v_new = hmac_sha256(&k_new, v);
783 (k_new, v_new)
784}
785
786fn ct_select_bytes<const N: usize>(a: &[u8; N], b: &[u8; N], choice: bool) -> [u8; N] {
788 let mask = (choice as u8).wrapping_neg();
789 let mut out = [0u8; N];
790 for i in 0..N {
791 out[i] = (a[i] & mask) | (b[i] & !mask);
792 }
793 out
794}
795
796fn rfc6979_generate_k(private_key: &Scalar, message_hash: &[u8; 32]) -> Scalar {
797 let (mut k, mut v) = rfc6979_init_state(private_key, message_hash);
798
799 let mut candidate = [0u8; 32];
807 let mut found = false;
808
809 for _ in 0..3 {
810 v = hmac_sha256(&k, &v);
811 let val = U256::from_be_slice(&v);
812 let is_valid = !val.is_zero() && !val.ct_ge(&MODULUS_N);
813
814 let take = is_valid && !found;
816 candidate = ct_select_bytes(&v, &candidate, take);
817 found = found || is_valid;
818
819 let (k_retry, v_retry) = rfc6979_retry_clone(&k, &v);
821 k = ct_select_bytes(&k, &k_retry, !is_valid);
822 v = ct_select_bytes(&v, &v_retry, !is_valid);
823 }
824
825 if found {
826 return Scalar::from_bytes(&candidate).unwrap_or(Scalar::ZERO);
828 }
829
830 v = hmac_sha256(&k, &v);
832 if let Some(sc) = Scalar::from_bytes(&v) {
833 return sc;
834 }
835
836 loop {
838 v = hmac_sha256(&k, &v);
839 if let Some(sc) = Scalar::from_bytes(&v) {
840 return sc;
841 }
842 rfc6979_retry(&mut k, &mut v);
843 }
844}
845
846fn parse_secret_key(private_key: &[u8; SECRET_KEY_SIZE]) -> Result<Scalar, EllipticCurveError> {
847 Scalar::from_bytes(private_key).ok_or(EllipticCurveError::InvalidKey)
848}
849
850fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, EllipticCurveError> {
851 AffinePoint::from_sec1_bytes(public_key).ok_or(EllipticCurveError::InvalidKey)
852}
853
854#[cfg(test)]
855fn derive_public_key_uncompressed(
856 private_key: &[u8; SECRET_KEY_SIZE],
857) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], EllipticCurveError> {
858 let scalar = parse_secret_key(private_key)?;
859 let point = scalar_mul_generator(&scalar)
860 .to_affine()
861 .ok_or(EllipticCurveError::Unspecified)?;
862 Ok(point.to_uncompressed_bytes())
863}
864
865#[cfg(test)]
866fn derive_public_key_compressed(
867 private_key: &[u8; SECRET_KEY_SIZE],
868) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], EllipticCurveError> {
869 let scalar = parse_secret_key(private_key)?;
870 let point = scalar_mul_generator(&scalar)
871 .to_affine()
872 .ok_or(EllipticCurveError::Unspecified)?;
873 Ok(point.to_compressed_bytes())
874}
875
876fn ecdh_inner(scalar: &Scalar, peer_point: &AffinePoint) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
877 let shared_point = scalar_mul_affine(peer_point, scalar)
878 .to_affine()
879 .ok_or(EllipticCurveError::Unspecified)?;
880 Ok(shared_point.x.to_bytes())
881}
882
883pub fn ecdh(
884 secret_key: &[u8; SECRET_KEY_SIZE],
885 peer_public_key: &[u8],
886) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
887 let scalar = parse_secret_key(secret_key)?;
888 let peer_point = parse_public_key(peer_public_key)?;
889 ecdh_inner(&scalar, &peer_point)
890}
891
892fn ecdsa_sign_inner(scalar: &Scalar, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
893 let message_hash = hash_message(message);
894 let z = Scalar::from_hash(&message_hash);
895
896 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_hash(&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[..32].copy_from_slice(&r.to_bytes());
919 out[32..].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[..32].try_into().unwrap()).ok_or(EllipticCurveError::Unspecified)?;
932 let s = Scalar::from_bytes(signature[32..].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_hash(&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])> {
969 if *offset >= data.len() {
970 return None;
971 }
972 let tag = data[*offset];
973 *offset += 1;
974 if *offset >= data.len() {
975 return None;
976 }
977 let len_byte = data[*offset];
978 *offset += 1;
979 let (len, _) = if len_byte & 0x80 != 0 {
980 let num_bytes = (len_byte & 0x7f) as usize;
981 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
982 return None;
983 }
984 if num_bytes > 1 && data[*offset] == 0 {
987 return None;
988 }
989 let mut l = 0usize;
990 for i in 0..num_bytes {
991 l = (l << 8) | data[*offset + i] as usize;
992 }
993 if l < 128 {
994 return None;
995 }
996 *offset += num_bytes;
997 (l, num_bytes + 1)
998 } else {
999 (len_byte as usize, 1)
1000 };
1001 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
1002 return None;
1003 }
1004 let value = &data[*offset..*offset + len];
1005 *offset = (*offset).checked_add(len)?;
1006 Some((tag, value))
1007 }
1008
1009 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; 64]> {
1012 let mut offset = 0;
1013 let (tag, inner) = der_read_tlv(der, &mut offset)?;
1014 if tag != 0x30 {
1015 return None;
1016 }
1017 if offset != der.len() {
1019 return None;
1020 }
1021 let mut inner_offset = 0;
1022 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
1023 if rtag != 0x02 || rval.is_empty() || rval.len() > 33 {
1024 return None;
1025 }
1026 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
1027 if stag != 0x02 || sval.is_empty() || sval.len() > 33 {
1028 return None;
1029 }
1030 if inner_offset != inner.len() {
1032 return None;
1033 }
1034 let r_valid = if rval.len() == 32 && rval[0] >= 0x80 {
1039 false
1040 } else if rval.len() == 33 && rval[0] != 0 {
1041 false
1042 } else if rval.len() == 33 && rval[0] == 0 && rval[1] < 0x80 {
1043 false
1044 } else if rval.len() > 33 {
1045 false
1046 } else {
1047 true
1048 };
1049 let s_valid = if sval.len() == 32 && sval[0] >= 0x80 {
1050 false
1051 } else if sval.len() == 33 && sval[0] != 0 {
1052 false
1053 } else if sval.len() == 33 && sval[0] == 0 && sval[1] < 0x80 {
1054 false
1055 } else if sval.len() > 33 {
1056 false
1057 } else {
1058 true
1059 };
1060 if !r_valid || !s_valid {
1061 return None;
1062 }
1063
1064 let r_trimmed = if rval.len() == 33 && rval[0] == 0 {
1065 &rval[1..]
1066 } else {
1067 rval
1068 };
1069 let s_trimmed = if sval.len() == 33 && sval[0] == 0 {
1070 &sval[1..]
1071 } else {
1072 sval
1073 };
1074 if r_trimmed.len() > 32 || s_trimmed.len() > 32 {
1075 return None;
1076 }
1077 let mut sig = [0u8; 64];
1078 sig[32 - r_trimmed.len()..32].copy_from_slice(r_trimmed);
1079 sig[64 - s_trimmed.len()..64].copy_from_slice(s_trimmed);
1080 Some(sig)
1081 }
1082
1083 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
1086 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
1087 let secp256r1_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
1088 let mut offset = 0;
1089 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
1090 let mut inner = 0;
1091 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
1093 if _alg_tag != 0x30 {
1094 return None;
1095 }
1096 let mut ai = 0;
1098 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
1099 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
1100 return None;
1101 }
1102 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
1104 if oid2_tag != 0x06 || oid2 != secp256r1_oid {
1105 return None;
1106 }
1107 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
1109 if _bs_tag != 0x03 || bs_val.is_empty() {
1110 return None;
1111 }
1112 Some(bs_val[1..].to_vec())
1114 }
1115
1116 #[test]
1117 fn from_x_y_matches_generator() {
1118 let key = PublicKey::from_x_y(
1119 &hex::decode("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")
1120 .unwrap()
1121 .try_into()
1122 .unwrap(),
1123 &hex::decode("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")
1124 .unwrap()
1125 .try_into()
1126 .unwrap(),
1127 )
1128 .unwrap();
1129 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
1130 assert_eq!(key, from_sec1);
1131 }
1132
1133 #[test]
1134 fn from_x_y_rejects_off_curve() {
1135 assert!(PublicKey::from_x_y(&[0u8; 32], &[0u8; 32]).is_err());
1136 }
1137
1138 #[test]
1139 fn derive_public_key_generator_matches_sec1_base_point() {
1140 let mut private_key = [0u8; 32];
1141 private_key[31] = 1;
1142 let derived = derive_public_key_uncompressed(&private_key).unwrap();
1143 let expected = decode_hex::<65>(
1144 "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\
1145 4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
1146 );
1147 assert_eq!(derived, expected);
1148 }
1149
1150 #[test]
1151 fn derive_public_key_matches_rfc6979_vector() {
1152 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1153 let expected = decode_hex::<65>(
1154 "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6\
1155 7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1156 );
1157 assert_eq!(derive_public_key_uncompressed(&private_key).unwrap(), expected);
1158 assert_eq!(
1159 derive_public_key_compressed(&private_key).unwrap(),
1160 decode_hex::<33>("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6"),
1161 );
1162 }
1163
1164 #[test]
1165 fn ecdsa_sign_matches_rfc6979_vectors() {
1166 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1167 let key = SecretKey::from_bytes(&private_key).unwrap();
1168 let sample_signature = key.sign(b"sample").unwrap();
1169 let expected_sample = decode_hex::<64>(
1170 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
1171 f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1172 );
1173 assert_eq!(sample_signature, expected_sample);
1174
1175 let test_signature = key.sign(b"test").unwrap();
1176 let expected_test = decode_hex::<64>(
1177 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367\
1178 019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
1179 );
1180 assert_eq!(test_signature, expected_test);
1181 }
1182
1183 #[test]
1184 fn rfc6979_nonce_point_x_matches_signature_r() {
1185 let nonce = decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60");
1186 let public = derive_public_key_uncompressed(&nonce).unwrap();
1187 assert_eq!(
1188 &public[1..33],
1189 &decode_hex::<32>("efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716")
1190 );
1191 }
1192
1193 #[test]
1194 fn rfc6979_nonce_generation_matches_known_value() {
1195 let private_key = Scalar::from_bytes(&decode_hex::<32>(
1196 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
1197 ))
1198 .unwrap();
1199 let hash = hash_message(b"sample");
1200 assert_eq!(
1201 rfc6979_generate_k(&private_key, &hash).to_bytes(),
1202 decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")
1203 );
1204 }
1205
1206 #[test]
1207 fn rfc6979_intermediate_hmac_values_match() {
1208 let x = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1209 let h1 = hash_message(b"sample");
1210 let mut v = [0x01u8; 32];
1211 let mut k = [0u8; 32];
1212
1213 let mut buf = [0u8; 97];
1214 buf[..32].copy_from_slice(&v);
1215 buf[32] = 0x00;
1216 buf[33..65].copy_from_slice(&x);
1217 buf[65..97].copy_from_slice(&h1);
1218 k = hmac_sha256(&k, &buf);
1219 assert_eq!(
1220 k,
1221 decode_hex::<32>("122db1de98dae4dfa33f2da8e98494c80bff807b479fd79261b37e25f267ee58")
1222 );
1223 v = hmac_sha256(&k, &v);
1224 assert_eq!(
1225 v,
1226 decode_hex::<32>("c9947803a747fc60c23535fdcc13b5ca566b48221ca67d4964d22daa48275844")
1227 );
1228
1229 buf[..32].copy_from_slice(&v);
1230 buf[32] = 0x01;
1231 k = hmac_sha256(&k, &buf);
1232 assert_eq!(
1233 k,
1234 decode_hex::<32>("b6d4f98ebae70aa15a2238ade4e20ab323fc1e777d22f0c582d8ef2e6ba73569")
1235 );
1236 v = hmac_sha256(&k, &v);
1237 assert_eq!(
1238 v,
1239 decode_hex::<32>("bae57fe256de2de806b10635497237e7bae96754582566384c47c6c3416494d1")
1240 );
1241 v = hmac_sha256(&k, &v);
1242 assert_eq!(
1243 v,
1244 decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")
1245 );
1246 }
1247
1248 #[test]
1249 fn ecdsa_verify_accepts_compressed_and_uncompressed_public_keys() {
1250 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1251 let key = SecretKey::from_bytes(&private_key).unwrap();
1252 let uncompressed = key.public_key();
1253 let compressed = derive_public_key_compressed(&private_key).unwrap();
1254 let signature = key.sign(b"sample").unwrap();
1255
1256 assert!(uncompressed.verify(b"sample", &signature).is_ok());
1257 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1258 assert!(ecdsa_verify_inner(&point, b"sample", &signature).is_ok());
1259 }
1260
1261 #[test]
1262 fn verify_rejects_tampering_and_invalid_points() {
1263 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1264 let key = SecretKey::from_bytes(&private_key).unwrap();
1265 let pub_key = key.public_key();
1266 let mut off_curve = [0u8; 65];
1267 off_curve.copy_from_slice(&pub_key.to_bytes());
1268 let signature = key.sign(b"sample").unwrap();
1269
1270 assert!(pub_key.verify(b"tampered", &signature).is_err());
1271
1272 let mut bad_signature = signature;
1273 bad_signature[10] ^= 0x80;
1274 assert!(pub_key.verify(b"sample", &bad_signature).is_err());
1275
1276 off_curve[64] ^= 0x01;
1277 assert!(!is_valid_public_key(&off_curve));
1278 assert!(PublicKey::from_bytes(&off_curve).is_err());
1279
1280 let invalid_x = decode_hex::<33>("02ffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
1281 assert!(!is_valid_public_key(&invalid_x));
1282 }
1283
1284 #[test]
1285 fn invalid_inputs_are_rejected() {
1286 let invalid_private_key = [0u8; SECRET_KEY_SIZE];
1287 assert!(SecretKey::from_bytes(&invalid_private_key).is_err());
1288 assert!(derive_public_key_uncompressed(&invalid_private_key).is_err());
1289 assert!(derive_public_key_compressed(&invalid_private_key).is_err());
1290
1291 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1292 let key = SecretKey::from_bytes(&private_key).unwrap();
1293 let signature = key.sign(b"msg").unwrap();
1294 let mut zero_r = signature;
1295 zero_r[..32].fill(0);
1296 assert!(key.public_key().verify(b"msg", &zero_r).is_err());
1297 }
1298
1299 #[test]
1300 fn public_key_validation_accepts_known_good_points() {
1301 assert!(is_valid_public_key(&decode_hex::<65>(
1302 "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\
1303 4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
1304 )));
1305 assert!(is_valid_public_key(&decode_hex::<33>(
1306 "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6"
1307 )));
1308 }
1309
1310 #[test]
1313 fn wycheproof_ecdsa_p256_sha256_p1363() {
1314 let data: serde_json::Value = serde_json::from_str(include_str!(
1315 "../testdata/wycheproof/testvectors_v1/ecdsa_secp256r1_sha256_p1363_test.json"
1316 ))
1317 .unwrap();
1318 let mut valid_tested = 0u64;
1319 let mut invalid_tested = 0u64;
1320 for group in data["testGroups"].as_array().unwrap() {
1321 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1322 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1323 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1324
1325 for test in group["tests"].as_array().unwrap() {
1326 let msg_hex = test["msg"].as_str().unwrap();
1327 let sig_hex = test["sig"].as_str().unwrap();
1328 let result = test["result"].as_str().unwrap();
1329
1330 let msg = hex::decode(msg_hex).unwrap();
1331
1332 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1333 continue;
1334 }
1335 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1336
1337 let verify_result = pk.verify(&msg, &sig);
1338
1339 if result == "valid" {
1340 assert!(
1341 verify_result.is_ok(),
1342 "wycheproof ECDSA P1363 tcId={} expected valid but failed",
1343 test["tcId"]
1344 );
1345 valid_tested += 1;
1346 } else {
1347 assert!(
1348 verify_result.is_err(),
1349 "wycheproof ECDSA P1363 tcId={} expected invalid but passed",
1350 test["tcId"]
1351 );
1352 invalid_tested += 1;
1353 }
1354 }
1355 }
1356 assert!(valid_tested > 0, "no valid ECDSA P1363 wycheproof tests were run");
1357 assert!(invalid_tested > 0, "no invalid ECDSA P1363 wycheproof tests were run");
1358 }
1359
1360 #[test]
1361 fn ecdsa_sign_verify_round_trip_multiple_messages() {
1362 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1363 let key = SecretKey::from_bytes(&private_key).unwrap();
1364 let pub_key = key.public_key();
1365
1366 let messages: &[&[u8]] = &[
1367 b"",
1368 b"hello world",
1369 b"The quick brown fox jumps over the lazy dog",
1370 &[0u8; 0],
1371 &[0xffu8; 100],
1372 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1373 ];
1374
1375 for msg in messages {
1376 let sig = key.sign(msg).unwrap();
1377 assert!(pub_key.verify(msg, &sig).is_ok(), "round-trip failed for message {:?}", msg);
1378 let mut wrong_msg = msg.to_vec();
1380 wrong_msg.push(0x42);
1381 assert!(pub_key.verify(&wrong_msg, &sig).is_err());
1382 }
1383 }
1384
1385 #[test]
1386 fn ecdsa_sign_verify_different_keys() {
1387 let keys: &[&str] = &[
1389 "0000000000000000000000000000000000000000000000000000000000000001",
1390 "0000000000000000000000000000000000000000000000000000000000000002",
1391 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550",
1392 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011",
1393 ];
1394
1395 for key_hex in keys {
1396 let private_key = decode_hex::<32>(key_hex);
1397 let key = SecretKey::from_bytes(&private_key).unwrap();
1398 let sig = key.sign(b"test message").unwrap();
1399 assert!(
1400 key.public_key().verify(b"test message", &sig).is_ok(),
1401 "sign/verify failed for key {}",
1402 key_hex
1403 );
1404 }
1405 }
1406
1407 #[test]
1408 fn ecdsa_verify_wrong_public_key_rejects() {
1409 let private_key1 = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1410 let private_key2 = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001");
1411 let key1 = SecretKey::from_bytes(&private_key1).unwrap();
1412 let key2 = SecretKey::from_bytes(&private_key2).unwrap();
1413
1414 let sig = key1.sign(b"message").unwrap();
1415 assert!(key2.public_key().verify(b"message", &sig).is_err());
1416 }
1417
1418 #[test]
1419 fn scalar_from_bytes_rejects_boundary_values() {
1420 let zero = [0u8; 32];
1422 assert!(Scalar::from_bytes(&zero).is_none());
1423
1424 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1426 assert!(Scalar::from_bytes(&n_bytes).is_none());
1427
1428 let n_minus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550");
1430 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1431
1432 let one = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001");
1434 assert!(Scalar::from_bytes(&one).is_some());
1435 }
1436
1437 #[test]
1438 fn field_element_from_bytes_rejects_boundary_values() {
1439 let p_bytes = decode_hex::<32>("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
1441 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1442
1443 let p_minus_1 = decode_hex::<32>("ffffffff00000001000000000000000000000000fffffffffffffffffffffffe");
1445 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1446
1447 let zero = [0u8; 32];
1449 assert!(FieldElement::from_bytes(&zero).is_some());
1450 }
1451
1452 #[test]
1453 fn point_decompression_round_trip() {
1454 let keys: &[&str] = &[
1456 "0000000000000000000000000000000000000000000000000000000000000001",
1457 "0000000000000000000000000000000000000000000000000000000000000002",
1458 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
1459 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011",
1460 ];
1461
1462 for key_hex in keys {
1463 let private_key = decode_hex::<32>(key_hex);
1464 let key = SecretKey::from_bytes(&private_key).unwrap();
1465 let uncompressed = key.public_key();
1466 let compressed = derive_public_key_compressed(&private_key).unwrap();
1467
1468 let sig = key.sign(b"round-trip").unwrap();
1470 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
1471 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1472 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
1473
1474 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1476 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
1477 }
1478 }
1479
1480 #[test]
1481 fn nist_cavp_verify_vectors() {
1482 struct VerifyVector {
1486 qx: &'static str,
1487 qy: &'static str,
1488 msg: &'static [u8],
1489 r: &'static str,
1490 s: &'static str,
1491 valid: bool,
1492 }
1493
1494 let vectors = [
1495 VerifyVector {
1497 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1498 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1499 msg: b"sample",
1500 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1501 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1502 valid: true,
1503 },
1504 VerifyVector {
1506 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1507 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1508 msg: b"test",
1509 r: "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
1510 s: "019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
1511 valid: true,
1512 },
1513 VerifyVector {
1515 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1516 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1517 msg: b"wrong",
1518 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1519 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1520 valid: false,
1521 },
1522 VerifyVector {
1524 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1525 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1526 msg: b"test",
1527 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1528 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1529 valid: false,
1530 },
1531 VerifyVector {
1533 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1534 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1535 msg: b"sample",
1536 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3717",
1537 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1538 valid: false,
1539 },
1540 ];
1541
1542 for (i, v) in vectors.iter().enumerate() {
1543 let mut pubkey = [0u8; 65];
1544 pubkey[0] = 0x04;
1545 pubkey[1..33].copy_from_slice(&hex::decode(v.qx).unwrap());
1546 pubkey[33..65].copy_from_slice(&hex::decode(v.qy).unwrap());
1547
1548 let mut sig = [0u8; 64];
1549 sig[..32].copy_from_slice(&hex::decode(v.r).unwrap());
1550 sig[32..].copy_from_slice(&hex::decode(v.s).unwrap());
1551
1552 let pk = PublicKey::from_bytes(&pubkey).unwrap();
1553 let result = pk.verify(v.msg, &sig);
1554 if v.valid {
1555 assert!(result.is_ok(), "NIST vector {} should be valid", i);
1556 } else {
1557 assert!(result.is_err(), "NIST vector {} should be invalid", i);
1558 }
1559 }
1560 }
1561
1562 #[test]
1563 fn rfc6979_bits2octets_matches_spec() {
1564 let hash = hash_message(b"sample");
1566 let result = bits2octets(&hash);
1567 assert_eq!(result, hash);
1571
1572 let big_hash: [u8; 32] = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1574 let reduced = bits2octets(&big_hash);
1575 assert_eq!(
1577 reduced,
1578 decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001")
1579 );
1580 }
1581
1582 #[test]
1583 fn scalar_inversion_correctness() {
1584 let k = Scalar::from_bytes(&decode_hex::<32>(
1586 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
1587 ))
1588 .unwrap();
1589 let k_inv = k.invert().unwrap();
1590 let product = k.mul(k_inv);
1591 assert_eq!(product, Scalar::ONE);
1592 }
1593
1594 #[test]
1595 fn field_element_inversion_correctness() {
1596 let x = FieldElement::from_bytes(&decode_hex::<32>(
1598 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1599 ))
1600 .unwrap();
1601 let x_inv = x.invert().unwrap();
1602 let product = x.mul(x_inv);
1603 assert_eq!(product, FieldElement::ONE);
1604 let product = x.mul(x_inv);
1605 assert_eq!(product, FieldElement::ONE);
1606 }
1607
1608 #[test]
1609 fn generator_point_is_on_curve() {
1610 assert!(AffinePoint::GENERATOR.is_on_curve());
1611 }
1612
1613 #[test]
1614 fn p256_fast_mul_mod_matches_generic() {
1615 for _ in 0..1000 {
1618 let a_bytes: [u8; 32] = rand::random();
1619 let b_bytes: [u8; 32] = rand::random();
1620 let a_opt = FieldElement::from_bytes(&a_bytes);
1621 let b_opt = FieldElement::from_bytes(&b_bytes);
1622 if a_opt.is_none() || b_opt.is_none() {
1623 continue;
1624 }
1625 let a = a_opt.unwrap();
1626 let b = b_opt.unwrap();
1627 let expected = U256::from_limbs({
1628 let mut p = [0u64; 8];
1629 for i in 0..4 {
1630 let mut c = 0u64;
1631 for j in 0..4 {
1632 let (v, cc) = mac(p[i + j], a.0.limbs[i], b.0.limbs[j], c);
1633 p[i + j] = v;
1634 c = cc;
1635 }
1636 p[i + 4] = c;
1637 }
1638 let mut rem = [0u64; 4];
1639 for bi in (0..512).rev() {
1640 let li = bi / 64;
1641 let pi = bi % 64;
1642 let bit = ((p[li] >> pi) & 1) as u64;
1643 let mut shifted = [0u64; 4];
1644 let mut carry = bit;
1645 for j in 0..4 {
1646 let next = rem[j] >> 63;
1647 shifted[j] = (rem[j] << 1) | carry;
1648 carry = next;
1649 }
1650 let (red, br) = U256::from_limbs(shifted).sub_raw(&MODULUS_P);
1651 if carry == 1 || br == 0 {
1652 rem = red.limbs;
1653 } else {
1654 rem = shifted;
1655 }
1656 }
1657 rem
1658 });
1659 let fast = p256_fast_mul_mod(&a.0, &b.0);
1660 assert_eq!(expected, fast, "mismatch");
1661 }
1662 }
1663
1664 #[test]
1665 fn scalar_mul_generator_n_gives_identity() {
1666 let n_minus_1 = Scalar::from_bytes(&decode_hex::<32>(
1671 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550",
1672 ))
1673 .unwrap();
1674 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
1675 assert_eq!(result.x, GENERATOR_X);
1676 let neg_gy = GENERATOR_Y.negate();
1678 assert_eq!(result.y, neg_gy);
1679 }
1680
1681 #[test]
1684 fn ecdh_rfc5903_section_8_1() {
1685 let i_priv = decode_hex::<32>("c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433");
1687 let i_pub = decode_hex::<65>(
1688 "04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c3772581180\
1689 5271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3",
1690 );
1691 let r_priv = decode_hex::<32>("c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53");
1692 let r_pub = decode_hex::<65>(
1693 "04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf63\
1694 56fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab",
1695 );
1696 let expected_shared = decode_hex::<32>("d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de");
1697
1698 let alice = SecretKey::from_bytes(&i_priv).unwrap();
1699 let bob = SecretKey::from_bytes(&r_priv).unwrap();
1700 let bob_pub = PublicKey::from_bytes(&r_pub).unwrap();
1701 let alice_pub = PublicKey::from_bytes(&i_pub).unwrap();
1702
1703 assert_eq!(alice.public_key().to_bytes(), i_pub);
1704 assert_eq!(bob.public_key().to_bytes(), r_pub);
1705
1706 let alice_shared = alice.ecdh(&bob_pub).unwrap();
1707 let bob_shared = bob.ecdh(&alice_pub).unwrap();
1708
1709 assert_eq!(alice_shared, expected_shared);
1710 assert_eq!(bob_shared, expected_shared);
1711 }
1712
1713 #[test]
1714 fn ecdh_nist_cavp_vector_from_go() {
1715 let priv_key = decode_hex::<32>("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534");
1717 let pub_key = decode_hex::<65>(
1718 "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230\
1719 28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
1720 );
1721 let peer_pub = decode_hex::<65>(
1722 "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287\
1723 db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
1724 );
1725 let expected_shared = decode_hex::<32>("46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b");
1726
1727 let key = SecretKey::from_bytes(&priv_key).unwrap();
1728 assert_eq!(key.public_key().to_bytes(), pub_key);
1729
1730 let peer = PublicKey::from_bytes(&peer_pub).unwrap();
1731 let shared = key.ecdh(&peer).unwrap();
1732 assert_eq!(shared, expected_shared);
1733 }
1734
1735 #[test]
1736 fn ecdh_with_compressed_public_key() {
1737 let priv_alice = decode_hex::<32>("c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433");
1739 let bob_pub_compressed = decode_hex::<33>("03d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf63");
1740
1741 assert!(is_valid_public_key(&bob_pub_compressed));
1742
1743 let expected_shared = decode_hex::<32>("d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de");
1744
1745 let shared = ecdh(&priv_alice, &bob_pub_compressed).unwrap();
1746 assert_eq!(shared, expected_shared);
1747 }
1748
1749 #[test]
1750 fn ecdh_round_trip_alice_bob() {
1751 let alice = SecretKey::generate().unwrap();
1753 let bob = SecretKey::generate().unwrap();
1754
1755 let alice_shared = alice.ecdh(&bob.public_key()).unwrap();
1756 let bob_shared = bob.ecdh(&alice.public_key()).unwrap();
1757
1758 assert_eq!(alice_shared, bob_shared);
1759 assert_eq!(alice_shared.len(), 32);
1760 }
1761
1762 #[test]
1763 fn ecdh_rejects_off_curve_peer_public_key() {
1764 let alice = SecretKey::generate().unwrap();
1765 let mut bad_pub = alice.public_key().to_bytes().to_vec();
1766 bad_pub[64] ^= 0x01;
1768 assert!(!is_valid_public_key(&bad_pub));
1769 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1770 }
1771
1772 #[test]
1773 fn ecdh_rejects_infinity_peer_public_key() {
1774 let alice = SecretKey::generate().unwrap();
1775 let infinity = [0x00u8];
1777 assert!(ecdh(&alice.to_bytes(), &infinity).is_err());
1778 }
1779
1780 #[test]
1781 fn ecdh_rejects_bad_length_peer_public_key() {
1782 let alice = SecretKey::generate().unwrap();
1783 assert!(ecdh(&alice.to_bytes(), &[]).is_err());
1785 assert!(ecdh(&alice.to_bytes(), &[0x04, 0x00]).is_err());
1787 let mut long = [0x04u8; 200];
1789 long[0] = 0x04;
1790 assert!(ecdh(&alice.to_bytes(), &long).is_err());
1791 }
1792
1793 #[test]
1794 fn ecdh_rejects_invalid_private_key_zero() {
1795 let zero_key = [0u8; 32];
1796 assert!(SecretKey::from_bytes(&zero_key).is_err());
1797 let bob = SecretKey::generate().unwrap();
1798 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1799 }
1800
1801 #[test]
1802 fn ecdh_rejects_invalid_private_key_order() {
1803 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1805 assert!(SecretKey::from_bytes(&n_bytes).is_err());
1806
1807 let n_plus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1809 assert!(SecretKey::from_bytes(&n_plus_1).is_err());
1810
1811 let all_ones = [0xffu8; 32];
1813 assert!(SecretKey::from_bytes(&all_ones).is_err());
1814 }
1815
1816 #[test]
1817 fn ecdh_rejects_peer_public_key_x_equal_to_p() {
1818 let alice = SecretKey::generate().unwrap();
1820 let mut bad_pub = [0u8; 65];
1821 bad_pub[0] = 0x04;
1822 bad_pub[1..33].copy_from_slice(&decode_hex::<32>(
1823 "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
1824 ));
1825 bad_pub[33..65].fill(0x01);
1826 assert!(!is_valid_public_key(&bad_pub));
1827 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1828 }
1829
1830 #[test]
1831 fn ecdh_different_messages_same_shared_secret() {
1832 let alice = SecretKey::generate().unwrap();
1834 let bob = SecretKey::generate().unwrap();
1835
1836 let shared1 = alice.ecdh(&bob.public_key()).unwrap();
1837 let shared2 = alice.ecdh(&bob.public_key()).unwrap();
1838 assert_eq!(shared1, shared2);
1839 }
1840
1841 #[test]
1842 fn ecdh_self_exchange_is_deterministic() {
1843 let alice = SecretKey::generate().unwrap();
1845 let shared = alice.ecdh(&alice.public_key()).unwrap();
1846 let shared2 = alice.ecdh(&alice.public_key()).unwrap();
1847 assert_eq!(shared, shared2);
1848 }
1849
1850 #[test]
1851 fn ecdh_different_keys_produce_different_secrets() {
1852 let alice = SecretKey::generate().unwrap();
1853 let bob1 = SecretKey::generate().unwrap();
1854 let bob2 = SecretKey::generate().unwrap();
1855
1856 let shared1 = alice.ecdh(&bob1.public_key()).unwrap();
1857 let shared2 = alice.ecdh(&bob2.public_key()).unwrap();
1858 assert_ne!(shared1, shared2);
1860 }
1861
1862 #[test]
1863 fn ecdh_generator_multiplication_matches_go_p256_mult_test1() {
1864 let k = decode_hex::<32>("2a265f8bcbdcaf94d58519141e578124cb40d64a501fba9c11847b28965bc737");
1866 let x_in = decode_hex::<32>("023819813ac969847059028ea88a1f30dfbcde03fc791d3a252c6b41211882ea");
1867 let y_in = decode_hex::<32>("f93e4ae433cc12cf2a43fc0ef26400c0e125508224cdb649380f25479148a4ad");
1868 let x_out = decode_hex::<32>("4d4de80f1534850d261075997e3049321a0864082d24a917863366c0724f5ae3");
1869 let y_out = decode_hex::<32>("a22d2b7f7818a3563e0f7a76c9bf0921ac55e06e2e4d11795b233824b1db8cc0");
1870
1871 let mut pubkey = [0u8; 65];
1872 pubkey[0] = 0x04;
1873 pubkey[1..33].copy_from_slice(&x_in);
1874 pubkey[33..65].copy_from_slice(&y_in);
1875
1876 let point = parse_public_key(&pubkey).unwrap();
1877 let scalar = Scalar::from_bytes(&k).unwrap();
1878 let result = scalar_mul_affine(&point, &scalar).to_affine().unwrap();
1879
1880 assert_eq!(result.x.to_bytes(), x_out, "x coordinate mismatch in Go test 1");
1881 assert_eq!(result.y.to_bytes(), y_out, "y coordinate mismatch in Go test 1");
1882 }
1883
1884 #[test]
1885 fn ecdh_generator_multiplication_matches_go_p256_mult_test2() {
1886 let k = decode_hex::<32>("313f72ff9fe811bf573176231b286a3bdb6f1b14e05c40146590727a71c3bccd");
1888 let x_in = decode_hex::<32>("cc11887b2d66cbae8f4d306627192522932146b42f01d3c6f92bd5c8ba739b06");
1889 let y_in = decode_hex::<32>("a2f08a029cd06b46183085bae9248b0ed15b70280c7ef13a457f5af382426031");
1890 let x_out = decode_hex::<32>("831c3f6b5f762d2f461901577af41354ac5f228c2591f84f8a6e51e2e3f17991");
1891 let y_out = decode_hex::<32>("93f90934cd0ef2c698cc471c60a93524e87ab31ca2412252337f364513e43684");
1892
1893 let mut pubkey = [0u8; 65];
1894 pubkey[0] = 0x04;
1895 pubkey[1..33].copy_from_slice(&x_in);
1896 pubkey[33..65].copy_from_slice(&y_in);
1897
1898 let point = parse_public_key(&pubkey).unwrap();
1899 let scalar = Scalar::from_bytes(&k).unwrap();
1900 let result = scalar_mul_affine(&point, &scalar).to_affine().unwrap();
1901
1902 assert_eq!(result.x.to_bytes(), x_out, "x coordinate mismatch in Go test 2");
1903 assert_eq!(result.y.to_bytes(), y_out, "y coordinate mismatch in Go test 2");
1904 }
1905
1906 #[test]
1907 fn ecdh_rejects_invalid_curve_attack() {
1908 let alice = SecretKey::generate().unwrap();
1911 let mut off_curve = [0u8; 65];
1912 off_curve[0] = 0x04;
1913 off_curve[33] = 0x01;
1914 off_curve[64] = 0x01;
1915 off_curve[1] = 0x01;
1916
1917 assert!(!is_valid_public_key(&off_curve));
1918 assert!(ecdh(&alice.to_bytes(), &off_curve).is_err());
1919 }
1920
1921 #[test]
1922 fn ecdh_edge_case_shared_secret_x_equals_zero() {
1923 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1926 let pub_hex = "0458fd4168a87795603e2b04390285bdca6e57de6027fe211dd9d25e2212d29e6\
1927 2080d36bd224d7405509295eed02a17150e03b314f96da37445b0d1d29377d12c";
1928 let expected_shared = [0u8; 32];
1929
1930 let priv_key = decode_hex::<32>(priv_hex);
1931 let pub_key = decode_hex::<65>(pub_hex);
1932
1933 assert!(is_valid_public_key(&pub_key));
1934 let shared = ecdh(&priv_key, &pub_key).unwrap();
1935 assert_eq!(shared, expected_shared);
1936 }
1937
1938 #[test]
1939 fn ecdh_edge_case_shared_secret_x_equals_p_minus_3() {
1940 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1943 let pub_hex = "04a1ecc24bf0d0053d23f5fd80ddf1735a1925039dc1176c581a7e795163c8b9ba\
1944 2cb5a4e4d5109f4527575e3137b83d79a9bcb3faeff90d2aca2bed71bb523e7e";
1945 let expected_shared = decode_hex::<32>("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc");
1946
1947 let priv_key = decode_hex::<32>(priv_hex);
1948 let pub_key = decode_hex::<65>(pub_hex);
1949
1950 assert!(is_valid_public_key(&pub_key));
1951 let shared = ecdh(&priv_key, &pub_key).unwrap();
1952 assert_eq!(shared, expected_shared);
1953 }
1954
1955 #[test]
1956 fn ecdh_edge_case_shared_secret_power_of_two() {
1957 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1960 let pub_hex = "041b0e7437c33d379929430d3ec10df59bed7fe2a1d950c5791e1e9ddeef1f4d70\
1961 fbdb0e3bbce63a27f27838c685207f2ccaf689d25eb622744db1168ac92619e8";
1962 let expected_shared = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000010000");
1963
1964 let priv_key = decode_hex::<32>(priv_hex);
1965 let pub_key = decode_hex::<65>(pub_hex);
1966
1967 assert!(is_valid_public_key(&pub_key));
1968 let shared = ecdh(&priv_key, &pub_key).unwrap();
1969 assert_eq!(shared, expected_shared);
1970 }
1971
1972 #[test]
1973 fn ecdh_wrong_curve_rejected() {
1974 let alice = SecretKey::generate().unwrap();
1979 let p224_gen_x = [
1980 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03,
1981 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21,
1982 ];
1983 let p224_gen_y = [
1984 0x00, 0x00, 0x00, 0x00, 0xbd, 0x37, 0x68, 0x08, 0xb3, 0x2c, 0x81, 0x2e, 0xd7, 0xd2, 0x86, 0x72, 0x37, 0x46,
1985 0xa5, 0xdc, 0x63, 0x63, 0x9c, 0x5d, 0x99, 0xd6, 0x9c, 0xb4, 0xd4, 0xfc, 0xb5, 0x9e,
1986 ];
1987 let mut bad_pub = [0u8; 65];
1988 bad_pub[0] = 0x04;
1989 bad_pub[1..33].copy_from_slice(&p224_gen_x);
1990 bad_pub[33..65].copy_from_slice(&p224_gen_y);
1991
1992 assert!(!is_valid_public_key(&bad_pub));
1993 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1994 }
1995
1996 #[test]
1997 fn ecdh_private_key_rejects_zero_and_order() {
1998 let zero = [0u8; 32];
2000 assert!(SecretKey::from_bytes(&zero).is_err());
2001
2002 let n = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
2003 assert!(SecretKey::from_bytes(&n).is_err());
2004
2005 let n_minus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550");
2006 assert!(SecretKey::from_bytes(&n_minus_1).is_ok());
2007 }
2008
2009 #[test]
2010 fn ecdh_public_key_rejects_invalid_encodings() {
2011 assert!(!is_valid_public_key(&[0x00]));
2013
2014 let mut bad_prefix = [0u8; 65];
2016 bad_prefix[0] = 0x05;
2017 bad_prefix[1] = 0x01;
2018 assert!(!is_valid_public_key(&bad_prefix));
2019
2020 assert!(!is_valid_public_key(&[0x04, 0x00]));
2022
2023 let mut too_long = [0u8; 66];
2025 too_long[0] = 0x04;
2026 assert!(!is_valid_public_key(&too_long));
2027 }
2028
2029 #[test]
2030 fn ecdh_multiple_exchanges_consistency() {
2031 let alice = SecretKey::generate().unwrap();
2033 let bob = SecretKey::generate().unwrap();
2034 let charlie = SecretKey::generate().unwrap();
2035
2036 let alice_bob = alice.ecdh(&bob.public_key()).unwrap();
2037 let bob_alice = bob.ecdh(&alice.public_key()).unwrap();
2038 assert_eq!(alice_bob, bob_alice);
2039
2040 let alice_charlie = alice.ecdh(&charlie.public_key()).unwrap();
2041 let charlie_alice = charlie.ecdh(&alice.public_key()).unwrap();
2042 assert_eq!(alice_charlie, charlie_alice);
2043
2044 let bob_charlie = bob.ecdh(&charlie.public_key()).unwrap();
2045 let charlie_bob = charlie.ecdh(&bob.public_key()).unwrap();
2046 assert_eq!(bob_charlie, charlie_bob);
2047
2048 assert_ne!(alice_bob, alice_charlie);
2050 assert_ne!(alice_bob, bob_charlie);
2051 assert_ne!(alice_charlie, bob_charlie);
2052 }
2053
2054 #[test]
2055 fn ecdh_standalone_function_matches_method() {
2056 let alice = SecretKey::generate().unwrap();
2057 let bob = SecretKey::generate().unwrap();
2058
2059 let method_result = alice.ecdh(&bob.public_key()).unwrap();
2060 let standalone_result = ecdh(&alice.to_bytes(), &bob.public_key().to_bytes()).unwrap();
2061
2062 assert_eq!(method_result, standalone_result);
2063 }
2064
2065 #[test]
2066 fn rfc6979_test_message_nonce_matches_known_value() {
2067 let private_key = Scalar::from_bytes(&decode_hex::<32>(
2068 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
2069 ))
2070 .unwrap();
2071 let hash = hash_message(b"test");
2072 assert_eq!(
2073 rfc6979_generate_k(&private_key, &hash).to_bytes(),
2074 decode_hex::<32>("d16b6ae827f17175e040871a1c7ec3500192c4c92677336ec2537acaee0008e0")
2075 );
2076 }
2077
2078 #[test]
2079 fn ecdsa_rejects_ptr_at_infinity_as_public_key() {
2080 assert!(!is_valid_public_key(&[0x00]));
2082 assert!(PublicKey::from_bytes(&[0x00]).is_err());
2083 }
2084
2085 #[test]
2086 fn ecdsa_verify_rejects_non_canonical_r_and_s() {
2087 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
2088 let key = SecretKey::from_bytes(&private_key).unwrap();
2089 let _valid_sig = key.sign(b"msg").unwrap();
2090
2091 let sig = decode_hex::<64>(
2093 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552\
2094 f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
2095 );
2096 assert!(key.public_key().verify(b"msg", &sig).is_err());
2097
2098 let sig = decode_hex::<64>(
2100 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
2101 ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552",
2102 );
2103 assert!(key.public_key().verify(b"msg", &sig).is_err());
2104 }
2105
2106 #[test]
2107 fn private_key_round_trip_bytes() {
2108 let key = SecretKey::generate().unwrap();
2109 let bytes = key.to_bytes();
2110 let key2 = SecretKey::from_bytes(&bytes).unwrap();
2111 assert_eq!(key.to_bytes(), key2.to_bytes());
2112 assert_eq!(key.public_key().to_bytes(), key2.public_key().to_bytes());
2113 }
2114
2115 #[test]
2116 fn public_key_round_trip_bytes() {
2117 let key = SecretKey::generate().unwrap();
2118 let pub_key = key.public_key();
2119 let bytes = pub_key.to_bytes();
2120 let pub_key2 = PublicKey::from_bytes(&bytes).unwrap();
2121 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
2122 }
2123
2124 #[test]
2125 fn field_element_add_sub_mul_consistency() {
2126 let a = FieldElement::from_bytes(&decode_hex::<32>(
2127 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
2128 ))
2129 .unwrap();
2130 let b = FieldElement::from_bytes(&decode_hex::<32>(
2131 "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
2132 ))
2133 .unwrap();
2134
2135 assert_eq!(a.add(b).sub(b), a);
2137
2138 assert_eq!(a.add(b), b.add(a));
2140
2141 assert_eq!(a.mul(b), b.mul(a));
2143
2144 let c = FieldElement::from_bytes(&decode_hex::<32>(
2146 "3bce3c3e27d2604b651d06b0cc53b0f6b3ebbd55769886bc5ac635d8aa3a93e7",
2147 ))
2148 .unwrap();
2149 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
2150 }
2151
2152 #[test]
2153 fn scalar_add_sub_mul_consistency() {
2154 let a = Scalar::from_bytes(&decode_hex::<32>(
2155 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
2156 ))
2157 .unwrap();
2158 let one = Scalar::from_bytes(&decode_hex::<32>(
2160 "0000000000000000000000000000000000000000000000000000000000000001",
2161 ))
2162 .unwrap();
2163
2164 assert_eq!(a.add(one).sub(one), a);
2166
2167 assert_eq!(a.mul(one), a);
2169
2170 let b = Scalar::from_bytes(&decode_hex::<32>(
2172 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
2173 ))
2174 .unwrap();
2175 assert_eq!(a.mul(b), b.mul(a));
2176 assert_eq!(a.add(b), b.add(a));
2177 }
2178
2179 #[test]
2180 fn ecdh_shared_secret_boundary_values() {
2181 let alice = SecretKey::generate().unwrap();
2183 let bob = SecretKey::generate().unwrap();
2184
2185 let shared = alice.ecdh(&bob.public_key()).unwrap();
2186 assert_eq!(shared.len(), ECDH_SHARED_SECRET_SIZE);
2187
2188 let shared2 = alice.ecdh(&bob.public_key()).unwrap();
2190 assert_eq!(shared, shared2);
2191 }
2192
2193 #[test]
2194 fn ecdh_rejects_empty_and_invalid_public_key_bytes() {
2195 let key = SecretKey::generate().unwrap();
2196
2197 let mut bad = key.public_key().to_bytes();
2199 bad[0] = 0xff;
2200 assert!(!is_valid_public_key(&bad));
2201 assert!(PublicKey::from_bytes(&bad).is_err());
2202
2203 assert!(!is_valid_public_key(&[0x04]));
2205
2206 assert!(!is_valid_public_key(&bad[..64]));
2208
2209 let zero_x_compressed = decode_hex::<33>("020000000000000000000000000000000000000000000000000000000000000000");
2211 let _ = PublicKey::from_bytes(&zero_x_compressed);
2214 }
2215
2216 #[test]
2217 fn ecdsa_sign_then_verify_consistent_for_random_keys() {
2218 for _ in 0..5 {
2219 let key = SecretKey::generate().unwrap();
2220 let msg = rand::random::<[u8; 32]>();
2221 let sig = key.sign(&msg).unwrap();
2222 assert!(key.public_key().verify(&msg, &sig).is_ok());
2223 }
2224 }
2225
2226 #[test]
2227 fn field_element_negate_round_trip() {
2228 let x = FieldElement::from_bytes(&decode_hex::<32>(
2229 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
2230 ))
2231 .unwrap();
2232 let neg = x.negate();
2233 assert_eq!(neg.negate(), x);
2234 assert_eq!(x.add(neg), FieldElement::ZERO);
2235 }
2236
2237 #[test]
2238 fn scalar_negate_round_trip() {
2239 let a = Scalar::from_bytes(&decode_hex::<32>(
2240 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
2241 ))
2242 .unwrap();
2243 let neg_a = Scalar::ZERO.sub(a);
2244 assert_eq!(a.add(neg_a), Scalar::ZERO);
2245 assert_eq!(Scalar::ZERO.sub(neg_a), a);
2247 }
2248
2249 #[test]
2250 fn point_double_and_add_consistency() {
2251 let g = AffinePoint::GENERATOR;
2253 let proj_g = ProjectivePoint::from_affine(&g);
2254 let doubled = proj_g.double();
2255 let added = proj_g.add(&proj_g);
2256 assert_eq!(
2257 doubled.to_affine().unwrap().to_uncompressed_bytes(),
2258 added.to_affine().unwrap().to_uncompressed_bytes(),
2259 );
2260 }
2261
2262 #[test]
2263 fn scalar_mul_by_two_matches_double() {
2264 let two = Scalar::from_bytes(&decode_hex::<32>(
2265 "0000000000000000000000000000000000000000000000000000000000000002",
2266 ))
2267 .unwrap();
2268 let g_times_2 = scalar_mul_affine(&AffinePoint::GENERATOR, &two).to_affine().unwrap();
2269 let proj_g = ProjectivePoint::from_affine(&AffinePoint::GENERATOR);
2270 let g_doubled = proj_g.double().to_affine().unwrap();
2271
2272 assert_eq!(g_times_2.to_uncompressed_bytes(), g_doubled.to_uncompressed_bytes());
2273 }
2274
2275 #[test]
2276 fn ecdh_with_self_is_consistent() {
2277 let key = SecretKey::generate().unwrap();
2278 let shared1 = key.ecdh(&key.public_key()).unwrap();
2279 let shared2 = key.ecdh(&key.public_key()).unwrap();
2280 assert_eq!(shared1, shared2);
2281 }
2282
2283 #[test]
2284 fn wycheproof_ecdh_p256_ecpoint() {
2285 let data: serde_json::Value = serde_json::from_str(include_str!(
2286 "../testdata/wycheproof/testvectors_v1/ecdh_secp256r1_ecpoint_test.json"
2287 ))
2288 .unwrap();
2289 let mut valid_tested = 0u64;
2290 let mut invalid_tested = 0u64;
2291 let mut acceptable_tested = 0u64;
2292 for group in data["testGroups"].as_array().unwrap() {
2293 if group["curve"].as_str() != Some("secp256r1") {
2294 continue;
2295 }
2296 for test in group["tests"].as_array().unwrap() {
2297 let public_hex = test["public"].as_str().unwrap();
2298 let private_hex = test["private"].as_str().unwrap();
2299 let expected_shared_hex = test["shared"].as_str().unwrap();
2300 let result = test["result"].as_str().unwrap();
2301
2302 let public_key = hex::decode(public_hex).unwrap();
2303
2304 let private_bytes = hex::decode(private_hex).unwrap();
2307 let mut private_key = [0u8; SECRET_KEY_SIZE];
2308 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
2309 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
2310 private_bytes.len() - SECRET_KEY_SIZE
2311 } else {
2312 0
2313 };
2314 private_key[SECRET_KEY_SIZE - effective_len..]
2315 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
2316
2317 let shared = ecdh(&private_key, &public_key);
2318
2319 if result == "valid" {
2320 let shared = shared.unwrap();
2321 let shared_hex = hex::encode(shared);
2322 assert_eq!(shared_hex, expected_shared_hex, "wycheproof ECDH ecpoint tcId={}", test["tcId"]);
2323 valid_tested += 1;
2324 } else if result == "invalid" {
2325 assert!(
2326 shared.is_err(),
2327 "wycheproof ECDH ecpoint tcId={} expected invalid but passed",
2328 test["tcId"]
2329 );
2330 invalid_tested += 1;
2331 } else {
2332 acceptable_tested += 1;
2333 }
2334 }
2335 }
2336 assert!(valid_tested > 0, "no valid ECDH ecpoint wycheproof tests were run");
2337 assert!(invalid_tested > 0, "no invalid ECDH ecpoint wycheproof tests were run");
2338 assert!(acceptable_tested > 0, "no acceptable ECDH ecpoint wycheproof tests were run");
2339 }
2340
2341 #[test]
2342 fn compressed_public_key_has_correct_prefix() {
2343 for _ in 0..5 {
2344 let key = SecretKey::generate().unwrap();
2345 let compressed = derive_public_key_compressed(&key.to_bytes()).unwrap();
2346 let prefix = compressed[0];
2347 assert!(prefix == 0x02 || prefix == 0x03, "invalid compressed prefix: {prefix:#x}");
2348 }
2349 }
2350
2351 #[test]
2352 fn p256_ecdsa_rejects_truncated_signature() {
2353 let key = SecretKey::generate().unwrap();
2354 let sig = key.sign(b"msg").unwrap();
2355 let mut truncated = [0u8; SIGNATURE_SIZE];
2357 truncated[..63].copy_from_slice(&sig[..63]);
2358 if truncated == sig {
2361 truncated[63] ^= 0x01;
2362 }
2363 assert!(key.public_key().verify(b"msg", &truncated).is_err());
2364 }
2365
2366 #[test]
2367 fn is_on_curve_accepts_generator_and_random_points() {
2368 assert!(AffinePoint::GENERATOR.is_on_curve());
2369 for _ in 0..5 {
2370 let key = SecretKey::generate().unwrap();
2371 let pb = key.public_key().to_bytes();
2374 let pk = PublicKey::from_bytes(&pb).unwrap();
2375 let _ = pk; }
2377 }
2378
2379 #[test]
2380 fn field_element_pow_correctness() {
2381 let x = FieldElement::from_bytes(&decode_hex::<32>(
2382 "0000000000000000000000000000000000000000000000000000000000000002",
2383 ))
2384 .unwrap();
2385 let x3 = x.pow(&U256::from_u64(3));
2387 let expected = x.mul(x).mul(x);
2388 assert_eq!(x3, expected);
2389
2390 let x0 = x.pow(&U256::ZERO);
2392 assert_eq!(x0, FieldElement::ONE);
2393 }
2394
2395 #[test]
2396 fn nist_p256_vector_verify_all_rfc6979_signatures() {
2397 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
2399 let key = SecretKey::from_bytes(&private_key).unwrap();
2400
2401 let vectors: &[(&[u8], &str)] = &[
2402 (
2403 b"sample" as &[u8],
2404 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
2405 f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
2406 ),
2407 (
2408 b"test" as &[u8],
2409 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367\
2410 019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
2411 ),
2412 ];
2413
2414 for (msg, hex_sig) in vectors {
2415 let sig = key.sign(msg).unwrap();
2416 let expected = decode_hex::<64>(hex_sig);
2417 assert_eq!(sig, expected, "failed for message: {:?}", String::from_utf8_lossy(msg));
2418 }
2419 }
2420
2421 #[test]
2422 fn wycheproof_ecdsa_p256_sha256_der() {
2423 let data: serde_json::Value = serde_json::from_str(include_str!(
2424 "../testdata/wycheproof/testvectors_v1/ecdsa_secp256r1_sha256_test.json"
2425 ))
2426 .unwrap();
2427 let mut valid_tested = 0u64;
2428 let mut invalid_tested = 0u64;
2429 for group in data["testGroups"].as_array().unwrap() {
2430 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
2431 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
2432 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
2433
2434 for test in group["tests"].as_array().unwrap() {
2435 let msg_hex = test["msg"].as_str().unwrap();
2436 let sig_hex = test["sig"].as_str().unwrap();
2437 let result = test["result"].as_str().unwrap();
2438
2439 let msg = hex::decode(msg_hex).unwrap();
2440 let der_sig = hex::decode(sig_hex).unwrap();
2441 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
2442 continue;
2443 };
2444
2445 let verify_result = pk.verify(&msg, &sig);
2446
2447 if result == "valid" {
2448 assert!(
2449 verify_result.is_ok(),
2450 "wycheproof ECDSA DER SHA-256 tcId={} expected valid but failed",
2451 test["tcId"]
2452 );
2453 valid_tested += 1;
2454 } else {
2455 assert!(
2456 verify_result.is_err(),
2457 "wycheproof ECDSA DER SHA-256 tcId={} expected invalid but passed",
2458 test["tcId"]
2459 );
2460 invalid_tested += 1;
2461 }
2462 }
2463 }
2464 assert!(valid_tested > 0, "no valid ECDSA DER SHA-256 wycheproof tests were run");
2465 assert!(invalid_tested > 0, "no invalid ECDSA DER SHA-256 wycheproof tests were run");
2466 }
2467
2468 #[test]
2469 fn wycheproof_ecdh_p256_asn() {
2470 let data: serde_json::Value =
2471 serde_json::from_str(include_str!("../testdata/wycheproof/testvectors_v1/ecdh_secp256r1_test.json"))
2472 .unwrap();
2473 let mut valid_tested = 0u64;
2474 let mut invalid_tested = 0u64;
2475 let mut acceptable_tested = 0u64;
2476 for group in data["testGroups"].as_array().unwrap() {
2477 for test in group["tests"].as_array().unwrap() {
2478 let public_hex = test["public"].as_str().unwrap();
2479 let private_hex = test["private"].as_str().unwrap();
2480 let expected_shared_hex = test["shared"].as_str().unwrap();
2481 let result = test["result"].as_str().unwrap();
2482
2483 let spki_der = hex::decode(public_hex).unwrap();
2484 let Some(sec1_point) = spki_to_sec1_point(&spki_der) else {
2485 if result == "valid" {
2486 panic!("wycheproof ECDH ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
2487 }
2488 invalid_tested += 1;
2489 continue;
2490 };
2491
2492 let private_bytes = hex::decode(private_hex).unwrap();
2495 let mut private_key = [0u8; SECRET_KEY_SIZE];
2496 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
2497 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
2498 private_bytes.len() - SECRET_KEY_SIZE
2499 } else {
2500 0
2501 };
2502 private_key[SECRET_KEY_SIZE - effective_len..]
2503 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
2504
2505 let shared = ecdh(&private_key, &sec1_point);
2506
2507 if result == "valid" {
2508 let shared = shared.unwrap();
2509 let shared_hex = hex::encode(shared);
2510 assert_eq!(shared_hex, expected_shared_hex, "wycheproof ECDH ASN tcId={}", test["tcId"]);
2511 valid_tested += 1;
2512 } else if result == "invalid" {
2513 assert!(
2514 shared.is_err(),
2515 "wycheproof ECDH ASN tcId={} expected invalid but passed",
2516 test["tcId"]
2517 );
2518 invalid_tested += 1;
2519 } else {
2520 acceptable_tested += 1;
2521 }
2522 }
2523 }
2524 assert!(valid_tested > 0, "no valid ECDH ASN wycheproof tests were run");
2525 assert!(invalid_tested > 0, "no invalid ECDH ASN wycheproof tests were run");
2526 assert!(acceptable_tested > 0, "no acceptable ECDH ASN wycheproof tests were run");
2527 }
2528}