Skip to content

Commit b5293db

Browse files
committed
v0.4.6 RC1
1 parent 0670719 commit b5293db

File tree

4 files changed

+90
-7
lines changed

4 files changed

+90
-7
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.4.6 (2024-12-21)
9+
10+
- Added support deterministic signatures via `_seed`
11+
- Trivial typo on signature return error doc
12+
813
## 0.4.5 (2024-11-08)
914

1015
- Bug fix in Hash-ML-DSA - thank you @codespree

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ workspace = { exclude = ["ct_cm4", "dudect", "fuzz", "wasm"] }
22

33
[package]
44
name = "fips204"
5-
version = "0.4.5"
5+
version = "0.4.6"
66
authors = ["Eric Schorn <[email protected]>"]
77
description = "FIPS 204: Module-Lattice-Based Digital Signature"
88
categories = ["cryptography", "no-std"]

src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,12 @@ macro_rules! functionality {
533533
}
534534
assert_eq!(pk.clone().into_bytes(), sk.get_public_key().into_bytes());
535535

536-
let (pk, _) = KG::keygen_from_seed(&[0x11u8; 32]);
536+
let (pk, sk) = KG::keygen_from_seed(&[0x11u8; 32]);
537+
let sig = sk.try_sign_with_seed(&[12u8; 32], &message1, &[]).unwrap();
538+
assert!(pk.verify(&message1, &sig, &[]));
539+
let sig = sk.try_hash_sign_with_seed(&[34u8; 32], &message1, &[], &Ph::SHA256).unwrap();
540+
assert!(pk.hash_verify(&message1, &sig, &[], &Ph::SHA256));
541+
537542
let pk_bytes = pk.into_bytes();
538543
if pk_bytes.len() == 1312 { assert_eq!(pk_bytes[0], 197) }
539544
if pk_bytes.len() == 1952 { assert_eq!(pk_bytes[0], 177) }

src/traits.rs

+78-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::types::Ph;
2-
use rand_core::CryptoRngCore;
2+
use rand_core::{CryptoRng, CryptoRngCore, RngCore};
33
#[cfg(feature = "default-rng")]
44
use rand_core::OsRng;
55

