1use crate::mont_field;
8use crate::nist::arith::{sqrt_p3mod4, Field};
9use crate::nist::point::Curve;
10use crate::nist::{ecdh, ecdsa};
11use ic_core::traits::{Algorithm, KeyAgreement, SelfTest, SignatureScheme};
12use ic_core::{ensure, Result};
13
14mont_field!(
15 Fp,
16 4,
17 32,
18 [
19 0xffff_ffff_ffff_ffff,
20 0x0000_0000_ffff_ffff,
21 0x0000_0000_0000_0000,
22 0xffff_ffff_0000_0001,
23 ],
24 "The P-256 coordinate field, GF(p) with p = 2^256 - 2^224 + 2^192 + 2^96 - 1."
25);
26
27mont_field!(
28 Fn,
29 4,
30 32,
31 [
32 0xf3b9_cac2_fc63_2551,
33 0xbce6_faad_a717_9e84,
34 0xffff_ffff_ffff_ffff,
35 0xffff_ffff_0000_0000,
36 ],
37 "The P-256 scalar ring, Z/nZ where n is the order of the base point."
38);
39
40#[derive(Debug, Clone, Copy)]
42pub struct P256;
43
44crate::nist::gentable::generator_table_for!(P256);
47
48impl Curve for P256 {
49 type Field = Fp;
50 type Scalar = Fn;
51
52 const NAME: &'static str = "P-256";
53 const FIELD_BYTES: usize = 32;
54 const SCALAR_BYTES: usize = 32;
55 const ORDER_BITS: usize = 256;
56
57 const B: Fp = Fp::to_mont_const([
59 0x3bce_3c3e_27d2_604b,
60 0x651d_06b0_cc53_b0f6,
61 0xb3eb_bd55_7698_86bc,
62 0x5ac6_35d8_aa3a_93e7,
63 ]);
64
65 const GX: Fp = Fp::to_mont_const([
66 0xf4a1_3945_d898_c296,
67 0x7703_7d81_2deb_33a0,
68 0xf8bc_e6e5_63a4_40f2,
69 0x6b17_d1f2_e12c_4247,
70 ]);
71
72 const GY: Fp = Fp::to_mont_const([
73 0xcbb6_4068_37bf_51f5,
74 0x2bce_3357_6b31_5ece,
75 0x8ee7_eb4a_7c0f_9e16,
76 0x4fe3_42e2_fe1a_7f9b,
77 ]);
78
79 fn sqrt(x: &Fp) -> Fp {
81 sqrt_p3mod4(x, Fp::MODULUS, |v, e| v.pow(e))
86 }
87
88 fn field_from_slice(bytes: &[u8]) -> Option<Fp> {
89 let mut b = [0u8; 32];
90 if bytes.len() != 32 {
91 return None;
92 }
93 b.copy_from_slice(bytes);
94 Fp::from_bytes(&b)
95 }
96
97 fn scalar_from_slice(bytes: &[u8]) -> Option<Fn> {
98 let mut b = [0u8; 32];
99 if bytes.len() != 32 {
100 return None;
101 }
102 b.copy_from_slice(bytes);
103 Fn::from_bytes(&b)
104 }
105
106 fn scalar_reduce_slice(bytes: &[u8]) -> Fn {
107 let mut b = [0u8; 32];
108 let n = core::cmp::min(32, bytes.len());
109 b[32 - n..].copy_from_slice(&bytes[..n]);
112 Fn::from_bytes_reduced(&b)
113 }
114}
115
116impl ecdsa::EcdsaCurve for P256 {
117 type Digest = ic_hash::Sha256;
118 type Hmac = ic_mac::HmacSha256;
119}
120
121pub struct EcdsaP256Sha256;
123
124impl Algorithm for EcdsaP256Sha256 {
125 const ID: &'static str = "ecdsa-p256-sha256";
126 const NAME: &'static str = "ECDSA P-256 with SHA-256";
127}
128
129impl SignatureScheme for EcdsaP256Sha256 {
130 const PRIVATE_KEY_LEN: usize = 32;
131 const PUBLIC_KEY_LEN: usize = 65;
133 const SIGNATURE_LEN: usize = 64;
135
136 fn public_key(private_key: &[u8], out: &mut [u8]) -> Result<()> {
137 ecdsa::public_key::<P256>(private_key, out)
138 }
139
140 fn sign(private_key: &[u8], message: &[u8], signature: &mut [u8]) -> Result<()> {
141 ecdsa::sign::<P256>(private_key, message, signature)
142 }
143
144 fn verify(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<()> {
145 ecdsa::verify::<P256>(public_key, message, signature)
146 }
147}
148
149impl EcdsaP256Sha256 {
150 pub fn verify_prehash(public_key: &[u8], digest: &[u8], signature: &[u8]) -> Result<()> {
158 ecdsa::verify_prehash::<P256>(public_key, digest, signature)
159 }
160
161 pub fn public_key_compressed(private_key: &[u8], out: &mut [u8]) -> Result<()> {
163 ecdsa::public_key_compressed::<P256>(private_key, out)
164 }
165
166 pub fn normalize_s(signature: &mut [u8]) -> Result<()> {
175 ecdsa::normalize_s::<P256>(signature)
176 }
177
178 pub fn has_low_s(signature: &[u8]) -> Result<bool> {
180 ecdsa::has_low_s::<P256>(signature)
181 }
182}
183
184impl SelfTest for EcdsaP256Sha256 {
185 fn self_test() -> Result<()> {
186 let mut key = [0u8; 32];
188 ic_core::codec::hex_decode(
189 b"c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
190 &mut key,
191 )?;
192 let mut want = [0u8; 64];
193 ic_core::codec::hex_decode(
194 b"efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
195 &mut want,
196 )?;
197
198 let mut sig = [0u8; 64];
199 <Self as SignatureScheme>::sign(&key, b"sample", &mut sig)?;
200 ensure!(
201 ic_core::ct::verify(&want, &sig),
202 SelfTestFailed,
203 "ecdsa-p256-sha256"
204 );
205
206 let mut pk = [0u8; 65];
207 <Self as SignatureScheme>::public_key(&key, &mut pk)?;
208 <Self as SignatureScheme>::verify(&pk, b"sample", &sig)?;
209
210 sig[0] ^= 1;
212 ensure!(
213 <Self as SignatureScheme>::verify(&pk, b"sample", &sig).is_err(),
214 SelfTestFailed,
215 "ecdsa-p256-sha256"
216 );
217 Ok(())
218 }
219}
220
221pub struct EcdhP256;
223
224impl Algorithm for EcdhP256 {
225 const ID: &'static str = "ecdh-p256";
226 const NAME: &'static str = "ECDH P-256";
227}
228
229impl KeyAgreement for EcdhP256 {
230 const PRIVATE_KEY_LEN: usize = 32;
231 const PUBLIC_KEY_LEN: usize = 65;
233 const SHARED_SECRET_LEN: usize = 32;
234
235 fn public_key(private_key: &[u8], out: &mut [u8]) -> Result<()> {
236 ecdh::public_key::<P256>(private_key, out)
237 }
238
239 fn agree(private_key: &[u8], peer_public_key: &[u8], out: &mut [u8]) -> Result<()> {
240 ecdh::agree::<P256>(private_key, peer_public_key, out)
241 }
242}
243
244impl EcdhP256 {
245 pub fn public_key_compressed(private_key: &[u8], out: &mut [u8]) -> Result<()> {
250 ecdh::public_key_compressed::<P256>(private_key, out)
251 }
252}
253
254impl SelfTest for EcdhP256 {
255 fn self_test() -> Result<()> {
256 let mut d = [0u8; 32];
258 ic_core::codec::hex_decode(
259 b"7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
260 &mut d,
261 )?;
262 let mut peer = [0u8; 65];
263 peer[0] = 0x04;
264 ic_core::codec::hex_decode(
265 b"700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287",
266 &mut peer[1..33],
267 )?;
268 ic_core::codec::hex_decode(
269 b"db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
270 &mut peer[33..],
271 )?;
272 let mut want = [0u8; 32];
273 ic_core::codec::hex_decode(
274 b"46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
275 &mut want,
276 )?;
277
278 let mut got = [0u8; 32];
279 <Self as KeyAgreement>::agree(&d, &peer, &mut got)?;
280 ensure!(
281 ic_core::ct::verify(&want, &got),
282 SelfTestFailed,
283 "ecdh-p256"
284 );
285 Ok(())
286 }
287}
288
289pub type Point = crate::nist::point::Point<P256>;
291pub type AffinePoint = crate::nist::point::AffinePoint<P256>;
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297 use ic_core::codec::{hex, unhex};
298
299 #[test]
303 #[ignore = "timing; run manually with --release"]
304 fn where_the_time_goes() {
305 use crate::nist::arith::Field;
306 use std::hint::black_box;
307 use std::time::Instant;
308 fn ns(label: &str, iters: u32, mut f: impl FnMut()) {
309 let mut best = f64::INFINITY;
310 for _ in 0..7 {
311 let t = Instant::now();
312 for _ in 0..iters {
313 f();
314 }
315 best = best.min(t.elapsed().as_secs_f64() * 1e9 / iters as f64);
316 }
317 std::println!("{label:32} {best:10.1} ns");
318 }
319 let a = Fp::to_mont([7, 11, 13, 17]);
320 let b = Fp::to_mont([19, 23, 29, 31]);
321 ns("fp mul", 2_000_000, || {
322 black_box(black_box(a).mul(&black_box(b)));
323 });
324 ns("fp square", 2_000_000, || {
325 black_box(black_box(a).square());
326 });
327 ns("fp add", 2_000_000, || {
328 black_box(black_box(a).add(&black_box(b)));
329 });
330 ns("fp sub", 2_000_000, || {
331 black_box(black_box(a).sub(&black_box(b)));
332 });
333 ns("fp invert", 2_000, || {
334 black_box(black_box(a).invert());
335 });
336 let g = Point::generator();
337 let p = g.double();
338 ns("point double", 200_000, || {
339 black_box(black_box(p).double());
340 });
341 ns("point add (complete)", 200_000, || {
342 black_box(black_box(p).add(&black_box(g)));
343 });
344 let k = Fn::to_mont([0x1234_5678, 0x9abc_def0, 0x1357_9bdf, 0x2468_ace0]);
345 ns("scalar invert", 2_000, || {
346 black_box(black_box(k).invert());
347 });
348 ns("mul_generator (table)", 2_000, || {
349 black_box(Point::mul_generator(&black_box(k)));
350 });
351 ns("mul_scalar (windowed)", 500, || {
352 black_box(black_box(p).mul_scalar(&black_box(k)));
353 });
354 ns("mul_scalar_vartime", 500, || {
355 black_box(black_box(p).mul_scalar_vartime(&black_box(k)));
356 });
357 ns("to_affine", 2_000, || {
358 black_box(black_box(p).to_affine());
359 });
360 let mut sig = [0u8; 64];
361 ns("ecdsa sign", 500, || {
362 EcdsaP256Sha256::sign(&[0x5a; 32], b"message", &mut sig).unwrap();
363 });
364 }
365
366 fn scalar(v: u64) -> Fn {
367 Fn::to_mont([v, 0, 0, 0])
368 }
369
370 fn fp(v: u64) -> Fp {
371 Fp::to_mont([v, 0, 0, 0])
372 }
373
374 #[test]
377 fn montgomery_constants_are_consistent() {
378 assert_eq!(Fp::MODULUS[0].wrapping_mul(Fp::NEG_INV), u64::MAX, "p");
379 assert_eq!(Fn::MODULUS[0].wrapping_mul(Fn::NEG_INV), u64::MAX, "n");
380 }
381
382 #[test]
383 fn small_arithmetic_matches_integers() {
384 assert_eq!(fp(2).add(&fp(3)), fp(5));
385 assert_eq!(fp(5).sub(&fp(3)), fp(2));
386 assert_eq!(fp(6).mul(&fp(7)), fp(42));
387 assert_eq!(fp(9).square(), fp(81));
388 assert_eq!(fp(5).double(), fp(10));
389 assert_eq!(fp(5).triple(), fp(15));
390 assert_eq!(Fp::ONE.from_mont(), [1, 0, 0, 0]);
391 }
392
393 #[test]
394 fn inversion_is_correct() {
395 for v in [1u64, 2, 3, 19, 65537, u32::MAX as u64] {
396 assert_eq!(fp(v).mul(&fp(v).invert()), Fp::ONE, "1/{v} in Fp");
397 assert_eq!(scalar(v).mul(&scalar(v).invert()), Fn::ONE, "1/{v} in Fn");
398 }
399 assert_eq!(Fp::ZERO.invert(), Fp::ZERO);
400 }
401
402 #[test]
403 fn arithmetic_laws_hold_on_large_values() {
404 let a = P256::field_from_slice(&[0x3a; 32]).unwrap();
405 let b = P256::field_from_slice(&[0x91; 32]).unwrap();
406 let c = P256::field_from_slice(&[0xc7; 32]).unwrap();
407 assert_eq!(a.mul(&b).mul(&c), a.mul(&b.mul(&c)), "associativity");
408 assert_eq!(a.mul(&b), b.mul(&a), "commutativity");
409 assert_eq!(
410 a.mul(&b.add(&c)),
411 a.mul(&b).add(&a.mul(&c)),
412 "distributivity"
413 );
414 assert_eq!(a.add(&a.neg()), Fp::ZERO);
415 }
416
417 #[test]
418 fn byte_encoding_round_trips_and_rejects_non_canonical() {
419 let bytes = [0x7fu8; 32];
420 let a = P256::field_from_slice(&bytes).unwrap();
421 assert_eq!(a.to_bytes(), bytes);
422
423 let mut p_bytes = [0u8; 32];
425 for i in 0..4 {
426 let hi = 32 - i * 8;
427 p_bytes[hi - 8..hi].copy_from_slice(&Fp::MODULUS[i].to_be_bytes());
428 }
429 assert!(P256::field_from_slice(&p_bytes).is_none());
430 }
431
432 #[test]
437 fn the_base_point_is_on_the_curve() {
438 let g = Point::generator().to_affine().unwrap();
439 assert!(bool::from(g.is_on_curve()));
440 }
441
442 #[test]
444 fn the_base_point_has_order_n() {
445 let n_minus_1 = Fn::ZERO.sub(&Fn::ONE);
446 let p = Point::generator().mul_scalar(&n_minus_1);
447 assert!(
448 bool::from(p.ct_eq(&Point::generator().neg())),
449 "[n-1]G == -G"
450 );
451 assert!(
452 bool::from(p.add(&Point::generator()).is_identity()),
453 "[n]G is the identity"
454 );
455 }
456
457 #[test]
458 fn identity_and_negation_behave() {
459 let g = Point::generator();
460 assert!(bool::from(g.add(&Point::identity()).ct_eq(&g)));
461 assert!(bool::from(Point::identity().add(&g).ct_eq(&g)));
462 assert!(bool::from(Point::identity().double().is_identity()));
463 assert!(bool::from(g.add(&g.neg()).is_identity()));
464 assert!(Point::identity().to_affine().is_none());
465 }
466
467 #[test]
469 fn addition_handles_equal_inputs_as_a_doubling() {
470 let g = Point::generator();
471 assert!(bool::from(g.add(&g).ct_eq(&g.double())));
472 let p = g.mul_scalar(&scalar(5));
473 assert!(bool::from(p.add(&p).ct_eq(&p.double())));
474 }
475
476 #[test]
485 fn the_vartime_multiplication_agrees_with_the_ladder() {
486 let g = Point::generator();
487
488 let mut checked = 0;
489 for raw in [
490 [0u8; 32],
491 {
492 let mut v = [0u8; 32];
493 v[31] = 1;
494 v
495 },
496 [0xffu8; 32],
497 [0x55u8; 32],
498 [0xaau8; 32],
499 [0x9du8; 32],
500 ] {
501 let k = Fn::from_bytes_reduced(&raw);
502 assert!(
503 bool::from(g.mul_scalar_vartime(&k).ct_eq(&g.mul_scalar(&k))),
504 "vartime and ladder differ for {raw:02x?}"
505 );
506 checked += 1;
507 }
508 assert_eq!(checked, 6, "the comparison did not run");
509 }
510
511 #[test]
512 fn scalar_multiplication_matches_repeated_addition() {
513 let g = Point::generator();
514 let mut acc = Point::identity();
515 for k in 1..=10u64 {
516 acc = acc.add(&g);
517 assert!(bool::from(acc.ct_eq(&g.mul_scalar(&scalar(k)))), "[{k}]G");
518 }
519 }
520
521 #[test]
522 fn scalar_multiplication_is_linear() {
523 let g = Point::generator();
524 let a = scalar(1_234_567);
525 let b = scalar(7_654_321);
526 assert!(bool::from(
527 g.mul_scalar(&a.add(&b))
528 .ct_eq(&g.mul_scalar(&a).add(&g.mul_scalar(&b)))
529 ));
530 assert!(bool::from(
531 g.mul_scalar(&a)
532 .mul_scalar(&b)
533 .ct_eq(&g.mul_scalar(&a.mul(&b)))
534 ));
535 }
536
537 #[test]
540 fn two_g_matches_the_published_value() {
541 let two_g = Point::generator().double().to_affine().unwrap();
542 assert_eq!(
543 hex(two_g.x.to_bytes().as_ref()),
544 "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978"
545 );
546 assert_eq!(
547 hex(two_g.y.to_bytes().as_ref()),
548 "07775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d1"
549 );
550 }
551
552 #[test]
553 fn sec1_round_trips_in_both_forms() {
554 let g = Point::generator();
555 for k in [1u64, 2, 3, 4, 5, 6, 7, 8] {
556 let p = g.mul_scalar(&scalar(k)).to_affine().unwrap();
557 let mut unc = [0u8; 65];
558 let mut comp = [0u8; 33];
559 assert!(p.write_uncompressed(&mut unc));
560 assert!(p.write_compressed(&mut comp));
561 assert_eq!(unc[0], 0x04);
562 assert!(comp[0] == 0x02 || comp[0] == 0x03);
563
564 let a = AffinePoint::from_sec1(&unc).unwrap();
565 let b = AffinePoint::from_sec1(&comp).unwrap();
566 assert_eq!(a.x, p.x);
567 assert_eq!(a.y, p.y);
568 assert_eq!(b.x, p.x);
569 assert_eq!(b.y, p.y, "compressed y for [{k}]G");
570 }
571 }
572
573 #[test]
574 fn decoding_rejects_bad_encodings() {
575 let g = Point::generator().to_affine().unwrap();
576 let mut unc = [0u8; 65];
577 assert!(g.write_uncompressed(&mut unc));
578
579 assert!(AffinePoint::from_sec1(&[]).is_none());
580 assert!(AffinePoint::from_sec1(&[0u8; 65]).is_none(), "identity");
581 assert!(AffinePoint::from_sec1(&unc[..64]).is_none(), "truncated");
582
583 let mut bad = unc;
584 bad[0] = 0x05;
585 assert!(AffinePoint::from_sec1(&bad).is_none(), "bad tag");
586
587 let mut bad = unc;
588 bad[64] ^= 1;
589 assert!(AffinePoint::from_sec1(&bad).is_none(), "off curve");
590 }
591
592 const KEY: &str = "c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721";
595
596 #[test]
600 fn rfc6979_sample_vector() {
601 let key = unhex(KEY).unwrap();
602 let mut sig = [0u8; 64];
603 EcdsaP256Sha256::sign(&key, b"sample", &mut sig).unwrap();
604 assert_eq!(
605 hex(&sig[..32]),
606 "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716",
607 "r"
608 );
609 assert_eq!(
610 hex(&sig[32..]),
611 "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8",
612 "s"
613 );
614 }
615
616 #[test]
618 fn rfc6979_test_vector() {
619 let key = unhex(KEY).unwrap();
620 let mut sig = [0u8; 64];
621 EcdsaP256Sha256::sign(&key, b"test", &mut sig).unwrap();
622 assert_eq!(
623 hex(&sig[..32]),
624 "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367",
625 "r"
626 );
627 assert_eq!(
628 hex(&sig[32..]),
629 "019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083",
630 "s"
631 );
632 }
633
634 #[test]
635 fn rfc6979_public_key() {
636 let key = unhex(KEY).unwrap();
637 let mut pk = [0u8; 65];
638 EcdsaP256Sha256::public_key(&key, &mut pk).unwrap();
639 assert_eq!(
640 hex(&pk[1..33]),
641 "60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
642 "Ux"
643 );
644 assert_eq!(
645 hex(&pk[33..]),
646 "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
647 "Uy"
648 );
649 }
650
651 #[test]
652 fn signing_is_deterministic_and_message_bound() {
653 let key = unhex(KEY).unwrap();
654 let mut a = [0u8; 64];
655 let mut b = [0u8; 64];
656 EcdsaP256Sha256::sign(&key, b"same", &mut a).unwrap();
657 EcdsaP256Sha256::sign(&key, b"same", &mut b).unwrap();
658 assert_eq!(a, b, "RFC 6979 signing must not depend on an RNG");
659
660 EcdsaP256Sha256::sign(&key, b"other", &mut b).unwrap();
661 assert_ne!(&a[..32], &b[..32], "r must differ between messages");
662 }
663
664 #[test]
665 fn sign_and_verify_round_trip() {
666 let key = unhex(KEY).unwrap();
667 let mut pk = [0u8; 65];
668 EcdsaP256Sha256::public_key(&key, &mut pk).unwrap();
669 for message in [&b""[..], b"short", &[0x5au8; 1000][..]] {
670 let mut sig = [0u8; 64];
671 EcdsaP256Sha256::sign(&key, message, &mut sig).unwrap();
672 EcdsaP256Sha256::verify(&pk, message, &sig).unwrap();
673 }
674 }
675
676 #[test]
677 fn verification_rejects_tampering() {
678 let key = unhex(KEY).unwrap();
679 let mut pk = [0u8; 65];
680 EcdsaP256Sha256::public_key(&key, &mut pk).unwrap();
681 let mut sig = [0u8; 64];
682 EcdsaP256Sha256::sign(&key, b"authentic", &mut sig).unwrap();
683
684 assert!(EcdsaP256Sha256::verify(&pk, b"forged", &sig).is_err());
685 let mut bad = sig;
686 bad[0] ^= 1;
687 assert!(EcdsaP256Sha256::verify(&pk, b"authentic", &bad).is_err());
688 let mut bad = sig;
689 bad[63] ^= 1;
690 assert!(EcdsaP256Sha256::verify(&pk, b"authentic", &bad).is_err());
691
692 let mut other = [0u8; 65];
693 EcdsaP256Sha256::public_key(&[0x11u8; 32], &mut other).unwrap();
694 assert!(EcdsaP256Sha256::verify(&other, b"authentic", &sig).is_err());
695 }
696
697 #[test]
698 fn verification_rejects_degenerate_signatures() {
699 let key = unhex(KEY).unwrap();
700 let mut pk = [0u8; 65];
701 EcdsaP256Sha256::public_key(&key, &mut pk).unwrap();
702
703 let mut zero_r = [0u8; 64];
704 zero_r[63] = 1;
705 assert!(EcdsaP256Sha256::verify(&pk, b"m", &zero_r).is_err());
706
707 let mut zero_s = [0u8; 64];
708 zero_s[31] = 1;
709 assert!(EcdsaP256Sha256::verify(&pk, b"m", &zero_s).is_err());
710
711 let n_bytes =
712 unhex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551").unwrap();
713 let mut at_n = [0u8; 64];
714 at_n[..32].copy_from_slice(&n_bytes);
715 at_n[32..].copy_from_slice(&n_bytes);
716 assert!(EcdsaP256Sha256::verify(&pk, b"m", &at_n).is_err());
717 }
718
719 #[test]
720 fn signing_rejects_invalid_private_keys() {
721 let mut sig = [0u8; 64];
722 assert!(
723 EcdsaP256Sha256::sign(&[0u8; 32], b"m", &mut sig).is_err(),
724 "zero"
725 );
726 assert!(
727 EcdsaP256Sha256::sign(&[0xffu8; 32], b"m", &mut sig).is_err(),
728 ">= n"
729 );
730 assert!(
731 EcdsaP256Sha256::sign(&[1u8; 31], b"m", &mut sig).is_err(),
732 "short"
733 );
734 }
735
736 #[test]
738 fn malleability_and_normalization() {
739 let key = unhex(KEY).unwrap();
740 let mut pk = [0u8; 65];
741 EcdsaP256Sha256::public_key(&key, &mut pk).unwrap();
742 let mut sig = [0u8; 64];
743 EcdsaP256Sha256::sign(&key, b"sample", &mut sig).unwrap();
744 assert!(
745 !EcdsaP256Sha256::has_low_s(&sig).unwrap(),
746 "RFC 6979 s is high here"
747 );
748
749 let mut flipped = sig;
750 EcdsaP256Sha256::normalize_s(&mut flipped).unwrap();
751 assert_ne!(flipped, sig);
752 EcdsaP256Sha256::verify(&pk, b"sample", &flipped).unwrap();
753 assert!(EcdsaP256Sha256::has_low_s(&flipped).unwrap());
754
755 let mut twice = flipped;
756 EcdsaP256Sha256::normalize_s(&mut twice).unwrap();
757 assert_eq!(twice, flipped, "normalization must be idempotent");
758 }
759
760 #[test]
761 fn ecdsa_self_test_passes() {
762 EcdsaP256Sha256::self_test().unwrap();
763 }
764
765 #[test]
769 fn cavp_ecc_cdh_vector() {
770 let d = unhex("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534").unwrap();
771 let mut peer = vec![0x04u8];
772 peer.extend_from_slice(
773 &unhex("700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287").unwrap(),
774 );
775 peer.extend_from_slice(
776 &unhex("db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac").unwrap(),
777 );
778 let mut z = [0u8; 32];
779 EcdhP256::agree(&d, &peer, &mut z).unwrap();
780 assert_eq!(
781 hex(&z),
782 "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b"
783 );
784 }
785
786 #[test]
787 fn both_parties_derive_the_same_secret() {
788 let (alice, bob) = ([0x11u8; 32], [0x22u8; 32]);
789 let mut alice_pk = [0u8; 65];
790 let mut bob_pk = [0u8; 65];
791 EcdhP256::public_key(&alice, &mut alice_pk).unwrap();
792 EcdhP256::public_key(&bob, &mut bob_pk).unwrap();
793
794 let mut z1 = [0u8; 32];
795 let mut z2 = [0u8; 32];
796 EcdhP256::agree(&alice, &bob_pk, &mut z1).unwrap();
797 EcdhP256::agree(&bob, &alice_pk, &mut z2).unwrap();
798 assert_eq!(z1, z2);
799 assert_ne!(z1, [0u8; 32]);
800 }
801
802 #[test]
803 fn compressed_and_uncompressed_peers_agree() {
804 let (alice, bob) = ([0x33u8; 32], [0x44u8; 32]);
805 let mut unc = [0u8; 65];
806 let mut comp = [0u8; 33];
807 EcdhP256::public_key(&bob, &mut unc).unwrap();
808 EcdhP256::public_key_compressed(&bob, &mut comp).unwrap();
809
810 let mut z1 = [0u8; 32];
811 let mut z2 = [0u8; 32];
812 EcdhP256::agree(&alice, &unc, &mut z1).unwrap();
813 EcdhP256::agree(&alice, &comp, &mut z2).unwrap();
814 assert_eq!(z1, z2, "the peer key encoding must not matter");
815 }
816
817 #[test]
818 fn ecdh_rejects_invalid_inputs() {
819 let alice = [0x11u8; 32];
820 let mut z = [0u8; 32];
821 assert!(EcdhP256::agree(&alice, &[0u8; 65], &mut z).is_err());
822 assert!(EcdhP256::agree(&alice, &[], &mut z).is_err());
823
824 let mut bob_pk = [0u8; 65];
825 EcdhP256::public_key(&[0x22u8; 32], &mut bob_pk).unwrap();
826 bob_pk[64] ^= 1;
827 assert!(
828 EcdhP256::agree(&alice, &bob_pk, &mut z).is_err(),
829 "off curve"
830 );
831
832 let mut pk = [0u8; 65];
833 assert!(EcdhP256::public_key(&[0u8; 32], &mut pk).is_err());
834 assert!(EcdhP256::public_key(&[0xffu8; 32], &mut pk).is_err());
835 }
836
837 #[test]
838 fn ecdh_self_test_passes() {
839 EcdhP256::self_test().unwrap();
840 }
841}