Skip to main content

crypto/p_curves/
p256.rs

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