1use big_number::{Uint, mac};
2
3use crate::{EllipticCurveError, Hasher, hmac::Hmac, sha2::Sha384};
4
5pub const PRIVATE_KEY_SIZE: usize = 48;
7pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 49;
9pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 97;
11pub const SIGNATURE_SIZE: usize = 96;
13pub const ECDH_SHARED_SECRET_SIZE: usize = 48;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
47pub struct PrivateKey {
48 scalar: Scalar,
49 public_point: AffinePoint,
50}
51
52impl PrivateKey {
53 #[cfg(feature = "random")]
54 pub fn generate() -> Result<PrivateKey, EllipticCurveError> {
55 let key: [u8; PRIVATE_KEY_SIZE] = crate::random::random_bytes();
56 Self::from_bytes(&key)
57 }
58
59 pub fn from_bytes(key: &[u8; PRIVATE_KEY_SIZE]) -> Result<PrivateKey, EllipticCurveError> {
60 let scalar = Scalar::from_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
61 let public_point = scalar_mul_generator(&scalar)
62 .to_affine()
63 .ok_or(EllipticCurveError::Unspecified)?;
64 Ok(PrivateKey {
65 scalar,
66 public_point,
67 })
68 }
69
70 pub fn public_key(&self) -> PublicKey {
71 PublicKey {
72 point: self.public_point,
73 }
74 }
75
76 pub fn sign(&self, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
77 ecdsa_sign_inner(&self.scalar, message)
78 }
79
80 pub fn ecdh(&self, peer_public: &PublicKey) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
81 ecdh_inner(&self.scalar, &peer_public.point)
82 }
83
84 pub fn to_bytes(&self) -> [u8; PRIVATE_KEY_SIZE] {
85 self.scalar.to_bytes()
86 }
87}
88
89#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103pub struct PublicKey {
104 point: AffinePoint,
105}
106
107impl PublicKey {
108 pub fn from_bytes(key: &[u8]) -> Result<PublicKey, EllipticCurveError> {
109 let point = AffinePoint::from_sec1_bytes(key).ok_or(EllipticCurveError::InvalidKey)?;
110 Ok(PublicKey {
111 point,
112 })
113 }
114
115 #[inline]
122 pub fn from_x_y(x_bytes: &[u8; 48], y_bytes: &[u8; 48]) -> Result<PublicKey, EllipticCurveError> {
123 let x = FieldElement::from_bytes(x_bytes).ok_or(EllipticCurveError::InvalidKey)?;
124 let y = FieldElement::from_bytes(y_bytes).ok_or(EllipticCurveError::InvalidKey)?;
125 let point = AffinePoint::new(x, y).ok_or(EllipticCurveError::InvalidKey)?;
126 Ok(PublicKey {
127 point,
128 })
129 }
130
131 pub fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
132 ecdsa_verify_inner(&self.point, message, signature)
133 }
134
135 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
136 self.point.to_uncompressed_bytes()
137 }
138
139 #[inline]
141 pub fn x_y(&self) -> ([u8; 48], [u8; 48]) {
142 (self.point.x.to_bytes(), self.point.y.to_bytes())
143 }
144}
145
146type U384 = Uint<384, 6>;
147
148const MODULUS_P: U384 = U384::from_limbs([
149 0x00000000ffffffff,
150 0xffffffff00000000,
151 0xfffffffffffffffe,
152 0xffffffffffffffff,
153 0xffffffffffffffff,
154 0xffffffffffffffff,
155]);
156
157const MODULUS_N: U384 = U384::from_limbs([
158 0xecec196accc52973,
159 0x581a0db248b0a77a,
160 0xc7634d81f4372ddf,
161 0xffffffffffffffff,
162 0xffffffffffffffff,
163 0xffffffffffffffff,
164]);
165
166const P_MINUS_TWO: U384 = U384::from_limbs([
167 0x00000000fffffffd,
168 0xffffffff00000000,
169 0xfffffffffffffffe,
170 0xffffffffffffffff,
171 0xffffffffffffffff,
172 0xffffffffffffffff,
173]);
174
175const P_PLUS_ONE_OVER_FOUR: U384 = U384::from_limbs([
176 0x0000000040000000,
177 0xbfffffffc0000000,
178 0xffffffffffffffff,
179 0xffffffffffffffff,
180 0xffffffffffffffff,
181 0x3fffffffffffffff,
182]);
183
184const N_MINUS_TWO: U384 = U384::from_limbs([
185 0xecec196accc52971,
186 0x581a0db248b0a77a,
187 0xc7634d81f4372ddf,
188 0xffffffffffffffff,
189 0xffffffffffffffff,
190 0xffffffffffffffff,
191]);
192
193const CURVE_B: FieldElement = FieldElement(U384::from_limbs([
194 0x2a85c8edd3ec2aef,
195 0xc656398d8a2ed19d,
196 0x0314088f5013875a,
197 0x181d9c6efe814112,
198 0x988e056be3f82d19,
199 0xb3312fa7e23ee7e4,
200]));
201
202const GENERATOR_X: FieldElement = FieldElement(U384::from_limbs([
203 0x3a545e3872760ab7,
204 0x5502f25dbf55296c,
205 0x59f741e082542a38,
206 0x6e1d3b628ba79b98,
207 0x8eb1c71ef320ad74,
208 0xaa87ca22be8b0537,
209]));
210
211const GENERATOR_Y: FieldElement = FieldElement(U384::from_limbs([
212 0x7a431d7c90ea0e5f,
213 0x0a60b1ce1d7e819d,
214 0xe9da3113b5f0b8c0,
215 0xf8f41dbd289a147c,
216 0x5d9e98bf9292dc29,
217 0x3617de4a96262c6f,
218]));
219
220const S6: [u64; 6] = [
224 0xffffffff00000001,
225 0x00000000ffffffff,
226 0x0000000000000001,
227 0x0000000000000000,
228 0x0000000000000000,
229 0x0000000000000000,
230];
231
232const S7: [u64; 6] = [
233 0x0000000000000000,
234 0xffffffff00000001,
235 0x00000000ffffffff,
236 0x0000000000000001,
237 0x0000000000000000,
238 0x0000000000000000,
239];
240
241const S8: [u64; 6] = [
242 0x0000000000000000,
243 0x0000000000000000,
244 0xffffffff00000001,
245 0x00000000ffffffff,
246 0x0000000000000001,
247 0x0000000000000000,
248];
249
250const S9: [u64; 6] = [
251 0x0000000000000000,
252 0x0000000000000000,
253 0x0000000000000000,
254 0xffffffff00000001,
255 0x00000000ffffffff,
256 0x0000000000000001,
257];
258
259const S10: [u64; 6] = [
260 0xffffffff00000001,
261 0x00000000ffffffff,
262 0x0000000000000001,
263 0x0000000000000000,
264 0xffffffff00000001,
265 0x00000000ffffffff,
266];
267
268const S11: [u64; 6] = [
269 0x00000001ffffffff,
270 0xfffffffe00000000,
271 0x00000001ffffffff,
272 0x0000000000000001,
273 0x0000000000000000,
274 0xffffffff00000001,
275];
276
277#[inline]
278fn ct_select_u128(a: u128, b: u128, choice: bool) -> u128 {
279 let mask = (choice as u128).wrapping_neg();
280 (a & mask) | (b & !mask)
281}
282
283fn p384_fast_mul_mod(a: &U384, b: &U384) -> U384 {
286 let al = a.limbs;
287 let bl = b.limbs;
288
289 let mut prod = [0u64; 12];
290 for i in 0..6 {
291 let mut carry = 0u64;
292 for j in 0..6 {
293 let (v, cc) = mac(prod[i + j], al[i], bl[j], carry);
294 prod[i + j] = v;
295 carry = cc;
296 }
297 prod[i + 6] = carry;
298 }
299
300 const MASK: u128 = 0xffffffffffffffff;
301 let c0 = [
302 S6[0] as u128,
303 S6[1] as u128,
304 S6[2] as u128,
305 S6[3] as u128,
306 S6[4] as u128,
307 S6[5] as u128,
308 ];
309 let c1 = [
310 S7[0] as u128,
311 S7[1] as u128,
312 S7[2] as u128,
313 S7[3] as u128,
314 S7[4] as u128,
315 S7[5] as u128,
316 ];
317 let c2 = [
318 S8[0] as u128,
319 S8[1] as u128,
320 S8[2] as u128,
321 S8[3] as u128,
322 S8[4] as u128,
323 S8[5] as u128,
324 ];
325 let c3 = [
326 S9[0] as u128,
327 S9[1] as u128,
328 S9[2] as u128,
329 S9[3] as u128,
330 S9[4] as u128,
331 S9[5] as u128,
332 ];
333 let c4 = [
334 S10[0] as u128,
335 S10[1] as u128,
336 S10[2] as u128,
337 S10[3] as u128,
338 S10[4] as u128,
339 S10[5] as u128,
340 ];
341 let c5 = [
342 S11[0] as u128,
343 S11[1] as u128,
344 S11[2] as u128,
345 S11[3] as u128,
346 S11[4] as u128,
347 S11[5] as u128,
348 ];
349 let coeffs: [&[u128; 6]; 6] = [&c0, &c1, &c2, &c3, &c4, &c5];
350
351 let mut r0 = prod[0] as u128;
352 let mut r1 = prod[1] as u128;
353 let mut r2 = prod[2] as u128;
354 let mut r3 = prod[3] as u128;
355 let mut r4 = prod[4] as u128;
356 let mut r5 = prod[5] as u128;
357
358 for i in 0..6 {
359 let w = prod[6 + i] as u128;
360 let c = coeffs[i];
361
362 r0 = r0.wrapping_add(w.wrapping_mul(c[0]));
363 r1 = r1.wrapping_add(w.wrapping_mul(c[1]));
364 r2 = r2.wrapping_add(w.wrapping_mul(c[2]));
365 r3 = r3.wrapping_add(w.wrapping_mul(c[3]));
366 r4 = r4.wrapping_add(w.wrapping_mul(c[4]));
367 r5 = r5.wrapping_add(w.wrapping_mul(c[5]));
368
369 for _ in 0..4 {
371 let carry = r0 >> 64;
372 r1 = r1.wrapping_add(carry);
373 r0 &= MASK;
374 let carry = r1 >> 64;
375 r2 = r2.wrapping_add(carry);
376 r1 &= MASK;
377 let carry = r2 >> 64;
378 r3 = r3.wrapping_add(carry);
379 r2 &= MASK;
380 let carry = r3 >> 64;
381 r4 = r4.wrapping_add(carry);
382 r3 &= MASK;
383 let carry = r4 >> 64;
384 r5 = r5.wrapping_add(carry);
385 r4 &= MASK;
386
387 let residual = r5 >> 64;
388 let need_reduce = residual != 0;
389
390 let rr5 = r5 & MASK;
391 let rr0 = r0.wrapping_add(residual.wrapping_mul(c0[0]));
392 let rr1 = r1.wrapping_add(residual.wrapping_mul(c0[1]));
393 let rr2 = r2.wrapping_add(residual.wrapping_mul(c0[2]));
394 let rr3 = r3.wrapping_add(residual.wrapping_mul(c0[3]));
395 let rr4 = r4.wrapping_add(residual.wrapping_mul(c0[4]));
396 let rr5r = rr5.wrapping_add(residual.wrapping_mul(c0[5]));
397
398 r0 = ct_select_u128(rr0, r0, need_reduce);
399 r1 = ct_select_u128(rr1, r1, need_reduce);
400 r2 = ct_select_u128(rr2, r2, need_reduce);
401 r3 = ct_select_u128(rr3, r3, need_reduce);
402 r4 = ct_select_u128(rr4, r4, need_reduce);
403 r5 = ct_select_u128(rr5r, r5, need_reduce);
404 }
405 }
406
407 let mut result = U384::from_limbs([r0 as u64, r1 as u64, r2 as u64, r3 as u64, r4 as u64, r5 as u64]);
409 for _ in 0..8 {
410 let (sub, borrow) = result.sub_raw(&MODULUS_P);
411 result = U384::ct_select(&sub, &result, borrow == 0);
412 }
413 result
414}
415
416#[derive(Clone, Copy, Debug, PartialEq, Eq)]
417struct FieldElement(U384);
418
419impl FieldElement {
420 const ZERO: Self = Self(U384::ZERO);
421 const ONE: Self = Self(U384::ONE);
422
423 #[inline]
424 fn from_bytes(bytes: &[u8; 48]) -> Option<Self> {
425 let value = U384::from_be_slice(bytes);
426 if value.ct_ge(&MODULUS_P) {
427 None
428 } else {
429 Some(Self(value))
430 }
431 }
432
433 #[inline]
434 fn to_bytes(self) -> [u8; 48] {
435 self.0.to_be_bytes_fixed::<48>()
436 }
437
438 #[inline]
439 fn is_zero(&self) -> bool {
440 self.0.is_zero()
441 }
442
443 #[inline]
444 fn is_odd(&self) -> bool {
445 self.0.is_odd()
446 }
447
448 #[inline]
449 fn add(self, rhs: Self) -> Self {
450 Self(self.0.add_mod(&rhs.0, &MODULUS_P))
451 }
452
453 #[inline]
454 fn sub(self, rhs: Self) -> Self {
455 Self(self.0.sub_mod(&rhs.0, &MODULUS_P))
456 }
457
458 #[inline]
459 fn double(self) -> Self {
460 Self(self.0.double_mod(&MODULUS_P))
461 }
462
463 #[inline]
464 fn square(self) -> Self {
465 self.mul(self)
466 }
467
468 #[inline]
469 fn mul(self, rhs: Self) -> Self {
470 Self(p384_fast_mul_mod(&self.0, &rhs.0))
471 }
472
473 #[inline]
474 fn triple(self) -> Self {
475 self.double().add(self)
476 }
477
478 #[inline]
479 fn negate(self) -> Self {
480 let (diff, _) = MODULUS_P.sub_raw(&self.0);
481 Self(U384::ct_select(&U384::ZERO, &diff, self.is_zero()))
482 }
483
484 #[inline]
485 fn pow(self, exponent: &U384) -> Self {
486 let mut result = Self::ONE;
487 let mut i = 384usize;
488 while i > 0 {
489 i -= 1;
490 result = result.square();
491 let product = result.mul(self);
492 result = Self::select(&product, &result, exponent.bit(i));
493 }
494 result
495 }
496
497 #[inline]
498 fn invert(self) -> Option<Self> {
499 Some(self.pow(&P_MINUS_TWO))
500 }
501
502 #[inline]
503 fn sqrt(self) -> Option<Self> {
504 let candidate = self.pow(&P_PLUS_ONE_OVER_FOUR);
505 if U384::ct_eq(&self.0, &candidate.square().0) {
506 Some(candidate)
507 } else {
508 None
509 }
510 }
511
512 #[inline]
513 fn select(a: &Self, b: &Self, choice: bool) -> Self {
514 Self(U384::ct_select(&a.0, &b.0, choice))
515 }
516}
517
518#[derive(Clone, Copy, Debug, PartialEq, Eq)]
519struct Scalar(U384);
520
521impl Scalar {
522 const ZERO: Self = Self(U384::ZERO);
523 const ONE: Self = Self(U384::ONE);
524
525 #[inline]
526 fn from_bytes(bytes: &[u8; 48]) -> Option<Self> {
527 let value = U384::from_be_slice(bytes);
528 if value.is_zero() || value.ct_ge(&MODULUS_N) {
529 None
530 } else {
531 Some(Self(value))
532 }
533 }
534
535 #[inline]
536 fn from_hash(hash: &[u8; 48]) -> Self {
537 let value = U384::from_be_slice(hash);
538 let (sub_value, _) = value.sub_raw(&MODULUS_N);
539 let reduced = U384::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N));
540 Self(reduced)
541 }
542
543 #[inline]
544 fn to_bytes(self) -> [u8; 48] {
545 self.0.to_be_bytes_fixed::<48>()
546 }
547
548 #[inline]
549 fn is_zero(&self) -> bool {
550 self.0.is_zero()
551 }
552
553 #[inline]
554 fn bit(&self, index: usize) -> bool {
555 self.0.bit(index)
556 }
557
558 #[inline]
559 fn add(self, rhs: Self) -> Self {
560 Self(self.0.add_mod(&rhs.0, &MODULUS_N))
561 }
562
563 #[cfg(test)]
564 #[inline]
565 fn sub(self, rhs: Self) -> Self {
566 Self(self.0.sub_mod(&rhs.0, &MODULUS_N))
567 }
568
569 #[inline]
570 fn mul(self, rhs: Self) -> Self {
571 Self(self.0.mul_mod(&rhs.0, &MODULUS_N))
572 }
573
574 #[inline]
575 fn invert(self) -> Option<Self> {
576 Some(Self(self.scalar_pow(&N_MINUS_TWO)))
577 }
578
579 #[inline]
580 fn scalar_pow(self, exponent: &U384) -> U384 {
581 let mut result = Scalar::ONE;
582 let mut i = 384usize;
583 while i > 0 {
584 i -= 1;
585 result = result.mul(result);
586 let product = result.mul(self);
587 result = Scalar::select(&product, &result, exponent.bit(i));
588 }
589 result.0
590 }
591
592 #[inline]
593 fn select(a: &Self, b: &Self, choice: bool) -> Self {
594 Self(U384::ct_select(&a.0, &b.0, choice))
595 }
596}
597
598#[derive(Clone, Copy, Debug, PartialEq, Eq)]
599struct AffinePoint {
600 x: FieldElement,
601 y: FieldElement,
602 infinity: bool,
603}
604
605impl AffinePoint {
606 const GENERATOR: Self = Self {
607 x: GENERATOR_X,
608 y: GENERATOR_Y,
609 infinity: false,
610 };
611
612 #[inline]
613 fn new(x: FieldElement, y: FieldElement) -> Option<Self> {
614 let point = Self {
615 x,
616 y,
617 infinity: false,
618 };
619 if point.is_on_curve() { Some(point) } else { None }
620 }
621
622 #[inline]
623 fn is_on_curve(&self) -> bool {
624 if self.infinity {
625 return false;
626 }
627 let x2 = self.x.square();
628 let x3 = x2.mul(self.x);
629 let rhs = x3.sub(self.x.triple()).add(CURVE_B);
630 self.y.square() == rhs
631 }
632
633 #[inline]
634 fn to_uncompressed_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
635 let mut out = [0u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
636 out[0] = 0x04;
637 out[1..49].copy_from_slice(&self.x.to_bytes());
638 out[49..97].copy_from_slice(&self.y.to_bytes());
639 out
640 }
641
642 #[cfg(test)]
643 #[inline]
644 fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
645 let mut out = [0u8; PUBLIC_KEY_COMPRESSED_SIZE];
646 out[0] = if self.y.is_odd() { 0x03 } else { 0x02 };
647 out[1..49].copy_from_slice(&self.x.to_bytes());
648 out
649 }
650
651 fn from_sec1_bytes(bytes: &[u8]) -> Option<Self> {
652 match bytes.len() {
653 PUBLIC_KEY_UNCOMPRESSED_SIZE if bytes[0] == 0x04 => {
654 let x = FieldElement::from_bytes(bytes[1..49].try_into().unwrap())?;
655 let y = FieldElement::from_bytes(bytes[49..97].try_into().unwrap())?;
656 Self::new(x, y)
657 }
658 PUBLIC_KEY_COMPRESSED_SIZE if bytes[0] == 0x02 || bytes[0] == 0x03 => {
659 let x = FieldElement::from_bytes(bytes[1..49].try_into().unwrap())?;
660 let rhs = x.square().mul(x).sub(x.triple()).add(CURVE_B);
661 let y = rhs.sqrt()?;
662 let y_is_odd = y.is_odd();
663 let select_neg = y_is_odd != (bytes[0] == 0x03);
664 let y = FieldElement::select(&y.negate(), &y, select_neg);
665 Self::new(x, y)
666 }
667 _ => None,
668 }
669 }
670}
671
672#[derive(Clone, Copy, Debug, PartialEq, Eq)]
673struct ProjectivePoint {
674 x: FieldElement,
675 y: FieldElement,
676 z: FieldElement,
677}
678
679impl ProjectivePoint {
680 const IDENTITY: Self = Self {
681 x: FieldElement::ZERO,
682 y: FieldElement::ONE,
683 z: FieldElement::ZERO,
684 };
685
686 #[cfg(test)]
687 #[inline]
688 fn from_affine(point: &AffinePoint) -> Self {
689 if point.infinity {
690 Self::IDENTITY
691 } else {
692 Self {
693 x: point.x,
694 y: point.y,
695 z: FieldElement::ONE,
696 }
697 }
698 }
699
700 #[inline]
701 fn is_identity(&self) -> bool {
702 self.z.is_zero()
703 }
704
705 #[inline]
706 fn select(a: &Self, b: &Self, choice: bool) -> Self {
707 Self {
708 x: FieldElement::select(&a.x, &b.x, choice),
709 y: FieldElement::select(&a.y, &b.y, choice),
710 z: FieldElement::select(&a.z, &b.z, choice),
711 }
712 }
713
714 #[inline]
715 fn to_affine(&self) -> Option<AffinePoint> {
716 if self.is_identity() {
717 return None;
718 }
719 let z_inv = self.z.invert()?;
720 AffinePoint::new(self.x.mul(z_inv), self.y.mul(z_inv))
721 }
722
723 fn add(&self, rhs: &Self) -> Self {
724 let xx = self.x.mul(rhs.x);
725 let yy = self.y.mul(rhs.y);
726 let zz = self.z.mul(rhs.z);
727 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
728 let yz_pairs = self.y.add(self.z).mul(rhs.y.add(rhs.z)).sub(yy.add(zz));
729 let xz_pairs = self.x.add(self.z).mul(rhs.x.add(rhs.z)).sub(xx.add(zz));
730
731 let bzz_part = xz_pairs.sub(CURVE_B.mul(zz));
732 let bzz3_part = bzz_part.triple();
733 let yy_m_bzz3 = yy.sub(bzz3_part);
734 let yy_p_bzz3 = yy.add(bzz3_part);
735
736 let zz3 = zz.triple();
737 let bxz_part = CURVE_B.mul(xz_pairs).sub(zz3.add(xx));
738 let bxz3_part = bxz_part.triple();
739 let xx3_m_zz3 = xx.triple().sub(zz3);
740
741 Self {
742 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
743 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
744 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
745 }
746 }
747
748 fn add_mixed(&self, rhs: &AffinePoint) -> Self {
749 if rhs.infinity {
750 return *self;
751 }
752
753 let xx = self.x.mul(rhs.x);
754 let yy = self.y.mul(rhs.y);
755 let xy_pairs = self.x.add(self.y).mul(rhs.x.add(rhs.y)).sub(xx.add(yy));
756 let yz_pairs = rhs.y.mul(self.z).add(self.y);
757 let xz_pairs = rhs.x.mul(self.z).add(self.x);
758
759 let bz_part = xz_pairs.sub(CURVE_B.mul(self.z));
760 let bz3_part = bz_part.triple();
761 let yy_m_bzz3 = yy.sub(bz3_part);
762 let yy_p_bzz3 = yy.add(bz3_part);
763
764 let z3 = self.z.triple();
765 let bxz_part = CURVE_B.mul(xz_pairs).sub(z3.add(xx));
766 let bxz3_part = bxz_part.triple();
767 let xx3_m_zz3 = xx.triple().sub(z3);
768
769 Self {
770 x: yy_p_bzz3.mul(xy_pairs).sub(yz_pairs.mul(bxz3_part)),
771 y: yy_p_bzz3.mul(yy_m_bzz3).add(xx3_m_zz3.mul(bxz3_part)),
772 z: yy_m_bzz3.mul(yz_pairs).add(xy_pairs.mul(xx3_m_zz3)),
773 }
774 }
775
776 fn double(&self) -> Self {
777 let xx = self.x.square();
778 let yy = self.y.square();
779 let zz = self.z.square();
780 let xy2 = self.x.mul(self.y).double();
781 let xz2 = self.x.mul(self.z).double();
782
783 let bzz_part = CURVE_B.mul(zz).sub(xz2);
784 let bzz3_part = bzz_part.triple();
785 let yy_m_bzz3 = yy.sub(bzz3_part);
786 let yy_p_bzz3 = yy.add(bzz3_part);
787 let y_frag = yy_p_bzz3.mul(yy_m_bzz3);
788 let x_frag = yy_m_bzz3.mul(xy2);
789
790 let zz3 = zz.triple();
791 let bxz2_part = CURVE_B.mul(xz2).sub(zz3.add(xx));
792 let bxz6_part = bxz2_part.triple();
793 let xx3_m_zz3 = xx.triple().sub(zz3);
794
795 let y = y_frag.add(xx3_m_zz3.mul(bxz6_part));
796 let yz2 = self.y.mul(self.z).double();
797 let x = x_frag.sub(bxz6_part.mul(yz2));
798 let z = yz2.mul(yy).double().double();
799
800 Self {
801 x,
802 y,
803 z,
804 }
805 }
806}
807
808fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
809 scalar_mul_affine(&AffinePoint::GENERATOR, scalar)
810}
811
812fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
813 let mut acc = ProjectivePoint::IDENTITY;
814 let mut bit = 384usize;
815 while bit > 0 {
816 bit -= 1;
817 acc = acc.double();
818 let candidate = acc.add_mixed(base);
819 acc = ProjectivePoint::select(&candidate, &acc, scalar.bit(bit));
820 }
821 acc
822}
823
824#[inline]
825fn hash_message(message: &[u8]) -> [u8; 48] {
826 let digest = Sha384::hash(message);
827 digest.as_ref().try_into().unwrap()
828}
829
830#[inline]
831fn hmac_sha384(key: &[u8], data: &[u8]) -> [u8; 48] {
832 let mac = Hmac::<Sha384>::mac(key, data);
833 mac.as_ref().try_into().unwrap()
834}
835
836fn bits2octets(hash: &[u8; 48]) -> [u8; 48] {
837 Scalar::from_hash(hash).to_bytes()
838}
839
840fn rfc6979_init_state(private_key: &Scalar, message_hash: &[u8; 48]) -> ([u8; 48], [u8; 48]) {
841 let x = private_key.to_bytes();
842 let h1 = bits2octets(message_hash);
843
844 let mut v = [0x01u8; 48];
845 let mut k = [0u8; 48];
846
847 let mut buf = [0u8; 145];
848 buf[..48].copy_from_slice(&v);
849 buf[48] = 0x00;
850 buf[49..97].copy_from_slice(&x);
851 buf[97..145].copy_from_slice(&h1);
852 k = hmac_sha384(&k, &buf);
853 v = hmac_sha384(&k, &v);
854
855 buf[..48].copy_from_slice(&v);
856 buf[48] = 0x01;
857 k = hmac_sha384(&k, &buf);
858 v = hmac_sha384(&k, &v);
859
860 (k, v)
861}
862
863fn rfc6979_retry(k: &mut [u8; 48], v: &mut [u8; 48]) {
864 let mut retry_buf = [0u8; 49];
865 retry_buf[..48].copy_from_slice(v);
866 retry_buf[48] = 0x00;
867 *k = hmac_sha384(k, &retry_buf);
868 *v = hmac_sha384(k, v);
869}
870
871fn rfc6979_retry_clone(k: &[u8; 48], v: &[u8; 48]) -> ([u8; 48], [u8; 48]) {
872 let mut retry_buf = [0u8; 49];
873 retry_buf[..48].copy_from_slice(v);
874 retry_buf[48] = 0x00;
875 let k_new = hmac_sha384(k, &retry_buf);
876 let v_new = hmac_sha384(&k_new, v);
877 (k_new, v_new)
878}
879
880fn ct_select_bytes<const N: usize>(a: &[u8; N], b: &[u8; N], choice: bool) -> [u8; N] {
881 let mask = (choice as u8).wrapping_neg();
882 let mut out = [0u8; N];
883 for i in 0..N {
884 out[i] = (a[i] & mask) | (b[i] & !mask);
885 }
886 out
887}
888
889fn rfc6979_generate_k(private_key: &Scalar, message_hash: &[u8; 48]) -> Scalar {
890 let (mut k, mut v) = rfc6979_init_state(private_key, message_hash);
891
892 let mut candidate = [0u8; 48];
893 let mut found = false;
894
895 for _ in 0..3 {
896 v = hmac_sha384(&k, &v);
897 let val = U384::from_be_slice(&v);
898 let is_valid = !val.is_zero() && !val.ct_ge(&MODULUS_N);
899
900 let take = is_valid && !found;
901 candidate = ct_select_bytes(&v, &candidate, take);
902 found = found || is_valid;
903
904 let (k_retry, v_retry) = rfc6979_retry_clone(&k, &v);
905 k = ct_select_bytes(&k, &k_retry, !is_valid);
906 v = ct_select_bytes(&v, &v_retry, !is_valid);
907 }
908
909 if found {
910 return Scalar::from_bytes(&candidate).unwrap_or(Scalar::ZERO);
911 }
912
913 v = hmac_sha384(&k, &v);
914 if let Some(sc) = Scalar::from_bytes(&v) {
915 return sc;
916 }
917
918 loop {
919 v = hmac_sha384(&k, &v);
920 if let Some(sc) = Scalar::from_bytes(&v) {
921 return sc;
922 }
923 rfc6979_retry(&mut k, &mut v);
924 }
925}
926
927fn parse_private_key(private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Scalar, EllipticCurveError> {
928 Scalar::from_bytes(private_key).ok_or(EllipticCurveError::InvalidKey)
929}
930
931fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, EllipticCurveError> {
932 AffinePoint::from_sec1_bytes(public_key).ok_or(EllipticCurveError::InvalidKey)
933}
934
935#[cfg(test)]
936fn derive_public_key_uncompressed(
937 private_key: &[u8; PRIVATE_KEY_SIZE],
938) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], EllipticCurveError> {
939 let scalar = parse_private_key(private_key)?;
940 let point = scalar_mul_generator(&scalar)
941 .to_affine()
942 .ok_or(EllipticCurveError::Unspecified)?;
943 Ok(point.to_uncompressed_bytes())
944}
945
946#[cfg(test)]
947fn derive_public_key_compressed(
948 private_key: &[u8; PRIVATE_KEY_SIZE],
949) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], EllipticCurveError> {
950 let scalar = parse_private_key(private_key)?;
951 let point = scalar_mul_generator(&scalar)
952 .to_affine()
953 .ok_or(EllipticCurveError::Unspecified)?;
954 Ok(point.to_compressed_bytes())
955}
956
957fn ecdh_inner(scalar: &Scalar, peer_point: &AffinePoint) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
958 let shared_point = scalar_mul_affine(peer_point, scalar)
959 .to_affine()
960 .ok_or(EllipticCurveError::Unspecified)?;
961 Ok(shared_point.x.to_bytes())
962}
963
964pub fn ecdh(
965 private_key: &[u8; PRIVATE_KEY_SIZE],
966 peer_public_key: &[u8],
967) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
968 let scalar = parse_private_key(private_key)?;
969 let peer_point = parse_public_key(peer_public_key)?;
970 ecdh_inner(&scalar, &peer_point)
971}
972
973fn ecdsa_sign_inner(scalar: &Scalar, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
974 let message_hash = hash_message(message);
975 let z = Scalar::from_hash(&message_hash);
976
977 for _ in 0..2 {
978 let k = rfc6979_generate_k(scalar, &message_hash);
979
980 let r_point = scalar_mul_generator(&k)
981 .to_affine()
982 .ok_or(EllipticCurveError::Unspecified)?;
983 let r = Scalar::from_hash(&r_point.x.to_bytes());
984 if r.is_zero() {
985 continue;
986 }
987
988 let kinv = k.invert().ok_or(EllipticCurveError::Unspecified)?;
989 let s = kinv.mul(z.add(r.mul(*scalar)));
990 if s.is_zero() {
991 continue;
992 }
993
994 let mut out = [0u8; SIGNATURE_SIZE];
995 out[..48].copy_from_slice(&r.to_bytes());
996 out[48..].copy_from_slice(&s.to_bytes());
997 return Ok(out);
998 }
999
1000 Err(EllipticCurveError::Unspecified)
1001}
1002
1003fn ecdsa_verify_inner(
1004 public_point: &AffinePoint,
1005 message: &[u8],
1006 signature: &[u8; SIGNATURE_SIZE],
1007) -> Result<(), EllipticCurveError> {
1008 let r = Scalar::from_bytes(signature[..48].try_into().unwrap()).ok_or(EllipticCurveError::Unspecified)?;
1009 let s = Scalar::from_bytes(signature[48..].try_into().unwrap()).ok_or(EllipticCurveError::Unspecified)?;
1010 let z = Scalar::from_hash(&hash_message(message));
1011
1012 let w = s.invert().ok_or(EllipticCurveError::Unspecified)?;
1013 let u1 = z.mul(w);
1014 let u2 = r.mul(w);
1015
1016 let point = scalar_mul_generator(&u1).add(&scalar_mul_affine(public_point, &u2));
1017 let affine = point.to_affine().ok_or(EllipticCurveError::Unspecified)?;
1018 let x_mod_n = Scalar::from_hash(&affine.x.to_bytes());
1019
1020 if x_mod_n == r {
1021 Ok(())
1022 } else {
1023 Err(EllipticCurveError::Unspecified)
1024 }
1025}
1026
1027pub fn is_valid_public_key(public_key: &[u8]) -> bool {
1028 AffinePoint::from_sec1_bytes(public_key).is_some()
1029}
1030
1031#[cfg(test)]
1032mod tests {
1033 use super::*;
1034
1035 fn decode_hex<const N: usize>(hex_bytes: &str) -> [u8; N] {
1036 let bytes = hex::decode(hex_bytes).unwrap();
1037 assert_eq!(bytes.len(), N);
1038 let mut out = [0u8; N];
1039 out.copy_from_slice(&bytes);
1040 out
1041 }
1042
1043 fn der_read_tlv<'a>(data: &'a [u8], offset: &mut usize) -> Option<(u8, &'a [u8])> {
1044 if *offset >= data.len() {
1045 return None;
1046 }
1047 let tag = data[*offset];
1048 *offset += 1;
1049 if *offset >= data.len() {
1050 return None;
1051 }
1052 let len_byte = data[*offset];
1053 *offset += 1;
1054 let (len, _) = if len_byte & 0x80 != 0 {
1055 let num_bytes = (len_byte & 0x7f) as usize;
1056 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
1057 return None;
1058 }
1059 if num_bytes > 1 && data[*offset] == 0 {
1060 return None;
1061 }
1062 let mut l = 0usize;
1063 for i in 0..num_bytes {
1064 l = (l << 8) | data[*offset + i] as usize;
1065 }
1066 if l < 128 {
1067 return None;
1068 }
1069 *offset += num_bytes;
1070 (l, num_bytes + 1)
1071 } else {
1072 (len_byte as usize, 1)
1073 };
1074 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
1075 return None;
1076 }
1077 let value = &data[*offset..*offset + len];
1078 *offset = (*offset).checked_add(len)?;
1079 Some((tag, value))
1080 }
1081
1082 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; 96]> {
1083 let mut offset = 0;
1084 let (tag, inner) = der_read_tlv(der, &mut offset)?;
1085 if tag != 0x30 {
1086 return None;
1087 }
1088 if offset != der.len() {
1089 return None;
1090 }
1091 let mut inner_offset = 0;
1092 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
1093 if rtag != 0x02 || rval.is_empty() || rval.len() > 49 {
1094 return None;
1095 }
1096 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
1097 if stag != 0x02 || sval.is_empty() || sval.len() > 49 {
1098 return None;
1099 }
1100 if inner_offset != inner.len() {
1101 return None;
1102 }
1103 let r_valid = if rval.len() == 48 && rval[0] >= 0x80 {
1104 false
1105 } else if rval.len() == 49 && rval[0] != 0 {
1106 false
1107 } else if rval.len() == 49 && rval[0] == 0 && rval[1] < 0x80 {
1108 false
1109 } else if rval.len() > 49 {
1110 false
1111 } else {
1112 true
1113 };
1114 let s_valid = if sval.len() == 48 && sval[0] >= 0x80 {
1115 false
1116 } else if sval.len() == 49 && sval[0] != 0 {
1117 false
1118 } else if sval.len() == 49 && sval[0] == 0 && sval[1] < 0x80 {
1119 false
1120 } else if sval.len() > 49 {
1121 false
1122 } else {
1123 true
1124 };
1125 if !r_valid || !s_valid {
1126 return None;
1127 }
1128
1129 let r_trimmed = if rval.len() == 49 && rval[0] == 0 {
1130 &rval[1..]
1131 } else {
1132 rval
1133 };
1134 let s_trimmed = if sval.len() == 49 && sval[0] == 0 {
1135 &sval[1..]
1136 } else {
1137 sval
1138 };
1139 if r_trimmed.len() > 48 || s_trimmed.len() > 48 {
1140 return None;
1141 }
1142 let mut sig = [0u8; 96];
1143 sig[48 - r_trimmed.len()..48].copy_from_slice(r_trimmed);
1144 sig[96 - s_trimmed.len()..96].copy_from_slice(s_trimmed);
1145 Some(sig)
1146 }
1147
1148 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
1149 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
1150 let secp384r1_oid: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x22];
1151 let mut offset = 0;
1152 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
1153 let mut inner = 0;
1154 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
1155 if _alg_tag != 0x30 {
1156 return None;
1157 }
1158 let mut ai = 0;
1159 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
1160 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
1161 return None;
1162 }
1163 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
1164 if oid2_tag != 0x06 || oid2 != secp384r1_oid {
1165 return None;
1166 }
1167 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
1168 if _bs_tag != 0x03 || bs_val.is_empty() {
1169 return None;
1170 }
1171 Some(bs_val[1..].to_vec())
1172 }
1173
1174 #[test]
1175 fn derive_public_key_generator_matches_sec1_base_point() {
1176 let mut private_key = [0u8; 48];
1177 private_key[47] = 1;
1178 let derived = derive_public_key_uncompressed(&private_key).unwrap();
1179 let expected = decode_hex::<97>(
1180 "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1181 5502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29\
1182 f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
1183 );
1184 assert_eq!(derived, expected);
1185 }
1186
1187 #[test]
1188 fn ecdsa_verify_accepts_compressed_and_uncompressed_public_keys() {
1189 let private_key = decode_hex::<48>(
1190 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1191 96d5724e4c70a825f872c9ea60d2edf5",
1192 );
1193 let key = PrivateKey::from_bytes(&private_key).unwrap();
1194 let uncompressed = key.public_key();
1195 let compressed = derive_public_key_compressed(&private_key).unwrap();
1196 let signature = key.sign(b"sample").unwrap();
1197
1198 assert!(uncompressed.verify(b"sample", &signature).is_ok());
1199 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1200 assert!(ecdsa_verify_inner(&point, b"sample", &signature).is_ok());
1201 }
1202
1203 #[test]
1204 fn invalid_inputs_are_rejected() {
1205 let invalid_private_key = [0u8; PRIVATE_KEY_SIZE];
1206 assert!(PrivateKey::from_bytes(&invalid_private_key).is_err());
1207 assert!(derive_public_key_uncompressed(&invalid_private_key).is_err());
1208 assert!(derive_public_key_compressed(&invalid_private_key).is_err());
1209
1210 let private_key = decode_hex::<48>(
1211 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1212 96d5724e4c70a825f872c9ea60d2edf5",
1213 );
1214 let key = PrivateKey::from_bytes(&private_key).unwrap();
1215 let signature = key.sign(b"msg").unwrap();
1216 let mut zero_r = signature;
1217 zero_r[..48].fill(0);
1218 assert!(key.public_key().verify(b"msg", &zero_r).is_err());
1219 }
1220
1221 #[test]
1222 fn public_key_validation_accepts_known_good_points() {
1223 assert!(is_valid_public_key(&decode_hex::<97>(
1224 "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1225 5502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29\
1226 f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
1227 )));
1228 }
1229
1230 #[test]
1231 fn ecdsa_sign_verify_round_trip_multiple_messages() {
1232 let private_key = decode_hex::<48>(
1233 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1234 96d5724e4c70a825f872c9ea60d2edf5",
1235 );
1236 let key = PrivateKey::from_bytes(&private_key).unwrap();
1237 let pub_key = key.public_key();
1238
1239 let messages: &[&[u8]] = &[
1240 b"",
1241 b"hello world",
1242 b"The quick brown fox jumps over the lazy dog",
1243 &[0u8; 0],
1244 &[0xffu8; 100],
1245 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1246 ];
1247
1248 for msg in messages {
1249 let sig = key.sign(msg).unwrap();
1250 assert!(pub_key.verify(msg, &sig).is_ok(), "round-trip failed for message {:?}", msg);
1251 let mut wrong_msg = msg.to_vec();
1252 wrong_msg.push(0x42);
1253 assert!(pub_key.verify(&wrong_msg, &sig).is_err());
1254 }
1255 }
1256
1257 #[test]
1258 fn ecdsa_sign_verify_different_keys() {
1259 let keys: &[&str] = &[
1260 "0000000000000000000000000000000000000000000000000000000000000000\
1261 00000000000000000000000000000001",
1262 "0000000000000000000000000000000000000000000000000000000000000000\
1263 00000000000000000000000000000002",
1264 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011\
1265 2233445566778899aabbccddeeff0011",
1266 ];
1267
1268 for key_hex in keys {
1269 let private_key = decode_hex::<48>(key_hex);
1270 let key = PrivateKey::from_bytes(&private_key).unwrap();
1271 let sig = key.sign(b"test message").unwrap();
1272 assert!(
1273 key.public_key().verify(b"test message", &sig).is_ok(),
1274 "sign/verify failed for key {}",
1275 key_hex
1276 );
1277 }
1278 }
1279
1280 #[test]
1281 fn ecdsa_verify_wrong_public_key_rejects() {
1282 let private_key1 = decode_hex::<48>(
1283 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1284 96d5724e4c70a825f872c9ea60d2edf5",
1285 );
1286 let private_key2 = decode_hex::<48>(
1287 "0000000000000000000000000000000000000000000000000000000000000000\
1288 00000000000000000000000000000001",
1289 );
1290 let key1 = PrivateKey::from_bytes(&private_key1).unwrap();
1291 let key2 = PrivateKey::from_bytes(&private_key2).unwrap();
1292
1293 let sig = key1.sign(b"message").unwrap();
1294 assert!(key2.public_key().verify(b"message", &sig).is_err());
1295 }
1296
1297 #[test]
1298 fn scalar_from_bytes_rejects_boundary_values() {
1299 let zero = [0u8; 48];
1300 assert!(Scalar::from_bytes(&zero).is_none());
1301
1302 let n_bytes = decode_hex::<48>(
1303 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1304 581a0db248b0a77aecec196accc52973",
1305 );
1306 assert!(Scalar::from_bytes(&n_bytes).is_none());
1307
1308 let n_minus_1 = decode_hex::<48>(
1309 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1310 581a0db248b0a77aecec196accc52972",
1311 );
1312 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1313
1314 let one = decode_hex::<48>(
1315 "0000000000000000000000000000000000000000000000000000000000000000\
1316 00000000000000000000000000000001",
1317 );
1318 assert!(Scalar::from_bytes(&one).is_some());
1319 }
1320
1321 #[test]
1322 fn field_element_from_bytes_rejects_boundary_values() {
1323 let p_bytes = decode_hex::<48>(
1324 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
1325 );
1326 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1327
1328 let p_minus_1 = decode_hex::<48>(
1329 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffe",
1330 );
1331 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1332
1333 let zero = [0u8; 48];
1334 assert!(FieldElement::from_bytes(&zero).is_some());
1335 }
1336
1337 #[test]
1338 fn point_decompression_round_trip() {
1339 let keys: &[&str] = &[
1340 "0000000000000000000000000000000000000000000000000000000000000000\
1341 00000000000000000000000000000001",
1342 "0000000000000000000000000000000000000000000000000000000000000000\
1343 00000000000000000000000000000002",
1344 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1345 96d5724e4c70a825f872c9ea60d2edf5",
1346 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011\
1347 2233445566778899aabbccddeeff0011",
1348 ];
1349
1350 for key_hex in keys {
1351 let private_key = decode_hex::<48>(key_hex);
1352 let key = PrivateKey::from_bytes(&private_key).unwrap();
1353 let uncompressed = key.public_key();
1354 let compressed = derive_public_key_compressed(&private_key).unwrap();
1355
1356 let sig = key.sign(b"round-trip").unwrap();
1357 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
1358 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1359 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
1360
1361 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1362 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
1363 }
1364 }
1365
1366 #[test]
1367 fn scalar_inversion_correctness() {
1368 let k = Scalar::from_bytes(&decode_hex::<48>(
1369 "c22b201cc45cd130ef80acfc70e84fa17b91b0ffbfe4c9c44eda37e1ad1d7f8f\
1370 ae4c4c8b52559930e08ba1c822c105b0",
1371 ))
1372 .unwrap();
1373 let k_inv = k.invert().unwrap();
1374 let product = k.mul(k_inv);
1375 assert_eq!(product, Scalar::ONE);
1376 }
1377
1378 #[test]
1379 fn field_element_inversion_correctness() {
1380 let x = FieldElement::from_bytes(&decode_hex::<48>(
1381 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1382 5502f25dbf55296c3a545e3872760ab7",
1383 ))
1384 .unwrap();
1385 let x_inv = x.invert().unwrap();
1386 let product = x.mul(x_inv);
1387 assert_eq!(product, FieldElement::ONE);
1388 }
1389
1390 #[test]
1391 fn generator_point_is_on_curve() {
1392 assert!(AffinePoint::GENERATOR.is_on_curve());
1393 }
1394
1395 #[test]
1396 fn p384_fast_mul_mod_matches_generic() {
1397 for _ in 0..1000 {
1398 let a_bytes: [u8; 48] = rand::random();
1399 let b_bytes: [u8; 48] = rand::random();
1400 let a_opt = FieldElement::from_bytes(&a_bytes);
1401 let b_opt = FieldElement::from_bytes(&b_bytes);
1402 if a_opt.is_none() || b_opt.is_none() {
1403 continue;
1404 }
1405 let a = a_opt.unwrap();
1406 let b = b_opt.unwrap();
1407 let expected = U384::from_limbs({
1408 let mut p = [0u64; 12];
1409 for i in 0..6 {
1410 let mut c = 0u64;
1411 for j in 0..6 {
1412 let (v, cc) = mac(p[i + j], a.0.limbs[i], b.0.limbs[j], c);
1413 p[i + j] = v;
1414 c = cc;
1415 }
1416 p[i + 6] = c;
1417 }
1418 let mut rem = [0u64; 6];
1419 for bi in (0..768).rev() {
1420 let li = bi / 64;
1421 let pi = bi % 64;
1422 let bit = ((p[li] >> pi) & 1) as u64;
1423 let mut shifted = [0u64; 6];
1424 let mut carry = bit;
1425 for j in 0..6 {
1426 let next = rem[j] >> 63;
1427 shifted[j] = (rem[j] << 1) | carry;
1428 carry = next;
1429 }
1430 let (red, br) = U384::from_limbs(shifted).sub_raw(&MODULUS_P);
1431 if carry == 1 || br == 0 {
1432 rem = red.limbs;
1433 } else {
1434 rem = shifted;
1435 }
1436 }
1437 rem
1438 });
1439 let fast = p384_fast_mul_mod(&a.0, &b.0);
1440 assert_eq!(expected, fast, "mismatch in p384_fast_mul_mod");
1441 }
1442 }
1443
1444 #[test]
1445 fn scalar_mul_generator_n_gives_identity() {
1446 let n_minus_1 = Scalar::from_bytes(&decode_hex::<48>(
1447 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1448 581a0db248b0a77aecec196accc52972",
1449 ))
1450 .unwrap();
1451 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
1452 assert_eq!(result.x, GENERATOR_X);
1453 let neg_gy = GENERATOR_Y.negate();
1454 assert_eq!(result.y, neg_gy);
1455 }
1456
1457 #[test]
1458 fn ecdh_round_trip_alice_bob() {
1459 let alice = PrivateKey::generate().unwrap();
1460 let bob = PrivateKey::generate().unwrap();
1461
1462 let alice_shared = alice.ecdh(&bob.public_key()).unwrap();
1463 let bob_shared = bob.ecdh(&alice.public_key()).unwrap();
1464
1465 assert_eq!(alice_shared, bob_shared);
1466 assert_eq!(alice_shared.len(), ECDH_SHARED_SECRET_SIZE);
1467 }
1468
1469 #[test]
1470 fn ecdh_rejects_off_curve_peer_public_key() {
1471 let alice = PrivateKey::generate().unwrap();
1472 let mut bad_pub = alice.public_key().to_bytes().to_vec();
1473 bad_pub[96] ^= 0x01;
1474 assert!(!is_valid_public_key(&bad_pub));
1475 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1476 }
1477
1478 #[test]
1479 fn ecdh_rejects_infinity_peer_public_key() {
1480 let alice = PrivateKey::generate().unwrap();
1481 let infinity = [0x00u8];
1482 assert!(ecdh(&alice.to_bytes(), &infinity).is_err());
1483 }
1484
1485 #[test]
1486 fn ecdh_rejects_bad_length_peer_public_key() {
1487 let alice = PrivateKey::generate().unwrap();
1488 assert!(ecdh(&alice.to_bytes(), &[]).is_err());
1489 assert!(ecdh(&alice.to_bytes(), &[0x04, 0x00]).is_err());
1490 let mut long = [0x04u8; 200];
1491 long[0] = 0x04;
1492 assert!(ecdh(&alice.to_bytes(), &long).is_err());
1493 }
1494
1495 #[test]
1496 fn ecdh_rejects_invalid_private_key_zero() {
1497 let zero_key = [0u8; 48];
1498 assert!(PrivateKey::from_bytes(&zero_key).is_err());
1499 let bob = PrivateKey::generate().unwrap();
1500 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1501 }
1502
1503 #[test]
1504 fn ecdh_multiple_exchanges_consistency() {
1505 let alice = PrivateKey::generate().unwrap();
1506 let bob = PrivateKey::generate().unwrap();
1507 let charlie = PrivateKey::generate().unwrap();
1508
1509 let alice_bob = alice.ecdh(&bob.public_key()).unwrap();
1510 let bob_alice = bob.ecdh(&alice.public_key()).unwrap();
1511 assert_eq!(alice_bob, bob_alice);
1512
1513 let alice_charlie = alice.ecdh(&charlie.public_key()).unwrap();
1514 let charlie_alice = charlie.ecdh(&alice.public_key()).unwrap();
1515 assert_eq!(alice_charlie, charlie_alice);
1516
1517 let bob_charlie = bob.ecdh(&charlie.public_key()).unwrap();
1518 let charlie_bob = charlie.ecdh(&bob.public_key()).unwrap();
1519 assert_eq!(bob_charlie, charlie_bob);
1520
1521 assert_ne!(alice_bob, alice_charlie);
1522 assert_ne!(alice_bob, bob_charlie);
1523 assert_ne!(alice_charlie, bob_charlie);
1524 }
1525
1526 #[test]
1527 fn ecdsa_rejects_non_canonical_r_and_s() {
1528 let key = PrivateKey::generate().unwrap();
1529 let valid_sig = key.sign(b"msg").unwrap();
1530
1531 let mut bad_r = valid_sig;
1532 bad_r[..48].copy_from_slice(&decode_hex::<48>(
1533 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
1534 ));
1535 assert!(key.public_key().verify(b"msg", &bad_r).is_err());
1536
1537 let mut bad_s = valid_sig;
1538 bad_s[48..].copy_from_slice(&decode_hex::<48>(
1539 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
1540 ));
1541 assert!(key.public_key().verify(b"msg", &bad_s).is_err());
1542 }
1543
1544 #[test]
1545 fn verify_rejects_tampered_message_and_signature() {
1546 let key = PrivateKey::generate().unwrap();
1547 let pub_key = key.public_key();
1548 let sig = key.sign(b"message").unwrap();
1549
1550 assert!(pub_key.verify(b"tampered", &sig).is_err());
1551
1552 let mut bad_sig = sig;
1553 bad_sig[10] ^= 0x80;
1554 assert!(pub_key.verify(b"message", &bad_sig).is_err());
1555 }
1556
1557 #[test]
1558 fn public_key_rejects_off_curve_point() {
1559 let key = PrivateKey::generate().unwrap();
1560 let mut off_curve = key.public_key().to_bytes();
1561 off_curve[96] ^= 0x01;
1562 assert!(!is_valid_public_key(&off_curve));
1563 assert!(PublicKey::from_bytes(&off_curve).is_err());
1564 }
1565
1566 #[test]
1567 fn private_key_round_trip_bytes() {
1568 let key = PrivateKey::generate().unwrap();
1569 let bytes = key.to_bytes();
1570 let key2 = PrivateKey::from_bytes(&bytes).unwrap();
1571 assert_eq!(key.to_bytes(), key2.to_bytes());
1572 assert_eq!(key.public_key().to_bytes(), key2.public_key().to_bytes());
1573 }
1574
1575 #[test]
1576 fn public_key_round_trip_bytes() {
1577 let key = PrivateKey::generate().unwrap();
1578 let pub_key = key.public_key();
1579 let bytes = pub_key.to_bytes();
1580 let pub_key2 = PublicKey::from_bytes(&bytes).unwrap();
1581 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1582 }
1583
1584 #[test]
1585 fn x_y_round_trip() {
1586 let key = PrivateKey::generate().unwrap();
1587 let pub_key = key.public_key();
1588 let (x, y) = pub_key.x_y();
1589 let pub_key2 = PublicKey::from_x_y(&x, &y).unwrap();
1590 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1591 }
1592
1593 #[test]
1594 fn from_x_y_matches_generator() {
1595 let key = PublicKey::from_x_y(
1596 &decode_hex::<48>(
1597 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1598 5502f25dbf55296c3a545e3872760ab7",
1599 ),
1600 &decode_hex::<48>(
1601 "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0\
1602 0a60b1ce1d7e819d7a431d7c90ea0e5f",
1603 ),
1604 )
1605 .unwrap();
1606 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
1607 assert_eq!(key, from_sec1);
1608 }
1609
1610 #[test]
1611 fn from_x_y_rejects_off_curve() {
1612 assert!(PublicKey::from_x_y(&[0u8; 48], &[0u8; 48]).is_err());
1613 }
1614
1615 #[test]
1616 fn field_element_add_sub_mul_consistency() {
1617 let a = FieldElement::from_bytes(&decode_hex::<48>(
1618 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1619 5502f25dbf55296c3a545e3872760ab7",
1620 ))
1621 .unwrap();
1622 let b = FieldElement::from_bytes(&decode_hex::<48>(
1623 "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0\
1624 0a60b1ce1d7e819d7a431d7c90ea0e5f",
1625 ))
1626 .unwrap();
1627
1628 assert_eq!(a.add(b).sub(b), a);
1629 assert_eq!(a.add(b), b.add(a));
1630 assert_eq!(a.mul(b), b.mul(a));
1631
1632 let c = FieldElement::from_bytes(&decode_hex::<48>(
1633 "2a85c8edd3ec2aefc656398d8a2ed19d0314088f5013875a181d9c6efe814112\
1634 988e056be3f82d19b3312fa7e23ee7e4",
1635 ))
1636 .unwrap();
1637 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
1638 }
1639
1640 #[test]
1641 fn scalar_add_sub_mul_consistency() {
1642 let a = Scalar::from_bytes(&decode_hex::<48>(
1643 "c22b201cc45cd130ef80acfc70e84fa17b91b0ffbfe4c9c44eda37e1ad1d7f8f\
1644 ae4c4c8b52559930e08ba1c822c105b0",
1645 ))
1646 .unwrap();
1647 let one = Scalar::from_bytes(&decode_hex::<48>(
1648 "0000000000000000000000000000000000000000000000000000000000000000\
1649 00000000000000000000000000000001",
1650 ))
1651 .unwrap();
1652
1653 assert_eq!(a.add(one).sub(one), a);
1654 assert_eq!(a.mul(one), a);
1655
1656 let b = Scalar::from_bytes(&decode_hex::<48>(
1657 "7cf1be7a45d8d72e6e974229bfad108f3d2d4aa6208248adb9343258e4f30f80\
1658 8252a11a87ddc7e0d8ba3b5e28878944",
1659 ))
1660 .unwrap();
1661 assert_eq!(a.mul(b), b.mul(a));
1662 assert_eq!(a.add(b), b.add(a));
1663 }
1664
1665 #[test]
1666 fn field_element_negate_round_trip() {
1667 let x = FieldElement::from_bytes(&decode_hex::<48>(
1668 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1669 5502f25dbf55296c3a545e3872760ab7",
1670 ))
1671 .unwrap();
1672 let neg = x.negate();
1673 assert_eq!(neg.negate(), x);
1674 assert_eq!(x.add(neg), FieldElement::ZERO);
1675 }
1676
1677 #[test]
1678 fn point_double_and_add_consistency() {
1679 let g = AffinePoint::GENERATOR;
1680 let proj_g = ProjectivePoint::from_affine(&g);
1681 let doubled = proj_g.double();
1682 let added = proj_g.add(&proj_g);
1683 assert_eq!(
1684 doubled.to_affine().unwrap().to_uncompressed_bytes(),
1685 added.to_affine().unwrap().to_uncompressed_bytes(),
1686 );
1687 }
1688
1689 #[test]
1690 fn scalar_mul_by_two_matches_double() {
1691 let two = Scalar::from_bytes(&decode_hex::<48>(
1692 "0000000000000000000000000000000000000000000000000000000000000000\
1693 00000000000000000000000000000002",
1694 ))
1695 .unwrap();
1696 let g_times_2 = scalar_mul_affine(&AffinePoint::GENERATOR, &two).to_affine().unwrap();
1697 let proj_g = ProjectivePoint::from_affine(&AffinePoint::GENERATOR);
1698 let g_doubled = proj_g.double().to_affine().unwrap();
1699
1700 assert_eq!(g_times_2.to_uncompressed_bytes(), g_doubled.to_uncompressed_bytes());
1701 }
1702
1703 #[test]
1704 fn compressed_public_key_has_correct_prefix() {
1705 for _ in 0..5 {
1706 let key = PrivateKey::generate().unwrap();
1707 let compressed = derive_public_key_compressed(&key.to_bytes()).unwrap();
1708 let prefix = compressed[0];
1709 assert!(prefix == 0x02 || prefix == 0x03, "invalid compressed prefix: {prefix:#x}");
1710 }
1711 }
1712
1713 #[test]
1714 fn ecdsa_sign_then_verify_consistent_for_random_keys() {
1715 for _ in 0..5 {
1716 let key = PrivateKey::generate().unwrap();
1717 let msg = rand::random::<[u8; 32]>();
1718 let sig = key.sign(&msg).unwrap();
1719 assert!(key.public_key().verify(&msg, &sig).is_ok());
1720 }
1721 }
1722
1723 #[test]
1724 fn is_on_curve_accepts_generator_and_random_points() {
1725 assert!(AffinePoint::GENERATOR.is_on_curve());
1726 for _ in 0..5 {
1727 let key = PrivateKey::generate().unwrap();
1728 let pb = key.public_key().to_bytes();
1729 let pk = PublicKey::from_bytes(&pb).unwrap();
1730 let _ = pk;
1731 }
1732 }
1733
1734 #[test]
1735 fn ecdh_with_self_is_consistent() {
1736 let key = PrivateKey::generate().unwrap();
1737 let shared1 = key.ecdh(&key.public_key()).unwrap();
1738 let shared2 = key.ecdh(&key.public_key()).unwrap();
1739 assert_eq!(shared1, shared2);
1740 }
1741
1742 #[test]
1743 fn field_element_pow_correctness() {
1744 let x = FieldElement::from_bytes(&decode_hex::<48>(
1745 "0000000000000000000000000000000000000000000000000000000000000000\
1746 00000000000000000000000000000002",
1747 ))
1748 .unwrap();
1749 let x3 = x.pow(&U384::from_u64(3));
1750 let expected = x.mul(x).mul(x);
1751 assert_eq!(x3, expected);
1752
1753 let x0 = x.pow(&U384::ZERO);
1754 assert_eq!(x0, FieldElement::ONE);
1755 }
1756
1757 #[test]
1760 fn wycheproof_ecdsa_p384_sha384_p1363() {
1761 let data: serde_json::Value = serde_json::from_str(include_str!(
1762 "../testdata/wycheproof/testvectors_v1/ecdsa_secp384r1_sha384_p1363_test.json"
1763 ))
1764 .unwrap();
1765 let mut valid_tested = 0u64;
1766 let mut invalid_tested = 0u64;
1767 for group in data["testGroups"].as_array().unwrap() {
1768 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1769 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1770 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1771
1772 for test in group["tests"].as_array().unwrap() {
1773 let msg_hex = test["msg"].as_str().unwrap();
1774 let sig_hex = test["sig"].as_str().unwrap();
1775 let result = test["result"].as_str().unwrap();
1776
1777 let msg = hex::decode(msg_hex).unwrap();
1778
1779 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1780 continue;
1781 }
1782 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1783
1784 let verify_result = pk.verify(&msg, &sig);
1785
1786 if result == "valid" {
1787 assert!(
1788 verify_result.is_ok(),
1789 "wycheproof ECDSA P384 P1363 tcId={} expected valid but failed",
1790 test["tcId"]
1791 );
1792 valid_tested += 1;
1793 } else {
1794 assert!(
1795 verify_result.is_err(),
1796 "wycheproof ECDSA P384 P1363 tcId={} expected invalid but passed",
1797 test["tcId"]
1798 );
1799 invalid_tested += 1;
1800 }
1801 }
1802 }
1803 assert!(valid_tested > 0, "no valid ECDSA P384 P1363 wycheproof tests were run");
1804 assert!(invalid_tested > 0, "no invalid ECDSA P384 P1363 wycheproof tests were run");
1805 }
1806
1807 #[test]
1808 fn wycheproof_ecdsa_p384_sha384_der() {
1809 let data: serde_json::Value = serde_json::from_str(include_str!(
1810 "../testdata/wycheproof/testvectors_v1/ecdsa_secp384r1_sha384_test.json"
1811 ))
1812 .unwrap();
1813 let mut valid_tested = 0u64;
1814 let mut invalid_tested = 0u64;
1815 for group in data["testGroups"].as_array().unwrap() {
1816 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1817 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1818 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1819
1820 for test in group["tests"].as_array().unwrap() {
1821 let msg_hex = test["msg"].as_str().unwrap();
1822 let sig_hex = test["sig"].as_str().unwrap();
1823 let result = test["result"].as_str().unwrap();
1824
1825 let msg = hex::decode(msg_hex).unwrap();
1826 let der_sig = hex::decode(sig_hex).unwrap();
1827 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
1828 continue;
1829 };
1830
1831 let verify_result = pk.verify(&msg, &sig);
1832
1833 if result == "valid" {
1834 assert!(
1835 verify_result.is_ok(),
1836 "wycheproof ECDSA P384 DER SHA-384 tcId={} expected valid but failed",
1837 test["tcId"]
1838 );
1839 valid_tested += 1;
1840 } else {
1841 assert!(
1842 verify_result.is_err(),
1843 "wycheproof ECDSA P384 DER SHA-384 tcId={} expected invalid but passed",
1844 test["tcId"]
1845 );
1846 invalid_tested += 1;
1847 }
1848 }
1849 }
1850 assert!(valid_tested > 0, "no valid ECDSA P384 DER SHA-384 wycheproof tests were run");
1851 assert!(
1852 invalid_tested > 0,
1853 "no invalid ECDSA P384 DER SHA-384 wycheproof tests were run"
1854 );
1855 }
1856
1857 #[test]
1858 fn wycheproof_ecdh_p384_ecpoint() {
1859 let data: serde_json::Value = serde_json::from_str(include_str!(
1860 "../testdata/wycheproof/testvectors_v1/ecdh_secp384r1_ecpoint_test.json"
1861 ))
1862 .unwrap();
1863 let mut valid_tested = 0u64;
1864 let mut invalid_tested = 0u64;
1865 let mut acceptable_tested = 0u64;
1866 for group in data["testGroups"].as_array().unwrap() {
1867 if group["curve"].as_str() != Some("secp384r1") {
1868 continue;
1869 }
1870 for test in group["tests"].as_array().unwrap() {
1871 let public_hex = test["public"].as_str().unwrap();
1872 let private_hex = test["private"].as_str().unwrap();
1873 let expected_shared_hex = test["shared"].as_str().unwrap();
1874 let result = test["result"].as_str().unwrap();
1875
1876 let public_key = hex::decode(public_hex).unwrap();
1877
1878 let private_bytes = hex::decode(private_hex).unwrap();
1879 let mut private_key = [0u8; PRIVATE_KEY_SIZE];
1880 let effective_len = private_bytes.len().min(PRIVATE_KEY_SIZE);
1881 let skip = if private_bytes.len() > PRIVATE_KEY_SIZE {
1882 private_bytes.len() - PRIVATE_KEY_SIZE
1883 } else {
1884 0
1885 };
1886 private_key[PRIVATE_KEY_SIZE - effective_len..]
1887 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1888
1889 let shared = ecdh(&private_key, &public_key);
1890
1891 if result == "valid" {
1892 let shared = shared.unwrap();
1893 let shared_hex = hex::encode(shared);
1894 assert_eq!(
1895 shared_hex, expected_shared_hex,
1896 "wycheproof ECDH P384 ecpoint tcId={}",
1897 test["tcId"]
1898 );
1899 valid_tested += 1;
1900 } else if result == "invalid" {
1901 assert!(
1902 shared.is_err(),
1903 "wycheproof ECDH P384 ecpoint tcId={} expected invalid but passed",
1904 test["tcId"]
1905 );
1906 invalid_tested += 1;
1907 } else {
1908 acceptable_tested += 1;
1909 }
1910 }
1911 }
1912 assert!(valid_tested > 0, "no valid ECDH P384 ecpoint wycheproof tests were run");
1913 assert!(invalid_tested > 0, "no invalid ECDH P384 ecpoint wycheproof tests were run");
1914 assert!(
1915 acceptable_tested > 0,
1916 "no acceptable ECDH P384 ecpoint wycheproof tests were run"
1917 );
1918 }
1919
1920 #[test]
1921 fn wycheproof_ecdh_p384_asn() {
1922 let data: serde_json::Value =
1923 serde_json::from_str(include_str!("../testdata/wycheproof/testvectors_v1/ecdh_secp384r1_test.json"))
1924 .unwrap();
1925 let mut valid_tested = 0u64;
1926 let mut invalid_tested = 0u64;
1927 let mut acceptable_tested = 0u64;
1928 for group in data["testGroups"].as_array().unwrap() {
1929 for test in group["tests"].as_array().unwrap() {
1930 let public_hex = test["public"].as_str().unwrap();
1931 let private_hex = test["private"].as_str().unwrap();
1932 let expected_shared_hex = test["shared"].as_str().unwrap();
1933 let result = test["result"].as_str().unwrap();
1934
1935 let spki_der = hex::decode(public_hex).unwrap();
1936 let Some(sec1_point) = spki_to_sec1_point(&spki_der) else {
1937 if result == "valid" {
1938 panic!("wycheproof ECDH P384 ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
1939 }
1940 invalid_tested += 1;
1941 continue;
1942 };
1943
1944 let private_bytes = hex::decode(private_hex).unwrap();
1945 let mut private_key = [0u8; PRIVATE_KEY_SIZE];
1946 let effective_len = private_bytes.len().min(PRIVATE_KEY_SIZE);
1947 let skip = if private_bytes.len() > PRIVATE_KEY_SIZE {
1948 private_bytes.len() - PRIVATE_KEY_SIZE
1949 } else {
1950 0
1951 };
1952 private_key[PRIVATE_KEY_SIZE - effective_len..]
1953 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1954
1955 let shared = ecdh(&private_key, &sec1_point);
1956
1957 if result == "valid" {
1958 let shared = shared.unwrap();
1959 let shared_hex = hex::encode(shared);
1960 assert_eq!(
1961 shared_hex, expected_shared_hex,
1962 "wycheproof ECDH P384 ASN tcId={}",
1963 test["tcId"]
1964 );
1965 valid_tested += 1;
1966 } else if result == "invalid" {
1967 assert!(
1968 shared.is_err(),
1969 "wycheproof ECDH P384 ASN tcId={} expected invalid but passed",
1970 test["tcId"]
1971 );
1972 invalid_tested += 1;
1973 } else {
1974 acceptable_tested += 1;
1975 }
1976 }
1977 }
1978 assert!(valid_tested > 0, "no valid ECDH P384 ASN wycheproof tests were run");
1979 assert!(invalid_tested > 0, "no invalid ECDH P384 ASN wycheproof tests were run");
1980 assert!(acceptable_tested > 0, "no acceptable ECDH P384 ASN wycheproof tests were run");
1981 }
1982}