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

WotsPlus

class WotsPlus
using Org.BouncyCastle.Crypto.Utilities; using System; namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus { internal class WotsPlus { private SphincsPlusEngine engine; private uint w; internal WotsPlus(SphincsPlusEngine engine) { this.engine = engine; w = this.engine.WOTS_W; } internal void PKGen(byte[] skSeed, byte[] pkSeed, Adrs paramAdrs, Span<byte> output) { Adrs adrs = new Adrs(paramAdrs); byte[] array = new byte[engine.WOTS_LEN * engine.N]; for (uint num = 0; num < engine.WOTS_LEN; num++) { Adrs adrs2 = new Adrs(paramAdrs); adrs2.SetAdrsType(Adrs.WOTS_PRF); adrs2.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs2.SetChainAddress(num); adrs2.SetHashAddress(0); engine.PRF(pkSeed, skSeed, adrs2, array, engine.N * (int)num); adrs2.SetAdrsType(Adrs.WOTS_HASH); adrs2.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs2.SetChainAddress(num); adrs2.SetHashAddress(0); Chain(0, w - 1, pkSeed, adrs2, array.AsSpan(engine.N * (int)num, engine.N)); } adrs.SetAdrsType(Adrs.WOTS_PK); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); engine.T_l(pkSeed, adrs, array, output); } private bool Chain(uint i, uint s, byte[] pkSeed, Adrs adrs, Span<byte> X) { if (s == 0) return true; if (i + s > w - 1) return false; for (uint num = 0; num < s; num++) { adrs.SetHashAddress(i + num); engine.F(pkSeed, adrs, X); } return true; } internal unsafe byte[] Sign(byte[] M, byte[] skSeed, byte[] pkSeed, Adrs paramAdrs) { Adrs adrs = new Adrs(paramAdrs); int wOTS_LEN = engine.WOTS_LEN; Span<uint> span = new Span<uint>(stackalloc byte[(int)checked(unchecked((ulong)(uint)wOTS_LEN) * 4)], wOTS_LEN); BaseW(M, w, span.Slice(0, engine.WOTS_LEN1)); uint num = 0; for (int i = 0; i < engine.WOTS_LEN1; i++) { num += w - 1 - span[i]; } if (engine.WOTS_LOGW % 8 != 0) num <<= 8 - engine.WOTS_LEN2 * engine.WOTS_LOGW % 8; int num2 = (engine.WOTS_LEN2 * engine.WOTS_LOGW + 7) / 8; Span<byte> bs = new Span<byte>(stackalloc byte[4], 4); Pack.UInt32_To_BE(num, bs); wOTS_LEN = num2; int length = bs.Length; int num3 = length - wOTS_LEN; ReadOnlySpan<byte> x = bs.Slice(num3, length - num3); uint num4 = w; num3 = engine.WOTS_LEN1; BaseW(x, num4, span.Slice(num3, span.Length - num3)); byte[] array = new byte[engine.WOTS_LEN * engine.N]; for (int j = 0; j < engine.WOTS_LEN; j++) { adrs.SetAdrsType(Adrs.WOTS_PRF); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs.SetChainAddress((uint)j); adrs.SetHashAddress(0); engine.PRF(pkSeed, skSeed, adrs, array, engine.N * j); adrs.SetAdrsType(Adrs.WOTS_HASH); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs.SetChainAddress((uint)j); adrs.SetHashAddress(0); Chain(0, span[j], pkSeed, adrs, array.AsSpan(engine.N * j, engine.N)); } return array; } internal void BaseW(ReadOnlySpan<byte> X, uint w, Span<uint> output) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < output.Length; i++) { if (num2 == 0) { num = X[num3++]; num2 += 8; } num2 -= engine.WOTS_LOGW; output[num4++] = (uint)((num >> num2) & (w - 1)); } } internal unsafe void PKFromSig(byte[] sig, byte[] M, byte[] pkSeed, Adrs adrs, Span<byte> output) { Adrs adrs2 = new Adrs(adrs); int wOTS_LEN = engine.WOTS_LEN; Span<uint> span = new Span<uint>(stackalloc byte[(int)checked(unchecked((ulong)(uint)wOTS_LEN) * 4)], wOTS_LEN); BaseW(M, w, span.Slice(0, engine.WOTS_LEN1)); uint num = 0; for (int i = 0; i < engine.WOTS_LEN1; i++) { num += w - 1 - span[i]; } num <<= 8 - engine.WOTS_LEN2 * engine.WOTS_LOGW % 8; int num2 = (engine.WOTS_LEN2 * engine.WOTS_LOGW + 7) / 8; Span<byte> bs = new Span<byte>(stackalloc byte[4], 4); Pack.UInt32_To_BE(num, bs); wOTS_LEN = num2; int length = bs.Length; int num3 = length - wOTS_LEN; ReadOnlySpan<byte> x = bs.Slice(num3, length - num3); uint num4 = w; num3 = engine.WOTS_LEN1; BaseW(x, num4, span.Slice(num3, span.Length - num3)); byte[] array = new byte[engine.WOTS_LEN * engine.N]; for (int j = 0; j < engine.WOTS_LEN; j++) { adrs.SetChainAddress((uint)j); int num5 = engine.N * j; Array.Copy(sig, num5, array, num5, engine.N); Chain(span[j], w - 1 - span[j], pkSeed, adrs, array.AsSpan(num5, engine.N)); } adrs2.SetAdrsType(Adrs.WOTS_PK); adrs2.SetKeyPairAddress(adrs.GetKeyPairAddress()); engine.T_l(pkSeed, adrs2, array, output); } } }