<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />

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); } } }