diff --git a/src/algs.rs b/src/algs.rs index 9152f7a..7d89dd0 100644 --- a/src/algs.rs +++ b/src/algs.rs @@ -1,4 +1,4 @@ -use crate::types::{ADRS, WotsSig}; +use crate::types::{WotsSig, Adrs}; use crate::types::{WOTS_PK, WOTS_PRF}; use crate::Context; use alloc::vec; @@ -9,6 +9,7 @@ use sha3::{ Shake256, }; + /// Algorithm 1: `toInt(X, n)` on page 14. /// Convert a byte string to an integer. /// @@ -16,15 +17,20 @@ use sha3::{ /// Output: Integer value of `X`. pub(crate) fn to_int(x: &[u8], n: usize) -> u64 { assert_eq!(x.len(), n); + // 1: total ← 0 let mut total = 0_u64; + // 2: // 3: for i from 0 to n − 1 do - for i in 0..n { + for item in x.iter().take(n) { + // // 4: total ← 256 · total + X[i] - total = (total << 8) + x[i] as u64; + total = (total << 8) + u64::from(*item); + // 5: end for } + // 6: return total total } @@ -42,12 +48,11 @@ pub(crate) fn to_byte(x: u64, n: usize) -> Vec { let mut total = x; // 2: - // 3: for i from 0 to n − 1 do for i in 0..n { // // 4: S[n − 1 − i] ← total mod 256 ▷ Least significant 8 bits of total - s[n - 1 - i] = total as u8; + s[n - 1 - i] = total.to_le_bytes()[0]; // 5: total ← total ≫ 8 total >>= 8; @@ -68,35 +73,49 @@ pub(crate) fn to_byte(x: u64, n: usize) -> Vec { pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize) -> Vec { assert!(x.len() >= out_len * b as usize / 8); let mut baseb = vec![0u64; out_len]; + // 1: in ← 0 let mut inn = 0; + // 2: bits ← 0 let mut bits = 0; + // 3: total ← 0 let mut total = 0; + // 4: // 5: for out from 0 to out_len − 1 do - for out in 0..out_len { + for item in baseb.iter_mut().take(out_len) { + // // 6: while bits < b do while bits < b { + // // 7: total ← (total ≪ 8) + X[in] - total = (total << 8) + x[inn] as u64; + total = (total << 8) + u64::from(x[inn]); + // 8: in ← in + 1 inn += 1; + // 9: bits ← bits + 8 bits += 8; + // 10: end while } + // 11: bits ← bits − b bits -= b; + // 12: baseb[out] ← (total ≫ bits) mod 2^b - baseb[out] = (total >> bits) & (2u64.pow(b) - 1); + *item = (total >> bits) & (2u64.pow(b) - 1); + // 13: end for } + // 14: return baseb baseb } + #[must_use] pub(crate) fn shake256(input: &[&[u8]]) -> GenericArray { let mut hasher = Shake256::default(); @@ -107,8 +126,11 @@ pub(crate) fn shake256(input: &[&[u8]]) -> GenericArray { result } -pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &GenericArray) -> GenericArray { - shake256(&[&pk_seed, &adrs.to_bytes(), tmp]).into() + +pub(crate) fn f( + pk_seed: &[u8], adrs: &Adrs, tmp: &GenericArray, +) -> GenericArray { + shake256(&[&pk_seed, &adrs.to_bytes(), tmp]) } @@ -123,48 +145,56 @@ pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &GenericArray< /// 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: GenericArray, i: usize, s: usize, pk_seed: &[u8], adrs: &ADRS, + 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 return None; + // 3: end if } + // 4: // 5: tmp ← X let mut tmp = cap_x; + // 6: // 7: for j from i to i + s − 1 do for j in i..(i + s) { + // // 8: ADRS.setHashAddress(j) adrs.set_hash_address(j.try_into().expect("usize->u32 fails")); + // 9: tmp ← F(PK.seed, ADRS, tmp) - tmp = f(&pk_seed, &adrs, &tmp) + tmp = f(pk_seed, &adrs, &tmp); + // 10: end for } + // 11: return tmp Some(tmp) } -pub(crate) fn prf(pk_seed: &[u8], sk_seed: &[u8], adrs: &ADRS) -> GenericArray { +#[allow(clippy::similar_names)] +pub(crate) fn prf( + pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs, +) -> GenericArray { shake256(&[&pk_seed, &sk_seed, &adrs.to_bytes()]) } pub(crate) fn tlen( - _context: &Context, pk_seed: &[u8], adrs: &ADRS, ml: &GenericArray, LEN>, + _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())); + ml.iter().for_each(|item| hasher.update(item)); let mut reader = hasher.finalize_xof(); let mut result = GenericArray::default(); reader.read(&mut result); @@ -180,8 +210,9 @@ pub(crate) fn tlen( /// /// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`.
/// Output: WOTS+ public key `pk`. +#[allow(clippy::similar_names)] pub(crate) fn wots_pkgen( - context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut ADRS, + context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut Adrs, ) -> GenericArray { let mut tmp: GenericArray, LEN> = GenericArray::default(); @@ -196,6 +227,7 @@ pub(crate) fn wots_pkgen( // 4: for i from 0 to len − 1 do for i in 0..context.len1 { + // // 5: skADRS.setChainAddress(i) sk_adrs.set_chain_address(i); @@ -210,6 +242,7 @@ pub(crate) fn wots_pkgen( // 9: end for } + // 10: wotspkADRS ← ADRS ▷ Copy address to create WOTS+ public key address let mut wotspk_adrs = adrs.clone(); @@ -220,6 +253,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 + #[allow(clippy::let_and_return)] let pk = tlen(context, pk_seed, &wotspk_adrs, &tmp); // 14: return pk @@ -232,7 +266,10 @@ 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) -> WotsSig { +#[allow(clippy::similar_names)] +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(); @@ -245,19 +282,25 @@ pub(crate) fn wots_sign(context: &Context, m: // 4: // 5: for i from 0 to len1 − 1 do ▷ Compute checksum - for i in 0..context.len1 { - + for item in msg.iter().take(context.len1) { + // // 6: csum ← csum + w − 1 − msg[i] - csum += context.w as u64 - 1 - msg[i]; + csum += context.w as u64 - 1 - item; // 7: end for } + // 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); + //csum = csum << ((8 - ((context.len2 * context.lgw as usize) % 8)) % 8); + 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)); + msg.extend(&base_2b( + &to_byte(csum, (context.len2 * context.lgw as usize).div_ceil(8)), + context.lgw, + context.len2, + )); // 11: // 12: skADRS ← ADRS @@ -270,8 +313,9 @@ pub(crate) fn wots_sign(context: &Context, m: sk_addrs.set_key_pair_address(adrs.get_key_pair_address()); // 15: for i from 0 to len − 1 do - for i in 0..context.len { - + #[allow(clippy::cast_possible_truncation)] // step 19 + for (i, item) in msg.iter().enumerate().take(context.len) { + // // 16: skADRS.setChainAddress(i) sk_addrs.set_chain_address(i); @@ -282,14 +326,16 @@ pub(crate) fn wots_sign(context: &Context, m: 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(); + sig.data[i] = chain(context, sk, 0, *item as usize, pk_seed, &adrs).unwrap(); // 20: end for } + // 21: return sig sig } + /// Algorithm 7: `wots_PKFromSig(sig, M, PK.seed, ADRS)` on page 20. /// Compute a WOTS+ public key from a message and its signature. /// @@ -395,7 +441,7 @@ const _A10: u32 = 0; /// /// Input: Message `M`, private seed `SK.seed`, public seed `PK.seed`, tree index `idx_tree`, leaf /// index `idx_leaf`.
-/// Output: HT signature SIG_HT. +/// Output: HT signature `SIG_HT`. const _A11: u32 = 0; // 1: ADRS ← toByte(0, 32) // 2: diff --git a/src/lib.rs b/src/lib.rs index de0c5a4..de1fff3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,31 +22,28 @@ struct Context { w: usize, len1: usize, len2: usize, - len: usize + len: usize, } macro_rules! functionality { () => { use crate::traits::PK; - use crate::types::{SlhDsaSig}; - use generic_array::typenum::{U5, U16}; + use crate::types::SlhDsaSig; use crate::Context; + use generic_array::typenum::{U16, U5}; use zeroize::{Zeroize, ZeroizeOnDrop}; // ----- 'EXTERNAL' DATA TYPES ----- 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 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}; + static CONTEXT: Context = Context { lgw: LGW, w: W, len1: LEN1, len2: LEN2, len: LEN }; - fn sign() -> SlhDsaSig:: { - SlhDsaSig::::default() - } + 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 788bc0e..21c5d54 100644 --- a/src/types.rs +++ b/src/types.rs @@ -23,34 +23,22 @@ pub(crate) struct ForsSig { /// Fig 10? #[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] pub(crate) struct Auth { - tree: GenericArray, A> + tree: GenericArray, A>, } #[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] pub(crate) struct HtSig { - x: GenericArray + x: GenericArray, } #[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] pub struct WotsSig { - pub(crate) data: GenericArray, LEN> + pub(crate) data: GenericArray, LEN>, } - - - - - - - - - - - - const WOTS_HASH: u32 = 0; pub(crate) const WOTS_PK: u32 = 1; const TREE: u32 = 2; @@ -63,7 +51,7 @@ const FORS_PRF: u32 = 6; /// Straddling the line between struct, enum and union... #[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] #[repr(align(32))] -pub struct ADRS { +pub struct Adrs { f0: [u8; 4], // layer address f1: [u8; 4], // tree address (LSB?) f2: [u8; 4], // tree address @@ -75,11 +63,12 @@ pub struct ADRS { } -impl ADRS { +impl Adrs { pub(crate) fn get_key_pair_address(&self) -> [u8; 4] { self.f5 } pub(crate) fn set_key_pair_address(&mut self, kp_addr: [u8; 4]) { self.f5 = kp_addr; } + #[allow(clippy::cast_possible_truncation)] pub(crate) fn set_chain_address(&mut self, i: usize) { self.f6 = (i as u32).to_be_bytes(); } pub(crate) fn set_type_and_clear(&mut self, type_t: u32) { @@ -92,7 +81,6 @@ impl ADRS { pub(crate) fn set_hash_address(&mut self, addr: u32) { self.f7 = addr.to_be_bytes(); } pub(crate) fn to_bytes(&self) -> Vec { - let x = [self.f0, self.f1, self.f2, self.f3].concat(); - x + [self.f0, self.f1, self.f2, self.f3].concat() } }