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