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
127const 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#[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
161fn 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 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 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 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 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
696fn 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
706fn 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 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 let take = is_valid && !found;
736 candidate = ct_select_bytes(&v, &candidate, take);
737 found = found || is_valid;
738
739 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 return Scalar::from_bytes(&candidate).unwrap_or(Scalar::ZERO);
748 }
749
750 v = hmac_sha256(&k, &v);
752 if let Some(sc) = Scalar::from_bytes(&v) {
753 return sc;
754 }
755
756 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 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 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 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 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 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 if inner_offset != inner.len() {
950 return None;
951 }
952 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 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 let (_alg_tag, alg_content) = der_read_tlv(outer, &mut inner)?;
1011 if _alg_tag != 0x30 {
1012 return None;
1013 }
1014 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 let (oid2_tag, oid2) = der_read_tlv(alg_content, &mut ai)?;
1022 if oid2_tag != 0x06 || oid2 != secp256r1_oid {
1023 return None;
1024 }
1025 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 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 #[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 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 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 let zero = [0u8; 32];
1318 assert!(Scalar::from_bytes(&zero).is_none());
1319
1320 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1322 assert!(Scalar::from_bytes(&n_bytes).is_none());
1323
1324 let n_minus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550");
1326 assert!(Scalar::from_bytes(&n_minus_1).is_some());
1327
1328 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 let p_bytes = decode_hex::<32>("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
1337 assert!(FieldElement::from_bytes(&p_bytes).is_none());
1338
1339 let p_minus_1 = decode_hex::<32>("ffffffff00000001000000000000000000000000fffffffffffffffffffffffe");
1341 assert!(FieldElement::from_bytes(&p_minus_1).is_some());
1342
1343 let zero = [0u8; 32];
1345 assert!(FieldElement::from_bytes(&zero).is_some());
1346 }
1347
1348 #[test]
1349 fn point_decompression_round_trip() {
1350 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 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 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 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 VerifyVector {
1393 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1394 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1395 msg: b"sample",
1396 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1397 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1398 valid: true,
1399 },
1400 VerifyVector {
1402 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1403 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1404 msg: b"test",
1405 r: "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
1406 s: "019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
1407 valid: true,
1408 },
1409 VerifyVector {
1411 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1412 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1413 msg: b"wrong",
1414 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1415 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1416 valid: false,
1417 },
1418 VerifyVector {
1420 qx: "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
1421 qy: "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
1422 msg: b"test",
1423 r: "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
1424 s: "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1425 valid: false,
1426 },
1427 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 let hash = hash_message(b"sample");
1462 let result = bits2octets(&hash);
1463 assert_eq!(result, hash);
1467
1468 let big_hash: [u8; 32] = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1470 let reduced = bits2octets(&big_hash);
1471 assert_eq!(
1473 reduced,
1474 decode_hex::<32>("0000000000000000000000000000000000000000000000000000000000000001")
1475 );
1476 }
1477
1478 #[test]
1479 fn scalar_inversion_correctness() {
1480 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 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 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 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 let neg_gy = GENERATOR_Y.negate();
1574 assert_eq!(result.y, neg_gy);
1575 }
1576
1577 #[test]
1580 fn ecdh_rfc5903_section_8_1() {
1581 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 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 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 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 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 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 assert!(ecdh(&alice.to_bytes(), &[]).is_err());
1681 assert!(ecdh(&alice.to_bytes(), &[0x04, 0x00]).is_err());
1683 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 let n_bytes = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
1701 assert!(PrivateKey::from_bytes(&n_bytes).is_err());
1702
1703 let n_plus_1 = decode_hex::<32>("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552");
1705 assert!(PrivateKey::from_bytes(&n_plus_1).is_err());
1706
1707 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 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 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 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 assert_ne!(shared1, shared2);
1756 }
1757
1758 #[test]
1759 fn ecdh_generator_multiplication_matches_go_p256_mult_test1() {
1760 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 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 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 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 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 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 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 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 assert!(!is_valid_public_key(&[0x00]));
1909
1910 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 assert!(!is_valid_public_key(&[0x04, 0x00]));
1918
1919 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 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 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 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 let sig = decode_hex::<64>(
1993 "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552\
1994 f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
1995 );
1996 assert!(key.public_key().verify(b"msg", &sig).is_err());
1997
1998 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 assert_eq!(a.add(b).sub(b), a);
2037
2038 assert_eq!(a.add(b), b.add(a));
2040
2041 assert_eq!(a.mul(b), b.mul(a));
2043
2044 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 let one = Scalar::from_bytes(&decode_hex::<32>(
2060 "0000000000000000000000000000000000000000000000000000000000000001",
2061 ))
2062 .unwrap();
2063
2064 assert_eq!(a.add(one).sub(one), a);
2066
2067 assert_eq!(a.mul(one), a);
2069
2070 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 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 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 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 assert!(!is_valid_public_key(&[0x04]));
2105
2106 assert!(!is_valid_public_key(&bad[..64]));
2108
2109 let zero_x_compressed = decode_hex::<33>("020000000000000000000000000000000000000000000000000000000000000000");
2111 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 assert_eq!(Scalar::ZERO.sub(neg_a), a);
2147 }
2148
2149 #[test]
2150 fn point_double_and_add_consistency() {
2151 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 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 let truncated: [u8; 63] = sig[..63].try_into().unwrap();
2257 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 let pb = key.public_key().to_bytes();
2270 let pk = PublicKey::from_bytes(&pb).unwrap();
2271 let _ = pk; }
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 let x3 = x.pow(&U256::from_u64(3));
2283 let expected = x.mul(x).mul(x);
2284 assert_eq!(x3, expected);
2285
2286 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 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 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}