mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-04 20:03:45 +00:00
a9
This commit is contained in:
parent
f3f22d6c4f
commit
befcf9a600
3 changed files with 172 additions and 55 deletions
194
src/algs.rs
194
src/algs.rs
|
|
@ -1,14 +1,15 @@
|
|||
use crate::types::{WotsSig, Adrs};
|
||||
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,
|
||||
};
|
||||
|
||||
use crate::types::{Adrs, WotsPk, WotsSig};
|
||||
use crate::types::{TREE, WOTS_HASH, WOTS_PK, WOTS_PRF};
|
||||
use crate::Context;
|
||||
|
||||
/// Algorithm 1: `toInt(X, n)` on page 14.
|
||||
/// Convert a byte string to an integer.
|
||||
|
|
@ -212,8 +213,9 @@ pub(crate) fn tlen<LEN: ArrayLength, N: ArrayLength>(
|
|||
/// Output: WOTS+ public key `pk`.
|
||||
#[allow(clippy::similar_names)]
|
||||
pub(crate) fn wots_pkgen<LEN: ArrayLength, N: ArrayLength>(
|
||||
context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &mut Adrs,
|
||||
) -> GenericArray<u8, N> {
|
||||
context: &Context, sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> WotsPk<N> {
|
||||
let mut adrs = adrs.clone();
|
||||
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
|
||||
|
||||
// 1: skADRS ← ADRS ▷ Copy address to create key generation key address
|
||||
|
|
@ -238,7 +240,7 @@ pub(crate) fn wots_pkgen<LEN: ArrayLength, N: ArrayLength>(
|
|||
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).expect("chain broek!");
|
||||
tmp[i] = chain(context, sk, 0, context.w - 1, pk_seed, &adrs).expect("chain broek!");
|
||||
|
||||
// 9: end for
|
||||
}
|
||||
|
|
@ -253,11 +255,10 @@ pub(crate) fn wots_pkgen<LEN: ArrayLength, N: ArrayLength>(
|
|||
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
|
||||
pk
|
||||
WotsPk(pk)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -292,7 +293,6 @@ pub(crate) fn wots_sign<N: ArrayLength, LEN: ArrayLength>(
|
|||
|
||||
// 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 <<= (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
|
||||
|
|
@ -341,26 +341,89 @@ pub(crate) fn wots_sign<N: ArrayLength, LEN: ArrayLength>(
|
|||
///
|
||||
/// Input: WOTS+ signature `sig`, message `M`, public seed `PK.seed`, address `ADRS`. <br>
|
||||
/// Output: WOTS+ public key `pksig` derived from `sig`.
|
||||
const _A7: u32 = 0;
|
||||
// 1: csum ← 0
|
||||
// 2:
|
||||
// 3: msg ← base_2b (M, lgw , len1 ) ▷ Convert message to base w
|
||||
// 4:
|
||||
// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
|
||||
// 6: csum ← csum + w − 1 − msg[i]
|
||||
// 7: end for
|
||||
// 8:
|
||||
// 9: csum ← csum ≪ ((8 − ((len2·lgw) mod 8)) mod 8) ▷ For lgw = 4 left shift by 4
|
||||
// 10: msg ← msg ∥ base_2^b(toByte(csum, ceil(len2·lgw/8)), lgw, len2) ▷ Convert csum to base w
|
||||
// 11: for i from 0 to len − 1 do
|
||||
// 12: ADRS.setChainAddress(i)
|
||||
// 13: tmp[i] ← chain(sig[i], msg[i], w − 1 − msg[i], PK.seed, ADRS)
|
||||
// 14: end for
|
||||
// 15: wotspkADRS ← ADRS
|
||||
// 16: wotspkADRS.setTypeAndClear(WOTS_PK)
|
||||
// 17: wotspkADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
|
||||
// 18: pksig ← Tlen (PK.seed, wotspkADRS, tmp)
|
||||
// 19: return pksig
|
||||
pub(crate) fn wots_pk_from_sig<LEN: ArrayLength, N: ArrayLength>(
|
||||
context: &Context, sig: &WotsSig<LEN, N>, m: &[u8], pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> WotsPk<N> {
|
||||
let mut adrs = adrs.clone();
|
||||
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
|
||||
|
||||
// 1: csum ← 0
|
||||
let mut csum = 0;
|
||||
|
||||
// 2:
|
||||
// 3: msg ← base_2b (M, lgw , len1 ) ▷ Convert message to base w
|
||||
let mut msg = base_2b(m, context.lgw, context.len1);
|
||||
|
||||
// 4:
|
||||
// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
|
||||
for item in msg.iter().take(context.len1) {
|
||||
//
|
||||
// 6: csum ← csum + w − 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 <<= (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: for i from 0 to len − 1 do
|
||||
for i in 0..context.len {
|
||||
//
|
||||
// 12: ADRS.setChainAddress(i)
|
||||
adrs.set_chain_address(i);
|
||||
|
||||
// 13: tmp[i] ← chain(sig[i], msg[i], w − 1 − msg[i], PK.seed, ADRS)
|
||||
tmp[i] = chain(
|
||||
context,
|
||||
sig.data[i].clone(),
|
||||
usize::try_from(msg[i]).unwrap(),
|
||||
context.w - 1 - usize::try_from(msg[i]).unwrap(),
|
||||
pk_seed,
|
||||
&adrs,
|
||||
)
|
||||
.expect("chain broek!");
|
||||
|
||||
// 14: end for
|
||||
}
|
||||
|
||||
// 15: wotspkADRS ← ADRS
|
||||
let mut wotspk_adrs = adrs.clone();
|
||||
|
||||
// 16: wotspkADRS.setTypeAndClear(WOTS_PK)
|
||||
wotspk_adrs.set_type_and_clear(WOTS_PK);
|
||||
|
||||
// 17: wotspkADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
|
||||
wotspk_adrs.set_key_pair_address(adrs.get_key_pair_address());
|
||||
|
||||
// 18: pksig ← Tlen (PK.seed, wotspkADRS, tmp)
|
||||
let pk = tlen(context, pk_seed, &wotspk_adrs, &tmp);
|
||||
|
||||
// 19: return pksig
|
||||
WotsPk(pk)
|
||||
}
|
||||
|
||||
#[allow(clippy::similar_names)] // lnode and rnode
|
||||
pub(crate) fn h<N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, lnode: &[u8], rnode: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut hasher = Shake256::default();
|
||||
[pk_seed, &adrs.to_bytes(), lnode, rnode]
|
||||
.iter()
|
||||
.for_each(|item| hasher.update(item));
|
||||
let mut reader = hasher.finalize_xof();
|
||||
let mut result = GenericArray::default();
|
||||
reader.read(&mut result);
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
/// Algorithm 8: `xmss_node(SK.seed, i, z, PK.seed, ADRS)` on page 22.
|
||||
|
|
@ -369,23 +432,62 @@ const _A7: u32 = 0;
|
|||
/// Input: Secret seed `SK.seed`, target node index `i`, target node height `z`, public seed `PK.seed`,
|
||||
/// `address ADRS`. <br>
|
||||
/// Output: n-byte root `node`.
|
||||
const _A8: u32 = 0;
|
||||
// 1: if z > h′ or i ≥ 2^{h −z} then
|
||||
// 2: return NULL
|
||||
// 3: end if
|
||||
// 4: if z = 0 then
|
||||
// 5: ADRS.setTypeAndClear(WOTS_HASH)
|
||||
// 6: ADRS.setKeyPairAddress(i)
|
||||
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
|
||||
// 8: else
|
||||
// 9: lnode ← xmss_node(SK.seed, 2i, z − 1, PK.seed, ADRS)
|
||||
// 10: rnode ← xmss_node(SK.seed, 2i + 1, z − 1, PK.seed, ADRS)
|
||||
// 11: ADRS.setTypeAndClear(TREE)
|
||||
// 12: ADRS.setTreeHeight(z)
|
||||
// 13: ADRS.setTreeIndex(i)
|
||||
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
||||
// 15: end if
|
||||
// 16: return node
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn xmss_node<LEN: ArrayLength, N: ArrayLength>(
|
||||
context: &Context, sk_seed: &[u8], i: u32, z: u32, pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> Option<GenericArray<u8, N>> {
|
||||
let mut adrs = adrs.clone();
|
||||
|
||||
// 1: if z > h′ or i ≥ 2^{h −z} then
|
||||
if (z > context.h_prime) | (i >= 2u32.pow(context.h - z)) {
|
||||
//
|
||||
// 2: return NULL
|
||||
return None;
|
||||
|
||||
// 3: end if
|
||||
}
|
||||
|
||||
// 4: if z = 0 then
|
||||
let node = if z == 0 {
|
||||
//
|
||||
// 5: ADRS.setTypeAndClear(WOTS_HASH)
|
||||
adrs.set_type_and_clear(WOTS_HASH);
|
||||
|
||||
// 6: ADRS.setKeyPairAddress(i)
|
||||
adrs.set_key_pair_address(i.to_be_bytes());
|
||||
|
||||
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
|
||||
wots_pkgen::<LEN, N>(context, sk_seed, pk_seed, &adrs)
|
||||
.0
|
||||
.clone() // TODO revisit
|
||||
|
||||
// 8: else
|
||||
} else {
|
||||
//
|
||||
// 9: lnode ← xmss_node(SK.seed, 2 * i, z − 1, PK.seed, ADRS)
|
||||
let lnode = xmss_node::<LEN, N>(context, sk_seed, 2 * i, z - 1, pk_seed, &adrs)?;
|
||||
|
||||
// 10: rnode ← xmss_node(SK.seed, 2 * i + 1, z − 1, PK.seed, ADRS)
|
||||
let rnode = xmss_node::<LEN, N>(context, sk_seed, 2 * i + 1, z - 1, pk_seed, &adrs)?;
|
||||
|
||||
// 11: ADRS.setTypeAndClear(TREE)
|
||||
adrs.set_type_and_clear(TREE);
|
||||
|
||||
// 12: ADRS.setTreeHeight(z)
|
||||
adrs.set_tree_height(z);
|
||||
|
||||
// 13: ADRS.setTreeIndex(i)
|
||||
adrs.set_tree_index(i);
|
||||
|
||||
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
||||
h(pk_seed, &adrs, &lnode, &rnode)
|
||||
|
||||
// 15: end if
|
||||
};
|
||||
|
||||
// 16: return node
|
||||
Some(node)
|
||||
}
|
||||
|
||||
|
||||
/// Algorithm 9: `xmss_sign(M, SK.seed, idx, PK.seed, ADRS)` on page 23.
|
||||
|
|
|
|||
12
src/lib.rs
12
src/lib.rs
|
|
@ -23,6 +23,8 @@ struct Context {
|
|||
len1: usize,
|
||||
len2: usize,
|
||||
len: usize,
|
||||
h: u32,
|
||||
h_prime: u32,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -40,7 +42,15 @@ macro_rules! functionality {
|
|||
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,
|
||||
h: H,
|
||||
h_prime: H_PRIME,
|
||||
};
|
||||
|
||||
|
||||
fn sign() -> SlhDsaSig<U5, U5, U16> { SlhDsaSig::<U5, U5, U16>::default() }
|
||||
|
|
|
|||
21
src/types.rs
21
src/types.rs
|
|
@ -34,14 +34,17 @@ pub(crate) struct HtSig<N: ArrayLength> {
|
|||
|
||||
|
||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsSig<N: ArrayLength, LEN: ArrayLength> {
|
||||
pub struct WotsSig<LEN: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) data: GenericArray<GenericArray<u8, N>, LEN>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsPk<N: ArrayLength>(pub(crate) GenericArray<u8, N>);
|
||||
|
||||
const WOTS_HASH: u32 = 0;
|
||||
|
||||
pub(crate) const WOTS_HASH: u32 = 0;
|
||||
pub(crate) const WOTS_PK: u32 = 1;
|
||||
const TREE: u32 = 2;
|
||||
pub(crate) const TREE: u32 = 2;
|
||||
const FORS_TREE: u32 = 3;
|
||||
const FORS_ROOTS: u32 = 4;
|
||||
pub(crate) const WOTS_PRF: u32 = 5;
|
||||
|
|
@ -59,7 +62,7 @@ pub struct Adrs {
|
|||
f4: [u8; 4], // type
|
||||
f5: [u8; 4], // key pair address OR padding
|
||||
f6: [u8; 4], // chain address OR padding OR tree height
|
||||
f7: [u8; 4], // hash address OR padding ORtree index OR hash address = 0
|
||||
f7: [u8; 4], // hash address OR padding OR tree index OR hash address = 0
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -78,9 +81,11 @@ impl Adrs {
|
|||
self.f7 = 0u32.to_be_bytes();
|
||||
}
|
||||
|
||||
pub(crate) fn set_hash_address(&mut self, addr: u32) { self.f7 = addr.to_be_bytes(); }
|
||||
pub(crate) fn set_hash_address(&mut self, addr: u32) { self.f7 = addr.to_be_bytes() }
|
||||
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
[self.f0, self.f1, self.f2, self.f3].concat()
|
||||
}
|
||||
pub(crate) fn set_tree_height(&mut self, z: u32) { self.f6 = z.to_be_bytes() }
|
||||
|
||||
pub(crate) fn set_tree_index(&mut self, i: u32) { self.f7 = i.to_be_bytes() }
|
||||
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> { [self.f0, self.f1, self.f2, self.f3].concat() }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue