Skip to main content

crypto/
p256.rs

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