This commit is contained in:
eschorn1 2024-02-07 15:31:17 -06:00
parent 7bb838973b
commit a6ff2130de
4 changed files with 45 additions and 42 deletions

View file

@ -10,7 +10,7 @@ use rand_core::CryptoRngCore;
/// Algorithm 1: `toInt(X, n)` on page 14.
/// Convert a byte string to an integer.
///
/// Input: n-byte string `X`. <br>
/// Input: n-byte string `X`, string length `n`. <br>
/// Output: Integer value of `X`.
pub(crate) fn to_int(x: &[u8], n: usize) -> u64 {
debug_assert_eq!(x.len(), n);
@ -66,12 +66,12 @@ pub(crate) fn to_byte(x: u64, n: usize) -> [u8; ((crate::LEN2 * crate::LGW + 7)
/// Algorithm 3: `base_2^b(X, b, out_len)` on page 15.
/// Compute the base 2^b representation of X.
///
/// Input: Byte string `X` of length at least ceil(`out_len·b/8`), integer `b`, output length `out_len`. <br>
/// Input: Byte string `X` of length at least ceil(out_len·b/8), integer `b`, output length `out_len`. <br>
/// Output: Array of `out_len` integers in the range `[0, . . . , 2^b 1]`.
pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize, baseb: &mut [u64]) {
assert!(x.len() >= out_len * b as usize / 8);
assert!(b < 64);
assert_eq!(out_len, baseb.len());
debug_assert!(x.len() >= out_len * b as usize / 8);
debug_assert!(b < 16);
debug_assert_eq!(out_len, baseb.len());
// 1: in ← 0
let mut inn = 0;
@ -105,7 +105,7 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize, baseb: &mut [u64]) {
bits -= b;
// 12: baseb[out] ← (total ≫ bits) mod 2^b
*item = (total >> bits) % 2u64.pow(b);
*item = (total >> bits) & (u64::MAX >> (16 - b));
// 13: end for
}
@ -116,7 +116,7 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize, baseb: &mut [u64]) {
/// Algorithm 4: `chain(X, i, s, PK.seed, ADRS)` on page 17.
/// Chaining function used in WOTS+. The chain function takes as input an n-byte string `X` and integers `s` and `i`
/// and returns the result of iterating a hash function `F` on the input `s` times, starting from an index of `i`.
/// and returns the result of iterating the hash function `F` on the input `s` times, starting from an index of `i`.
/// The chain function also requires as input PK.seed, which is part of the SLH-DSA public key, and an address `ADRS`.
/// The type in `ADRS` must be set to `WOTS_HASH`, and the layer address, tree address, key pair address, and chain
/// address must be set to the address of the chain being computed. The chain function updates the hash address in
@ -128,6 +128,7 @@ pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLe
hashers: &Hashers<K, LEN, M, N>, cap_x: GenericArray<u8, N>, i: usize, s: usize,
pk_seed: &[u8], adrs: &Adrs,
) -> Option<GenericArray<u8, N>> {
debug_assert!(i + s < u32::MAX as usize);
let mut adrs = adrs.clone();
// 1: if (i + s) ≥ w then
@ -148,7 +149,7 @@ pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLe
for j in i..(i + s) {
//
// 8: ADRS.setHashAddress(j)
adrs.set_hash_address(j.try_into().expect("usize->u32 fails")); // TODO: something better than expect?
adrs.set_hash_address(j as u32);
// 9: tmp ← F(PK.seed, ADRS, tmp)
tmp = (hashers.f)(pk_seed, &adrs, &tmp);
@ -172,7 +173,7 @@ pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLe
#[allow(clippy::similar_names)]
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,
) -> WotsPk<N> {
) -> Result<WotsPk<N>, &'static str> {
let mut adrs = adrs.clone();
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
@ -186,8 +187,7 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
sk_adrs.set_key_pair_address(adrs.get_key_pair_address());
// 4: for i from 0 to len 1 do
let len = 2 * N::to_u32() + 3;
for i in 0..len {
for i in 0..LEN::to_u32() {
//
// 5: skADRS.setChainAddress(i)
sk_adrs.set_chain_address(i);
@ -200,7 +200,7 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
// 8: tmp[i] ← chain(sk, 0, w 1, PK.seed, ADRS) ▷ Compute public value for chain i
tmp[i as usize] =
chain(hashers, sk, 0, crate::W as usize - 1, pk_seed, &adrs).expect("chain broke!");
chain(hashers, sk, 0, crate::W as usize - 1, pk_seed, &adrs).ok_or("chain broke")?;
// 9: end for
}
@ -218,7 +218,7 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
let pk = (hashers.t_l)(pk_seed, &wotspk_adrs, &tmp);
// 14: return pk
WotsPk(pk)
Ok(WotsPk(pk))
}
@ -235,7 +235,7 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
let mut sig: WotsSig<LEN, N> = WotsSig::default();
// 1: csum ← 0
let mut csum = 0u64;
let mut csum = 0;
// 2:
// 3: msg ← base_2b(M, lgw, len1) ▷ Convert message to base w
@ -255,11 +255,11 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
// 8:
// 9: csum ← csum ≪ ((8 ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4
let len2 = 3_usize; //
csum <<= (8 - ((len2 as u64 * u64::from(crate::LGW)) % 8)) % 8;
csum <<= (8 - ((len2 as u64 * u64::from(crate::LGW)) & 0x07)) & 0x07;
// 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w
base_2b(
&to_byte(csum, (len2 * crate::LGW as usize).div_ceil(8)),
&to_byte(csum as u64, (len2 * crate::LGW as usize).div_ceil(8)),
crate::LGW,
len2,
&mut msg[(2 * N::to_usize())..],
@ -277,20 +277,20 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
// 15: for i from 0 to len 1 do
let len = 2 * N::to_usize() + 3;
#[allow(clippy::cast_possible_truncation)] // step 18/19
for (i, item) in msg.iter().enumerate().take(len) {
#[allow(clippy::cast_possible_truncation)] // step 19
for (item, i) in msg.iter().zip(0u32..).take(len) {
//
// 16: skADRS.setChainAddress(i)
sk_addrs.set_chain_address(i as u32);
sk_addrs.set_chain_address(i);
// 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
let sk = (hashers.prf)(pk_seed, sk_seed, &sk_addrs);
// 18: ADRS.setChainAddress(i)
adrs.set_chain_address(i as u32);
adrs.set_chain_address(i);
// 19: sig[i] ← chain(sk, 0, msg[i], PK.seed, ADRS) ▷ Compute signature value for chain i
sig.data[i] = chain(hashers, sk, 0, *item as usize, pk_seed, &adrs).unwrap();
sig.data[i as usize] = chain(hashers, sk, 0, *item as usize, pk_seed, &adrs).unwrap();
// 20: end for
}
@ -316,13 +316,12 @@ pub(crate) fn wots_pk_from_sig<K: ArrayLength, LEN: ArrayLength, M: ArrayLength,
// 2:
// 3: msg ← base_2b (M, lgw , len1 ) ▷ Convert message to base w
let len1 = 2 * N::to_usize();
let mut msg: GenericArray<u64, LEN> = GenericArray::default();
base_2b(m, crate::LGW, 2 * N::to_usize(), &mut msg[0..(2 * N::to_usize())]);
// 4:
// 5: for i from 0 to len1 1 do ▷ Compute checksum
for item in msg.iter().take(len1) {
for item in msg.iter().take(2 * N::to_usize()) {
//
// 6: csum ← csum + w 1 msg[i]
csum += u64::from(crate::W) - 1 - item;
@ -333,11 +332,11 @@ pub(crate) fn wots_pk_from_sig<K: ArrayLength, LEN: ArrayLength, M: ArrayLength,
// 8:
// 9: csum ← csum ≪ ((8 ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4
let len2 = 3;
csum <<= (8 - ((len2 * crate::LGW as usize) % 8)) % 8;
csum <<= (8 - ((len2 * crate::LGW as usize) & 0x07)) & 0x07;
// 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w
base_2b(
&to_byte(csum, (len2 * crate::LGW as usize).div_ceil(8)),
&to_byte(csum as u64, (len2 * crate::LGW as usize).div_ceil(8)),
crate::LGW,
len2,
&mut msg[(2 * N::to_usize())..],
@ -419,7 +418,7 @@ pub(crate) fn xmss_node<
adrs.set_key_pair_address(i);
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
wots_pkgen::<K, LEN, M, N>(hashers, sk_seed, pk_seed, &adrs)
wots_pkgen::<K, LEN, M, N>(hashers, sk_seed, pk_seed, &adrs)?
.0
.clone() // TODO remove clone?

View file

@ -308,7 +308,7 @@ pub(crate) mod sha2_cat_3_5 {
],
&mut digest,
); // Note that the spec swaps order of last to params
//println!("prf: {:?}", &digest[0..4]);
//println!("prf: {:?}", &digest[0..4]);
digest
}

View file

@ -1,14 +1,13 @@
//#![no_std]
#![no_std]
#![deny(clippy::pedantic)]
#![deny(warnings)]
//#![deny(missing_docs)]
/// TKTK crate doc
/// crate doc?
// TODO
// 1. General clean-up
// 2. NOTE: SHA2 HASHERS DUMMIED UP TO PASS TEST; IMPLEMENT!
// 3. Implement SHA2 KATs
// 2. SerDes on keys
// 3. Proper traits and non-rng functions
// 4. Separate into proper files
// 5. Doc, of course!
mod algs;
@ -17,16 +16,16 @@ mod test;
mod traits;
mod types;
// Per eqns 5.1-4 on page 16, LGW=4, W=16 and LEN2=3 are constant across all parameter sets.
// Per eqns 5.1-4 on page 16, LGW=4, W=16 and LEN2=3 are constant across all security parameter sets.
const LGW: u32 = 4;
const W: u32 = 16;
const LEN2: u32 = 3;
/// blah
macro_rules! functionality {
() => {
use crate::types::{SlhDsaSig, SlhPrivateKey, SlhPublicKey};
//use generic_array::typenum::{Prod, Sum, U2, U3};
use rand_core::CryptoRngCore;
/// blah
@ -61,13 +60,13 @@ macro_rules! functionality {
use rand_chacha::rand_core::SeedableRng;
#[test]
fn simple_loop() {
fn simple_round_trips() {
let mut message = [0u8, 1, 2, 3];
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
for i in 0..5 {
message[3] = i as u8;
let (sk, pk) = slh_keygen_with_rng(&mut rng).unwrap();
let sig = slh_sign_with_rng(&mut rng, &message, &sk, false).unwrap();
let sig = slh_sign_with_rng(&mut rng, &message, &sk, true).unwrap();
let result = slh_verify(&message, &sig, &pk);
assert_eq!(result, true, "Signature failed to verify");
message[3] = (i + 1) as u8;
@ -79,11 +78,11 @@ macro_rules! functionality {
};
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_128s")]
pub mod slh_dsa_sha2_128s {
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U12, U14, U16, U2, U3, U30, U63, U7, U9};
@ -104,6 +103,7 @@ pub mod slh_dsa_sha2_128s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_128s")]
pub mod slh_dsa_shake_128s {
@ -128,11 +128,11 @@ pub mod slh_dsa_shake_128s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_128f")]
pub mod slh_dsa_sha2_128f {
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U16, U2, U22, U3, U33, U34, U6, U66};
@ -153,6 +153,7 @@ pub mod slh_dsa_sha2_128f {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_128f")]
pub mod slh_dsa_shake_128f {
@ -177,11 +178,11 @@ pub mod slh_dsa_shake_128f {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_192s")]
pub mod slh_dsa_sha2_192s {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U14, U17, U2, U24, U3, U39, U63, U7, U9};
@ -202,11 +203,11 @@ pub mod slh_dsa_sha2_192s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_192s")]
pub mod slh_dsa_shake_192s {
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U14, U17, U2, U24, U3, U39, U63, U7, U9};
@ -227,6 +228,7 @@ pub mod slh_dsa_shake_192s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_192f")]
pub mod slh_dsa_sha2_192f {
@ -251,6 +253,7 @@ pub mod slh_dsa_sha2_192f {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_192f")]
pub mod slh_dsa_shake_192f {
@ -275,11 +278,11 @@ pub mod slh_dsa_shake_192f {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_256s")]
pub mod slh_dsa_sha2_256s {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U14, U2, U22, U3, U32, U47, U64, U8};
@ -300,6 +303,7 @@ pub mod slh_dsa_sha2_256s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_256s")]
pub mod slh_dsa_shake_256s {
@ -324,11 +328,11 @@ pub mod slh_dsa_shake_256s {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_sha2_256f")]
pub mod slh_dsa_sha2_256f {
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l, t_len};
use crate::hashers::Hashers;
use generic_array::typenum::{Prod, Sum, U17, U2, U3, U32, U35, U4, U49, U68, U9};
@ -349,6 +353,7 @@ pub mod slh_dsa_sha2_256f {
functionality!();
}
/// TKTK
#[cfg(feature = "slh_dsa_shake_256f")]
pub mod slh_dsa_shake_256f {

File diff suppressed because one or more lines are too long