Skip to main content

crypto/p_curves/
p521.rs

1//! P-521 (secp521r1) ECDSA and ECDH.
2//!
3//! See [`SecretKey`] and [`PublicKey`] for the signing, verification and key
4//! agreement APIs.
5
6use big_number::{Uint, mac};
7
8use super::p_curves::{self, Curve, UintOps, field_pow};
9use crate::{EllipticCurveError, Hasher, RandomError, hmac::Hmac, sha2::Sha512};
10
11/// Size of a P-521 secret key in bytes (66 bytes).
12pub const SECRET_KEY_SIZE: usize = 66;
13/// Size of a compressed P-521 public key in bytes (67 bytes, includes 0x02/0x03 prefix).
14pub const PUBLIC_KEY_COMPRESSED_SIZE: usize = 67;
15/// Size of an uncompressed P-521 public key in bytes (133 bytes, includes 0x04 prefix).
16pub const PUBLIC_KEY_UNCOMPRESSED_SIZE: usize = 133;
17/// Size of a P-521 ECDSA signature in bytes (132 bytes, r || s).
18pub const SIGNATURE_SIZE: usize = 132;
19/// Size of the raw ECDH shared secret in bytes (66 bytes). **Must not** be used directly
20/// as an encryption key; apply a KDF first.
21pub const ECDH_SHARED_SECRET_SIZE: usize = 66;
22
23/// P-521 (secp521r1) ECDSA secret key.
24///
25/// Supports signing and ECDH key agreement.
26///
27/// # Signing
28///
29/// ```ignore
30/// use crypto::p521::SecretKey;
31///
32/// let key = SecretKey::generate().unwrap();
33/// let signature = key.sign(b"message").unwrap();
34/// ```
35///
36/// # ECDH key exchange
37///
38/// ```ignore
39/// use crypto::p521::SecretKey;
40///
41/// let alice = SecretKey::generate().unwrap();
42/// let bob = SecretKey::generate().unwrap();
43/// let alice_shared = alice.ecdh(&bob.public_key()).unwrap();
44/// let bob_shared = bob.ecdh(&alice.public_key()).unwrap();
45/// assert_eq!(alice_shared, bob_shared);
46/// ```
47///
48/// # Security
49///
50/// The raw shared secret from [`ecdh`](Self::ecdh) **must not** be used
51/// directly as an encryption key. Apply a KDF (e.g. HKDF) first.
52#[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    /// Generates a fresh random secret key.
58    #[cfg(feature = "random")]
59    pub fn generate() -> Result<SecretKey, EllipticCurveError> {
60        Ok(SecretKey(p_curves::SecretKey::generate()?))
61    }
62
63    /// Builds a secret key from its 66-byte big-endian scalar.
64    ///
65    /// Returns [`EllipticCurveError::InvalidKey`] when the scalar is zero or
66    /// greater than or equal to the group order.
67    pub fn from_bytes(key: &[u8; SECRET_KEY_SIZE]) -> Result<SecretKey, EllipticCurveError> {
68        Ok(SecretKey(p_curves::SecretKey::from_bytes(key)?))
69    }
70
71    /// Returns the corresponding public key.
72    pub fn public_key(&self) -> PublicKey {
73        PublicKey(self.0.public_key())
74    }
75
76    /// Signs `message` with ECDSA using SHA-512 and deterministic (RFC 6979)
77    /// nonces.
78    ///
79    /// The emitted signature is always in canonical low-s form (`s <= n / 2`),
80    /// so a given key and message always produce the exact same signature
81    /// bytes. This prevents signature malleability for systems that hash the
82    /// signature bytes (e.g. transaction ids, replay caches).
83    ///
84    /// Verification remains permissive by default (both `s` and `n - s` are
85    /// accepted); use [`PublicKey::verify_strict`] if high-s signatures must be
86    /// rejected.
87    pub fn sign(&self, message: &[u8]) -> Result<[u8; SIGNATURE_SIZE], EllipticCurveError> {
88        self.0.sign(message)
89    }
90
91    /// Computes the ECDH shared secret with `peer_public`.
92    ///
93    /// # Security
94    ///
95    /// The raw shared secret **must not** be used directly as an encryption
96    /// key. Apply a KDF (e.g. HKDF) first.
97    pub fn ecdh(&self, peer_public: &PublicKey) -> Result<[u8; ECDH_SHARED_SECRET_SIZE], EllipticCurveError> {
98        self.0.ecdh(&peer_public.0)
99    }
100
101    /// Returns the secret scalar as 66 big-endian bytes.
102    pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE] {
103        self.0.to_bytes()
104    }
105}
106
107/// P-521 (secp521r1) ECDSA public key.
108///
109/// Supports signature verification and ECDH key agreement.
110///
111/// # Verification
112///
113/// ```ignore
114/// use crypto::p521::SecretKey;
115///
116/// let key = SecretKey::generate().unwrap();
117/// let signature = key.sign(b"message").unwrap();
118/// assert!(key.public_key().verify(b"message", &signature).is_ok());
119/// ```
120#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub struct PublicKey(p_curves::PublicKey<P521>);
122
123impl PublicKey {
124    /// Parses a compressed (67-byte) or uncompressed (133-byte) SEC1 encoding.
125    ///
126    /// Returns [`EllipticCurveError::InvalidKey`] when the encoding is not a
127    /// valid point on the P-521 curve.
128    #[inline]
129    pub fn from_bytes(key: &[u8]) -> Result<PublicKey, EllipticCurveError> {
130        Ok(PublicKey(p_curves::PublicKey::from_bytes(key)?))
131    }
132
133    /// Builds a public key from raw affine x and y coordinates (both
134    /// big-endian, 66 bytes each). Returns `InvalidKey` if the coordinates
135    /// are not a valid point on the P-521 curve.
136    ///
137    /// This is useful when importing keys from formats like JWK where `x`
138    /// and `y` are available directly.
139    #[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    /// Verifies an ECDSA signature over `message` using SHA-512.
145    ///
146    /// Both canonical low-s and non-canonical high-s signatures are accepted,
147    /// matching typical ECDSA interoperability. Use [`Self::verify_strict`] to
148    /// additionally reject high-s signatures.
149    pub fn verify(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
150        self.0.verify(message, signature)
151    }
152
153    /// Verifies an ECDSA signature over `message` using SHA-512, additionally
154    /// rejecting non-canonical high-s signatures (`s > n / 2`).
155    ///
156    /// Use this when signature malleability must be excluded (Bitcoin/EIP-2
157    /// style). Note that some third-party signers emit high-s signatures, which
158    /// this method will reject; [`Self::verify`] accepts both forms.
159    pub fn verify_strict(&self, message: &[u8], signature: &[u8; SIGNATURE_SIZE]) -> Result<(), EllipticCurveError> {
160        self.0.verify_strict(message, signature)
161    }
162
163    /// Returns the 133-byte uncompressed SEC1 encoding (`0x04 || x || y`).
164    #[inline]
165    pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_UNCOMPRESSED_SIZE] {
166        self.0.to_bytes()
167    }
168
169    /// Returns the 67-byte compressed SEC1 encoding (`0x02`/`0x03 || x`).
170    #[inline]
171    pub fn to_compressed_bytes(&self) -> [u8; PUBLIC_KEY_COMPRESSED_SIZE] {
172        self.0.to_compressed_bytes()
173    }
174
175    /// Returns the `X` and `Y` points as big-endian arrays.
176    #[inline]
177    pub fn x_y(&self) -> ([u8; 66], [u8; 66]) {
178        self.0.x_y()
179    }
180}
181
182/// Marker type carrying the P-521 curve parameters.
183#[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
213/// Barrett reciprocal `mu = floor(2^(2 * 9 * 64) / n)` for the group order,
214/// computed by `big_number`'s `compute_mu_for_barrett`.
215const 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
228// floor(n / 2). A signature scalar `s` is "high" when `s > N_HALF`, in which
229// case it is normalized to `n - s` so that signatures are non-malleable.
230const 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
254// (p + 1) / 4 = 2^519. P-521 has p = 2^521 - 1, hence a square root of `a` is
255// `a^((p + 1) / 4)`.
256const 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// Reduce a big-endian value modulo n, accepting zero and values >= n.
317#[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
323// P-521 fast modular multiplication.
324//
325// Since p = 2^521 - 1, we have 2^521 ≡ 1 (mod p). The 1042-bit product is
326// split at bit 521 into its low part `L` and high part `H`, so that
327// `P ≡ L + H (mod p)`. Because `L, H < 2^521`, `L + H < 2^522 = 2p + 2`, so at
328// most two conditional subtractions bring the result below `p`.
329fn 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    // L = product mod 2^521 (limb 8 holds only its low 9 bits).
345    let mut lo = [0u64; 9];
346    lo[..8].copy_from_slice(&prod[..8]);
347    lo[8] = prod[8] & 0x1ff;
348
349    // H = product >> 521. Bit 521 is limb 8, bit 9, so each high limb is a
350    // 9-bit shift of the product.
351    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        // The group order is 521 bits while a field element occupies 66 bytes
431        // (528 bits). Clear the unused high bits and retry on the vanishingly
432        // rare value that still lands outside `[1, n - 1]`.
433        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
443/// Returns `true` when `public_key` is a valid SEC1 encoding of a point on the
444/// P-521 curve.
445pub 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    // Concrete wrappers around the generic core helpers.
462    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    // Raw-byte ECDH built from the public method, for the vector tests.
515    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    // RFC 6979 A.2.7: P-521 with SHA-512 test key pair.
669    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        // Compressed form derives from the same point; prefix encodes y parity.
705        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        // RFC 6979 A.2.7, SHA-512 "sample". The vector's s is already the
715        // canonical low-s value, so the emitted signature matches it verbatim.
716        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        // The "test" vector's `s` (`01fb…dce3`) is in high-s form, so the
724        // canonical low-s signature emitted here is `r || (n - s)`.
725        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        // P-521's order (521 bits) is wider than SHA-512's output (512 bits),
735        // so RFC 6979 must concatenate two HMAC blocks before `bits2int`.
736        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        // RFC 6979 §3.2 h.3: an r=0/s=0 retry must continue the DRBG, not
773        // reproduce the same nonce.
774        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        // Force the r=0/s=0 retry path. The signature must be produced with the
787        // next DRBG nonce; repeating the first nonce would yield `normal`.
788        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        // Canonical low-s signature passes both permissive and strict verification.
813        assert!(public_key.verify(b"sample", &signature).is_ok());
814        assert!(public_key.verify_strict(b"sample", &signature).is_ok());
815
816        // The malleable counterpart (r, n - s) is rejected only by strict verify.
817        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        // ECDH between the RFC 6979 private key and the generator: the shared
988        // secret is the x-coordinate of the derived public key.
989        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    // --- Wycheproof test vectors ---
1171
1172    #[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    // The `bits2octets` and message-hash paths must reduce a 512-bit digest
1392    // that is shorter than the 521-bit order.
1393    #[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    // Shared curve-independent tests, instantiated for P521.
1400    #[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}