This commit is contained in:
eschorn1 2024-03-08 18:25:57 -06:00
parent db92cdfabd
commit aaf3b57066
8 changed files with 28 additions and 29 deletions

View file

@ -4,14 +4,18 @@ version = "0.1.2"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "FIPS 205 (draft): Stateless Hash-Based Digital Signature Standard"
authors = ["Eric Schorn <eschorn@integritychain.com>"]
documentation = "https://docs.rs/fips205"
categories = ["cryptography", "no-std"]
keywords = ["FIPS", "FIPS205", "hash", "signature"]
repository = "https://github.com/integritychain/fips205"
rust-version = "1.70"
[dependencies]
zeroize = { version = "1.7.0", features = ["zeroize_derive"] }
zeroize = { version = "1.6.0", default-features = false, features = ["zeroize_derive"] } # For MSRV 1.70
rand_core = { version = "0.6.4", default-features = false }
sha3 = { version = "0.10.8", default-features = false }
sha3 = { version = "0.10.2", default-features = false } # For MSRV 1.70
sha2 = { version = "0.10.8", default-features = false }
generic-array = { version = "1.0.0", features=["const-default", "zeroize"] }

View file

@ -53,8 +53,8 @@ The Rust [Documentation][docs-link] lives under each **Module** corresponding to
* This crate is fully functional and corresponds to the first initial public draft of FIPS 205.
* Constant-time assurances target the source-code level only, and are a work in progress.
* Note that FIPS 205 places specific requirements on randomness per section 3.1, hence the exposed `RNG`.
* Requires Rust **1.70** or higher due to `div_ceil()`. The minimum supported Rust version may be changed
in the future, but it will be done with a minor version bump.
* Requires Rust **1.70** or higher. The minimum supported Rust version may be changed in the future,
but it will be done with a minor version bump.
* All on-by-default features of this library are covered by SemVer.
* This software is experimental and still under active development -- USE AT YOUR OWN RISK!

View file

