This commit is contained in:
eschorn1 2024-12-22 18:32:27 -06:00
parent e77284a10d
commit 6f0f48eaee
8 changed files with 351 additions and 50 deletions

View file

@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.4.1 (2024-12-22)
- Added keygen with seeds for deterministic keygen
- Added two fuzzing harnesses (still some work to go)
## 0.4.0 (2024-10-04)
- Updated to FIPS 205 final spec
## 0.1.2 (2024-03-15) ## 0.1.2 (2024-03-15)
- Internal improvements, removed dependency on generic-array, MSRV at 1.70 - Internal improvements, removed dependency on generic-array, MSRV at 1.70

View file

@ -1,8 +1,8 @@
workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4"] } workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4", "fuzz"] }
[package] [package]
name = "fips205" name = "fips205"
version = "0.4.0" version = "0.4.1"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "FIPS 205: Stateless Hash-Based Digital Signature Standard" description = "FIPS 205: Stateless Hash-Based Digital Signature Standard"

48
fuzz/Cargo.toml Normal file
View file

@ -0,0 +1,48 @@
[package]
name = "fips205-fuzz"
version = "0.4.1"
authors = ["Eric Schorn <eschorn@integritychain.com>"]
description = "Fuzz harness for FIPS 205 (release) ML-DSA"
edition = "2021"
license = "MIT OR Apache-2.0"
publish = false
rust-version = "1.70"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
rand_core = { version = "0.6.4", default-features = false }
rand_chacha = "0.3.1"
arbitrary = { version = "1.0", features = ["derive"] }
[dependencies.fips205]
path = ".."
# Prevent this from interfering with workspaces
#[workspace]
#members = ["."]
[profile.release]
opt-level = 0
debug = true
debug-assertions = true
overflow-checks = true
[[bin]]
name = "fuzz_verify"
path = "fuzz_targets/fuzz_verify.rs"
test = false
doc = false
[[bin]]
name = "fuzz_sign"
path = "fuzz_targets/fuzz_sign.rs"
test = false
doc = false

42
fuzz/README.md Normal file
View file

@ -0,0 +1,42 @@
This is a work in progress, but good results currently.
Harness code is in fuzz/fuzz_targets/*. The Cargo.toml file specifies that overflow-checks and
debug-assertions are enabled (so the fuzzer can find these panics).
See <https://rust-fuzz.github.io/book/introduction.html>
~~~
$ cd fuzz # this directory; you may need to install cargo fuzz
$ rustup default nightly
$ mkdir -p corpus/fuzz_sign
$ dd if=/dev/zero bs=1 count=6292 > corpus/fuzz_sign/seed0
$ for i in $(seq 1 9); do head -c 6292 </dev/urandom > corpus/fuzz_sign/seed$i; done
$ mkdir -p corpus/fuzz_verify
$ dd if=/dev/zero bs=1 count=6292 > corpus/fuzz_verify/seed0
$ for i in $(seq 0 9); do head -c 6292 </dev/urandom > corpus/fuzz_verify/seed$i; done
$ cargo fuzz run fuzz_sign -j 4 -- -max_total_time=1000
...
#205: cov: 2486 ft: 4394 corp: 10 exec/s: 0 oom/timeout/crash: 0/0/0 time: 965s job: 51 dft_time: 0
#209: cov: 2486 ft: 4394 corp: 10 exec/s: 0 oom/timeout/crash: 0/0/0 time: 965s job: 49 dft_time: 0
#215: cov: 2486 ft: 4394 corp: 10 exec/s: 0 oom/timeout/crash: 0/0/0 time: 980s job: 52 dft_time: 0
#219: cov: 2486 ft: 4394 corp: 10 exec/s: 0 oom/timeout/crash: 0/0/0 time: 1020s job: 54 dft_time: 0
INFO: fuzzed for 1020 seconds, wrapping up soon
INFO: exiting: 0 time: 1050s
$ cargo fuzz run fuzz_verify -j 4 -- -max_total_time=1000
...
#307: cov: 18818 ft: 12996 corp: 30 exec/s 0 oom/timeout/crash: 0/0/0 time: 915s job: 57 dft_time: 0
#314: cov: 18818 ft: 13023 corp: 32 exec/s 0 oom/timeout/crash: 0/0/0 time: 934s job: 58 dft_time: 0
#321: cov: 18818 ft: 13040 corp: 33 exec/s 0 oom/timeout/crash: 0/0/0 time: 945s job: 59 dft_time: 0
#328: cov: 18818 ft: 13063 corp: 34 exec/s 0 oom/timeout/crash: 0/0/0 time: 964s job: 60 dft_time: 0
#336: cov: 18818 ft: 13078 corp: 35 exec/s 0 oom/timeout/crash: 0/0/0 time: 998s job: 61 dft_time: 0
INFO: fuzzed for 1018 seconds, wrapping up soon
INFO: exiting: 0 time: 1031s
~~~
Coverage status is a work-in-progress (note that verify also exercises signing); see FIPS 204 code for example runs

View file

@ -0,0 +1,53 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use fips205::{
slh_dsa_sha2_128f, // Using sha2_128f as an example parameter set
traits::Signer,
Ph,
};
use rand_core::OsRng;
// Wrapper struct to help organize the fuzz input
#[derive(arbitrary::Arbitrary, Debug)]
struct FuzzInput {
message: Vec<u8>,
context: Vec<u8>,
hedged: bool,
use_hash: bool,
hash_function: u8, // We'll map this to Ph variants
}
fuzz_target!(|input: FuzzInput| {
// Generate a keypair first (using real RNG for this part)
if let Ok((_, sk)) = slh_dsa_sha2_128f::try_keygen() {
// Map the hash function input to actual Ph variants
let ph = match input.hash_function % 3 {
0 => Ph::SHA256,
1 => Ph::SHA512,
_ => Ph::SHAKE256,
};
// Test regular signing
let _ = sk.try_sign_with_rng(
&mut OsRng,
&input.message,
&input.context[..input.context.len() % 255],
input.hedged
);
// Test hash signing
if input.use_hash {
let _ = sk.try_hash_sign_with_rng(
&mut OsRng,
&input.message,
&input.context[..input.context.len() % 255],
&ph,
input.hedged
);
}
// Test public key derivation
let _pk = sk.get_public_key();
}
});

View file

@ -0,0 +1,50 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use fips205::{
slh_dsa_sha2_128f, // Using slh_dsa_sha2_128f as example, could test other parameter sets
traits::{SerDes, Signer, Verifier},
Ph,
};
fuzz_target!(|data: &[u8]| {
// Need at least some bytes for our test cases
if data.len() < 32 {
return;
}
// Generate a valid key pair first
if let Ok((pk, sk)) = slh_dsa_sha2_128f::try_keygen() {
// Split fuzz data into message and context
let split_point = data.len() % 255;
let message = &data[split_point..];
let context = &data[..split_point];
// Test 1: Regular verification with valid signature
if let Ok(valid_sig) = sk.try_sign(message, context, true) {
let _ = pk.verify(message, &valid_sig, context);
}
// Test 2: Hash verification with valid signature
if let Ok(valid_hash_sig) = sk.try_hash_sign(message, context, &Ph::SHA256, true) {
let _ = pk.hash_verify(message, &valid_hash_sig, context, &Ph::SHA256);
}
// Test 3: Try to deserialize and verify with potentially malformed public key
if let Ok(maybe_pk) = slh_dsa_sha2_128f::PublicKey::try_from_bytes(
&pk.clone().into_bytes() // Use valid key bytes but could use fuzzed data instead
) {
if let Ok(sig) = sk.try_sign(message, context, true) {
let _ = maybe_pk.verify(message, &sig, context);
}
}
// Test 4: Verify with modified message
if let Ok(sig) = sk.try_sign(message, context, true) {
let mut modified_message = message.to_vec();
if !modified_message.is_empty() {
modified_message[0] ^= 1; // Flip one bit
let _ = pk.verify(&modified_message, &sig, context);
}
}
}
});

View file

@ -402,6 +402,12 @@ macro_rules! functionality {
let sig = sk2.try_sign_with_rng(&mut rng, &message, b"context", true).unwrap(); let sig = sk2.try_sign_with_rng(&mut rng, &message, b"context", true).unwrap();
let result = pk2.verify(&message, &sig, b"context"); let result = pk2.verify(&message, &sig, b"context");
assert!(result, "Signature failed to verify");
let (pk3, sk3) = KG::keygen_with_seeds(&[0u8; N], &[1u8; N], &[2u8; N]);
let sig = sk3.try_sign_with_rng(&mut rng, &message, b"context", true).unwrap();
let result = pk3.verify(&message, &sig, b"context");
assert!(result, "Signature failed to verify"); assert!(result, "Signature failed to verify");
let result = pk2.verify(&message, &sig, b"some other context"); let result = pk2.verify(&message, &sig, b"some other context");
assert!(!result, "Signature should not have verified"); assert!(!result, "Signature should not have verified");
@ -420,9 +426,10 @@ macro_rules! functionality {
} }
/// Functionality for the **SLH-DSA-SHA2-128s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-128s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-128s parameter set is claimed to be in security strength category 1. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-128s parameter set is claimed to be in security strength category 1.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_128s::PublicKey`] and [`slh_dsa_sha2_128s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_128s::PublicKey`] and [`slh_dsa_sha2_128s::PrivateKey`] structs. The resulting
@ -443,7 +450,8 @@ pub mod slh_dsa_sha2_128s {
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 16; /// Seed size
pub const N: usize = 16;
const H: usize = 63; const H: usize = 63;
const D: usize = 7; const D: usize = 7;
const HP: usize = 9; const HP: usize = 9;
@ -468,9 +476,10 @@ pub mod slh_dsa_sha2_128s {
} }
/// Functionality for the **SLH-DSA-SHAKE-128s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-128s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE-128s parameter set is claimed to be in security strength category 1. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE-128s parameter set is claimed to be in security strength category 1.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_128s::PublicKey`] and [`slh_dsa_shake_128s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_128s::PublicKey`] and [`slh_dsa_shake_128s::PrivateKey`] structs. The resulting
@ -491,7 +500,8 @@ pub mod slh_dsa_shake_128s {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 16; /// Seed size
pub const N: usize = 16;
const H: usize = 63; const H: usize = 63;
const D: usize = 7; const D: usize = 7;
const HP: usize = 9; const HP: usize = 9;
@ -516,9 +526,10 @@ pub mod slh_dsa_shake_128s {
} }
/// Functionality for the **SLH-DSA-SHA2-128f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-128f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-128f parameter set is claimed to be in security strength category 1. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-128f parameter set is claimed to be in security strength category 1.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_128f::PublicKey`] and [`slh_dsa_sha2_128f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_128f::PublicKey`] and [`slh_dsa_sha2_128f::PrivateKey`] structs. The resulting
@ -539,7 +550,8 @@ pub mod slh_dsa_sha2_128f {
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 16; /// Seed size
pub const N: usize = 16;
const H: usize = 66; const H: usize = 66;
const D: usize = 22; const D: usize = 22;
const HP: usize = 3; const HP: usize = 3;
@ -564,9 +576,10 @@ pub mod slh_dsa_sha2_128f {
} }
/// Functionality for the **SLH-DSA-SHAKE-128f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-128f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE-128f parameter set is claimed to be in security strength category 1. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE-128f parameter set is claimed to be in security strength category 1.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_128f::PublicKey`] and [`slh_dsa_shake_128f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_128f::PublicKey`] and [`slh_dsa_shake_128f::PrivateKey`] structs. The resulting
@ -587,7 +600,8 @@ pub mod slh_dsa_shake_128f {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 16; /// Seed size
pub const N: usize = 16;
const H: usize = 66; const H: usize = 66;
const D: usize = 22; const D: usize = 22;
const HP: usize = 3; const HP: usize = 3;
@ -612,9 +626,10 @@ pub mod slh_dsa_shake_128f {
} }
/// Functionality for the **SLH-DSA-SHA2-192s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-192s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-192s parameter set is claimed to be in security strength category 3. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-192s parameter set is claimed to be in security strength category 3.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_192s::PublicKey`] and [`slh_dsa_sha2_192s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_192s::PublicKey`] and [`slh_dsa_sha2_192s::PrivateKey`] structs. The resulting
@ -635,7 +650,8 @@ pub mod slh_dsa_sha2_192s {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 24; /// Seed size
pub const N: usize = 24;
const H: usize = 63; const H: usize = 63;
const D: usize = 7; const D: usize = 7;
const HP: usize = 9; const HP: usize = 9;
@ -660,9 +676,10 @@ pub mod slh_dsa_sha2_192s {
} }
/// Functionality for the **SLH-DSA-SHAKE-192s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-192s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE-192s parameter set is claimed to be in security strength category 3. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE-192s parameter set is claimed to be in security strength category 3.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_192s::PublicKey`] and [`slh_dsa_shake_192s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_192s::PublicKey`] and [`slh_dsa_shake_192s::PrivateKey`] structs. The resulting
@ -683,7 +700,8 @@ pub mod slh_dsa_shake_192s {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 24; /// Seed size
pub const N: usize = 24;
const H: usize = 63; const H: usize = 63;
const D: usize = 7; const D: usize = 7;
const HP: usize = 9; const HP: usize = 9;
@ -708,9 +726,10 @@ pub mod slh_dsa_shake_192s {
} }
/// Functionality for the **SLH-DSA-SHA2-192f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-192f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-192f parameter set is claimed to be in security strength category 3. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-192f parameter set is claimed to be in security strength category 3.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_192f::PublicKey`] and [`slh_dsa_sha2_192f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_192f::PublicKey`] and [`slh_dsa_sha2_192f::PrivateKey`] structs. The resulting
@ -731,7 +750,8 @@ pub mod slh_dsa_sha2_192f {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 24; /// Seed size
pub const N: usize = 24;
const H: usize = 66; const H: usize = 66;
const D: usize = 22; const D: usize = 22;
const HP: usize = 3; const HP: usize = 3;
@ -756,9 +776,10 @@ pub mod slh_dsa_sha2_192f {
} }
/// Functionality for the **SLH-DSA-SHAKE-192f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-192f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE-192f parameter set is claimed to be in security strength category 3. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE-192f parameter set is claimed to be in security strength category 3.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_192f::PublicKey`] and [`slh_dsa_shake_192f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_192f::PublicKey`] and [`slh_dsa_shake_192f::PrivateKey`] structs. The resulting
@ -779,7 +800,8 @@ pub mod slh_dsa_shake_192f {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 24; /// Seed size
pub const N: usize = 24;
const H: usize = 66; const H: usize = 66;
const D: usize = 22; const D: usize = 22;
const HP: usize = 3; const HP: usize = 3;
@ -804,9 +826,10 @@ pub mod slh_dsa_shake_192f {
} }
/// Functionality for the **SLH-DSA-SHA2-256s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-256s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-256s parameter set is claimed to be in security strength category 5. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-256s parameter set is claimed to be in security strength category 5.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_256s::PublicKey`] and [`slh_dsa_sha2_256s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_256s::PublicKey`] and [`slh_dsa_sha2_256s::PrivateKey`] structs. The resulting
@ -827,7 +850,8 @@ pub mod slh_dsa_sha2_256s {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 32; /// Seed size
pub const N: usize = 32;
const H: usize = 64; const H: usize = 64;
const D: usize = 8; const D: usize = 8;
const HP: usize = 8; const HP: usize = 8;
@ -852,9 +876,10 @@ pub mod slh_dsa_sha2_256s {
} }
/// Functionality for the **SLH-DSA-SHAKE-256s** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-256s** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE_256s parameter set is claimed to be in security strength category 5. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE_256s parameter set is claimed to be in security strength category 5.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256s::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_256s::PublicKey`] and [`slh_dsa_shake_256s::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_256s::PublicKey`] and [`slh_dsa_shake_256s::PrivateKey`] structs. The resulting
@ -875,7 +900,8 @@ pub mod slh_dsa_shake_256s {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 32; /// Seed size
pub const N: usize = 32;
const H: usize = 64; const H: usize = 64;
const D: usize = 8; const D: usize = 8;
const HP: usize = 8; const HP: usize = 8;
@ -900,9 +926,10 @@ pub mod slh_dsa_shake_256s {
} }
/// Functionality for the **SLH-DSA-SHA2-256f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHA2-256f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHA2-256f parameter set is claimed to be in security strength category 5. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHA2-256f parameter set is claimed to be in security strength category 5.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_256f::PublicKey`] and [`slh_dsa_sha2_256f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_sha2_256f::PublicKey`] and [`slh_dsa_sha2_256f::PrivateKey`] structs. The resulting
@ -923,7 +950,8 @@ pub mod slh_dsa_sha2_256f {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 32; /// Seed size
pub const N: usize = 32;
const H: usize = 68; const H: usize = 68;
const D: usize = 17; const D: usize = 17;
const HP: usize = 4; const HP: usize = 4;
@ -948,9 +976,10 @@ pub mod slh_dsa_sha2_256f {
} }
/// Functionality for the **SLH-DSA-SHAKE-256f** security parameter set per FIPS 205 section 11. This includes specific /// Functionality for the **SLH-DSA-SHAKE-256f** security parameter set per FIPS 205 section 11.
/// sizes for the public key, secret key, and signature along with a number of internal constants. The ///
/// SLH-DSA-SHAKE-256f parameter set is claimed to be in security strength category 5. /// This includes specific sizes for the public key, secret key, and signature along with a number of internal
/// constants. The SLH-DSA-SHAKE-256f parameter set is claimed to be in security strength category 5.
/// ///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256f::try_keygen`] function below /// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_256f::PublicKey`] and [`slh_dsa_shake_256f::PrivateKey`] structs. The resulting /// to generate both [`slh_dsa_shake_256f::PublicKey`] and [`slh_dsa_shake_256f::PrivateKey`] structs. The resulting
@ -971,7 +1000,8 @@ pub mod slh_dsa_shake_256f {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l}; use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
use crate::hashers::Hashers; use crate::hashers::Hashers;
const N: usize = 32; /// Seed size
pub const N: usize = 32;
const H: usize = 68; const H: usize = 68;
const D: usize = 17; const D: usize = 17;
const HP: usize = 4; const HP: usize = 4;

View file

@ -1,4 +1,6 @@
use rand_core::CryptoRngCore; use rand_core::CryptoRngCore;
use rand_core::RngCore;
use rand_core::CryptoRng;
use crate::Ph; use crate::Ph;
#[cfg(feature = "default-rng")] #[cfg(feature = "default-rng")]
@ -99,8 +101,75 @@ pub trait KeyGen {
fn try_keygen_with_rng( fn try_keygen_with_rng(
rng: &mut impl CryptoRngCore, rng: &mut impl CryptoRngCore,
) -> Result<(Self::PublicKey, Self::PrivateKey), &'static str>; ) -> Result<(Self::PublicKey, Self::PrivateKey), &'static str>;
/// Generates a public and private key pair specific to this security parameter set.
/// This function utilizes **three provided seeds** rather than a random number
/// generator in order to deterministically generate keys. This function operates
/// in constant-time relative to secret data.
/// # Errors
/// Returns an error when the random number generator fails.
/// # Examples
/// ```rust
/// use fips205::slh_dsa_shake_128s; // Could use any of the twelve security parameter sets.
/// use fips205::traits::{KeyGen, SerDes, Signer, Verifier};
/// # use std::error::Error;
/// # use rand_core::OsRng;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
///
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
/// let mut rng = OsRng;
///
/// // Generate both public and secret keys. This only fails when the provided rng fails.
/// let (pk1, sk) = slh_dsa_shake_128s::KG::keygen_with_seeds(&[0u8; slh_dsa_shake_128s::N],
/// &[1u8; slh_dsa_shake_128s::N], &[1u8; slh_dsa_shake_128s::N]);
/// // Use the secret key to generate a signature. The second parameter is the
/// // context string (often just an empty &[]), and the last parameter selects
/// // the preferred hedged variant. This only fails when the OS rng fails.
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?;
///
///
/// // Serialize the public key, and send with message and signature bytes. These
/// // statements model sending byte arrays over the wire.
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
/// let (pk_recv, msg_recv, sig_recv) = (pk_send, msg_send, sig_send);
///
///
/// // Deserialize the public key. This only fails on a malformed key.
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// // Use the public key to verify the msg signature
/// let v = pk2.verify(&msg_recv, &sig_recv, b"context");
/// assert!(v);
/// # Ok(())
/// # }
/// ```
fn keygen_with_seeds<const N: usize>(
sk_seed: &[u8; N], sk_prf: &[u8; N], pk_seed: &[u8; N]
) -> (Self::PublicKey, Self::PrivateKey) {
Self::try_keygen_with_rng(&mut DummyRng {data: [*sk_seed, *sk_prf, *pk_seed], i: 0 }).expect("rng will not fail")
}
} }
// This is for the deterministic keygen functions; will be refactored more nicely
struct DummyRng<const N: usize> { data: [[u8; N]; 3], i: usize }
impl<const N: usize> RngCore for DummyRng<N> {
fn next_u32(&mut self) -> u32 { unimplemented!() }
fn next_u64(&mut self) -> u64 { unimplemented!() }
fn fill_bytes(&mut self, _out: &mut [u8]) { unimplemented!() }
fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> {
out.copy_from_slice(&self.data[self.i]);
self.i += 1;
Ok(())
}
}
impl<const N: usize> CryptoRng for DummyRng<N> {}
/// The Signer trait is implemented for the `PrivateKey` struct on each of the security parameter sets /// The Signer trait is implemented for the `PrivateKey` struct on each of the security parameter sets
pub trait Signer { pub trait Signer {