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