diff --git a/Cargo.lock b/Cargo.lock index 5af6b71b..56cef6c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,12 +38,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cfg-if" version = "1.0.0" @@ -52,9 +46,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-oid" @@ -64,9 +58,9 @@ checksum = "f7e3352a27098ba6b09546e5f13b15165e6a88b5c2723afecb3ea9576b27e3ea" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -80,6 +74,7 @@ dependencies = [ "hybrid-array", "num-traits", "rand_core", + "serdect 0.2.0", "subtle", "zeroize", ] @@ -95,13 +90,23 @@ dependencies = [ "rand_core", ] +[[package]] +name = "crypto-primes" +version = "0.6.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31bb1382ea4ef18b2da595f36ca284c7b6366d22264ac02f8baee109361cd6b0" +dependencies = [ + "crypto-bigint", + "rand_core", +] + [[package]] name = "der" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ - "const-oid 0.9.5", + "const-oid 0.9.6", "pem-rfc7468 0.7.0", "zeroize", ] @@ -133,9 +138,9 @@ dependencies = [ name = "dsa" version = "0.7.0-pre" dependencies = [ + "crypto-bigint", + "crypto-primes", "digest", - "num-bigint-dig", - "num-traits", "pkcs8 0.11.0-pre.0", "rand", "rand_chacha", @@ -221,9 +226,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -258,72 +263,19 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.2.0-rc.1" +version = "0.2.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b700a69c9d992339e82b6cda619873ee17768be06e80ed5ef07c50c50d499ab" +checksum = "662b1e7b4a15dc889bf687cdd5dc4291b278ad0cf546424a87721dcb54ff1d82" dependencies = [ "typenum", "zeroize", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - [[package]] name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "libm" -version = "0.2.8" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "num-traits" @@ -380,18 +332,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -453,9 +405,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] @@ -471,9 +423,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -532,18 +484,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spki" version = "0.7.3" @@ -572,9 +512,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", diff --git a/dsa/Cargo.toml b/dsa/Cargo.toml index cd88db9a..f13acd6b 100644 --- a/dsa/Cargo.toml +++ b/dsa/Cargo.toml @@ -16,12 +16,16 @@ rust-version = "1.72" [dependencies] digest = "=0.11.0-pre.7" -num-bigint = { package = "num-bigint-dig", version = "0.8", default-features = false, features = ["prime", "rand", "zeroize"] } -num-traits = { version = "0.2", default-features = false } +crypto-bigint = { version = "0.6.0-pre.7", features = ["alloc", "zeroize"] } +crypto-primes = "0.6.0-pre.0" pkcs8 = { version = "=0.11.0-pre.0", default-features = false, features = ["alloc"] } rfc6979 = { version = "=0.5.0-pre.2", path = "../rfc6979" } sha2 = { version = "=0.11.0-pre.2", default-features = false } -signature = { version = "=2.3.0-pre.2", default-features = false, features = ["alloc", "digest", "rand_core"] } +signature = { version = "=2.3.0-pre.2", default-features = false, features = [ + "alloc", + "digest", + "rand_core", +] } zeroize = { version = "1", default-features = false } [dev-dependencies] diff --git a/dsa/src/components.rs b/dsa/src/components.rs index b2450e2f..db1acf11 100644 --- a/dsa/src/components.rs +++ b/dsa/src/components.rs @@ -3,8 +3,7 @@ //! use crate::{size::KeySize, two}; -use num_bigint::BigUint; -use num_traits::Zero; +use crypto_bigint::{BoxedUint, NonZero}; use pkcs8::der::{ self, asn1::UintRef, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, @@ -18,19 +17,23 @@ use signature::rand_core::CryptoRngCore; #[must_use] pub struct Components { /// Prime p - p: BigUint, + p: NonZero, /// Quotient q - q: BigUint, + q: NonZero, /// Generator g - g: BigUint, + g: NonZero, } impl Components { /// Construct the common components container from its inner values (p, q and g) - pub fn from_components(p: BigUint, q: BigUint, g: BigUint) -> signature::Result { - if p < two() || q < two() || g.is_zero() || g > p { + pub fn from_components( + p: NonZero, + q: NonZero, + g: NonZero, + ) -> signature::Result { + if *p < two() || *q < two() || g > p { return Err(signature::Error::new()); } @@ -45,19 +48,19 @@ impl Components { /// DSA prime p #[must_use] - pub const fn p(&self) -> &BigUint { + pub const fn p(&self) -> &NonZero { &self.p } /// DSA quotient q #[must_use] - pub const fn q(&self) -> &BigUint { + pub const fn q(&self) -> &NonZero { &self.q } /// DSA generator g #[must_use] - pub const fn g(&self) -> &BigUint { + pub const fn g(&self) -> &NonZero { &self.g } } @@ -68,9 +71,13 @@ impl<'a> DecodeValue<'a> for Components { let q = reader.decode::>()?; let g = reader.decode::>()?; - let p = BigUint::from_bytes_be(p.as_bytes()); - let q = BigUint::from_bytes_be(q.as_bytes()); - let g = BigUint::from_bytes_be(g.as_bytes()); + let p = BoxedUint::from_be_slice(p.as_bytes(), (p.as_bytes().len() * 8) as u32).unwrap(); + let q = BoxedUint::from_be_slice(q.as_bytes(), (q.as_bytes().len() * 8) as u32).unwrap(); + let g = BoxedUint::from_be_slice(g.as_bytes(), (g.as_bytes().len() * 8) as u32).unwrap(); + + let p = NonZero::new(p).unwrap(); + let q = NonZero::new(q).unwrap(); + let g = NonZero::new(g).unwrap(); Self::from_components(p, q, g).map_err(|_| Tag::Integer.value_error()) } @@ -78,15 +85,15 @@ impl<'a> DecodeValue<'a> for Components { impl EncodeValue for Components { fn value_len(&self) -> der::Result { - UintRef::new(&self.p.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.q.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.g.to_bytes_be())?.encoded_len()? + UintRef::new(&self.p.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.q.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.g.to_be_bytes())?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - UintRef::new(&self.p.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.q.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.g.to_bytes_be())?.encode(writer)?; + UintRef::new(&self.p.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.q.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.g.to_be_bytes())?.encode(writer)?; Ok(()) } } diff --git a/dsa/src/generate.rs b/dsa/src/generate.rs index 1e9b12c3..749a36a7 100644 --- a/dsa/src/generate.rs +++ b/dsa/src/generate.rs @@ -1,6 +1,5 @@ use crate::two; -use num_bigint::{BigUint, RandPrime}; -use num_traits::Pow; +use crypto_bigint::BoxedUint; use signature::rand_core::CryptoRngCore; mod components; @@ -13,9 +12,9 @@ pub use self::secret_number::{secret_number, secret_number_rfc6979}; /// Calculate the upper and lower bounds for generating values like p or q #[inline] -fn calculate_bounds(size: u32) -> (BigUint, BigUint) { - let lower = two().pow(size - 1); - let upper = two().pow(size); +fn calculate_bounds(size: u32) -> (BoxedUint, BoxedUint) { + let lower = two().shl(size - 1); + let upper = two().shl(size); (lower, upper) } @@ -24,6 +23,6 @@ fn calculate_bounds(size: u32) -> (BigUint, BigUint) { /// /// This wrapper function mainly exists to enforce the [`CryptoRng`](rand::CryptoRng) requirement (I might otherwise forget it) #[inline] -fn generate_prime(bit_length: usize, rng: &mut impl CryptoRngCore) -> BigUint { - rng.gen_prime(bit_length) +fn generate_prime(bit_length: u32, rng: &mut impl CryptoRngCore) -> BoxedUint { + crypto_primes::generate_prime_with_rng(rng, bit_length, bit_length) } diff --git a/dsa/src/generate/components.rs b/dsa/src/generate/components.rs index 101aefab..f8511c4e 100644 --- a/dsa/src/generate/components.rs +++ b/dsa/src/generate/components.rs @@ -7,59 +7,63 @@ use crate::{ size::KeySize, two, Components, }; -use num_bigint::{prime::probably_prime, BigUint, RandBigInt}; -use num_traits::One; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, NonZero, Odd, RandomBits, +}; use signature::rand_core::CryptoRngCore; -/// Numbers of miller-rabin rounds performed to determine primality -const MR_ROUNDS: usize = 64; - /// Generate the common components p, q, and g /// /// # Returns /// -/// Tuple of three `BigUint`s. Ordered like this `(p, q, g)` +/// Tuple of three `BoxedUint`s. Ordered like this `(p, q, g)` pub fn common( rng: &mut impl CryptoRngCore, KeySize { l, n }: KeySize, -) -> (BigUint, BigUint, BigUint) { +) -> (NonZero, NonZero, NonZero) { // Calculate the lower and upper bounds of p and q let (p_min, p_max) = calculate_bounds(l); let (q_min, q_max) = calculate_bounds(n); let (p, q) = 'gen_pq: loop { - let q = generate_prime(n as usize, rng); + let q = generate_prime(n, rng); if q < q_min || q > q_max { continue; } + let q = NonZero::new(q).unwrap(); // Attempt to find a prime p which has a subgroup of the order q for _ in 0..4096 { let m = 'gen_m: loop { - let m = rng.gen_biguint(l as usize); + let m = BoxedUint::random_bits(rng, l); if m > p_min && m < p_max { break 'gen_m m; } }; - let mr = &m % (two() * &q); - let p = m - mr + BigUint::one(); + let mr = &m % NonZero::new(two() * &*q).unwrap(); + let p = m - mr + BoxedUint::one(); + let p = NonZero::new(p).unwrap(); - if probably_prime(&p, MR_ROUNDS) { + if crypto_primes::is_prime_with_rng(rng, &*p) { break 'gen_pq (p, q); } } }; // Generate g using the unverifiable method as defined by Appendix A.2.1 - let e = (&p - BigUint::one()) / &q; - let mut h = BigUint::one(); + let e = (&*p - &BoxedUint::one()) / &q; + let mut h = BoxedUint::one(); let g = loop { - let g = h.modpow(&e, &p); - if !g.is_one() { - break g; + let params = BoxedMontyParams::new_vartime(Odd::new((*p).clone()).unwrap()); + let form = BoxedMontyForm::new(h.clone(), params); + let g = form.pow(&e).to_montgomery(); + + if !bool::from(g.is_one()) { + break NonZero::new(g).unwrap(); } - h += BigUint::one(); + h = h + BoxedUint::one(); }; (p, q, g) @@ -67,9 +71,12 @@ pub fn common( /// Calculate the public component from the common components and the private component #[inline] -pub fn public(components: &Components, x: &BigUint) -> BigUint { +pub fn public(components: &Components, x: &NonZero) -> NonZero { let p = components.p(); let g = components.g(); - g.modpow(x, p) + let params = BoxedMontyParams::new_vartime(Odd::new((**p).clone()).unwrap()); + let form = BoxedMontyForm::new((**g).clone(), params); + + NonZero::new(form.pow(x).to_montgomery()).unwrap() } diff --git a/dsa/src/generate/keypair.rs b/dsa/src/generate/keypair.rs index 39cdc2b5..e07b5e23 100644 --- a/dsa/src/generate/keypair.rs +++ b/dsa/src/generate/keypair.rs @@ -3,14 +3,19 @@ //! use crate::{generate::components, Components, SigningKey, VerifyingKey}; -use num_bigint::{BigUint, RandBigInt}; -use num_traits::One; +use crypto_bigint::{BoxedUint, NonZero, RandomMod}; use signature::rand_core::CryptoRngCore; /// Generate a new keypair #[inline] pub fn keypair(rng: &mut impl CryptoRngCore, components: Components) -> SigningKey { - let x = rng.gen_biguint_range(&BigUint::one(), components.q()); + let x = loop { + let x = BoxedUint::random_mod(rng, components.q()); + if let Some(x) = NonZero::new(x).into() { + break x; + } + }; + let y = components::public(&components, &x); VerifyingKey::from_components(components, y) diff --git a/dsa/src/generate/secret_number.rs b/dsa/src/generate/secret_number.rs index 3c974ed4..2009dba1 100644 --- a/dsa/src/generate/secret_number.rs +++ b/dsa/src/generate/secret_number.rs @@ -5,25 +5,24 @@ use crate::{Components, SigningKey}; use alloc::{vec, vec::Vec}; use core::cmp::min; +use crypto_bigint::{BoxedUint, InvMod, NonZero, RandomBits}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; -use num_bigint::{BigUint, ModInverse, RandBigInt}; -use num_traits::{One, Zero}; use rfc6979::HmacDrbg; use signature::rand_core::CryptoRngCore; use zeroize::Zeroize; /// Reduce the hash into an RFC-6979 appropriate form -fn reduce_hash(q: &BigUint, hash: &[u8]) -> Vec { +fn reduce_hash(q: &NonZero, hash: &[u8]) -> Vec { // Reduce the hash modulo Q let q_byte_len = q.bits() / 8; - let hash_len = min(hash.len(), q_byte_len); + let hash_len = min(hash.len(), q_byte_len as usize); let hash = &hash[..hash_len]; - let hash = BigUint::from_bytes_be(hash); - let mut reduced = (hash % q).to_bytes_be(); + let hash = BoxedUint::from_be_slice(hash, (hash.len() * 8) as u32).unwrap(); + let mut reduced = Vec::from((hash % q).to_be_bytes()); - while reduced.len() < q_byte_len { + while reduced.len() < q_byte_len as usize { reduced.insert(0, 0); } @@ -36,15 +35,15 @@ fn reduce_hash(q: &BigUint, hash: &[u8]) -> Vec { /// /// Secret number k and its modular multiplicative inverse with q #[inline] -pub fn secret_number_rfc6979(signing_key: &SigningKey, hash: &[u8]) -> (BigUint, BigUint) +pub fn secret_number_rfc6979(signing_key: &SigningKey, hash: &[u8]) -> (BoxedUint, BoxedUint) where D: Digest + BlockSizeUser + FixedOutputReset, { let q = signing_key.verifying_key().components().q(); - let k_size = q.bits() / 8; + let k_size = (q.bits() / 8) as usize; let hash = reduce_hash(q, hash); - let mut x_bytes = signing_key.x().to_bytes_be(); + let mut x_bytes = signing_key.x().to_be_bytes(); let mut hmac = HmacDrbg::::new(&x_bytes, &hash, &[]); x_bytes.zeroize(); @@ -52,11 +51,9 @@ where loop { hmac.fill_bytes(&mut buffer); - let k = BigUint::from_bytes_be(&buffer); - if let Some(inv_k) = (&k).mod_inverse(q) { - let inv_k = inv_k.to_biguint().unwrap(); - - if k > BigUint::zero() && &k < q { + let k = BoxedUint::from_be_slice(&buffer, (buffer.len() * 8) as u32).unwrap(); + if let Some(inv_k) = k.inv_mod(q).into() { + if k > BoxedUint::zero() && k < **q { return (k, inv_k); } } @@ -72,21 +69,19 @@ where pub fn secret_number( rng: &mut impl CryptoRngCore, components: &Components, -) -> Option<(BigUint, BigUint)> { +) -> Option<(BoxedUint, BoxedUint)> { let q = components.q(); let n = q.bits(); // Attempt to try a fitting secret number // Give up after 4096 tries for _ in 0..4096 { - let c = rng.gen_biguint(n + 64); - let k = (c % (q - BigUint::one())) + BigUint::one(); - - if let Some(inv_k) = (&k).mod_inverse(q) { - let inv_k = inv_k.to_biguint().unwrap(); + let c = BoxedUint::random_bits(rng, n + 64); + let k = (c % NonZero::new(&**q - &BoxedUint::one()).unwrap()) + BoxedUint::one(); + if let Some(inv_k) = k.inv_mod(q).into() { // `k` and `k^-1` both have to be in the range `[1, q-1]` - if (inv_k > BigUint::zero() && &inv_k < q) && (k > BigUint::zero() && &k < q) { + if (inv_k > BoxedUint::zero() && inv_k < **q) && (k > BoxedUint::zero() && k < **q) { return Some((k, inv_k)); } } diff --git a/dsa/src/lib.rs b/dsa/src/lib.rs index 3a0fa78b..a3571265 100644 --- a/dsa/src/lib.rs +++ b/dsa/src/lib.rs @@ -24,11 +24,11 @@ //! //! ``` //! # use dsa::{Components, SigningKey, VerifyingKey}; -//! # use num_bigint::BigUint; +//! # use crypto_bigint::BoxedUint; //! # use num_traits::One; -//! # let read_common_parameters = || (BigUint::one(), BigUint::one(), BigUint::one()); -//! # let read_public_component = || BigUint::one(); -//! # let read_private_component = || BigUint::one(); +//! # let read_common_parameters = || (BoxedUint::one(), BoxedUint::one(), BoxedUint::one()); +//! # let read_public_component = || BoxedUint::one(); +//! # let read_private_component = || BoxedUint::one(); //! # || -> signature::Result<()> { //! let (p, q, g) = read_common_parameters(); //! let components = Components::from_components(p, q, g)?; @@ -50,7 +50,8 @@ pub use crate::{ components::Components, signing_key::SigningKey, size::KeySize, verifying_key::VerifyingKey, }; -pub use num_bigint::BigUint; +pub use crypto_bigint::BoxedUint; +use crypto_bigint::NonZero; pub use pkcs8; pub use signature; @@ -68,7 +69,6 @@ mod verifying_key; pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10040.4.1"); use alloc::{boxed::Box, vec::Vec}; -use num_traits::Zero; use pkcs8::der::{ self, asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, @@ -80,31 +80,27 @@ use signature::SignatureEncoding; #[must_use] pub struct Signature { /// Signature part r - r: BigUint, + r: NonZero, /// Signature part s - s: BigUint, + s: NonZero, } impl Signature { /// Create a new Signature container from its components - pub fn from_components(r: BigUint, s: BigUint) -> signature::Result { - if r.is_zero() || s.is_zero() { - return Err(signature::Error::new()); - } - - Ok(Self { r, s }) + pub fn from_components(r: NonZero, s: NonZero) -> Self { + Self { r, s } } /// Signature part r #[must_use] - pub fn r(&self) -> &BigUint { + pub fn r(&self) -> &NonZero { &self.r } /// Signature part s #[must_use] - pub fn s(&self) -> &BigUint { + pub fn s(&self) -> &NonZero { &self.s } } @@ -115,23 +111,26 @@ impl<'a> DecodeValue<'a> for Signature { let r = UintRef::decode(reader)?; let s = UintRef::decode(reader)?; - let r = BigUint::from_bytes_be(r.as_bytes()); - let s = BigUint::from_bytes_be(s.as_bytes()); + let r = BoxedUint::from_be_slice(r.as_bytes(), r.as_bytes().len() as u32 * 8).unwrap(); + let s = BoxedUint::from_be_slice(s.as_bytes(), s.as_bytes().len() as u32 * 8).unwrap(); + + let r = NonZero::new(r).unwrap(); + let s = NonZero::new(s).unwrap(); - Self::from_components(r, s).map_err(|_| der::Tag::Integer.value_error()) + Ok(Self::from_components(r, s)) }) } } impl EncodeValue for Signature { fn value_len(&self) -> der::Result { - UintRef::new(&self.r.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.s.to_bytes_be())?.encoded_len()? + UintRef::new(&self.r.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.s.to_be_bytes())?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - UintRef::new(&self.r.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.s.to_bytes_be())?.encode(writer)?; + UintRef::new(&self.r.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.s.to_be_bytes())?.encode(writer)?; Ok(()) } } @@ -177,8 +176,8 @@ impl TryFrom<&[u8]> for Signature { } } -/// Returns a `BigUint` with the value 2 +/// Returns a `BoxedUint` with the value 2 #[inline] -fn two() -> BigUint { - BigUint::from(2_u8) +fn two() -> BoxedUint { + BoxedUint::from(2_u8) } diff --git a/dsa/src/signing_key.rs b/dsa/src/signing_key.rs index d471aae5..b2c05cbb 100644 --- a/dsa/src/signing_key.rs +++ b/dsa/src/signing_key.rs @@ -7,9 +7,11 @@ use core::{ cmp::min, fmt::{self, Debug}, }; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, NonZero, Odd, +}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; -use num_bigint::BigUint; -use num_traits::Zero; use pkcs8::{ der::{asn1::UintRef, AnyRef, Decode, Encode}, AlgorithmIdentifierRef, EncodePrivateKey, PrivateKeyInfo, SecretDocument, @@ -32,13 +34,16 @@ pub struct SigningKey { verifying_key: VerifyingKey, /// Private component x - x: Zeroizing, + x: Zeroizing>, } impl SigningKey { /// Construct a new private key from the public key and private component - pub fn from_components(verifying_key: VerifyingKey, x: BigUint) -> signature::Result { - if x.is_zero() || x > *verifying_key.components().q() { + pub fn from_components( + verifying_key: VerifyingKey, + x: NonZero, + ) -> signature::Result { + if x > *verifying_key.components().q() { return Err(signature::Error::new()); } @@ -63,31 +68,34 @@ impl SigningKey { /// /// If you decide to clone this value, please consider using [`Zeroize::zeroize`](::zeroize::Zeroize::zeroize()) to zero out the memory after you're done using the clone #[must_use] - pub fn x(&self) -> &BigUint { + pub fn x(&self) -> &NonZero { &self.x } /// Sign some pre-hashed data fn sign_prehashed( &self, - (k, inv_k): (BigUint, BigUint), + (k, inv_k): (BoxedUint, BoxedUint), hash: &[u8], ) -> signature::Result { let components = self.verifying_key().components(); let (p, q, g) = (components.p(), components.q(), components.g()); let x = self.x(); - let r = g.modpow(&k, p) % q; + let params = BoxedMontyParams::new(Odd::new(k).unwrap()); + let form = BoxedMontyForm::new((**g).clone(), params); + let r = NonZero::new(form.pow(p).to_montgomery() % q).unwrap(); let n = q.bits() / 8; let block_size = hash.len(); // Hash function output size - let z_len = min(n, block_size); - let z = BigUint::from_bytes_be(&hash[..z_len]); + let z_len = min(n as usize, block_size); + let z = BoxedUint::from_be_slice(&hash[..z_len], z_len as u32 * 8).unwrap(); - let s = (inv_k * (z + x * &r)) % q; + let s = inv_k.mul_mod(&(z + &**x * &*r), q); + let s = NonZero::new(s).unwrap(); - let signature = Signature::from_components(r, s)?; + let signature = Signature::from_components(r, s); if signature.r() < q && signature.s() < q { Ok(signature) @@ -165,7 +173,7 @@ impl EncodePrivateKey for SigningKey { parameters: Some(parameters), }; - let mut x_bytes = self.x().to_bytes_be(); + let mut x_bytes = self.x().to_be_bytes(); let x = UintRef::new(&x_bytes)?; let mut signing_key = x.to_der()?; @@ -189,11 +197,15 @@ impl<'a> TryFrom> for SigningKey { let components = parameters.decode_as::()?; let x = UintRef::from_der(value.private_key)?; - let x = BigUint::from_bytes_be(x.as_bytes()); + let x = BoxedUint::from_be_slice(x.as_bytes(), x.as_bytes().len() as u32 * 8).unwrap(); + let x = NonZero::new(x).unwrap(); let y = if let Some(y_bytes) = value.public_key { let y = UintRef::from_der(y_bytes)?; - BigUint::from_bytes_be(y.as_bytes()) + NonZero::new( + BoxedUint::from_be_slice(y.as_bytes(), y.as_bytes().len() as u32 * 8).unwrap(), + ) + .unwrap() } else { crate::generate::public_component(&components, &x) }; diff --git a/dsa/src/verifying_key.rs b/dsa/src/verifying_key.rs index e44bebf4..95c7ff74 100644 --- a/dsa/src/verifying_key.rs +++ b/dsa/src/verifying_key.rs @@ -4,9 +4,11 @@ use crate::{two, Components, Signature, OID}; use core::cmp::min; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, InvMod, NonZero, Odd, +}; use digest::Digest; -use num_bigint::{BigUint, ModInverse}; -use num_traits::One; use pkcs8::{ der::{ asn1::{BitStringRef, UintRef}, @@ -24,13 +26,19 @@ pub struct VerifyingKey { components: Components, /// Public component y - y: BigUint, + y: NonZero, } impl VerifyingKey { /// Construct a new public key from the common components and the public component - pub fn from_components(components: Components, y: BigUint) -> signature::Result { - if y < two() || y.modpow(components.q(), components.p()) != BigUint::one() { + pub fn from_components( + components: Components, + y: NonZero, + ) -> signature::Result { + let params = BoxedMontyParams::new_vartime(Odd::new((**components.p()).clone()).unwrap()); + let form = BoxedMontyForm::new((*y).clone(), params); + + if *y < two() || form.pow(components.q()).to_montgomery() != BoxedUint::one() { return Err(signature::Error::new()); } @@ -44,7 +52,7 @@ impl VerifyingKey { /// DSA public component #[must_use] - pub const fn y(&self) -> &BigUint { + pub const fn y(&self) -> &NonZero { &self.y } @@ -60,19 +68,26 @@ impl VerifyingKey { return Some(false); } - let w = s.mod_inverse(q)?.to_biguint().unwrap(); + let w = Option::from(s.inv_mod(q))?; let n = q.bits() / 8; let block_size = hash.len(); // Hash function output size - let z_len = min(n, block_size); - let z = BigUint::from_bytes_be(&hash[..z_len]); + let z_len = min(n as usize, block_size); + let z = BoxedUint::from_be_slice(&hash[..z_len], z_len as u32 * 8).unwrap(); let u1 = (&z * &w) % q; - let u2 = (r * &w) % q; - let v = (g.modpow(&u1, p) * y.modpow(&u2, p) % p) % q; + let u2 = r.mul_mod(&w, q); + + let u1_params = BoxedMontyParams::new(Odd::new(u1).unwrap()); + let u2_params = BoxedMontyParams::new(Odd::new(u2).unwrap()); + + let g_form = BoxedMontyForm::new((**g).clone(), u1_params); + let y_form = BoxedMontyForm::new((**y).clone(), u2_params); + + let v = (g_form.pow(p).to_montgomery() * y_form.pow(p).to_montgomery() % p) % q; - Some(v == *r) + Some(v == **r) } } @@ -124,7 +139,7 @@ impl EncodePublicKey for VerifyingKey { parameters: Some(parameters), }; - let y_bytes = self.y.to_bytes_be(); + let y_bytes = self.y.to_be_bytes(); let y = UintRef::new(&y_bytes)?; let public_key = y.to_der()?; @@ -151,7 +166,13 @@ impl<'a> TryFrom> for VerifyingKey { .ok_or(spki::Error::KeyMalformed)?, )?; - Self::from_components(components, BigUint::from_bytes_be(y.as_bytes())) - .map_err(|_| spki::Error::KeyMalformed) + Self::from_components( + components, + NonZero::new( + BoxedUint::from_be_slice(y.as_bytes(), y.as_bytes().len() as u32 * 8).unwrap(), + ) + .unwrap(), + ) + .map_err(|_| spki::Error::KeyMalformed) } } diff --git a/dsa/tests/deterministic.rs b/dsa/tests/deterministic.rs index 483844a0..3d21e2df 100644 --- a/dsa/tests/deterministic.rs +++ b/dsa/tests/deterministic.rs @@ -1,7 +1,6 @@ +use crypto_bigint::{BoxedUint, NonZero}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; use dsa::{Components, Signature, SigningKey, VerifyingKey}; -use num_bigint::BigUint; -use num_traits::Num; use sha1::Sha1; use sha2::{Sha224, Sha256, Sha384, Sha512}; use signature::DigestSigner; @@ -10,33 +9,37 @@ const MESSAGE: &[u8] = b"sample"; const MESSAGE_2: &[u8] = b"test"; fn dsa_1024_signing_key() -> SigningKey { - let p = BigUint::from_str_radix( - "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447\ + let p_str = "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447\ E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88\ 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C\ - 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", - 16, - ) - .unwrap(); - let q = BigUint::from_str_radix("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16).unwrap(); - let g = BigUint::from_str_radix( - "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ + 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779"; + let p = BoxedUint::from_be_hex(p_str, p_str.len() as u32 * 8 / 2).unwrap(); + + let q_str = "996F967F6C8E388D9E28D01E205FBA957A5698B1"; + let q = BoxedUint::from_be_hex(q_str, q_str.len() as u32 * 8 / 2).unwrap(); + + let g_str = "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD\ 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4\ - 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", - 16, - ) - .unwrap(); + 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD"; + let g = BoxedUint::from_be_hex(g_str, g_str.len() as u32 / 2 * 8).unwrap(); - let x = BigUint::from_str_radix("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16).unwrap(); - let y = BigUint::from_str_radix( - "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ + let x_str = "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7"; + let x = BoxedUint::from_be_hex(x_str, x_str.len() as u32 / 2 * 8).unwrap(); + + let y_str = "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D\ 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6\ - 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B", - 16, - ) - .unwrap(); + 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B"; + let y = BoxedUint::from_be_hex(y_str, y_str.len() as u32 / 2 * 8).unwrap(); + + let (p, q, g, y, x) = ( + NonZero::new(p).unwrap(), + NonZero::new(q).unwrap(), + NonZero::new(g).unwrap(), + NonZero::new(y).unwrap(), + NonZero::new(x).unwrap(), + ); let components = Components::from_components(p, q, g).expect("Invalid components"); let verifying_key = @@ -46,7 +49,7 @@ fn dsa_1024_signing_key() -> SigningKey { } fn dsa_2048_signing_key() -> SigningKey { - let p = BigUint::from_str_radix( + let p = BoxedUint::from_be_hex( "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48\ C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F\ FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5\ @@ -55,15 +58,15 @@ fn dsa_2048_signing_key() -> SigningKey { F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE\ 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15\ 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", - 16, + 2048, ) .unwrap(); - let q = BigUint::from_str_radix( + let q = BoxedUint::from_be_hex( "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - 16, + 2048, ) .unwrap(); - let g = BigUint::from_str_radix( + let g = BoxedUint::from_be_hex( "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613\ D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4\ 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472\ @@ -72,16 +75,16 @@ fn dsa_2048_signing_key() -> SigningKey { 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71\ BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0\ DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - 16, + 2048, ) .unwrap(); - let x = BigUint::from_str_radix( + let x = BoxedUint::from_be_hex( "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - 16, + 2048, ) .unwrap(); - let y = BigUint::from_str_radix( + let y = BoxedUint::from_be_hex( "667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94\ 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61\ 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE\ @@ -90,10 +93,18 @@ fn dsa_2048_signing_key() -> SigningKey { 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1\ 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA\ 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF", - 16, + 2048, ) .unwrap(); + let (p, q, g, y, x) = ( + NonZero::new(p).unwrap(), + NonZero::new(q).unwrap(), + NonZero::new(g).unwrap(), + NonZero::new(y).unwrap(), + NonZero::new(x).unwrap(), + ); + let components = Components::from_components(p, q, g).expect("Invalid components"); let verifying_key = VerifyingKey::from_components(components, y).expect("Invalid verifying key"); @@ -128,10 +139,9 @@ where /// Create a signature container from the two components in their textual hexadecimal form fn from_str_signature(r: &str, s: &str) -> Signature { Signature::from_components( - BigUint::from_str_radix(r, 16).unwrap(), - BigUint::from_str_radix(s, 16).unwrap(), + NonZero::new(BoxedUint::from_be_hex(r, r.len() as u32 / 2 * 8).unwrap()).unwrap(), + NonZero::new(BoxedUint::from_be_hex(s, s.len() as u32 / 2 * 8).unwrap()).unwrap(), ) - .unwrap() } /// Return the RFC 6979 test cases diff --git a/dsa/tests/signing_key.rs b/dsa/tests/signing_key.rs index 5b853987..a5d68b48 100644 --- a/dsa/tests/signing_key.rs +++ b/dsa/tests/signing_key.rs @@ -2,10 +2,12 @@ // But we want to use those small key sizes for fast tests #![allow(deprecated)] +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, Odd, +}; use digest::Digest; use dsa::{Components, KeySize, SigningKey}; -use num_bigint::BigUint; -use num_traits::Zero; use pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding}; use sha1::Sha1; use signature::{DigestVerifier, RandomizedDigestSigner}; @@ -59,13 +61,16 @@ fn verify_validity() { let signing_key = generate_keypair(); let components = signing_key.verifying_key().components(); + let params = BoxedMontyParams::new(Odd::new((**signing_key.x()).clone()).unwrap()); + let form = BoxedMontyForm::new((**components.g()).clone(), params); + assert!( - BigUint::zero() < *signing_key.x() && signing_key.x() < components.q(), + BoxedUint::zero() < **signing_key.x() && signing_key.x() < components.q(), "Requirement 0