HT
class HT
using Org.BouncyCastle.Utilities;
using System.Collections.Generic;
namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
{
internal class HT
{
private byte[] skSeed;
private byte[] pkSeed;
private SphincsPlusEngine engine;
private WotsPlus wots;
internal byte[] HTPubKey;
internal HT(SphincsPlusEngine engine, byte[] skSeed, byte[] pkSeed)
{
this.skSeed = skSeed;
this.pkSeed = pkSeed;
this.engine = engine;
wots = new WotsPlus(engine);
Adrs adrs = new Adrs();
adrs.SetLayerAddress(engine.D - 1);
adrs.SetTreeAddress(0);
if (skSeed != null)
HTPubKey = xmss_PKgen(skSeed, pkSeed, adrs);
else
HTPubKey = null;
}
internal void Sign(byte[] M, ulong idx_tree, uint idx_leaf, byte[] signature, ref int pos)
{
Adrs adrs = new Adrs();
adrs.SetLayerAddress(0);
adrs.SetTreeAddress(idx_tree);
SIG_XMSS sIG_XMSS = xmss_sign(M, skSeed, idx_leaf, pkSeed, adrs);
SIG_XMSS[] array = new SIG_XMSS[engine.D];
array[0] = sIG_XMSS;
adrs.SetLayerAddress(0);
adrs.SetTreeAddress(idx_tree);
byte[] m = xmss_pkFromSig(idx_leaf, sIG_XMSS, M, pkSeed, adrs);
for (uint num = 1; num < engine.D; num++) {
idx_leaf = (uint)((long)idx_tree & (long)((1 << (int)engine.H_PRIME) - 1));
idx_tree >>= (int)engine.H_PRIME;
adrs.SetLayerAddress(num);
adrs.SetTreeAddress(idx_tree);
sIG_XMSS = (array[num] = xmss_sign(m, skSeed, idx_leaf, pkSeed, adrs));
if (num < engine.D - 1)
m = xmss_pkFromSig(idx_leaf, sIG_XMSS, m, pkSeed, adrs);
}
for (int i = 0; i < array.Length; i++) {
array[i].CopyToSignature(signature, ref pos);
}
}
private byte[] xmss_PKgen(byte[] skSeed, byte[] pkSeed, Adrs adrs)
{
return TreeHash(skSeed, 0, (int)engine.H_PRIME, pkSeed, adrs);
}
private byte[] xmss_pkFromSig(uint idx, SIG_XMSS sig_xmss, byte[] M, byte[] pkSeed, Adrs paramAdrs)
{
Adrs adrs = new Adrs(paramAdrs);
adrs.SetTypeAndClear(0);
adrs.SetKeyPairAddress(idx);
byte[] wotsSig = sig_xmss.WotsSig;
byte[][] xmssAuth = sig_xmss.XmssAuth;
byte[] array = new byte[engine.N];
wots.PKFromSig(wotsSig, M, pkSeed, adrs, array);
adrs.SetTypeAndClear(2);
adrs.SetTreeIndex(idx);
for (uint num = 0; num < engine.H_PRIME; num++) {
adrs.SetTreeHeight(num + 1);
if ((long)idx / (long)(1 << (int)num) % 2 == 0) {
adrs.SetTreeIndex(adrs.GetTreeIndex() / 2);
engine.H(pkSeed, adrs, array, xmssAuth[num], array);
} else {
adrs.SetTreeIndex((adrs.GetTreeIndex() - 1) / 2);
engine.H(pkSeed, adrs, xmssAuth[num], array, array);
}
}
return array;
}
private SIG_XMSS xmss_sign(byte[] M, byte[] skSeed, uint idx, byte[] pkSeed, Adrs paramAdrs)
{
byte[][] array = new byte[engine.H_PRIME][];
Adrs adrs = new Adrs(paramAdrs);
adrs.SetTypeAndClear(2);
adrs.SetLayerAddress(paramAdrs.GetLayerAddress());
adrs.SetTreeAddress(paramAdrs.GetTreeAddress());
for (int i = 0; i < engine.H_PRIME; i++) {
uint num = (idx >> i) ^ 1;
array[i] = TreeHash(skSeed, num << i, i, pkSeed, adrs);
}
adrs = new Adrs(paramAdrs);
adrs.SetTypeAndClear(0);
adrs.SetKeyPairAddress(idx);
return new SIG_XMSS(wots.Sign(M, skSeed, pkSeed, adrs), array);
}
private byte[] TreeHash(byte[] skSeed, uint s, int z, byte[] pkSeed, Adrs adrsParam)
{
if (s >> z << z != s)
return null;
Stack<NodeEntry> stack = new Stack<NodeEntry>();
Adrs adrs = new Adrs(adrsParam);
for (uint num = 0; num < (uint)(1 << z); num++) {
adrs.SetTypeAndClear(0);
adrs.SetKeyPairAddress(s + num);
byte[] array = new byte[engine.N];
wots.PKGen(skSeed, pkSeed, adrs, array);
adrs.SetTypeAndClear(2);
adrs.SetTreeHeight(1);
adrs.SetTreeIndex(s + num);
uint num2 = 1;
uint num3 = s + num;
while (stack.Count > 0 && stack.Peek().nodeHeight == num2) {
num3 = (num3 - 1) / 2;
adrs.SetTreeIndex(num3);
NodeEntry nodeEntry = stack.Pop();
engine.H(pkSeed, adrs, nodeEntry.nodeValue, array, array);
adrs.SetTreeHeight(++num2);
}
stack.Push(new NodeEntry(array, num2));
}
return stack.Peek().nodeValue;
}
internal bool Verify(byte[] M, SIG_XMSS[] sig_ht, byte[] pkSeed, ulong idx_tree, uint idx_leaf, byte[] PK_HT)
{
Adrs adrs = new Adrs();
SIG_XMSS sig_xmss = sig_ht[0];
adrs.SetLayerAddress(0);
adrs.SetTreeAddress(idx_tree);
byte[] array = xmss_pkFromSig(idx_leaf, sig_xmss, M, pkSeed, adrs);
for (uint num = 1; num < engine.D; num++) {
idx_leaf = (uint)((long)idx_tree & (long)((1 << (int)engine.H_PRIME) - 1));
idx_tree >>= (int)engine.H_PRIME;
sig_xmss = sig_ht[num];
adrs.SetLayerAddress(num);
adrs.SetTreeAddress(idx_tree);
array = xmss_pkFromSig(idx_leaf, sig_xmss, array, pkSeed, adrs);
}
return Arrays.AreEqual(PK_HT, array);
}
}
}