@@ -132,7 +132,7 @@ pub trait Signer {
132132
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>).
133133
///
134134
/// # Errors
135-
/// Returns an error when the random number generator fails; propagates internal errors.
135+
/// Returns an error when the random number generator fails or the `ctx` is longer than 255 bytes; propagates internal errors.
136136
///
137137
/// # Examples
138138
/// ```rust
@@ -167,7 +167,7 @@ pub trait Signer {
167167
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>.
168168
///
169169
/// # Errors
170-
/// Returns an error when the random number generator fails; propagates internal errors.
170+
/// Returns an error when the random number generator fails or the `ctx` is longer than 255 bytes; propagates internal errors.
171171
///
172172
/// # Examples
173173
/// ```rust
@@ -193,7 +193,45 @@ pub trait Signer {
193193
&self, rng: &mut impl CryptoRngCore, message: &[u8], ctx: &[u8],
194194
) -> Result<Self::Signature, &'static str>;
195195

196+
197+
/// Attempt to sign the given message, returning a digital signature on success, or an error if
198+
/// something went wrong. This function utilizes the **provided seed to support (less common)
199+
/// deterministic signatures**. This function operates in constant-time relative to secret data
200+
/// (which specifically excludes the `rho` value stored in the public key, the hash-derived
201+
/// `rho_prime` value that is rejection-sampled/expanded into the internal `s_1` and `s_2` values,
202+
/// and the main signing rejection loop as noted in section 5.5 of
203+
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>.
204+
///
205+
/// # Errors
206+
/// Returns an error when the `ctx` is longer than 255 bytes; propagates internal errors.
207+
///
208+
/// # Examples
209+
/// ```rust
210+
/// # use std::error::Error;
211+
/// # fn main() -> Result<(), Box<dyn Error>> {
212+
/// # #[cfg(feature = "ml-dsa-65")] {
213+
/// use fips204::ml_dsa_65; // Could also be ml_dsa_44 or ml_dsa_87.
214+
/// use fips204::traits::{KeyGen, SerDes, Signer, Verifier};
215+
/// use rand_chacha::rand_core::SeedableRng;
216+
///
217+
/// let message = [0u8, 1, 2, 3, 4, 5, 6, 7];
218+
/// let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
196219
///
220+
/// // Generate key pair and signature
221+
/// let (pk, sk) = ml_dsa_65::KG::try_keygen_with_rng(&mut rng)?; // Generate both public and secret keys
222+
/// let sig = sk.try_sign_with_seed(&[0u8;32], &message, &[0])?; // Use the secret key to generate a message signature
223+
/// let v = pk.verify(&message, &sig, &[0]); // Use the public to verify message signature
224+
/// assert!(v);
225+
/// # }
226+
/// # Ok(())}
227+
/// ```
228+
fn try_sign_with_seed(
229+
&self, seed: &[u8; 32], message: &[u8], ctx: &[u8],
230+
) -> Result<Self::Signature, &'static str> {
231+
self.try_sign_with_rng(&mut DummyRng {data: *seed}, message, ctx)
232+
}
233+
234+
197235
/// Attempt to sign the hash of the given message, returning a digital signature on success,
198236
/// or an error if something went wrong. This function utilizes the **default OS** random number
199237
/// generator and allows for several hash algorithms. This function operates in constant-time
@@ -204,7 +242,7 @@ pub trait Signer {
204242
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>.
205243
///
206244
/// # Errors
207-
/// Will return an error on rng failure
245+
/// Returns an error when the random number generator fails or the `ctx` is longer than 255 bytes; propagates internal errors.
208246
#[cfg(feature = "default-rng")]
209247
fn try_hash_sign(
210248
&self, message: &[u8], ctx: &[u8], ph: &Ph,
@@ -223,12 +261,29 @@ pub trait Signer {
223261
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>.
224262
///
225263
/// # Errors
226-
/// Will return an error on rng failure
264+
/// Returns an error when the random number generator fails or the `ctx` is longer than 255 bytes; propagates internal errors.
227265
fn try_hash_sign_with_rng(
228266
&self, rng: &mut impl CryptoRngCore, message: &[u8], ctx: &[u8], ph: &Ph,
229267
) -> Result<Self::Signature, &'static str>;
230268

231269

270+
/// Attempt to sign the hash of the given message, returning a digital signature on success,
271+
/// something went wrong. This function utilizes the **provided seed to support (less common)
272+
/// deterministic signatures**. This function operates in constant-time relative to secret data
273+
/// (which specifically excludes the `rho` value stored in the public key, the hash-derived
274+
/// `rho_prime` value that is rejection-sampled/expanded into the internal `s_1` and `s_2` values,
275+
/// and the main signing rejection loop as noted in section 5.5 of
276+
/// <https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf>.
277+
///
278+
/// # Errors
279+
/// Returns an error when the `ctx` is longer than 255 bytes; propagates internal errors.
280+
fn try_hash_sign_with_seed(
281+
&self, seed: &[u8;32], message: &[u8], ctx: &[u8], ph: &Ph,
282+
) -> Result<Self::Signature, &'static str> {
283+
self.try_hash_sign_with_rng(&mut DummyRng {data: *seed}, message, ctx, ph)
284+
}
285+
286+
232287
/// Retrieves the public key associated with this private/secret key
233288
///
234289
/// # Examples
@@ -252,6 +307,24 @@ pub trait Signer {
252307
fn get_public_key(&self) -> Self::PublicKey;
253308
}
254309

310+
// This is for the deterministic signing functions; will be refactored more nicely
311+
struct DummyRng { data: [u8; 32] }
312+
313+
impl RngCore for DummyRng {
314+
fn next_u32(&mut self) -> u32 { unimplemented!() }
315+
316+
fn next_u64(&mut self) -> u64 { unimplemented!() }
317+
318+
fn fill_bytes(&mut self, _out: &mut [u8]) { unimplemented!() }
319+
320+
fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> {
321+
out.copy_from_slice(&self.data);
322+
Ok(())
323+
}
324+
}
325+
326+
impl CryptoRng for DummyRng {}
327+
255328

256329
/// The Verifier trait is implemented for `PublicKey` on each of the security parameter sets.
257330
pub trait Verifier {

0 commit comments

Comments
 (0)