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