mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-03 19:53:49 +00:00
v0.4.0 RC1
This commit is contained in:
parent
5f8a96c02b
commit
e77284a10d
7 changed files with 53 additions and 21 deletions
|
|
@ -12,8 +12,8 @@ dudect-bencher = "0.6"
|
||||||
rand_core = { version = "0.6.4", default-features = false }
|
rand_core = { version = "0.6.4", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
[profile.bench]
|
[profile.release]
|
||||||
debug = true
|
debug = false
|
||||||
debug-assertions = false
|
debug-assertions = false
|
||||||
incremental = false
|
incremental = false
|
||||||
lto = true
|
lto = true
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,22 @@ Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017 Rust 1.81
|
||||||
|
|
||||||
$ cd dudect # this directory
|
$ cd dudect # this directory
|
||||||
$ cargo clean
|
$ cargo clean
|
||||||
$ time RUSTFLAGS="-C target-cpu=native" cargo run --release
|
$ time RUSTFLAGS="-C target-cpu=native" cargo run --release # A ~11 hour run
|
||||||
|
|
||||||
...
|
...
|
||||||
|
Compiling fips205 v0.4.0 (/home/eric/work/fips205)
|
||||||
Compiling fips205-dudect v0.4.0 (/home/eric/work/fips205/dudect)
|
Compiling fips205-dudect v0.4.0 (/home/eric/work/fips205/dudect)
|
||||||
Finished `release` profile [optimized] target(s) in 7.36s
|
Finished `release` profile [optimized] target(s) in 12.04s
|
||||||
Running `target/release/fips205-dudect`
|
Running `target/release/fips205-dudect`
|
||||||
|
|
||||||
running 1 bench
|
running 1 bench
|
||||||
bench keygen_and_sign seeded with 0x89b5d1d7e0207f97
|
bench keygen_and_sign seeded with 0x54522172d8fff6c0
|
||||||
bench keygen_and_sign ... : n == +0.001M, max t = -1.03786, max tau = -0.03383, (5/tau)^2 = 21840
|
bench keygen_and_sign ... : n == +0.007M, max t = +3.04638, max tau = +0.03693, (5/tau)^2 = 18331
|
||||||
|
|
||||||
dudect benches complete
|
dudect benches complete
|
||||||
|
|
||||||
|
|
||||||
real 63m43.206s
|
real 660m35.132s
|
||||||
user 64m12.095s
|
user 660m47.614s
|
||||||
sys 0m2.511s
|
sys 0m2.662s
|
||||||
~~~
|
~~~
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ pub struct AlignedBytes<const BYTE_LEN: usize>(pub(crate) [u8; BYTE_LEN]);
|
||||||
|
|
||||||
|
|
||||||
fn keygen_and_sign(runner: &mut CtRunner, mut _rng: &mut BenchRng) {
|
fn keygen_and_sign(runner: &mut CtRunner, mut _rng: &mut BenchRng) {
|
||||||
const ITERATIONS_OUTER: usize = 1_000;
|
const ITERATIONS_OUTER: usize = 20_000;
|
||||||
const ITERATIONS_INNER: usize = 4;
|
const ITERATIONS_INNER: usize = 2;
|
||||||
|
|
||||||
let message = AlignedBytes::<8>([0u8, 1, 2, 3, 4, 5, 6, 7]);
|
let message = AlignedBytes::<8>([0u8, 1, 2, 3, 4, 5, 6, 7]);
|
||||||
let z_left = AlignedBytes::<16>([0xAAu8; 16]);
|
let z_left = AlignedBytes::<16>([0xAAu8; 16]);
|
||||||
|
|
|
||||||
|
|
@ -157,5 +157,5 @@ pub(crate) fn ht_verify<
|
||||||
// 15: else
|
// 15: else
|
||||||
// 16: return false
|
// 16: return false
|
||||||
// 17: end if
|
// 17: end if
|
||||||
node == *pk_root // TODO: CT equal (double-check: is this in signing path??)
|
node == *pk_root // Public data, thus no CT eq required
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/lib.rs
12
src/lib.rs
|
|
@ -48,7 +48,7 @@
|
||||||
|
|
||||||
// TODO: Roadmap
|
// TODO: Roadmap
|
||||||
// 1. Additional (external) top-level test vectors, particularly for hash variants (!!)
|
// 1. Additional (external) top-level test vectors, particularly for hash variants (!!)
|
||||||
// 2. Implement fuzz harness, embedded target, code provenance functionality
|
// 2. Implement fuzz harness, embedded target, revise WASM test
|
||||||
// 3. Experiment with struct alignment for performance uplift? (and fixed size 'slices')
|
// 3. Experiment with struct alignment for performance uplift? (and fixed size 'slices')
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -206,6 +206,7 @@ macro_rules! functionality {
|
||||||
|
|
||||||
impl Signer for PrivateKey {
|
impl Signer for PrivateKey {
|
||||||
type Signature = [u8; SIG_LEN];
|
type Signature = [u8; SIG_LEN];
|
||||||
|
type PublicKey = PublicKey;
|
||||||
|
|
||||||
// Documented in traits.rs
|
// Documented in traits.rs
|
||||||
fn try_sign_with_rng(
|
fn try_sign_with_rng(
|
||||||
|
|
@ -244,6 +245,11 @@ macro_rules! functionality {
|
||||||
sig.map(|s| s.serialize())
|
sig.map(|s| s.serialize())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Documented in traits.rs
|
||||||
|
fn get_public_key(&self) -> Self::PublicKey {
|
||||||
|
PublicKey(SlhPublicKey{pk_seed: self.0.pk_seed, pk_root: self.0.pk_root})
|
||||||
|
}
|
||||||
|
|
||||||
// Documented in traits.rs
|
// Documented in traits.rs
|
||||||
fn _test_only_raw_sign(
|
fn _test_only_raw_sign(
|
||||||
&self, rng: &mut impl CryptoRngCore, m: &[u8], hedged: bool,
|
&self, rng: &mut impl CryptoRngCore, m: &[u8], hedged: bool,
|
||||||
|
|
@ -338,8 +344,6 @@ macro_rules! functionality {
|
||||||
|
|
||||||
// Documented in traits.rs
|
// Documented in traits.rs
|
||||||
fn try_from_bytes(bytes: &Self::ByteArray) -> Result<Self, &'static str> {
|
fn try_from_bytes(bytes: &Self::ByteArray) -> Result<Self, &'static str> {
|
||||||
// Result: opportunity for validation
|
|
||||||
//let mut pk = SlhPublicKey::default();
|
|
||||||
let mut pk = SlhPublicKey { pk_seed: [0u8; N], pk_root: [0u8; N] };
|
let mut pk = SlhPublicKey { pk_seed: [0u8; N], pk_root: [0u8; N] };
|
||||||
pk.pk_seed.copy_from_slice(&bytes[..(PK_LEN / 2)]);
|
pk.pk_seed.copy_from_slice(&bytes[..(PK_LEN / 2)]);
|
||||||
pk.pk_root.copy_from_slice(&bytes[(PK_LEN / 2)..]);
|
pk.pk_root.copy_from_slice(&bytes[(PK_LEN / 2)..]);
|
||||||
|
|
@ -373,6 +377,8 @@ macro_rules! functionality {
|
||||||
sk.sk_prf.copy_from_slice(&bytes[(SK_LEN / 4)..(SK_LEN / 2)]);
|
sk.sk_prf.copy_from_slice(&bytes[(SK_LEN / 4)..(SK_LEN / 2)]);
|
||||||
sk.pk_seed.copy_from_slice(&bytes[(SK_LEN / 2)..(3 * SK_LEN / 4)]);
|
sk.pk_seed.copy_from_slice(&bytes[(SK_LEN / 2)..(3 * SK_LEN / 4)]);
|
||||||
sk.pk_root.copy_from_slice(&bytes[(3 * SK_LEN / 4)..]);
|
sk.pk_root.copy_from_slice(&bytes[(3 * SK_LEN / 4)..]);
|
||||||
|
let (sk_test, _) = crate::slh::slh_keygen_internal::<D, H, HP, K, LEN, M, N>(&HASHERS, sk.sk_seed, sk.sk_prf, sk.pk_seed);
|
||||||
|
if sk_test.pk_root != sk.pk_root { return Err("Corrupted key")}
|
||||||
Ok(PrivateKey(sk))
|
Ok(PrivateKey(sk))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,6 @@ pub(crate) fn slh_sign_internal<
|
||||||
///
|
///
|
||||||
/// Input: Message `M`, signature `SIG`, context string `ctx`, public key `PK = (PK.seed, PK.root)`. <br>
|
/// Input: Message `M`, signature `SIG`, context string `ctx`, public key `PK = (PK.seed, PK.root)`. <br>
|
||||||
/// Output: Boolean.
|
/// Output: Boolean.
|
||||||
#[allow(clippy::cast_possible_truncation)] // TODO: temporary
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub(crate) fn slh_verify<
|
pub(crate) fn slh_verify<
|
||||||
const A: usize,
|
const A: usize,
|
||||||
|
|
@ -273,7 +272,6 @@ pub(crate) fn slh_verify<
|
||||||
///
|
///
|
||||||
/// Input: Message `M`, signature `SIG`, public key `PK = (PK.seed, PK.root)`. <br>
|
/// Input: Message `M`, signature `SIG`, public key `PK = (PK.seed, PK.root)`. <br>
|
||||||
/// Output: Boolean.
|
/// Output: Boolean.
|
||||||
#[allow(clippy::cast_possible_truncation)] // TODO: temporary
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub(crate) fn slh_verify_internal<
|
pub(crate) fn slh_verify_internal<
|
||||||
const A: usize,
|
const A: usize,
|
||||||
|
|
@ -293,7 +291,7 @@ pub(crate) fn slh_verify_internal<
|
||||||
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
|
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
|
||||||
// 2: return false
|
// 2: return false
|
||||||
// 3: end if
|
// 3: end if
|
||||||
// The above size is performed in the wrapper/adapter deserialize function
|
// The above size check is performed in the wrapper/adapter deserialize function
|
||||||
|
|
||||||
// 4: ADRS ← toByte(0, 32)
|
// 4: ADRS ← toByte(0, 32)
|
||||||
let mut adrs = Adrs::default();
|
let mut adrs = Adrs::default();
|
||||||
|
|
@ -337,7 +335,8 @@ pub(crate) fn slh_verify_internal<
|
||||||
adrs.set_type_and_clear(FORS_TREE);
|
adrs.set_type_and_clear(FORS_TREE);
|
||||||
|
|
||||||
// 16: ADRS.setKeyPairAddress(idx_leaf)
|
// 16: ADRS.setKeyPairAddress(idx_leaf)
|
||||||
adrs.set_key_pair_address(idx_leaf as u32);
|
let Ok(idx_leaf_u32) = u32::try_from(idx_leaf) else { return false }; // should never fail
|
||||||
|
adrs.set_key_pair_address(idx_leaf_u32);
|
||||||
|
|
||||||
// 17: PK_FORS ← fors_pkFromSig(SIG_FORS, md, PK.seed, ADRS)
|
// 17: PK_FORS ← fors_pkFromSig(SIG_FORS, md, PK.seed, ADRS)
|
||||||
let pk_fors =
|
let pk_fors =
|
||||||
|
|
@ -350,7 +349,7 @@ pub(crate) fn slh_verify_internal<
|
||||||
sig_ht,
|
sig_ht,
|
||||||
&pk.pk_seed,
|
&pk.pk_seed,
|
||||||
idx_tree,
|
idx_tree,
|
||||||
idx_leaf as u32,
|
idx_leaf_u32,
|
||||||
&pk.pk_root,
|
&pk.pk_root,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,8 @@ pub trait KeyGen {
|
||||||
pub trait Signer {
|
pub trait Signer {
|
||||||
/// The signature is specific to the chosen security parameter set, e.g., `slh_dsa_shake_128s`, `slh_dsa_sha2_128s` etc
|
/// The signature is specific to the chosen security parameter set, e.g., `slh_dsa_shake_128s`, `slh_dsa_sha2_128s` etc
|
||||||
type Signature;
|
type Signature;
|
||||||
|
/// The public key that corresponds to the private/secret key
|
||||||
|
type PublicKey;
|
||||||
|
|
||||||
/// Attempt to sign the given message, returning a digital signature on success, or an error if
|
/// Attempt to sign the given message, returning a digital signature on success, or an error if
|
||||||
/// something went wrong. This function utilizes the **OS default** random number generator.
|
/// something went wrong. This function utilizes the **OS default** random number generator.
|
||||||
|
|
@ -296,6 +297,31 @@ pub trait Signer {
|
||||||
) -> Result<Self::Signature, &'static str>;
|
) -> Result<Self::Signature, &'static str>;
|
||||||
|
|
||||||
|
|
||||||
|
/// Retrieves the public key associated with this private/secret key
|
||||||
|
/// # Examples
|
||||||
|
/// ```rust
|
||||||
|
/// use fips205::slh_dsa_shake_128s; // Could use any of the twelve security parameter sets.
|
||||||
|
/// use fips205::traits::{SerDes, Signer, Verifier};
|
||||||
|
/// # use std::error::Error;
|
||||||
|
/// # use rand_core::OsRng;
|
||||||
|
/// # use fips205::Ph;
|
||||||
|
/// # 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, but only hang onto the secret key.
|
||||||
|
/// let (_, sk) = slh_dsa_shake_128s::try_keygen()?;
|
||||||
|
///
|
||||||
|
/// // The public key can be derived from the secret key
|
||||||
|
/// let pk = sk.get_public_key();
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn get_public_key(&self) -> Self::PublicKey;
|
||||||
|
|
||||||
|
|
||||||
/// As of October 4 2024, the available NIST test vectors are applied to the **internal** functions
|
/// As of October 4 2024, the available NIST test vectors are applied to the **internal** functions
|
||||||
/// rather than the external API. This function should not be used outside of this scenario.
|
/// rather than the external API. This function should not be used outside of this scenario.
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue