2024-02-09 22:31:05 +00:00
|
|
|
|
use crate::hashers::Hashers;
|
|
|
|
|
|
use crate::types::{Adrs, HtSig};
|
|
|
|
|
|
use crate::xmss;
|
2024-02-09 23:43:59 +00:00
|
|
|
|
use generic_array::{ArrayLength, GenericArray};
|
2024-02-09 22:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Algorithm 11: `ht_sign(M, SK.seed, PK.seed, idx_tree, idx_leaf)` on page 27.
|
|
|
|
|
|
/// Generate a hypertree signature.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Input: Message `M`, private seed `SK.seed`, public seed `PK.seed`, tree index `idx_tree`, leaf
|
|
|
|
|
|
/// index `idx_leaf`. <br>
|
|
|
|
|
|
/// 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,
|
|
|
|
|
|
>(
|
|
|
|
|
|
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;
|
|
|
|
|
|
//
|
|
|
|
|
|
// 1: ADRS ← toByte(0, 32)
|
|
|
|
|
|
let mut adrs = Adrs::default();
|
|
|
|
|
|
|
|
|
|
|
|
// 2:
|
|
|
|
|
|
// 3: ADRS.setTreeAddress(idxtree)
|
|
|
|
|
|
adrs.set_tree_address(idx_tree);
|
|
|
|
|
|
|
|
|
|
|
|
// 4: SIG_tmp ← xmss_sign(M, SK.seed, idxleaf, PK.seed, ADRS)
|
|
|
|
|
|
let mut sig_tmp =
|
|
|
|
|
|
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();
|
|
|
|
|
|
sig_ht.xmss_sigs[0] = sig_tmp.clone();
|
|
|
|
|
|
|
|
|
|
|
|
// 6: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, M, PK.seed, ADRS)
|
|
|
|
|
|
let mut root =
|
|
|
|
|
|
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() {
|
|
|
|
|
|
//
|
|
|
|
|
|
// 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")?;
|
|
|
|
|
|
|
|
|
|
|
|
// 9: idx_tree ← idx_tree ≫ h′ ▷ Remove least significant h′ bits from idx_tree
|
|
|
|
|
|
idx_tree >>= HP::to_u32();
|
|
|
|
|
|
|
|
|
|
|
|
// 10: ADRS.setLayerAddress(j)
|
|
|
|
|
|
adrs.set_layer_address(j);
|
|
|
|
|
|
|
|
|
|
|
|
// 11: ADRS.setTreeAddress(idx_tree)
|
|
|
|
|
|
adrs.set_tree_address(idx_tree);
|
|
|
|
|
|
|
|
|
|
|
|
// 12: SIG_tmp ← xmss_sign(root, SK.seed, idx_leaf, PK.seed, ADRS)
|
|
|
|
|
|
sig_tmp = xmss::xmss_sign::<H, HP, K, LEN, M, N>(
|
|
|
|
|
|
hashers, &root, sk_seed, idx_leaf, pk_seed, &adrs,
|
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 13: SIG_HT ← SIG_HT ∥ SIG_tmp
|
|
|
|
|
|
sig_ht.xmss_sigs[j as usize] = sig_tmp.clone();
|
|
|
|
|
|
|
|
|
|
|
|
// 14: if j < d − 1 then
|
|
|
|
|
|
if j < (D::to_u32() - 1) {
|
|
|
|
|
|
//
|
|
|
|
|
|
// 15: root ← xmss_PKFromSig(idx_leaf, SIG_tmp, root, PK.seed, ADRS)
|
|
|
|
|
|
root = xmss::xmss_pk_from_sig::<HP, K, LEN, M, N>(
|
|
|
|
|
|
hashers, idx_leaf, &sig_tmp, &root, pk_seed, &adrs,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 16: end if
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 17: end for
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 18: return SIGHT
|
|
|
|
|
|
Ok(sig_ht)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Algorithm 12: `ht_verify(M, SIG_HT, PK.seed, idx_tree, idx_leaf, PK.root)` on page 28.
|
|
|
|
|
|
/// Verify a hypertree signature.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Input: Message `M`, signature `SIG_HT`, public seed `PK.seed`, tree index `idx_tree`, leaf index `idx_leaf`,
|
|
|
|
|
|
/// 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,
|
|
|
|
|
|
>(
|
|
|
|
|
|
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>,
|
|
|
|
|
|
) -> bool {
|
|
|
|
|
|
let mut idx_tree = idx_tree;
|
|
|
|
|
|
//
|
|
|
|
|
|
// 1: ADRS ← toByte(0, 32)
|
|
|
|
|
|
let mut adrs = Adrs::default();
|
|
|
|
|
|
|
|
|
|
|
|
// 2:
|
|
|
|
|
|
// 3: ADRS.setTreeAddress(idx_tree)
|
|
|
|
|
|
adrs.set_tree_address(idx_tree);
|
|
|
|
|
|
|
|
|
|
|
|
// 4: SIG_tmp ← SIG_HT.getXMSSSignature(0) ▷ SIG_HT [0 : (h′ + len) · n]
|
|
|
|
|
|
let sig_tmp = sig_ht.xmss_sigs[0].clone();
|
|
|
|
|
|
|
|
|
|
|
|
// 5: node ← xmss_PKFromSig(idx_leaf, SIG_tmp, M, PK.seed, ADRS)
|
|
|
|
|
|
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() {
|
|
|
|
|
|
//
|
|
|
|
|
|
// 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
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
|
|
// 9: ADRS.setLayerAddress(j)
|
|
|
|
|
|
adrs.set_layer_address(j);
|
|
|
|
|
|
|
|
|
|
|
|
// 10: ADRS.setTreeAddress(idx_tree)
|
|
|
|
|
|
adrs.set_tree_address(idx_tree);
|
|
|
|
|
|
|
|
|
|
|
|
// 11: SIG_tmp ← SIG_HT.getXMSSSignature(j) ▷ SIGHT [ j · (h′ + len) · n : ( j + 1)(h′ + len) · n]
|
|
|
|
|
|
let sig_tmp = sig_ht.xmss_sigs[j as usize].clone();
|
|
|
|
|
|
|
|
|
|
|
|
// 12: node ← xmss_PKFromSig(idx_leaf, SIG_tmp, node, PK.seed, ADRS)
|
|
|
|
|
|
node = xmss::xmss_pk_from_sig(hashers, idx_leaf, &sig_tmp, &node, pk_seed, &adrs);
|
|
|
|
|
|
|
|
|
|
|
|
// 13: end for
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 14: if node = PK.root then
|
|
|
|
|
|
// 15: return true
|
|
|
|
|
|
// 16: else
|
|
|
|
|
|
// 17: return false
|
|
|
|
|
|
// 18: end if
|
|
|
|
|
|
node == *pk_root // TODO: CT equal
|
|
|
|
|
|
}
|