Fors
class Fors
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 ((long)s % (long)(1 << z) != 0)
return null;
Stack<NodeEntry> stack = new Stack<NodeEntry>();
Adrs adrs = new Adrs(adrsParam);
byte[] array = new byte[engine.N];
for (uint num = 0; num < 1 << z; num++) {
adrs.SetAdrsType(Adrs.FORS_PRF);
adrs.SetKeyPairAddress(adrsParam.GetKeyPairAddress());
adrs.SetTreeHeight(0);
adrs.SetTreeIndex(s + num);
engine.PRF(pkSeed, skSeed, adrs, array, 0);
adrs.ChangeAdrsType(Adrs.FORS_TREE);
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);
engine.H(pkSeed, adrs, stack.Pop().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)
{
Adrs adrs = new Adrs(paramAdrs);
SIG_FORS[] array = new SIG_FORS[engine.K];
uint t = engine.T;
for (uint num = 0; num < engine.K; num++) {
uint messageIdx = GetMessageIdx(md, (int)num, engine.A);
adrs.SetAdrsType(Adrs.FORS_PRF);
adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress());
adrs.SetTreeHeight(0);
adrs.SetTreeIndex(num * t + messageIdx);
byte[] array2 = new byte[engine.N];
engine.PRF(pkSeed, skSeed, adrs, array2, 0);
adrs.ChangeAdrsType(Adrs.FORS_TREE);
byte[][] array3 = new byte[engine.A][];
for (int i = 0; i < engine.A; i++) {
uint num2 = (messageIdx >> i) ^ 1;
array3[i] = TreeHash(skSeed, num * t + (num2 << i), i, pkSeed, adrs);
}
array[num] = new SIG_FORS(array2, array3);
}
return array;
}
internal byte[] PKFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, Adrs adrs)
{
byte[][] array = new byte[engine.K][];
uint t = engine.T;
for (uint num = 0; num < engine.K; num++) {
uint messageIdx = GetMessageIdx(message, (int)num, engine.A);
byte[] sK = sig_fors[num].SK;
adrs.SetTreeHeight(0);
adrs.SetTreeIndex(num * t + messageIdx);
byte[] array2 = engine.F(pkSeed, adrs, sK);
byte[][] authPath = sig_fors[num].AuthPath;
uint num2 = num * t + messageIdx;
for (int i = 0; i < engine.A; i++) {
adrs.SetTreeHeight((uint)(i + 1));
if ((messageIdx >> i) % 2 == 0) {
num2 /= 2;
adrs.SetTreeIndex(num2);
engine.H(pkSeed, adrs, array2, authPath[i], array2);
} else {
num2 = (num2 - 1) / 2;
adrs.SetTreeIndex(num2);
engine.H(pkSeed, adrs, authPath[i], array2, array2);
}
}
array[num] = array2;
}
Adrs adrs2 = new Adrs(adrs);
adrs2.SetAdrsType(Adrs.FORS_PK);
adrs2.SetKeyPairAddress(adrs.GetKeyPairAddress());
byte[] array3 = new byte[engine.N];
engine.T_l(pkSeed, adrs2, Arrays.ConcatenateAll(array), array3);
return array3;
}
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;
}
}
}