diff --git a/dsa/src/generate/secret_number.rs b/dsa/src/generate/secret_number.rs index 3f50845f..96e3cc3f 100644 --- a/dsa/src/generate/secret_number.rs +++ b/dsa/src/generate/secret_number.rs @@ -5,15 +5,12 @@ use crate::{Components, signing_key::SigningKey}; use alloc::vec; use core::cmp::min; -use crypto_bigint::{BoxedUint, NonZero, RandomBits, Resize}; +use crypto_bigint::{BoxedUint, NonZero, NonZeroBoxedUint, RandomBits, Resize}; use digest::{Digest, common::BlockSizeUser}; +use rfc6979::KGenerator; use signature::rand_core::TryCryptoRng; use zeroize::Zeroizing; -fn truncate_hash(hash: &[u8], desired_size: usize) -> &[u8] { - &hash[(hash.len() - desired_size)..] -} - /// Generate a per-message secret number k deterministically using the method described in RFC 6979 /// /// # Returns @@ -23,39 +20,56 @@ fn truncate_hash(hash: &[u8], desired_size: usize) -> &[u8] { pub(crate) fn secret_number_rfc6979( signing_key: &SigningKey, hash: &[u8], -) -> Result<(BoxedUint, BoxedUint), signature::Error> +) -> (BoxedUint, BoxedUint) where D: BlockSizeUser + Digest, { let q = signing_key.verifying_key().components().q(); - let size = (q.bits() / 8) as usize; - - // Truncate hash and reduce mod q - // TODO(tarcieri): `rfc6979` now truncates and reduces mod q. some of this may be redundant? - let hash = BoxedUint::from_be_slice(&hash[..min(size, hash.len())], q.bits_precision()) - .map_err(|_| signature::Error::new())?; - let hash = (hash % q).to_be_bytes(); - let hash = truncate_hash(&hash, size); - - let x_bytes = Zeroizing::new(signing_key.x().to_be_bytes()); - let x_bytes = truncate_hash(&x_bytes, size); + let mut kgen = init_kgen::(signing_key.x(), hash, q); + let mut buffer = vec![0; qlen(q)]; - let mut kgen = rfc6979::KGenerator::::new(x_bytes, hash, &[], q); - - let mut buffer = vec![0; size]; loop { kgen.fill_next_k(&mut buffer); - - let k = BoxedUint::from_be_slice(&buffer, q.bits_precision()) - .map_err(|_| signature::Error::new())?; + let k = bytes2uint(&buffer, q); if let Some(inv_k) = k.invert_mod(q).into() { - if (bool::from(k.is_nonzero())) && (k < **q) { - return Ok((k, inv_k)); + if bool::from(k.is_nonzero()) && k < **q { + return (k, inv_k); } } } } +/// Initialize `KGenerator` from a `hash`, `q`, and the +fn init_kgen<'a, D: BlockSizeUser + Digest>( + x: &NonZeroBoxedUint, + z: &[u8], + q: &'a NonZeroBoxedUint, +) -> KGenerator<'a, D, BoxedUint> { + // Truncate to the right `size` most bytes + fn truncate(b: &[u8], size: usize) -> &[u8] { + &b[(b.len() - size)..] + } + + // Truncate hash and reduce mod q + let size = qlen(q); + let z = bytes2uint(&z[..min(size, z.len())], q); + let z = (z % q).to_be_bytes(); + let z = truncate(&z, size); + + let x = Zeroizing::new(x.to_be_bytes()); + let x = truncate(&x, size); + + rfc6979::KGenerator::::new(x, z, &[], q) +} + +fn bytes2uint(b: &[u8], q: &NonZeroBoxedUint) -> BoxedUint { + BoxedUint::from_be_slice_truncated(b, q.bits_precision()) +} + +fn qlen(q: &NonZeroBoxedUint) -> usize { + q.bits().div_ceil(8) as usize +} + /// Generate a per-message secret number k according to Appendix B.2.1 /// /// # Returns diff --git a/dsa/src/signing_key.rs b/dsa/src/signing_key.rs index 98bea54d..adb63848 100644 --- a/dsa/src/signing_key.rs +++ b/dsa/src/signing_key.rs @@ -4,7 +4,7 @@ #![cfg(feature = "hazmat")] -use crate::{Components, Signature, VerifyingKey}; +use crate::{Components, Signature, VerifyingKey, generate}; use core::{ cmp::min, fmt::{self, Debug}, @@ -73,7 +73,7 @@ impl SigningKey { rng: &mut R, components: Components, ) -> Result { - crate::generate::signing_keypair(rng, components) + generate::signing_keypair(rng, components) } /// DSA public key @@ -98,7 +98,7 @@ impl SigningKey { where D: BlockSizeUser + Digest, { - let k_kinv = crate::generate::secret_number_rfc6979::(self, prehash)?; + let k_kinv = generate::secret_number_rfc6979::(self, prehash); self.sign_prehashed(k_kinv, prehash) } @@ -179,7 +179,7 @@ impl MultipartSigner for SigningKey { impl PrehashSigner for SigningKey { /// Warning: This uses `sha2::Sha256` as the hash function for the digest. If you need to use a different one, use [`SigningKey::sign_prehashed_rfc6979`]. fn sign_prehash(&self, prehash: &[u8]) -> Result { - let k_kinv = crate::generate::secret_number_rfc6979::(self, prehash)?; + let k_kinv = generate::secret_number_rfc6979::(self, prehash); self.sign_prehashed(k_kinv, prehash) } } @@ -192,7 +192,7 @@ impl RandomizedPrehashSigner for SigningKey { ) -> Result { let components = self.verifying_key.components(); - if let Some(k_kinv) = crate::generate::secret_number(rng, components)? { + if let Some(k_kinv) = generate::secret_number(rng, components)? { self.sign_prehashed(k_kinv, prehash) } else { Err(signature::Error::new()) @@ -211,7 +211,7 @@ where let mut digest = D::new(); f(&mut digest)?; let hash = digest.finalize(); - let ks = crate::generate::secret_number_rfc6979::(self, &hash)?; + let ks = generate::secret_number_rfc6979::(self, &hash); self.sign_prehashed(ks, &hash) } @@ -229,7 +229,7 @@ where rng: &mut R, f: F, ) -> Result { - let ks = crate::generate::secret_number(rng, self.verifying_key().components())? + let ks = generate::secret_number(rng, self.verifying_key().components())? .ok_or_else(signature::Error::new)?; let mut digest = D::new(); f(&mut digest)?; @@ -290,7 +290,7 @@ impl<'a> TryFrom> for SigningKey { BoxedUint::from_be_slice(y.as_bytes(), precision) .map_err(|_| pkcs8::KeyError::Invalid)? } else { - crate::generate::public_component(&components, &x) + generate::public_component(&components, &x) .into_option() .ok_or(pkcs8::KeyError::Invalid)? .get()