mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-04 20:03:45 +00:00
generic arrays...
This commit is contained in:
parent
0c9f00e8a9
commit
5ee9e944b6
4 changed files with 128 additions and 36 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
89
src/algs.rs
89
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::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.
|
||||||
|
|
|
||||||
21
src/lib.rs
21
src/lib.rs
|
|
@ -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)]
|
||||||
|
|
|
||||||
50
src/types.rs
50
src/types.rs
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue