From 5ee9e944b678e14f3f3221628f75a26858cff57b Mon Sep 17 00:00:00 2001 From: eschorn1 Date: Sat, 13 Jan 2024 16:45:33 -0600 Subject: [PATCH] generic arrays... --- Cargo.toml | 4 +-- src/algs.rs | 89 +++++++++++++++++++++++++++++++++------------------- src/lib.rs | 21 +++++++++++-- src/types.rs | 50 +++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7fa9000..71d32b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,10 @@ rust-version = "1.73" [dependencies] -zeroize = { version = "1.6.0", features = ["zeroize_derive"] } +zeroize = { version = "1.7.0", features = ["zeroize_derive"] } rand_core = { version = "0.6.4", default-features = false } sha3 = { version = "0.10.8", default-features = false } - +generic-array = { version = "1.0.0", features=["const-default", "zeroize"] } [features] default = ["default-rng", "slh_dsa_sha2_128s", "slh_dsa_shake_128s", "slh_dsa_sha2_128f", "slh_dsa_shake_128f", diff --git a/src/algs.rs b/src/algs.rs index 09ba71d..9152f7a 100644 --- a/src/algs.rs +++ b/src/algs.rs @@ -1,8 +1,9 @@ -use crate::types::ADRS; +use crate::types::{ADRS, WotsSig}; use crate::types::{WOTS_PK, WOTS_PRF}; use crate::Context; use alloc::vec; use alloc::vec::Vec; +use generic_array::{ArrayLength, GenericArray}; use sha3::{ digest::{ExtendableOutput, Update, XofReader}, Shake256, @@ -97,16 +98,16 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize) -> Vec { } #[must_use] -pub(crate) fn shake256(input: &[&[u8]]) -> [u8; 32] { +pub(crate) fn shake256(input: &[&[u8]]) -> GenericArray { let mut hasher = Shake256::default(); input.iter().for_each(|item| hasher.update(item)); let mut reader = hasher.finalize_xof(); - let mut result = [0u8; 32]; + let mut result = GenericArray::default(); reader.read(&mut result); result } -pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &[u8]) -> Vec { +pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &GenericArray) -> GenericArray { shake256(&[&pk_seed, &adrs.to_bytes(), tmp]).into() } @@ -121,9 +122,10 @@ pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &[u8]) -> Vec { /// /// Input: Input string `X`, start index `i`, number of steps `s`, public seed `PK.seed`, address `ADRS`.
/// Output: Value of `F` iterated `s` times on `X`. -pub(crate) fn chain( - context: &Context, cap_x: Vec, i: usize, s: usize, pk_seed: &[u8], adrs: &mut ADRS, -) -> Option> { +pub(crate) fn chain( + context: &Context, cap_x: GenericArray, i: usize, s: usize, pk_seed: &[u8], adrs: &ADRS, +) -> Option> { + let mut adrs = adrs.clone(); // 1: if (i + s) ≥ w then if (i + s) >= context.w { // 2: return NULL @@ -147,27 +149,26 @@ pub(crate) fn chain( } -pub(crate) fn prf(pk_seed: &[u8], sk_seed: &[u8], adrs: &ADRS) -> Vec { - shake256(&[&pk_seed, &sk_seed, &adrs.to_bytes()]).into() +pub(crate) fn prf(pk_seed: &[u8], sk_seed: &[u8], adrs: &ADRS) -> GenericArray { + shake256(&[&pk_seed, &sk_seed, &adrs.to_bytes()]) } -/// Note: duplicates a bunch of shake256 due to `ml` vec>> type 'challenges'. TODO: improve -pub(crate) fn tlen( - context: &Context, pk_seed: &[u8], adrs: &ADRS, ml: Vec>>, -) -> Vec { - assert!(ml - .iter() - .all(|item| item.is_some() & (item.as_ref().unwrap().len() == context.len1))); +pub(crate) fn tlen( + _context: &Context, pk_seed: &[u8], adrs: &ADRS, ml: &GenericArray, LEN>, +) -> GenericArray { + // assert!(ml + // .iter() + // .all(|item| item.as_ref().len() == context.len1)); let mut hasher = Shake256::default(); hasher.update(pk_seed); hasher.update(&adrs.to_bytes()); ml.iter() - .for_each(|item| hasher.update(&item.as_ref().unwrap())); + .for_each(|item| hasher.update(&item.as_ref())); let mut reader = hasher.finalize_xof(); - let mut result = [0u8; 32]; + let mut result = GenericArray::default(); reader.read(&mut result); - result.into() + result } @@ -179,9 +180,11 @@ pub(crate) fn tlen( /// /// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`.
/// Output: WOTS+ public key `pk`. -pub(crate) fn wots_pkgen( +pub(crate) fn wots_pkgen( context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut ADRS, -) -> Vec { +) -> GenericArray { + let mut tmp: GenericArray, LEN> = GenericArray::default(); + // 1: skADRS ← ADRS ▷ Copy address to create key generation key address let mut sk_adrs = adrs.clone(); @@ -192,7 +195,6 @@ pub(crate) fn wots_pkgen( sk_adrs.set_key_pair_address(adrs.get_key_pair_address()); // 4: for i from 0 to len − 1 do - let mut tmp: Vec>> = vec![]; for i in 0..context.len1 { // 5: skADRS.setChainAddress(i) sk_adrs.set_chain_address(i); @@ -204,7 +206,7 @@ pub(crate) fn wots_pkgen( adrs.set_chain_address(i); // 8: tmp[i] ← chain(sk, 0, w − 1, PK.seed, ADRS) ▷ Compute public value for chain i - tmp[i] = chain(context, sk, 0, context.w - 1, pk_seed, adrs); + tmp[i] = chain(context, sk, 0, context.w - 1, pk_seed, adrs).expect("chain broek!"); // 9: end for } @@ -218,7 +220,7 @@ pub(crate) fn wots_pkgen( wotspk_adrs.set_key_pair_address(adrs.get_key_pair_address()); // 13: pk ← Tlen (PK.seed, wotspkADRS,tmp) ▷ Compress public key - let pk = tlen(context, pk_seed, &wotspk_adrs, tmp); + let pk = tlen(context, pk_seed, &wotspk_adrs, &tmp); // 14: return pk pk @@ -230,13 +232,16 @@ pub(crate) fn wots_pkgen( /// /// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`.
/// Output: WOTS+ signature sig. -pub(crate) fn wots_sign(context: &Context, m: &[u8], _sk_seed: &[u8], _pk_seed: &[u8], _adrs: &ADRS) -> u32 { +pub(crate) fn wots_sign(context: &Context, m: &[u8], sk_seed: &[u8], pk_seed: &[u8], adrs: ADRS) -> WotsSig { + let mut adrs = adrs; + let mut sig: WotsSig = WotsSig::default(); + // 1: csum ← 0 let mut csum = 0u64; // 2: // 3: msg ← base_2b(M, lgw, len1) ▷ Convert message to base w - let msg = base_2b(m, context.lgw, context.len1); + let mut msg = base_2b(m, context.lgw, context.len1); // 4: // 5: for i from 0 to len1 − 1 do ▷ Compute checksum @@ -249,20 +254,40 @@ pub(crate) fn wots_sign(context: &Context, m: &[u8], _sk_seed: &[u8], _pk_seed: } // 8: // 9: csum ← csum ≪ ((8 − ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4 + csum = csum << ((8 - ((context.len2 * context.lgw as usize) % 8)) % 8); // 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w + msg.extend(&base_2b(&to_byte(csum, (context.len2 * context.lgw as usize).div_ceil(8)), context.lgw, context.len2)); + // 11: // 12: skADRS ← ADRS + let mut sk_addrs = adrs.clone(); + // 13: skADRS.setTypeAndClear(WOTS_PRF) + sk_addrs.set_type_and_clear(WOTS_PRF); + // 14: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress()) + sk_addrs.set_key_pair_address(adrs.get_key_pair_address()); + // 15: for i from 0 to len − 1 do - // 16: skADRS.setChainAddress(i) - // 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i - // 18: ADRS.setChainAddress(i) - // 19: sig[i] ← chain(sk, 0, msg[i], PK.seed, ADRS) ▷ Compute signature value for chain i - // 20: end for + for i in 0..context.len { + + // 16: skADRS.setChainAddress(i) + sk_addrs.set_chain_address(i); + + // 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i + let sk = prf(pk_seed, sk_seed, &sk_addrs); + + // 18: ADRS.setChainAddress(i) + 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(context, sk, 0, msg[i] as usize, pk_seed, &adrs).unwrap(); + + // 20: end for + } // 21: return sig - csum as u32 + sig } /// Algorithm 7: `wots_PKFromSig(sig, M, PK.seed, ADRS)` on page 20. diff --git a/src/lib.rs b/src/lib.rs index 92cce59..de0c5a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ extern crate alloc; + mod algs; mod traits; mod types; @@ -19,17 +20,33 @@ pub fn add(left: usize, right: usize) -> usize { left + right } struct Context { lgw: u32, w: usize, - len1: usize + len1: usize, + len2: usize, + len: usize } + macro_rules! functionality { () => { use crate::traits::PK; + use crate::types::{SlhDsaSig}; + use generic_array::typenum::{U5, U16}; use crate::Context; use zeroize::{Zeroize, ZeroizeOnDrop}; // ----- 'EXTERNAL' DATA TYPES ----- - static CONTEXT: Context = Context{lgw: LGW, w: 2_usize.pow(LGW), len1: (8*N).div_ceil(LGW as usize)}; + const W: usize = 2_usize.pow(LGW); + const LEN1: usize = (8*N).div_ceil(LGW as usize); + const LEN2: usize = ((LEN1*(W-1)).ilog2()/LGW) as usize + 1; + const LEN: usize = LEN1 + LEN2; + + static CONTEXT: Context = Context{lgw: LGW, w: W, len1: LEN1, + len2: LEN2, len: LEN}; + + + fn sign() -> SlhDsaSig:: { + SlhDsaSig::::default() + } /// Correctly sized private key specific to the target security parameter set.
#[derive(Clone, Zeroize, ZeroizeOnDrop)] diff --git a/src/types.rs b/src/types.rs index 3be9d83..788bc0e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,56 @@ use alloc::vec::Vec; +use generic_array::{ArrayLength, GenericArray}; use zeroize::{Zeroize, ZeroizeOnDrop}; + +/// Fig 16 on page 34 +#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] +pub struct SlhDsaSig { + randomness: GenericArray, + fors_sig: ForsSig, + ht_sig: HtSig, +} + + +/// Fig 13 on page 29 +#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] +pub(crate) struct ForsSig { + private_key_value: GenericArray, K>, + auth: GenericArray, K>, +} + + +/// Fig 10? +#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] +pub(crate) struct Auth { + tree: GenericArray, A> +} + + +#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] +pub(crate) struct HtSig { + x: GenericArray +} + + +#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] +pub struct WotsSig { + pub(crate) data: GenericArray, LEN> +} + + + + + + + + + + + + + + const WOTS_HASH: u32 = 0; pub(crate) const WOTS_PK: u32 = 1; const TREE: u32 = 2;