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

Fors

class Fors
using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities; using System.Collections.Generic; namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus { internal class Fors { private readonly SphincsPlusEngine engine; internal Fors(SphincsPlusEngine engine) { this.engine = engine; } internal 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); byte[] array = new byte[engine.N]; for (uint num = 0; num < (uint)(1 << z); num++) { adrs.SetTypeAndClear(6); adrs.SetKeyPairAddress(adrsParam.GetKeyPairAddress()); adrs.SetTreeHeight(0); adrs.SetTreeIndex(s + num); engine.PRF(pkSeed, skSeed, adrs, array, 0); adrs.ChangeAdrsType(3); byte[] array2 = engine.F(pkSeed, adrs, array); adrs.SetTreeHeight(1); 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, array2, array2); adrs.SetTreeHeight(++num2); } stack.Push(new NodeEntry(array2, num2)); } return stack.Peek().nodeValue; } internal SIG_FORS[] Sign(byte[] md, byte[] skSeed, byte[] pkSeed, Adrs paramAdrs, bool legacy) { Adrs adrs = new Adrs(paramAdrs); SIG_FORS[] array = new SIG_FORS[engine.K]; uint[] array2 = legacy ? null : Base2B(md, engine.A, engine.K); uint t = engine.T; for (uint num = 0; num < engine.K; num++) { uint num2 = legacy ? GetMessageIdx(md, (int)num, engine.A) : array2[num]; adrs.SetTypeAndClear(6); adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress()); adrs.SetTreeHeight(0); adrs.SetTreeIndex(num * t + num2); byte[] array3 = new byte[engine.N]; engine.PRF(pkSeed, skSeed, adrs, array3, 0); adrs.ChangeAdrsType(3); byte[][] array4 = new byte[engine.A][]; for (int i = 0; i < engine.A; i++) { uint num3 = (num2 >> i) ^ 1; array4[i] = TreeHash(skSeed, num * t + (num3 << i), i, pkSeed, adrs); } array[num] = new SIG_FORS(array3, array4); } return array; } internal byte[] PKFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, Adrs adrs, bool legacy) { byte[][] array = new byte[engine.K][]; uint t = engine.T; uint[] array2 = legacy ? null : Base2B(message, engine.A, engine.K); for (uint num = 0; num < engine.K; num++) { uint num2 = legacy ? GetMessageIdx(message, (int)num, engine.A) : array2[num]; byte[] sK = sig_fors[num].SK; adrs.SetTreeHeight(0); adrs.SetTreeIndex(num * t + num2); byte[] array3 = engine.F(pkSeed, adrs, sK); byte[][] authPath = sig_fors[num].AuthPath; uint num3 = num * t + num2; for (int i = 0; i < engine.A; i++) { adrs.SetTreeHeight((uint)(i + 1)); if ((num2 >> i) % 2 == 0) { num3 /= 2; adrs.SetTreeIndex(num3); engine.H(pkSeed, adrs, array3, authPath[i], array3); } else { num3 = (num3 - 1) / 2; adrs.SetTreeIndex(num3); engine.H(pkSeed, adrs, authPath[i], array3, array3); } } array[num] = array3; } Adrs adrs2 = new Adrs(adrs); adrs2.SetTypeAndClear(4); adrs2.SetKeyPairAddress(adrs.GetKeyPairAddress()); byte[] array4 = new byte[engine.N]; engine.T_l(pkSeed, adrs2, Arrays.ConcatenateAll(array), array4); return array4; } private static uint GetMessageIdx(byte[] msg, int fors_tree, int fors_height) { int num = fors_tree * fors_height; uint num2 = 0; for (int i = 0; i < fors_height; i++) { num2 ^= (((uint)msg[num >> 3] >> (num & 7)) & 1) << i; num++; } return num2; } private static uint[] Base2B(byte[] msg, int b, int outLen) { uint[] array = new uint[outLen]; int num = 0; int i = 0; BigInteger bigInteger = BigInteger.Zero; for (int j = 0; j < outLen; j++) { for (; i < b; i += 8) { bigInteger = bigInteger.ShiftLeft(8).Add(BigInteger.ValueOf(msg[num])); num++; } i -= b; array[j] = (uint)bigInteger.ShiftRight(i).Mod(BigInteger.Two.Pow(b)).IntValueExact; } return array; } } }