generic arrays...

This commit is contained in:
eschorn1 2024-01-13 16:45:33 -06:00
parent 0c9f00e8a9
commit 5ee9e944b6
4 changed files with 128 additions and 36 deletions

View file

@ -9,10 +9,10 @@ rust-version = "1.73"
[dependencies] [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 } rand_core = { version = "0.6.4", default-features = false }
sha3 = { version = "0.10.8", default-features = false } sha3 = { version = "0.10.8", default-features = false }
generic-array = { version = "1.0.0", features=["const-default", "zeroize"] }
[features] [features]
default = ["default-rng", "slh_dsa_sha2_128s", "slh_dsa_shake_128s", "slh_dsa_sha2_128f", "slh_dsa_shake_128f", default = ["default-rng", "slh_dsa_sha2_128s", "slh_dsa_shake_128s", "slh_dsa_sha2_128f", "slh_dsa_shake_128f",

View file

@ -1,8 +1,9 @@
use crate::types::ADRS; use crate::types::{ADRS, WotsSig};
use crate::types::{WOTS_PK, WOTS_PRF}; use crate::types::{WOTS_PK, WOTS_PRF};
use crate::Context; use crate::Context;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use generic_array::{ArrayLength, GenericArray};
use sha3::{ use sha3::{
digest::{ExtendableOutput, Update, XofReader}, digest::{ExtendableOutput, Update, XofReader},
Shake256, Shake256,
@ -97,16 +98,16 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize) -> Vec<u64> {
} }
#[must_use] #[must_use]
pub(crate) fn shake256(input: &[&[u8]]) -> [u8; 32] { pub(crate) fn shake256<N: ArrayLength>(input: &[&[u8]]) -> GenericArray<u8, N> {
let mut hasher = Shake256::default(); let mut hasher = Shake256::default();
input.iter().for_each(|item| hasher.update(item)); input.iter().for_each(|item| hasher.update(item));
let mut reader = hasher.finalize_xof(); let mut reader = hasher.finalize_xof();
let mut result = [0u8; 32]; let mut result = GenericArray::default();
reader.read(&mut result); reader.read(&mut result);
result result
} }
pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &[u8]) -> Vec<u8> { pub(crate) fn f<N: ArrayLength>(pk_seed: &[u8], adrs: &ADRS, tmp: &GenericArray<u8, N>) -> GenericArray<u8, N> {
shake256(&[&pk_seed, &adrs.to_bytes(), tmp]).into() shake256(&[&pk_seed, &adrs.to_bytes(), tmp]).into()
} }
@ -121,9 +122,10 @@ pub(crate) fn f(pk_seed: &[u8], adrs: &ADRS, tmp: &[u8]) -> Vec<u8> {
/// ///
/// Input: Input string `X`, start index `i`, number of steps `s`, public seed `PK.seed`, address `ADRS`. <br> /// Input: Input string `X`, start index `i`, number of steps `s`, public seed `PK.seed`, address `ADRS`. <br>
/// Output: Value of `F` iterated `s` times on `X`. /// Output: Value of `F` iterated `s` times on `X`.
pub(crate) fn chain( pub(crate) fn chain<N: ArrayLength>(
context: &Context, cap_x: Vec<u8>, i: usize, s: usize, pk_seed: &[u8], adrs: &mut ADRS, context: &Context, cap_x: GenericArray<u8, N>, i: usize, s: usize, pk_seed: &[u8], adrs: &ADRS,
) -> Option<Vec<u8>> { ) -> Option<GenericArray<u8, N>> {
let mut adrs = adrs.clone();
// 1: if (i + s) ≥ w then // 1: if (i + s) ≥ w then
if (i + s) >= context.w { if (i + s) >= context.w {
// 2: return NULL // 2: return NULL
@ -147,27 +149,26 @@ pub(crate) fn chain(
} }
pub(crate) fn prf(pk_seed: &[u8], sk_seed: &[u8], adrs: &ADRS) -> Vec<u8> { pub(crate) fn prf<N: ArrayLength>(pk_seed: &[u8], sk_seed: &[u8], adrs: &ADRS) -> GenericArray<u8, N> {
shake256(&[&pk_seed, &sk_seed, &adrs.to_bytes()]).into() shake256(&[&pk_seed, &sk_seed, &adrs.to_bytes()])
} }
/// Note: duplicates a bunch of shake256 due to `ml` vec<option<vec<u8>>> type 'challenges'. TODO: improve pub(crate) fn tlen<LEN: ArrayLength, N: ArrayLength>(
pub(crate) fn tlen( _context: &Context, pk_seed: &[u8], adrs: &ADRS, ml: &GenericArray<GenericArray<u8, N>, LEN>,
context: &Context, pk_seed: &[u8], adrs: &ADRS, ml: Vec<Option<Vec<u8>>>, ) -> GenericArray<u8, N> {
) -> Vec<u8> { // assert!(ml
assert!(ml // .iter()
.iter() // .all(|item| item.as_ref().len() == context.len1));
.all(|item| item.is_some() & (item.as_ref().unwrap().len() == context.len1)));
let mut hasher = Shake256::default(); let mut hasher = Shake256::default();
hasher.update(pk_seed); hasher.update(pk_seed);
hasher.update(&adrs.to_bytes()); hasher.update(&adrs.to_bytes());
ml.iter() 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 reader = hasher.finalize_xof();
let mut result = [0u8; 32]; let mut result = GenericArray::default();
reader.read(&mut result); 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`. <br> /// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
/// Output: WOTS+ public key `pk`. /// Output: WOTS+ public key `pk`.
pub(crate) fn wots_pkgen( pub(crate) fn wots_pkgen<LEN: ArrayLength, N: ArrayLength>(
context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut ADRS, context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut ADRS,
) -> Vec<u8> { ) -> GenericArray<u8, N> {
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
// 1: skADRS ← ADRS ▷ Copy address to create key generation key address // 1: skADRS ← ADRS ▷ Copy address to create key generation key address
let mut sk_adrs = adrs.clone(); 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()); sk_adrs.set_key_pair_address(adrs.get_key_pair_address());
// 4: for i from 0 to len 1 do // 4: for i from 0 to len 1 do
let mut tmp: Vec<Option<Vec<u8>>> = vec![];
for i in 0..context.len1 { for i in 0..context.len1 {
// 5: skADRS.setChainAddress(i) // 5: skADRS.setChainAddress(i)
sk_adrs.set_chain_address(i); sk_adrs.set_chain_address(i);
@ -204,7 +206,7 @@ pub(crate) fn wots_pkgen(
adrs.set_chain_address(i); adrs.set_chain_address(i);
// 8: tmp[i] ← chain(sk, 0, w 1, PK.seed, ADRS) ▷ Compute public value for chain 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 // 9: end for
} }
@ -218,7 +220,7 @@ pub(crate) fn wots_pkgen(
wotspk_adrs.set_key_pair_address(adrs.get_key_pair_address()); wotspk_adrs.set_key_pair_address(adrs.get_key_pair_address());
// 13: pk ← Tlen (PK.seed, wotspkADRS,tmp) ▷ Compress public key // 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 // 14: return pk
pk pk
@ -230,13 +232,16 @@ pub(crate) fn wots_pkgen(
/// ///
/// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br> /// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
/// Output: WOTS+ signature sig. /// 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<N: ArrayLength, LEN: ArrayLength>(context: &Context, m: &[u8], sk_seed: &[u8], pk_seed: &[u8], adrs: ADRS) -> WotsSig<N, LEN> {
let mut adrs = adrs;
let mut sig: WotsSig<N, LEN> = WotsSig::default();
// 1: csum ← 0 // 1: csum ← 0
let mut csum = 0u64; let mut csum = 0u64;
// 2: // 2:
// 3: msg ← base_2b(M, lgw, len1) ▷ Convert message to base w // 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: // 4:
// 5: for i from 0 to len1 1 do ▷ Compute checksum // 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: // 8:
// 9: csum ← csum ≪ ((8 ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4 // 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 // 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: // 11:
// 12: skADRS ← ADRS // 12: skADRS ← ADRS
let mut sk_addrs = adrs.clone();
// 13: skADRS.setTypeAndClear(WOTS_PRF) // 13: skADRS.setTypeAndClear(WOTS_PRF)
sk_addrs.set_type_and_clear(WOTS_PRF);
// 14: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress()) // 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 // 15: for i from 0 to len 1 do
// 16: skADRS.setChainAddress(i) for i in 0..context.len {
// 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
// 18: ADRS.setChainAddress(i) // 16: skADRS.setChainAddress(i)
// 19: sig[i] ← chain(sk, 0, msg[i], PK.seed, ADRS) ▷ Compute signature value for chain i sk_addrs.set_chain_address(i);
// 20: end for
// 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 // 21: return sig
csum as u32 sig
} }
/// Algorithm 7: `wots_PKFromSig(sig, M, PK.seed, ADRS)` on page 20. /// Algorithm 7: `wots_PKFromSig(sig, M, PK.seed, ADRS)` on page 20.

View file

@ -8,6 +8,7 @@
extern crate alloc; extern crate alloc;
mod algs; mod algs;
mod traits; mod traits;
mod types; mod types;
@ -19,17 +20,33 @@ pub fn add(left: usize, right: usize) -> usize { left + right }
struct Context { struct Context {
lgw: u32, lgw: u32,
w: usize, w: usize,
len1: usize len1: usize,
len2: usize,
len: usize
} }
macro_rules! functionality { macro_rules! functionality {
() => { () => {
use crate::traits::PK; use crate::traits::PK;
use crate::types::{SlhDsaSig};
use generic_array::typenum::{U5, U16};
use crate::Context; use crate::Context;
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
// ----- 'EXTERNAL' DATA TYPES ----- // ----- '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::<U5, U5, U16> {
SlhDsaSig::<U5, U5, U16>::default()
}
/// Correctly sized private key specific to the target security parameter set. <br> /// Correctly sized private key specific to the target security parameter set. <br>
#[derive(Clone, Zeroize, ZeroizeOnDrop)] #[derive(Clone, Zeroize, ZeroizeOnDrop)]

View file

@ -1,6 +1,56 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use generic_array::{ArrayLength, GenericArray};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
/// Fig 16 on page 34
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
pub struct SlhDsaSig<A: ArrayLength, K: ArrayLength, N: ArrayLength> {
randomness: GenericArray<u8, N>,
fors_sig: ForsSig<A, K, N>,
ht_sig: HtSig<N>,
}
/// Fig 13 on page 29
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
pub(crate) struct ForsSig<A: ArrayLength, K: ArrayLength, N: ArrayLength> {
private_key_value: GenericArray<GenericArray<u8, N>, K>,
auth: GenericArray<Auth<A, N>, K>,
}
/// Fig 10?
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
pub(crate) struct Auth<A: ArrayLength, N: ArrayLength> {
tree: GenericArray<GenericArray<u8, N>, A>
}
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
pub(crate) struct HtSig<N: ArrayLength> {
x: GenericArray<u8, N>
}
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
pub struct WotsSig<N: ArrayLength, LEN: ArrayLength> {
pub(crate) data: GenericArray<GenericArray<u8, N>, LEN>
}
const WOTS_HASH: u32 = 0; const WOTS_HASH: u32 = 0;
pub(crate) const WOTS_PK: u32 = 1; pub(crate) const WOTS_PK: u32 = 1;
const TREE: u32 = 2; const TREE: u32 = 2;