mirror of
https://github.com/saymrwulf/fips205-source.git
synced 2026-09-03 19:53:49 +00:00
unwound generic-array
This commit is contained in:
parent
aaf3b57066
commit
f4bd328bf1
9 changed files with 472 additions and 544 deletions
76
src/fors.rs
76
src/fors.rs
|
|
@ -1,7 +1,6 @@
|
|||
use crate::hashers::Hashers;
|
||||
use crate::helpers;
|
||||
use crate::types::{Adrs, ForsPk, ForsSig, FORS_PRF, FORS_ROOTS};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use crate::types::{Adrs, ForsPk, ForsSig, FORS_PRF, FORS_ROOTS, Auth};
|
||||
|
||||
|
||||
/// Algorithm 13: `fors_SKgen(SK.seed, PK.seed, ADRS, idx)` on page 29.
|
||||
|
|
@ -10,9 +9,9 @@ use generic_array::{ArrayLength, GenericArray};
|
|||
/// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`, secret key index `idx`. <br>
|
||||
/// Output: n-byte FORS private-key value.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn fors_sk_gen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
|
||||
pub(crate) fn fors_sk_gen<const K: usize, const LEN: usize, const M: usize, const N: usize>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs, idx: u32,
|
||||
) -> GenericArray<u8, N> {
|
||||
) -> [u8; N] {
|
||||
// 1: skADRS ← ADRS ▷ Copy address to create key generation address
|
||||
let mut sk_adrs = adrs.clone();
|
||||
|
||||
|
|
@ -38,18 +37,19 @@ pub(crate) fn fors_sk_gen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: A
|
|||
/// Output: n-byte root node.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn fors_node<
|
||||
A: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sk_seed: &[u8], i: u32, z: u32, pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> Result<GenericArray<u8, N>, &'static str> {
|
||||
) -> Result<[u8; N], &'static str> {
|
||||
let mut adrs = adrs.clone();
|
||||
let (a32, k32) = (u32::try_from(A).unwrap(), u32::try_from(K).unwrap());
|
||||
|
||||
// 1: if z > a or i ≥ k · 2^(a−z) then
|
||||
if (z > A::to_u32()) | (i > K::to_u32() * 2u32.pow(A::to_u32() - z)) {
|
||||
if (z > a32) | (i > k32 * 2u32.pow(a32 - z)) {
|
||||
//
|
||||
// 2: return NULL
|
||||
return Err("Alg14 fails");
|
||||
|
|
@ -61,7 +61,7 @@ pub(crate) fn fors_node<
|
|||
let node = if z == 0 {
|
||||
//
|
||||
// 5: sk ← fors_SKgen(SK.seed, PK.seed, ADRS, i)
|
||||
let sk: GenericArray<u8, N> = fors_sk_gen(hashers, sk_seed, pk_seed, &adrs, i);
|
||||
let sk: [u8; N] = fors_sk_gen(hashers, sk_seed, pk_seed, &adrs, i);
|
||||
|
||||
// 6: ADRS.setTreeHeight(0)
|
||||
adrs.set_tree_height(0);
|
||||
|
|
@ -106,23 +106,24 @@ pub(crate) fn fors_node<
|
|||
/// Output: FORS signature `SIG_FORS`.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn fors_sign<
|
||||
A: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, md: &[u8], sk_seed: &[u8], adrs: &Adrs, pk_seed: &[u8],
|
||||
) -> Result<ForsSig<A, K, N>, &'static str> {
|
||||
// 1: SIG_FORS = NULL ▷ Initialize SIG_FORS as a zero-length byte string
|
||||
let mut sig_fors = ForsSig::default();
|
||||
let mut sig_fors = ForsSig { private_key_value: [[0u8; N]; K], auth: core::array::from_fn(|_| Auth{ tree: [[0u8; N]; A] }) }; //ForsSig::default();
|
||||
let (a32, k32) = (u32::try_from(A).unwrap(), u32::try_from(K).unwrap());
|
||||
|
||||
// 2: indices ← base_2^b(md, a, k)
|
||||
let mut indices: GenericArray<u32, K> = GenericArray::default();
|
||||
helpers::base_2b(md, A::to_u32(), K::to_u32(), &mut indices);
|
||||
let mut indices = [0u32; K];
|
||||
helpers::base_2b(md, a32, k32, &mut indices);
|
||||
|
||||
// 3: for i from 0 to k − 1 do ▷ Compute signature elements
|
||||
for i in 0..K::to_u32() {
|
||||
for i in 0..k32 {
|
||||
//
|
||||
// 4: SIG_FORS ← SIG_FORS ∥ fors_SKgen(SK.seed, PK.seed, ADRS, i · 2^a + indices[i])
|
||||
sig_fors.private_key_value[i as usize] = fors_sk_gen::<K, LEN, M, N>(
|
||||
|
|
@ -130,12 +131,12 @@ pub(crate) fn fors_sign<
|
|||
sk_seed,
|
||||
pk_seed,
|
||||
adrs,
|
||||
i * 2u32.pow(A::to_u32()) + indices[i as usize],
|
||||
i * 2u32.pow(a32) + indices[i as usize],
|
||||
);
|
||||
|
||||
// 5:
|
||||
// 6: for j from 0 to a − 1 do ▷ Compute auth path
|
||||
for j in 0..A::to_u32() {
|
||||
for j in 0..a32 {
|
||||
//
|
||||
// 7: s ← indices[i]/2^j xor 1
|
||||
let s = (indices[i as usize] >> j) ^ 1;
|
||||
|
|
@ -144,7 +145,7 @@ pub(crate) fn fors_sign<
|
|||
sig_fors.auth[i as usize].tree[j as usize] = fors_node::<A, K, LEN, M, N>(
|
||||
hashers,
|
||||
sk_seed,
|
||||
i * 2u32.pow(A::to_u32() - j) + s,
|
||||
i * 2u32.pow(a32 - j) + s,
|
||||
j,
|
||||
pk_seed,
|
||||
adrs,
|
||||
|
|
@ -169,34 +170,37 @@ pub(crate) fn fors_sign<
|
|||
///
|
||||
/// Input: FORS signature `SIG_FORS`, message digest `md`, public seed `PK.seed`, address `ADRS`. <br>
|
||||
/// Output: FORS public key.
|
||||
#[allow(clippy::similar_names)]
|
||||
pub(crate) fn fors_pk_from_sig<
|
||||
A: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sig_fors: &ForsSig<A, K, N>, md: &[u8], pk_seed: &[u8],
|
||||
adrs: &Adrs,
|
||||
) -> ForsPk<N> {
|
||||
let mut adrs = adrs.clone();
|
||||
|
||||
let (a32, k32) = (u32::try_from(A).unwrap(), u32::try_from(K).unwrap());
|
||||
|
||||
// 1: indices ← base_2^b(md, a, k)
|
||||
let mut indices: GenericArray<u32, K> = GenericArray::default();
|
||||
helpers::base_2b(md, A::to_u32(), K::to_u32(), &mut indices);
|
||||
let mut indices = [0u32; K];
|
||||
helpers::base_2b(md, a32, k32, &mut indices);
|
||||
|
||||
// 2: for i from 0 to k − 1 do
|
||||
let mut root: GenericArray<GenericArray<u8, N>, K> = GenericArray::default();
|
||||
for i in 0..K::to_u32() {
|
||||
let mut root = [[0u8; N]; K];
|
||||
for i in 0..k32 {
|
||||
//
|
||||
// 3: sk ← SIG_FORS.getSK(i) ▷ SIG_FORS [i · (a + 1) · n : (i · (a + 1) + 1) · n]
|
||||
let sk = sig_fors.private_key_value[i as usize].clone();
|
||||
let sk = sig_fors.private_key_value[i as usize];
|
||||
|
||||
// 4: ADRS.setTreeHeight(0) ▷ Compute leaf
|
||||
adrs.set_tree_height(0);
|
||||
|
||||
// 5: ADRS.setTreeIndex(i · 2^a + indices[i])
|
||||
adrs.set_tree_index(i * 2u32.pow(A::to_u32()) + indices[i as usize]);
|
||||
adrs.set_tree_index(i * 2u32.pow(a32) + indices[i as usize]);
|
||||
|
||||
// 6: node[0] ← F(PK.seed, ADRS, sk)
|
||||
let mut node_0 = (hashers.f)(pk_seed, &adrs, &sk);
|
||||
|
|
@ -206,7 +210,7 @@ pub(crate) fn fors_pk_from_sig<
|
|||
let auth = sig_fors.auth[i as usize].clone();
|
||||
|
||||
// 9: for j from 0 to a − 1 do ▷ Compute root from leaf and AUTH
|
||||
for j in 0..A::to_u32() {
|
||||
for j in 0..a32 {
|
||||
//
|
||||
// 10: ADRS.setTreeHeight(j + 1)
|
||||
adrs.set_tree_height(j + 1);
|
||||
|
|
|
|||
213
src/hashers.rs
213
src/hashers.rs
|
|
@ -1,19 +1,16 @@
|
|||
use crate::types::Adrs;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
|
||||
// Holds hasher function references; constructed by each wrapper
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) struct Hashers<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) h_msg: fn(&[u8], &[u8], &[u8], &[u8]) -> GenericArray<u8, M>,
|
||||
pub(crate) prf: fn(&[u8], &[u8], &Adrs) -> GenericArray<u8, N>,
|
||||
pub(crate) prf_msg: fn(&[u8], &[u8], &[u8]) -> GenericArray<u8, N>,
|
||||
pub(crate) f: fn(&[u8], &Adrs, &[u8]) -> GenericArray<u8, N>,
|
||||
pub(crate) h: fn(&[u8], &Adrs, &[u8], &[u8]) -> GenericArray<u8, N>,
|
||||
pub(crate) t_l:
|
||||
fn(&[u8], &Adrs, &GenericArray<GenericArray<u8, N>, LEN>) -> GenericArray<u8, N>,
|
||||
pub(crate) t_len:
|
||||
fn(&[u8], &Adrs, &GenericArray<GenericArray<u8, N>, K>) -> GenericArray<u8, N>,
|
||||
pub(crate) struct Hashers<const K: usize, const LEN: usize, const M: usize, const N: usize> {
|
||||
pub(crate) h_msg: fn(&[u8], &[u8], &[u8], &[u8]) -> [u8; M],
|
||||
pub(crate) prf: fn(&[u8], &[u8], &Adrs) -> [u8; N],
|
||||
pub(crate) prf_msg: fn(&[u8], &[u8], &[u8]) -> [u8; N],
|
||||
pub(crate) f: fn(&[u8], &Adrs, &[u8]) -> [u8; N],
|
||||
pub(crate) h: fn(&[u8], &Adrs, &[u8], &[u8]) -> [u8; N],
|
||||
pub(crate) t_l: fn(&[u8], &Adrs, &[[u8; N]; LEN]) -> [u8; N],
|
||||
pub(crate) t_len: fn(&[u8], &Adrs, &[[u8; N]; K]) -> [u8; N],
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -27,7 +24,6 @@ pub(crate) struct Hashers<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: A
|
|||
))]
|
||||
pub(crate) mod shake {
|
||||
use crate::types::Adrs;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||
use sha3::Shake256;
|
||||
|
||||
|
|
@ -41,60 +37,54 @@ pub(crate) mod shake {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn h_msg<M: ArrayLength>(
|
||||
pub(crate) fn h_msg<const M: usize>(
|
||||
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, M> {
|
||||
let mut digest: GenericArray<u8, M> = GenericArray::default();
|
||||
) -> [u8; M] {
|
||||
let mut digest = [0u8; M];
|
||||
shake256(&[r, pk_seed, pk_root, m], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::similar_names)] // pk_seed and sk_seed
|
||||
pub(crate) fn prf<N: ArrayLength>(
|
||||
pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs,
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn prf<const N: usize>(pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
shake256(&[pk_seed, &adrs.to_32_bytes(), sk_seed], &mut digest); // Note that the spec swaps order of last to params
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn prf_msg<N: ArrayLength>(
|
||||
sk_prf: &[u8], opt_rand: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
shake256(&[sk_prf, opt_rand, m], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn f<N: ArrayLength>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn f<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
shake256(&[pk_seed, &adrs.to_32_bytes(), m1], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn h<N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn h<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
shake256(&[pk_seed, &adrs.to_32_bytes(), m1, m2], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
// Perhaps there is a more elegant way to covert ml into list of bytes
|
||||
pub(crate) fn t_l<X: ArrayLength, Y: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray<GenericArray<u8, Y>, X>,
|
||||
) -> GenericArray<u8, Y> {
|
||||
pub(crate) fn t_l<const X: usize, const Y: usize>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &[[u8; Y]; X],
|
||||
) -> [u8; Y] {
|
||||
let mut hasher = Shake256::default();
|
||||
hasher.update(pk_seed);
|
||||
hasher.update(&adrs.to_32_bytes());
|
||||
ml.iter().for_each(|item| hasher.update(item));
|
||||
let mut reader = hasher.finalize_xof();
|
||||
let mut result = GenericArray::default();
|
||||
let mut result = [0u8; Y];
|
||||
reader.read(&mut result);
|
||||
result
|
||||
}
|
||||
|
|
@ -105,7 +95,6 @@ pub(crate) mod shake {
|
|||
pub(crate) mod sha2_cat_1 {
|
||||
use crate::types::Adrs;
|
||||
use core::cmp::min;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
|
||||
|
|
@ -118,18 +107,18 @@ pub(crate) mod sha2_cat_1 {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn h_msg<M: ArrayLength>(
|
||||
pub(crate) fn h_msg<const M: usize>(
|
||||
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, M> {
|
||||
) -> [u8; M] {
|
||||
let mut digest1 = [0u8; 32];
|
||||
sha2_256(&[r, pk_seed, pk_root, m], &mut digest1);
|
||||
let mut result: GenericArray<u8, M> = GenericArray::default();
|
||||
let mut result = [0u8; M];
|
||||
let mut start = 0;
|
||||
let mut counter = 0u32;
|
||||
while start < M::to_usize() {
|
||||
while start < M {
|
||||
let mut tmp = [0u8; 32];
|
||||
sha2_256(&[r, pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
|
||||
let len = min(M::to_usize() - start, 32);
|
||||
let len = min(M - start, 32);
|
||||
result[start..start + len].copy_from_slice(&tmp[0..len]);
|
||||
start += 32;
|
||||
counter += 1;
|
||||
|
|
@ -139,20 +128,10 @@ pub(crate) mod sha2_cat_1 {
|
|||
|
||||
|
||||
#[allow(clippy::similar_names)] // pk_seed and sk_seed
|
||||
pub(crate) fn prf<N: ArrayLength>(
|
||||
pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs,
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn prf<const N: usize>(pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
sha2_256(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(64 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
sk_seed,
|
||||
],
|
||||
&mut digest,
|
||||
); // Note that the spec swaps order of last to params
|
||||
sha2_256(&[pk_seed, &to_byte[0..(64 - N)], &adrs.to_22_bytes(), sk_seed], &mut digest); // Note that the spec swaps order of last to params
|
||||
digest
|
||||
}
|
||||
|
||||
|
|
@ -177,65 +156,43 @@ pub(crate) mod sha2_cat_1 {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn prf_msg<N: ArrayLength>(
|
||||
sk_prf: &[u8], opt_rand: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
//sha2_256(&[sk_prf, opt_rand, m], &mut digest);
|
||||
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let xxx = hmac_sha_256(sk_prf, opt_rand, m);
|
||||
digest.copy_from_slice(&xxx[0..N::to_usize()]);
|
||||
digest.copy_from_slice(&xxx[0..N]);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn f<N: ArrayLength>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn f<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
sha2_256(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(64 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
m1,
|
||||
],
|
||||
&mut digest,
|
||||
);
|
||||
sha2_256(&[pk_seed, &to_byte[0..(64 - N)], &adrs.to_22_bytes(), m1], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn h<N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn h<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
sha2_256(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(64 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
m1,
|
||||
m2,
|
||||
],
|
||||
&mut digest,
|
||||
);
|
||||
sha2_256(&[pk_seed, &to_byte[0..(64 - N)], &adrs.to_22_bytes(), m1, m2], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
// Perhaps there is a more elegant way to covert ml into list of bytes
|
||||
pub(crate) fn t_l<LEN: ArrayLength, N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray<GenericArray<u8, N>, LEN>,
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut result = GenericArray::default();
|
||||
pub(crate) fn t_l<const LEN: usize, const N: usize>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &[[u8; N]; LEN],
|
||||
) -> [u8; N] {
|
||||
let mut result = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(pk_seed);
|
||||
hasher.update(&to_byte[0..(64 - N::to_usize())]);
|
||||
hasher.update(&to_byte[0..(64 - N)]);
|
||||
hasher.update(adrs.to_22_bytes());
|
||||
ml.iter().for_each(|item| hasher.update(item));
|
||||
let digest = hasher.finalize();
|
||||
result.copy_from_slice(&digest[0..N::to_usize()]);
|
||||
result.copy_from_slice(&digest[0..N]);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
@ -250,7 +207,6 @@ pub(crate) mod sha2_cat_1 {
|
|||
pub(crate) mod sha2_cat_3_5 {
|
||||
use crate::types::Adrs;
|
||||
use core::cmp::min;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use sha2::{Digest, Sha256, Sha512};
|
||||
|
||||
|
||||
|
|
@ -272,18 +228,18 @@ pub(crate) mod sha2_cat_3_5 {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn h_msg<M: ArrayLength>(
|
||||
pub(crate) fn h_msg<const M: usize>(
|
||||
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, M> {
|
||||
) -> [u8; M] {
|
||||
let mut digest1 = [0u8; 64];
|
||||
sha2_512(&[r, pk_seed, pk_root, m], &mut digest1);
|
||||
let mut result: GenericArray<u8, M> = GenericArray::default();
|
||||
let mut result = [0u8; M];
|
||||
let mut start = 0;
|
||||
let mut counter = 0u32;
|
||||
while start < M::to_usize() {
|
||||
while start < M {
|
||||
let mut tmp = [0u8; 64];
|
||||
sha2_512(&[r, pk_seed, &digest1, &counter.to_be_bytes()], &mut tmp);
|
||||
let len = min(M::to_usize() - start, 64);
|
||||
let len = min(M - start, 64);
|
||||
result[start..start + len].copy_from_slice(&tmp[0..len]);
|
||||
start += 64;
|
||||
counter += 1;
|
||||
|
|
@ -293,20 +249,10 @@ pub(crate) mod sha2_cat_3_5 {
|
|||
|
||||
|
||||
#[allow(clippy::similar_names)] // pk_seed and sk_seed
|
||||
pub(crate) fn prf<N: ArrayLength>(
|
||||
pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs,
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn prf<const N: usize>(pk_seed: &[u8], sk_seed: &[u8], adrs: &Adrs) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
sha2_256(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(64 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
sk_seed,
|
||||
],
|
||||
&mut digest,
|
||||
); // Note that the spec swaps order of last to params
|
||||
sha2_256(&[pk_seed, &to_byte[0..(64 - N)], &adrs.to_22_bytes(), sk_seed], &mut digest); // Note that the spec swaps order of last to params
|
||||
digest
|
||||
}
|
||||
|
||||
|
|
@ -331,64 +277,43 @@ pub(crate) mod sha2_cat_3_5 {
|
|||
}
|
||||
|
||||
|
||||
pub(crate) fn prf_msg<N: ArrayLength>(
|
||||
sk_prf: &[u8], opt_rand: &[u8], m: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let xxx = hmac_sha_512(sk_prf, opt_rand, m);
|
||||
digest.copy_from_slice(&xxx[0..N::to_usize()]);
|
||||
digest.copy_from_slice(&xxx[0..N]);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn f<N: ArrayLength>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn f<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 64];
|
||||
sha2_256(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(64 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
m1,
|
||||
],
|
||||
&mut digest,
|
||||
);
|
||||
sha2_256(&[pk_seed, &to_byte[0..(64-N)], &adrs.to_22_bytes(), m1], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn h<N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8],
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut digest: GenericArray<u8, N> = GenericArray::default();
|
||||
pub(crate) fn h<const N: usize>(pk_seed: &[u8], adrs: &Adrs, m1: &[u8], m2: &[u8]) -> [u8; N] {
|
||||
let mut digest = [0u8; N];
|
||||
let to_byte = [0u8; 128];
|
||||
sha2_512(
|
||||
&[
|
||||
pk_seed,
|
||||
&to_byte[0..(128 - N::to_usize())],
|
||||
&adrs.to_22_bytes(),
|
||||
m1,
|
||||
m2,
|
||||
],
|
||||
&mut digest,
|
||||
);
|
||||
sha2_512(&[pk_seed, &to_byte[0..(128 - N)], &adrs.to_22_bytes(), m1, m2], &mut digest);
|
||||
digest
|
||||
}
|
||||
|
||||
|
||||
// Perhaps there is a more elegant way to covert ml into list of bytes
|
||||
pub(crate) fn t_l<LEN: ArrayLength, N: ArrayLength>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray<GenericArray<u8, N>, LEN>,
|
||||
) -> GenericArray<u8, N> {
|
||||
let mut result = GenericArray::default();
|
||||
pub(crate) fn t_l<const LEN: usize, const N: usize>(
|
||||
pk_seed: &[u8], adrs: &Adrs, ml: &[[u8; N]; LEN],
|
||||
) -> [u8; N] {
|
||||
let mut result = [0u8; N];
|
||||
let to_byte = [0u8; 128];
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(pk_seed);
|
||||
hasher.update(&to_byte[0..(128 - N::to_usize())]);
|
||||
hasher.update(&to_byte[0..(128 - N)]);
|
||||
hasher.update(adrs.to_22_bytes());
|
||||
ml.iter().for_each(|item| hasher.update(item));
|
||||
let digest = hasher.finalize();
|
||||
result.copy_from_slice(&digest[0..N::to_usize()]);
|
||||
result.copy_from_slice(&digest[0..N]);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::types::{Adrs, SlhDsaSig};
|
||||
use generic_array::ArrayLength;
|
||||
use crate::types::{Adrs, Auth, ForsSig, HtSig, SlhDsaSig, WotsSig, XmssSig};
|
||||
|
||||
|
||||
/// Algorithm 1: `toInt(X, n)` on page 14.
|
||||
|
|
@ -112,44 +111,42 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: u32, baseb: &mut [u32]) {
|
|||
|
||||
|
||||
impl<
|
||||
A: ArrayLength,
|
||||
D: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const D: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const N: usize,
|
||||
> SlhDsaSig<A, D, HP, K, LEN, N>
|
||||
{
|
||||
pub(crate) fn deserialize<const SIG_LEN: usize>(self) -> [u8; SIG_LEN] {
|
||||
let mut out = [0u8; SIG_LEN];
|
||||
debug_assert_eq!(
|
||||
out.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())
|
||||
N + // randomness
|
||||
N * K + K * A * N + // ForsSig
|
||||
D * (HP * N + LEN * N)
|
||||
);
|
||||
out[0..N::to_usize()].copy_from_slice(&self.randomness);
|
||||
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 a in 0..A::to_usize() {
|
||||
out[start..(start + N::to_usize())].copy_from_slice(&self.fors_sig.auth[k].tree[a]);
|
||||
start += N::to_usize();
|
||||
out[0..N].copy_from_slice(&self.randomness);
|
||||
let mut start = N;
|
||||
for k in 0..K {
|
||||
out[start..(start + N)].copy_from_slice(&self.fors_sig.private_key_value[k]);
|
||||
start += N;
|
||||
for a in 0..A {
|
||||
out[start..(start + N)].copy_from_slice(&self.fors_sig.auth[k].tree[a]);
|
||||
start += N;
|
||||
}
|
||||
}
|
||||
for d in 0..D::to_usize() {
|
||||
for d in 0..D {
|
||||
//println!("and we move to xmss {} starting at {}", d, start);
|
||||
for len in 0..LEN::to_usize() {
|
||||
out[start..(start + N::to_usize())]
|
||||
for len in 0..LEN {
|
||||
out[start..(start + N)]
|
||||
.copy_from_slice(&self.ht_sig.xmss_sigs[d].sig_wots.data[len]);
|
||||
start += N::to_usize();
|
||||
start += N;
|
||||
}
|
||||
for hp in 0..HP::to_usize() {
|
||||
out[start..(start + N::to_usize())]
|
||||
.copy_from_slice(&self.ht_sig.xmss_sigs[d].auth[hp]);
|
||||
start += N::to_usize();
|
||||
for hp in 0..HP {
|
||||
out[start..(start + N)].copy_from_slice(&self.ht_sig.xmss_sigs[d].auth[hp]);
|
||||
start += N;
|
||||
}
|
||||
}
|
||||
debug_assert_eq!(start, out.len());
|
||||
|
|
@ -159,33 +156,35 @@ impl<
|
|||
pub(crate) 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())
|
||||
N + // randomness
|
||||
N * K + K * A * N + // ForsSig
|
||||
D * (HP * N + LEN * N)
|
||||
);
|
||||
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();
|
||||
//let mut output = Self::default();
|
||||
let mut output = SlhDsaSig{
|
||||
randomness: [0u8; N], //r.clone(),
|
||||
fors_sig: ForsSig { private_key_value: [[0u8; N]; K], auth: core::array::from_fn(|_| Auth{ tree: [[0u8; N]; A] }) },
|
||||
ht_sig: HtSig { xmss_sigs: core::array::from_fn(|_| XmssSig { sig_wots: WotsSig { data: [[0u8; N]; LEN] }, auth: [[0u8; N]; HP] }) },
|
||||
};
|
||||
output.randomness.copy_from_slice(&bytes[0..N]);
|
||||
let mut start = N;
|
||||
for k in 0..K {
|
||||
output.fors_sig.private_key_value[k].copy_from_slice(&bytes[start..(start + N)]);
|
||||
start += N;
|
||||
for a in 0..A {
|
||||
output.fors_sig.auth[k].tree[a].copy_from_slice(&bytes[start..(start + N)]);
|
||||
start += N;
|
||||
}
|
||||
}
|
||||
for d in 0..D::to_usize() {
|
||||
for len in 0..LEN::to_usize() {
|
||||
for d in 0..D {
|
||||
for len in 0..LEN {
|
||||
output.ht_sig.xmss_sigs[d].sig_wots.data[len]
|
||||
.copy_from_slice(&bytes[start..(start + N::to_usize())]);
|
||||
start += N::to_usize();
|
||||
.copy_from_slice(&bytes[start..(start + N)]);
|
||||
start += N;
|
||||
}
|
||||
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();
|
||||
for hp in 0..HP {
|
||||
output.ht_sig.xmss_sigs[d].auth[hp].copy_from_slice(&bytes[start..(start + N)]);
|
||||
start += N;
|
||||
}
|
||||
}
|
||||
debug_assert_eq!(start, bytes.len());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use crate::hashers::Hashers;
|
||||
use crate::types::{Adrs, HtSig};
|
||||
use crate::types::{Adrs, HtSig, WotsSig, XmssSig};
|
||||
use crate::xmss;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
|
||||
/// Algorithm 11: `ht_sign(M, SK.seed, PK.seed, idx_tree, idx_leaf)` on page 27.
|
||||
|
|
@ -12,18 +11,19 @@ use generic_array::{ArrayLength, GenericArray};
|
|||
/// Output: HT signature `SIG_HT`.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn ht_sign<
|
||||
D: ArrayLength,
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const D: usize,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk_seed: &[u8], pk_seed: &[u8], idx_tree: u64,
|
||||
idx_leaf: u32,
|
||||
) -> Result<HtSig<D, HP, LEN, N>, &'static str> {
|
||||
let mut idx_tree = idx_tree;
|
||||
let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
|
||||
//
|
||||
// 1: ADRS ← toByte(0, 32)
|
||||
let mut adrs = Adrs::default();
|
||||
|
|
@ -37,7 +37,7 @@ pub(crate) fn ht_sign<
|
|||
xmss::xmss_sign::<H, HP, K, LEN, M, N>(hashers, m, sk_seed, idx_leaf, pk_seed, &adrs)?;
|
||||
|
||||
// 5: SIG_HT ← SIG_tmp
|
||||
let mut sig_ht = HtSig::default();
|
||||
let mut sig_ht = HtSig { xmss_sigs: core::array::from_fn(|_| XmssSig { sig_wots: WotsSig { data: [[0u8; N]; LEN] }, auth: [[0u8; N]; HP] }) }; //HtSig::default();
|
||||
sig_ht.xmss_sigs[0] = sig_tmp.clone();
|
||||
|
||||
// 6: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, M, PK.seed, ADRS)
|
||||
|
|
@ -45,14 +45,14 @@ pub(crate) fn ht_sign<
|
|||
xmss::xmss_pk_from_sig::<HP, K, LEN, M, N>(hashers, idx_leaf, &sig_tmp, m, pk_seed, &adrs);
|
||||
|
||||
// 7: for j from 1 to d − 1 do
|
||||
for j in 1..D::to_u32() {
|
||||
for j in 1..d32 {
|
||||
//
|
||||
// 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()))
|
||||
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(hp32))
|
||||
.map_err(|_| "Alg11: oversized idx leaf")?;
|
||||
|
||||
// 9: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
||||
idx_tree >>= HP::to_u32();
|
||||
idx_tree >>= hp32;
|
||||
|
||||
// 10: ADRS.setLayerAddress(j)
|
||||
adrs.set_layer_address(j);
|
||||
|
|
@ -69,7 +69,7 @@ pub(crate) fn ht_sign<
|
|||
sig_ht.xmss_sigs[j as usize] = sig_tmp.clone();
|
||||
|
||||
// 14: if j < d − 1 then
|
||||
if j < (D::to_u32() - 1) {
|
||||
if j < (d32 - 1) {
|
||||
//
|
||||
// 15: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, root, PK.seed, ADRS)
|
||||
root = xmss::xmss_pk_from_sig::<HP, K, LEN, M, N>(
|
||||
|
|
@ -94,17 +94,18 @@ pub(crate) fn ht_sign<
|
|||
/// HT public key `PK.root`. <br>
|
||||
/// Output: Boolean.
|
||||
pub(crate) fn ht_verify<
|
||||
D: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const D: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sig_ht: &HtSig<D, HP, LEN, N>, pk_seed: &[u8],
|
||||
idx_tree: u64, idx_leaf: u32, pk_root: &GenericArray<u8, N>,
|
||||
idx_tree: u64, idx_leaf: u32, pk_root: &[u8; N],
|
||||
) -> bool {
|
||||
let mut idx_tree = idx_tree;
|
||||
let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
|
||||
//
|
||||
// 1: ADRS ← toByte(0, 32)
|
||||
let mut adrs = Adrs::default();
|
||||
|
|
@ -120,17 +121,17 @@ pub(crate) fn ht_verify<
|
|||
let mut node = xmss::xmss_pk_from_sig(hashers, idx_leaf, &sig_tmp, m, pk_seed, &adrs);
|
||||
|
||||
// 6: for j from 1 to d − 1 do
|
||||
for j in 1..D::to_u32() {
|
||||
for j in 1..d32 {
|
||||
//
|
||||
// 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())); // TODO: clean
|
||||
let idx_leaf = u32::try_from(idx_tree % 2u64.pow(hp32)); // TODO: clean
|
||||
if idx_leaf.is_err() {
|
||||
return false;
|
||||
};
|
||||
let idx_leaf = idx_leaf.unwrap();
|
||||
|
||||
// 8: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
||||
idx_tree >>= HP::to_u32();
|
||||
idx_tree >>= hp32;
|
||||
|
||||
// 9: ADRS.setLayerAddress(j)
|
||||
adrs.set_layer_address(j);
|
||||
|
|
|
|||
266
src/lib.rs
266
src/lib.rs
|
|
@ -131,7 +131,7 @@ macro_rules! functionality {
|
|||
fn try_keygen_with_rng_vt(
|
||||
rng: &mut impl CryptoRngCore,
|
||||
) -> Result<(PublicKey, PrivateKey), &'static str> {
|
||||
let res = crate::slh::slh_keygen_with_rng::<D, H, HP, K, Len, M, N>(rng, &HASHERS);
|
||||
let res = crate::slh::slh_keygen_with_rng::<D, H, HP, K, LEN, M, N>(rng, &HASHERS);
|
||||
res.map(|(sk, pk)| (PublicKey(pk), PrivateKey(sk)))
|
||||
}
|
||||
}
|
||||
|
|
@ -143,7 +143,7 @@ macro_rules! functionality {
|
|||
fn try_sign_with_rng_ct(
|
||||
&self, rng: &mut impl CryptoRngCore, m: &[u8], randomize: bool,
|
||||
) -> Result<[u8; SIG_LEN], &'static str> {
|
||||
let sig = crate::slh::slh_sign_with_rng::<A, D, H, HP, K, Len, M, N>(
|
||||
let sig = crate::slh::slh_sign_with_rng::<A, D, H, HP, K, LEN, M, N>(
|
||||
rng, &HASHERS, &m, &self.0, randomize,
|
||||
);
|
||||
sig.map(|s| s.deserialize())
|
||||
|
|
@ -157,8 +157,8 @@ macro_rules! functionality {
|
|||
fn try_verify_vt(
|
||||
&self, m: &[u8], sig_bytes: &[u8; SIG_LEN],
|
||||
) -> Result<bool, &'static str> {
|
||||
let sig = SlhDsaSig::<A, D, HP, K, Len, N>::serialize(sig_bytes);
|
||||
let res = crate::slh::slh_verify::<A, D, H, HP, K, Len, M, N>(
|
||||
let sig = SlhDsaSig::<A, D, HP, K, LEN, N>::serialize(sig_bytes);
|
||||
let res = crate::slh::slh_verify::<A, D, H, HP, K, LEN, M, N>(
|
||||
&HASHERS, &m, &sig, &self.0,
|
||||
);
|
||||
Ok(res)
|
||||
|
|
@ -180,7 +180,8 @@ macro_rules! functionality {
|
|||
|
||||
fn try_from_bytes(bytes: &Self::ByteArray) -> Result<Self, &'static str> {
|
||||
// Result: opportunity for validation
|
||||
let mut pk = SlhPublicKey::default();
|
||||
//let mut pk = SlhPublicKey::default();
|
||||
let mut pk = SlhPublicKey{pk_seed: [0u8; N], pk_root: [0u8; N]};
|
||||
pk.pk_seed.copy_from_slice(&bytes[..(PK_LEN / 2)]);
|
||||
pk.pk_root.copy_from_slice(&bytes[(PK_LEN / 2)..]);
|
||||
Ok(PublicKey(pk))
|
||||
|
|
@ -202,7 +203,8 @@ macro_rules! functionality {
|
|||
|
||||
fn try_from_bytes(bytes: &Self::ByteArray) -> Result<Self, &'static str> {
|
||||
// Result: opportunity for validation
|
||||
let mut sk = SlhPrivateKey::default();
|
||||
//let mut sk = SlhPrivateKey::default();
|
||||
let mut sk = SlhPrivateKey{sk_seed: [0u8; N], sk_prf: [0u8; N], pk_seed: [0u8; N], pk_root: [0u8; N]};
|
||||
sk.sk_seed.copy_from_slice(&bytes[0..(SK_LEN / 4)]);
|
||||
sk.sk_prf
|
||||
.copy_from_slice(&bytes[(SK_LEN / 4)..(SK_LEN / 2)]);
|
||||
|
|
@ -266,16 +268,15 @@ macro_rules! functionality {
|
|||
pub mod slh_dsa_sha2_128s {
|
||||
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U12, U14, U16, U2, U3, U30, U63, U7, U9};
|
||||
|
||||
type N = U16;
|
||||
type H = U63;
|
||||
type D = U7;
|
||||
type HP = U9;
|
||||
type A = U12;
|
||||
type K = U14;
|
||||
type M = U30;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 16;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
const HP: usize = 9;
|
||||
const A: usize = 12;
|
||||
const K: usize = 14;
|
||||
const M: usize = 30;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 32;
|
||||
|
|
@ -286,8 +287,8 @@ pub mod slh_dsa_sha2_128s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -315,16 +316,15 @@ pub mod slh_dsa_sha2_128s {
|
|||
pub mod slh_dsa_shake_128s {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U12, U14, U16, U2, U3, U30, U63, U7, U9};
|
||||
|
||||
type N = U16;
|
||||
type H = U63;
|
||||
type D = U7;
|
||||
type HP = U9;
|
||||
type A = U12;
|
||||
type K = U14;
|
||||
type M = U30;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 16;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
const HP: usize = 9;
|
||||
const A: usize = 12;
|
||||
const K: usize = 14;
|
||||
const M: usize = 30;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 32;
|
||||
|
|
@ -335,8 +335,8 @@ pub mod slh_dsa_shake_128s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -364,16 +364,15 @@ pub mod slh_dsa_shake_128s {
|
|||
pub mod slh_dsa_sha2_128f {
|
||||
use crate::hashers::sha2_cat_1::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U16, U2, U22, U3, U33, U34, U6, U66};
|
||||
|
||||
type N = U16;
|
||||
type H = U66;
|
||||
type D = U22;
|
||||
type HP = U3;
|
||||
type A = U6;
|
||||
type K = U33;
|
||||
type M = U34;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 16;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
const HP: usize = 3;
|
||||
const A: usize = 6;
|
||||
const K: usize = 33;
|
||||
const M: usize = 34;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 32;
|
||||
|
|
@ -384,8 +383,8 @@ pub mod slh_dsa_sha2_128f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -413,16 +412,15 @@ pub mod slh_dsa_sha2_128f {
|
|||
pub mod slh_dsa_shake_128f {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U16, U2, U22, U3, U33, U34, U6, U66};
|
||||
|
||||
type N = U16;
|
||||
type H = U66;
|
||||
type D = U22;
|
||||
type HP = U3;
|
||||
type A = U6;
|
||||
type K = U33;
|
||||
type M = U34;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 16;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
const HP: usize = 3;
|
||||
const A: usize = 6;
|
||||
const K: usize = 33;
|
||||
const M: usize = 34;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 32;
|
||||
|
|
@ -433,8 +431,8 @@ pub mod slh_dsa_shake_128f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -462,16 +460,15 @@ pub mod slh_dsa_shake_128f {
|
|||
pub mod slh_dsa_sha2_192s {
|
||||
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U14, U17, U2, U24, U3, U39, U63, U7, U9};
|
||||
|
||||
type N = U24;
|
||||
type H = U63;
|
||||
type D = U7;
|
||||
type HP = U9;
|
||||
type A = U14;
|
||||
type K = U17;
|
||||
type M = U39;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 24;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
const HP: usize = 9;
|
||||
const A: usize = 14;
|
||||
const K: usize = 17;
|
||||
const M: usize = 39;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 48;
|
||||
|
|
@ -482,8 +479,8 @@ pub mod slh_dsa_sha2_192s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -511,16 +508,15 @@ pub mod slh_dsa_sha2_192s {
|
|||
pub mod slh_dsa_shake_192s {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U14, U17, U2, U24, U3, U39, U63, U7, U9};
|
||||
|
||||
type N = U24;
|
||||
type H = U63;
|
||||
type D = U7;
|
||||
type HP = U9;
|
||||
type A = U14;
|
||||
type K = U17;
|
||||
type M = U39;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 24;
|
||||
const H: usize = 63;
|
||||
const D: usize = 7;
|
||||
const HP: usize = 9;
|
||||
const A: usize = 14;
|
||||
const K: usize = 17;
|
||||
const M: usize = 39;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 48;
|
||||
|
|
@ -531,8 +527,8 @@ pub mod slh_dsa_shake_192s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -560,16 +556,15 @@ pub mod slh_dsa_shake_192s {
|
|||
pub mod slh_dsa_sha2_192f {
|
||||
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U2, U22, U24, U3, U33, U42, U66, U8};
|
||||
|
||||
type N = U24;
|
||||
type H = U66;
|
||||
type D = U22;
|
||||
type HP = U3;
|
||||
type A = U8;
|
||||
type K = U33;
|
||||
type M = U42;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 24;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
const HP: usize = 3;
|
||||
const A: usize = 8;
|
||||
const K: usize = 33;
|
||||
const M: usize = 42;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 48;
|
||||
|
|
@ -580,8 +575,8 @@ pub mod slh_dsa_sha2_192f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -609,16 +604,15 @@ pub mod slh_dsa_sha2_192f {
|
|||
pub mod slh_dsa_shake_192f {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U2, U22, U24, U3, U33, U42, U66, U8};
|
||||
|
||||
type N = U24;
|
||||
type H = U66;
|
||||
type D = U22;
|
||||
type HP = U3;
|
||||
type A = U8;
|
||||
type K = U33;
|
||||
type M = U42;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 24;
|
||||
const H: usize = 66;
|
||||
const D: usize = 22;
|
||||
const HP: usize = 3;
|
||||
const A: usize = 8;
|
||||
const K: usize = 33;
|
||||
const M: usize = 42;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 48;
|
||||
|
|
@ -629,8 +623,8 @@ pub mod slh_dsa_shake_192f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -658,16 +652,15 @@ pub mod slh_dsa_shake_192f {
|
|||
pub mod slh_dsa_sha2_256s {
|
||||
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U14, U2, U22, U3, U32, U47, U64, U8};
|
||||
|
||||
type N = U32;
|
||||
type H = U64;
|
||||
type D = U8;
|
||||
type HP = U8;
|
||||
type A = U14;
|
||||
type K = U22;
|
||||
type M = U47;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 32;
|
||||
const H: usize = 64;
|
||||
const D: usize = 8;
|
||||
const HP: usize = 8;
|
||||
const A: usize = 14;
|
||||
const K: usize = 22;
|
||||
const M: usize = 47;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 64;
|
||||
|
|
@ -678,8 +671,8 @@ pub mod slh_dsa_sha2_256s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -707,16 +700,15 @@ pub mod slh_dsa_sha2_256s {
|
|||
pub mod slh_dsa_shake_256s {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U14, U2, U22, U3, U32, U47, U64, U8};
|
||||
|
||||
type N = U32;
|
||||
type H = U64;
|
||||
type D = U8;
|
||||
type HP = U8;
|
||||
type A = U14;
|
||||
type K = U22;
|
||||
type M = U47;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 32;
|
||||
const H: usize = 64;
|
||||
const D: usize = 8;
|
||||
const HP: usize = 8;
|
||||
const A: usize = 14;
|
||||
const K: usize = 22;
|
||||
const M: usize = 47;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 64;
|
||||
|
|
@ -727,8 +719,8 @@ pub mod slh_dsa_shake_256s {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -756,16 +748,15 @@ pub mod slh_dsa_shake_256s {
|
|||
pub mod slh_dsa_sha2_256f {
|
||||
use crate::hashers::sha2_cat_3_5::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U17, U2, U3, U32, U35, U4, U49, U68, U9};
|
||||
|
||||
type N = U32;
|
||||
type H = U68;
|
||||
type D = U17;
|
||||
type HP = U4;
|
||||
type A = U9;
|
||||
type K = U35;
|
||||
type M = U49;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 32;
|
||||
const H: usize = 68;
|
||||
const D: usize = 17;
|
||||
const HP: usize = 4;
|
||||
const A: usize = 9;
|
||||
const K: usize = 35;
|
||||
const M: usize = 49;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 64;
|
||||
|
|
@ -776,8 +767,8 @@ pub mod slh_dsa_sha2_256f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
@ -805,16 +796,15 @@ pub mod slh_dsa_sha2_256f {
|
|||
pub mod slh_dsa_shake_256f {
|
||||
use crate::hashers::shake::{f, h, h_msg, prf, prf_msg, t_l};
|
||||
use crate::hashers::Hashers;
|
||||
use generic_array::typenum::{Prod, Sum, U17, U2, U3, U32, U35, U4, U49, U68, U9};
|
||||
|
||||
type N = U32;
|
||||
type H = U68;
|
||||
type D = U17;
|
||||
type HP = U4;
|
||||
type A = U9;
|
||||
type K = U35;
|
||||
type M = U49;
|
||||
type Len = Sum<Prod<U2, N>, U3>;
|
||||
const N: usize = 32;
|
||||
const H: usize = 68;
|
||||
const D: usize = 17;
|
||||
const HP: usize = 4;
|
||||
const A: usize = 9;
|
||||
const K: usize = 35;
|
||||
const M: usize = 49;
|
||||
const LEN: usize = 2 * N + 3;
|
||||
|
||||
/// Length of public key
|
||||
pub const PK_LEN: usize = 64;
|
||||
|
|
@ -825,8 +815,8 @@ pub mod slh_dsa_shake_256f {
|
|||
/// Length of private/secret key
|
||||
pub const SK_LEN: usize = PK_LEN * 2;
|
||||
|
||||
static HASHERS: Hashers<K, Len, M, N> =
|
||||
Hashers::<K, Len, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
static HASHERS: Hashers<K, LEN, M, N> =
|
||||
Hashers::<K, LEN, M, N> { h_msg, prf, prf_msg, f, h, t_l, t_len: t_l };
|
||||
|
||||
functionality!();
|
||||
}
|
||||
|
|
|
|||
118
src/slh.rs
118
src/slh.rs
|
|
@ -1,8 +1,7 @@
|
|||
use crate::hashers::Hashers;
|
||||
use crate::types::FORS_TREE;
|
||||
use crate::types::{Auth, FORS_TREE, ForsSig, HtSig, WotsSig, XmssSig};
|
||||
use crate::types::{Adrs, SlhDsaSig, SlhPrivateKey, SlhPublicKey};
|
||||
use crate::{fors, helpers, hypertree, xmss};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand_core::CryptoRngCore;
|
||||
|
||||
|
||||
|
|
@ -13,29 +12,31 @@ use rand_core::CryptoRngCore;
|
|||
/// Output: SLH-DSA key pair `(SK, PK)`.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn slh_keygen_with_rng<
|
||||
D: ArrayLength,
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const D: usize,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
rng: &mut impl CryptoRngCore, hashers: &Hashers<K, LEN, M, N>,
|
||||
) -> Result<(SlhPrivateKey<N>, SlhPublicKey<N>), &'static str> {
|
||||
let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
|
||||
|
||||
//
|
||||
// 1: SK.seed ←$ B^n ▷ Set SK.seed, SK.prf, and PK.seed to random n-byte
|
||||
let mut sk_seed = GenericArray::default();
|
||||
let mut sk_seed = [0u8; N]; // = GenericArray::default();
|
||||
rng.try_fill_bytes(&mut sk_seed)
|
||||
.map_err(|_| "Alg17: rng failed1")?;
|
||||
|
||||
// 2: SK.prf ←$ B^n ▷ strings using an approved random bit generator
|
||||
let mut sk_prf = GenericArray::default();
|
||||
let mut sk_prf = [0u8; N]; //GenericArray::default();
|
||||
rng.try_fill_bytes(&mut sk_prf)
|
||||
.map_err(|_| "Alg17: rng failed2")?;
|
||||
|
||||
// 3: PK.seed ←$ B^n
|
||||
let mut pk_seed = GenericArray::default();
|
||||
let mut pk_seed = [0u8; N]; //GenericArray::default();
|
||||
rng.try_fill_bytes(&mut pk_seed)
|
||||
.map_err(|_| "Alg17: rng failed3")?;
|
||||
|
||||
|
|
@ -44,21 +45,15 @@ pub(crate) fn slh_keygen_with_rng<
|
|||
let mut adrs = Adrs::default();
|
||||
|
||||
// 6: ADRS.setLayerAddress(d − 1)
|
||||
adrs.set_layer_address(D::to_u32() - 1);
|
||||
adrs.set_layer_address(d32 - 1);
|
||||
|
||||
// 7: PK.root ← xmss_node(SK.seed, 0, h′, PK.seed, ADRS)
|
||||
let pk_root = xmss::xmss_node::<H, HP, K, LEN, M, N>(
|
||||
hashers,
|
||||
&sk_seed,
|
||||
0,
|
||||
HP::to_u32(),
|
||||
&pk_seed,
|
||||
&adrs,
|
||||
)?;
|
||||
let pk_root =
|
||||
xmss::xmss_node::<H, HP, K, LEN, M, N>(hashers, &sk_seed, 0, hp32, &pk_seed, &adrs)?;
|
||||
|
||||
// 8:
|
||||
// 9: return ( (SK.seed, SK.prf, PK.seed, PK.root), (PK.seed, PK.root) )
|
||||
let pk = SlhPublicKey { pk_seed: pk_seed.clone(), pk_root: pk_root.clone() };
|
||||
let pk = SlhPublicKey { pk_seed, pk_root };
|
||||
let sk = SlhPrivateKey { sk_seed, sk_prf, pk_seed, pk_root };
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
|
@ -69,27 +64,29 @@ pub(crate) fn slh_keygen_with_rng<
|
|||
///
|
||||
/// Input: Message `M`, private key `SK = (SK.seed, SK.prf, PK.seed, PK.root)`. <br>
|
||||
/// Output: SLH-DSA signature `SIG`.
|
||||
#[allow(clippy::similar_names)]
|
||||
#[allow(clippy::cast_possible_truncation)] // temporary, investigating idx_leaf int sizes
|
||||
pub(crate) fn slh_sign_with_rng<
|
||||
A: ArrayLength,
|
||||
D: ArrayLength,
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const D: usize,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
rng: &mut impl CryptoRngCore, hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk: &SlhPrivateKey<N>,
|
||||
randomize: bool,
|
||||
) -> Result<SlhDsaSig<A, D, HP, K, LEN, N>, &'static str> {
|
||||
let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());
|
||||
//
|
||||
// 1: ADRS ← toByte(0, 32)
|
||||
let mut adrs = Adrs::default();
|
||||
|
||||
// 2:
|
||||
// 3: opt_rand ← PK.seed ▷ Set opt_rand to either PK.seed
|
||||
let mut opt_rand = sk.pk_seed.clone();
|
||||
let mut opt_rand = sk.pk_seed;
|
||||
|
||||
// 4: if (RANDOMIZE) then ▷ or to a random n-byte string
|
||||
if randomize {
|
||||
|
|
@ -104,34 +101,39 @@ pub(crate) fn slh_sign_with_rng<
|
|||
let r = (hashers.prf_msg)(&sk.sk_prf, &opt_rand, m);
|
||||
|
||||
// 8: SIG ← R
|
||||
let mut sig = SlhDsaSig::default();
|
||||
sig.randomness = r.clone();
|
||||
//let mut sig = SlhDsaSig::default();
|
||||
let mut sig = SlhDsaSig{
|
||||
randomness: r,
|
||||
fors_sig: ForsSig { private_key_value: [[0u8; N]; K], auth: core::array::from_fn(|_| Auth{ tree: [[0u8; N]; A] }) },
|
||||
ht_sig: HtSig { xmss_sigs: core::array::from_fn(|_| XmssSig { sig_wots: WotsSig { data: [[0u8; N]; LEN] }, auth: [[0u8; N]; HP] }) },
|
||||
};
|
||||
|
||||
//sig.randomness.0 = r.clone();
|
||||
|
||||
// 9:
|
||||
// 10: digest ← H_msg(R, PK.seed, PK.root, M) ▷ Compute message digest
|
||||
let digest = (hashers.h_msg)(&r, &sk.pk_seed, &sk.pk_root, m);
|
||||
|
||||
// 11: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
||||
let index1 = (K::to_usize() * A::to_usize() + 7) / 8;
|
||||
let index1 = (K * A + 7) / 8;
|
||||
let md = &digest[0..index1];
|
||||
|
||||
// 12: tmp_idx_tree ← digest[ceil(k·a/8) : ceil(k·a/8) + ceil((h-h/d)/8)] ▷ next ceil((h-h/d)/8) bytes
|
||||
let index2 = index1 + (H::to_usize() - H::to_usize() / D::to_usize() + 7) / 8;
|
||||
let index2 = index1 + (H - H / D + 7) / 8;
|
||||
let tmp_idx_tree = &digest[index1..index2];
|
||||
|
||||
// 13: tmp_idx_leaf ← digest[ceil(k·a/8) + ceil((h-h/d)/8) : ceil(k·a/8) + ceil((h-h/d)/8) + ceil(h/8d)] ▷ next ceil(h/8d) bytes
|
||||
let index3 = index2 + (H::to_usize() + 8 * D::to_usize() - 1) / (8 * D::to_usize());
|
||||
let index3 = index2 + (H + 8 * D - 1) / (8 * D);
|
||||
let tmp_idx_leaf = &digest[index2..index3];
|
||||
|
||||
// 14:
|
||||
// 15: idx_tree ← toInt(tmp_idx_tree, ceil((h-h/d)/8)) mod 2^{h−h/d}
|
||||
let idx_tree = helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) / 8)
|
||||
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
|
||||
let idx_tree = helpers::to_int(tmp_idx_tree, (h32 - h32 / d32 + 7) / 8)
|
||||
& (u64::MAX >> (64 - (h32 - h32 / d32)));
|
||||
|
||||
// 16: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
|
||||
let idx_leaf =
|
||||
helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
|
||||
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
|
||||
let idx_leaf = helpers::to_int(tmp_idx_leaf, (h32 + 8 * d32 - 1) / (8 * d32))
|
||||
& (u64::MAX >> (64 - h32 / d32));
|
||||
|
||||
// 17:
|
||||
// 18: ADRS.setTreeAddress(idx_tree)
|
||||
|
|
@ -175,19 +177,22 @@ pub(crate) fn slh_sign_with_rng<
|
|||
/// Input: Message `M`, signature `SIG`, public key `PK = (PK.seed, PK.root)`. <br>
|
||||
/// Output: Boolean.
|
||||
#[allow(clippy::cast_possible_truncation)] // TODO: temporary
|
||||
#[allow(clippy::similar_names)]
|
||||
pub(crate) fn slh_verify<
|
||||
A: ArrayLength,
|
||||
D: ArrayLength,
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const D: usize,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sig: &SlhDsaSig<A, D, HP, K, LEN, N>,
|
||||
pk: &SlhPublicKey<N>,
|
||||
) -> bool {
|
||||
let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());
|
||||
|
||||
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
|
||||
// 2: return false
|
||||
// 3: end if
|
||||
|
|
@ -210,26 +215,25 @@ pub(crate) fn slh_verify<
|
|||
let digest = (hashers.h_msg)(r, &pk.pk_seed, &pk.pk_root, m);
|
||||
|
||||
// 10: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes
|
||||
let index1 = (K::to_usize() * A::to_usize() + 7) / 8;
|
||||
let index1 = (K * A + 7) / 8;
|
||||
let md = &digest[0..index1];
|
||||
|
||||
// 11: tmp_idx_tree ← digest[ceil(k·a/8) : ceil(k·a/8) + ceil((h - h/d)/8)] ▷ next ceil((h - h/d)/8) bytes
|
||||
let index2 = index1 + (H::to_usize() - H::to_usize() / D::to_usize() + 7) / 8;
|
||||
let index2 = index1 + (H - H / D + 7) / 8;
|
||||
let tmp_idx_tree = &digest[index1..index2];
|
||||
|
||||
// 12: tmp_idx_leaf ← digest[ceil(k·a/8) + ceil((h - h/d)/8) : ceil(k·a/8) + ceil((h - h/d)/8) + ceil(h/8d)] ▷ next ceil(h/8d) bytes
|
||||
let index3 = index2 + (H::to_usize() + 8 * D::to_usize() - 1) / (8 * D::to_usize());
|
||||
let index3 = index2 + (H + 8 * D - 1) / (8 * D);
|
||||
let tmp_idx_leaf = &digest[index2..index3];
|
||||
|
||||
// 13:
|
||||
// 14: idx_tree ← toInt(tmp_idx_tree, ceil((h - h/d)/8)) mod 2^{h−h/d}
|
||||
let idx_tree = helpers::to_int(tmp_idx_tree, (H::to_u32() - H::to_u32() / D::to_u32() + 7) / 8)
|
||||
& (u64::MAX >> (64 - (H::to_u32() - H::to_u32() / D::to_u32())));
|
||||
let idx_tree = helpers::to_int(tmp_idx_tree, (h32 - h32 / d32 + 7) / 8)
|
||||
& (u64::MAX >> (64 - (h32 - h32 / d32)));
|
||||
|
||||
// 15: idx_leaf ← toInt(tmp_idx_leaf, ceil(h/8d) mod 2^{h/d}
|
||||
let idx_leaf =
|
||||
helpers::to_int(tmp_idx_leaf, (H::to_u32() + 8 * D::to_u32() - 1) / (8 * D::to_u32()))
|
||||
& (u64::MAX >> (64 - H::to_u32() / D::to_u32()));
|
||||
let idx_leaf = helpers::to_int(tmp_idx_leaf, (h32 + 8 * d32 - 1) / (8 * d32))
|
||||
& (u64::MAX >> (64 - h32 / d32));
|
||||
|
||||
// 16:
|
||||
// 17: ADRS.setTreeAddress(idx_tree) ▷ Compute FORS public key
|
||||
|
|
|
|||
92
src/types.rs
92
src/types.rs
|
|
@ -1,87 +1,89 @@
|
|||
use generic_array::{ArrayLength, GenericArray};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
|
||||
/// Fig 16 on page 34
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct SlhDsaSig<
|
||||
A: ArrayLength,
|
||||
D: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const A: usize,
|
||||
const D: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const N: usize,
|
||||
> {
|
||||
pub(crate) randomness: GenericArray<u8, N>,
|
||||
pub(crate) randomness: [u8; N],
|
||||
pub(crate) fors_sig: ForsSig<A, K, N>,
|
||||
pub(crate) ht_sig: HtSig<D, HP, LEN, N>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct SlhPublicKey<N: ArrayLength> {
|
||||
pub(crate) pk_seed: GenericArray<u8, N>,
|
||||
pub(crate) pk_root: GenericArray<u8, N>,
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct SlhPublicKey<const N: usize> {
|
||||
pub(crate) pk_seed: [u8; N],
|
||||
pub(crate) pk_root: [u8; N],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct SlhPrivateKey<N: ArrayLength> {
|
||||
pub(crate) sk_seed: GenericArray<u8, N>,
|
||||
pub(crate) sk_prf: GenericArray<u8, N>,
|
||||
pub(crate) pk_seed: GenericArray<u8, N>,
|
||||
pub(crate) pk_root: GenericArray<u8, N>,
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct SlhPrivateKey<const N: usize> {
|
||||
pub(crate) sk_seed: [u8; N],
|
||||
pub(crate) sk_prf: [u8; N],
|
||||
pub(crate) pk_seed: [u8; N],
|
||||
pub(crate) pk_root: [u8; N],
|
||||
}
|
||||
|
||||
|
||||
/// Fig 13 on page 29
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct ForsSig<A: ArrayLength, K: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) private_key_value: GenericArray<GenericArray<u8, N>, K>,
|
||||
pub(crate) auth: GenericArray<Auth<A, N>, K>,
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct ForsSig<const A: usize, const K: usize, const N: usize> {
|
||||
pub(crate) private_key_value: [[u8; N]; K],
|
||||
pub(crate) auth: [Auth<A, N>; K],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct ForsPk<N: ArrayLength> {
|
||||
pub(crate) key: GenericArray<u8, N>,
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct ForsPk<const N: usize> {
|
||||
pub(crate) key: [u8; N],
|
||||
}
|
||||
|
||||
|
||||
/// Fig 10?
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct Auth<A: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) tree: GenericArray<GenericArray<u8, N>, A>,
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct Auth<const A: usize, const N: usize> {
|
||||
pub(crate) tree: [[u8; N]; A],
|
||||
}
|
||||
|
||||
impl<const A: usize, const N: usize> Default for Auth<A, N> {
|
||||
fn default() -> Self { Auth { tree: [[0u8; N]; A] } }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct HtSig<const D: usize, const HP: usize, const LEN: usize, const N: usize> {
|
||||
pub(crate) xmss_sigs: [XmssSig<HP, LEN, N>; D],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct HtSig<D: ArrayLength, HP: ArrayLength, LEN: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) xmss_sigs: GenericArray<XmssSig<HP, LEN, N>, D>,
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsSig<const LEN: usize, const N: usize> {
|
||||
pub(crate) data: [[u8; N]; LEN],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsSig<LEN: ArrayLength, N: ArrayLength> {
|
||||
pub(crate) data: GenericArray<GenericArray<u8, N>, LEN>,
|
||||
}
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsPk<const N: usize>(pub(crate) [u8; N]);
|
||||
|
||||
|
||||
#[derive(Clone, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct WotsPk<N: ArrayLength>(pub(crate) GenericArray<u8, N>);
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct XmssSig<HP: ArrayLength, LEN: ArrayLength, N: ArrayLength> {
|
||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct XmssSig<const HP: usize, const LEN: usize, const N: usize> {
|
||||
pub(crate) sig_wots: WotsSig<LEN, N>,
|
||||
pub(crate) auth: GenericArray<GenericArray<u8, N>, HP>,
|
||||
pub(crate) auth: [[u8; N]; HP],
|
||||
}
|
||||
|
||||
|
||||
impl<HP: ArrayLength, LEN: ArrayLength, N: ArrayLength> XmssSig<HP, LEN, N> {
|
||||
impl<const HP: usize, const LEN: usize, const N: usize> XmssSig<HP, LEN, N> {
|
||||
pub(crate) fn get_wots_sig(&self) -> &WotsSig<LEN, N> { &self.sig_wots }
|
||||
|
||||
pub(crate) fn get_xmss_auth(&self) -> &GenericArray<GenericArray<u8, N>, HP> { &self.auth }
|
||||
pub(crate) fn get_xmss_auth(&self) -> &[[u8; N]; HP] { &self.auth }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
46
src/wots.rs
46
src/wots.rs
|
|
@ -1,7 +1,6 @@
|
|||
use crate::hashers::Hashers;
|
||||
use crate::helpers;
|
||||
use crate::types::{Adrs, WotsPk, WotsSig, WOTS_PK, WOTS_PRF};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
|
||||
/// Algorithm 4: `chain(X, i, s, PK.seed, ADRS)` on page 17.
|
||||
|
|
@ -14,10 +13,9 @@ use generic_array::{ArrayLength, GenericArray};
|
|||
///
|
||||
/// 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`.
|
||||
pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
|
||||
hashers: &Hashers<K, LEN, M, N>, cap_x: GenericArray<u8, N>, i: u32, s: u32, pk_seed: &[u8],
|
||||
adrs: &Adrs,
|
||||
) -> Option<GenericArray<u8, N>> {
|
||||
pub(crate) fn chain<const K: usize, const LEN: usize, const M: usize, const N: usize>(
|
||||
hashers: &Hashers<K, LEN, M, N>, cap_x: [u8; N], i: u32, s: u32, pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> Option<[u8; N]> {
|
||||
debug_assert!(i + s < u32::MAX);
|
||||
let mut adrs = adrs.clone();
|
||||
|
||||
|
|
@ -61,11 +59,12 @@ pub(crate) fn chain<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLe
|
|||
/// Input: Secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
|
||||
/// Output: WOTS+ public key `pk`.
|
||||
#[allow(clippy::similar_names)] // pk_seed and sk_seed
|
||||
pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
|
||||
pub(crate) fn wots_pkgen<const K: usize, const LEN: usize, const M: usize, const N: usize>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> Result<WotsPk<N>, &'static str> {
|
||||
let mut adrs = adrs.clone();
|
||||
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
|
||||
let mut tmp = [[0u8; N]; LEN];
|
||||
let len32 = u32::try_from(LEN).unwrap();
|
||||
|
||||
// 1: skADRS ← ADRS ▷ Copy address to create key generation key address
|
||||
let mut sk_adrs = adrs.clone();
|
||||
|
|
@ -77,7 +76,7 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
|
|||
sk_adrs.set_key_pair_address(adrs.get_key_pair_address());
|
||||
|
||||
// 4: for i from 0 to len − 1 do
|
||||
for i in 0..LEN::to_u32() {
|
||||
for i in 0..len32 {
|
||||
//
|
||||
// 5: skADRS.setChainAddress(i)
|
||||
sk_adrs.set_chain_address(i);
|
||||
|
|
@ -118,23 +117,25 @@ pub(crate) fn wots_pkgen<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Ar
|
|||
/// Input: Message `M`, secret seed `SK.seed`, public seed `PK.seed`, address `ADRS`. <br>
|
||||
/// Output: WOTS+ signature sig.
|
||||
#[allow(clippy::similar_names)] // pk_seed and sk_seed
|
||||
pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
|
||||
pub(crate) fn wots_sign<const K: usize, const LEN: usize, const M: usize, const N: usize>(
|
||||
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk_seed: &[u8], pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> WotsSig<LEN, N> {
|
||||
let n32 = u32::try_from(N).unwrap();
|
||||
let mut adrs = adrs.clone();
|
||||
let mut sig: WotsSig<LEN, N> = WotsSig::default();
|
||||
//let mut sig: WotsSig<LEN, N> = WotsSig::default();
|
||||
let mut sig: WotsSig<LEN, N> = WotsSig{ data: [[0u8; N]; LEN] };
|
||||
|
||||
// 1: csum ← 0
|
||||
let mut csum = 0_u32;
|
||||
|
||||
// 2:
|
||||
// 3: msg ← base_2b(M, lgw, len1) ▷ Convert message to base w
|
||||
let mut msg = GenericArray::<u32, LEN>::default(); // note: 3 entries left over, used step 10
|
||||
helpers::base_2b(m, crate::LGW, 2 * N::to_u32(), &mut msg[0..(2 * N::to_usize())]);
|
||||
let mut msg = [0u32; LEN]; //GenericArray::<u32, LEN>::default(); // note: 3 entries left over, used step 10
|
||||
helpers::base_2b(m, crate::LGW, 2 * n32, &mut msg[0..(2 * N)]);
|
||||
|
||||
// 4:
|
||||
// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
|
||||
for item in msg.iter().take(2 * N::to_usize()) {
|
||||
for item in msg.iter().take(2 * N) {
|
||||
//
|
||||
// 6: csum ← csum + w − 1 − msg[i]
|
||||
csum += crate::W - 1 - *item;
|
||||
|
|
@ -151,7 +152,7 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
|
|||
&helpers::to_byte(csum, (crate::LEN2 * crate::LGW + 7) / 8),
|
||||
crate::LGW,
|
||||
crate::LEN2,
|
||||
&mut msg[(2 * N::to_usize())..],
|
||||
&mut msg[(2 * N)..],
|
||||
);
|
||||
|
||||
// 11:
|
||||
|
|
@ -192,23 +193,24 @@ pub(crate) fn wots_sign<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: Arr
|
|||
///
|
||||
/// Input: WOTS+ signature `sig`, message `M`, public seed `PK.seed`, address `ADRS`. <br>
|
||||
/// Output: WOTS+ public key `pksig` derived from `sig`.
|
||||
pub(crate) fn wots_pk_from_sig<K: ArrayLength, LEN: ArrayLength, M: ArrayLength, N: ArrayLength>(
|
||||
pub(crate) fn wots_pk_from_sig<const K: usize, const LEN: usize, const M: usize, const N: usize>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sig: &WotsSig<LEN, N>, m: &[u8], pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> WotsPk<N> {
|
||||
let n32 = u32::try_from(N).unwrap();
|
||||
let mut adrs = adrs.clone();
|
||||
let mut tmp: GenericArray<GenericArray<u8, N>, LEN> = GenericArray::default();
|
||||
let mut tmp = [[0u8; N]; LEN]; //GenericArray::default();
|
||||
|
||||
// 1: csum ← 0
|
||||
let mut csum = 0_u32;
|
||||
|
||||
// 2:
|
||||
// 3: msg ← base_2b (M, lgw , len1 ) ▷ Convert message to base w
|
||||
let mut msg: GenericArray<u32, LEN> = GenericArray::default();
|
||||
helpers::base_2b(m, crate::LGW, 2 * N::to_u32(), &mut msg[0..(2 * N::to_usize())]);
|
||||
let mut msg = [0u32; LEN]; //GenericArray::default();
|
||||
helpers::base_2b(m, crate::LGW, 2 * n32, &mut msg[0..(2 * N)]);
|
||||
|
||||
// 4:
|
||||
// 5: for i from 0 to len1 − 1 do ▷ Compute checksum
|
||||
for item in msg.iter().take(2 * N::to_usize()) {
|
||||
for item in msg.iter().take(2 * N) {
|
||||
//
|
||||
// 6: csum ← csum + w − 1 − msg[i]
|
||||
csum += crate::W - 1 - item;
|
||||
|
|
@ -225,12 +227,12 @@ pub(crate) fn wots_pk_from_sig<K: ArrayLength, LEN: ArrayLength, M: ArrayLength,
|
|||
&helpers::to_byte(csum, (crate::LEN2 * crate::LGW + 7) / 8),
|
||||
crate::LGW,
|
||||
crate::LEN2,
|
||||
&mut msg[(2 * N::to_usize())..],
|
||||
&mut msg[(2 * N)..],
|
||||
);
|
||||
|
||||
// 11: for i from 0 to len − 1 do
|
||||
#[allow(clippy::cast_possible_truncation)] // steps 12 and 13
|
||||
for i in 0..LEN::to_usize() {
|
||||
for i in 0..LEN {
|
||||
//
|
||||
// 12: ADRS.setChainAddress(i)
|
||||
adrs.set_chain_address(i as u32);
|
||||
|
|
@ -238,7 +240,7 @@ pub(crate) fn wots_pk_from_sig<K: ArrayLength, LEN: ArrayLength, M: ArrayLength,
|
|||
// 13: tmp[i] ← chain(sig[i], msg[i], w − 1 − msg[i], PK.seed, ADRS)
|
||||
tmp[i] = chain::<K, LEN, M, N>(
|
||||
hashers,
|
||||
sig.data[i].clone(),
|
||||
sig.data[i],
|
||||
msg[i],
|
||||
crate::W - 1 - msg[i],
|
||||
pk_seed,
|
||||
|
|
|
|||
57
src/xmss.rs
57
src/xmss.rs
|
|
@ -1,7 +1,6 @@
|
|||
use crate::hashers::Hashers;
|
||||
use crate::types::{Adrs, XmssSig, TREE, WOTS_HASH};
|
||||
use crate::types::{Adrs, XmssSig, TREE, WOTS_HASH, WotsSig};
|
||||
use crate::wots;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
|
||||
/// Algorithm 8: `xmss_node(SK.seed, i, z, PK.seed, ADRS)` on page 22.
|
||||
|
|
@ -12,19 +11,20 @@ use generic_array::{ArrayLength, GenericArray};
|
|||
/// Output: n-byte root `node`.
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn xmss_node<
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, sk_seed: &[u8], i: u32, z: u32, pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> Result<GenericArray<u8, N>, &'static str> {
|
||||
) -> Result<[u8; N], &'static str> {
|
||||
let hp32 = u32::try_from(HP).unwrap();
|
||||
let mut adrs = adrs.clone();
|
||||
|
||||
// 1: if z > h′ or i ≥ 2^{h −z} then
|
||||
if (z > HP::to_u32()) | (u64::from(i) >= 2u64.pow(HP::to_u32() - z)) {
|
||||
if (z > hp32) | (u64::from(i) >= 2u64.pow(hp32 - z)) {
|
||||
//
|
||||
// 2: return NULL
|
||||
return Err("Alg8: fail");
|
||||
|
|
@ -44,7 +44,6 @@ pub(crate) fn xmss_node<
|
|||
// 7: node ← wots_PKgen(SK.seed, PK.seed, ADRS)
|
||||
wots::wots_pkgen::<K, LEN, M, N>(hashers, sk_seed, pk_seed, &adrs)?
|
||||
.0
|
||||
.clone()
|
||||
|
||||
// 8: else
|
||||
} else {
|
||||
|
|
@ -84,21 +83,23 @@ pub(crate) fn xmss_node<
|
|||
/// Output: XMSS signature SIGXMSS = (sig ∥ AUTH).
|
||||
#[allow(clippy::similar_names)] // sk_seed and pk_seed
|
||||
pub(crate) fn xmss_sign<
|
||||
H: ArrayLength,
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const H: usize,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk_seed: &[u8], idx: u32, pk_seed: &[u8],
|
||||
adrs: &Adrs,
|
||||
) -> Result<XmssSig<HP, LEN, N>, &'static str> {
|
||||
let hp32 = u32::try_from(HP).unwrap();
|
||||
let mut adrs = adrs.clone();
|
||||
let mut sig_xmss = XmssSig::default();
|
||||
//let mut sig_xmss = XmssSig::default();
|
||||
let mut sig_xmss = XmssSig{ sig_wots: WotsSig { data: [[0u8; N]; LEN] }, auth: [[0u8; N]; HP] };
|
||||
|
||||
// 1: for j from 0 to h′-1 do ▷ Build authentication path
|
||||
for j in 0..HP::to_u32() {
|
||||
for j in 0..hp32 {
|
||||
//
|
||||
// 2: k ← idx/2 ^j xor 1
|
||||
let k = (idx >> j) ^ 1;
|
||||
|
|
@ -135,15 +136,16 @@ pub(crate) fn xmss_sign<
|
|||
/// address `ADRS`. <br>
|
||||
/// Output: n-byte root value `node[0]`.
|
||||
pub(crate) fn xmss_pk_from_sig<
|
||||
HP: ArrayLength,
|
||||
K: ArrayLength,
|
||||
LEN: ArrayLength,
|
||||
M: ArrayLength,
|
||||
N: ArrayLength,
|
||||
const HP: usize,
|
||||
const K: usize,
|
||||
const LEN: usize,
|
||||
const M: usize,
|
||||
const N: usize,
|
||||
>(
|
||||
hashers: &Hashers<K, LEN, M, N>, idx: u32, sig_xmss: &XmssSig<HP, LEN, N>, m: &[u8],
|
||||
pk_seed: &[u8], adrs: &Adrs,
|
||||
) -> GenericArray<u8, N> {
|
||||
) -> [u8; N] {
|
||||
let hp32 = u32::try_from(HP).unwrap();
|
||||
let mut adrs = adrs.clone();
|
||||
|
||||
// 1: ADRS.setTypeAndClear(WOTS_HASH) ▷ Compute WOTS+ pk from WOTS+ sig
|
||||
|
|
@ -160,8 +162,7 @@ pub(crate) fn xmss_pk_from_sig<
|
|||
|
||||
// 5: node[0] ← wots_PKFromSig(sig, M, PK.seed, ADRS)
|
||||
let mut node_0 = wots::wots_pk_from_sig::<K, LEN, M, N>(hashers, sig, m, pk_seed, &adrs)
|
||||
.0
|
||||
.clone();
|
||||
.0;
|
||||
|
||||
// 6:
|
||||
// 7: ADRS.setTypeAndClear(TREE) ▷ Compute root from WOTS+ pk and AUTH
|
||||
|
|
@ -171,7 +172,7 @@ pub(crate) fn xmss_pk_from_sig<
|
|||
adrs.set_tree_index(idx);
|
||||
|
||||
// 9: for k from 0 to h′ − 1 do
|
||||
for k in 0..HP::to_u32() {
|
||||
for k in 0..hp32 {
|
||||
//
|
||||
// 10: ADRS.setTreeHeight(k + 1)
|
||||
adrs.set_tree_height(k + 1);
|
||||
|
|
|
|||
Loading…
Reference in a new issue