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

WotsPlus

class WotsPlus
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.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, byte[] output) { Adrs adrs = new Adrs(paramAdrs); byte[][] array = new byte[engine.WOTS_LEN][]; byte[] array2 = new byte[engine.N]; for (uint num = 0; num < engine.WOTS_LEN; num++) { Adrs adrs2 = new Adrs(paramAdrs); adrs2.SetTypeAndClear(5); adrs2.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs2.SetChainAddress(num); adrs2.SetHashAddress(0); engine.PRF(pkSeed, skSeed, adrs2, array2, 0); adrs2.SetTypeAndClear(0); adrs2.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs2.SetChainAddress(num); adrs2.SetHashAddress(0); array[num] = Chain(array2, 0, w - 1, pkSeed, adrs2); } adrs.SetTypeAndClear(1); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); engine.T_l(pkSeed, adrs, Arrays.ConcatenateAll(array), output); } private byte[] Chain(byte[] X, uint i, uint s, byte[] pkSeed, Adrs adrs) { if (s == 0) return Arrays.Clone(X); if (i + s > w - 1) return null; byte[] array = X; for (uint num = 0; num < s; num++) { adrs.SetHashAddress(i + num); array = engine.F(pkSeed, adrs, array); } return array; } internal byte[] Sign(byte[] M, byte[] skSeed, byte[] pkSeed, Adrs paramAdrs) { Adrs adrs = new Adrs(paramAdrs); uint[] array = new uint[engine.WOTS_LEN]; BaseW(M, 0, w, array, 0, engine.WOTS_LEN1); uint num = 0; for (int i = 0; i < engine.WOTS_LEN1; i++) { num += w - 1 - array[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; byte[] x = Pack.UInt32_To_BE(num); BaseW(x, 4 - num2, w, array, engine.WOTS_LEN1, engine.WOTS_LEN2); byte[][] array2 = new byte[engine.WOTS_LEN][]; byte[] array3 = new byte[engine.N]; for (int j = 0; j < engine.WOTS_LEN; j++) { adrs.SetTypeAndClear(5); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs.SetChainAddress((uint)j); adrs.SetHashAddress(0); engine.PRF(pkSeed, skSeed, adrs, array3, 0); adrs.SetTypeAndClear(0); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs.SetChainAddress((uint)j); adrs.SetHashAddress(0); array2[j] = Chain(array3, 0, array[j], pkSeed, adrs); } return Arrays.ConcatenateAll(array2); } internal void BaseW(byte[] X, int XOff, uint w, uint[] output, int outOff, int outLen) { int num = 0; int num2 = 0; for (int i = 0; i < outLen; i++) { if (num2 == 0) { num = X[XOff++]; num2 += 8; } num2 -= engine.WOTS_LOGW; output[outOff++] = (uint)((num >> num2) & (w - 1)); } } internal void PKFromSig(byte[] sig, byte[] M, byte[] pkSeed, Adrs adrs, byte[] output) { Adrs adrs2 = new Adrs(adrs); uint[] array = new uint[engine.WOTS_LEN]; BaseW(M, 0, w, array, 0, engine.WOTS_LEN1); uint num = 0; for (int i = 0; i < engine.WOTS_LEN1; i++) { num += w - 1 - array[i]; } num <<= 8 - engine.WOTS_LEN2 * engine.WOTS_LOGW % 8; int num2 = (engine.WOTS_LEN2 * engine.WOTS_LOGW + 7) / 8; byte[] x = Pack.UInt32_To_BE(num); BaseW(x, 4 - num2, w, array, engine.WOTS_LEN1, engine.WOTS_LEN2); byte[] array2 = new byte[engine.N]; byte[][] array3 = new byte[engine.WOTS_LEN][]; for (int j = 0; j < engine.WOTS_LEN; j++) { adrs.SetChainAddress((uint)j); int sourceIndex = engine.N * j; Array.Copy(sig, sourceIndex, array2, 0, engine.N); array3[j] = Chain(array2, array[j], w - 1 - array[j], pkSeed, adrs); } adrs2.SetTypeAndClear(1); adrs2.SetKeyPairAddress(adrs.GetKeyPairAddress()); engine.T_l(pkSeed, adrs2, Arrays.ConcatenateAll(array3), output); } } }