1use big_number::{Uint, mac};
7
8use super::p_curves::{self, Curve, UintOps, field_pow};
9use crate::{EllipticCurveError, Hasher, RandomError, hmac::Hmac, sha2::Sha512};
10
11pub const SECRET_KEY_SIZE: usize = 66;
13pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 67;
15pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 133;
17pub const SIGNATURE_SIZE: usize = 132;
19pub const ECDH_SHARED_SECRET_SIZE: usize = 66;
22
23#[derive(Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
54pub struct SecretKey(p_curves::SecretKey<P521>);
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<P521>);
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; 66], y_bytes: &[u8; 66]) -> 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; 66], [u8; 66]) {
178 self.0.x_y()
179 }
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184struct P521;
185
186type U521 = Uint<521, 9>;
187type CurveUint = U521;
188
189const MODULUS_P: CurveUint = CurveUint::from_limbs([
190 0xffffffffffffffff,
191 0xffffffffffffffff,
192 0xffffffffffffffff,
193 0xffffffffffffffff,
194 0xffffffffffffffff,
195 0xffffffffffffffff,
196 0xffffffffffffffff,
197 0xffffffffffffffff,
198 0x00000000000001ff,
199]);
200
201const MODULUS_N: CurveUint = CurveUint::from_limbs([
202 0xbb6fb71e91386409,
203 0x3bb5c9b8899c47ae,
204 0x7fcc0148f709a5d0,
205 0x51868783bf2f966b,
206 0xfffffffffffffffa,
207 0xffffffffffffffff,
208 0xffffffffffffffff,
209 0xffffffffffffffff,
210 0x00000000000001ff,
211]);
212
213const N_MU: [u64; 10] = [
216 0xcd2dad1d7f46221c,
217 0xe6fdc408f501c8d1,
218 0xee14512412385bb1,
219 0x968bf1128d91dd98,
220 0x1a65200cffadc23d,
221 0x00016b9e5e1f1034,
222 0x0000000000000000,
223 0x0000000000000000,
224 0x0000000000000000,
225 0x0080000000000000,
226];
227
228const N_HALF: CurveUint = CurveUint::from_limbs([
231 0x5db7db8f489c3204,
232 0x1ddae4dc44ce23d7,
233 0xbfe600a47b84d2e8,
234 0x28c343c1df97cb35,
235 0xfffffffffffffffd,
236 0xffffffffffffffff,
237 0xffffffffffffffff,
238 0xffffffffffffffff,
239 0x00000000000000ff,
240]);
241
242const P_MINUS_TWO: CurveUint = CurveUint::from_limbs([
243 0xfffffffffffffffd,
244 0xffffffffffffffff,
245 0xffffffffffffffff,
246 0xffffffffffffffff,
247 0xffffffffffffffff,
248 0xffffffffffffffff,
249 0xffffffffffffffff,
250 0xffffffffffffffff,
251 0x00000000000001ff,
252]);
253
254const P_PLUS_ONE_OVER_FOUR: CurveUint = CurveUint::from_limbs([
257 0x0000000000000000,
258 0x0000000000000000,
259 0x0000000000000000,
260 0x0000000000000000,
261 0x0000000000000000,
262 0x0000000000000000,
263 0x0000000000000000,
264 0x0000000000000000,
265 0x0000000000000080,
266]);
267
268const N_MINUS_TWO: CurveUint = CurveUint::from_limbs([
269 0xbb6fb71e91386407,
270 0x3bb5c9b8899c47ae,
271 0x7fcc0148f709a5d0,
272 0x51868783bf2f966b,
273 0xfffffffffffffffa,
274 0xffffffffffffffff,
275 0xffffffffffffffff,
276 0xffffffffffffffff,
277 0x00000000000001ff,
278]);
279
280const CURVE_B: CurveUint = CurveUint::from_limbs([
281 0xef451fd46b503f00,
282 0x3573df883d2c34f1,
283 0x1652c0bd3bb1bf07,
284 0x56193951ec7e937b,
285 0xb8b489918ef109e1,
286 0xa2da725b99b315f3,
287 0x929a21a0b68540ee,
288 0x953eb9618e1c9a1f,
289 0x0000000000000051,
290]);
291
292const GENERATOR_X: CurveUint = CurveUint::from_limbs([
293 0xf97e7e31c2e5bd66,
294 0x3348b3c1856a429b,
295 0xfe1dc127a2ffa8de,
296 0xa14b5e77efe75928,
297 0xf828af606b4d3dba,
298 0x9c648139053fb521,
299 0x9e3ecb662395b442,
300 0x858e06b70404e9cd,
301 0x00000000000000c6,
302]);
303
304const GENERATOR_Y: CurveUint = CurveUint::from_limbs([
305 0x88be94769fd16650,
306 0x353c7086a272c240,
307 0xc550b9013fad0761,
308 0x97ee72995ef42640,
309 0x17afbd17273e662c,
310 0x98f54449579b4468,
311 0x5c8a5fb42c7d1bd9,
312 0x39296a789a3bc004,
313 0x0000000000000118,
314]);
315
316#[inline]
318fn reduce_mod(value: CurveUint) -> CurveUint {
319 let (sub_value, _) = value.sub_raw(&MODULUS_N);
320 CurveUint::ct_select(&sub_value, &value, value.ct_ge(&MODULUS_N))
321}
322
323fn p521_fast_mul_mod(a: &CurveUint, b: &CurveUint) -> CurveUint {
330 let al = a.limbs;
331 let bl = b.limbs;
332
333 let mut prod = [0u64; 18];
334 for i in 0..9 {
335 let mut carry = 0u64;
336 for j in 0..9 {
337 let (v, cc) = mac(prod[i + j], al[i], bl[j], carry);
338 prod[i + j] = v;
339 carry = cc;
340 }
341 prod[i + 9] = carry;
342 }
343
344 let mut lo = [0u64; 9];
346 lo[..8].copy_from_slice(&prod[..8]);
347 lo[8] = prod[8] & 0x1ff;
348
349 let mut hi = [0u64; 9];
352 for j in 0..9 {
353 hi[j] = (prod[8 + j] >> 9) | (prod[9 + j] << 55);
354 }
355
356 let (mut result, _) = CurveUint::from_limbs(lo).add_raw(&CurveUint::from_limbs(hi));
357 for _ in 0..2 {
358 let (reduced, borrow) = result.sub_raw(&MODULUS_P);
359 result = CurveUint::ct_select(&reduced, &result, borrow == 0);
360 }
361 result
362}
363
364impl Curve for P521 {
365 type U = CurveUint;
366 type FieldBytes = [u8; SECRET_KEY_SIZE];
367 type DigestBytes = [u8; 64];
368 type CompressedBytes = [u8; PUBLIC_KEY_COMPRESSED_SIZE];
369 type UncompressedBytes = [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
370 type SignatureBytes = [u8; SIGNATURE_SIZE];
371
372 const FIELD_BITS: usize = 521;
373 const FIELD_BYTES: usize = SECRET_KEY_SIZE;
374 const DIGEST_BYTES: usize = 64;
375 const COMPRESSED_BYTES: usize = PUBLIC_KEY_COMPRESSED_SIZE;
376 const UNCOMPRESSED_BYTES: usize = PUBLIC_KEY_UNCOMPRESSED_SIZE;
377
378 const MODULUS_P: CurveUint = MODULUS_P;
379 const MODULUS_N: CurveUint = MODULUS_N;
380 const N_HALF: CurveUint = N_HALF;
381 const P_MINUS_TWO: CurveUint = P_MINUS_TWO;
382 const N_MINUS_TWO: CurveUint = N_MINUS_TWO;
383 const CURVE_B: CurveUint = CURVE_B;
384 const GENERATOR_X: CurveUint = GENERATOR_X;
385 const GENERATOR_Y: CurveUint = GENERATOR_Y;
386
387 #[inline]
388 fn field_mul(a: &Self::U, b: &Self::U) -> Self::U {
389 p521_fast_mul_mod(a, b)
390 }
391
392 #[inline]
393 fn scalar_mul(a: &Self::U, b: &Self::U) -> Self::U {
394 a.mul_mod_barrett_w::<20>(b, &MODULUS_N, &N_MU)
395 }
396
397 #[inline]
398 fn field_sqrt(a: Self::U) -> Option<Self::U> {
399 let candidate = field_pow::<Self>(a, &P_PLUS_ONE_OVER_FOUR);
400 if a.ct_eq(&Self::field_mul(&candidate, &candidate)) {
401 Some(candidate)
402 } else {
403 None
404 }
405 }
406
407 #[inline]
408 fn hash(data: &[u8]) -> Self::DigestBytes {
409 Sha512::hash(data).as_ref().try_into().unwrap()
410 }
411
412 #[inline]
413 fn hmac(key: &[u8], data: &[u8]) -> Self::DigestBytes {
414 Hmac::<Sha512>::mac(key, data).as_ref().try_into().unwrap()
415 }
416
417 #[inline]
418 fn scalar_from_digest(digest: &Self::DigestBytes) -> Self::U {
419 reduce_mod(CurveUint::read_be(digest.as_ref()))
420 }
421
422 #[inline]
423 fn scalar_from_field_bytes(bytes: &Self::FieldBytes) -> Self::U {
424 reduce_mod(CurveUint::read_be(bytes.as_ref()))
425 }
426
427 #[cfg(feature = "random")]
428 #[inline]
429 fn random_secret_key() -> Result<Self::FieldBytes, RandomError> {
430 loop {
434 let mut bytes: Self::FieldBytes = crate::random::bytes()?;
435 bytes[0] &= 0x01;
436 if p_curves::Scalar::<P521>::from_bytes(&bytes).is_some() {
437 return Ok(bytes);
438 }
439 }
440 }
441}
442
443pub fn is_valid_public_key(public_key: &[u8]) -> bool {
446 p_curves::is_valid_public_key::<P521>(public_key)
447}
448
449#[cfg(test)]
450mod tests {
451 #![allow(dead_code)]
452 use super::*;
453 use crate::p_curves::p_curves;
454
455 type FieldElement = p_curves::FieldElement<P521>;
456 type Scalar = p_curves::Scalar<P521>;
457 type AffinePoint = p_curves::AffinePoint<P521>;
458 type ProjectivePoint = p_curves::ProjectivePoint<P521>;
459 type Rfc6979 = p_curves::Rfc6979<P521>;
460
461 fn hash_message(message: &[u8]) -> [u8; 64] {
463 p_curves::hash_message::<P521>(message)
464 }
465
466 fn hmac_digest(key: &[u8], data: &[u8]) -> [u8; 64] {
467 p_curves::hmac_digest::<P521>(key, data)
468 }
469
470 fn bits2octets(hash: &[u8; 64]) -> [u8; SECRET_KEY_SIZE] {
471 p_curves::bits2octets::<P521>(hash)
472 }
473
474 fn derive_public_key_uncompressed(
475 private_key: &[u8; SECRET_KEY_SIZE],
476 ) -> Result<[u8; PUBLIC_KEY_UNCOMPRESSED_SIZE], crate::EllipticCurveError> {
477 p_curves::derive_public_key_uncompressed::<P521>(private_key)
478 }
479
480 fn derive_public_key_compressed(
481 private_key: &[u8; SECRET_KEY_SIZE],
482 ) -> Result<[u8; PUBLIC_KEY_COMPRESSED_SIZE], crate::EllipticCurveError> {
483 p_curves::derive_public_key_compressed::<P521>(private_key)
484 }
485
486 fn ecdsa_sign_inner_impl(
487 scalar: &Scalar,
488 message: &[u8],
489 force_first_retry: bool,
490 ) -> Result<[u8; SIGNATURE_SIZE], crate::EllipticCurveError> {
491 p_curves::ecdsa_sign_inner_impl::<P521>(scalar, message, force_first_retry)
492 }
493
494 fn ecdsa_verify_inner(
495 public_point: &AffinePoint,
496 message: &[u8],
497 signature: &[u8; SIGNATURE_SIZE],
498 ) -> Result<(), crate::EllipticCurveError> {
499 p_curves::ecdsa_verify_inner::<P521>(public_point, message, signature)
500 }
501
502 fn parse_public_key(public_key: &[u8]) -> Result<AffinePoint, crate::EllipticCurveError> {
503 p_curves::parse_public_key::<P521>(public_key)
504 }
505
506 fn scalar_mul_generator(scalar: &Scalar) -> ProjectivePoint {
507 p_curves::scalar_mul_generator::<P521>(scalar)
508 }
509
510 fn scalar_mul_affine(base: &AffinePoint, scalar: &Scalar) -> ProjectivePoint {
511 p_curves::scalar_mul_affine::<P521>(base, scalar)
512 }
513
514 fn ecdh(
516 secret_key: &[u8; SECRET_KEY_SIZE],
517 peer_public_key: &[u8],
518 ) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], crate::EllipticCurveError> {
519 SecretKey::from_bytes(secret_key)?.ecdh(&PublicKey::from_bytes(peer_public_key)?)
520 }
521
522 #[cfg(feature = "zeroize")]
523 #[test]
524 fn private_key_zeroize_clears_scalar() {
525 use zeroize::Zeroize;
526
527 let mut key = SecretKey::from_bytes(&[1u8; SECRET_KEY_SIZE]).unwrap();
528 assert_ne!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
529 key.zeroize();
530 assert_eq!(key.to_bytes(), [0u8; SECRET_KEY_SIZE]);
531 }
532
533 fn decode_hex<const N: usize>(hex_bytes: &str) -> [u8; N] {
534 let bytes = hex::decode(hex_bytes).unwrap();
535 assert_eq!(bytes.len(), N);
536 let mut out = [0u8; N];
537 out.copy_from_slice(&bytes);
538 out
539 }
540
541 fn der_read_tlv<'a>(data: &'a [u8], offset: &mut usize) -> Option<(u8, &'a [u8])> {
542 if *offset >= data.len() {
543 return None;
544 }
545 let tag = data[*offset];
546 *offset += 1;
547 if *offset >= data.len() {
548 return None;
549 }
550 let len_byte = data[*offset];
551 *offset += 1;
552 let (len, _) = if len_byte & 0x80 != 0 {
553 let num_bytes = (len_byte & 0x7f) as usize;
554 if num_bytes == 0 || num_bytes > core::mem::size_of::<usize>() || *offset + num_bytes > data.len() {
555 return None;
556 }
557 if num_bytes > 1 && data[*offset] == 0 {
558 return None;
559 }
560 let mut l = 0usize;
561 for i in 0..num_bytes {
562 l = (l << 8) | data[*offset + i] as usize;
563 }
564 if l < 128 {
565 return None;
566 }
567 *offset += num_bytes;
568 (l, num_bytes + 1)
569 } else {
570 (len_byte as usize, 1)
571 };
572 if (*offset).checked_add(len).map_or(true, |sum| sum > data.len()) {
573 return None;
574 }
575 let value = &data[*offset..*offset + len];
576 *offset = (*offset).checked_add(len)?;
577 Some((tag, value))
578 }
579
580 fn der_ecdsa_sig_to_p1363(der: &[u8]) -> Option<[u8; SIGNATURE_SIZE]> {
581 let mut offset = 0;
582 let (tag, inner) = der_read_tlv(der, &mut offset)?;
583 if tag != 0x30 {
584 return None;
585 }
586 if offset != der.len() {
587 return None;
588 }
589 let mut inner_offset = 0;
590 let (rtag, rval) = der_read_tlv(inner, &mut inner_offset)?;
591 if rtag != 0x02 || rval.is_empty() || rval.len() > 67 {
592 return None;
593 }
594 let (stag, sval) = der_read_tlv(inner, &mut inner_offset)?;
595 if stag != 0x02 || sval.is_empty() || sval.len() > 67 {
596 return None;
597 }
598 if inner_offset != inner.len() {
599 return None;
600 }
601 let r_valid = if rval.len() == 66 && rval[0] >= 0x80 {
602 false
603 } else if rval.len() == 67 && rval[0] != 0 {
604 false
605 } else if rval.len() == 67 && rval[0] == 0 && rval[1] < 0x80 {
606 false
607 } else {
608 rval.len() <= 67
609 };
610 let s_valid = if sval.len() == 66 && sval[0] >= 0x80 {
611 false
612 } else if sval.len() == 67 && sval[0] != 0 {
613 false
614 } else if sval.len() == 67 && sval[0] == 0 && sval[1] < 0x80 {
615 false
616 } else {
617 sval.len() <= 67
618 };
619 if !r_valid || !s_valid {
620 return None;
621 }
622
623 let r_trimmed = if rval.len() == 67 && rval[0] == 0 {
624 &rval[1..]
625 } else {
626 rval
627 };
628 let s_trimmed = if sval.len() == 67 && sval[0] == 0 {
629 &sval[1..]
630 } else {
631 sval
632 };
633 if r_trimmed.len() > 66 || s_trimmed.len() > 66 {
634 return None;
635 }
636 let mut sig = [0u8; SIGNATURE_SIZE];
637 sig[66 - r_trimmed.len()..66].copy_from_slice(r_trimmed);
638 sig[132 - s_trimmed.len()..132].copy_from_slice(s_trimmed);
639 Some(sig)
640 }
641
642 fn spki_to_sec1_point(spki: &[u8]) -> Option<Vec<u8>> {
643 let ec_public_key_oid: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
644 let secp521r1_oid: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x23];
645 let mut offset = 0;
646 let (_tag, outer) = der_read_tlv(spki, &mut offset)?;
647 let mut inner = 0;
648 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
649 if _alg_tag != 0x30 {
650 return None;
651 }
652 let mut ai = 0;
653 let (oid1_tag, oid1) = der_read_tlv(alg_content, &mut ai)?;
654 if oid1_tag != 0x06 || oid1 != ec_public_key_oid {
655 return None;
656 }
657 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
658 if oid2_tag != 0x06 || oid2 != secp521r1_oid {
659 return None;
660 }
661 let (_bs_tag, bs_val) = der_read_tlv(outer, &mut inner)?;
662 if _bs_tag != 0x03 || bs_val.is_empty() {
663 return None;
664 }
665 Some(bs_val[1..].to_vec())
666 }
667
668 const RFC6979_PRIVATE_KEY: &str = "00fad06daa62ba3b25d2fb40133da757205de67f5bb0018fee8c86e1b68c7e75c\
670 aa896eb32f1f47c70855836a6d16fcc1466f6d8fbec67db89ec0c08b0e996b83\
671 538";
672 const RFC6979_PUBLIC_X: &str = "01894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd3\
673 71123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f502\
674 3a4";
675 const RFC6979_PUBLIC_Y: &str = "00493101c962cd4d2fddf782285e64584139c2f91b47f87ff82354d6630f746a2\
676 8a0db25741b5b34a828008b22acc23f924faafbd4d33f81ea66956dfeaa2bfdf\
677 cf5";
678
679 #[test]
680 fn derive_public_key_generator_matches_sec1_base_point() {
681 let mut private_key = [0u8; SECRET_KEY_SIZE];
682 private_key[65] = 1;
683 let derived = derive_public_key_uncompressed(&private_key).unwrap();
684 let expected = decode_hex::<133>(
685 "0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
686 );
687 assert_eq!(derived, expected);
688 }
689
690 #[test]
691 fn derive_public_key_matches_rfc6979_vector() {
692 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
693 let expected = decode_hex::<133>(
694 "0401894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd371123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f5023a400493101c962cd4d2fddf782285e64584139c2f91b47f87ff82354d6630f746a28a0db25741b5b34a828008b22acc23f924faafbd4d33f81ea66956dfeaa2bfdfcf5",
695 );
696 assert_eq!(derive_public_key_uncompressed(&private_key).unwrap(), expected);
697 assert_eq!(
698 PublicKey::from_x_y(&decode_hex::<66>(RFC6979_PUBLIC_X), &decode_hex::<66>(RFC6979_PUBLIC_Y),)
699 .unwrap()
700 .to_bytes(),
701 expected,
702 );
703
704 let compressed = derive_public_key_compressed(&private_key).unwrap();
706 assert_eq!(&compressed[1..], &decode_hex::<66>(RFC6979_PUBLIC_X));
707 }
708
709 #[test]
710 fn ecdsa_sign_matches_rfc6979_vectors() {
711 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
712 let key = SecretKey::from_bytes(&private_key).unwrap();
713
714 let sample_signature = key.sign(b"sample").unwrap();
717 let expected_sample = decode_hex::<132>(
718 "00c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f174e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e377fa\
719 00617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af282623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4a67a",
720 );
721 assert_eq!(sample_signature, expected_sample);
722
723 let test_signature = key.sign(b"test").unwrap();
726 let expected_test = decode_hex::<132>(
727 "013e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d08725f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945babd47ee6d00042ffec398b558634c67b6ad86e931cfe39915831747f97d879529f067081875e0871c978df9bb9587cc2b53e229002daeeea20ec39fefe7398bf4a1c063538726",
728 );
729 assert_eq!(test_signature, expected_test);
730 }
731
732 #[test]
733 fn rfc6979_nonce_generation_matches_known_value() {
734 let private_key = Scalar::from_bytes(&decode_hex::<66>(RFC6979_PRIVATE_KEY)).unwrap();
737 let hash = hash_message(b"sample");
738 assert_eq!(
739 Rfc6979::new(&private_key, &hash).generate().to_bytes(),
740 decode_hex::<66>(
741 "01dae2ea071f8110dc26882d4d5eae0621a3256fc8847fb9022e2b7d28e6f10198b1574fdd03a9053c08a1854a168aa5a57470ec97dd5ce090124ef52a2f7ecbffd3"
742 )
743 );
744 }
745
746 #[test]
747 fn rfc6979_test_message_nonce_matches_known_value() {
748 let private_key = Scalar::from_bytes(&decode_hex::<66>(RFC6979_PRIVATE_KEY)).unwrap();
749 let hash = hash_message(b"test");
750 assert_eq!(
751 Rfc6979::new(&private_key, &hash).generate().to_bytes(),
752 decode_hex::<66>(
753 "016200813020ec986863bedfc1b121f605c1215645018aea1a7b215a564de9eb1b38a67aa1128b80ce391c4fb71187654aaa3431027bfc7f395766ca988c964dc56d"
754 )
755 );
756 }
757
758 #[test]
759 fn rfc6979_retry_advances_drbg() {
760 let private_key = Scalar::from_bytes(&decode_hex::<66>(RFC6979_PRIVATE_KEY)).unwrap();
761 let hash = hash_message(b"sample");
762
763 let mut drbg = Rfc6979::new(&private_key, &hash);
764 let k1 = drbg.generate();
765 assert_eq!(
766 k1.to_bytes(),
767 decode_hex::<66>(
768 "01dae2ea071f8110dc26882d4d5eae0621a3256fc8847fb9022e2b7d28e6f10198b1574fdd03a9053c08a1854a168aa5a57470ec97dd5ce090124ef52a2f7ecbffd3"
769 )
770 );
771
772 drbg.retry();
775 let k2 = drbg.generate();
776 assert_ne!(k1.to_bytes(), k2.to_bytes());
777 }
778
779 #[test]
780 fn ecdsa_forced_retry_uses_fresh_nonce() {
781 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
782 let key = SecretKey::from_bytes(&private_key).unwrap();
783 let scalar = Scalar::from_bytes(&private_key).unwrap();
784
785 let normal = key.sign(b"sample").unwrap();
786 let retried = ecdsa_sign_inner_impl(&scalar, b"sample", true).unwrap();
789
790 assert_ne!(normal, retried);
791 assert!(key.public_key().verify(b"sample", &retried).is_ok());
792 }
793
794 #[test]
795 fn ecdsa_sign_emits_canonical_low_s() {
796 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
797 let key = SecretKey::from_bytes(&private_key).unwrap();
798 for msg in [&b"sample"[..], b"test", b"", b"another message"] {
799 let sig = key.sign(msg).unwrap();
800 let s = Scalar::from_bytes(sig[66..].try_into().unwrap()).unwrap();
801 assert!(!s.is_high(), "sign produced a high-s signature for {:?}", msg);
802 }
803 }
804
805 #[test]
806 fn ecdsa_verify_strict_rejects_high_s() {
807 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
808 let key = SecretKey::from_bytes(&private_key).unwrap();
809 let public_key = key.public_key();
810 let signature = key.sign(b"sample").unwrap();
811
812 assert!(public_key.verify(b"sample", &signature).is_ok());
814 assert!(public_key.verify_strict(b"sample", &signature).is_ok());
815
816 let r = Scalar::from_bytes(signature[..66].try_into().unwrap()).unwrap();
818 let s = Scalar::from_bytes(signature[66..].try_into().unwrap()).unwrap();
819 let high_s = Scalar::ZERO.sub(s);
820 assert!(high_s.is_high());
821
822 let mut malleable = [0u8; SIGNATURE_SIZE];
823 malleable[..66].copy_from_slice(&r.to_bytes());
824 malleable[66..].copy_from_slice(&high_s.to_bytes());
825
826 assert!(public_key.verify(b"sample", &malleable).is_ok());
827 assert!(public_key.verify_strict(b"sample", &malleable).is_err());
828 }
829
830 #[test]
831 fn scalar_from_bytes_rejects_boundary_values() {
832 let zero = [0u8; 66];
833 assert!(Scalar::from_bytes(&zero).is_none());
834
835 let n_bytes = decode_hex::<66>(
836 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
837 );
838 assert!(Scalar::from_bytes(&n_bytes).is_none());
839
840 let n_minus_1 = decode_hex::<66>(
841 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386408",
842 );
843 assert!(Scalar::from_bytes(&n_minus_1).is_some());
844
845 let one = decode_hex::<66>(
846 "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
847 );
848 assert!(Scalar::from_bytes(&one).is_some());
849 }
850
851 #[test]
852 fn field_element_from_bytes_rejects_boundary_values() {
853 let p_bytes = decode_hex::<66>(
854 "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
855 );
856 assert!(FieldElement::from_bytes(&p_bytes).is_none());
857
858 let p_minus_1 = decode_hex::<66>(
859 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
860 );
861 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
862
863 let zero = [0u8; 66];
864 assert!(FieldElement::from_bytes(&zero).is_some());
865 }
866
867 #[test]
868 fn point_decompression_round_trip() {
869 let keys: &[&str] = &[
870 "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
871 "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
872 RFC6979_PRIVATE_KEY,
873 ];
874
875 for key_hex in keys {
876 let private_key = decode_hex::<66>(key_hex);
877 let key = SecretKey::from_bytes(&private_key).unwrap();
878 let uncompressed = key.public_key();
879 let compressed = derive_public_key_compressed(&private_key).unwrap();
880
881 let sig = key.sign(b"round-trip").unwrap();
882 assert!(uncompressed.verify(b"round-trip", &sig).is_ok());
883 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
884 assert!(ecdsa_verify_inner(&point, b"round-trip", &sig).is_ok());
885
886 let point = AffinePoint::from_sec1_bytes(&compressed).unwrap();
887 assert_eq!(point.to_uncompressed_bytes(), uncompressed.to_bytes());
888 }
889 }
890
891 #[test]
892 fn scalar_inversion_correctness() {
893 let k = Scalar::from_bytes(&decode_hex::<66>(
894 "01894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd371123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f5023a4",
895 ))
896 .unwrap();
897 let k_inv = k.invert().unwrap();
898 let product = k.mul(k_inv);
899 assert_eq!(product, Scalar::ONE);
900 }
901
902 #[test]
903 fn field_element_inversion_correctness() {
904 let x = FieldElement::from_bytes(&decode_hex::<66>(
905 "00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
906 ))
907 .unwrap();
908 let x_inv = x.invert().unwrap();
909 let product = x.mul(x_inv);
910 assert_eq!(product, FieldElement::ONE);
911 }
912
913 #[test]
914 fn p521_fast_mul_mod_matches_generic() {
915 for _ in 0..1000 {
916 let a_bytes: [u8; 66] = rand::random();
917 let b_bytes: [u8; 66] = rand::random();
918 let a_opt = FieldElement::from_bytes(&a_bytes);
919 let b_opt = FieldElement::from_bytes(&b_bytes);
920 if a_opt.is_none() || b_opt.is_none() {
921 continue;
922 }
923 let a = a_opt.unwrap();
924 let b = b_opt.unwrap();
925 let expected = U521::from_limbs({
926 let mut p = [0u64; 18];
927 for i in 0..9 {
928 let mut c = 0u64;
929 for j in 0..9 {
930 let (v, cc) = mac(p[i + j], a.0.limbs[i], b.0.limbs[j], c);
931 p[i + j] = v;
932 c = cc;
933 }
934 p[i + 9] = c;
935 }
936 let mut rem = [0u64; 9];
937 for bi in (0..1152).rev() {
938 let li = bi / 64;
939 let pi = bi % 64;
940 let bit = ((p[li] >> pi) & 1) as u64;
941 let mut shifted = [0u64; 9];
942 let mut carry = bit;
943 for j in 0..9 {
944 let next = rem[j] >> 63;
945 shifted[j] = (rem[j] << 1) | carry;
946 carry = next;
947 }
948 let (red, br) = U521::from_limbs(shifted).sub_raw(&MODULUS_P);
949 if carry == 1 || br == 0 {
950 rem = red.limbs;
951 } else {
952 rem = shifted;
953 }
954 }
955 rem
956 });
957 let fast = p521_fast_mul_mod(&a.0, &b.0);
958 assert_eq!(expected, fast, "mismatch in p521_fast_mul_mod");
959 }
960 }
961
962 #[test]
963 fn scalar_mul_generator_n_gives_identity() {
964 let n_minus_1 = Scalar::from_bytes(&decode_hex::<66>(
965 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386408",
966 ))
967 .unwrap();
968 let result = scalar_mul_generator(&n_minus_1).to_affine().unwrap();
969 assert_eq!(result.x, FieldElement::from_uint(GENERATOR_X));
970 let neg_gy = FieldElement::from_uint(GENERATOR_Y).negate();
971 assert_eq!(result.y, neg_gy);
972 }
973
974 #[test]
975 fn scalar_mul_by_two_matches_double() {
976 let two = Scalar::from_bytes(&decode_hex::<66>("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"))
977 .unwrap();
978 let g_times_2 = scalar_mul_affine(&AffinePoint::GENERATOR, &two).to_affine().unwrap();
979 let proj_g = ProjectivePoint::from_affine(&AffinePoint::GENERATOR);
980 let g_doubled = proj_g.double().to_affine().unwrap();
981
982 assert_eq!(g_times_2.to_uncompressed_bytes(), g_doubled.to_uncompressed_bytes());
983 }
984
985 #[test]
986 fn ecdh_deterministic_vector_against_generator() {
987 let private_key = decode_hex::<66>(RFC6979_PRIVATE_KEY);
990 let generator = decode_hex::<133>(
991 "0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
992 );
993
994 let key = SecretKey::from_bytes(&private_key).unwrap();
995 let shared = ecdh(&private_key, &generator).unwrap();
996 assert_eq!(shared, key.public_key().x_y().0);
997 assert_eq!(shared, decode_hex::<66>(RFC6979_PUBLIC_X));
998 }
999
1000 #[test]
1001 fn ecdh_with_compressed_public_key() {
1002 let alice = SecretKey::generate().unwrap();
1003 let bob = SecretKey::generate().unwrap();
1004 let bob_compressed = derive_public_key_compressed(&bob.to_bytes()).unwrap();
1005
1006 assert!(is_valid_public_key(&bob_compressed));
1007 let shared = alice.ecdh(&PublicKey::from_bytes(&bob_compressed).unwrap()).unwrap();
1008 let expected = bob.ecdh(&alice.public_key()).unwrap();
1009 assert_eq!(shared, expected);
1010 }
1011
1012 #[test]
1013 fn ecdh_rejects_invalid_private_key_zero() {
1014 let zero_key = [0u8; 66];
1015 assert!(SecretKey::from_bytes(&zero_key).is_err());
1016 let bob = SecretKey::generate().unwrap();
1017 assert!(ecdh(&zero_key, &bob.public_key().to_bytes()).is_err());
1018 }
1019
1020 #[test]
1021 fn ecdsa_rejects_non_canonical_r_and_s() {
1022 let key = SecretKey::generate().unwrap();
1023 let mut bad_r = key.sign(b"msg").unwrap();
1024 bad_r[..66].copy_from_slice(&decode_hex::<66>(
1025 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138640a",
1026 ));
1027 assert!(key.public_key().verify(b"msg", &bad_r).is_err());
1028
1029 let mut bad_s = key.sign(b"msg").unwrap();
1030 bad_s[66..].copy_from_slice(&decode_hex::<66>(
1031 "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138640a",
1032 ));
1033 assert!(key.public_key().verify(b"msg", &bad_s).is_err());
1034 }
1035
1036 #[test]
1037 fn verify_rejects_tampered_message_and_signature() {
1038 let key = SecretKey::generate().unwrap();
1039 let pub_key = key.public_key();
1040 let sig = key.sign(b"message").unwrap();
1041
1042 assert!(pub_key.verify(b"tampered", &sig).is_err());
1043
1044 let mut bad_sig = sig;
1045 bad_sig[10] ^= 0x80;
1046 assert!(pub_key.verify(b"message", &bad_sig).is_err());
1047 }
1048
1049 #[test]
1050 fn public_key_rejects_off_curve_point() {
1051 let key = SecretKey::generate().unwrap();
1052 let mut off_curve = key.public_key().to_bytes();
1053 off_curve[132] ^= 0x01;
1054 assert!(!is_valid_public_key(&off_curve));
1055 assert!(PublicKey::from_bytes(&off_curve).is_err());
1056 }
1057
1058 #[test]
1059 fn x_y_round_trip() {
1060 let key = SecretKey::generate().unwrap();
1061 let pub_key = key.public_key();
1062 let (x, y) = pub_key.x_y();
1063 let pub_key2 = PublicKey::from_x_y(&x, &y).unwrap();
1064 assert_eq!(pub_key.to_bytes(), pub_key2.to_bytes());
1065 }
1066
1067 #[test]
1068 fn from_x_y_matches_generator() {
1069 let key = PublicKey::from_x_y(
1070 &decode_hex::<66>(
1071 "00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
1072 ),
1073 &decode_hex::<66>(
1074 "011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
1075 ),
1076 )
1077 .unwrap();
1078 let from_sec1 = PublicKey::from_bytes(&key.to_bytes()).unwrap();
1079 assert_eq!(key, from_sec1);
1080 }
1081
1082 #[test]
1083 fn field_element_add_sub_mul_consistency() {
1084 let a = FieldElement::from_bytes(&decode_hex::<66>(
1085 "00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
1086 ))
1087 .unwrap();
1088 let b = FieldElement::from_bytes(&decode_hex::<66>(
1089 "011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
1090 ))
1091 .unwrap();
1092
1093 assert_eq!(a.add(b).sub(b), a);
1094 assert_eq!(a.add(b), b.add(a));
1095 assert_eq!(a.mul(b), b.mul(a));
1096
1097 let c = FieldElement::from_bytes(&decode_hex::<66>(
1098 "0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
1099 ))
1100 .unwrap();
1101 assert_eq!(a.add(b).mul(c), a.mul(c).add(b.mul(c)));
1102 }
1103
1104 #[test]
1105 fn scalar_add_sub_mul_consistency() {
1106 let a = Scalar::from_bytes(&decode_hex::<66>(
1107 "01894550d0785932e00eaa23b694f213f8c3121f86dc97a04e5a7167db4e5bcd371123d46e45db6b5d5370a7f20fb633155d38ffa16d2bd761dcac474b9a2f5023a4",
1108 ))
1109 .unwrap();
1110 let one = Scalar::from_bytes(&decode_hex::<66>("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"))
1111 .unwrap();
1112
1113 assert_eq!(a.add(one).sub(one), a);
1114 assert_eq!(a.mul(one), a);
1115
1116 let b = Scalar::from_bytes(&decode_hex::<66>(
1117 "00493101c962cd4d2fddf782285e64584139c2f91b47f87ff82354d6630f746a28a0db25741b5b34a828008b22acc23f924faafbd4d33f81ea66956dfeaa2bfdfcf5",
1118 ))
1119 .unwrap();
1120 assert_eq!(a.mul(b), b.mul(a));
1121 assert_eq!(a.add(b), b.add(a));
1122 }
1123
1124 #[test]
1125 fn field_element_negate_round_trip() {
1126 let x = FieldElement::from_bytes(&decode_hex::<66>(
1127 "00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
1128 ))
1129 .unwrap();
1130 let neg = x.negate();
1131 assert_eq!(neg.negate(), x);
1132 assert_eq!(x.add(neg), FieldElement::ZERO);
1133 }
1134
1135 #[test]
1136 fn field_element_pow_correctness() {
1137 let x = FieldElement::from_bytes(&decode_hex::<66>("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"))
1138 .unwrap();
1139 let x3 = x.pow(&U521::from_u64(3));
1140 let expected = x.mul(x).mul(x);
1141 assert_eq!(x3, expected);
1142
1143 let x0 = x.pow(&U521::ZERO);
1144 assert_eq!(x0, FieldElement::ONE);
1145 }
1146
1147 #[test]
1148 fn sqrt_matches_squares_and_rejects_non_residues() {
1149 for _ in 0..100 {
1150 let bytes: [u8; 66] = rand::random();
1151 let Some(x) = FieldElement::from_bytes(&bytes) else {
1152 continue;
1153 };
1154 let square = x.square();
1155 let root = square.sqrt().expect("square should have a square root");
1156 assert_eq!(root.square(), square);
1157 }
1158 }
1159
1160 #[test]
1161 fn ecdsa_sign_then_verify_consistent_for_random_keys() {
1162 for _ in 0..5 {
1163 let key = SecretKey::generate().unwrap();
1164 let msg = rand::random::<[u8; 32]>();
1165 let sig = key.sign(&msg).unwrap();
1166 assert!(key.public_key().verify(&msg, &sig).is_ok());
1167 }
1168 }
1169
1170 #[test]
1173 fn wycheproof_ecdsa_p521_sha512_p1363() {
1174 let data: serde_json::Value = serde_json::from_str(include_str!(
1175 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp521r1_sha512_p1363_test.json"
1176 ))
1177 .unwrap();
1178 let mut valid_tested = 0u64;
1179 let mut invalid_tested = 0u64;
1180 for group in data["testGroups"].as_array().unwrap() {
1181 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1182 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1183 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1184
1185 for test in group["tests"].as_array().unwrap() {
1186 let msg = hex::decode(test["msg"].as_str().unwrap()).unwrap();
1187 let sig_hex = test["sig"].as_str().unwrap();
1188 let result = test["result"].as_str().unwrap();
1189
1190 if sig_hex.len() != SIGNATURE_SIZE * 2 {
1191 continue;
1192 }
1193 let sig = decode_hex::<SIGNATURE_SIZE>(sig_hex);
1194 let verify_result = pk.verify(&msg, &sig);
1195
1196 if result == "valid" {
1197 assert!(
1198 verify_result.is_ok(),
1199 "wycheproof ECDSA P521 P1363 tcId={} expected valid but failed",
1200 test["tcId"]
1201 );
1202 valid_tested += 1;
1203 } else {
1204 assert!(
1205 verify_result.is_err(),
1206 "wycheproof ECDSA P521 P1363 tcId={} expected invalid but passed",
1207 test["tcId"]
1208 );
1209 invalid_tested += 1;
1210 }
1211 }
1212 }
1213 assert!(valid_tested > 0, "no valid ECDSA P521 P1363 wycheproof tests were run");
1214 assert!(invalid_tested > 0, "no invalid ECDSA P521 P1363 wycheproof tests were run");
1215 }
1216
1217 #[test]
1218 fn wycheproof_ecdsa_p521_sha512_der() {
1219 let data: serde_json::Value = serde_json::from_str(include_str!(
1220 "../../testdata/wycheproof/testvectors_v1/ecdsa_secp521r1_sha512_test.json"
1221 ))
1222 .unwrap();
1223 let mut valid_tested = 0u64;
1224 let mut invalid_tested = 0u64;
1225 for group in data["testGroups"].as_array().unwrap() {
1226 let uncompressed_hex = group["publicKey"]["uncompressed"].as_str().unwrap();
1227 let pubkey_bytes = hex::decode(uncompressed_hex).unwrap();
1228 let pk = PublicKey::from_bytes(&pubkey_bytes).unwrap();
1229
1230 for test in group["tests"].as_array().unwrap() {
1231 let msg = hex::decode(test["msg"].as_str().unwrap()).unwrap();
1232 let der_sig = hex::decode(test["sig"].as_str().unwrap()).unwrap();
1233 let result = test["result"].as_str().unwrap();
1234
1235 let Some(sig) = der_ecdsa_sig_to_p1363(&der_sig) else {
1236 continue;
1237 };
1238
1239 let verify_result = pk.verify(&msg, &sig);
1240 if result == "valid" {
1241 assert!(
1242 verify_result.is_ok(),
1243 "wycheproof ECDSA P521 DER SHA-512 tcId={} expected valid but failed",
1244 test["tcId"]
1245 );
1246 valid_tested += 1;
1247 } else {
1248 assert!(
1249 verify_result.is_err(),
1250 "wycheproof ECDSA P521 DER SHA-512 tcId={} expected invalid but passed",
1251 test["tcId"]
1252 );
1253 invalid_tested += 1;
1254 }
1255 }
1256 }
1257 assert!(valid_tested > 0, "no valid ECDSA P521 DER SHA-512 wycheproof tests were run");
1258 assert!(
1259 invalid_tested > 0,
1260 "no invalid ECDSA P521 DER SHA-512 wycheproof tests were run"
1261 );
1262 }
1263
1264 #[test]
1265 fn wycheproof_ecdh_p521_ecpoint() {
1266 let data: serde_json::Value = serde_json::from_str(include_str!(
1267 "../../testdata/wycheproof/testvectors_v1/ecdh_secp521r1_ecpoint_test.json"
1268 ))
1269 .unwrap();
1270 let mut valid_tested = 0u64;
1271 let mut invalid_tested = 0u64;
1272 let mut acceptable_tested = 0u64;
1273 for group in data["testGroups"].as_array().unwrap() {
1274 if group["curve"].as_str() != Some("secp521r1") {
1275 continue;
1276 }
1277 for test in group["tests"].as_array().unwrap() {
1278 let public_hex = test["public"].as_str().unwrap();
1279 let private_hex = test["private"].as_str().unwrap();
1280 let expected_shared_hex = test["shared"].as_str().unwrap();
1281 let result = test["result"].as_str().unwrap();
1282
1283 let public_key = hex::decode(public_hex).unwrap();
1284
1285 let private_bytes = hex::decode(private_hex).unwrap();
1286 let mut private_key = [0u8; SECRET_KEY_SIZE];
1287 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1288 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
1289 private_bytes.len() - SECRET_KEY_SIZE
1290 } else {
1291 0
1292 };
1293 private_key[SECRET_KEY_SIZE - effective_len..]
1294 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1295
1296 let shared = ecdh(&private_key, &public_key);
1297
1298 if result == "valid" {
1299 let shared = shared.unwrap();
1300 let shared_hex = hex::encode(shared);
1301 assert_eq!(
1302 shared_hex, expected_shared_hex,
1303 "wycheproof ECDH P521 ecpoint tcId={}",
1304 test["tcId"]
1305 );
1306 valid_tested += 1;
1307 } else if result == "invalid" {
1308 assert!(
1309 shared.is_err(),
1310 "wycheproof ECDH P521 ecpoint tcId={} expected invalid but passed",
1311 test["tcId"]
1312 );
1313 invalid_tested += 1;
1314 } else {
1315 acceptable_tested += 1;
1316 }
1317 }
1318 }
1319 assert!(valid_tested > 0, "no valid ECDH P521 ecpoint wycheproof tests were run");
1320 assert!(invalid_tested > 0, "no invalid ECDH P521 ecpoint wycheproof tests were run");
1321 assert!(
1322 acceptable_tested > 0,
1323 "no acceptable ECDH P521 ecpoint wycheproof tests were run"
1324 );
1325 }
1326
1327 #[test]
1328 fn wycheproof_ecdh_p521_asn() {
1329 let data: serde_json::Value = serde_json::from_str(include_str!(
1330 "../../testdata/wycheproof/testvectors_v1/ecdh_secp521r1_test.json"
1331 ))
1332 .unwrap();
1333 let mut valid_tested = 0u64;
1334 let mut invalid_tested = 0u64;
1335 let mut acceptable_tested = 0u64;
1336 for group in data["testGroups"].as_array().unwrap() {
1337 for test in group["tests"].as_array().unwrap() {
1338 let public_hex = test["public"].as_str().unwrap();
1339 let private_hex = test["private"].as_str().unwrap();
1340 let expected_shared_hex = test["shared"].as_str().unwrap();
1341 let result = test["result"].as_str().unwrap();
1342
1343 let spki_der = hex::decode(public_hex).unwrap();
1344 let Some(sec1_point) = spki_to_sec1_point(&spki_der) else {
1345 if result == "valid" {
1346 panic!("wycheproof ECDH P521 ASN tcId={}: failed to parse valid SPKI", test["tcId"]);
1347 }
1348 invalid_tested += 1;
1349 continue;
1350 };
1351
1352 let private_bytes = hex::decode(private_hex).unwrap();
1353 let mut private_key = [0u8; SECRET_KEY_SIZE];
1354 let effective_len = private_bytes.len().min(SECRET_KEY_SIZE);
1355 let skip = if private_bytes.len() > SECRET_KEY_SIZE {
1356 private_bytes.len() - SECRET_KEY_SIZE
1357 } else {
1358 0
1359 };
1360 private_key[SECRET_KEY_SIZE - effective_len..]
1361 .copy_from_slice(&private_bytes[skip..skip + effective_len]);
1362
1363 let shared = ecdh(&private_key, &sec1_point);
1364
1365 if result == "valid" {
1366 let shared = shared.unwrap();
1367 let shared_hex = hex::encode(shared);
1368 assert_eq!(
1369 shared_hex, expected_shared_hex,
1370 "wycheproof ECDH P521 ASN tcId={}",
1371 test["tcId"]
1372 );
1373 valid_tested += 1;
1374 } else if result == "invalid" {
1375 assert!(
1376 shared.is_err(),
1377 "wycheproof ECDH P521 ASN tcId={} expected invalid but passed",
1378 test["tcId"]
1379 );
1380 invalid_tested += 1;
1381 } else {
1382 acceptable_tested += 1;
1383 }
1384 }
1385 }
1386 assert!(valid_tested > 0, "no valid ECDH P521 ASN wycheproof tests were run");
1387 assert!(invalid_tested > 0, "no invalid ECDH P521 ASN wycheproof tests were run");
1388 assert!(acceptable_tested > 0, "no acceptable ECDH P521 ASN wycheproof tests were run");
1389 }
1390
1391 #[test]
1394 fn bits2octets_reduces_digest() {
1395 let hash = hash_message(b"sample");
1396 assert_eq!(bits2octets(&hash), <P521 as Curve>::bits2int_octets(&hash));
1397 }
1398
1399 #[test]
1401 fn generator_point_is_on_curve() {
1402 p_curves::test_support::generator_point_is_on_curve::<P521>();
1403 }
1404
1405 #[test]
1406 fn from_x_y_rejects_off_curve() {
1407 p_curves::test_support::from_x_y_rejects_off_curve::<P521>();
1408 }
1409
1410 #[test]
1411 fn ecdh_round_trip_alice_bob() {
1412 p_curves::test_support::ecdh_round_trip_alice_bob::<P521>();
1413 }
1414
1415 #[test]
1416 fn ecdh_rejects_off_curve_peer_public_key() {
1417 p_curves::test_support::ecdh_rejects_off_curve_peer_public_key::<P521>();
1418 }
1419
1420 #[test]
1421 fn ecdh_rejects_infinity_peer_public_key() {
1422 p_curves::test_support::ecdh_rejects_infinity_peer_public_key::<P521>();
1423 }
1424
1425 #[test]
1426 fn ecdh_rejects_bad_length_peer_public_key() {
1427 p_curves::test_support::ecdh_rejects_bad_length_peer_public_key::<P521>();
1428 }
1429
1430 #[test]
1431 fn ecdh_multiple_exchanges_consistency() {
1432 p_curves::test_support::ecdh_multiple_exchanges_consistency::<P521>();
1433 }
1434
1435 #[test]
1436 fn private_key_round_trip_bytes() {
1437 p_curves::test_support::private_key_round_trip_bytes::<P521>();
1438 }
1439
1440 #[test]
1441 fn public_key_round_trip_bytes() {
1442 p_curves::test_support::public_key_round_trip_bytes::<P521>();
1443 }
1444
1445 #[test]
1446 fn point_double_and_add_consistency() {
1447 p_curves::test_support::point_double_and_add_consistency::<P521>();
1448 }
1449
1450 #[test]
1451 fn compressed_public_key_has_correct_prefix() {
1452 p_curves::test_support::compressed_public_key_has_correct_prefix::<P521>();
1453 }
1454
1455 #[cfg(feature = "zeroize")]
1456 #[test]
1457 fn rfc6979_state_zeroize_clears_drbg() {
1458 p_curves::test_support::rfc6979_state_zeroize_clears_drbg::<P521>();
1459 }
1460}