1use core::cmp::Ordering;
19
20use crate::drbg::HmacDrbgSha256;
21use crate::hash::noxtls_sha384;
22use crate::internal_alloc::Vec;
23use noxtls_core::{Error, Result};
24
25use super::bignum::BigUint;
26
27#[derive(Debug, Clone, Eq, PartialEq)]
29pub struct P384PrivateKey {
30 scalar: BigUint,
31}
32
33#[derive(Debug, Clone, Eq, PartialEq)]
35pub struct P384PublicKey {
36 point: CurvePoint,
37}
38
39#[derive(Debug, Clone, Eq, PartialEq)]
40struct CurvePoint {
41 x: BigUint,
42 y: BigUint,
43 infinity: bool,
44}
45
46#[derive(Debug, Clone, Eq, PartialEq)]
47struct JacobianPoint {
48 x: BigUint,
49 y: BigUint,
50 z: BigUint,
51 infinity: bool,
52}
53
54impl P384PrivateKey {
55 pub fn from_bytes(bytes: [u8; 48]) -> Result<Self> {
63 let scalar = BigUint::from_be_bytes(&bytes);
64 if scalar.is_zero() {
65 return Err(Error::CryptoFailure("p384 private scalar must be non-zero"));
66 }
67 let n = curve_order_n();
68 if scalar.cmp(&n) != Ordering::Less {
69 return Err(Error::CryptoFailure("p384 private scalar out of range"));
70 }
71 Ok(Self { scalar })
72 }
73
74 pub fn to_bytes(&self) -> Result<[u8; 48]> {
90 let bytes = self.scalar.to_be_bytes_padded(48)?;
91 let mut out = [0_u8; 48];
92 out.copy_from_slice(&bytes);
93 Ok(out)
94 }
95
96 pub fn clear(&mut self) {
108 self.scalar.clear();
109 }
110
111 pub fn public_key(&self) -> Result<P384PublicKey> {
119 let g = curve_base_point();
120 let point = scalar_mul(&self.scalar, &g)?;
121 if point.infinity {
122 return Err(Error::CryptoFailure(
123 "p384 public key derivation produced infinity",
124 ));
125 }
126 Ok(P384PublicKey { point })
127 }
128
129 pub fn diffie_hellman(&self, peer: &P384PublicKey) -> Result<[u8; 48]> {
138 peer.validate()?;
139 let shared = scalar_mul(&self.scalar, &peer.point)?;
140 if shared.infinity {
141 return Err(Error::CryptoFailure("p384 shared point is at infinity"));
142 }
143 let secret = shared.x.to_be_bytes_padded(48)?;
144 let mut out = [0_u8; 48];
145 out.copy_from_slice(&secret);
146 if is_all_zero(&out) {
147 return Err(Error::CryptoFailure("p384 shared secret is all-zero"));
148 }
149 Ok(out)
150 }
151
152 pub fn sign_sha384(&self, message: &[u8]) -> Result<([u8; 48], [u8; 48])> {
160 let digest = noxtls_sha384(message);
161 self.sign_digest(&digest)
162 }
163
164 pub fn sign_sha384_auto(
173 &self,
174 message: &[u8],
175 drbg: &mut HmacDrbgSha256,
176 ) -> Result<([u8; 48], [u8; 48])> {
177 let digest = noxtls_sha384(message);
178 self.sign_digest_auto(&digest, drbg)
179 }
180
181 pub fn sign_digest(&self, digest: &[u8; 48]) -> Result<([u8; 48], [u8; 48])> {
189 let n = curve_order_n();
190 let g = curve_base_point();
191 let e = BigUint::from_be_bytes(digest).modulo(&n);
192 let d = self.scalar.clone();
193
194 let mut counter = 0_u32;
196 loop {
197 let k = derive_signing_nonce(&d, digest, counter).modulo(&n);
198 counter = counter.wrapping_add(1);
199 if k.is_zero() {
200 if counter == 0 {
201 return Err(Error::CryptoFailure(
202 "p384 ecdsa nonce derivation exhausted",
203 ));
204 }
205 continue;
206 }
207
208 let rp = scalar_mul(&k, &g)?;
209 if rp.infinity {
210 if counter == 0 {
211 return Err(Error::CryptoFailure(
212 "p384 ecdsa nonce derivation exhausted",
213 ));
214 }
215 continue;
216 }
217 let r_bn = rp.x.modulo(&n);
218 if r_bn.is_zero() {
219 if counter == 0 {
220 return Err(Error::CryptoFailure(
221 "p384 ecdsa nonce derivation exhausted",
222 ));
223 }
224 continue;
225 }
226
227 let rd = mod_mul(&r_bn, &d, &n);
228 let e_plus_rd = e.add(&rd).modulo(&n);
229 let k_inv = mod_inv(&k, &n)?;
230 let s_bn = mod_mul(&k_inv, &e_plus_rd, &n);
231 if s_bn.is_zero() {
232 if counter == 0 {
233 return Err(Error::CryptoFailure(
234 "p384 ecdsa nonce derivation exhausted",
235 ));
236 }
237 continue;
238 }
239
240 let mut r = [0_u8; 48];
241 let mut s = [0_u8; 48];
242 r.copy_from_slice(&r_bn.to_be_bytes_padded(48)?);
243 s.copy_from_slice(&s_bn.to_be_bytes_padded(48)?);
244 return Ok((r, s));
245 }
246 }
247
248 pub fn sign_digest_auto(
257 &self,
258 digest: &[u8; 48],
259 drbg: &mut HmacDrbgSha256,
260 ) -> Result<([u8; 48], [u8; 48])> {
261 let n = curve_order_n();
262 let g = curve_base_point();
263 let e = BigUint::from_be_bytes(digest).modulo(&n);
264 let d = self.scalar.clone();
265
266 for _ in 0..64 {
267 let nonce_bytes = drbg.generate(48, b"p384_ecdsa_nonce")?;
268 let nonce_arr: [u8; 48] = nonce_bytes
269 .as_slice()
270 .try_into()
271 .map_err(|_| Error::InvalidLength("p384 ecdsa nonce length mismatch"))?;
272 let k = BigUint::from_be_bytes(&nonce_arr).modulo(&n);
273 if k.is_zero() {
274 continue;
275 }
276
277 let rp = scalar_mul(&k, &g)?;
278 if rp.infinity {
279 continue;
280 }
281 let r_bn = rp.x.modulo(&n);
282 if r_bn.is_zero() {
283 continue;
284 }
285
286 let rd = mod_mul(&r_bn, &d, &n);
287 let e_plus_rd = e.add(&rd).modulo(&n);
288 let k_inv = mod_inv(&k, &n)?;
289 let s_bn = mod_mul(&k_inv, &e_plus_rd, &n);
290 if s_bn.is_zero() {
291 continue;
292 }
293
294 let mut r = [0_u8; 48];
295 let mut s = [0_u8; 48];
296 r.copy_from_slice(&r_bn.to_be_bytes_padded(48)?);
297 s.copy_from_slice(&s_bn.to_be_bytes_padded(48)?);
298 return Ok((r, s));
299 }
300 Err(Error::CryptoFailure(
301 "p384 ecdsa nonce generation exhausted retry budget",
302 ))
303 }
304}
305
306impl Drop for P384PrivateKey {
307 fn drop(&mut self) {
308 self.clear();
309 }
310}
311
312impl P384PublicKey {
313 pub fn from_uncompressed(bytes: &[u8]) -> Result<Self> {
321 if bytes.len() != 97 {
322 return Err(Error::InvalidLength(
323 "p384 uncompressed public key must be 97 bytes",
324 ));
325 }
326 if bytes[0] != 0x04 {
327 return Err(Error::ParseFailure(
328 "p384 public key must be uncompressed SEC1 format",
329 ));
330 }
331 let x = BigUint::from_be_bytes(&bytes[1..49]);
332 let y = BigUint::from_be_bytes(&bytes[49..97]);
333 let point = CurvePoint {
334 x,
335 y,
336 infinity: false,
337 };
338 let key = Self { point };
339 key.validate()?;
340 Ok(key)
341 }
342
343 pub fn to_uncompressed(&self) -> Result<[u8; 97]> {
351 self.validate()?;
352 let mut out = [0_u8; 97];
353 out[0] = 0x04;
354 let x = self.point.x.to_be_bytes_padded(48)?;
355 let y = self.point.y.to_be_bytes_padded(48)?;
356 out[1..49].copy_from_slice(&x);
357 out[49..97].copy_from_slice(&y);
358 Ok(out)
359 }
360
361 pub fn validate(&self) -> Result<()> {
369 if self.point.infinity {
370 return Err(Error::CryptoFailure(
371 "p384 public point at infinity is invalid",
372 ));
373 }
374 let p = curve_modulus_p();
375 if self.point.x.cmp(&p) != Ordering::Less || self.point.y.cmp(&p) != Ordering::Less {
376 return Err(Error::CryptoFailure(
377 "p384 public point coordinates out of field range",
378 ));
379 }
380 if !is_point_on_curve(&self.point) {
381 return Err(Error::CryptoFailure("p384 public point is not on curve"));
382 }
383 Ok(())
384 }
385}
386
387pub fn noxtls_p384_ecdh_shared_secret(
396 private_key: &P384PrivateKey,
397 peer_public_key: &P384PublicKey,
398) -> Result<[u8; 48]> {
399 private_key.diffie_hellman(peer_public_key)
400}
401
402pub fn noxtls_p384_ecdsa_sign_sha384(
411 private_key: &P384PrivateKey,
412 message: &[u8],
413) -> Result<([u8; 48], [u8; 48])> {
414 private_key.sign_sha384(message)
415}
416
417pub fn noxtls_p384_ecdsa_sign_sha384_auto(
427 private_key: &P384PrivateKey,
428 message: &[u8],
429 drbg: &mut HmacDrbgSha256,
430) -> Result<([u8; 48], [u8; 48])> {
431 private_key.sign_sha384_auto(message, drbg)
432}
433
434pub fn noxtls_p384_ecdsa_sign_digest(
443 private_key: &P384PrivateKey,
444 digest: &[u8; 48],
445) -> Result<([u8; 48], [u8; 48])> {
446 private_key.sign_digest(digest)
447}
448
449pub fn noxtls_p384_ecdsa_sign_digest_auto(
459 private_key: &P384PrivateKey,
460 digest: &[u8; 48],
461 drbg: &mut HmacDrbgSha256,
462) -> Result<([u8; 48], [u8; 48])> {
463 private_key.sign_digest_auto(digest, drbg)
464}
465
466pub fn noxtls_p384_ecdsa_verify_sha384(
477 public_key: &P384PublicKey,
478 message: &[u8],
479 r: &[u8; 48],
480 s: &[u8; 48],
481) -> Result<()> {
482 let digest = noxtls_sha384(message);
483 noxtls_p384_ecdsa_verify_digest(public_key, &digest, r, s)
484}
485
486pub fn noxtls_p384_ecdsa_verify_digest(
497 public_key: &P384PublicKey,
498 digest: &[u8; 48],
499 r: &[u8; 48],
500 s: &[u8; 48],
501) -> Result<()> {
502 public_key.validate()?;
503
504 let n = curve_order_n();
505 if is_all_zero(r) || is_all_zero(s) {
506 return Err(Error::CryptoFailure(
507 "p384 ecdsa signature scalars must be non-zero",
508 ));
509 }
510 let r_bn = BigUint::from_be_bytes(r);
511 let s_bn = BigUint::from_be_bytes(s);
512 if r_bn.cmp(&n) != Ordering::Less || s_bn.cmp(&n) != Ordering::Less {
513 return Err(Error::CryptoFailure(
514 "p384 ecdsa signature scalars out of range",
515 ));
516 }
517
518 let e = BigUint::from_be_bytes(digest).modulo(&n);
519 let w = mod_inv(&s_bn, &n)?;
520 let u1 = mod_mul(&e, &w, &n);
521 let u2 = mod_mul(&r_bn, &w, &n);
522
523 let g = curve_base_point();
524 let p1 = scalar_mul_jacobian(&u1, &g);
525 let p2 = scalar_mul_jacobian(&u2, &public_key.point);
526 let r_point = jacobian_add(&p1, &p2).to_affine()?;
527 if r_point.infinity {
528 return Err(Error::CryptoFailure(
529 "p384 ecdsa verification produced point at infinity",
530 ));
531 }
532 let v = r_point.x.modulo(&n);
533 let v_bytes = v.to_be_bytes_padded(48)?;
534 if ct_bytes_eq(v_bytes.as_slice(), r) {
535 return Ok(());
536 }
537 Err(Error::CryptoFailure("p384 ecdsa verification failed"))
538}
539
540pub fn noxtls_p384_generate_private_key_auto(drbg: &mut HmacDrbgSha256) -> Result<P384PrivateKey> {
548 for _ in 0..64 {
549 let scalar = drbg.generate(48, b"p384_private_scalar")?;
550 let bytes: [u8; 48] = scalar
551 .as_slice()
552 .try_into()
553 .map_err(|_| Error::InvalidLength("p384 private scalar length mismatch"))?;
554 if let Ok(key) = P384PrivateKey::from_bytes(bytes) {
555 return Ok(key);
556 }
557 }
558 Err(Error::CryptoFailure(
559 "p384 private key generation exhausted retry budget",
560 ))
561}
562
563fn scalar_mul(scalar: &BigUint, point: &CurvePoint) -> Result<CurvePoint> {
582 scalar_mul_jacobian(scalar, point).to_affine()
583}
584
585fn scalar_mul_jacobian(scalar: &BigUint, point: &CurvePoint) -> JacobianPoint {
600 if point.infinity {
601 return JacobianPoint::infinity();
602 }
603
604 let base = JacobianPoint::from_affine(point);
605 let table = precompute_nibble_window(&base);
606 let mut acc = JacobianPoint::infinity();
607 let bits = scalar.to_be_bytes();
608 for byte in bits {
609 let hi = usize::from(byte >> 4);
610 for _ in 0..4 {
611 acc = jacobian_double(&acc);
612 }
613 if hi != 0 {
614 acc = jacobian_add(&acc, &table[hi]);
615 }
616
617 let lo = usize::from(byte & 0x0F);
618 for _ in 0..4 {
619 acc = jacobian_double(&acc);
620 }
621 if lo != 0 {
622 acc = jacobian_add(&acc, &table[lo]);
623 }
624 }
625 acc
626}
627
628fn precompute_nibble_window(base: &JacobianPoint) -> Vec<JacobianPoint> {
642 let mut table = Vec::with_capacity(16);
643 table.push(JacobianPoint::infinity());
644 table.push(base.clone());
645 for idx in 2..16 {
646 let next = jacobian_add(&table[idx - 1], base);
647 table.push(next);
648 }
649 table
650}
651
652fn is_point_on_curve(point: &CurvePoint) -> bool {
666 if point.infinity {
667 return false;
668 }
669 let p = curve_modulus_p();
670 let a = curve_a();
671 let b = curve_b();
672 let y_sq = mod_mul(&point.y, &point.y, &p);
673 let x_sq = mod_mul(&point.x, &point.x, &p);
674 let x_cu = mod_mul(&x_sq, &point.x, &p);
675 let ax = mod_mul(&a, &point.x, &p);
676 let rhs = mod_add(&mod_add(&x_cu, &ax, &p), &b, &p);
677 y_sq == rhs
678}
679
680impl CurvePoint {
681 fn infinity() -> Self {
684 Self {
685 x: BigUint::zero(),
686 y: BigUint::zero(),
687 infinity: true,
688 }
689 }
690}
691
692impl JacobianPoint {
693 fn infinity() -> Self {
696 Self {
697 x: BigUint::zero(),
698 y: BigUint::zero(),
699 z: BigUint::zero(),
700 infinity: true,
701 }
702 }
703
704 fn from_affine(point: &CurvePoint) -> Self {
707 if point.infinity {
708 return Self::infinity();
709 }
710 Self {
711 x: point.x.clone(),
712 y: point.y.clone(),
713 z: BigUint::one(),
714 infinity: false,
715 }
716 }
717
718 fn to_affine(&self) -> Result<CurvePoint> {
722 if self.infinity || self.z.is_zero() {
723 return Ok(CurvePoint::infinity());
724 }
725 let p = curve_modulus_p();
726 let z_inv = mod_inv(&self.z, &p)?;
727 let z_inv2 = mod_mul(&z_inv, &z_inv, &p);
728 let z_inv3 = mod_mul(&z_inv2, &z_inv, &p);
729 Ok(CurvePoint {
730 x: mod_mul(&self.x, &z_inv2, &p),
731 y: mod_mul(&self.y, &z_inv3, &p),
732 infinity: false,
733 })
734 }
735}
736
737fn jacobian_double(a: &JacobianPoint) -> JacobianPoint {
751 if a.infinity || a.y.is_zero() {
752 return JacobianPoint::infinity();
753 }
754 let p = curve_modulus_p();
755 let two = BigUint::from_u128(2);
756 let three = BigUint::from_u128(3);
757 let four = BigUint::from_u128(4);
758 let eight = BigUint::from_u128(8);
759
760 let yy = mod_mul(&a.y, &a.y, &p);
761 let yyyy = mod_mul(&yy, &yy, &p);
762 let x_yy = mod_mul(&a.x, &yy, &p);
763 let s = mod_mul(&x_yy, &four, &p);
764
765 let zz = mod_mul(&a.z, &a.z, &p);
766 let x_minus_zz = mod_sub(&a.x, &zz, &p);
767 let x_plus_zz = mod_add(&a.x, &zz, &p);
768 let m_term = mod_mul(&x_minus_zz, &x_plus_zz, &p);
769 let m = mod_mul(&m_term, &three, &p);
770
771 let m2 = mod_mul(&m, &m, &p);
772 let two_s = mod_mul(&s, &two, &p);
773 let x3 = mod_sub(&m2, &two_s, &p);
774 let s_minus_x3 = mod_sub(&s, &x3, &p);
775 let m_s_minus_x3 = mod_mul(&m, &s_minus_x3, &p);
776 let eight_yyyy = mod_mul(&yyyy, &eight, &p);
777 let y3 = mod_sub(&m_s_minus_x3, &eight_yyyy, &p);
778 let yz = mod_mul(&a.y, &a.z, &p);
779 let z3 = mod_mul(&yz, &two, &p);
780
781 JacobianPoint {
782 x: x3,
783 y: y3,
784 z: z3,
785 infinity: false,
786 }
787}
788
789fn jacobian_add(a: &JacobianPoint, b: &JacobianPoint) -> JacobianPoint {
804 if a.infinity {
805 return b.clone();
806 }
807 if b.infinity {
808 return a.clone();
809 }
810
811 let p = curve_modulus_p();
812 let two = BigUint::from_u128(2);
813
814 let z1z1 = mod_mul(&a.z, &a.z, &p);
815 let z2z2 = mod_mul(&b.z, &b.z, &p);
816 let u1 = mod_mul(&a.x, &z2z2, &p);
817 let u2 = mod_mul(&b.x, &z1z1, &p);
818
819 let z1_cubed = mod_mul(&z1z1, &a.z, &p);
820 let z2_cubed = mod_mul(&z2z2, &b.z, &p);
821 let s1 = mod_mul(&a.y, &z2_cubed, &p);
822 let s2 = mod_mul(&b.y, &z1_cubed, &p);
823
824 if u1 == u2 {
825 if s1 != s2 {
826 return JacobianPoint::infinity();
827 }
828 return jacobian_double(a);
829 }
830
831 let h = mod_sub(&u2, &u1, &p);
832 let two_h = mod_mul(&h, &two, &p);
833 let i = mod_mul(&two_h, &two_h, &p);
834 let j = mod_mul(&h, &i, &p);
835 let s2_minus_s1 = mod_sub(&s2, &s1, &p);
836 let r = mod_mul(&s2_minus_s1, &two, &p);
837 let v = mod_mul(&u1, &i, &p);
838
839 let r2 = mod_mul(&r, &r, &p);
840 let two_v = mod_mul(&v, &two, &p);
841 let x3 = mod_sub(&mod_sub(&r2, &j, &p), &two_v, &p);
842
843 let v_minus_x3 = mod_sub(&v, &x3, &p);
844 let r_v_minus_x3 = mod_mul(&r, &v_minus_x3, &p);
845 let two_s1 = mod_mul(&s1, &two, &p);
846 let two_s1_j = mod_mul(&two_s1, &j, &p);
847 let y3 = mod_sub(&r_v_minus_x3, &two_s1_j, &p);
848
849 let z1_plus_z2 = mod_add(&a.z, &b.z, &p);
850 let z1_plus_z2_sq = mod_mul(&z1_plus_z2, &z1_plus_z2, &p);
851 let z_sum = mod_sub(&mod_sub(&z1_plus_z2_sq, &z1z1, &p), &z2z2, &p);
852 let z3 = mod_mul(&z_sum, &h, &p);
853
854 JacobianPoint {
855 x: x3,
856 y: y3,
857 z: z3,
858 infinity: false,
859 }
860}
861
862fn mod_add(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint {
878 a.add(b).modulo(m)
879}
880
881fn mod_sub(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint {
897 if a.cmp(b) != Ordering::Less {
898 a.sub(b).modulo(m)
899 } else {
900 m.sub(&b.sub(a)).modulo(m)
901 }
902}
903
904fn mod_mul(a: &BigUint, b: &BigUint, m: &BigUint) -> BigUint {
920 a.mul(b).modulo(m)
921}
922
923fn mod_inv(a: &BigUint, m: &BigUint) -> Result<BigUint> {
942 if a.is_zero() {
943 return Err(Error::CryptoFailure(
944 "p384 modular inverse of zero is undefined",
945 ));
946 }
947 let two = BigUint::from_u128(2);
948 let exp = m.sub(&two);
949 Ok(BigUint::mod_exp(a, &exp, m))
950}
951
952fn curve_modulus_p() -> BigUint {
966 BigUint::from_be_bytes(&[
967 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
968 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
969 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
970 0xff, 0xff, 0xff,
971 ])
972}
973
974fn curve_a() -> BigUint {
988 BigUint::from_be_bytes(&[
989 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
990 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
991 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
992 0xff, 0xff, 0xfc,
993 ])
994}
995
996fn curve_b() -> BigUint {
1010 BigUint::from_be_bytes(&[
1011 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d,
1012 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13,
1013 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3,
1014 0xec, 0x2a, 0xef,
1015 ])
1016}
1017
1018fn curve_order_n() -> BigUint {
1032 BigUint::from_be_bytes(&[
1033 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1034 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37,
1035 0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc,
1036 0xc5, 0x29, 0x73,
1037 ])
1038}
1039
1040fn curve_base_point() -> CurvePoint {
1054 CurvePoint {
1055 x: BigUint::from_be_bytes(&[
1056 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20,
1057 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0,
1058 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54,
1059 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7,
1060 ]),
1061 y: BigUint::from_be_bytes(&[
1062 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92,
1063 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13,
1064 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43,
1065 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f,
1066 ]),
1067 infinity: false,
1068 }
1069}
1070
1071fn is_all_zero(bytes: &[u8; 48]) -> bool {
1085 let mut acc = 0_u8;
1086 for byte in bytes {
1087 acc |= *byte;
1088 }
1089 acc == 0
1090}
1091
1092fn ct_bytes_eq(left: &[u8], right: &[u8]) -> bool {
1107 if left.len() != right.len() {
1108 return false;
1109 }
1110 let mut diff = 0_u8;
1111 for (&l, &r) in left.iter().zip(right.iter()) {
1112 diff |= l ^ r;
1113 }
1114 diff == 0
1115}
1116
1117fn derive_signing_nonce(private_scalar: &BigUint, digest: &[u8; 48], counter: u32) -> BigUint {
1133 let mut seed = Vec::with_capacity(100);
1134 let scalar_bytes = private_scalar
1135 .to_be_bytes_padded(48)
1136 .expect("p384 private scalar should fit in 48 bytes");
1137 seed.extend_from_slice(&scalar_bytes);
1138 seed.extend_from_slice(digest);
1139 seed.extend_from_slice(&counter.to_be_bytes());
1140 BigUint::from_be_bytes(&noxtls_sha384(&seed))
1141}