1use core::fmt;
36
37use crate::hash::Digest;
38use crate::public_key::bigint::BigUint;
39use crate::public_key::ec::{AffinePoint, CurveParams};
40use crate::public_key::io::{
41 decode_biguints, encode_biguints, pem_unwrap, pem_wrap, xml_unwrap, xml_wrap,
42};
43use crate::public_key::primes::{mod_inverse, random_nonzero_below};
44use crate::Csprng;
45use crate::Hmac;
46
47const ECDSA_PUBLIC_LABEL: &str = "CRYPTOGRAPHY ECDSA PUBLIC KEY";
48const ECDSA_PRIVATE_LABEL: &str = "CRYPTOGRAPHY ECDSA PRIVATE KEY";
49
50#[derive(Clone, Debug)]
56pub struct EcdsaPublicKey {
57 curve: CurveParams,
59 q: AffinePoint,
61}
62
63#[derive(Clone)]
70pub struct EcdsaPrivateKey {
71 curve: CurveParams,
73 d: BigUint,
75 q: AffinePoint,
77}
78
79#[derive(Clone, Debug, Eq, PartialEq)]
87pub struct EcdsaSignature {
88 r: BigUint,
89 s: BigUint,
90}
91
92pub struct Ecdsa;
93
94impl EcdsaPublicKey {
97 #[must_use]
99 pub fn curve(&self) -> &CurveParams {
100 &self.curve
101 }
102
103 #[must_use]
105 pub fn public_point(&self) -> &AffinePoint {
106 &self.q
107 }
108
109 #[must_use]
111 pub fn to_wire_bytes(&self) -> Vec<u8> {
112 self.curve.encode_point(&self.q)
113 }
114
115 #[must_use]
117 pub fn from_wire_bytes(curve: CurveParams, bytes: &[u8]) -> Option<Self> {
118 let q = curve.decode_point(bytes)?;
119 if !curve.scalar_mul(&q, &curve.n).is_infinity() {
122 return None;
123 }
124 Some(Self { curve, q })
125 }
126
127 #[must_use]
129 pub fn verify_message<H: Digest>(&self, message: &[u8], signature: &EcdsaSignature) -> bool {
130 let digest = H::digest(message);
131 self.verify(&digest, signature)
132 }
133
134 #[must_use]
136 pub fn verify_message_bytes<H: Digest>(&self, message: &[u8], signature: &[u8]) -> bool {
137 let digest = H::digest(message);
138 self.verify_bytes(&digest, signature)
139 }
140
141 #[must_use]
146 pub fn verify(&self, digest: &[u8], signature: &EcdsaSignature) -> bool {
147 let z = digest_to_scalar(digest, &self.curve.n);
148 self.verify_digest_scalar(&z, signature)
149 }
150
151 #[must_use]
153 pub fn verify_digest_scalar(&self, hash: &BigUint, signature: &EcdsaSignature) -> bool {
154 let n = &self.curve.n;
155
156 if signature.r.is_zero() || signature.s.is_zero() || &signature.r >= n || &signature.s >= n
158 {
159 return false;
160 }
161
162 let mut half_n = n.clone();
167 half_n.shr1();
168 if signature.s.cmp(&half_n).is_gt() {
169 return false;
170 }
171
172 let Some(w) = mod_inverse(&signature.s, n) else {
173 return false;
174 };
175
176 let u1 = BigUint::mod_mul(hash, &w, n);
178 let u2 = BigUint::mod_mul(&signature.r, &w, n);
179
180 let g = self.curve.base_point();
182 let term1 = self.curve.scalar_mul(&g, &u1);
183 let term2 = self.curve.scalar_mul(&self.q, &u2);
184 let sum = self.curve.add(&term1, &term2);
185
186 if sum.is_infinity() {
187 return false;
188 }
189
190 sum.x.modulo(n) == signature.r
192 }
193
194 #[must_use]
196 pub fn verify_bytes(&self, digest: &[u8], signature: &[u8]) -> bool {
197 let Some(sig) = EcdsaSignature::from_key_blob(signature) else {
198 return false;
199 };
200 self.verify(digest, &sig)
201 }
202
203 #[must_use]
209 pub fn to_key_blob(&self) -> Vec<u8> {
210 let h = BigUint::from_u64(self.curve.h);
211 let field_byte = u8::from(self.curve.gf2m_degree().is_some());
212 let mut out = vec![field_byte];
213 out.extend_from_slice(&encode_biguints(&[
214 &self.curve.p,
215 &self.curve.a,
216 &self.curve.b,
217 &self.curve.n,
218 &h,
219 &self.curve.gx,
220 &self.curve.gy,
221 &self.q.x,
222 &self.q.y,
223 ]));
224 out
225 }
226
227 #[must_use]
229 pub fn from_key_blob(blob: &[u8]) -> Option<Self> {
230 let (&field_type, rest) = blob.split_first()?;
231 let mut fields = decode_biguints(rest)?.into_iter();
232 let field_prime = fields.next()?;
233 let curve_a = fields.next()?;
234 let curve_b = fields.next()?;
235 let subgroup_order = fields.next()?;
236 let cofactor_big = fields.next()?;
237 let base_x = fields.next()?;
238 let base_y = fields.next()?;
239 let public_x = fields.next()?;
240 let public_y = fields.next()?;
241 if fields.next().is_some() {
242 return None;
243 }
244 let cofactor = biguint_to_u64(&cofactor_big)?;
245 let curve = if field_type == 0x01 {
246 let field_degree = field_prime.bits().checked_sub(1)?;
247 CurveParams::new_binary(
248 field_prime,
249 field_degree,
250 curve_a,
251 curve_b,
252 subgroup_order,
253 cofactor,
254 (base_x, base_y),
255 )?
256 } else {
257 CurveParams::new(
258 field_prime,
259 curve_a,
260 curve_b,
261 subgroup_order,
262 cofactor,
263 base_x,
264 base_y,
265 )?
266 };
267 let public_point = AffinePoint::new(public_x, public_y);
268 if !curve.is_on_curve(&public_point) {
269 return None;
270 }
271 if !curve.scalar_mul(&public_point, &curve.n).is_infinity() {
276 return None;
277 }
278 Some(Self {
279 curve,
280 q: public_point,
281 })
282 }
283
284 #[must_use]
285 pub fn to_pem(&self) -> String {
286 pem_wrap(ECDSA_PUBLIC_LABEL, &self.to_key_blob())
287 }
288
289 #[must_use]
291 pub fn from_pem(pem: &str) -> Option<Self> {
292 let blob = pem_unwrap(ECDSA_PUBLIC_LABEL, pem)?;
293 Self::from_key_blob(&blob)
294 }
295
296 #[must_use]
301 pub fn to_xml(&self) -> String {
302 let h = BigUint::from_u64(self.curve.h);
303 let degree = BigUint::from_u64(
304 u64::try_from(self.curve.gf2m_degree().unwrap_or(0)).expect("degree fits in u64"),
305 );
306 xml_wrap(
307 "EcdsaPublicKey",
308 &[
309 ("p", &self.curve.p),
310 ("a", &self.curve.a),
311 ("b", &self.curve.b),
312 ("n", &self.curve.n),
313 ("h", &h),
314 ("degree", °ree),
315 ("gx", &self.curve.gx),
316 ("gy", &self.curve.gy),
317 ("qx", &self.q.x),
318 ("qy", &self.q.y),
319 ],
320 )
321 }
322
323 #[must_use]
325 pub fn from_xml(xml: &str) -> Option<Self> {
326 let mut fields = xml_unwrap(
327 "EcdsaPublicKey",
328 &["p", "a", "b", "n", "h", "degree", "gx", "gy", "qx", "qy"],
329 xml,
330 )?
331 .into_iter();
332 let field_prime = fields.next()?;
333 let curve_a = fields.next()?;
334 let curve_b = fields.next()?;
335 let subgroup_order = fields.next()?;
336 let cofactor_big = fields.next()?;
337 let degree_big = fields.next()?;
338 let base_x = fields.next()?;
339 let base_y = fields.next()?;
340 let public_x = fields.next()?;
341 let public_y = fields.next()?;
342 if fields.next().is_some() {
343 return None;
344 }
345 let cofactor = biguint_to_u64(&cofactor_big)?;
346 let field_degree = usize::try_from(biguint_to_u64(°ree_big)?).ok()?;
347 let curve = if field_degree > 0 {
348 CurveParams::new_binary(
349 field_prime,
350 field_degree,
351 curve_a,
352 curve_b,
353 subgroup_order,
354 cofactor,
355 (base_x, base_y),
356 )?
357 } else {
358 CurveParams::new(
359 field_prime,
360 curve_a,
361 curve_b,
362 subgroup_order,
363 cofactor,
364 base_x,
365 base_y,
366 )?
367 };
368 let public_point = AffinePoint::new(public_x, public_y);
369 if !curve.is_on_curve(&public_point) {
370 return None;
371 }
372 if !curve.scalar_mul(&public_point, &curve.n).is_infinity() {
373 return None;
374 }
375 Some(Self {
376 curve,
377 q: public_point,
378 })
379 }
380}
381
382impl EcdsaPrivateKey {
385 #[must_use]
387 pub fn curve(&self) -> &CurveParams {
388 &self.curve
389 }
390
391 #[must_use]
393 pub fn private_scalar(&self) -> &BigUint {
394 &self.d
395 }
396
397 #[must_use]
399 pub fn to_public_key(&self) -> EcdsaPublicKey {
400 EcdsaPublicKey {
401 curve: self.curve.clone(),
402 q: self.q.clone(),
403 }
404 }
405
406 #[must_use]
419 pub fn sign_digest_with_nonce(&self, digest: &[u8], nonce: &BigUint) -> Option<EcdsaSignature> {
420 let n = &self.curve.n;
421 if nonce.is_zero() || nonce >= n {
422 return None;
423 }
424
425 let z = digest_to_scalar(digest, n);
426
427 let r_point = self.curve.scalar_mul(&self.curve.base_point(), nonce);
429 if r_point.is_infinity() {
430 return None;
431 }
432 let r = r_point.x.modulo(n);
433 if r.is_zero() {
434 return None;
435 }
436
437 let k_inv = mod_inverse(nonce, n)?;
439 let rd = BigUint::mod_mul(&r, &self.d, n);
440 let z_plus_rd = z.add_ref(&rd).modulo(n);
441 let mut s = BigUint::mod_mul(&k_inv, &z_plus_rd, n);
442 if s.is_zero() {
443 return None;
444 }
445 canonicalize_low_s(n, &mut s);
446
447 Some(EcdsaSignature { r, s })
448 }
449
450 #[must_use]
452 pub fn sign_digest<H: Digest>(&self, digest: &[u8]) -> Option<EcdsaSignature> {
453 let nonce = rfc6979_nonce::<H>(&self.curve.n, &self.d, digest)?;
454 self.sign_digest_with_nonce(digest, &nonce)
455 }
456
457 #[must_use]
461 pub fn sign_digest_with_rng<R: Csprng>(
462 &self,
463 digest: &[u8],
464 rng: &mut R,
465 ) -> Option<EcdsaSignature> {
466 loop {
467 let nonce = random_nonzero_below(rng, &self.curve.n)?;
468 if let Some(sig) = self.sign_digest_with_nonce(digest, &nonce) {
469 return Some(sig);
470 }
471 }
472 }
473
474 #[must_use]
476 pub fn sign_message<H: Digest>(&self, message: &[u8]) -> Option<EcdsaSignature> {
477 let digest = H::digest(message);
478 self.sign_digest::<H>(&digest)
479 }
480
481 #[must_use]
483 pub fn sign_message_with_rng<H: Digest, R: Csprng>(
484 &self,
485 message: &[u8],
486 rng: &mut R,
487 ) -> Option<EcdsaSignature> {
488 let digest = H::digest(message);
489 self.sign_digest_with_rng(&digest, rng)
490 }
491
492 #[must_use]
494 pub fn sign_digest_bytes<H: Digest>(&self, digest: &[u8]) -> Option<Vec<u8>> {
495 let sig = self.sign_digest::<H>(digest)?;
496 Some(sig.to_key_blob())
497 }
498
499 #[must_use]
501 pub fn sign_digest_bytes_with_rng<R: Csprng>(
502 &self,
503 digest: &[u8],
504 rng: &mut R,
505 ) -> Option<Vec<u8>> {
506 let sig = self.sign_digest_with_rng(digest, rng)?;
507 Some(sig.to_key_blob())
508 }
509
510 #[must_use]
512 pub fn sign_message_bytes<H: Digest>(&self, message: &[u8]) -> Option<Vec<u8>> {
513 let sig = self.sign_message::<H>(message)?;
514 Some(sig.to_key_blob())
515 }
516
517 #[must_use]
519 pub fn sign_message_bytes_with_rng<H: Digest, R: Csprng>(
520 &self,
521 message: &[u8],
522 rng: &mut R,
523 ) -> Option<Vec<u8>> {
524 let sig = self.sign_message_with_rng::<H, R>(message, rng)?;
525 Some(sig.to_key_blob())
526 }
527
528 #[must_use]
533 pub fn to_key_blob(&self) -> Vec<u8> {
534 let h = BigUint::from_u64(self.curve.h);
535 let field_byte = u8::from(self.curve.gf2m_degree().is_some());
536 let mut out = vec![field_byte];
537 out.extend_from_slice(&encode_biguints(&[
538 &self.curve.p,
539 &self.curve.a,
540 &self.curve.b,
541 &self.curve.n,
542 &h,
543 &self.curve.gx,
544 &self.curve.gy,
545 &self.d,
546 ]));
547 out
548 }
549
550 #[must_use]
552 pub fn from_key_blob(blob: &[u8]) -> Option<Self> {
553 let (&field_type, rest) = blob.split_first()?;
554 let mut fields = decode_biguints(rest)?.into_iter();
555 let field_prime = fields.next()?;
556 let curve_a = fields.next()?;
557 let curve_b = fields.next()?;
558 let subgroup_order = fields.next()?;
559 let cofactor_big = fields.next()?;
560 let base_x = fields.next()?;
561 let base_y = fields.next()?;
562 let private_scalar = fields.next()?;
563 if fields.next().is_some() {
564 return None;
565 }
566 let cofactor = biguint_to_u64(&cofactor_big)?;
567 let curve = if field_type == 0x01 {
568 let field_degree = field_prime.bits().checked_sub(1)?;
569 CurveParams::new_binary(
570 field_prime,
571 field_degree,
572 curve_a,
573 curve_b,
574 subgroup_order,
575 cofactor,
576 (base_x, base_y),
577 )?
578 } else {
579 CurveParams::new(
580 field_prime,
581 curve_a,
582 curve_b,
583 subgroup_order,
584 cofactor,
585 base_x,
586 base_y,
587 )?
588 };
589 if private_scalar.is_zero() || private_scalar.cmp(&curve.n).is_ge() {
590 return None;
591 }
592 let q = curve.scalar_mul(&curve.base_point(), &private_scalar);
593 Some(Self {
594 curve,
595 d: private_scalar,
596 q,
597 })
598 }
599
600 #[must_use]
601 pub fn to_pem(&self) -> String {
602 pem_wrap(ECDSA_PRIVATE_LABEL, &self.to_key_blob())
603 }
604
605 #[must_use]
607 pub fn from_pem(pem: &str) -> Option<Self> {
608 let blob = pem_unwrap(ECDSA_PRIVATE_LABEL, pem)?;
609 Self::from_key_blob(&blob)
610 }
611
612 #[must_use]
617 pub fn to_xml(&self) -> String {
618 let h = BigUint::from_u64(self.curve.h);
619 let degree = BigUint::from_u64(
620 u64::try_from(self.curve.gf2m_degree().unwrap_or(0)).expect("degree fits in u64"),
621 );
622 xml_wrap(
623 "EcdsaPrivateKey",
624 &[
625 ("p", &self.curve.p),
626 ("a", &self.curve.a),
627 ("b", &self.curve.b),
628 ("n", &self.curve.n),
629 ("h", &h),
630 ("degree", °ree),
631 ("gx", &self.curve.gx),
632 ("gy", &self.curve.gy),
633 ("d", &self.d),
634 ],
635 )
636 }
637
638 #[must_use]
640 pub fn from_xml(xml: &str) -> Option<Self> {
641 let mut fields = xml_unwrap(
642 "EcdsaPrivateKey",
643 &["p", "a", "b", "n", "h", "degree", "gx", "gy", "d"],
644 xml,
645 )?
646 .into_iter();
647 let field_prime = fields.next()?;
648 let curve_a = fields.next()?;
649 let curve_b = fields.next()?;
650 let subgroup_order = fields.next()?;
651 let cofactor_big = fields.next()?;
652 let degree_big = fields.next()?;
653 let base_x = fields.next()?;
654 let base_y = fields.next()?;
655 let private_scalar = fields.next()?;
656 if fields.next().is_some() {
657 return None;
658 }
659 let cofactor = biguint_to_u64(&cofactor_big)?;
660 let field_degree = usize::try_from(biguint_to_u64(°ree_big)?).ok()?;
661 let curve = if field_degree > 0 {
662 CurveParams::new_binary(
663 field_prime,
664 field_degree,
665 curve_a,
666 curve_b,
667 subgroup_order,
668 cofactor,
669 (base_x, base_y),
670 )?
671 } else {
672 CurveParams::new(
673 field_prime,
674 curve_a,
675 curve_b,
676 subgroup_order,
677 cofactor,
678 base_x,
679 base_y,
680 )?
681 };
682 if private_scalar.is_zero() || private_scalar.cmp(&curve.n).is_ge() {
683 return None;
684 }
685 let q = curve.scalar_mul(&curve.base_point(), &private_scalar);
686 Some(Self {
687 curve,
688 d: private_scalar,
689 q,
690 })
691 }
692}
693
694impl fmt::Debug for EcdsaPrivateKey {
695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696 f.write_str("EcdsaPrivateKey(<redacted>)")
697 }
698}
699
700impl EcdsaSignature {
703 #[must_use]
704 pub fn r(&self) -> &BigUint {
705 &self.r
706 }
707
708 #[must_use]
709 pub fn s(&self) -> &BigUint {
710 &self.s
711 }
712
713 #[must_use]
715 pub fn to_key_blob(&self) -> Vec<u8> {
716 encode_biguints(&[&self.r, &self.s])
717 }
718
719 #[must_use]
725 pub fn from_key_blob(blob: &[u8]) -> Option<Self> {
726 let mut fields = decode_biguints(blob)?.into_iter();
727 let r = fields.next()?;
728 let s = fields.next()?;
729 if fields.next().is_some() || r.is_zero() || s.is_zero() {
730 return None;
731 }
732 Some(Self { r, s })
733 }
734}
735
736impl Ecdsa {
739 #[must_use]
741 pub fn generate<R: Csprng>(
742 curve: CurveParams,
743 rng: &mut R,
744 ) -> (EcdsaPublicKey, EcdsaPrivateKey) {
745 let (d, q) = curve.generate_keypair(rng);
746 let public = EcdsaPublicKey {
747 curve: curve.clone(),
748 q: q.clone(),
749 };
750 let private = EcdsaPrivateKey { curve, d, q };
751 (public, private)
752 }
753
754 #[must_use]
758 pub fn from_secret_scalar(
759 curve: CurveParams,
760 secret: &BigUint,
761 ) -> Option<(EcdsaPublicKey, EcdsaPrivateKey)> {
762 if secret.is_zero() || secret >= &curve.n {
763 return None;
764 }
765 let q = curve.scalar_mul(&curve.base_point(), secret);
766 Some((
767 EcdsaPublicKey {
768 curve: curve.clone(),
769 q: q.clone(),
770 },
771 EcdsaPrivateKey {
772 curve,
773 d: secret.clone(),
774 q,
775 },
776 ))
777 }
778}
779
780fn biguint_to_u64(value: &BigUint) -> Option<u64> {
787 let bytes = value.to_be_bytes();
788 if bytes.len() > 8 {
789 return None;
790 }
791 let mut arr = [0u8; 8];
792 arr[8 - bytes.len()..].copy_from_slice(&bytes);
793 Some(u64::from_be_bytes(arr))
794}
795
796fn digest_to_scalar(digest: &[u8], modulus: &BigUint) -> BigUint {
802 let mut value = BigUint::from_be_bytes(digest);
803 let hash_bits = digest.len() * 8;
804 let target_bits = modulus.bits();
805 if hash_bits > target_bits {
806 for _ in 0..(hash_bits - target_bits) {
807 value.shr1();
808 }
809 }
810 value
811}
812
813fn canonicalize_low_s(order: &BigUint, s: &mut BigUint) {
814 let mut half = order.clone();
815 half.shr1();
816 if (*s).cmp(&half).is_gt() {
817 *s = order.sub_ref(s);
818 }
819}
820
821fn int_to_octets(value: &BigUint, len: usize) -> Vec<u8> {
822 let bytes = value.to_be_bytes();
823 if bytes.len() >= len {
824 return bytes[bytes.len() - len..].to_vec();
825 }
826 let mut out = vec![0u8; len];
827 out[len - bytes.len()..].copy_from_slice(&bytes);
828 out
829}
830
831fn bits_to_int(input: &[u8], target_bits: usize) -> BigUint {
832 let mut value = BigUint::from_be_bytes(input);
833 let input_bits = input.len() * 8;
834 if input_bits > target_bits {
835 for _ in 0..(input_bits - target_bits) {
836 value.shr1();
837 }
838 }
839 value
840}
841
842fn bits_to_octets(input: &[u8], q: &BigUint, q_bits: usize, ro_len: usize) -> Vec<u8> {
843 let z1 = bits_to_int(input, q_bits);
844 let z2 = z1.modulo(q);
845 int_to_octets(&z2, ro_len)
846}
847
848fn rfc6979_nonce<H: Digest>(q: &BigUint, x: &BigUint, digest: &[u8]) -> Option<BigUint> {
849 if q <= &BigUint::one() {
850 return None;
851 }
852
853 let q_bits = q.bits();
854 let ro_len = q_bits.div_ceil(8);
855 let bx = int_to_octets(x, ro_len);
856 let bh = bits_to_octets(digest, q, q_bits, ro_len);
857
858 let mut v = vec![0x01; H::OUTPUT_LEN];
859 let mut k = vec![0x00; H::OUTPUT_LEN];
860
861 let mut data = Vec::with_capacity(v.len() + 1 + bx.len() + bh.len());
862 data.extend_from_slice(&v);
863 data.push(0x00);
864 data.extend_from_slice(&bx);
865 data.extend_from_slice(&bh);
866 k = Hmac::<H>::compute(&k, &data);
867 v = Hmac::<H>::compute(&k, &v);
868
869 data.clear();
870 data.extend_from_slice(&v);
871 data.push(0x01);
872 data.extend_from_slice(&bx);
873 data.extend_from_slice(&bh);
874 k = Hmac::<H>::compute(&k, &data);
875 v = Hmac::<H>::compute(&k, &v);
876
877 loop {
878 let mut t = Vec::with_capacity(ro_len);
879 while t.len() < ro_len {
880 v = Hmac::<H>::compute(&k, &v);
881 let take = (ro_len - t.len()).min(v.len());
882 t.extend_from_slice(&v[..take]);
883 }
884
885 let candidate = bits_to_int(&t, q_bits);
886 if !candidate.is_zero() && &candidate < q {
887 return Some(candidate);
888 }
889
890 data.clear();
891 data.extend_from_slice(&v);
892 data.push(0x00);
893 k = Hmac::<H>::compute(&k, &data);
894 v = Hmac::<H>::compute(&k, &v);
895 }
896}
897
898#[cfg(test)]
901mod tests {
902 use super::{Ecdsa, EcdsaPrivateKey, EcdsaPublicKey, EcdsaSignature};
903 use crate::public_key::bigint::BigUint;
904 use crate::public_key::ec::{b163, p256, p384, p521, secp256k1};
905 use crate::{CtrDrbgAes256, Sha256, Sha384, Sha512};
906
907 fn rng() -> CtrDrbgAes256 {
908 CtrDrbgAes256::new(&[0xab; 48])
909 }
910
911 fn decode_hex(hex: &str) -> Vec<u8> {
912 let cleaned: String = hex.chars().filter(|c| !c.is_whitespace()).collect();
913 assert_eq!(
914 cleaned.len() % 2,
915 0,
916 "hex input must have an even number of nybbles"
917 );
918 (0..cleaned.len())
919 .step_by(2)
920 .map(|i| u8::from_str_radix(&cleaned[i..i + 2], 16).expect("valid hex byte"))
921 .collect()
922 }
923
924 fn from_hex(hex: &str) -> BigUint {
925 BigUint::from_be_bytes(&decode_hex(hex))
926 }
927
928 #[test]
931 fn sign_verify_roundtrip_p256() {
932 let mut rng = rng();
933 let (public, private) = Ecdsa::generate(p256(), &mut rng);
934 let msg = b"hello world";
935 let sig = private.sign_message::<Sha256>(msg).expect("sign");
936 assert!(public.verify_message::<Sha256>(msg, &sig));
937 }
938
939 #[test]
940 fn sign_verify_roundtrip_p384() {
941 let mut rng = rng();
942 let (public, private) = Ecdsa::generate(p384(), &mut rng);
943 let msg = b"p384 test message";
944 let sig = private.sign_message::<Sha384>(msg).expect("sign");
945 assert!(public.verify_message::<Sha384>(msg, &sig));
946 }
947
948 #[test]
949 fn sign_verify_roundtrip_secp256k1() {
950 let mut rng = rng();
951 let (public, private) = Ecdsa::generate(secp256k1(), &mut rng);
952 let msg = b"secp256k1 test";
953 let sig = private.sign_message::<Sha256>(msg).expect("sign");
954 assert!(public.verify_message::<Sha256>(msg, &sig));
955 }
956
957 #[test]
958 fn sign_verify_roundtrip_p521() {
959 let mut rng = rng();
960 let (public, private) = Ecdsa::generate(p521(), &mut rng);
961 let msg = b"p521 test message";
962 let sig = private.sign_message::<Sha512>(msg).expect("sign");
963 assert!(public.verify_message::<Sha512>(msg, &sig));
964 }
965
966 #[test]
967 fn sign_verify_roundtrip_b163() {
968 let mut rng = rng();
969 let (public, private) = Ecdsa::generate(b163(), &mut rng);
970 let msg = b"binary curve ecdsa";
971 let sig = private.sign_message::<Sha256>(msg).expect("sign");
972 assert!(public.verify_message::<Sha256>(msg, &sig));
973 }
974
975 #[test]
978 fn sign_digest_with_nonce_is_deterministic() {
979 let mut rng = rng();
980 let (_, private) = Ecdsa::generate(p256(), &mut rng);
981 let digest = [0x42u8; 32];
982 let k = BigUint::from_u64(12_345_678_901_234_567_u64);
983 let sig1 = private
984 .sign_digest_with_nonce(&digest, &k)
985 .expect("first sign");
986 let sig2 = private
987 .sign_digest_with_nonce(&digest, &k)
988 .expect("second sign");
989 assert_eq!(sig1, sig2);
990 }
991
992 #[test]
993 fn sign_digest_with_nonce_repeatable_for_fixed_nonce() {
994 let mut rng = rng();
995 let (_, private) = Ecdsa::generate(p256(), &mut rng);
996 let digest = [0x42u8; 32];
997 let nonce = BigUint::from_u64(12_345_678_901_234_567_u64);
998 let lhs = private
999 .sign_digest_with_nonce(&digest, &nonce)
1000 .expect("first");
1001 let rhs = private
1002 .sign_digest_with_nonce(&digest, &nonce)
1003 .expect("second");
1004 assert_eq!(lhs, rhs);
1005 }
1006
1007 #[test]
1008 fn sign_digest_with_nonce_zero_rejected() {
1009 let mut rng = rng();
1010 let (_, private) = Ecdsa::generate(p256(), &mut rng);
1011 let digest = [0x00u8; 32];
1012 assert!(private
1013 .sign_digest_with_nonce(&digest, &BigUint::zero())
1014 .is_none());
1015 }
1016
1017 #[test]
1018 fn sign_digest_with_nonce_equal_to_n_rejected() {
1019 let curve = p256();
1020 let n = curve.n.clone();
1021 let mut rng = rng();
1022 let (_, private) = Ecdsa::generate(curve, &mut rng);
1023 let digest = [0x01u8; 32];
1024 assert!(private.sign_digest_with_nonce(&digest, &n).is_none());
1025 }
1026
1027 #[test]
1028 fn sign_digest_with_nonce_returns_low_s() {
1029 let curve = p256();
1030 let secret = BigUint::from_u64(0x1234_5678_9abc_def0);
1031 let (_, private) = Ecdsa::from_secret_scalar(curve.clone(), &secret).expect("from secret");
1032 let digest = Sha256::digest(b"low-s canonicalization");
1033 let nonce = BigUint::from_u64(0xdead_beef_cafe_babe);
1034
1035 let sig = private
1036 .sign_digest_with_nonce(&digest, &nonce)
1037 .expect("sign with nonce");
1038 let mut half = curve.n.clone();
1039 half.shr1();
1040 assert!(
1041 sig.s.cmp(&half).is_le(),
1042 "signature must be canonical low-s"
1043 );
1044 }
1045
1046 #[test]
1049 fn wrong_message_rejected() {
1050 let mut rng = rng();
1051 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1052 let msg = b"correct message";
1053 let wrong = b"wrong message";
1054 let sig = private.sign_message::<Sha256>(msg).expect("sign");
1055 assert!(!public.verify_message::<Sha256>(wrong, &sig));
1056 }
1057
1058 #[test]
1059 fn tampered_r_rejected() {
1060 let mut rng = rng();
1061 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1062 let msg = b"message";
1063 let sig = private.sign_message::<Sha256>(msg).expect("sign");
1064 let bad = EcdsaSignature {
1065 r: sig.r.add_ref(&BigUint::one()),
1066 s: sig.s.clone(),
1067 };
1068 assert!(!public.verify_message::<Sha256>(msg, &bad));
1069 }
1070
1071 #[test]
1072 fn tampered_s_rejected() {
1073 let mut rng = rng();
1074 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1075 let msg = b"message";
1076 let sig = private.sign_message::<Sha256>(msg).expect("sign");
1077 let bad = EcdsaSignature {
1078 r: sig.r.clone(),
1079 s: sig.s.add_ref(&BigUint::one()),
1080 };
1081 assert!(!public.verify_message::<Sha256>(msg, &bad));
1082 }
1083
1084 #[test]
1085 fn wrong_key_rejected() {
1086 let mut rng = rng();
1087 let (_, private1) = Ecdsa::generate(p256(), &mut rng);
1088 let (public2, _) = Ecdsa::generate(p256(), &mut rng);
1089 let msg = b"message";
1090 let sig = private1.sign_message::<Sha256>(msg).expect("sign");
1091 assert!(!public2.verify_message::<Sha256>(msg, &sig));
1092 }
1093
1094 #[test]
1097 fn to_public_key_matches_generated() {
1098 let mut rng = rng();
1099 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1100 let derived = private.to_public_key();
1101 let msg = b"derived key test";
1103 let sig = private.sign_message::<Sha256>(msg).expect("sign");
1104 assert!(derived.verify_message::<Sha256>(msg, &sig));
1105 assert_eq!(derived.q, public.q);
1107 }
1108
1109 #[test]
1112 fn from_secret_scalar_rejects_zero() {
1113 assert!(Ecdsa::from_secret_scalar(p256(), &BigUint::zero()).is_none());
1114 }
1115
1116 #[test]
1117 fn from_secret_scalar_rejects_out_of_range() {
1118 let curve = p256();
1119 let too_large = curve.n.clone();
1120 assert!(Ecdsa::from_secret_scalar(curve, &too_large).is_none());
1121 }
1122
1123 #[test]
1126 fn public_key_binary_roundtrip() {
1127 let mut rng = rng();
1128 let (public, _) = Ecdsa::generate(p256(), &mut rng);
1129 let blob = public.to_key_blob();
1130 let recovered = EcdsaPublicKey::from_key_blob(&blob).expect("from_binary");
1131 assert_eq!(recovered.q, public.q);
1132 assert_eq!(recovered.curve.n, public.curve.n);
1133 }
1134
1135 #[test]
1136 fn public_key_bytes_roundtrip() {
1137 let mut rng = rng();
1138 let (public, _) = Ecdsa::generate(p256(), &mut rng);
1139 let bytes = public.to_wire_bytes();
1140 let recovered = EcdsaPublicKey::from_wire_bytes(p256(), &bytes).expect("from_bytes");
1141 assert_eq!(recovered.q, public.q);
1142 assert_eq!(recovered.curve.n, public.curve.n);
1143 }
1144
1145 #[test]
1146 fn private_key_binary_roundtrip() {
1147 let mut rng = rng();
1148 let (_, private) = Ecdsa::generate(p256(), &mut rng);
1149 let blob = private.to_key_blob();
1150 let recovered = EcdsaPrivateKey::from_key_blob(&blob).expect("from_binary");
1151 assert_eq!(recovered.d, private.d);
1152 assert_eq!(recovered.curve.n, private.curve.n);
1153 }
1154
1155 #[test]
1156 fn signature_binary_roundtrip() {
1157 let mut rng = rng();
1158 let (_, private) = Ecdsa::generate(p256(), &mut rng);
1159 let msg = b"roundtrip test";
1160 let sig = private.sign_message::<Sha256>(msg).expect("sign");
1161 let blob = sig.to_key_blob();
1162 let recovered = EcdsaSignature::from_key_blob(&blob).expect("from_binary");
1163 assert_eq!(recovered, sig);
1164 }
1165
1166 #[test]
1169 fn public_key_pem_roundtrip() {
1170 let mut rng = rng();
1171 let (public, _) = Ecdsa::generate(p384(), &mut rng);
1172 let pem = public.to_pem();
1173 assert!(pem.contains("CRYPTOGRAPHY ECDSA PUBLIC KEY"));
1174 let recovered = EcdsaPublicKey::from_pem(&pem).expect("from_pem");
1175 assert_eq!(recovered.q, public.q);
1176 }
1177
1178 #[test]
1179 fn private_key_pem_roundtrip() {
1180 let mut rng = rng();
1181 let (_, private) = Ecdsa::generate(p384(), &mut rng);
1182 let pem = private.to_pem();
1183 assert!(pem.contains("CRYPTOGRAPHY ECDSA PRIVATE KEY"));
1184 let recovered = EcdsaPrivateKey::from_pem(&pem).expect("from_pem");
1185 assert_eq!(recovered.d, private.d);
1186 }
1187
1188 #[test]
1191 fn public_key_xml_roundtrip() {
1192 let mut rng = rng();
1193 let (public, _) = Ecdsa::generate(secp256k1(), &mut rng);
1194 let xml = public.to_xml();
1195 assert!(xml.contains("EcdsaPublicKey"));
1196 let recovered = EcdsaPublicKey::from_xml(&xml).expect("from_xml");
1197 assert_eq!(recovered.q, public.q);
1198 }
1199
1200 #[test]
1201 fn private_key_xml_roundtrip() {
1202 let mut rng = rng();
1203 let (_, private) = Ecdsa::generate(secp256k1(), &mut rng);
1204 let xml = private.to_xml();
1205 assert!(xml.contains("EcdsaPrivateKey"));
1206 let recovered = EcdsaPrivateKey::from_xml(&xml).expect("from_xml");
1207 assert_eq!(recovered.d, private.d);
1208 }
1209
1210 #[test]
1213 fn sign_bytes_verify_bytes_roundtrip() {
1214 let mut rng = rng();
1215 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1216 let digest = Sha256::digest(b"test message bytes");
1217 let sig_bytes = private
1218 .sign_digest_bytes::<Sha256>(&digest)
1219 .expect("sign_digest_bytes");
1220 assert!(public.verify_bytes(&digest, &sig_bytes));
1221 }
1222
1223 #[test]
1224 fn sign_message_bytes_verify_message_bytes_roundtrip() {
1225 let mut rng = rng();
1226 let (public, private) = Ecdsa::generate(p256(), &mut rng);
1227 let msg = b"end-to-end bytes test";
1228 let sig_bytes = private
1229 .sign_message_bytes::<Sha256>(msg)
1230 .expect("sign_message_bytes");
1231 assert!(public.verify_message_bytes::<Sha256>(msg, &sig_bytes));
1232 }
1233
1234 #[test]
1237 fn private_key_debug_redacted() {
1238 let mut rng = rng();
1239 let (_, private) = Ecdsa::generate(p256(), &mut rng);
1240 let s = format!("{private:?}");
1241 assert_eq!(s, "EcdsaPrivateKey(<redacted>)");
1242 assert!(!s.contains(&format!("{:?}", private.d)));
1244 }
1245
1246 #[test]
1247 fn rfc6979_ecdsa_p256_sha256_sample_vector_with_low_s_canonicalization() {
1248 let x = from_hex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
1250 let expected_ux =
1251 from_hex("60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6");
1252 let expected_uy =
1253 from_hex("7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299");
1254 let expected_k =
1255 from_hex("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
1256 let expected_r =
1257 from_hex("EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716");
1258 let expected_s_rfc =
1259 from_hex("F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8");
1260
1261 let (public, private) =
1262 Ecdsa::from_secret_scalar(p256(), &x).expect("RFC secret scalar must be valid");
1263 assert_eq!(public.q.x, expected_ux);
1264 assert_eq!(public.q.y, expected_uy);
1265
1266 let message = b"sample";
1267 let digest = Sha256::digest(message);
1268 let derived_k = super::rfc6979_nonce::<Sha256>(&private.curve.n, &private.d, &digest)
1269 .expect("RFC nonce must derive");
1270 assert_eq!(derived_k, expected_k, "RFC 6979 nonce mismatch");
1271
1272 let signature = private.sign_message::<Sha256>(message).expect("sign");
1273 assert_eq!(signature.r, expected_r);
1274
1275 let expected_s_low = private.curve.n.sub_ref(&expected_s_rfc);
1277 assert_eq!(signature.s, expected_s_low);
1278 assert!(public.verify_message::<Sha256>(message, &signature));
1279 }
1280}