mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-04 20:03:45 +00:00
1.5 hashes
This commit is contained in:
parent
402cfdd832
commit
3ff32e592a
4 changed files with 116 additions and 114 deletions
126
src/algs.rs
126
src/algs.rs
|
|
@ -1,15 +1,16 @@
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
|
use generic_array::typenum::U33;
|
||||||
use rand_core::CryptoRngCore;
|
use rand_core::CryptoRngCore;
|
||||||
use sha3::{
|
use sha3::{
|
||||||
digest::{ExtendableOutput, Update, XofReader},
|
digest::{ExtendableOutput, Update, XofReader},
|
||||||
Shake256,
|
Shake256,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Adrs, ForsPk, ForsSig, HtSig, SlhDsaSig, SlhPrivateKey, SlhPublicKey, WotsPk, WotsSig, XmssSig,
|
Adrs, ForsPk, ForsSig, HtSig, SlhDsaSig, SlhPrivateKey, SlhPublicKey, WotsPk, WotsSig, XmssSig,
|
||||||
};
|
};
|
||||||
use crate::types::{FORS_PRF, FORS_ROOTS, FORS_TREE, TREE, WOTS_HASH, WOTS_PK, WOTS_PRF};
|
use crate::types::{FORS_PRF, FORS_ROOTS, FORS_TREE, TREE, WOTS_HASH, WOTS_PK, WOTS_PRF};
|
||||||
|
|
||||||
|
|
||||||
/// Algorithm 1: `toInt(X, n)` on page 14.
|
/// Algorithm 1: `toInt(X, n)` on page 14.
|
||||||
/// Convert a byte string to an integer.
|
/// Convert a byte string to an integer.
|
||||||
///
|
///
|
||||||
|
|
@ -116,22 +117,11 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize, baseb: &mut [u64]) {
|
||||||
// 14: return baseb (mutable parameter)
|
// 14: return baseb (mutable parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn shake256_a(input: &[&[u8]], out: &mut [u8]) {
|
||||||
#[must_use]
|
|
||||||
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 = GenericArray::default();
|
reader.read(out);
|
||||||
reader.read(&mut result);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn f<N: ArrayLength>(
|
|
||||||
pk_seed: &[u8], adrs: &Adrs, tmp: &GenericArray<u8, N>,
|
|
||||||
) -> GenericArray<u8, N> {
|
|
||||||
shake256(&[&pk_seed, &adrs.to_32_bytes(), tmp])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -171,7 +161,8 @@ pub(crate) fn chain<N: ArrayLength>(
|
||||||
adrs.set_hash_address(j.try_into().expect("usize->u32 fails")); // TODO: something better than expect?
|
adrs.set_hash_address(j.try_into().expect("usize->u32 fails")); // TODO: something better than expect?
|
||||||
|
|
||||||
// 9: tmp ← F(PK.seed, ADRS, tmp)
|
// 9: tmp ← F(PK.seed, ADRS, tmp)
|
||||||
tmp = f(pk_seed, &adrs, &tmp);
|
//tmp = f(pk_seed, &adrs, &tmp);
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &tmp.clone()], &mut tmp[..]);
|
||||||
|
|
||||||
// 10: end for
|
// 10: end for
|
||||||
}
|
}
|
||||||
|
|
@ -181,23 +172,10 @@ pub(crate) fn chain<N: ArrayLength>(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
|
||||||
pub(crate) fn prf<N: ArrayLength>(
|
|
||||||
pk_seed: &[u8], sk_seed: &[u8], adrs: &[u8],
|
|
||||||
) -> GenericArray<u8, N> {
|
|
||||||
shake256(&[&pk_seed, &adrs, &sk_seed]) // note order
|
|
||||||
} // NOTE ORDER
|
|
||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
|
||||||
pub(crate) fn prf2<N: ArrayLength>(a0: &[u8], b1: &[u8], c2: &[u8]) -> GenericArray<u8, N> {
|
|
||||||
shake256(&[&a0, &b1, &c2])
|
|
||||||
} // NOTE ORDER
|
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn tlen<LEN: ArrayLength, N: ArrayLength>(
|
pub(crate) fn tlen<LEN: ArrayLength, N: ArrayLength>(
|
||||||
pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray<GenericArray<u8, N>, LEN>,
|
pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray<GenericArray<u8, N>, LEN>,
|
||||||
) -> GenericArray<u8, N>
|
) -> GenericArray<u8, N>
|
||||||
where
|
where
|
||||||
{
|
{
|
||||||
let mut hasher = Shake256::default();
|
let mut hasher = Shake256::default();
|
||||||
hasher.update(pk_seed);
|
hasher.update(pk_seed);
|
||||||
|
|
@ -242,7 +220,8 @@ pub(crate) fn wots_pkgen<LEN: ArrayLength, N: ArrayLength>(
|
||||||
sk_adrs.set_chain_address(i);
|
sk_adrs.set_chain_address(i);
|
||||||
|
|
||||||
// 6: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
|
// 6: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
|
||||||
let sk = prf(pk_seed, sk_seed, &sk_adrs.to_32_bytes());
|
let mut sk = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &sk_adrs.to_32_bytes(), sk_seed], &mut sk); // Note spec swaps latter two parms
|
||||||
|
|
||||||
// 7: ADRS.setChainAddress(i)
|
// 7: ADRS.setChainAddress(i)
|
||||||
adrs.set_chain_address(i);
|
adrs.set_chain_address(i);
|
||||||
|
|
@ -333,7 +312,8 @@ pub(crate) fn wots_sign<LEN: ArrayLength, N: ArrayLength>(
|
||||||
sk_addrs.set_chain_address(i as u32);
|
sk_addrs.set_chain_address(i as u32);
|
||||||
|
|
||||||
// 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
|
// 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i
|
||||||
let sk = prf(pk_seed, sk_seed, &sk_addrs.to_32_bytes());
|
let mut sk = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &sk_addrs.to_32_bytes(), sk_seed], &mut sk);
|
||||||
|
|
||||||
// 18: ADRS.setChainAddress(i)
|
// 18: ADRS.setChainAddress(i)
|
||||||
adrs.set_chain_address(i as u32);
|
adrs.set_chain_address(i as u32);
|
||||||
|
|
@ -408,7 +388,7 @@ pub(crate) fn wots_pk_from_sig<LEN: ArrayLength, N: ArrayLength>(
|
||||||
pk_seed,
|
pk_seed,
|
||||||
&adrs,
|
&adrs,
|
||||||
)
|
)
|
||||||
.expect("chain broke2!");
|
.expect("chain broke2!");
|
||||||
|
|
||||||
// 14: end for
|
// 14: end for
|
||||||
}
|
}
|
||||||
|
|
@ -430,21 +410,6 @@ pub(crate) fn wots_pk_from_sig<LEN: ArrayLength, N: ArrayLength>(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(clippy::similar_names)] // lnode and rnode
|
|
||||||
pub(crate) fn h<N: ArrayLength>(
|
|
||||||
pk_seed: &[u8], adrs: &[u8], lnode: &[u8], rnode: &[u8],
|
|
||||||
) -> GenericArray<u8, N> {
|
|
||||||
let mut hasher = Shake256::default();
|
|
||||||
[pk_seed, adrs, 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.
|
/// Algorithm 8: `xmss_node(SK.seed, i, z, PK.seed, ADRS)` on page 22.
|
||||||
/// Compute the root of a Merkle subtree of WOTS+ public keys.
|
/// Compute the root of a Merkle subtree of WOTS+ public keys.
|
||||||
///
|
///
|
||||||
|
|
@ -478,7 +443,7 @@ pub(crate) fn xmss_node<H: ArrayLength, HP: ArrayLength, LEN: ArrayLength, N: Ar
|
||||||
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
|
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
|
||||||
wots_pkgen::<LEN, N>(sk_seed, pk_seed, &adrs).0.clone() // TODO remove clone?
|
wots_pkgen::<LEN, N>(sk_seed, pk_seed, &adrs).0.clone() // TODO remove clone?
|
||||||
|
|
||||||
// 8: else
|
// 8: else
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// 9: lnode ← xmss_node(SK.seed, 2 * i, z − 1, PK.seed, ADRS)
|
// 9: lnode ← xmss_node(SK.seed, 2 * i, z − 1, PK.seed, ADRS)
|
||||||
|
|
@ -497,7 +462,9 @@ pub(crate) fn xmss_node<H: ArrayLength, HP: ArrayLength, LEN: ArrayLength, N: Ar
|
||||||
adrs.set_tree_index(i);
|
adrs.set_tree_index(i);
|
||||||
|
|
||||||
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &lnode, &rnode)
|
let mut node = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &lnode, &rnode], &mut node);
|
||||||
|
node
|
||||||
|
|
||||||
// 15: end if
|
// 15: end if
|
||||||
};
|
};
|
||||||
|
|
@ -590,14 +557,16 @@ pub(crate) fn xmss_pk_from_sig<HP: ArrayLength, LEN: ArrayLength, N: ArrayLength
|
||||||
|
|
||||||
// 11: if idx/2^k is even then
|
// 11: if idx/2^k is even then
|
||||||
#[allow(clippy::if_not_else)] // Follows the algorithm as written
|
#[allow(clippy::if_not_else)] // Follows the algorithm as written
|
||||||
let node_1 = if ((idx >> k) & 1) == 0 {
|
let node_1 = if ((idx >> k) & 1) == 0 {
|
||||||
//
|
//
|
||||||
// 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2)
|
// 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2)
|
||||||
let tmp = adrs.get_tree_index() / 2;
|
let tmp = adrs.get_tree_index() / 2;
|
||||||
adrs.set_tree_index(tmp);
|
adrs.set_tree_index(tmp);
|
||||||
|
|
||||||
// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ AUTH[k])
|
// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ AUTH[k])
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &node_0, &auth[k as usize])
|
let mut node_1 = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &node_0, &auth[k as usize]], &mut node_1);
|
||||||
|
node_1
|
||||||
|
|
||||||
// 14: else
|
// 14: else
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -607,7 +576,9 @@ pub(crate) fn xmss_pk_from_sig<HP: ArrayLength, LEN: ArrayLength, N: ArrayLength
|
||||||
adrs.set_tree_index(tmp);
|
adrs.set_tree_index(tmp);
|
||||||
|
|
||||||
// 16: node[1] ← H(PK.seed, ADRS, AUTH[k] ∥ node[0])
|
// 16: node[1] ← H(PK.seed, ADRS, AUTH[k] ∥ node[0])
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &auth[k as usize], &node_0)
|
let mut node_1 = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &auth[k as usize], &node_0], &mut node_1);
|
||||||
|
node_1
|
||||||
|
|
||||||
// 17: end if
|
// 17: end if
|
||||||
};
|
};
|
||||||
|
|
@ -662,7 +633,8 @@ pub(crate) fn ht_sign<
|
||||||
for j in 1..D::to_u32() {
|
for j in 1..D::to_u32() {
|
||||||
//
|
//
|
||||||
// 8: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
|
// 8: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
|
||||||
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(HP::to_u32())).map_err(|_| "Alg11: oversized idx leaf")?;
|
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(HP::to_u32()))
|
||||||
|
.map_err(|_| "Alg11: oversized idx leaf")?;
|
||||||
|
|
||||||
// 9: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
// 9: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
||||||
idx_tree >>= HP::to_u32();
|
idx_tree >>= HP::to_u32();
|
||||||
|
|
@ -726,7 +698,9 @@ pub(crate) fn ht_verify<D: ArrayLength, HP: ArrayLength, LEN: ArrayLength, N: Ar
|
||||||
//
|
//
|
||||||
// 7: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
|
// 7: idx_leaf ← idx_tree mod 2^{h′} ▷ h′ least significant bits of idx_tree
|
||||||
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(HP::to_u32()));
|
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(HP::to_u32()));
|
||||||
if idx_leaf.is_err() {return false};
|
if idx_leaf.is_err() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
let idx_leaf = idx_leaf.unwrap();
|
let idx_leaf = idx_leaf.unwrap();
|
||||||
|
|
||||||
// 8: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
// 8: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
||||||
|
|
@ -778,7 +752,9 @@ pub(crate) fn fors_sk_gen<N: ArrayLength>(
|
||||||
sk_adrs.set_tree_index(idx);
|
sk_adrs.set_tree_index(idx);
|
||||||
|
|
||||||
// 5: return PRF(PK.seed, SK.seed, skADRS)
|
// 5: return PRF(PK.seed, SK.seed, skADRS)
|
||||||
prf(pk_seed, sk_seed, &sk_adrs.to_32_bytes())
|
let mut res = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &sk_adrs.to_32_bytes(), sk_seed], &mut res); // Note the spec swaps latter two parms
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -807,7 +783,7 @@ pub(crate) fn fors_node<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
let node = if z == 0 {
|
let node = if z == 0 {
|
||||||
//
|
//
|
||||||
// 5: sk ← fors_SKgen(SK.seed, PK.seed, ADRS, i)
|
// 5: sk ← fors_SKgen(SK.seed, PK.seed, ADRS, i)
|
||||||
let sk = fors_sk_gen(sk_seed, pk_seed, &adrs, i);
|
let sk: GenericArray<u8, N> = fors_sk_gen(sk_seed, pk_seed, &adrs, i);
|
||||||
|
|
||||||
// 6: ADRS.setTreeHeight(0)
|
// 6: ADRS.setTreeHeight(0)
|
||||||
adrs.set_tree_height(0);
|
adrs.set_tree_height(0);
|
||||||
|
|
@ -816,7 +792,9 @@ pub(crate) fn fors_node<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
adrs.set_tree_index(i);
|
adrs.set_tree_index(i);
|
||||||
|
|
||||||
// 8: node ← F(PK.seed, ADRS, sk)
|
// 8: node ← F(PK.seed, ADRS, sk)
|
||||||
f(pk_seed, &adrs, &sk)
|
let mut node = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &sk], &mut node);
|
||||||
|
node
|
||||||
|
|
||||||
// 9: else
|
// 9: else
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -834,7 +812,9 @@ pub(crate) fn fors_node<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
adrs.set_tree_index(i);
|
adrs.set_tree_index(i);
|
||||||
|
|
||||||
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
// 14: node ← H(PK.seed, ADRS, lnode ∥ rnode)
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &lnode, &rnode)
|
let mut node = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &lnode, &rnode], &mut node);
|
||||||
|
node
|
||||||
|
|
||||||
// 15: end if
|
// 15: end if
|
||||||
};
|
};
|
||||||
|
|
@ -933,7 +913,8 @@ pub(crate) fn fors_pk_from_sig<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
adrs.set_tree_index(i * 2u32.pow(A::to_u32()) + indices[i as usize] as u32);
|
adrs.set_tree_index(i * 2u32.pow(A::to_u32()) + indices[i as usize] as u32);
|
||||||
|
|
||||||
// 6: node[0] ← F(PK.seed, ADRS, sk)
|
// 6: node[0] ← F(PK.seed, ADRS, sk)
|
||||||
let mut node_0 = f(pk_seed, &adrs, &sk);
|
let mut node_0 = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &sk], &mut node_0);
|
||||||
|
|
||||||
// 7:
|
// 7:
|
||||||
// 8: auth ← SIGFORS.getAUTH(i) ▷ SIGFORS [(i · (a + 1) + 1) · n : (i + 1) · (a + 1) · n]
|
// 8: auth ← SIGFORS.getAUTH(i) ▷ SIGFORS [(i · (a + 1) + 1) · n : (i + 1) · (a + 1) · n]
|
||||||
|
|
@ -953,7 +934,9 @@ pub(crate) fn fors_pk_from_sig<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
adrs.set_tree_index(tmp);
|
adrs.set_tree_index(tmp);
|
||||||
|
|
||||||
// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ auth[j])
|
// 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ auth[j])
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &node_0, &auth.tree[j as usize])
|
let mut node_1 = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &node_0, &auth.tree[j as usize]], &mut node_1);
|
||||||
|
node_1
|
||||||
|
|
||||||
// 14: else
|
// 14: else
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -963,7 +946,9 @@ pub(crate) fn fors_pk_from_sig<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
adrs.set_tree_index(tmp);
|
adrs.set_tree_index(tmp);
|
||||||
|
|
||||||
// 16: node[1] ← H(PK.seed, ADRS, auth[j] ∥ node[0])
|
// 16: node[1] ← H(PK.seed, ADRS, auth[j] ∥ node[0])
|
||||||
h(pk_seed, &adrs.to_32_bytes(), &auth.tree[j as usize], &node_0)
|
let mut node_1 = GenericArray::default();
|
||||||
|
shake256_a(&[pk_seed, &adrs.to_32_bytes(), &auth.tree[j as usize], &node_0], &mut node_1);
|
||||||
|
node_1
|
||||||
|
|
||||||
// 17: end if
|
// 17: end if
|
||||||
};
|
};
|
||||||
|
|
@ -990,7 +975,13 @@ pub(crate) fn fors_pk_from_sig<A: ArrayLength, K: ArrayLength, N: ArrayLength>(
|
||||||
fors_pk_adrs.set_key_pair_address(adrs.get_key_pair_address());
|
fors_pk_adrs.set_key_pair_address(adrs.get_key_pair_address());
|
||||||
|
|
||||||
// 25: pk ← Tk(PK.seed, forspkADRS, root)
|
// 25: pk ← Tk(PK.seed, forspkADRS, root)
|
||||||
let pk = tlen(pk_seed, &fors_pk_adrs, &root);
|
let mut pk = GenericArray::default(); // TODO: UGLY UGLY UGLY!!
|
||||||
|
let mut root_refs: GenericArray<&[u8], U33> = GenericArray::default();
|
||||||
|
root_refs[0] = &pk_seed;
|
||||||
|
let binding = fors_pk_adrs.to_32_bytes();
|
||||||
|
root_refs[1] = &binding;
|
||||||
|
root.iter().enumerate().for_each(|(a, b)| root_refs[a + 2] = b);
|
||||||
|
shake256_a(&root_refs[0..K::to_usize() + 2], &mut pk);
|
||||||
|
|
||||||
// 26: return pk;
|
// 26: return pk;
|
||||||
ForsPk { key: pk }
|
ForsPk { key: pk }
|
||||||
|
|
@ -1080,7 +1071,8 @@ pub(crate) fn slh_sign_with_rng<
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7: R ← PRF_msg(SK.prf, opt_rand, M) ▷ Generate randomizer
|
// 7: R ← PRF_msg(SK.prf, opt_rand, M) ▷ Generate randomizer
|
||||||
let r = prf2(&sk.sk_prf, &opt_rand, m);
|
let mut r = GenericArray::default();
|
||||||
|
shake256_a(&[&sk.sk_prf, &opt_rand, m], &mut r);
|
||||||
|
|
||||||
|
|
||||||
// 8: SIG ← R
|
// 8: SIG ← R
|
||||||
|
|
@ -1089,7 +1081,8 @@ pub(crate) fn slh_sign_with_rng<
|
||||||
|
|
||||||
// 9:
|
// 9:
|
||||||
// 10: digest ← H_msg(R, PK.seed, PK.root, M) ▷ Compute message digest
|
// 10: digest ← H_msg(R, PK.seed, PK.root, M) ▷ Compute message digest
|
||||||
let digest = h::<M>(&r, &sk.pk_seed, &sk.pk_root, m);
|
let mut digest: generic_array::GenericArray<u8, M> = GenericArray::default();
|
||||||
|
shake256_a(&[&r, &sk.pk_seed, &sk.pk_root, m], &mut digest);
|
||||||
|
|
||||||
|
|
||||||
// 11: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
// 11: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
||||||
|
|
@ -1169,7 +1162,7 @@ pub(crate) fn slh_verify<
|
||||||
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
|
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
|
||||||
// 2: return false
|
// 2: return false
|
||||||
// 3: end if
|
// 3: end if
|
||||||
// TODO: THIS FUNCTION PROBABLY WANTS A BYTE ARRAY SIGNATURE, THEN DESERIALIZE (??)
|
// The above size is performed in the wrapper/adapter deserialize function
|
||||||
|
|
||||||
// 4: ADRS ← toByte(0, 32)
|
// 4: ADRS ← toByte(0, 32)
|
||||||
let mut adrs = Adrs::default();
|
let mut adrs = Adrs::default();
|
||||||
|
|
@ -1185,7 +1178,8 @@ pub(crate) fn slh_verify<
|
||||||
|
|
||||||
// 8:
|
// 8:
|
||||||
// 9: digest ← Hmsg(R, PK.seed, PK.root, M) ▷ Compute message digest
|
// 9: digest ← Hmsg(R, PK.seed, PK.root, M) ▷ Compute message digest
|
||||||
let digest = h::<M>(r, &pk.pk_seed, &pk.pk_root, m);
|
let mut digest: generic_array::GenericArray<u8, M> = GenericArray::default();
|
||||||
|
shake256_a(&[&r, &pk.pk_seed, &pk.pk_root, m], &mut digest);
|
||||||
|
|
||||||
// 10: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
// 10: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
||||||
let index1 = (K::to_usize() * A::to_usize()).div_ceil(8);
|
let index1 = (K::to_usize() * A::to_usize()).div_ceil(8);
|
||||||
|
|
|
||||||
26
src/lib.rs
26
src/lib.rs
|
|
@ -3,14 +3,12 @@
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
// TODO
|
// TODO
|
||||||
// 1. Get one instance working (or at least not erroring)
|
// 1. General clean-up
|
||||||
// 3. revisit/clean hash functions
|
// 2. revisit/clean hash functions
|
||||||
|
// 3. Doc, of course!
|
||||||
|
|
||||||
//! TKTK crate doc
|
//! TKTK crate doc
|
||||||
|
|
||||||
//extern crate alloc;
|
|
||||||
//extern crate core; // TODO: remove (with vecs)
|
|
||||||
|
|
||||||
mod algs;
|
mod algs;
|
||||||
mod test;
|
mod test;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
@ -30,7 +28,6 @@ macro_rules! functionality {
|
||||||
|
|
||||||
/// blah
|
/// blah
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
|
||||||
pub fn slh_keygen_with_rng(
|
pub fn slh_keygen_with_rng(
|
||||||
rng: &mut impl CryptoRngCore,
|
rng: &mut impl CryptoRngCore,
|
||||||
) -> Result<(SlhPrivateKey<N>, SlhPublicKey<N>), &'static str> {
|
) -> Result<(SlhPrivateKey<N>, SlhPublicKey<N>), &'static str> {
|
||||||
|
|
@ -39,20 +36,19 @@ macro_rules! functionality {
|
||||||
|
|
||||||
/// blah
|
/// blah
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
|
||||||
pub fn slh_sign_with_rng(
|
pub fn slh_sign_with_rng(
|
||||||
rng: &mut impl CryptoRngCore, m: &[u8], sk: &SlhPrivateKey<N>, randomize: bool,
|
rng: &mut impl CryptoRngCore, m: &[u8], sk: &SlhPrivateKey<N>, randomize: bool,
|
||||||
) -> Result<SlhDsaSig<A, D, HP, K, Sum<Prod<U2, N>, U3>, N>, &'static str> {
|
) -> Result<[u8; SIG_LEN], &'static str> {
|
||||||
crate::algs::slh_sign_with_rng::<A, D, H, HP, K, Sum<Prod<U2, N>, U3>, M, N>(
|
let sig = crate::algs::slh_sign_with_rng::<A, D, H, HP, K, Sum<Prod<U2, N>, U3>, M, N>(rng, &m, &sk, randomize);
|
||||||
rng, &m, &sk, randomize,
|
sig.map(|s| s.deserialize())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// blah
|
/// blah
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn slh_verify(
|
pub fn slh_verify(
|
||||||
m: &[u8], sig: &SlhDsaSig<A, D, HP, K, Sum<Prod<U2, N>, U3>, N>, pk: &SlhPublicKey<N>,
|
m: &[u8], sig_bytes: &[u8; SIG_LEN], pk: &SlhPublicKey<N>
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let sig = SlhDsaSig::<A, D, HP, K, Sum<Prod<U2, N>, U3>, N>::serialize(sig_bytes);
|
||||||
crate::algs::slh_verify::<A, D, H, HP, K, Sum<Prod<U2, N>, U3>, M, N>(&m, &sig, &pk)
|
crate::algs::slh_verify::<A, D, H, HP, K, Sum<Prod<U2, N>, U3>, M, N>(&m, &sig, &pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,9 +67,9 @@ macro_rules! functionality {
|
||||||
let sig = slh_sign_with_rng(&mut rng, &message, &sk, false).unwrap();
|
let sig = slh_sign_with_rng(&mut rng, &message, &sk, false).unwrap();
|
||||||
let result = slh_verify(&message, &sig, &pk);
|
let result = slh_verify(&message, &sig, &pk);
|
||||||
assert_eq!(result, true, "Signature failed to verify");
|
assert_eq!(result, true, "Signature failed to verify");
|
||||||
message[3] = i + 1 as u8;
|
message[3] = (i + 1) as u8;
|
||||||
let result = slh_verify(&message, &sig, &pk);
|
let result = slh_verify(&message, &sig, &pk);
|
||||||
assert_eq!(result, false, "Signature should not have verifed");
|
assert_eq!(result, false, "Signature should not have verified");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +89,7 @@ pub mod slh_dsa_sha2_128s {
|
||||||
type K = U14;
|
type K = U14;
|
||||||
type M = U30;
|
type M = U30;
|
||||||
//const PK_LEN: usize = 32;
|
//const PK_LEN: usize = 32;
|
||||||
//const SIG_LEN: usize = 7856;
|
const SIG_LEN: usize = 7856;
|
||||||
//const SK_LEN: usize = 0000;
|
//const SK_LEN: usize = 0000;
|
||||||
|
|
||||||
functionality!();
|
functionality!();
|
||||||
|
|
|
||||||
31
src/test.rs
31
src/test.rs
File diff suppressed because one or more lines are too long
47
src/types.rs
47
src/types.rs
|
|
@ -26,8 +26,9 @@ impl<
|
||||||
N: ArrayLength,
|
N: ArrayLength,
|
||||||
> SlhDsaSig<A, D, HP, K, LEN, N>
|
> SlhDsaSig<A, D, HP, K, LEN, N>
|
||||||
{
|
{
|
||||||
pub fn deser(self, out: &mut [u8]) {
|
pub fn deserialize<const SIG_LEN: usize>(self) -> [u8; SIG_LEN] {
|
||||||
assert_eq!(
|
let mut out = [0u8; SIG_LEN];
|
||||||
|
debug_assert_eq!(
|
||||||
out.len(),
|
out.len(),
|
||||||
N::to_usize() + // randomness
|
N::to_usize() + // randomness
|
||||||
N::to_usize() * K::to_usize() + K::to_usize() * A::to_usize() * N::to_usize() + // ForsSig
|
N::to_usize() * K::to_usize() + K::to_usize() * A::to_usize() * N::to_usize() + // ForsSig
|
||||||
|
|
@ -35,10 +36,6 @@ impl<
|
||||||
);
|
);
|
||||||
out[0..N::to_usize()].copy_from_slice(&self.randomness);
|
out[0..N::to_usize()].copy_from_slice(&self.randomness);
|
||||||
let mut start = N::to_usize();
|
let mut start = N::to_usize();
|
||||||
// for k in 0..K::to_usize() {
|
|
||||||
// out[start..(start+N::to_usize())].copy_from_slice(&self.fors_sig.private_key_value[k]);
|
|
||||||
// start += N::to_usize();
|
|
||||||
// }
|
|
||||||
for k in 0..K::to_usize() {
|
for k in 0..K::to_usize() {
|
||||||
out[start..(start + N::to_usize())]
|
out[start..(start + N::to_usize())]
|
||||||
.copy_from_slice(&self.fors_sig.private_key_value[k]);
|
.copy_from_slice(&self.fors_sig.private_key_value[k]);
|
||||||
|
|
@ -62,9 +59,47 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_assert_eq!(start, out.len());
|
debug_assert_eq!(start, out.len());
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize(bytes: &[u8]) -> Self {
|
||||||
|
debug_assert_eq!(
|
||||||
|
bytes.len(),
|
||||||
|
N::to_usize() + // randomness
|
||||||
|
N::to_usize() * K::to_usize() + K::to_usize() * A::to_usize() * N::to_usize() + // ForsSig
|
||||||
|
D::to_usize() * (HP::to_usize() * N::to_usize() + LEN::to_usize() * N::to_usize())
|
||||||
|
);
|
||||||
|
let mut output = Self::default();
|
||||||
|
output.randomness.copy_from_slice(&bytes[0..N::to_usize()]);
|
||||||
|
let mut start = N::to_usize();
|
||||||
|
for k in 0..K::to_usize() {
|
||||||
|
output.fors_sig.private_key_value[k]
|
||||||
|
.copy_from_slice(&bytes[start..(start + N::to_usize())]);
|
||||||
|
start += N::to_usize();
|
||||||
|
for a in 0..A::to_usize() {
|
||||||
|
output.fors_sig.auth[k].tree[a]
|
||||||
|
.copy_from_slice(&bytes[start..(start + N::to_usize())]);
|
||||||
|
start += N::to_usize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for d in 0..D::to_usize() {
|
||||||
|
for len in 0..LEN::to_usize() {
|
||||||
|
output.ht_sig.xmss_sigs[d].sig_wots.data[len]
|
||||||
|
.copy_from_slice(&bytes[start..(start + N::to_usize())]);
|
||||||
|
start += N::to_usize();
|
||||||
|
}
|
||||||
|
for hp in 0..HP::to_usize() {
|
||||||
|
output.ht_sig.xmss_sigs[d].auth[hp]
|
||||||
|
.copy_from_slice(&bytes[start..(start + N::to_usize())]);
|
||||||
|
start += N::to_usize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_assert_eq!(start, bytes.len());
|
||||||
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||||
pub struct SlhPublicKey<N: ArrayLength> {
|
pub struct SlhPublicKey<N: ArrayLength> {
|
||||||
pub(crate) pk_seed: GenericArray<u8, N>,
|
pub(crate) pk_seed: GenericArray<u8, N>,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue