1use big_number::{Uint, mac};
7
8use super::p_curves::{self, Curve, UintOps, field_pow};
9use crate::{EllipticCurveError, Hasher, RandomError, hmac::Hmac, sha2::Sha384};
10
11pub const SECRET_KEY_SIZE: usize = 48;
13pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 49;
15pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 97;
17pub const SIGNATURE_SIZE: usize = 96;
19pub const ECDH_SHARED_SECRET_SIZE: usize = 48;
22
23#[derive(Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
54pub struct SecretKey(p_curves::SecretKey<P384>);
55
56impl SecretKey {
57 #[cfg(feature = "random")]
59 pub fn generate() -> Result<SecretKey, EllipticCurveError> {
60 Ok(SecretKey(p_curves::SecretKey::generate()?))
61 }
62
63 pub fn from_bytes(key: &[u8; SECRET_KEY_SIZE]) -> Result<SecretKey, EllipticCurveError> {
68 Ok(SecretKey(p_curves::SecretKey::from_bytes(key)?))
69 }
70
71 pub fn public_key(&self) -> PublicKey {
73 PublicKey(self.0.public_key())
74 }
75
76 pub fn sign(&self, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
88 self.0.sign(message)
89 }
90
91 pub fn ecdh(&self, peer_public: &PublicKey) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
98 self.0.ecdh(&peer_public.0)
99 }
100
101 pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE] {
103 self.0.to_bytes()
104 }
105}
106
107#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub struct PublicKey(p_curves::PublicKey<P384>);
122
123impl PublicKey {
124 #[inline]
129 pub fn from_bytes(key: &[u8]) -> Result<PublicKey, EllipticCurveError> {
130 Ok(PublicKey(p_curves::PublicKey::from_bytes(key)?))
131 }
132
133 #[inline]
140 pub fn from_x_y(x_bytes: &[u8; 48], y_bytes: &[u8; 48]) -> Result<PublicKey, EllipticCurveError> {
141 Ok(PublicKey(p_curves::PublicKey::from_x_y(x_bytes, y_bytes)?))
142 }
143
144 pub fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
150 self.0.verify(message, signature)
151 }
152
153 pub fn verify_strict(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
160 self.0.verify_strict(message, signature)
161 }
162
163 #[inline]
165 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
166 self.0.to_bytes()
167 }
168
169 #[inline]
171 pub fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
172 self.0.to_compressed_bytes()
173 }
174
175 #[inline]
177 pub fn x_y(&self) -> ([u8; 48], [u8; 48]) {
178 self.0.x_y()
179 }
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184struct P384;
185
186type U384 = Uint<384, 6>;
187type CurveUint = U384;
188
189const MODULUS_P: CurveUint = CurveUint::from_limbs([
190 0x00000000ffffffff,
191 0xffffffff00000000,
192 0xfffffffffffffffe,
193 0xffffffffffffffff,
194 0xffffffffffffffff,
195 0xffffffffffffffff,
196]);
197
198const MODULUS_N: CurveUint = CurveUint::from_limbs([
199 0xecec196accc52973,
200 0x581a0db248b0a77a,
201 0xc7634d81f4372ddf,
202 0xffffffffffffffff,
203 0xffffffffffffffff,
204 0xffffffffffffffff,
205]);
206
207const N_MU: [u64; 7] = [
210 0x1313e695333ad68d,
211 0xa7e5f24db74f5885,
212 0x389cb27e0bc8d220,
213 0x0000000000000000,
214 0x0000000000000000,
215 0x0000000000000000,
216 0x0000000000000001,
217];
218
219const N_HALF: CurveUint = CurveUint::from_limbs([
222 0x76760cb5666294b9,
223 0xac0d06d9245853bd,
224 0xe3b1a6c0fa1b96ef,
225 0xffffffffffffffff,
226 0xffffffffffffffff,
227 0x7fffffffffffffff,
228]);
229
230const P_MINUS_TWO: CurveUint = CurveUint::from_limbs([
231 0x00000000fffffffd,
232 0xffffffff00000000,
233 0xfffffffffffffffe,
234 0xffffffffffffffff,
235 0xffffffffffffffff,
236 0xffffffffffffffff,
237]);
238
239const P_PLUS_ONE_OVER_FOUR: CurveUint = CurveUint::from_limbs([
240 0x0000000040000000,
241 0xbfffffffc0000000,
242 0xffffffffffffffff,
243 0xffffffffffffffff,
244 0xffffffffffffffff,
245 0x3fffffffffffffff,
246]);
247
248const N_MINUS_TWO: CurveUint = CurveUint::from_limbs([
249 0xecec196accc52971,
250 0x581a0db248b0a77a,
251 0xc7634d81f4372ddf,
252 0xffffffffffffffff,
253 0xffffffffffffffff,
254 0xffffffffffffffff,
255]);
256
257const CURVE_B: CurveUint = CurveUint::from_limbs([
258 0x2a85c8edd3ec2aef,
259 0xc656398d8a2ed19d,
260 0x0314088f5013875a,
261 0x181d9c6efe814112,
262 0x988e056be3f82d19,
263 0xb3312fa7e23ee7e4,
264]);
265
266const GENERATOR_X: CurveUint = CurveUint::from_limbs([
267 0x3a545e3872760ab7,
268 0x5502f25dbf55296c,
269 0x59f741e082542a38,
270 0x6e1d3b628ba79b98,
271 0x8eb1c71ef320ad74,
272 0xaa87ca22be8b0537,
273]);
274
275const GENERATOR_Y: CurveUint = CurveUint::from_limbs([
276 0x7a431d7c90ea0e5f,
277 0x0a60b1ce1d7e819d,
278 0xe9da3113b5f0b8c0,
279 0xf8f41dbd289a147c,
280 0x5d9e98bf9292dc29,
281 0x3617de4a96262c6f,
282]);
283
284const S6: [u64; 6] = [
288 0xffffffff00000001,
289 0x00000000ffffffff,
290 0x0000000000000001,
291 0x0000000000000000,
292 0x0000000000000000,
293 0x0000000000000000,
294];
295
296const S7: [u64; 6] = [
297 0x0000000000000000,
298 0xffffffff00000001,
299 0x00000000ffffffff,
300 0x0000000000000001,
301 0x0000000000000000,
302 0x0000000000000000,
303];
304
305const S8: [u64; 6] = [
306 0x0000000000000000,
307 0x0000000000000000,
308 0xffffffff00000001,
309 0x00000000ffffffff,
310 0x0000000000000001,
311 0x0000000000000000,
312];
313
314const S9: [u64; 6] = [
315 0x0000000000000000,
316 0x0000000000000000,
317 0x0000000000000000,
318 0xffffffff00000001,
319 0x00000000ffffffff,
320 0x0000000000000001,
321];
322
323const S10: [u64; 6] = [
324 0xffffffff00000001,
325 0x00000000ffffffff,
326 0x0000000000000001,
327 0x0000000000000000,
328 0xffffffff00000001,
329 0x00000000ffffffff,
330];
331
332const S11: [u64; 6] = [
333 0x00000001ffffffff,
334 0xfffffffe00000000,
335 0x00000001ffffffff,
336 0x0000000000000001,
337 0x0000000000000000,
338 0xffffffff00000001,
339];
340
341#[inline]
342fn ct_select_u128(a: u128, b: u128, choice: bool) -> u128 {
343 let mask = (choice as u128).wrapping_neg();
344 (a & mask) | (b & !mask)
345}
346
347fn p384_fast_mul_mod(a: &CurveUint, b: &CurveUint) -> CurveUint {
350 let al = a.limbs;
351 let bl = b.limbs;
352
353 let mut prod = [0u64; 12];
354 for i in 0..6 {
355 let mut carry = 0u64;
356 for j in 0..6 {
357 let (v, cc) = mac(prod[i + j], al[i], bl[j], carry);
358 prod[i + j] = v;
359 carry = cc;
360 }
361 prod[i + 6] = carry;
362 }
363
364 const MASK: u128 = 0xffffffffffffffff;
365 let c0 = [
366 S6[0] as u128,
367 S6[1] as u128,
368 S6[2] as u128,
369 S6[3] as u128,
370 S6[4] as u128,
371 S6[5] as u128,
372 ];
373 let c1 = [
374 S7[0] as u128,
375 S7[1] as u128,
376 S7[2] as u128,
377 S7[3] as u128,
378 S7[4] as u128,
379 S7[5] as u128,
380 ];
381 let c2 = [
382 S8[0] as u128,
383 S8[1] as u128,
384 S8[2] as u128,
385 S8[3] as u128,
386 S8[4] as u128,
387 S8[5] as u128,
388 ];
389 let c3 = [
390 S9[0] as u128,
391 S9[1] as u128,
392 S9[2] as u128,
393 S9[3] as u128,
394 S9[4] as u128,
395 S9[5] as u128,
396 ];
397 let c4 = [
398 S10[0] as u128,
399 S10[1] as u128,
400 S10[2] as u128,
401 S10[3] as u128,
402 S10[4] as u128,
403 S10[5] as u128,
404 ];
405 let c5 = [
406 S11[0] as u128,
407 S11[1] as u128,
408 S11[2] as u128,
409 S11[3] as u128,
410 S11[4] as u128,
411 S11[5] as u128,
412 ];
413 let coeffs: [&[u128; 6]; 6] = [&c0, &c1, &c2, &c3, &c4, &c5];
414
415 let mut r0 = prod[0] as u128;
416 let mut r1 = prod[1] as u128;
417 let mut r2 = prod[2] as u128;
418 let mut r3 = prod[3] as u128;
419 let mut r4 = prod[4] as u128;
420 let mut r5 = prod[5] as u128;
421
422 for i in 0..6 {
423 let w = prod[6 + i] as u128;
424 let c = coeffs[i];
425
426 r0 = r0.wrapping_add(w.wrapping_mul(c[0]));
427 r1 = r1.wrapping_add(w.wrapping_mul(c[1]));
428 r2 = r2.wrapping_add(w.wrapping_mul(c[2]));
429 r3 = r3.wrapping_add(w.wrapping_mul(c[3]));
430 r4 = r4.wrapping_add(w.wrapping_mul(c[4]));
431 r5 = r5.wrapping_add(w.wrapping_mul(c[5]));
432
433 for _ in 0..4 {
435 let carry = r0 >> 64;
436 r1 = r1.wrapping_add(carry);
437 r0 &= MASK;
438 let carry = r1 >> 64;
439 r2 = r2.wrapping_add(carry);
440 r1 &= MASK;
441 let carry = r2 >> 64;
442 r3 = r3.wrapping_add(carry);
443 r2 &= MASK;
444 let carry = r3 >> 64;
445 r4 = r4.wrapping_add(carry);
446 r3 &= MASK;
447 let carry = r4 >> 64;
448 r5 = r5.wrapping_add(carry);
449 r4 &= MASK;
450
451 let residual = r5 >> 64;
452 let need_reduce = residual != 0;
453
454 let rr5 = r5 & MASK;
455 let rr0 = r0.wrapping_add(residual.wrapping_mul(c0[0]));
456 let rr1 = r1.wrapping_add(residual.wrapping_mul(c0[1]));
457 let rr2 = r2.wrapping_add(residual.wrapping_mul(c0[2]));
458 let rr3 = r3.wrapping_add(residual.wrapping_mul(c0[3]));
459 let rr4 = r4.wrapping_add(residual.wrapping_mul(c0[4]));
460 let rr5r = rr5.wrapping_add(residual.wrapping_mul(c0[5]));
461
462 r0 = ct_select_u128(rr0, r0, need_reduce);
463 r1 = ct_select_u128(rr1, r1, need_reduce);
464 r2 = ct_select_u128(rr2, r2, need_reduce);
465 r3 = ct_select_u128(rr3, r3, need_reduce);
466 r4 = ct_select_u128(rr4, r4, need_reduce);
467 r5 = ct_select_u128(rr5r, r5, need_reduce);
468 }
469 }
470
471 let mut result = CurveUint::from_limbs([r0 as u64, r1 as u64, r2 as u64, r3 as u64, r4 as u64, r5 as u64]);
473 for _ in 0..8 {
474 let (sub, borrow) = result.sub_raw(&MODULUS_P);
475 result = CurveUint::ct_select(&sub, &result, borrow == 0);
476 }
477 result
478}
479
480#[inline]
482fn reduce_mod(value: CurveUint) -> CurveUint {
483 let (sub_value, _) = value.sub_raw(&MODULUS_N);
484 CurveUint::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N))
485}
486
487impl Curve for P384 {
488 type U = CurveUint;
489 type FieldBytes = [u8; SECRET_KEY_SIZE];
490 type DigestBytes = [u8; 48];
491 type CompressedBytes = [u8; PUBLIC_KEY_COMPRESSED_SIZE];
492 type UncompressedBytes = [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
493 type SignatureBytes = [u8; SIGNATURE_SIZE];
494
495 const FIELD_BITS: usize = 384;
496 const FIELD_BYTES: usize = SECRET_KEY_SIZE;
497 const DIGEST_BYTES: usize = 48;
498 const COMPRESSED_BYTES: usize = PUBLIC_KEY_COMPRESSED_SIZE;
499 const UNCOMPRESSED_BYTES: usize = PUBLIC_KEY_UNCOMPRESSED_SIZE;
500
501 const MODULUS_P: CurveUint = MODULUS_P;
502 const MODULUS_N: CurveUint = MODULUS_N;
503 const N_HALF: CurveUint = N_HALF;
504 const P_MINUS_TWO: CurveUint = P_MINUS_TWO;
505 const N_MINUS_TWO: CurveUint = N_MINUS_TWO;
506 const CURVE_B: CurveUint = CURVE_B;
507 const GENERATOR_X: CurveUint = GENERATOR_X;
508 const GENERATOR_Y: CurveUint = GENERATOR_Y;
509
510 #[inline]
511 fn field_mul(a: &Self::U, b: &Self::U) -> Self::U {
512 p384_fast_mul_mod(a, b)
513 }
514
515 #[inline]
516 fn scalar_mul(a: &Self::U, b: &Self::U) -> Self::U {
517 a.mul_mod_barrett_w::<14>(b, &MODULUS_N, &N_MU)
518 }
519
520 #[inline]
521 fn field_sqrt(a: Self::U) -> Option<Self::U> {
522 let candidate = field_pow::<Self>(a, &P_PLUS_ONE_OVER_FOUR);
523 if a.ct_eq(&Self::field_mul(&candidate, &candidate)) {
524 Some(candidate)
525 } else {
526 None
527 }
528 }
529
530 #[inline]
531 fn hash(data: &[u8]) -> Self::DigestBytes {
532 Sha384::hash(data).as_ref().try_into().unwrap()
533 }
534
535 #[inline]
536 fn hmac(key: &[u8], data: &[u8]) -> Self::DigestBytes {
537 Hmac::<Sha384>::mac(key, data).as_ref().try_into().unwrap()
538 }
539
540 #[inline]
541 fn scalar_from_digest(digest: &Self::DigestBytes) -> Self::U {
542 reduce_mod(CurveUint::read_be(digest.as_ref()))
543 }
544
545 #[inline]
546 fn scalar_from_field_bytes(bytes: &Self::FieldBytes) -> Self::U {
547 reduce_mod(CurveUint::read_be(bytes.as_ref()))
548 }
549
550 #[cfg(feature = "random")]
551 #[inline]
552 fn random_secret_key() -> Result<Self::FieldBytes, RandomError> {
553 crate::random::bytes()
554 }
555}
556
557pub fn is_valid_public_key(public_key: &[u8]) -> bool {
560 p_curves::is_valid_public_key::<P384>(public_key)
561}
562
563#[cfg(test)]
564mod tests {
565 #![allow(dead_code)]
566 use super::*;
567 use crate::p_curves::p_curves;
568
569 type FieldElement = p_curves::FieldElement<P384>;
570 type Scalar = p_curves::Scalar<P384>;
571 type AffinePoint = p_curves::AffinePoint<P384>;
572 type ProjectivePoint = p_curves::ProjectivePoint<P384>;
573 type Rfc6979 = p_curves::Rfc6979<P384>;
574
575 fn hash_message(message: &[u8]) -> [u8; 48] {
577 p_curves::hash_message::<P384>(message)
578 }
579
580 fn hmac_digest(key: &[u8], data: &[u8]) -> [u8; 48] {
581 p_curves::hmac_digest::<P384>(key, data)
582 }
583
584 fn bits2octets(hash: &[u8; 48]) -> [u8; SECRET_KEY_SIZE] {
585 p_curves::bits2octets::<P384>(hash)
586 }
587
588 fn derive_public_key_uncompressed(
589 private_key: &[u8; SECRET_KEY_SIZE],
590 ) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], crate::EllipticCurveError> {
591 p_curves::derive_public_key_uncompressed::<P384>(private_key)
592 }
593
594 fn derive_public_key_compressed(
595 private_key: &[u8; SECRET_KEY_SIZE],
596 ) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], crate::EllipticCurveError> {
597 p_curves::derive_public_key_compressed::<P384>(private_key)
598 }
599
600 fn ecdsa_sign_inner_impl(
601 scalar: &Scalar,
602 message: &[u8],
603 force_first_retry: bool,
604 ) -> Result<[u8; SIGNATURE_SIZE], crate::EllipticCurveError> {
605 p_curves::ecdsa_sign_inner_impl::<P384>(scalar, message, force_first_retry)
606 }
607
608 fn ecdsa_verify_inner(
609 public_point: &AffinePoint,
610 message: &[u8],
611 signature: &[u8; SIGNATURE_SIZE],
612 ) -> Result<(), crate::EllipticCurveError> {
613 p_curves::ecdsa_verify_inner::<P384>(public_point, message, signature)
614 }
615
616 fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, crate::EllipticCurveError> {
617 p_curves::parse_public_key::<P384>(public_key)
618 }
619
620 fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
621 p_curves::scalar_mul_generator::<P384>(scalar)
622 }
623
624 fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
625 p_curves::scalar_mul_affine::<P384>(base, scalar)
626 }
627
628 fn ecdh(
630 secret_key: &[u8; SECRET_KEY_SIZE],
631 peer_public_key: &[u8],
632 ) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], crate::EllipticCurveError> {
633 SecretKey::from_bytes(secret_key)?.ecdh(&PublicKey::from_bytes(peer_public_key)?)
634 }
635
636 #[cfg(feature = "zeroize")]
637 #[test]
638 fn private_key_zeroize_clears_scalar() {
639 use zeroize::Zeroize;
640
641 let mut key = SecretKey::from_bytes(&[1u8; SECRET_KEY_SIZE]).unwrap();
642 assert_ne!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
643 key.zeroize();
644 assert_eq!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
645 }
646
647 fn decode_hex<const N: usize>(hex_bytes: &str) -> [u8; N] {
648 let bytes = hex::decode(hex_bytes).unwrap();
649 assert_eq!(bytes.len(), N);
650 let mut out = [0u8; N];
651 out.copy_from_slice(&bytes);
652 out
653 }
654
655 fn der_read_tlv<'a>(data: &'a [u8], offset: &mut usize) -> Option<(u8, &'a [u8])> {
656 if *offset >= data.len() {
657 return None;
658 }
659 let tag = data[*offset];
660 *offset += 1;
661 if *offset >= data.len() {
662 return None;
663 }
664 let len_byte = data[*offset];
665 *offset += 1;
666 let (len, _) = if len_byte & 0x80 != 0 {
667 let num_bytes = (len_byte & 0x7f) as usize;
668 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
669 return None;
670 }
671 if num_bytes > 1 && data[*offset] == 0 {
672 return None;
673 }
674 let mut l = 0usize;
675 for i in 0..num_bytes {
676 l = (l << 8) | data[*offset + i] as usize;
677 }
678 if l < 128 {
679 return None;
680 }
681 *offset += num_bytes;
682 (l, num_bytes + 1)
683 } else {
684 (len_byte as usize, 1)
685 };
686 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
687 return None;
688 }
689 let value = &data[*offset..*offset + len];
690 *offset = (*offset).checked_add(len)?;
691 Some((tag, value))
692 }
693
694 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; 96]> {
695 let mut offset = 0;
696 let (tag, inner) = der_read_tlv(der, &mut offset)?;
697 if tag != 0x30 {
698 return None;
699 }
700 if offset != der.len() {
701 return None;
702 }
703 let mut inner_offset = 0;
704 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
705 if rtag != 0x02 || rval.is_empty() || rval.len() > 49 {
706 return None;
707 }
708 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
709 if stag != 0x02 || sval.is_empty() || sval.len() > 49 {
710 return None;
711 }
712 if inner_offset != inner.len() {
713 return None;
714 }
715 let r_valid = if rval.len() == 48 && rval[0] >= 0x80 {
716 false
717 } else if rval.len() == 49 && rval[0] != 0 {
718 false
719 } else if rval.len() == 49 && rval[0] == 0 && rval[1] < 0x80 {
720 false
721 } else if rval.len() > 49 {
722 false
723 } else {
724 true
725 };
726 let s_valid = if sval.len() == 48 && sval[0] >= 0x80 {
727 false
728 } else if sval.len() == 49 && sval[0] != 0 {
729 false
730 } else if sval.len() == 49 && sval[0] == 0 && sval[1] < 0x80 {
731 false
732 } else if sval.len() > 49 {
733 false
734 } else {
735 true
736 };
737 if !r_valid || !s_valid {
738 return None;
739 }
740
741 let r_trimmed = if rval.len() == 49 && rval[0] == 0 {
742 &rval[1..]
743 } else {
744 rval
745 };
746 let s_trimmed = if sval.len() == 49 && sval[0] == 0 {
747 &sval[1..]
748 } else {
749 sval
750 };
751 if r_trimmed.len() > 48 || s_trimmed.len() > 48 {
752 return None;
753 }
754 let mut sig = [0u8; 96];
755 sig[48 - r_trimmed.len()..48].copy_from_slice(r_trimmed);
756 sig[96 - s_trimmed.len()..96].copy_from_slice(s_trimmed);
757 Some(sig)
758 }
759
760 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
761 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
762 let secp384r1_oid: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x22];
763 let mut offset = 0;
764 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
765 let mut inner = 0;
766 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
767 if _alg_tag != 0x30 {
768 return None;
769 }
770 let mut ai = 0;
771 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
772 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
773 return None;
774 }
775 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
776 if oid2_tag != 0x06 || oid2 != secp384r1_oid {
777 return None;
778 }
779 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
780 if _bs_tag != 0x03 || bs_val.is_empty() {
781 return None;
782 }
783 Some(bs_val[1..].to_vec())
784 }
785
786 #[test]
787 fn derive_public_key_generator_matches_sec1_base_point() {
788 let mut private_key = [0u8; 48];
789 private_key[47] = 1;
790 let derived = derive_public_key_uncompressed(&private_key).unwrap();
791 let expected = decode_hex::<97>(
792 "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
793 5502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29\
794 f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
795 );
796 assert_eq!(derived, expected);
797 }
798
799 #[test]
800 fn ecdsa_verify_accepts_compressed_and_uncompressed_public_keys() {
801 let private_key = decode_hex::<48>(
802 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
803 96d5724e4c70a825f872c9ea60d2edf5",
804 );
805 let key = SecretKey::from_bytes(&private_key).unwrap();
806 let uncompressed = key.public_key();
807 let compressed = derive_public_key_compressed(&private_key).unwrap();
808 let signature = key.sign(b"sample").unwrap();
809
810 assert!(uncompressed.verify(b"sample", &signature).is_ok());
811 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
812 assert!(ecdsa_verify_inner(&point, b"sample", &signature).is_ok());
813 }
814
815 #[test]
816 fn invalid_inputs_are_rejected() {
817 let invalid_private_key = [0u8; SECRET_KEY_SIZE];
818 assert!(SecretKey::from_bytes(&invalid_private_key).is_err());
819 assert!(derive_public_key_uncompressed(&invalid_private_key).is_err());
820 assert!(derive_public_key_compressed(&invalid_private_key).is_err());
821
822 let private_key = decode_hex::<48>(
823 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
824 96d5724e4c70a825f872c9ea60d2edf5",
825 );
826 let key = SecretKey::from_bytes(&private_key).unwrap();
827 let signature = key.sign(b"msg").unwrap();
828 let mut zero_r = signature;
829 zero_r[..48].fill(0);
830 assert!(key.public_key().verify(b"msg", &zero_r).is_err());
831 }
832
833 #[test]
834 fn public_key_validation_accepts_known_good_points() {
835 assert!(is_valid_public_key(&decode_hex::<97>(
836 "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
837 5502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29\
838 f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f",
839 )));
840 }
841
842 #[test]
843 fn ecdsa_sign_verify_round_trip_multiple_messages() {
844 let private_key = decode_hex::<48>(
845 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
846 96d5724e4c70a825f872c9ea60d2edf5",
847 );
848 let key = SecretKey::from_bytes(&private_key).unwrap();
849 let pub_key = key.public_key();
850
851 let messages: &[&[u8]] = &[
852 b"",
853 b"hello world",
854 b"The quick brown fox jumps over the lazy dog",
855 &[0u8; 0],
856 &[0xffu8; 100],
857 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
858 ];
859
860 for msg in messages {
861 let sig = key.sign(msg).unwrap();
862 assert!(pub_key.verify(msg, &sig).is_ok(), "round-trip failed for message {:?}", msg);
863 let mut wrong_msg = msg.to_vec();
864 wrong_msg.push(0x42);
865 assert!(pub_key.verify(&wrong_msg, &sig).is_err());
866 }
867 }
868
869 #[test]
870 fn rfc6979_retry_advances_drbg() {
871 let private_key = Scalar::from_bytes(&decode_hex::<48>(
872 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
873 96d5724e4c70a825f872c9ea60d2edf5",
874 ))
875 .unwrap();
876 let hash = hash_message(b"sample");
877
878 let mut drbg = Rfc6979::new(&private_key, &hash);
879 let k1 = drbg.generate();
880 assert_eq!(
881 k1.to_bytes(),
882 decode_hex::<48>(
883 "94ed910d1a099dad3254e9242ae85abde4ba15168eaf0ca87a555fd56d10fbca\
884 2907e3e83ba95368623b8c4686915cf9"
885 )
886 );
887
888 drbg.retry();
891 let k2 = drbg.generate();
892 assert_ne!(k1.to_bytes(), k2.to_bytes());
893 assert_eq!(
894 k2.to_bytes(),
895 decode_hex::<48>(
896 "9d63ce4c96d070a67f7bee49e870b64838c0ac65bb7440cf46017dca69d35d23\
897 6219aae5e00a9f01f13e7774be1339fc"
898 )
899 );
900 }
901
902 #[test]
903 fn ecdsa_forced_retry_uses_fresh_nonce() {
904 let private_key = decode_hex::<48>(
905 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
906 96d5724e4c70a825f872c9ea60d2edf5",
907 );
908 let key = SecretKey::from_bytes(&private_key).unwrap();
909 let scalar = Scalar::from_bytes(&private_key).unwrap();
910
911 let normal = key.sign(b"sample").unwrap();
912 let retried = ecdsa_sign_inner_impl(&scalar, b"sample", true).unwrap();
915
916 assert_ne!(normal, retried);
917 assert!(key.public_key().verify(b"sample", &retried).is_ok());
918 }
919
920 #[test]
921 fn ecdsa_sign_verify_different_keys() {
922 let keys: &[&str] = &[
923 "0000000000000000000000000000000000000000000000000000000000000000\
924 00000000000000000000000000000001",
925 "0000000000000000000000000000000000000000000000000000000000000000\
926 00000000000000000000000000000002",
927 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011\
928 2233445566778899aabbccddeeff0011",
929 ];
930
931 for key_hex in keys {
932 let private_key = decode_hex::<48>(key_hex);
933 let key = SecretKey::from_bytes(&private_key).unwrap();
934 let sig = key.sign(b"test message").unwrap();
935 assert!(
936 key.public_key().verify(b"test message", &sig).is_ok(),
937 "sign/verify failed for key {}",
938 key_hex
939 );
940 }
941 }
942
943 #[test]
944 fn ecdsa_verify_wrong_public_key_rejects() {
945 let private_key1 = decode_hex::<48>(
946 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
947 96d5724e4c70a825f872c9ea60d2edf5",
948 );
949 let private_key2 = decode_hex::<48>(
950 "0000000000000000000000000000000000000000000000000000000000000000\
951 00000000000000000000000000000001",
952 );
953 let key1 = SecretKey::from_bytes(&private_key1).unwrap();
954 let key2 = SecretKey::from_bytes(&private_key2).unwrap();
955
956 let sig = key1.sign(b"message").unwrap();
957 assert!(key2.public_key().verify(b"message", &sig).is_err());
958 }
959
960 #[test]
961 fn ecdsa_sign_emits_canonical_low_s() {
962 let private_key = decode_hex::<48>(
963 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
964 96d5724e4c70a825f872c9ea60d2edf5",
965 );
966 let key = SecretKey::from_bytes(&private_key).unwrap();
967 for msg in [&b"sample"[..], b"test", b"", b"another message"] {
968 let sig = key.sign(msg).unwrap();
969 let s = Scalar::from_bytes(sig[48..].try_into().unwrap()).unwrap();
970 assert!(!s.is_high(), "sign produced a high-s signature for {:?}", msg);
971 }
972 }
973
974 #[test]
975 fn ecdsa_verify_strict_rejects_high_s() {
976 let private_key = decode_hex::<48>(
977 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
978 96d5724e4c70a825f872c9ea60d2edf5",
979 );
980 let key = SecretKey::from_bytes(&private_key).unwrap();
981 let public_key = key.public_key();
982 let signature = key.sign(b"sample").unwrap();
983
984 assert!(public_key.verify(b"sample", &signature).is_ok());
986 assert!(public_key.verify_strict(b"sample", &signature).is_ok());
987
988 let r = Scalar::from_bytes(signature[..48].try_into().unwrap()).unwrap();
990 let s = Scalar::from_bytes(signature[48..].try_into().unwrap()).unwrap();
991 let high_s = Scalar::ZERO.sub(s);
992 assert!(high_s.is_high());
993
994 let mut malleable = [0u8; SIGNATURE_SIZE];
995 malleable[..48].copy_from_slice(&r.to_bytes());
996 malleable[48..].copy_from_slice(&high_s.to_bytes());
997
998 assert!(public_key.verify(b"sample", &malleable).is_ok());
999 assert!(public_key.verify_strict(b"sample", &malleable).is_err());
1000 }
1001
1002 #[test]
1003 fn scalar_from_bytes_rejects_boundary_values() {
1004 let zero = [0u8; 48];
1005 assert!(Scalar::from_bytes(&zero).is_none());
1006
1007 let n_bytes = decode_hex::<48>(
1008 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1009 581a0db248b0a77aecec196accc52973",
1010 );
1011 assert!(Scalar::from_bytes(&n_bytes).is_none());
1012
1013 let n_minus_1 = decode_hex::<48>(
1014 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1015 581a0db248b0a77aecec196accc52972",
1016 );
1017 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1018
1019 let one = decode_hex::<48>(
1020 "0000000000000000000000000000000000000000000000000000000000000000\
1021 00000000000000000000000000000001",
1022 );
1023 assert!(Scalar::from_bytes(&one).is_some());
1024 }
1025
1026 #[test]
1027 fn field_element_from_bytes_rejects_boundary_values() {
1028 let p_bytes = decode_hex::<48>(
1029 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
1030 );
1031 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1032
1033 let p_minus_1 = decode_hex::<48>(
1034 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffe",
1035 );
1036 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1037
1038 let zero = [0u8; 48];
1039 assert!(FieldElement::from_bytes(&zero).is_some());
1040 }
1041
1042 #[test]
1043 fn point_decompression_round_trip() {
1044 let keys: &[&str] = &[
1045 "0000000000000000000000000000000000000000000000000000000000000000\
1046 00000000000000000000000000000001",
1047 "0000000000000000000000000000000000000000000000000000000000000000\
1048 00000000000000000000000000000002",
1049 "6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d8\
1050 96d5724e4c70a825f872c9ea60d2edf5",
1051 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011\
1052 2233445566778899aabbccddeeff0011",
1053 ];
1054
1055 for key_hex in keys {
1056 let private_key = decode_hex::<48>(key_hex);
1057 let key = SecretKey::from_bytes(&private_key).unwrap();
1058 let uncompressed = key.public_key();
1059 let compressed = derive_public_key_compressed(&private_key).unwrap();
1060
1061 let sig = key.sign(b"round-trip").unwrap();
1062 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
1063 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1064 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
1065
1066 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1067 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
1068 }
1069 }
1070
1071 #[test]
1072 fn scalar_inversion_correctness() {
1073 let k = Scalar::from_bytes(&decode_hex::<48>(
1074 "c22b201cc45cd130ef80acfc70e84fa17b91b0ffbfe4c9c44eda37e1ad1d7f8f\
1075 ae4c4c8b52559930e08ba1c822c105b0",
1076 ))
1077 .unwrap();
1078 let k_inv = k.invert().unwrap();
1079 let product = k.mul(k_inv);
1080 assert_eq!(product, Scalar::ONE);
1081 }
1082
1083 #[test]
1084 fn field_element_inversion_correctness() {
1085 let x = FieldElement::from_bytes(&decode_hex::<48>(
1086 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1087 5502f25dbf55296c3a545e3872760ab7",
1088 ))
1089 .unwrap();
1090 let x_inv = x.invert().unwrap();
1091 let product = x.mul(x_inv);
1092 assert_eq!(product, FieldElement::ONE);
1093 }
1094
1095 #[test]
1096 fn p384_fast_mul_mod_matches_generic() {
1097 for _ in 0..1000 {
1098 let a_bytes: [u8; 48] = rand::random();
1099 let b_bytes: [u8; 48] = rand::random();
1100 let a_opt = FieldElement::from_bytes(&a_bytes);
1101 let b_opt = FieldElement::from_bytes(&b_bytes);
1102 if a_opt.is_none() || b_opt.is_none() {
1103 continue;
1104 }
1105 let a = a_opt.unwrap();
1106 let b = b_opt.unwrap();
1107 let expected = U384::from_limbs({
1108 let mut p = [0u64; 12];
1109 for i in 0..6 {
1110 let mut c = 0u64;
1111 for j in 0..6 {
1112 let (v, cc) = mac(p[i + j], a.0.limbs[i], b.0.limbs[j], c);
1113 p[i + j] = v;
1114 c = cc;
1115 }
1116 p[i + 6] = c;
1117 }
1118 let mut rem = [0u64; 6];
1119 for bi in (0..768).rev() {
1120 let li = bi / 64;
1121 let pi = bi % 64;
1122 let bit = ((p[li] >> pi) & 1) as u64;
1123 let mut shifted = [0u64; 6];
1124 let mut carry = bit;
1125 for j in 0..6 {
1126 let next = rem[j] >> 63;
1127 shifted[j] = (rem[j] << 1) | carry;
1128 carry = next;
1129 }
1130 let (red, br) = U384::from_limbs(shifted).sub_raw(&MODULUS_P);
1131 if carry == 1 || br == 0 {
1132 rem = red.limbs;
1133 } else {
1134 rem = shifted;
1135 }
1136 }
1137 rem
1138 });
1139 let fast = p384_fast_mul_mod(&a.0, &b.0);
1140 assert_eq!(expected, fast, "mismatch in p384_fast_mul_mod");
1141 }
1142 }
1143
1144 #[test]
1145 fn scalar_mul_generator_n_gives_identity() {
1146 let n_minus_1 = Scalar::from_bytes(&decode_hex::<48>(
1147 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf\
1148 581a0db248b0a77aecec196accc52972",
1149 ))
1150 .unwrap();
1151 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
1152 assert_eq!(result.x, FieldElement::from_uint(GENERATOR_X));
1153 let neg_gy = FieldElement::from_uint(GENERATOR_Y).negate();
1154 assert_eq!(result.y, neg_gy);
1155 }
1156
1157 #[test]
1158 fn ecdh_rejects_invalid_private_key_zero() {
1159 let zero_key = [0u8; 48];
1160 assert!(SecretKey::from_bytes(&zero_key).is_err());
1161 let bob = SecretKey::generate().unwrap();
1162 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1163 }
1164
1165 #[test]
1166 fn ecdsa_rejects_non_canonical_r_and_s() {
1167 let key = SecretKey::generate().unwrap();
1168 let valid_sig = key.sign(b"msg").unwrap();
1169
1170 let mut bad_r = valid_sig;
1171 bad_r[..48].copy_from_slice(&decode_hex::<48>(
1172 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
1173 ));
1174 assert!(key.public_key().verify(b"msg", &bad_r).is_err());
1175
1176 let mut bad_s = valid_sig;
1177 bad_s[48..].copy_from_slice(&decode_hex::<48>(
1178 "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
1179 ));
1180 assert!(key.public_key().verify(b"msg", &bad_s).is_err());
1181 }
1182
1183 #[test]
1184 fn verify_rejects_tampered_message_and_signature() {
1185 let key = SecretKey::generate().unwrap();
1186 let pub_key = key.public_key();
1187 let sig = key.sign(b"message").unwrap();
1188
1189 assert!(pub_key.verify(b"tampered", &sig).is_err());
1190
1191 let mut bad_sig = sig;
1192 bad_sig[10] ^= 0x80;
1193 assert!(pub_key.verify(b"message", &bad_sig).is_err());
1194 }
1195
1196 #[test]
1197 fn public_key_rejects_off_curve_point() {
1198 let key = SecretKey::generate().unwrap();
1199 let mut off_curve = key.public_key().to_bytes();
1200 off_curve[96] ^= 0x01;
1201 assert!(!is_valid_public_key(&off_curve));
1202 assert!(PublicKey::from_bytes(&off_curve).is_err());
1203 }
1204
1205 #[test]
1206 fn x_y_round_trip() {
1207 let key = SecretKey::generate().unwrap();
1208 let pub_key = key.public_key();
1209 let (x, y) = pub_key.x_y();
1210 let pub_key2 = PublicKey::from_x_y(&x, &y).unwrap();
1211 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1212 }
1213
1214 #[test]
1215 fn from_x_y_matches_generator() {
1216 let key = PublicKey::from_x_y(
1217 &decode_hex::<48>(
1218 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1219 5502f25dbf55296c3a545e3872760ab7",
1220 ),
1221 &decode_hex::<48>(
1222 "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0\
1223 0a60b1ce1d7e819d7a431d7c90ea0e5f",
1224 ),
1225 )
1226 .unwrap();
1227 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
1228 assert_eq!(key, from_sec1);
1229 }
1230
1231 #[test]
1232 fn field_element_add_sub_mul_consistency() {
1233 let a = FieldElement::from_bytes(&decode_hex::<48>(
1234 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1235 5502f25dbf55296c3a545e3872760ab7",
1236 ))
1237 .unwrap();
1238 let b = FieldElement::from_bytes(&decode_hex::<48>(
1239 "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0\
1240 0a60b1ce1d7e819d7a431d7c90ea0e5f",
1241 ))
1242 .unwrap();
1243
1244 assert_eq!(a.add(b).sub(b), a);
1245 assert_eq!(a.add(b), b.add(a));
1246 assert_eq!(a.mul(b), b.mul(a));
1247
1248 let c = FieldElement::from_bytes(&decode_hex::<48>(
1249 "2a85c8edd3ec2aefc656398d8a2ed19d0314088f5013875a181d9c6efe814112\
1250 988e056be3f82d19b3312fa7e23ee7e4",
1251 ))
1252 .unwrap();
1253 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
1254 }
1255
1256 #[test]
1257 fn scalar_add_sub_mul_consistency() {
1258 let a = Scalar::from_bytes(&decode_hex::<48>(
1259 "c22b201cc45cd130ef80acfc70e84fa17b91b0ffbfe4c9c44eda37e1ad1d7f8f\
1260 ae4c4c8b52559930e08ba1c822c105b0",
1261 ))
1262 .unwrap();
1263 let one = Scalar::from_bytes(&decode_hex::<48>(
1264 "0000000000000000000000000000000000000000000000000000000000000000\
1265 00000000000000000000000000000001",
1266 ))
1267 .unwrap();
1268
1269 assert_eq!(a.add(one).sub(one), a);
1270 assert_eq!(a.mul(one), a);
1271
1272 let b = Scalar::from_bytes(&decode_hex::<48>(
1273 "7cf1be7a45d8d72e6e974229bfad108f3d2d4aa6208248adb9343258e4f30f80\
1274 8252a11a87ddc7e0d8ba3b5e28878944",
1275 ))
1276 .unwrap();
1277 assert_eq!(a.mul(b), b.mul(a));
1278 assert_eq!(a.add(b), b.add(a));
1279 }
1280
1281 #[test]
1282 fn field_element_negate_round_trip() {
1283 let x = FieldElement::from_bytes(&decode_hex::<48>(
1284 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38\
1285 5502f25dbf55296c3a545e3872760ab7",
1286 ))
1287 .unwrap();
1288 let neg = x.negate();
1289 assert_eq!(neg.negate(), x);
1290 assert_eq!(x.add(neg), FieldElement::ZERO);
1291 }
1292
1293 #[test]
1294 fn scalar_mul_by_two_matches_double() {
1295 let two = Scalar::from_bytes(&decode_hex::<48>(
1296 "0000000000000000000000000000000000000000000000000000000000000000\
1297 00000000000000000000000000000002",
1298 ))
1299 .unwrap();
1300 let g_times_2 = scalar_mul_affine(&AffinePoint::GENERATOR, &two).to_affine().unwrap();
1301 let proj_g = ProjectivePoint::from_affine(&AffinePoint::GENERATOR);
1302 let g_doubled = proj_g.double().to_affine().unwrap();
1303
1304 assert_eq!(g_times_2.to_uncompressed_bytes(), g_doubled.to_uncompressed_bytes());
1305 }
1306
1307 #[test]
1308 fn ecdsa_sign_then_verify_consistent_for_random_keys() {
1309 for _ in 0..5 {
1310 let key = SecretKey::generate().unwrap();
1311 let msg = rand::random::<[u8; 32]>();
1312 let sig = key.sign(&msg).unwrap();
1313 assert!(key.public_key().verify(&msg, &sig).is_ok());
1314 }
1315 }
1316
1317 #[test]
1318 fn is_on_curve_accepts_generator_and_random_points() {
1319 assert!(AffinePoint::GENERATOR.is_on_curve());
1320 for _ in 0..5 {
1321 let key = SecretKey::generate().unwrap();
1322 let pb = key.public_key().to_bytes();
1323 let pk = PublicKey::from_bytes(&pb).unwrap();
1324 let _ = pk;
1325 }
1326 }
1327
1328 #[test]
1329 fn ecdh_with_self_is_consistent() {
1330 let key = SecretKey::generate().unwrap();
1331 let shared1 = key.ecdh(&key.public_key()).unwrap();
1332 let shared2 = key.ecdh(&key.public_key()).unwrap();
1333 assert_eq!(shared1, shared2);
1334 }
1335
1336 #[test]
1337 fn field_element_pow_correctness() {
1338 let x = FieldElement::from_bytes(&decode_hex::<48>(
1339 "0000000000000000000000000000000000000000000000000000000000000000\
1340 00000000000000000000000000000002",
1341 ))
1342 .unwrap();
1343 let x3 = x.pow(&U384::from_u64(3));
1344 let expected = x.mul(x).mul(x);
1345 assert_eq!(x3, expected);
1346
1347 let x0 = x.pow(&U384::ZERO);
1348 assert_eq!(x0, FieldElement::ONE);
1349 }
1350
1351 #[test]
1354 fn wycheproof_ecdsa_p384_sha384_p1363() {
1355 let data: serde_json::Value = serde_json::from_str(include_str!(
1356 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp384r1_sha384_p1363_test.json"
1357 ))
1358 .unwrap();
1359 let mut valid_tested = 0u64;
1360 let mut invalid_tested = 0u64;
1361 for group in data["testGroups"].as_array().unwrap() {
1362 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1363 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1364 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1365
1366 for test in group["tests"].as_array().unwrap() {
1367 let msg_hex = test["msg"].as_str().unwrap();
1368 let sig_hex = test["sig"].as_str().unwrap();
1369 let result = test["result"].as_str().unwrap();
1370
1371 let msg = hex::decode(msg_hex).unwrap();
1372
1373 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1374 continue;
1375 }
1376 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1377
1378 let verify_result = pk.verify(&msg, &sig);
1379
1380 if result == "valid" {
1381 assert!(
1382 verify_result.is_ok(),
1383 "wycheproof ECDSA P384 P1363 tcId={} expected valid but failed",
1384 test["tcId"]
1385 );
1386 valid_tested += 1;
1387 } else {
1388 assert!(
1389 verify_result.is_err(),
1390 "wycheproof ECDSA P384 P1363 tcId={} expected invalid but passed",
1391 test["tcId"]
1392 );
1393 invalid_tested += 1;
1394 }
1395 }
1396 }
1397 assert!(valid_tested > 0, "no valid ECDSA P384 P1363 wycheproof tests were run");
1398 assert!(invalid_tested > 0, "no invalid ECDSA P384 P1363 wycheproof tests were run");
1399 }
1400
1401 #[test]
1402 fn wycheproof_ecdsa_p384_sha384_der() {
1403 let data: serde_json::Value = serde_json::from_str(include_str!(
1404 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp384r1_sha384_test.json"
1405 ))
1406 .unwrap();
1407 let mut valid_tested = 0u64;
1408 let mut invalid_tested = 0u64;
1409 for group in data["testGroups"].as_array().unwrap() {
1410 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1411 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1412 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1413
1414 for test in group["tests"].as_array().unwrap() {
1415 let msg_hex = test["msg"].as_str().unwrap();
1416 let sig_hex = test["sig"].as_str().unwrap();
1417 let result = test["result"].as_str().unwrap();
1418
1419 let msg = hex::decode(msg_hex).unwrap();
1420 let der_sig = hex::decode(sig_hex).unwrap();
1421 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
1422 continue;
1423 };
1424
1425 let verify_result = pk.verify(&msg, &sig);
1426
1427 if result == "valid" {
1428 assert!(
1429 verify_result.is_ok(),
1430 "wycheproof ECDSA P384 DER SHA-384 tcId={} expected valid but failed",
1431 test["tcId"]
1432 );
1433 valid_tested += 1;
1434 } else {
1435 assert!(
1436 verify_result.is_err(),
1437 "wycheproof ECDSA P384 DER SHA-384 tcId={} expected invalid but passed",
1438 test["tcId"]
1439 );
1440 invalid_tested += 1;
1441 }
1442 }
1443 }
1444 assert!(valid_tested > 0, "no valid ECDSA P384 DER SHA-384 wycheproof tests were run");
1445 assert!(
1446 invalid_tested > 0,
1447 "no invalid ECDSA P384 DER SHA-384 wycheproof tests were run"
1448 );
1449 }
1450
1451 #[test]
1452 fn wycheproof_ecdh_p384_ecpoint() {
1453 let data: serde_json::Value = serde_json::from_str(include_str!(
1454 "../../testdata/wycheproof/testvectors_v1/ecdh_secp384r1_ecpoint_test.json"
1455 ))
1456 .unwrap();
1457 let mut valid_tested = 0u64;
1458 let mut invalid_tested = 0u64;
1459 let mut acceptable_tested = 0u64;
1460 for group in data["testGroups"].as_array().unwrap() {
1461 if group["curve"].as_str() != Some("secp384r1") {
1462 continue;
1463 }
1464 for test in group["tests"].as_array().unwrap() {
1465 let public_hex = test["public"].as_str().unwrap();
1466 let private_hex = test["private"].as_str().unwrap();
1467 let expected_shared_hex = test["shared"].as_str().unwrap();
1468 let result = test["result"].as_str().unwrap();
1469
1470 let public_key = hex::decode(public_hex).unwrap();
1471
1472 let private_bytes = hex::decode(private_hex).unwrap();
1473 let mut private_key = [0u8; SECRET_KEY_SIZE];
1474 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1475 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
1476 private_bytes.len() - SECRET_KEY_SIZE
1477 } else {
1478 0
1479 };
1480 private_key[SECRET_KEY_SIZE - effective_len..]
1481 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1482
1483 let shared = ecdh(&private_key, &public_key);
1484
1485 if result == "valid" {
1486 let shared = shared.unwrap();
1487 let shared_hex = hex::encode(shared);
1488 assert_eq!(
1489 shared_hex, expected_shared_hex,
1490 "wycheproof ECDH P384 ecpoint tcId={}",
1491 test["tcId"]
1492 );
1493 valid_tested += 1;
1494 } else if result == "invalid" {
1495 assert!(
1496 shared.is_err(),
1497 "wycheproof ECDH P384 ecpoint tcId={} expected invalid but passed",
1498 test["tcId"]
1499 );
1500 invalid_tested += 1;
1501 } else {
1502 acceptable_tested += 1;
1503 }
1504 }
1505 }
1506 assert!(valid_tested > 0, "no valid ECDH P384 ecpoint wycheproof tests were run");
1507 assert!(invalid_tested > 0, "no invalid ECDH P384 ecpoint wycheproof tests were run");
1508 assert!(
1509 acceptable_tested > 0,
1510 "no acceptable ECDH P384 ecpoint wycheproof tests were run"
1511 );
1512 }
1513
1514 #[test]
1515 fn wycheproof_ecdh_p384_asn() {
1516 let data: serde_json::Value = serde_json::from_str(include_str!(
1517 "../../testdata/wycheproof/testvectors_v1/ecdh_secp384r1_test.json"
1518 ))
1519 .unwrap();
1520 let mut valid_tested = 0u64;
1521 let mut invalid_tested = 0u64;
1522 let mut acceptable_tested = 0u64;
1523 for group in data["testGroups"].as_array().unwrap() {
1524 for test in group["tests"].as_array().unwrap() {
1525 let public_hex = test["public"].as_str().unwrap();
1526 let private_hex = test["private"].as_str().unwrap();
1527 let expected_shared_hex = test["shared"].as_str().unwrap();
1528 let result = test["result"].as_str().unwrap();
1529
1530 let spki_der = hex::decode(public_hex).unwrap();
1531 let Some(sec1_point) = spki_to_sec1_point(&spki_der) else {
1532 if result == "valid" {
1533 panic!("wycheproof ECDH P384 ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
1534 }
1535 invalid_tested += 1;
1536 continue;
1537 };
1538
1539 let private_bytes = hex::decode(private_hex).unwrap();
1540 let mut private_key = [0u8; SECRET_KEY_SIZE];
1541 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1542 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
1543 private_bytes.len() - SECRET_KEY_SIZE
1544 } else {
1545 0
1546 };
1547 private_key[SECRET_KEY_SIZE - effective_len..]
1548 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1549
1550 let shared = ecdh(&private_key, &sec1_point);
1551
1552 if result == "valid" {
1553 let shared = shared.unwrap();
1554 let shared_hex = hex::encode(shared);
1555 assert_eq!(
1556 shared_hex, expected_shared_hex,
1557 "wycheproof ECDH P384 ASN tcId={}",
1558 test["tcId"]
1559 );
1560 valid_tested += 1;
1561 } else if result == "invalid" {
1562 assert!(
1563 shared.is_err(),
1564 "wycheproof ECDH P384 ASN tcId={} expected invalid but passed",
1565 test["tcId"]
1566 );
1567 invalid_tested += 1;
1568 } else {
1569 acceptable_tested += 1;
1570 }
1571 }
1572 }
1573 assert!(valid_tested > 0, "no valid ECDH P384 ASN wycheproof tests were run");
1574 assert!(invalid_tested > 0, "no invalid ECDH P384 ASN wycheproof tests were run");
1575 assert!(acceptable_tested > 0, "no acceptable ECDH P384 ASN wycheproof tests were run");
1576 }
1577
1578 #[test]
1580 fn generator_point_is_on_curve() {
1581 p_curves::test_support::generator_point_is_on_curve::<P384>();
1582 }
1583
1584 #[test]
1585 fn from_x_y_rejects_off_curve() {
1586 p_curves::test_support::from_x_y_rejects_off_curve::<P384>();
1587 }
1588
1589 #[test]
1590 fn ecdh_round_trip_alice_bob() {
1591 p_curves::test_support::ecdh_round_trip_alice_bob::<P384>();
1592 }
1593
1594 #[test]
1595 fn ecdh_rejects_off_curve_peer_public_key() {
1596 p_curves::test_support::ecdh_rejects_off_curve_peer_public_key::<P384>();
1597 }
1598
1599 #[test]
1600 fn ecdh_rejects_infinity_peer_public_key() {
1601 p_curves::test_support::ecdh_rejects_infinity_peer_public_key::<P384>();
1602 }
1603
1604 #[test]
1605 fn ecdh_rejects_bad_length_peer_public_key() {
1606 p_curves::test_support::ecdh_rejects_bad_length_peer_public_key::<P384>();
1607 }
1608
1609 #[test]
1610 fn ecdh_multiple_exchanges_consistency() {
1611 p_curves::test_support::ecdh_multiple_exchanges_consistency::<P384>();
1612 }
1613
1614 #[test]
1615 fn private_key_round_trip_bytes() {
1616 p_curves::test_support::private_key_round_trip_bytes::<P384>();
1617 }
1618
1619 #[test]
1620 fn public_key_round_trip_bytes() {
1621 p_curves::test_support::public_key_round_trip_bytes::<P384>();
1622 }
1623
1624 #[test]
1625 fn point_double_and_add_consistency() {
1626 p_curves::test_support::point_double_and_add_consistency::<P384>();
1627 }
1628
1629 #[test]
1630 fn compressed_public_key_has_correct_prefix() {
1631 p_curves::test_support::compressed_public_key_has_correct_prefix::<P384>();
1632 }
1633
1634 #[cfg(feature = "zeroize")]
1635 #[test]
1636 fn rfc6979_state_zeroize_clears_drbg() {
1637 p_curves::test_support::rfc6979_state_zeroize_clears_drbg::<P384>();
1638 }
1639}