@ -122,7 +122,6 @@ pub(crate) fn fors_sign<
helpers::base_2b(md, A::to_u32(), K::to_u32(), &mut indices);
// 3: for i from 0 to k 1 do ▷ Compute signature elements
#[allow(clippy::cast_possible_truncation)]
for i in 0..K::to_u32() {
//
// 4: SIG_FORS ← SIG_FORS ∥ fors_SKgen(SK.seed, PK.seed, ADRS, i · 2^a + indices[i])
@ -188,7 +187,6 @@ pub(crate) fn fors_pk_from_sig<
// 2: for i from 0 to k 1 do
let mut root: GenericArray<GenericArray<u8, N>, K> = GenericArray::default();
#[allow(clippy::cast_possible_truncation)] // Step 5
for i in 0..K::to_u32() {
//
// 3: sk ← SIG_FORS.getSK(i) ▷ SIG_FORS [i · (a + 1) · n : (i · (a + 1) + 1) · n]

View file

@ -45,7 +45,7 @@ pub(crate) mod shake {
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
) -> GenericArray<u8, M> {
let mut digest: GenericArray<u8, M> = GenericArray::default();
shake256(&[&r, &pk_seed, &pk_root, m], &mut digest);
shake256(&[r, pk_seed, pk_root, m], &mut digest);
digest
}
@ -122,13 +122,13 @@ pub(crate) mod sha2_cat_1 {
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
) -> GenericArray<u8, M> {
let mut digest1 = [0u8; 32];
sha2_256(&[&r, &pk_seed, &pk_root, m], &mut digest1);
sha2_256(&[r, pk_seed, pk_root, m], &mut digest1);
let mut result: GenericArray<u8, M> = GenericArray::default();
let mut start = 0;
let mut counter = 0u32;
while start < M::to_usize() {
let mut tmp = [0u8; 32];
sha2_256(&[&r, &pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
sha2_256(&[r, pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
let len = min(M::to_usize() - start, 32);
result[start..start + len].copy_from_slice(&tmp[0..len]);
start += 32;
@ -276,13 +276,13 @@ pub(crate) mod sha2_cat_3_5 {
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
) -> GenericArray<u8, M> {
let mut digest1 = [0u8; 64];
sha2_512(&[&r, &pk_seed, &pk_root, m], &mut digest1);
sha2_512(&[r, pk_seed, pk_root, m], &mut digest1);
let mut result: GenericArray<u8, M> = GenericArray::default();
let mut start = 0;
let mut counter = 0u32;
while start < M::to_usize() {
let mut tmp = [0u8; 64];
sha2_512(&[&r, &pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
sha2_512(&[r, pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
let len = min(M::to_usize() - start, 64);
result[start..start + len].copy_from_slice(&tmp[0..len]);
start += 64;

View file

@ -201,7 +201,6 @@ impl Adrs {
pub(crate) fn set_key_pair_address(&mut self, kp_addr: u32) { self.f5 = kp_addr.to_be_bytes(); }
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn set_chain_address(&mut self, i: u32) { self.f6 = i.to_be_bytes(); }
pub(crate) fn set_type_and_clear(&mut self, type_t: u32) {
@ -211,10 +210,10 @@ impl Adrs {
self.f7 = 0u32.to_be_bytes();
}
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn set_tree_address(&mut self, t: u64) {
self.f2 = ((t >> 32) as u32).to_be_bytes();
self.f3 = (t as u32).to_be_bytes();
let bytes = t.to_be_bytes();
self.f2.copy_from_slice(&bytes[..4]); // = ((t >> 32) as u32).to_be_bytes();
self.f3.copy_from_slice(&bytes[4..]); // = (t as u32).to_be_bytes();
}
pub(crate) fn set_hash_address(&mut self, addr: u32) { self.f7 = addr.to_be_bytes() }

View file

@ -125,13 +125,13 @@ pub(crate) fn slh_sign_with_rng<
// 14:
// 15: idx_tree ← toInt(tmp_idx_tree, ceil((h-h/d)/8)) mod 2^{hh/d}
let idx_tree =
helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) / 8)
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
let idx_tree = helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) / 8)
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
// 16: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
let idx_leaf = helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
let idx_leaf =
helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
// 17:
// 18: ADRS.setTreeAddress(idx_tree)
@ -223,13 +223,13 @@ pub(crate) fn slh_verify<
// 13:
// 14: idx_tree ← toInt(tmp_idx_tree, ceil((h - h/d)/8)) mod 2^{hh/d}
let idx_tree =
helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) /8)
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
let idx_tree = helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) / 8)
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
// 15: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
let idx_leaf = helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
let idx_leaf =
helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
// 16:
// 17: ADRS.setTreeAddress(idx_tree) ▷ Compute FORS public key

View file

@ -60,7 +60,7 @@ pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLe
///
/// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
/// Output: WOTS+ public key `pk`.
#[allow(clippy::similar_names)]
#[allow(clippy::similar_names)] // pk_seed and sk_seed
pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
hashers: &Hashers<K, LEN, M, N>, sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs,
) -> Result<WotsPk<N>, &'static str> {
@ -117,7 +117,7 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
///
/// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
/// Output: WOTS+ signature sig.
#[allow(clippy::similar_names)]
#[allow(clippy::similar_names)] // pk_seed and sk_seed
pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs,
) -> WotsSig<LEN, N> {
@ -165,7 +165,6 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
sk_addrs.set_key_pair_address(adrs.get_key_pair_address());
// 15: for i from 0 to len 1 do
//#[allow(clippy::cast_possible_truncation)] // step 19
for (item, i) in msg.iter().zip(0u32..) {
//
// 16: skADRS.setChainAddress(i)

View file

@ -177,7 +177,6 @@ pub(crate) fn xmss_pk_from_sig<
adrs.set_tree_height(k + 1);
// 11: if idx/2^k is even then
#[allow(clippy::if_not_else)] // Follows the algorithm as written
let node_1 = if ((idx >> k) & 1) == 0 {
//
// 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2)