mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-03 19:53:49 +00:00
fuzz up
This commit is contained in:
parent
e77284a10d
commit
6f0f48eaee
8 changed files with 351 additions and 50 deletions
|
|
@ -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/),
|
||||
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)
|
||||
|
||||
- Internal improvements, removed dependency on generic-array, MSRV at 1.70
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4"] }
|
||||
workspace = { members = ['ffi'], exclude = ["dudect", "ct_cm4", "fuzz"] }
|
||||
|
||||
[package]
|
||||
name = "fips205"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "FIPS 205: Stateless Hash-Based Digital Signature Standard"
|
||||
|
|
|
|||
48
fuzz/Cargo.toml
Normal file
48
fuzz/Cargo.toml
Normal 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
42
fuzz/README.md
Normal 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
|
||||
53
fuzz/fuzz_targets/fuzz_sign.rs
Normal file
53
fuzz/fuzz_targets/fuzz_sign.rs
Normal 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();
|
||||
}
|
||||
});
|
||||
|
||||
50
fuzz/fuzz_targets/fuzz_verify.rs
Normal file
50
fuzz/fuzz_targets/fuzz_verify.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
126
src/lib.rs
126
src/lib.rs
|
|
@ -402,6 +402,12 @@ macro_rules! functionality {
|
|||
|
||||
let sig = sk2.try_sign_with_rng(&mut rng, &message, b"context", true).unwrap();
|
||||
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");
|
||||
let result = pk2.verify(&message, &sig, b"some other context");
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-128s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 16;
|
||||
/// Seed size
|
||||
pub const N: usize = 16;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-128s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 16;
|
||||
/// Seed size
|
||||
pub const N: usize = 16;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-128f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 16;
|
||||
/// Seed size
|
||||
pub const N: usize = 16;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-128f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 16;
|
||||
/// Seed size
|
||||
pub const N: usize = 16;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-192s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 24;
|
||||
/// Seed size
|
||||
pub const N: usize = 24;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-192s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 24;
|
||||
/// Seed size
|
||||
pub const N: usize = 24;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-192f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 24;
|
||||
/// Seed size
|
||||
pub const N: usize = 24;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-192f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 24;
|
||||
/// Seed size
|
||||
pub const N: usize = 24;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-256s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 32;
|
||||
/// Seed size
|
||||
pub const N: usize = 32;
|
||||
const H: usize = 64;
|
||||
const D: 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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-256s** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 32;
|
||||
/// Seed size
|
||||
pub const N: usize = 32;
|
||||
const H: usize = 64;
|
||||
const D: 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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHA2-256f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 32;
|
||||
/// Seed size
|
||||
pub const N: usize = 32;
|
||||
const H: usize = 68;
|
||||
const D: usize = 17;
|
||||
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
|
||||
/// 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.
|
||||
/// Functionality for the **SLH-DSA-SHAKE-256f** security parameter set per FIPS 205 section 11.
|
||||
///
|
||||
/// 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
|
||||
/// 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::Hashers;
|
||||
|
||||
const N: usize = 32;
|
||||
/// Seed size
|
||||
pub const N: usize = 32;
|
||||
const H: usize = 68;
|
||||
const D: usize = 17;
|
||||
const HP: usize = 4;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use rand_core::CryptoRngCore;
|
||||
use rand_core::RngCore;
|
||||
use rand_core::CryptoRng;
|
||||
|
||||
use crate::Ph;
|
||||
#[cfg(feature = "default-rng")]
|
||||
|
|
@ -99,8 +101,75 @@ pub trait KeyGen {
|
|||
fn try_keygen_with_rng(
|
||||
rng: &mut impl CryptoRngCore,
|
||||
) -> 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
|
||||
pub trait Signer {
|
||||
|
|
|
|||
Loading…
Reference in a new issue