1use core::fmt;
6
7use neco_galois::generate_k;
8use neco_galois::{Fp, P256Field, P256Order, PrimeField, SQRT_EXP_P256, U256};
9
10type FpField = Fp<P256Field>;
15type Scalar = Fp<P256Order>;
16
17fn curve_a() -> FpField {
26 let (a_val, _) = U256::sub(P256Field::MODULUS, U256::from_u64(3));
27 FpField::from_u256(a_val)
28}
29
30fn curve_b() -> FpField {
32 FpField::from_u256(U256::from_be_bytes([
33 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86,
34 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2,
35 0x60, 0x4b,
36 ]))
37}
38
39fn generator_x() -> FpField {
41 FpField::from_u256(U256::from_be_bytes([
42 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40,
43 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98,
44 0xc2, 0x96,
45 ]))
46}
47
48fn generator_y() -> FpField {
50 FpField::from_u256(U256::from_be_bytes([
51 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
52 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf,
53 0x51, 0xf5,
54 ]))
55}
56
57fn order_u256() -> U256 {
59 P256Order::MODULUS
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68struct AffinePoint {
69 x: FpField,
70 y: FpField,
71}
72
73#[derive(Clone, Copy, Debug)]
75struct ProjectivePoint {
76 x: FpField,
77 y: FpField,
78 z: FpField,
79 is_infinity: bool,
80}
81
82impl ProjectivePoint {
83 fn infinity() -> Self {
84 ProjectivePoint {
85 x: FpField::ZERO,
86 y: FpField::ZERO,
87 z: FpField::ZERO,
88 is_infinity: true,
89 }
90 }
91
92 fn from_affine(p: AffinePoint) -> Self {
93 ProjectivePoint {
94 x: p.x,
95 y: p.y,
96 z: FpField::one(),
97 is_infinity: false,
98 }
99 }
100}
101
102fn point_double(p: ProjectivePoint) -> ProjectivePoint {
109 if p.is_infinity {
110 return ProjectivePoint::infinity();
111 }
112
113 let x = p.x;
114 let y = p.y;
115 let z = p.z;
116
117 let z2 = FpField::sqr(z);
119 let xmz2 = FpField::sub(x, z2);
120 let xpz2 = FpField::add(x, z2);
121 let m_part = FpField::mul(xmz2, xpz2);
122 let two_m = FpField::add(m_part, m_part);
123 let m = FpField::add(two_m, m_part); let y2 = FpField::sqr(y);
127 let xy = FpField::mul(x, y2);
128 let two_xy = FpField::add(xy, xy);
129 let s = FpField::add(two_xy, two_xy);
130
131 let m2 = FpField::sqr(m);
133 let two_s = FpField::add(s, s);
134 let x_new = FpField::sub(m2, two_s);
135
136 let s_minus_x = FpField::sub(s, x_new);
138 let my = FpField::mul(m, s_minus_x);
139 let y4 = FpField::sqr(y2);
140 let eight_y4 = {
141 let two = FpField::add(y4, y4);
142 let four = FpField::add(two, two);
143 FpField::add(four, four)
144 };
145 let y_new = FpField::sub(my, eight_y4);
146
147 let yz = FpField::mul(y, z);
149 let z_new = FpField::add(yz, yz);
150
151 ProjectivePoint {
152 x: x_new,
153 y: y_new,
154 z: z_new,
155 is_infinity: false,
156 }
157}
158
159fn point_add(p: ProjectivePoint, q: ProjectivePoint) -> ProjectivePoint {
161 if p.is_infinity {
162 return q;
163 }
164 if q.is_infinity {
165 return p;
166 }
167
168 let x1 = p.x;
169 let y1 = p.y;
170 let z1 = p.z;
171 let x2 = q.x;
172 let y2 = q.y;
173 let z2 = q.z;
174
175 let z1_sq = FpField::sqr(z1);
177 let z2_sq = FpField::sqr(z2);
178 let u1 = FpField::mul(x1, z2_sq);
179 let u2 = FpField::mul(x2, z1_sq);
180
181 let s1 = FpField::mul(y1, FpField::mul(z2, z2_sq));
183 let s2 = FpField::mul(y2, FpField::mul(z1, z1_sq));
184
185 let h = FpField::sub(u2, u1);
186 let r = FpField::sub(s2, s1);
187
188 if FpField::is_zero(h) {
189 if FpField::is_zero(r) {
190 return point_double(p);
191 } else {
192 return ProjectivePoint::infinity();
193 }
194 }
195
196 let h2 = FpField::sqr(h);
197 let h3 = FpField::mul(h, h2);
198 let u1h2 = FpField::mul(u1, h2);
199
200 let r2 = FpField::sqr(r);
202 let two_u1h2 = FpField::add(u1h2, u1h2);
203 let x3 = FpField::sub(FpField::sub(r2, h3), two_u1h2);
204
205 let u1h2_minus_x3 = FpField::sub(u1h2, x3);
207 let s1h3 = FpField::mul(s1, h3);
208 let y3 = FpField::sub(FpField::mul(r, u1h2_minus_x3), s1h3);
209
210 let z3 = FpField::mul(h, FpField::mul(z1, z2));
212
213 ProjectivePoint {
214 x: x3,
215 y: y3,
216 z: z3,
217 is_infinity: false,
218 }
219}
220
221fn to_affine(p: ProjectivePoint) -> Option<AffinePoint> {
223 if p.is_infinity {
224 return None;
225 }
226 let z_inv = FpField::inv(p.z);
227 let z_inv2 = FpField::sqr(z_inv);
228 let z_inv3 = FpField::mul(z_inv, z_inv2);
229 let x = FpField::mul(p.x, z_inv2);
230 let y = FpField::mul(p.y, z_inv3);
231 Some(AffinePoint { x, y })
232}
233
234fn scalar_mul(k: U256, p: AffinePoint) -> ProjectivePoint {
236 let mut r0 = ProjectivePoint::infinity();
237 let mut r1 = ProjectivePoint::from_affine(p);
238
239 for i in (0..256u32).rev() {
240 if U256::bit(k, i) {
241 r0 = point_add(r0, r1);
242 r1 = point_double(r1);
243 } else {
244 r1 = point_add(r0, r1);
245 r0 = point_double(r0);
246 }
247 }
248 r0
249}
250
251fn is_on_curve(p: AffinePoint) -> bool {
253 let x = p.x;
254 let y = p.y;
255 let a = curve_a();
256 let b = curve_b();
257
258 let y2 = FpField::sqr(y);
259 let x3 = FpField::mul(FpField::sqr(x), x);
260 let ax = FpField::mul(a, x);
261 let rhs = FpField::add(FpField::add(x3, ax), b);
262
263 FpField::eq(y2, rhs)
264}
265
266fn encode_sec1_compressed(p: AffinePoint) -> [u8; 33] {
272 let x_bytes = p.x.to_u256().to_be_bytes();
273 let y_val = p.y.to_u256();
274 let prefix = if y_val.l0 & 1 == 1 { 0x03u8 } else { 0x02u8 };
275 let mut out = [0u8; 33];
276 out[0] = prefix;
277 out[1..].copy_from_slice(&x_bytes);
278 out
279}
280
281fn decode_sec1_compressed(bytes: &[u8]) -> Option<AffinePoint> {
283 if bytes.len() != 33 {
284 return None;
285 }
286 let prefix = bytes[0];
287 if prefix != 0x02 && prefix != 0x03 {
288 return None;
289 }
290 let x_bytes: [u8; 32] = bytes[1..].try_into().ok()?;
291 let x_u256 = U256::from_be_bytes(x_bytes);
292
293 if let core::cmp::Ordering::Less = U256::cmp(x_u256, P256Field::MODULUS) {
295 } else {
297 return None;
298 }
299
300 let x = FpField::from_u256(x_u256);
301 let a = curve_a();
302 let b = curve_b();
303
304 let x3 = FpField::mul(FpField::sqr(x), x);
306 let ax = FpField::mul(a, x);
307 let rhs = FpField::add(FpField::add(x3, ax), b);
308
309 let y = FpField::sqrt(rhs, SQRT_EXP_P256)?;
310 let y_u256 = y.to_u256();
311
312 let y_odd = y_u256.l0 & 1 == 1;
314 let want_odd = prefix == 0x03;
315
316 let y_final = if y_odd == want_odd {
317 y
318 } else {
319 FpField::neg(y)
320 };
321
322 let point = AffinePoint { x, y: y_final };
323
324 if !is_on_curve(point) {
325 return None;
326 }
327
328 Some(point)
329}
330
331fn normalize_s(s: U256, n: U256) -> U256 {
337 let half_n = U256::shr1(n);
338 if let core::cmp::Ordering::Greater = U256::cmp(s, half_n) {
339 let (ns, _) = U256::sub(n, s);
340 ns
341 } else {
342 s
343 }
344}
345
346fn ecdsa_sign(secret_bytes: &[u8; 32], digest: &[u8; 32]) -> Option<[u8; 64]> {
348 let n = order_u256();
349 let g = AffinePoint {
350 x: generator_x(),
351 y: generator_y(),
352 };
353
354 let d = U256::from_be_bytes(*secret_bytes);
355
356 let k = generate_k(secret_bytes, digest, &n);
358
359 let r_proj = scalar_mul(k, g);
361 let r_affine = to_affine(r_proj)?;
362
363 let rx = r_affine.x.to_u256();
365 let r = if let core::cmp::Ordering::Less = U256::cmp(rx, n) {
366 rx
367 } else {
368 let (v, _) = U256::sub(rx, n);
369 v
370 };
371 if U256::is_zero(r) {
372 return None;
373 }
374
375 let e_raw = U256::from_be_bytes(*digest);
377 let e = if let core::cmp::Ordering::Less = U256::cmp(e_raw, n) {
378 e_raw
379 } else {
380 let (v, _) = U256::sub(e_raw, n);
381 v
382 };
383
384 let k_scalar = Scalar::from_u256(k);
386 let k_inv = Scalar::inv(k_scalar);
387 let r_scalar = Scalar::from_u256(r);
388 let d_scalar = Scalar::from_u256(d);
389 let e_scalar = Scalar::from_u256(e);
390
391 let rd = Scalar::mul(r_scalar, d_scalar);
392 let e_plus_rd = Scalar::add(e_scalar, rd);
393 let s_scalar = Scalar::mul(k_inv, e_plus_rd);
394 let s = s_scalar.to_u256();
395
396 if U256::is_zero(s) {
397 return None;
398 }
399
400 let s = normalize_s(s, n);
402
403 let mut out = [0u8; 64];
404 out[..32].copy_from_slice(&r.to_be_bytes());
405 out[32..].copy_from_slice(&s.to_be_bytes());
406 Some(out)
407}
408
409fn ecdsa_verify(pubkey_sec1: &[u8; 33], digest: &[u8; 32], sig_bytes: &[u8; 64]) -> bool {
411 let n = order_u256();
412 let g = AffinePoint {
413 x: generator_x(),
414 y: generator_y(),
415 };
416
417 let r = U256::from_be_bytes(sig_bytes[..32].try_into().unwrap());
418 let s = U256::from_be_bytes(sig_bytes[32..].try_into().unwrap());
419
420 if U256::is_zero(r) || U256::is_zero(s) {
422 return false;
423 }
424 if !matches!(U256::cmp(r, n), core::cmp::Ordering::Less) {
425 return false;
426 }
427 if !matches!(U256::cmp(s, n), core::cmp::Ordering::Less) {
428 return false;
429 }
430
431 let half_n = U256::shr1(n);
433 if let core::cmp::Ordering::Greater = U256::cmp(s, half_n) {
434 return false;
435 }
436
437 let pubkey = match decode_sec1_compressed(pubkey_sec1) {
439 Some(p) => p,
440 None => return false,
441 };
442
443 let e_raw = U256::from_be_bytes(*digest);
445 let e = if let core::cmp::Ordering::Less = U256::cmp(e_raw, n) {
446 e_raw
447 } else {
448 let (v, _) = U256::sub(e_raw, n);
449 v
450 };
451
452 let s_scalar = Scalar::from_u256(s);
454 let w_scalar = Scalar::inv(s_scalar);
455
456 let e_scalar = Scalar::from_u256(e);
458 let r_scalar = Scalar::from_u256(r);
459
460 let u1 = Scalar::mul(e_scalar, w_scalar).to_u256();
461 let u2 = Scalar::mul(r_scalar, w_scalar).to_u256();
462
463 let u1g = scalar_mul(u1, g);
465 let u2q = scalar_mul(u2, pubkey);
466 let r_point = point_add(u1g, u2q);
467
468 let r_affine = match to_affine(r_point) {
469 Some(p) => p,
470 None => return false,
471 };
472
473 let r_x = r_affine.x.to_u256();
475 let r_x_mod_n = if let core::cmp::Ordering::Less = U256::cmp(r_x, n) {
476 r_x
477 } else {
478 let (v, _) = U256::sub(r_x, n);
479 v
480 };
481
482 U256::cmp(r_x_mod_n, r) == core::cmp::Ordering::Equal
483}
484
485#[derive(Debug, Clone, PartialEq, Eq)]
490pub enum P256Error {
491 InvalidSecretKey,
492 InvalidPublicKey,
493 InvalidSignature,
494 InvalidHex(&'static str),
495}
496
497impl fmt::Display for P256Error {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 match self {
500 Self::InvalidSecretKey => f.write_str("invalid secret key"),
501 Self::InvalidPublicKey => f.write_str("invalid public key"),
502 Self::InvalidSignature => f.write_str("invalid signature"),
503 Self::InvalidHex(message) => f.write_str(message),
504 }
505 }
506}
507
508impl std::error::Error for P256Error {}
509
510fn hex_encode(bytes: &[u8]) -> String {
515 const HEX: &[u8; 16] = b"0123456789abcdef";
516 let mut s = String::with_capacity(bytes.len() * 2);
517 for &b in bytes {
518 s.push(HEX[(b >> 4) as usize] as char);
519 s.push(HEX[(b & 0x0f) as usize] as char);
520 }
521 s
522}
523
524fn hex_decode(hex: &str) -> Result<Vec<u8>, P256Error> {
525 let hex = hex.as_bytes();
526 if hex.len() % 2 != 0 {
527 return Err(P256Error::InvalidHex("odd length"));
528 }
529
530 let mut out = Vec::with_capacity(hex.len() / 2);
531 for chunk in hex.chunks(2) {
532 let high = hex_nibble(chunk[0])?;
533 let low = hex_nibble(chunk[1])?;
534 out.push((high << 4) | low);
535 }
536 Ok(out)
537}
538
539fn hex_nibble(b: u8) -> Result<u8, P256Error> {
540 match b {
541 b'0'..=b'9' => Ok(b - b'0'),
542 b'a'..=b'f' => Ok(b - b'a' + 10),
543 b'A'..=b'F' => Ok(b - b'A' + 10),
544 _ => Err(P256Error::InvalidHex("invalid character")),
545 }
546}
547
548fn validate_secret_key(bytes: &[u8; 32]) -> bool {
553 let d = U256::from_be_bytes(*bytes);
554 if U256::is_zero(d) {
555 return false;
556 }
557 matches!(U256::cmp(d, order_u256()), core::cmp::Ordering::Less)
558}
559
560#[derive(Debug, Clone, Copy, PartialEq, Eq)]
565pub struct SecretKey {
566 bytes: [u8; 32],
567}
568
569impl SecretKey {
570 pub fn generate() -> Result<Self, P256Error> {
571 let n = order_u256();
572 loop {
573 let mut buf = [0u8; 32];
574 getrandom::getrandom(&mut buf).map_err(|_| P256Error::InvalidSecretKey)?;
575 let k = U256::from_be_bytes(buf);
576 if !U256::is_zero(k) {
577 if let core::cmp::Ordering::Less = U256::cmp(k, n) {
578 return Ok(Self { bytes: buf });
579 }
580 }
581 }
582 }
583
584 pub fn from_hex(hex: &str) -> Result<Self, P256Error> {
585 let bytes = hex_decode(hex)?;
586 if bytes.len() != 32 {
587 return Err(P256Error::InvalidHex("expected 64 hex characters"));
588 }
589
590 let mut arr = [0u8; 32];
591 arr.copy_from_slice(&bytes);
592 Self::from_bytes(arr)
593 }
594
595 pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, P256Error> {
596 if !validate_secret_key(&bytes) {
597 return Err(P256Error::InvalidSecretKey);
598 }
599 Ok(Self { bytes })
600 }
601
602 pub fn to_hex(&self) -> String {
603 hex_encode(&self.bytes)
604 }
605
606 pub fn to_bytes(&self) -> [u8; 32] {
607 self.bytes
608 }
609
610 pub fn public_key(&self) -> Result<PublicKey, P256Error> {
611 let d = U256::from_be_bytes(self.bytes);
612 let g = AffinePoint {
613 x: generator_x(),
614 y: generator_y(),
615 };
616 let q_proj = scalar_mul(d, g);
617 let q = to_affine(q_proj).ok_or(P256Error::InvalidSecretKey)?;
618 let sec1_bytes = encode_sec1_compressed(q);
619 Ok(PublicKey { sec1_bytes })
620 }
621
622 pub fn sign_ecdsa_prehash(&self, digest32: [u8; 32]) -> Result<EcdsaSignature, P256Error> {
623 let sig_bytes = ecdsa_sign(&self.bytes, &digest32).ok_or(P256Error::InvalidSignature)?;
624 Ok(EcdsaSignature { bytes: sig_bytes })
625 }
626}
627
628#[derive(Debug, Clone, Copy, PartialEq, Eq)]
629pub struct PublicKey {
630 sec1_bytes: [u8; 33],
631}
632
633impl PublicKey {
634 pub fn from_hex(hex: &str) -> Result<Self, P256Error> {
635 let bytes = hex_decode(hex)?;
636 if bytes.len() != 33 {
637 return Err(P256Error::InvalidHex("expected 66 hex characters"));
638 }
639 Self::from_sec1_bytes(&bytes)
640 }
641
642 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self, P256Error> {
643 if bytes.len() != 33 {
644 return Err(P256Error::InvalidPublicKey);
645 }
646 let point = decode_sec1_compressed(bytes).ok_or(P256Error::InvalidPublicKey)?;
647 let sec1_bytes = encode_sec1_compressed(point);
648 Ok(Self { sec1_bytes })
649 }
650
651 pub fn to_hex(&self) -> String {
652 hex_encode(&self.sec1_bytes)
653 }
654
655 pub fn to_sec1_bytes(&self) -> [u8; 33] {
656 self.sec1_bytes
657 }
658
659 pub fn verify_ecdsa_prehash(
660 &self,
661 digest32: [u8; 32],
662 sig: &EcdsaSignature,
663 ) -> Result<(), P256Error> {
664 if ecdsa_verify(&self.sec1_bytes, &digest32, &sig.bytes) {
665 Ok(())
666 } else {
667 Err(P256Error::InvalidSignature)
668 }
669 }
670}
671
672#[derive(Debug, Clone, Copy, PartialEq, Eq)]
673pub struct EcdsaSignature {
674 bytes: [u8; 64],
675}
676
677impl EcdsaSignature {
678 pub fn from_hex(hex: &str) -> Result<Self, P256Error> {
679 let bytes = hex_decode(hex)?;
680 if bytes.len() != 64 {
681 return Err(P256Error::InvalidHex("expected 128 hex characters"));
682 }
683
684 let mut arr = [0u8; 64];
685 arr.copy_from_slice(&bytes);
686 Ok(Self::from_bytes(arr))
687 }
688
689 pub fn from_bytes(bytes: [u8; 64]) -> Self {
690 Self { bytes }
691 }
692
693 pub fn to_hex(&self) -> String {
694 hex_encode(&self.bytes)
695 }
696
697 pub fn to_bytes(&self) -> [u8; 64] {
698 self.bytes
699 }
700}
701
702#[cfg(test)]
707mod tests {
708 use super::*;
709
710 fn hex_to_bytes32(s: &str) -> [u8; 32] {
711 let mut out = [0u8; 32];
712 for i in 0..32 {
713 out[i] = u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).unwrap();
714 }
715 out
716 }
717
718 #[test]
719 fn generator_on_curve() {
720 let g = AffinePoint {
721 x: generator_x(),
722 y: generator_y(),
723 };
724 assert!(is_on_curve(g), "generator G must be on P-256 curve");
725 }
726
727 #[test]
728 fn secret_key_validation() {
729 assert!(SecretKey::from_bytes([0u8; 32]).is_err());
730 let n_bytes = order_u256().to_be_bytes();
731 assert!(SecretKey::from_bytes(n_bytes).is_err());
732 let (n_minus_1, _) = U256::sub(order_u256(), U256::ONE);
733 assert!(SecretKey::from_bytes(n_minus_1.to_be_bytes()).is_ok());
734 }
735
736 #[test]
737 fn public_key_derivation_k1() {
738 let mut sk_bytes = [0u8; 32];
740 sk_bytes[31] = 1;
741 let sk = SecretKey::from_bytes(sk_bytes).unwrap();
742 let pk = sk.public_key().unwrap();
743 let sec1 = pk.to_sec1_bytes();
744 let gx = generator_x().to_u256().to_be_bytes();
745 assert_eq!(&sec1[1..], &gx, "1*G should have generator x");
746 }
747
748 #[test]
749 fn sign_verify_roundtrip() {
750 let sk = SecretKey::generate().unwrap();
751 let pk = sk.public_key().unwrap();
752 let digest = [0x42u8; 32];
753 let sig = sk.sign_ecdsa_prehash(digest).unwrap();
754 pk.verify_ecdsa_prehash(digest, &sig).unwrap();
755 }
756
757 #[test]
758 fn verify_wrong_message_fails() {
759 let sk = SecretKey::generate().unwrap();
760 let pk = sk.public_key().unwrap();
761 let sig = sk.sign_ecdsa_prehash([0x11; 32]).unwrap();
762 assert!(pk.verify_ecdsa_prehash([0x22; 32], &sig).is_err());
763 }
764
765 #[test]
766 fn low_s_normalization() {
767 let sk = SecretKey::generate().unwrap();
768 let digest = [0x77u8; 32];
769 let sig = sk.sign_ecdsa_prehash(digest).unwrap();
770 let s = U256::from_be_bytes(sig.to_bytes()[32..].try_into().unwrap());
771 let n = order_u256();
772 let half_n = U256::shr1(n);
773 assert!(
774 matches!(
775 U256::cmp(s, half_n),
776 core::cmp::Ordering::Less | core::cmp::Ordering::Equal
777 ),
778 "s must be <= n/2"
779 );
780 }
781
782 #[test]
783 fn high_s_rejected_in_verify() {
784 let sk = SecretKey::generate().unwrap();
785 let pk = sk.public_key().unwrap();
786 let digest = [0x77u8; 32];
787 let sig = sk.sign_ecdsa_prehash(digest).unwrap();
788
789 let mut bytes = sig.to_bytes();
791 let s = U256::from_be_bytes(bytes[32..].try_into().unwrap());
792 let n = order_u256();
793 let (high_s, _) = U256::sub(n, s);
794 bytes[32..].copy_from_slice(&high_s.to_be_bytes());
795
796 let high_s_sig = EcdsaSignature::from_bytes(bytes);
797 let half_n = U256::shr1(n);
798 if let core::cmp::Ordering::Greater = U256::cmp(high_s, half_n) {
800 assert!(
801 pk.verify_ecdsa_prehash(digest, &high_s_sig).is_err(),
802 "high-S should be rejected"
803 );
804 }
805 }
806
807 #[test]
808 fn hex_roundtrip() {
809 let sk = SecretKey::generate().unwrap();
810 let pk = sk.public_key().unwrap();
811 let sig = sk.sign_ecdsa_prehash([0x55; 32]).unwrap();
812
813 assert_eq!(SecretKey::from_hex(&sk.to_hex()).unwrap(), sk);
814 assert_eq!(PublicKey::from_hex(&pk.to_hex()).unwrap(), pk);
815 assert_eq!(EcdsaSignature::from_hex(&sig.to_hex()).unwrap(), sig);
816 }
817
818 #[test]
819 fn deterministic_signatures() {
820 let sk_bytes =
822 hex_to_bytes32("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
823 let sk = SecretKey::from_bytes(sk_bytes).unwrap();
824 let digest = [0x42u8; 32];
825 let sig1 = sk.sign_ecdsa_prehash(digest).unwrap();
826 let sig2 = sk.sign_ecdsa_prehash(digest).unwrap();
827 assert_eq!(sig1.to_bytes(), sig2.to_bytes());
828 }
829
830 #[test]
831 fn point_double_equals_point_add_self() {
832 let g = AffinePoint {
834 x: generator_x(),
835 y: generator_y(),
836 };
837 let g_proj = ProjectivePoint::from_affine(g);
838 let two_g_double = to_affine(point_double(g_proj)).unwrap();
839 let two_g_add = to_affine(point_add(g_proj, g_proj)).unwrap();
840 assert_eq!(two_g_double.x.to_u256(), two_g_add.x.to_u256());
841 assert_eq!(two_g_double.y.to_u256(), two_g_add.y.to_u256());
842 }
843
844 #[test]
845 fn sec1_roundtrip() {
846 let sk = SecretKey::generate().unwrap();
847 let pk = sk.public_key().unwrap();
848 let sec1 = pk.to_sec1_bytes();
849 let pk2 = PublicKey::from_sec1_bytes(&sec1).unwrap();
850 assert_eq!(pk, pk2);
851 }
852}