1use big_number::{Uint, mac};
7
8use super::p_curves::{self, Curve, UintOps, field_pow};
9use crate::{EllipticCurveError, Hasher, RandomError, hmac::Hmac, sha2::Sha256};
10
11pub const SECRET_KEY_SIZE: usize = 32;
13pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 33;
15pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 65;
17pub const SIGNATURE_SIZE: usize = 64;
19pub const ECDH_SHARED_SECRET_SIZE: usize = 32;
22
23#[derive(Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
54pub struct SecretKey(p_curves::SecretKey<P256>);
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<P256>);
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; 32], y_bytes: &[u8; 32]) -> 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; 32], [u8; 32]) {
178 self.0.x_y()
179 }
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184struct P256;
185
186type U256 = Uint<256, 4>;
187type CurveUint = U256;
188
189const MODULUS_P: CurveUint = CurveUint::from_limbs([
190 0xffff_ffff_ffff_ffff,
191 0x0000_0000_ffff_ffff,
192 0x0000_0000_0000_0000,
193 0xffff_ffff_0000_0001,
194]);
195
196const MODULUS_N: CurveUint = CurveUint::from_limbs([
197 0xf3b9_cac2_fc63_2551,
198 0xbce6_faad_a717_9e84,
199 0xffff_ffff_ffff_ffff,
200 0xffff_ffff_0000_0000,
201]);
202
203const N_MU: [u64; 5] = [
206 0x012ffd85eedf9bfe,
207 0x43190552df1a6c21,
208 0xfffffffeffffffff,
209 0x00000000ffffffff,
210 0x0000000000000001,
211];
212
213const N_HALF: CurveUint = CurveUint::from_limbs([
216 0x79dc_e561_7e31_92a8,
217 0xde73_7d56_d38b_cf42,
218 0x7fff_ffff_ffff_ffff,
219 0x7fff_ffff_8000_0000,
220]);
221
222const P_MINUS_TWO: CurveUint = CurveUint::from_limbs([
223 0xffff_ffff_ffff_fffd,
224 0x0000_0000_ffff_ffff,
225 0x0000_0000_0000_0000,
226 0xffff_ffff_0000_0001,
227]);
228
229const P_PLUS_ONE_OVER_FOUR: CurveUint = CurveUint::from_limbs([
230 0x0000_0000_0000_0000,
231 0x0000_0000_4000_0000,
232 0x4000_0000_0000_0000,
233 0x3fff_ffff_c000_0000,
234]);
235
236const N_MINUS_TWO: CurveUint = CurveUint::from_limbs([
237 0xf3b9_cac2_fc63_254f,
238 0xbce6_faad_a717_9e84,
239 0xffff_ffff_ffff_ffff,
240 0xffff_ffff_0000_0000,
241]);
242
243const CURVE_B: CurveUint = CurveUint::from_limbs([
244 0x3bce_3c3e_27d2_604b,
245 0x651d_06b0_cc53_b0f6,
246 0xb3eb_bd55_7698_86bc,
247 0x5ac6_35d8_aa3a_93e7,
248]);
249
250const GENERATOR_X: CurveUint = CurveUint::from_limbs([
251 0xf4a1_3945_d898_c296,
252 0x7703_7d81_2deb_33a0,
253 0xf8bc_e6e5_63a4_40f2,
254 0x6b17_d1f2_e12c_4247,
255]);
256
257const GENERATOR_Y: CurveUint = CurveUint::from_limbs([
258 0xcbb6_4068_37bf_51f5,
259 0x2bce_3357_6b31_5ece,
260 0x8ee7_eb4a_7c0f_9e16,
261 0x4fe3_42e2_fe1a_7f9b,
262]);
263
264const S4: [u64; 4] = [
267 0x0000000000000001,
268 0xffffffff00000000,
269 0xffffffffffffffff,
270 0x00000000fffffffe,
271];
272
273const S5: [u64; 4] = [
274 0x00000000ffffffff,
275 0x0000000100000001,
276 0xfffffffeffffffff,
277 0xfffffffe00000000,
278];
279
280const S6: [u64; 4] = [
281 0xfffffffefffffffe,
282 0x00000002ffffffff,
283 0x0000000000000002,
284 0xfffffffe00000001,
285];
286
287const S7: [u64; 4] = [
288 0xfffffffeffffffff,
289 0xfffffffffffffffe,
290 0x0000000200000000,
291 0x0000000000000003,
292];
293
294#[inline]
296fn ct_select_u128(a: u128, b: u128, choice: bool) -> u128 {
297 let mask = (choice as u128).wrapping_neg();
298 (a & mask) | (b & !mask)
299}
300
301fn p256_fast_mul_mod(a: &CurveUint, b: &CurveUint) -> CurveUint {
304 let al = a.limbs;
305 let bl = b.limbs;
306
307 let mut prod = [0u64; 8];
308 for i in 0..4 {
309 let mut carry = 0u64;
310 for j in 0..4 {
311 let (v, cc) = mac(prod[i + j], al[i], bl[j], carry);
312 prod[i + j] = v;
313 carry = cc;
314 }
315 prod[i + 4] = carry;
316 }
317
318 const MASK: u128 = 0xffffffffffffffff;
319 let c0 = [S4[0] as u128, S4[1] as u128, S4[2] as u128, S4[3] as u128];
320 let c1 = [S5[0] as u128, S5[1] as u128, S5[2] as u128, S5[3] as u128];
321 let c2 = [S6[0] as u128, S6[1] as u128, S6[2] as u128, S6[3] as u128];
322 let c3 = [S7[0] as u128, S7[1] as u128, S7[2] as u128, S7[3] as u128];
323 let coeffs = [c0, c1, c2, c3];
324
325 let mut r0 = prod[0] as u128;
326 let mut r1 = prod[1] as u128;
327 let mut r2 = prod[2] as u128;
328 let mut r3 = prod[3] as u128;
329
330 for i in 0..4 {
331 let w = prod[4 + i] as u128;
332 let c = coeffs[i];
333
334 r0 = r0.wrapping_add(w.wrapping_mul(c[0]));
335 r1 = r1.wrapping_add(w.wrapping_mul(c[1]));
336 r2 = r2.wrapping_add(w.wrapping_mul(c[2]));
337 r3 = r3.wrapping_add(w.wrapping_mul(c[3]));
338
339 for _ in 0..4 {
341 let carry = r0 >> 64;
342 r1 = r1.wrapping_add(carry);
343 r0 &= MASK;
344 let carry = r1 >> 64;
345 r2 = r2.wrapping_add(carry);
346 r1 &= MASK;
347 let carry = r2 >> 64;
348 r3 = r3.wrapping_add(carry);
349 r2 &= MASK;
350
351 let residual = r3 >> 64;
352 let need_reduce = residual != 0;
353
354 let rr3 = r3 & MASK;
356 let rr0 = r0.wrapping_add(residual.wrapping_mul(c0[0]));
357 let rr1 = r1.wrapping_add(residual.wrapping_mul(c0[1]));
358 let rr2 = r2.wrapping_add(residual.wrapping_mul(c0[2]));
359 let rr3r = rr3.wrapping_add(residual.wrapping_mul(c0[3]));
360
361 r0 = ct_select_u128(rr0, r0, need_reduce);
363 r1 = ct_select_u128(rr1, r1, need_reduce);
364 r2 = ct_select_u128(rr2, r2, need_reduce);
365 r3 = ct_select_u128(rr3r, r3, need_reduce);
366 }
367 }
368
369 let mut result = CurveUint::from_limbs([r0 as u64, r1 as u64, r2 as u64, r3 as u64]);
371 for _ in 0..8 {
372 let (sub, borrow) = result.sub_raw(&MODULUS_P);
373 result = CurveUint::ct_select(&sub, &result, borrow == 0);
374 }
375 result
376}
377
378#[inline]
380fn reduce_mod(value: CurveUint) -> CurveUint {
381 let (sub_value, _) = value.sub_raw(&MODULUS_N);
382 CurveUint::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N))
383}
384
385impl Curve for P256 {
386 type U = CurveUint;
387 type FieldBytes = [u8; SECRET_KEY_SIZE];
388 type DigestBytes = [u8; 32];
389 type CompressedBytes = [u8; PUBLIC_KEY_COMPRESSED_SIZE];
390 type UncompressedBytes = [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
391 type SignatureBytes = [u8; SIGNATURE_SIZE];
392
393 const FIELD_BITS: usize = 256;
394 const FIELD_BYTES: usize = SECRET_KEY_SIZE;
395 const DIGEST_BYTES: usize = 32;
396 const COMPRESSED_BYTES: usize = PUBLIC_KEY_COMPRESSED_SIZE;
397 const UNCOMPRESSED_BYTES: usize = PUBLIC_KEY_UNCOMPRESSED_SIZE;
398
399 const MODULUS_P: CurveUint = MODULUS_P;
400 const MODULUS_N: CurveUint = MODULUS_N;
401 const N_HALF: CurveUint = N_HALF;
402 const P_MINUS_TWO: CurveUint = P_MINUS_TWO;
403 const N_MINUS_TWO: CurveUint = N_MINUS_TWO;
404 const CURVE_B: CurveUint = CURVE_B;
405 const GENERATOR_X: CurveUint = GENERATOR_X;
406 const GENERATOR_Y: CurveUint = GENERATOR_Y;
407
408 #[inline]
409 fn field_mul(a: &Self::U, b: &Self::U) -> Self::U {
410 p256_fast_mul_mod(a, b)
411 }
412
413 #[inline]
414 fn scalar_mul(a: &Self::U, b: &Self::U) -> Self::U {
415 a.mul_mod_barrett_w::<10>(b, &MODULUS_N, &N_MU)
416 }
417
418 #[inline]
419 fn field_sqrt(a: Self::U) -> Option<Self::U> {
420 let candidate = field_pow::<Self>(a, &P_PLUS_ONE_OVER_FOUR);
421 if a.ct_eq(&Self::field_mul(&candidate, &candidate)) {
422 Some(candidate)
423 } else {
424 None
425 }
426 }
427
428 #[inline]
429 fn hash(data: &[u8]) -> Self::DigestBytes {
430 Sha256::hash(data).as_ref().try_into().unwrap()
431 }
432
433 #[inline]
434 fn hmac(key: &[u8], data: &[u8]) -> Self::DigestBytes {
435 Hmac::<Sha256>::mac(key, data).as_ref().try_into().unwrap()
436 }
437
438 #[inline]
439 fn scalar_from_digest(digest: &Self::DigestBytes) -> Self::U {
440 reduce_mod(CurveUint::read_be(digest.as_ref()))
441 }
442
443 #[inline]
444 fn scalar_from_field_bytes(bytes: &Self::FieldBytes) -> Self::U {
445 reduce_mod(CurveUint::read_be(bytes.as_ref()))
446 }
447
448 #[cfg(feature = "random")]
449 #[inline]
450 fn random_secret_key() -> Result<Self::FieldBytes, RandomError> {
451 crate::random::bytes()
452 }
453}
454
455pub fn is_valid_public_key(public_key: &[u8]) -> bool {
458 p_curves::is_valid_public_key::<P256>(public_key)
459}
460
461#[cfg(test)]
462mod tests {
463 #![allow(dead_code)]
464 use super::*;
465 use crate::p_curves::p_curves;
466
467 type FieldElement = p_curves::FieldElement<P256>;
468 type Scalar = p_curves::Scalar<P256>;
469 type AffinePoint = p_curves::AffinePoint<P256>;
470 type ProjectivePoint = p_curves::ProjectivePoint<P256>;
471 type Rfc6979 = p_curves::Rfc6979<P256>;
472
473 fn hash_message(message: &[u8]) -> [u8; 32] {
475 p_curves::hash_message::<P256>(message)
476 }
477
478 fn hmac_digest(key: &[u8], data: &[u8]) -> [u8; 32] {
479 p_curves::hmac_digest::<P256>(key, data)
480 }
481
482 fn bits2octets(hash: &[u8; 32]) -> [u8; SECRET_KEY_SIZE] {
483 p_curves::bits2octets::<P256>(hash)
484 }
485
486 fn derive_public_key_uncompressed(
487 private_key: &[u8; SECRET_KEY_SIZE],
488 ) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], crate::EllipticCurveError> {
489 p_curves::derive_public_key_uncompressed::<P256>(private_key)
490 }
491
492 fn derive_public_key_compressed(
493 private_key: &[u8; SECRET_KEY_SIZE],
494 ) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], crate::EllipticCurveError> {
495 p_curves::derive_public_key_compressed::<P256>(private_key)
496 }
497
498 fn ecdsa_sign_inner_impl(
499 scalar: &Scalar,
500 message: &[u8],
501 force_first_retry: bool,
502 ) -> Result<[u8; SIGNATURE_SIZE], crate::EllipticCurveError> {
503 p_curves::ecdsa_sign_inner_impl::<P256>(scalar, message, force_first_retry)
504 }
505
506 fn ecdsa_verify_inner(
507 public_point: &AffinePoint,
508 message: &[u8],
509 signature: &[u8; SIGNATURE_SIZE],
510 ) -> Result<(), crate::EllipticCurveError> {
511 p_curves::ecdsa_verify_inner::<P256>(public_point, message, signature)
512 }
513
514 fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, crate::EllipticCurveError> {
515 p_curves::parse_public_key::<P256>(public_key)
516 }
517
518 fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
519 p_curves::scalar_mul_generator::<P256>(scalar)
520 }
521
522 fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
523 p_curves::scalar_mul_affine::<P256>(base, scalar)
524 }
525
526 #[test]
529 fn mul_double_matches_separate_scalar_multiplications() {
530 let g = AffinePoint::GENERATOR;
531 let mut state = 0x1234_5678_9abc_def0u64;
532 for _ in 0..200 {
533 let mut bytes = [0u8; SECRET_KEY_SIZE];
534 for b in bytes.iter_mut() {
535 state ^= state << 13;
536 state ^= state >> 7;
537 state ^= state << 17;
538 *b = state as u8;
539 }
540 let u1 = Scalar::from_reduced_bytes(&bytes);
541 state ^= state << 13;
542 state ^= state >> 7;
543 state ^= state << 17;
544 let mut bytes2 = [0u8; SECRET_KEY_SIZE];
545 for b in bytes2.iter_mut() {
546 state ^= state << 13;
547 state ^= state >> 7;
548 state ^= state << 17;
549 *b = state as u8;
550 }
551 let u2 = Scalar::from_reduced_bytes(&bytes2);
552
553 let expected = scalar_mul_generator(&u1).add(&p_curves::scalar_mul_affine::<P256>(&g, &u2));
554 let got = p_curves::mul_double::<P256>(&u1, &g, &u2, &g);
555 assert_eq!(got.to_affine(), expected.to_affine(), "mul_double mismatch");
556 }
557
558 let zero = Scalar::ZERO;
560 let one = Scalar::ONE;
561 assert_eq!(
562 p_curves::mul_double::<P256>(&zero, &g, &one, &g).to_affine(),
563 scalar_mul_generator(&one).to_affine()
564 );
565 assert_eq!(
566 p_curves::mul_double::<P256>(&one, &g, &zero, &g).to_affine(),
567 scalar_mul_generator(&one).to_affine()
568 );
569 assert!(p_curves::mul_double::<P256>(&zero, &g, &zero, &g).is_identity());
570 }
571
572 fn ecdh(
574 secret_key: &[u8; SECRET_KEY_SIZE],
575 peer_public_key: &[u8],
576 ) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], crate::EllipticCurveError> {
577 SecretKey::from_bytes(secret_key)?.ecdh(&PublicKey::from_bytes(peer_public_key)?)
578 }
579
580 #[cfg(feature = "zeroize")]
581 #[test]
582 fn secret_key_zeroize_clears_scalar() {
583 use zeroize::Zeroize;
584
585 let mut key = SecretKey::from_bytes(&[1u8; SECRET_KEY_SIZE]).unwrap();
586 assert_ne!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
587 key.zeroize();
588 assert_eq!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
589 }
590
591 fn decode_hex<const N: usize>(hex_bytes: &str) -> [u8; N] {
592 let bytes = hex::decode(hex_bytes).unwrap();
593 assert_eq!(bytes.len(), N);
594 let mut out = [0u8; N];
595 out.copy_from_slice(&bytes);
596 out
597 }
598
599 fn der_read_tlv<'a>(data: &'a [u8], offset: &mut usize) -> Option<(u8, &'a [u8])> {
602 if *offset >= data.len() {
603 return None;
604 }
605 let tag = data[*offset];
606 *offset += 1;
607 if *offset >= data.len() {
608 return None;
609 }
610 let len_byte = data[*offset];
611 *offset += 1;
612 let (len, _) = if len_byte & 0x80 != 0 {
613 let num_bytes = (len_byte & 0x7f) as usize;
614 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
615 return None;
616 }
617 if num_bytes > 1 && data[*offset] == 0 {
620 return None;
621 }
622 let mut l = 0usize;
623 for i in 0..num_bytes {
624 l = (l << 8) | data[*offset + i] as usize;
625 }
626 if l < 128 {
627 return None;
628 }
629 *offset += num_bytes;
630 (l, num_bytes + 1)
631 } else {
632 (len_byte as usize, 1)
633 };
634 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
635 return None;
636 }
637 let value = &data[*offset..*offset + len];
638 *offset = (*offset).checked_add(len)?;
639 Some((tag, value))
640 }
641
642 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; 64]> {
645 let mut offset = 0;
646 let (tag, inner) = der_read_tlv(der, &mut offset)?;
647 if tag != 0x30 {
648 return None;
649 }
650 if offset != der.len() {
652 return None;
653 }
654 let mut inner_offset = 0;
655 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
656 if rtag != 0x02 || rval.is_empty() || rval.len() > 33 {
657 return None;
658 }
659 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
660 if stag != 0x02 || sval.is_empty() || sval.len() > 33 {
661 return None;
662 }
663 if inner_offset != inner.len() {
665 return None;
666 }
667 let r_valid = if rval.len() == 32 && rval[0] >= 0x80 {
672 false
673 } else if rval.len() == 33 && rval[0] != 0 {
674 false
675 } else if rval.len() == 33 && rval[0] == 0 && rval[1] < 0x80 {
676 false
677 } else if rval.len() > 33 {
678 false
679 } else {
680 true
681 };
682 let s_valid = if sval.len() == 32 && sval[0] >= 0x80 {
683 false
684 } else if sval.len() == 33 && sval[0] != 0 {
685 false
686 } else if sval.len() == 33 && sval[0] == 0 && sval[1] < 0x80 {
687 false
688 } else if sval.len() > 33 {
689 false
690 } else {
691 true
692 };
693 if !r_valid || !s_valid {
694 return None;
695 }
696
697 let r_trimmed = if rval.len() == 33 && rval[0] == 0 {
698 &rval[1..]
699 } else {
700 rval
701 };
702 let s_trimmed = if sval.len() == 33 && sval[0] == 0 {
703 &sval[1..]
704 } else {
705 sval
706 };
707 if r_trimmed.len() > 32 || s_trimmed.len() > 32 {
708 return None;
709 }
710 let mut sig = [0u8; 64];
711 sig[32 - r_trimmed.len()..32].copy_from_slice(r_trimmed);
712 sig[64 - s_trimmed.len()..64].copy_from_slice(s_trimmed);
713 Some(sig)
714 }
715
716 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
719 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
720 let secp256r1_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
721 let mut offset = 0;
722 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
723 let mut inner = 0;
724 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
726 if _alg_tag != 0x30 {
727 return None;
728 }
729 let mut ai = 0;
731 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
732 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
733 return None;
734 }
735 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
737 if oid2_tag != 0x06 || oid2 != secp256r1_oid {
738 return None;
739 }
740 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
742 if _bs_tag != 0x03 || bs_val.is_empty() {
743 return None;
744 }
745 Some(bs_val[1..].to_vec())
747 }
748
749 #[test]
750 fn from_x_y_matches_generator() {
751 let key = PublicKey::from_x_y(
752 &hex::decode("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")
753 .unwrap()
754 .try_into()
755 .unwrap(),
756 &hex::decode("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")
757 .unwrap()
758 .try_into()
759 .unwrap(),
760 )
761 .unwrap();
762 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
763 assert_eq!(key, from_sec1);
764 }
765
766 #[test]
767 fn derive_public_key_generator_matches_sec1_base_point() {
768 let mut private_key = [0u8; 32];
769 private_key[31] = 1;
770 let derived = derive_public_key_uncompressed(&private_key).unwrap();
771 let expected = decode_hex::<65>(
772 "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\
773 4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
774 );
775 assert_eq!(derived, expected);
776 }
777
778 #[test]
779 fn derive_public_key_matches_rfc6979_vector() {
780 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
781 let expected = decode_hex::<65>(
782 "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6\
783 7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
784 );
785 assert_eq!(derive_public_key_uncompressed(&private_key).unwrap(), expected);
786 assert_eq!(
787 derive_public_key_compressed(&private_key).unwrap(),
788 decode_hex::<33>("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6"),
789 );
790 }
791
792 #[test]
793 fn ecdsa_sign_matches_rfc6979_vectors() {
794 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
795 let key = SecretKey::from_bytes(&private_key).unwrap();
796 let sample_signature = key.sign(b"sample").unwrap();
799 let expected_sample = decode_hex::<64>(
800 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
801 0834e36ad29a83bf2bc9385e491d6099c8fdf9d1ed67aa7ea5f51f93782857a9",
802 );
803 assert_eq!(sample_signature, expected_sample);
804
805 let test_signature = key.sign(b"test").unwrap();
806 let expected_test = decode_hex::<64>(
807 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367\
808 019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
809 );
810 assert_eq!(test_signature, expected_test);
811 }
812
813 #[test]
814 fn ecdsa_sign_emits_canonical_low_s() {
815 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
816 let key = SecretKey::from_bytes(&private_key).unwrap();
817 for msg in [&b"sample"[..], b"test", b"", b"another message"] {
818 let sig = key.sign(msg).unwrap();
819 let s = Scalar::from_bytes(sig[32..].try_into().unwrap()).unwrap();
820 assert!(!s.is_high(), "sign produced a high-s signature for {:?}", msg);
821 }
822 }
823
824 #[test]
825 fn ecdsa_verify_strict_rejects_high_s() {
826 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
827 let key = SecretKey::from_bytes(&private_key).unwrap();
828 let public_key = key.public_key();
829 let signature = key.sign(b"sample").unwrap();
830
831 assert!(public_key.verify(b"sample", &signature).is_ok());
833 assert!(public_key.verify_strict(b"sample", &signature).is_ok());
834
835 let r = Scalar::from_bytes(signature[..32].try_into().unwrap()).unwrap();
838 let s = Scalar::from_bytes(signature[32..].try_into().unwrap()).unwrap();
839 let high_s = Scalar::ZERO.sub(s);
840 assert!(high_s.is_high());
841
842 let mut malleable = [0u8; SIGNATURE_SIZE];
843 malleable[..32].copy_from_slice(&r.to_bytes());
844 malleable[32..].copy_from_slice(&high_s.to_bytes());
845
846 assert!(public_key.verify(b"sample", &malleable).is_ok());
847 assert!(public_key.verify_strict(b"sample", &malleable).is_err());
848 }
849
850 #[test]
851 fn rfc6979_nonce_point_x_matches_signature_r() {
852 let nonce = decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60");
853 let public = derive_public_key_uncompressed(&nonce).unwrap();
854 assert_eq!(
855 &public[1..33],
856 &decode_hex::<32>("efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716")
857 );
858 }
859
860 #[test]
861 fn rfc6979_nonce_generation_matches_known_value() {
862 let private_key = Scalar::from_bytes(&decode_hex::<32>(
863 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
864 ))
865 .unwrap();
866 let hash = hash_message(b"sample");
867 assert_eq!(
868 Rfc6979::new(&private_key, &hash).generate().to_bytes(),
869 decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")
870 );
871 }
872
873 #[test]
874 fn rfc6979_retry_advances_drbg() {
875 let private_key = Scalar::from_bytes(&decode_hex::<32>(
876 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
877 ))
878 .unwrap();
879 let hash = hash_message(b"sample");
880
881 let mut drbg = Rfc6979::new(&private_key, &hash);
882 let k1 = drbg.generate();
883 assert_eq!(
884 k1.to_bytes(),
885 decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")
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::<32>("8e83dc490bc5fc4d5992bd63cd87f254adffcb930f8a8011702a88870f638fdb")
896 );
897 }
898
899 #[test]
900 fn ecdsa_forced_retry_uses_fresh_nonce() {
901 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
902 let key = SecretKey::from_bytes(&private_key).unwrap();
903 let scalar = Scalar::from_bytes(&private_key).unwrap();
904
905 let normal = key.sign(b"sample").unwrap();
906 let retried = ecdsa_sign_inner_impl(&scalar, b"sample", true).unwrap();
909
910 assert_ne!(normal, retried);
911 assert!(key.public_key().verify(b"sample", &retried).is_ok());
912 }
913
914 #[test]
915 fn rfc6979_intermediate_hmac_values_match() {
916 let x = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
917 let h1 = hash_message(b"sample");
918 let mut v = [0x01u8; 32];
919 let mut k = [0u8; 32];
920
921 let mut buf = [0u8; 97];
922 buf[..32].copy_from_slice(&v);
923 buf[32] = 0x00;
924 buf[33..65].copy_from_slice(&x);
925 buf[65..97].copy_from_slice(&h1);
926 k = hmac_digest(&k, &buf);
927 assert_eq!(
928 k,
929 decode_hex::<32>("122db1de98dae4dfa33f2da8e98494c80bff807b479fd79261b37e25f267ee58")
930 );
931 v = hmac_digest(&k, &v);
932 assert_eq!(
933 v,
934 decode_hex::<32>("c9947803a747fc60c23535fdcc13b5ca566b48221ca67d4964d22daa48275844")
935 );
936
937 buf[..32].copy_from_slice(&v);
938 buf[32] = 0x01;
939 k = hmac_digest(&k, &buf);
940 assert_eq!(
941 k,
942 decode_hex::<32>("b6d4f98ebae70aa15a2238ade4e20ab323fc1e777d22f0c582d8ef2e6ba73569")
943 );
944 v = hmac_digest(&k, &v);
945 assert_eq!(
946 v,
947 decode_hex::<32>("bae57fe256de2de806b10635497237e7bae96754582566384c47c6c3416494d1")
948 );
949 v = hmac_digest(&k, &v);
950 assert_eq!(
951 v,
952 decode_hex::<32>("a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60")
953 );
954 }
955
956 #[test]
957 fn ecdsa_verify_accepts_compressed_and_uncompressed_public_keys() {
958 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
959 let key = SecretKey::from_bytes(&private_key).unwrap();
960 let uncompressed = key.public_key();
961 let compressed = derive_public_key_compressed(&private_key).unwrap();
962 let signature = key.sign(b"sample").unwrap();
963
964 assert!(uncompressed.verify(b"sample", &signature).is_ok());
965 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
966 assert!(ecdsa_verify_inner(&point, b"sample", &signature).is_ok());
967 }
968
969 #[test]
970 fn verify_rejects_tampering_and_invalid_points() {
971 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
972 let key = SecretKey::from_bytes(&private_key).unwrap();
973 let pub_key = key.public_key();
974 let mut off_curve = [0u8; 65];
975 off_curve.copy_from_slice(&pub_key.to_bytes());
976 let signature = key.sign(b"sample").unwrap();
977
978 assert!(pub_key.verify(b"tampered", &signature).is_err());
979
980 let mut bad_signature = signature;
981 bad_signature[10] ^= 0x80;
982 assert!(pub_key.verify(b"sample", &bad_signature).is_err());
983
984 off_curve[64] ^= 0x01;
985 assert!(!is_valid_public_key(&off_curve));
986 assert!(PublicKey::from_bytes(&off_curve).is_err());
987
988 let invalid_x = decode_hex::<33>("02ffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
989 assert!(!is_valid_public_key(&invalid_x));
990 }
991
992 #[test]
993 fn invalid_inputs_are_rejected() {
994 let invalid_private_key = [0u8; SECRET_KEY_SIZE];
995 assert!(SecretKey::from_bytes(&invalid_private_key).is_err());
996 assert!(derive_public_key_uncompressed(&invalid_private_key).is_err());
997 assert!(derive_public_key_compressed(&invalid_private_key).is_err());
998
999 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1000 let key = SecretKey::from_bytes(&private_key).unwrap();
1001 let signature = key.sign(b"msg").unwrap();
1002 let mut zero_r = signature;
1003 zero_r[..32].fill(0);
1004 assert!(key.public_key().verify(b"msg", &zero_r).is_err());
1005 }
1006
1007 #[test]
1008 fn public_key_validation_accepts_known_good_points() {
1009 assert!(is_valid_public_key(&decode_hex::<65>(
1010 "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\
1011 4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
1012 )));
1013 assert!(is_valid_public_key(&decode_hex::<33>(
1014 "0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6"
1015 )));
1016 }
1017
1018 #[test]
1021 fn wycheproof_ecdsa_p256_sha256_p1363() {
1022 let data: serde_json::Value = serde_json::from_str(include_str!(
1023 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp256r1_sha256_p1363_test.json"
1024 ))
1025 .unwrap();
1026 let mut valid_tested = 0u64;
1027 let mut invalid_tested = 0u64;
1028 for group in data["testGroups"].as_array().unwrap() {
1029 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1030 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1031 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1032
1033 for test in group["tests"].as_array().unwrap() {
1034 let msg_hex = test["msg"].as_str().unwrap();
1035 let sig_hex = test["sig"].as_str().unwrap();
1036 let result = test["result"].as_str().unwrap();
1037
1038 let msg = hex::decode(msg_hex).unwrap();
1039
1040 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1041 continue;
1042 }
1043 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1044
1045 let verify_result = pk.verify(&msg, &sig);
1046
1047 if result == "valid" {
1048 assert!(
1049 verify_result.is_ok(),
1050 "wycheproof ECDSA P1363 tcId={} expected valid but failed",
1051 test["tcId"]
1052 );
1053 valid_tested += 1;
1054 } else {
1055 assert!(
1056 verify_result.is_err(),
1057 "wycheproof ECDSA P1363 tcId={} expected invalid but passed",
1058 test["tcId"]
1059 );
1060 invalid_tested += 1;
1061 }
1062 }
1063 }
1064 assert!(valid_tested > 0, "no valid ECDSA P1363 wycheproof tests were run");
1065 assert!(invalid_tested > 0, "no invalid ECDSA P1363 wycheproof tests were run");
1066 }
1067
1068 #[test]
1069 fn ecdsa_sign_verify_round_trip_multiple_messages() {
1070 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1071 let key = SecretKey::from_bytes(&private_key).unwrap();
1072 let pub_key = key.public_key();
1073
1074 let messages: &[&[u8]] = &[
1075 b"",
1076 b"hello world",
1077 b"The quick brown fox jumps over the lazy dog",
1078 &[0u8; 0],
1079 &[0xffu8; 100],
1080 b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1081 ];
1082
1083 for msg in messages {
1084 let sig = key.sign(msg).unwrap();
1085 assert!(pub_key.verify(msg, &sig).is_ok(), "round-trip failed for message {:?}", msg);
1086 let mut wrong_msg = msg.to_vec();
1088 wrong_msg.push(0x42);
1089 assert!(pub_key.verify(&wrong_msg, &sig).is_err());
1090 }
1091 }
1092
1093 #[test]
1094 fn ecdsa_sign_verify_different_keys() {
1095 let keys: &[&str] = &[
1097 "0000000000000000000000000000000000000000000000000000000000000001",
1098 "0000000000000000000000000000000000000000000000000000000000000002",
1099 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550",
1100 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011",
1101 ];
1102
1103 for key_hex in keys {
1104 let private_key = decode_hex::<32>(key_hex);
1105 let key = SecretKey::from_bytes(&private_key).unwrap();
1106 let sig = key.sign(b"test message").unwrap();
1107 assert!(
1108 key.public_key().verify(b"test message", &sig).is_ok(),
1109 "sign/verify failed for key {}",
1110 key_hex
1111 );
1112 }
1113 }
1114
1115 #[test]
1116 fn ecdsa_verify_wrong_public_key_rejects() {
1117 let private_key1 = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1118 let private_key2 = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001");
1119 let key1 = SecretKey::from_bytes(&private_key1).unwrap();
1120 let key2 = SecretKey::from_bytes(&private_key2).unwrap();
1121
1122 let sig = key1.sign(b"message").unwrap();
1123 assert!(key2.public_key().verify(b"message", &sig).is_err());
1124 }
1125
1126 #[test]
1127 fn scalar_from_bytes_rejects_boundary_values() {
1128 let zero = [0u8; 32];
1130 assert!(Scalar::from_bytes(&zero).is_none());
1131
1132 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1134 assert!(Scalar::from_bytes(&n_bytes).is_none());
1135
1136 let n_minus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550");
1138 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1139
1140 let one = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001");
1142 assert!(Scalar::from_bytes(&one).is_some());
1143 }
1144
1145 #[test]
1146 fn field_element_from_bytes_rejects_boundary_values() {
1147 let p_bytes = decode_hex::<32>("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
1149 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1150
1151 let p_minus_1 = decode_hex::<32>("ffffffff00000001000000000000000000000000fffffffffffffffffffffffe");
1153 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1154
1155 let zero = [0u8; 32];
1157 assert!(FieldElement::from_bytes(&zero).is_some());
1158 }
1159
1160 #[test]
1161 fn point_decompression_round_trip() {
1162 let keys: &[&str] = &[
1164 "0000000000000000000000000000000000000000000000000000000000000001",
1165 "0000000000000000000000000000000000000000000000000000000000000002",
1166 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
1167 "a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90011",
1168 ];
1169
1170 for key_hex in keys {
1171 let private_key = decode_hex::<32>(key_hex);
1172 let key = SecretKey::from_bytes(&private_key).unwrap();
1173 let uncompressed = key.public_key();
1174 let compressed = derive_public_key_compressed(&private_key).unwrap();
1175
1176 let sig = key.sign(b"round-trip").unwrap();
1178 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
1179 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1180 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
1181
1182 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
1184 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
1185 }
1186 }
1187
1188 #[test]
1189 fn nist_cavp_verify_vectors() {
1190 struct VerifyVector {
1194 qx: &'static str,
1195 qy: &'static str,
1196 msg: &'static [u8],
1197 r: &'static str,
1198 s: &'static str,
1199 valid: bool,
1200 }
1201
1202 let vectors = [
1203 VerifyVector {
1205 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1206 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1207 msg: b"sample",
1208 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1209 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1210 valid: true,
1211 },
1212 VerifyVector {
1214 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1215 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1216 msg: b"test",
1217 r: "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
1218 s: "019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
1219 valid: true,
1220 },
1221 VerifyVector {
1223 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1224 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1225 msg: b"wrong",
1226 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1227 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1228 valid: false,
1229 },
1230 VerifyVector {
1232 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1233 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1234 msg: b"test",
1235 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1236 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1237 valid: false,
1238 },
1239 VerifyVector {
1241 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1242 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1243 msg: b"sample",
1244 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3717",
1245 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1246 valid: false,
1247 },
1248 ];
1249
1250 for (i, v) in vectors.iter().enumerate() {
1251 let mut pubkey = [0u8; 65];
1252 pubkey[0] = 0x04;
1253 pubkey[1..33].copy_from_slice(&hex::decode(v.qx).unwrap());
1254 pubkey[33..65].copy_from_slice(&hex::decode(v.qy).unwrap());
1255
1256 let mut sig = [0u8; 64];
1257 sig[..32].copy_from_slice(&hex::decode(v.r).unwrap());
1258 sig[32..].copy_from_slice(&hex::decode(v.s).unwrap());
1259
1260 let pk = PublicKey::from_bytes(&pubkey).unwrap();
1261 let result = pk.verify(v.msg, &sig);
1262 if v.valid {
1263 assert!(result.is_ok(), "NIST vector {} should be valid", i);
1264 } else {
1265 assert!(result.is_err(), "NIST vector {} should be invalid", i);
1266 }
1267 }
1268 }
1269
1270 #[test]
1271 fn rfc6979_bits2octets_matches_spec() {
1272 let hash = hash_message(b"sample");
1274 let result = bits2octets(&hash);
1275 assert_eq!(result, hash);
1279
1280 let big_hash: [u8; 32] = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1282 let reduced = bits2octets(&big_hash);
1283 assert_eq!(
1285 reduced,
1286 decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001")
1287 );
1288 }
1289
1290 #[test]
1291 fn scalar_inversion_correctness() {
1292 let k = Scalar::from_bytes(&decode_hex::<32>(
1294 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
1295 ))
1296 .unwrap();
1297 let k_inv = k.invert().unwrap();
1298 let product = k.mul(k_inv);
1299 assert_eq!(product, Scalar::ONE);
1300 }
1301
1302 #[test]
1303 fn field_element_inversion_correctness() {
1304 let x = FieldElement::from_bytes(&decode_hex::<32>(
1306 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1307 ))
1308 .unwrap();
1309 let x_inv = x.invert().unwrap();
1310 let product = x.mul(x_inv);
1311 assert_eq!(product, FieldElement::ONE);
1312 let product = x.mul(x_inv);
1313 assert_eq!(product, FieldElement::ONE);
1314 }
1315
1316 #[test]
1317 fn p256_fast_mul_mod_matches_generic() {
1318 for _ in 0..1000 {
1321 let a_bytes: [u8; 32] = rand::random();
1322 let b_bytes: [u8; 32] = rand::random();
1323 let a_opt = FieldElement::from_bytes(&a_bytes);
1324 let b_opt = FieldElement::from_bytes(&b_bytes);
1325 if a_opt.is_none() || b_opt.is_none() {
1326 continue;
1327 }
1328 let a = a_opt.unwrap();
1329 let b = b_opt.unwrap();
1330 let expected = U256::from_limbs({
1331 let mut p = [0u64; 8];
1332 for i in 0..4 {
1333 let mut c = 0u64;
1334 for j in 0..4 {
1335 let (v, cc) = mac(p[i + j], a.0.limbs[i], b.0.limbs[j], c);
1336 p[i + j] = v;
1337 c = cc;
1338 }
1339 p[i + 4] = c;
1340 }
1341 let mut rem = [0u64; 4];
1342 for bi in (0..512).rev() {
1343 let li = bi / 64;
1344 let pi = bi % 64;
1345 let bit = ((p[li] >> pi) & 1) as u64;
1346 let mut shifted = [0u64; 4];
1347 let mut carry = bit;
1348 for j in 0..4 {
1349 let next = rem[j] >> 63;
1350 shifted[j] = (rem[j] << 1) | carry;
1351 carry = next;
1352 }
1353 let (red, br) = U256::from_limbs(shifted).sub_raw(&MODULUS_P);
1354 if carry == 1 || br == 0 {
1355 rem = red.limbs;
1356 } else {
1357 rem = shifted;
1358 }
1359 }
1360 rem
1361 });
1362 let fast = p256_fast_mul_mod(&a.0, &b.0);
1363 assert_eq!(expected, fast, "mismatch");
1364 }
1365 }
1366
1367 #[test]
1368 fn scalar_mul_generator_n_gives_identity() {
1369 let n_minus_1 = Scalar::from_bytes(&decode_hex::<32>(
1374 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550",
1375 ))
1376 .unwrap();
1377 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
1378 assert_eq!(result.x, FieldElement::from_uint(GENERATOR_X));
1379 let neg_gy = FieldElement::from_uint(GENERATOR_Y).negate();
1381 assert_eq!(result.y, neg_gy);
1382 }
1383
1384 #[test]
1387 fn ecdh_rfc5903_section_8_1() {
1388 let i_priv = decode_hex::<32>("c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433");
1390 let i_pub = decode_hex::<65>(
1391 "04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c3772581180\
1392 5271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3",
1393 );
1394 let r_priv = decode_hex::<32>("c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53");
1395 let r_pub = decode_hex::<65>(
1396 "04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf63\
1397 56fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab",
1398 );
1399 let expected_shared = decode_hex::<32>("d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de");
1400
1401 let alice = SecretKey::from_bytes(&i_priv).unwrap();
1402 let bob = SecretKey::from_bytes(&r_priv).unwrap();
1403 let bob_pub = PublicKey::from_bytes(&r_pub).unwrap();
1404 let alice_pub = PublicKey::from_bytes(&i_pub).unwrap();
1405
1406 assert_eq!(alice.public_key().to_bytes(), i_pub);
1407 assert_eq!(bob.public_key().to_bytes(), r_pub);
1408
1409 let alice_shared = alice.ecdh(&bob_pub).unwrap();
1410 let bob_shared = bob.ecdh(&alice_pub).unwrap();
1411
1412 assert_eq!(alice_shared, expected_shared);
1413 assert_eq!(bob_shared, expected_shared);
1414 }
1415
1416 #[test]
1417 fn ecdh_nist_cavp_vector_from_go() {
1418 let priv_key = decode_hex::<32>("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534");
1420 let pub_key = decode_hex::<65>(
1421 "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230\
1422 28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
1423 );
1424 let peer_pub = decode_hex::<65>(
1425 "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287\
1426 db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
1427 );
1428 let expected_shared = decode_hex::<32>("46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b");
1429
1430 let key = SecretKey::from_bytes(&priv_key).unwrap();
1431 assert_eq!(key.public_key().to_bytes(), pub_key);
1432
1433 let peer = PublicKey::from_bytes(&peer_pub).unwrap();
1434 let shared = key.ecdh(&peer).unwrap();
1435 assert_eq!(shared, expected_shared);
1436 }
1437
1438 #[test]
1439 fn ecdh_with_compressed_public_key() {
1440 let priv_alice = decode_hex::<32>("c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433");
1442 let bob_pub_compressed = decode_hex::<33>("03d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf63");
1443
1444 assert!(is_valid_public_key(&bob_pub_compressed));
1445
1446 let expected_shared = decode_hex::<32>("d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de");
1447
1448 let shared = ecdh(&priv_alice, &bob_pub_compressed).unwrap();
1449 assert_eq!(shared, expected_shared);
1450 }
1451
1452 #[test]
1453 fn ecdh_rejects_invalid_private_key_zero() {
1454 let zero_key = [0u8; 32];
1455 assert!(SecretKey::from_bytes(&zero_key).is_err());
1456 let bob = SecretKey::generate().unwrap();
1457 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1458 }
1459
1460 #[test]
1461 fn ecdh_rejects_invalid_private_key_order() {
1462 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1464 assert!(SecretKey::from_bytes(&n_bytes).is_err());
1465
1466 let n_plus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1468 assert!(SecretKey::from_bytes(&n_plus_1).is_err());
1469
1470 let all_ones = [0xffu8; 32];
1472 assert!(SecretKey::from_bytes(&all_ones).is_err());
1473 }
1474
1475 #[test]
1476 fn ecdh_rejects_peer_public_key_x_equal_to_p() {
1477 let alice = SecretKey::generate().unwrap();
1479 let mut bad_pub = [0u8; 65];
1480 bad_pub[0] = 0x04;
1481 bad_pub[1..33].copy_from_slice(&decode_hex::<32>(
1482 "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
1483 ));
1484 bad_pub[33..65].fill(0x01);
1485 assert!(!is_valid_public_key(&bad_pub));
1486 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1487 }
1488
1489 #[test]
1490 fn ecdh_different_messages_same_shared_secret() {
1491 let alice = SecretKey::generate().unwrap();
1493 let bob = SecretKey::generate().unwrap();
1494
1495 let shared1 = alice.ecdh(&bob.public_key()).unwrap();
1496 let shared2 = alice.ecdh(&bob.public_key()).unwrap();
1497 assert_eq!(shared1, shared2);
1498 }
1499
1500 #[test]
1501 fn ecdh_self_exchange_is_deterministic() {
1502 let alice = SecretKey::generate().unwrap();
1504 let shared = alice.ecdh(&alice.public_key()).unwrap();
1505 let shared2 = alice.ecdh(&alice.public_key()).unwrap();
1506 assert_eq!(shared, shared2);
1507 }
1508
1509 #[test]
1510 fn ecdh_different_keys_produce_different_secrets() {
1511 let alice = SecretKey::generate().unwrap();
1512 let bob1 = SecretKey::generate().unwrap();
1513 let bob2 = SecretKey::generate().unwrap();
1514
1515 let shared1 = alice.ecdh(&bob1.public_key()).unwrap();
1516 let shared2 = alice.ecdh(&bob2.public_key()).unwrap();
1517 assert_ne!(shared1, shared2);
1519 }
1520
1521 #[test]
1522 fn ecdh_generator_multiplication_matches_go_p256_mult_test1() {
1523 let k = decode_hex::<32>("2a265f8bcbdcaf94d58519141e578124cb40d64a501fba9c11847b28965bc737");
1525 let x_in = decode_hex::<32>("023819813ac969847059028ea88a1f30dfbcde03fc791d3a252c6b41211882ea");
1526 let y_in = decode_hex::<32>("f93e4ae433cc12cf2a43fc0ef26400c0e125508224cdb649380f25479148a4ad");
1527 let x_out = decode_hex::<32>("4d4de80f1534850d261075997e3049321a0864082d24a917863366c0724f5ae3");
1528 let y_out = decode_hex::<32>("a22d2b7f7818a3563e0f7a76c9bf0921ac55e06e2e4d11795b233824b1db8cc0");
1529
1530 let mut pubkey = [0u8; 65];
1531 pubkey[0] = 0x04;
1532 pubkey[1..33].copy_from_slice(&x_in);
1533 pubkey[33..65].copy_from_slice(&y_in);
1534
1535 let point = parse_public_key(&pubkey).unwrap();
1536 let scalar = Scalar::from_bytes(&k).unwrap();
1537 let result = scalar_mul_affine(&point, &scalar).to_affine().unwrap();
1538
1539 assert_eq!(result.x.to_bytes(), x_out, "x coordinate mismatch in Go test 1");
1540 assert_eq!(result.y.to_bytes(), y_out, "y coordinate mismatch in Go test 1");
1541 }
1542
1543 #[test]
1544 fn ecdh_generator_multiplication_matches_go_p256_mult_test2() {
1545 let k = decode_hex::<32>("313f72ff9fe811bf573176231b286a3bdb6f1b14e05c40146590727a71c3bccd");
1547 let x_in = decode_hex::<32>("cc11887b2d66cbae8f4d306627192522932146b42f01d3c6f92bd5c8ba739b06");
1548 let y_in = decode_hex::<32>("a2f08a029cd06b46183085bae9248b0ed15b70280c7ef13a457f5af382426031");
1549 let x_out = decode_hex::<32>("831c3f6b5f762d2f461901577af41354ac5f228c2591f84f8a6e51e2e3f17991");
1550 let y_out = decode_hex::<32>("93f90934cd0ef2c698cc471c60a93524e87ab31ca2412252337f364513e43684");
1551
1552 let mut pubkey = [0u8; 65];
1553 pubkey[0] = 0x04;
1554 pubkey[1..33].copy_from_slice(&x_in);
1555 pubkey[33..65].copy_from_slice(&y_in);
1556
1557 let point = parse_public_key(&pubkey).unwrap();
1558 let scalar = Scalar::from_bytes(&k).unwrap();
1559 let result = scalar_mul_affine(&point, &scalar).to_affine().unwrap();
1560
1561 assert_eq!(result.x.to_bytes(), x_out, "x coordinate mismatch in Go test 2");
1562 assert_eq!(result.y.to_bytes(), y_out, "y coordinate mismatch in Go test 2");
1563 }
1564
1565 #[test]
1566 fn ecdh_rejects_invalid_curve_attack() {
1567 let alice = SecretKey::generate().unwrap();
1570 let mut off_curve = [0u8; 65];
1571 off_curve[0] = 0x04;
1572 off_curve[33] = 0x01;
1573 off_curve[64] = 0x01;
1574 off_curve[1] = 0x01;
1575
1576 assert!(!is_valid_public_key(&off_curve));
1577 assert!(ecdh(&alice.to_bytes(), &off_curve).is_err());
1578 }
1579
1580 #[test]
1581 fn ecdh_edge_case_shared_secret_x_equals_zero() {
1582 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1585 let pub_hex = "0458fd4168a87795603e2b04390285bdca6e57de6027fe211dd9d25e2212d29e6\
1586 2080d36bd224d7405509295eed02a17150e03b314f96da37445b0d1d29377d12c";
1587 let expected_shared = [0u8; 32];
1588
1589 let priv_key = decode_hex::<32>(priv_hex);
1590 let pub_key = decode_hex::<65>(pub_hex);
1591
1592 assert!(is_valid_public_key(&pub_key));
1593 let shared = ecdh(&priv_key, &pub_key).unwrap();
1594 assert_eq!(shared, expected_shared);
1595 }
1596
1597 #[test]
1598 fn ecdh_edge_case_shared_secret_x_equals_p_minus_3() {
1599 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1602 let pub_hex = "04a1ecc24bf0d0053d23f5fd80ddf1735a1925039dc1176c581a7e795163c8b9ba\
1603 2cb5a4e4d5109f4527575e3137b83d79a9bcb3faeff90d2aca2bed71bb523e7e";
1604 let expected_shared = decode_hex::<32>("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc");
1605
1606 let priv_key = decode_hex::<32>(priv_hex);
1607 let pub_key = decode_hex::<65>(pub_hex);
1608
1609 assert!(is_valid_public_key(&pub_key));
1610 let shared = ecdh(&priv_key, &pub_key).unwrap();
1611 assert_eq!(shared, expected_shared);
1612 }
1613
1614 #[test]
1615 fn ecdh_edge_case_shared_secret_power_of_two() {
1616 let priv_hex = "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a";
1619 let pub_hex = "041b0e7437c33d379929430d3ec10df59bed7fe2a1d950c5791e1e9ddeef1f4d70\
1620 fbdb0e3bbce63a27f27838c685207f2ccaf689d25eb622744db1168ac92619e8";
1621 let expected_shared = decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000010000");
1622
1623 let priv_key = decode_hex::<32>(priv_hex);
1624 let pub_key = decode_hex::<65>(pub_hex);
1625
1626 assert!(is_valid_public_key(&pub_key));
1627 let shared = ecdh(&priv_key, &pub_key).unwrap();
1628 assert_eq!(shared, expected_shared);
1629 }
1630
1631 #[test]
1632 fn ecdh_wrong_curve_rejected() {
1633 let alice = SecretKey::generate().unwrap();
1638 let p224_gen_x = [
1639 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03,
1640 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21,
1641 ];
1642 let p224_gen_y = [
1643 0x00, 0x00, 0x00, 0x00, 0xbd, 0x37, 0x68, 0x08, 0xb3, 0x2c, 0x81, 0x2e, 0xd7, 0xd2, 0x86, 0x72, 0x37, 0x46,
1644 0xa5, 0xdc, 0x63, 0x63, 0x9c, 0x5d, 0x99, 0xd6, 0x9c, 0xb4, 0xd4, 0xfc, 0xb5, 0x9e,
1645 ];
1646 let mut bad_pub = [0u8; 65];
1647 bad_pub[0] = 0x04;
1648 bad_pub[1..33].copy_from_slice(&p224_gen_x);
1649 bad_pub[33..65].copy_from_slice(&p224_gen_y);
1650
1651 assert!(!is_valid_public_key(&bad_pub));
1652 assert!(ecdh(&alice.to_bytes(), &bad_pub).is_err());
1653 }
1654
1655 #[test]
1656 fn ecdh_private_key_rejects_zero_and_order() {
1657 let zero = [0u8; 32];
1659 assert!(SecretKey::from_bytes(&zero).is_err());
1660
1661 let n = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1662 assert!(SecretKey::from_bytes(&n).is_err());
1663
1664 let n_minus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550");
1665 assert!(SecretKey::from_bytes(&n_minus_1).is_ok());
1666 }
1667
1668 #[test]
1669 fn ecdh_public_key_rejects_invalid_encodings() {
1670 assert!(!is_valid_public_key(&[0x00]));
1672
1673 let mut bad_prefix = [0u8; 65];
1675 bad_prefix[0] = 0x05;
1676 bad_prefix[1] = 0x01;
1677 assert!(!is_valid_public_key(&bad_prefix));
1678
1679 assert!(!is_valid_public_key(&[0x04, 0x00]));
1681
1682 let mut too_long = [0u8; 66];
1684 too_long[0] = 0x04;
1685 assert!(!is_valid_public_key(&too_long));
1686 }
1687
1688 #[test]
1689 fn ecdh_standalone_function_matches_method() {
1690 let alice = SecretKey::generate().unwrap();
1691 let bob = SecretKey::generate().unwrap();
1692
1693 let method_result = alice.ecdh(&bob.public_key()).unwrap();
1694 let standalone_result = ecdh(&alice.to_bytes(), &bob.public_key().to_bytes()).unwrap();
1695
1696 assert_eq!(method_result, standalone_result);
1697 }
1698
1699 #[test]
1700 fn rfc6979_test_message_nonce_matches_known_value() {
1701 let private_key = Scalar::from_bytes(&decode_hex::<32>(
1702 "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
1703 ))
1704 .unwrap();
1705 let hash = hash_message(b"test");
1706 assert_eq!(
1707 Rfc6979::new(&private_key, &hash).generate().to_bytes(),
1708 decode_hex::<32>("d16b6ae827f17175e040871a1c7ec3500192c4c92677336ec2537acaee0008e0")
1709 );
1710 }
1711
1712 #[test]
1713 fn ecdsa_rejects_ptr_at_infinity_as_public_key() {
1714 assert!(!is_valid_public_key(&[0x00]));
1716 assert!(PublicKey::from_bytes(&[0x00]).is_err());
1717 }
1718
1719 #[test]
1720 fn ecdsa_verify_rejects_non_canonical_r_and_s() {
1721 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1722 let key = SecretKey::from_bytes(&private_key).unwrap();
1723 let _valid_sig = key.sign(b"msg").unwrap();
1724
1725 let sig = decode_hex::<64>(
1727 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552\
1728 f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1729 );
1730 assert!(key.public_key().verify(b"msg", &sig).is_err());
1731
1732 let sig = decode_hex::<64>(
1734 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
1735 ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552",
1736 );
1737 assert!(key.public_key().verify(b"msg", &sig).is_err());
1738 }
1739
1740 #[test]
1741 fn field_element_add_sub_mul_consistency() {
1742 let a = FieldElement::from_bytes(&decode_hex::<32>(
1743 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1744 ))
1745 .unwrap();
1746 let b = FieldElement::from_bytes(&decode_hex::<32>(
1747 "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
1748 ))
1749 .unwrap();
1750
1751 assert_eq!(a.add(b).sub(b), a);
1753
1754 assert_eq!(a.add(b), b.add(a));
1756
1757 assert_eq!(a.mul(b), b.mul(a));
1759
1760 let c = FieldElement::from_bytes(&decode_hex::<32>(
1762 "3bce3c3e27d2604b651d06b0cc53b0f6b3ebbd55769886bc5ac635d8aa3a93e7",
1763 ))
1764 .unwrap();
1765 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
1766 }
1767
1768 #[test]
1769 fn scalar_add_sub_mul_consistency() {
1770 let a = Scalar::from_bytes(&decode_hex::<32>(
1771 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
1772 ))
1773 .unwrap();
1774 let one = Scalar::from_bytes(&decode_hex::<32>(
1776 "0000000000000000000000000000000000000000000000000000000000000001",
1777 ))
1778 .unwrap();
1779
1780 assert_eq!(a.add(one).sub(one), a);
1782
1783 assert_eq!(a.mul(one), a);
1785
1786 let b = Scalar::from_bytes(&decode_hex::<32>(
1788 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
1789 ))
1790 .unwrap();
1791 assert_eq!(a.mul(b), b.mul(a));
1792 assert_eq!(a.add(b), b.add(a));
1793 }
1794
1795 #[test]
1796 fn ecdh_shared_secret_boundary_values() {
1797 let alice = SecretKey::generate().unwrap();
1799 let bob = SecretKey::generate().unwrap();
1800
1801 let shared = alice.ecdh(&bob.public_key()).unwrap();
1802 assert_eq!(shared.len(), ECDH_SHARED_SECRET_SIZE);
1803
1804 let shared2 = alice.ecdh(&bob.public_key()).unwrap();
1806 assert_eq!(shared, shared2);
1807 }
1808
1809 #[test]
1810 fn ecdh_rejects_empty_and_invalid_public_key_bytes() {
1811 let key = SecretKey::generate().unwrap();
1812
1813 let mut bad = key.public_key().to_bytes();
1815 bad[0] = 0xff;
1816 assert!(!is_valid_public_key(&bad));
1817 assert!(PublicKey::from_bytes(&bad).is_err());
1818
1819 assert!(!is_valid_public_key(&[0x04]));
1821
1822 assert!(!is_valid_public_key(&bad[..64]));
1824
1825 let zero_x_compressed = decode_hex::<33>("020000000000000000000000000000000000000000000000000000000000000000");
1827 let _ = PublicKey::from_bytes(&zero_x_compressed);
1830 }
1831
1832 #[test]
1833 fn ecdsa_sign_then_verify_consistent_for_random_keys() {
1834 for _ in 0..5 {
1835 let key = SecretKey::generate().unwrap();
1836 let msg = rand::random::<[u8; 32]>();
1837 let sig = key.sign(&msg).unwrap();
1838 assert!(key.public_key().verify(&msg, &sig).is_ok());
1839 }
1840 }
1841
1842 #[test]
1843 fn field_element_negate_round_trip() {
1844 let x = FieldElement::from_bytes(&decode_hex::<32>(
1845 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1846 ))
1847 .unwrap();
1848 let neg = x.negate();
1849 assert_eq!(neg.negate(), x);
1850 assert_eq!(x.add(neg), FieldElement::ZERO);
1851 }
1852
1853 #[test]
1854 fn scalar_negate_round_trip() {
1855 let a = Scalar::from_bytes(&decode_hex::<32>(
1856 "a6e3c57dd01abe90086538398355dd4c3b17aa873382b0f24d6129493d8aad60",
1857 ))
1858 .unwrap();
1859 let neg_a = Scalar::ZERO.sub(a);
1860 assert_eq!(a.add(neg_a), Scalar::ZERO);
1861 assert_eq!(Scalar::ZERO.sub(neg_a), a);
1863 }
1864
1865 #[test]
1866 fn scalar_mul_by_two_matches_double() {
1867 let two = Scalar::from_bytes(&decode_hex::<32>(
1868 "0000000000000000000000000000000000000000000000000000000000000002",
1869 ))
1870 .unwrap();
1871 let g_times_2 = scalar_mul_affine(&AffinePoint::GENERATOR, &two).to_affine().unwrap();
1872 let proj_g = ProjectivePoint::from_affine(&AffinePoint::GENERATOR);
1873 let g_doubled = proj_g.double().to_affine().unwrap();
1874
1875 assert_eq!(g_times_2.to_uncompressed_bytes(), g_doubled.to_uncompressed_bytes());
1876 }
1877
1878 #[test]
1879 fn ecdh_with_self_is_consistent() {
1880 let key = SecretKey::generate().unwrap();
1881 let shared1 = key.ecdh(&key.public_key()).unwrap();
1882 let shared2 = key.ecdh(&key.public_key()).unwrap();
1883 assert_eq!(shared1, shared2);
1884 }
1885
1886 #[test]
1887 fn wycheproof_ecdh_p256_ecpoint() {
1888 let data: serde_json::Value = serde_json::from_str(include_str!(
1889 "../../testdata/wycheproof/testvectors_v1/ecdh_secp256r1_ecpoint_test.json"
1890 ))
1891 .unwrap();
1892 let mut valid_tested = 0u64;
1893 let mut invalid_tested = 0u64;
1894 let mut acceptable_tested = 0u64;
1895 for group in data["testGroups"].as_array().unwrap() {
1896 if group["curve"].as_str() != Some("secp256r1") {
1897 continue;
1898 }
1899 for test in group["tests"].as_array().unwrap() {
1900 let public_hex = test["public"].as_str().unwrap();
1901 let private_hex = test["private"].as_str().unwrap();
1902 let expected_shared_hex = test["shared"].as_str().unwrap();
1903 let result = test["result"].as_str().unwrap();
1904
1905 let public_key = hex::decode(public_hex).unwrap();
1906
1907 let private_bytes = hex::decode(private_hex).unwrap();
1910 let mut private_key = [0u8; SECRET_KEY_SIZE];
1911 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1912 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
1913 private_bytes.len() - SECRET_KEY_SIZE
1914 } else {
1915 0
1916 };
1917 private_key[SECRET_KEY_SIZE - effective_len..]
1918 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1919
1920 let shared = ecdh(&private_key, &public_key);
1921
1922 if result == "valid" {
1923 let shared = shared.unwrap();
1924 let shared_hex = hex::encode(shared);
1925 assert_eq!(shared_hex, expected_shared_hex, "wycheproof ECDH ecpoint tcId={}", test["tcId"]);
1926 valid_tested += 1;
1927 } else if result == "invalid" {
1928 assert!(
1929 shared.is_err(),
1930 "wycheproof ECDH ecpoint tcId={} expected invalid but passed",
1931 test["tcId"]
1932 );
1933 invalid_tested += 1;
1934 } else {
1935 acceptable_tested += 1;
1936 }
1937 }
1938 }
1939 assert!(valid_tested > 0, "no valid ECDH ecpoint wycheproof tests were run");
1940 assert!(invalid_tested > 0, "no invalid ECDH ecpoint wycheproof tests were run");
1941 assert!(acceptable_tested > 0, "no acceptable ECDH ecpoint wycheproof tests were run");
1942 }
1943
1944 #[test]
1945 fn p256_ecdsa_rejects_truncated_signature() {
1946 let key = SecretKey::generate().unwrap();
1947 let sig = key.sign(b"msg").unwrap();
1948 let mut truncated = [0u8; SIGNATURE_SIZE];
1950 truncated[..63].copy_from_slice(&sig[..63]);
1951 if truncated == sig {
1954 truncated[63] ^= 0x01;
1955 }
1956 assert!(key.public_key().verify(b"msg", &truncated).is_err());
1957 }
1958
1959 #[test]
1960 fn is_on_curve_accepts_generator_and_random_points() {
1961 assert!(AffinePoint::GENERATOR.is_on_curve());
1962 for _ in 0..5 {
1963 let key = SecretKey::generate().unwrap();
1964 let pb = key.public_key().to_bytes();
1967 let pk = PublicKey::from_bytes(&pb).unwrap();
1968 let _ = pk; }
1970 }
1971
1972 #[test]
1973 fn field_element_pow_correctness() {
1974 let x = FieldElement::from_bytes(&decode_hex::<32>(
1975 "0000000000000000000000000000000000000000000000000000000000000002",
1976 ))
1977 .unwrap();
1978 let x3 = x.pow(&U256::from_u64(3));
1980 let expected = x.mul(x).mul(x);
1981 assert_eq!(x3, expected);
1982
1983 let x0 = x.pow(&U256::ZERO);
1985 assert_eq!(x0, FieldElement::ONE);
1986 }
1987
1988 #[test]
1989 fn nist_p256_vector_verify_all_rfc6979_signatures() {
1990 let private_key = decode_hex::<32>("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
1992 let key = SecretKey::from_bytes(&private_key).unwrap();
1993
1994 let vectors: &[(&[u8], &str)] = &[
1995 (
1997 b"sample" as &[u8],
1998 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716\
1999 0834e36ad29a83bf2bc9385e491d6099c8fdf9d1ed67aa7ea5f51f93782857a9",
2000 ),
2001 (
2002 b"test" as &[u8],
2003 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367\
2004 019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
2005 ),
2006 ];
2007
2008 for (msg, hex_sig) in vectors {
2009 let sig = key.sign(msg).unwrap();
2010 let expected = decode_hex::<64>(hex_sig);
2011 assert_eq!(sig, expected, "failed for message: {:?}", String::from_utf8_lossy(msg));
2012 }
2013 }
2014
2015 #[test]
2016 fn wycheproof_ecdsa_p256_sha256_der() {
2017 let data: serde_json::Value = serde_json::from_str(include_str!(
2018 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp256r1_sha256_test.json"
2019 ))
2020 .unwrap();
2021 let mut valid_tested = 0u64;
2022 let mut invalid_tested = 0u64;
2023 for group in data["testGroups"].as_array().unwrap() {
2024 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
2025 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
2026 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
2027
2028 for test in group["tests"].as_array().unwrap() {
2029 let msg_hex = test["msg"].as_str().unwrap();
2030 let sig_hex = test["sig"].as_str().unwrap();
2031 let result = test["result"].as_str().unwrap();
2032
2033 let msg = hex::decode(msg_hex).unwrap();
2034 let der_sig = hex::decode(sig_hex).unwrap();
2035 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
2036 continue;
2037 };
2038
2039 let verify_result = pk.verify(&msg, &sig);
2040
2041 if result == "valid" {
2042 assert!(
2043 verify_result.is_ok(),
2044 "wycheproof ECDSA DER SHA-256 tcId={} expected valid but failed",
2045 test["tcId"]
2046 );
2047 valid_tested += 1;
2048 } else {
2049 assert!(
2050 verify_result.is_err(),
2051 "wycheproof ECDSA DER SHA-256 tcId={} expected invalid but passed",
2052 test["tcId"]
2053 );
2054 invalid_tested += 1;
2055 }
2056 }
2057 }
2058 assert!(valid_tested > 0, "no valid ECDSA DER SHA-256 wycheproof tests were run");
2059 assert!(invalid_tested > 0, "no invalid ECDSA DER SHA-256 wycheproof tests were run");
2060 }
2061
2062 #[test]
2063 fn wycheproof_ecdh_p256_asn() {
2064 let data: serde_json::Value = serde_json::from_str(include_str!(
2065 "../../testdata/wycheproof/testvectors_v1/ecdh_secp256r1_test.json"
2066 ))
2067 .unwrap();
2068 let mut valid_tested = 0u64;
2069 let mut invalid_tested = 0u64;
2070 let mut acceptable_tested = 0u64;
2071 for group in data["testGroups"].as_array().unwrap() {
2072 for test in group["tests"].as_array().unwrap() {
2073 let public_hex = test["public"].as_str().unwrap();
2074 let private_hex = test["private"].as_str().unwrap();
2075 let expected_shared_hex = test["shared"].as_str().unwrap();
2076 let result = test["result"].as_str().unwrap();
2077
2078 let spki_der = hex::decode(public_hex).unwrap();
2079 let Some(sec1_point) = spki_to_sec1_point(&spki_der) else {
2080 if result == "valid" {
2081 panic!("wycheproof ECDH ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
2082 }
2083 invalid_tested += 1;
2084 continue;
2085 };
2086
2087 let private_bytes = hex::decode(private_hex).unwrap();
2090 let mut private_key = [0u8; SECRET_KEY_SIZE];
2091 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
2092 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
2093 private_bytes.len() - SECRET_KEY_SIZE
2094 } else {
2095 0
2096 };
2097 private_key[SECRET_KEY_SIZE - effective_len..]
2098 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
2099
2100 let shared = ecdh(&private_key, &sec1_point);
2101
2102 if result == "valid" {
2103 let shared = shared.unwrap();
2104 let shared_hex = hex::encode(shared);
2105 assert_eq!(shared_hex, expected_shared_hex, "wycheproof ECDH ASN tcId={}", test["tcId"]);
2106 valid_tested += 1;
2107 } else if result == "invalid" {
2108 assert!(
2109 shared.is_err(),
2110 "wycheproof ECDH ASN tcId={} expected invalid but passed",
2111 test["tcId"]
2112 );
2113 invalid_tested += 1;
2114 } else {
2115 acceptable_tested += 1;
2116 }
2117 }
2118 }
2119 assert!(valid_tested > 0, "no valid ECDH ASN wycheproof tests were run");
2120 assert!(invalid_tested > 0, "no invalid ECDH ASN wycheproof tests were run");
2121 assert!(acceptable_tested > 0, "no acceptable ECDH ASN wycheproof tests were run");
2122 }
2123
2124 #[test]
2126 fn generator_point_is_on_curve() {
2127 p_curves::test_support::generator_point_is_on_curve::<P256>();
2128 }
2129
2130 #[test]
2131 fn from_x_y_rejects_off_curve() {
2132 p_curves::test_support::from_x_y_rejects_off_curve::<P256>();
2133 }
2134
2135 #[test]
2136 fn ecdh_round_trip_alice_bob() {
2137 p_curves::test_support::ecdh_round_trip_alice_bob::<P256>();
2138 }
2139
2140 #[test]
2141 fn ecdh_rejects_off_curve_peer_public_key() {
2142 p_curves::test_support::ecdh_rejects_off_curve_peer_public_key::<P256>();
2143 }
2144
2145 #[test]
2146 fn ecdh_rejects_infinity_peer_public_key() {
2147 p_curves::test_support::ecdh_rejects_infinity_peer_public_key::<P256>();
2148 }
2149
2150 #[test]
2151 fn ecdh_rejects_bad_length_peer_public_key() {
2152 p_curves::test_support::ecdh_rejects_bad_length_peer_public_key::<P256>();
2153 }
2154
2155 #[test]
2156 fn ecdh_multiple_exchanges_consistency() {
2157 p_curves::test_support::ecdh_multiple_exchanges_consistency::<P256>();
2158 }
2159
2160 #[test]
2161 fn private_key_round_trip_bytes() {
2162 p_curves::test_support::private_key_round_trip_bytes::<P256>();
2163 }
2164
2165 #[test]
2166 fn public_key_round_trip_bytes() {
2167 p_curves::test_support::public_key_round_trip_bytes::<P256>();
2168 }
2169
2170 #[test]
2171 fn point_double_and_add_consistency() {
2172 p_curves::test_support::point_double_and_add_consistency::<P256>();
2173 }
2174
2175 #[test]
2176 fn compressed_public_key_has_correct_prefix() {
2177 p_curves::test_support::compressed_public_key_has_correct_prefix::<P256>();
2178 }
2179
2180 #[cfg(feature = "zeroize")]
2181 #[test]
2182 fn rfc6979_state_zeroize_clears_drbg() {
2183 p_curves::test_support::rfc6979_state_zeroize_clears_drbg::<P256>();
2184 }
2185}