1#![cfg_attr(not(feature = "std"), no_std)]
51
52pub(crate) mod curve25519_field;
53#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
58pub(crate) mod jsf;
59#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
60pub(crate) mod scalar_field;
61#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
62pub(crate) mod signing_key;
63#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
64pub(crate) mod strict;
65#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
66pub(crate) mod strict_sign;
67
68#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
69pub use signing_key::{SignError, SigningKey};
70#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
73use signing_key::sign;
74pub(crate) mod x25519;
75pub mod x25519_kem;
76
77pub use curve25519_field::{
78 Curve25519Field, Curve25519FieldCt, CurveSetupError, VerifyField, curve25519_schoolbook,
79};
80pub use modmath::{Field, FieldCt, FieldNct, Residue, ResidueCt, ResidueNct};
81
82use core::marker::PhantomData;
83
84pub trait UnsignedModularInt:
92 Sized
93 + Clone
94 + core::cmp::PartialOrd
95 + const_num_traits::One
96 + const_num_traits::Zero
97 + const_num_traits::BitsPrecision
98 + const_num_traits::WithPrecision
99 + const_num_traits::ops::overflowing::OverflowingAdd<Output = Self>
100 + const_num_traits::WrappingAdd<Output = Self>
101 + const_num_traits::WrappingSub<Output = Self>
102 + const_num_traits::WrappingMul<Output = Self>
103 + core::ops::Shr<usize, Output = Self>
104 + core::ops::BitAnd<Output = Self>
105 + core::ops::ShrAssign<usize>
106 + modmath::MontStorage
107 + modmath::Parity
108 + const_num_traits::FromByteSlice
109 + const_num_traits::ToBytes
110{
111}
112
113impl<T> UnsignedModularInt for T where
114 T: Sized
115 + Clone
116 + core::cmp::PartialOrd
117 + const_num_traits::One
118 + const_num_traits::Zero
119 + const_num_traits::BitsPrecision
120 + const_num_traits::WithPrecision
121 + const_num_traits::ops::overflowing::OverflowingAdd<Output = Self>
122 + const_num_traits::WrappingAdd<Output = Self>
123 + const_num_traits::WrappingSub<Output = Self>
124 + const_num_traits::WrappingMul<Output = Self>
125 + core::ops::Shr<usize, Output = Self>
126 + core::ops::BitAnd<Output = Self>
127 + core::ops::ShrAssign<usize>
128 + modmath::MontStorage
129 + modmath::Parity
130 + const_num_traits::FromByteSlice
131 + const_num_traits::ToBytes
132{
133}
134
135pub trait VerifyBackend:
143 Clone
144 + PartialOrd
145 + const_num_traits::One
146 + const_num_traits::Zero
147 + const_num_traits::BitsPrecision
148 + const_num_traits::WithPrecision
149 + const_num_traits::ops::overflowing::OverflowingAdd<Output = Self>
150 + const_num_traits::WrappingAdd<Output = Self>
151 + const_num_traits::WrappingSub<Output = Self>
152 + core::ops::Shr<usize, Output = Self>
153 + core::ops::ShrAssign<usize>
154 + modmath::Parity
155 + const_num_traits::FromByteSlice
156{
157}
158
159impl<T> VerifyBackend for T where
160 T: Clone
161 + PartialOrd
162 + const_num_traits::One
163 + const_num_traits::Zero
164 + const_num_traits::BitsPrecision
165 + const_num_traits::WithPrecision
166 + const_num_traits::ops::overflowing::OverflowingAdd<Output = Self>
167 + const_num_traits::WrappingAdd<Output = Self>
168 + const_num_traits::WrappingSub<Output = Self>
169 + core::ops::Shr<usize, Output = Self>
170 + core::ops::ShrAssign<usize>
171 + modmath::Parity
172 + const_num_traits::FromByteSlice
173{
174}
175
176#[inline]
184pub(crate) fn from_le_bytes<T>(bytes: &[u8]) -> T
185where
186 T: const_num_traits::FromByteSlice + const_num_traits::Zero,
187{
188 <T as const_num_traits::FromByteSlice>::from_le_slice(bytes).unwrap_or_else(|_| T::zero())
189}
190
191#[inline]
200pub(crate) fn to_le_bytes_ct<T>(
201 x: &T,
202) -> zeroize::Zeroizing<<T as const_num_traits::ToBytes>::Bytes>
203where
204 T: const_num_traits::ToBytes,
205 for<'a> &'a T: const_num_traits::ToBytes<Bytes = <T as const_num_traits::ToBytes>::Bytes>,
206 <T as const_num_traits::ToBytes>::Bytes: zeroize::Zeroize,
207{
208 zeroize::Zeroizing::new(<&T as const_num_traits::ToBytes>::to_le_bytes(x))
209}
210
211pub(crate) fn blind_scalar<const N: usize>(
226 scalar: &[u8; 32],
227 blinder: u32,
228 modulus: &[u8],
229) -> zeroize::Zeroizing<[u8; N]> {
230 fn read_le_u32(c: &[u8]) -> u32 {
232 <[u8; 4]>::try_from(c).map(u32::from_le_bytes).unwrap_or(0)
233 }
234 debug_assert_eq!(N % 4, 0);
235 debug_assert_eq!(modulus.len() % 4, 0);
236
237 let mut out = zeroize::Zeroizing::new([0u8; N]);
238 let mut mod_limbs = modulus.chunks_exact(4);
239 let mut scalar_limbs = scalar.chunks_exact(4);
240 let mut carry: u32 = 0;
241 for out_limb in out.chunks_exact_mut(4) {
242 let m = mod_limbs.next().map(read_le_u32).unwrap_or(0);
243 let s = scalar_limbs.next().map(read_le_u32).unwrap_or(0);
244 let (lo, hi) = const_num_traits::CarryingMul::carrying_mul_add(blinder, m, carry, s);
245 out_limb.copy_from_slice(&lo.to_le_bytes());
246 carry = hi;
247 }
248 debug_assert_eq!(carry, 0);
249
250 out
251}
252
253#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
265pub trait SignBackend:
266 UnsignedModularInt
267 + Copy
268 + modmath::WideMul
269 + modmath::CiosMontMulCt
270 + const_num_traits::CtIsZero
271 + subtle::ConditionallySelectable
272 + subtle::ConstantTimeLess
273 + zeroize::DefaultIsZeroes
274{
275}
276
277#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
278impl<T> SignBackend for T where
279 T: UnsignedModularInt
280 + Copy
281 + modmath::WideMul
282 + modmath::CiosMontMulCt
283 + const_num_traits::CtIsZero
284 + subtle::ConditionallySelectable
285 + subtle::ConstantTimeLess
286 + zeroize::DefaultIsZeroes
287{
288}
289
290pub(crate) const fn hx_le<const N: usize>(s: &str) -> [u8; N] {
297 const fn nib(c: u8) -> u8 {
298 match c {
299 b'0'..=b'9' => c - b'0',
300 b'a'..=b'f' => c - b'a' + 10,
301 b'A'..=b'F' => c - b'A' + 10,
302 _ => panic!("bad hex digit in curve constant"),
303 }
304 }
305 let s = s.as_bytes();
306 assert!(s.len() == 2 * N, "hex length must be 2*N chars");
307 let mut out = [0u8; N];
308 let mut i = 0;
309 while i < N {
310 out[N - 1 - i] = (nib(s[2 * i]) << 4) | nib(s[2 * i + 1]);
312 i += 1;
313 }
314 out
315}
316
317pub const P_BYTES: [u8; 32] =
319 hx_le("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed");
320pub const D_BYTES: [u8; 32] =
322 hx_le("52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3");
323pub const Q_BYTES: [u8; 32] =
325 hx_le("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed");
326
327pub const G_X_BYTES: [u8; 32] =
331 hx_le("216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a");
332pub const G_Y_BYTES: [u8; 32] =
333 hx_le("6666666666666666666666666666666666666666666666666666666666666658");
334pub const G_T_BYTES: [u8; 32] =
335 hx_le("67875f0fd78b766566ea4e8e64abe37d20f09f80775152f56dde8ab3a5b7dda3");
336
337pub const MODP_SQRT_M1_BYTES: [u8; 32] =
339 hx_le("2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0");
340
341#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
345use strict::verify;
346
347pub use x25519::{A24_BYTES, BASE_U_BYTES, BLINDING_MODULUS_BYTES};
349
350pub mod hazmat {
355 pub use crate::x25519::{clamp, x25519, x25519_base, x25519_base_blinded, x25519_blinded};
356
357 #[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
358 pub use crate::signing_key::sign_with_fields;
359 #[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
360 pub use crate::strict::verify_with_field;
361}
362
363pub struct VerifyingKey<T> {
365 public: [u8; 32],
366 _marker: PhantomData<T>,
367}
368
369impl<T> VerifyingKey<T> {
370 pub const fn from_bytes(public: [u8; 32]) -> Self {
372 Self {
373 public,
374 _marker: PhantomData,
375 }
376 }
377
378 pub const fn to_bytes(&self) -> [u8; 32] {
380 self.public
381 }
382}
383
384impl<T> From<[u8; 32]> for VerifyingKey<T> {
385 fn from(public: [u8; 32]) -> Self {
386 Self::from_bytes(public)
387 }
388}
389
390impl<T> Copy for VerifyingKey<T> {}
391
392impl<T> Clone for VerifyingKey<T> {
393 fn clone(&self) -> Self {
394 *self
395 }
396}
397
398impl<T> PartialEq for VerifyingKey<T> {
399 fn eq(&self, other: &Self) -> bool {
400 self.public == other.public
401 }
402}
403
404impl<T> Eq for VerifyingKey<T> {}
405
406impl<T> core::fmt::Debug for VerifyingKey<T> {
407 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
408 f.debug_struct("VerifyingKey")
409 .field("public", &self.public)
410 .finish()
411 }
412}
413
414#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
415fn parse_signature(signature: &[u8]) -> Result<[u8; 64], signature::Error> {
416 signature.try_into().map_err(|_| signature::Error::new())
417}
418
419#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
420impl<T, S> signature::Verifier<S> for VerifyingKey<T>
421where
422 S: AsRef<[u8]>,
423 T: UnsignedModularInt + Copy + modmath::WideMul + modmath::CiosMontMul + modmath::NonCt,
424 for<'a> &'a T: core::ops::BitAnd<Output = T>
425 + const_num_traits::WrappingAdd<Output = T>
426 + const_num_traits::WrappingSub<Output = T>,
427{
428 fn verify(&self, msg: &[u8], signature: &S) -> Result<(), signature::Error> {
429 let signature = parse_signature(signature.as_ref())?;
430 if verify::<T>(self.public, msg, signature) {
431 Ok(())
432 } else {
433 Err(signature::Error::new())
434 }
435 }
436}
437
438#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
439impl<T> signature::Signer<[u8; 64]> for SigningKey<T>
440where
441 T: SignBackend,
442 for<'a> &'a T: const_num_traits::WrappingAdd<Output = T>
443 + const_num_traits::WrappingSub<Output = T>
444 + const_num_traits::ToBytes<Bytes = <T as const_num_traits::ToBytes>::Bytes>,
445 <T as const_num_traits::ToBytes>::Bytes: zeroize::Zeroize,
446{
447 fn try_sign(&self, msg: &[u8]) -> Result<[u8; 64], signature::Error> {
448 sign::<T>(self, msg).map_err(|_| signature::Error::new())
449 }
450}
451
452#[cfg(any(feature = "sha512-hmac-sha512", feature = "sha512-sha2"))]
459impl<T> signature::RandomizedSigner<[u8; 64]> for SigningKey<T>
460where
461 T: SignBackend,
462 for<'a> &'a T: const_num_traits::WrappingAdd<Output = T>
463 + const_num_traits::WrappingSub<Output = T>
464 + const_num_traits::ToBytes<Bytes = <T as const_num_traits::ToBytes>::Bytes>,
465 <T as const_num_traits::ToBytes>::Bytes: zeroize::Zeroize,
466{
467 fn try_sign_with_rng<R: rand_core::TryCryptoRng + ?Sized>(
468 &self,
469 rng: &mut R,
470 msg: &[u8],
471 ) -> Result<[u8; 64], signature::Error> {
472 signing_key::sign_blinded::<T, R>(rng, self, msg).map_err(|_| signature::Error::new())
473 }
474}