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.SetTypeAndClear(5);
adrs2.SetKeyPairAddress(paramAdrs.GetKeyPairAddress());
adrs2.SetChainAddress(num);
adrs2.SetHashAddress(0);
engine.PRF(pkSeed, skSeed, adrs2, array, engine.N * (int)num);
adrs2.SetTypeAndClear(0);
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.SetTypeAndClear(1);
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.SetTypeAndClear(5);
adrs.SetKeyPairAddress(paramAdrs.GetKeyPairAddress());
adrs.SetChainAddress((uint)j);
adrs.SetHashAddress(0);
engine.PRF(pkSeed, skSeed, adrs, array, engine.N * j);
adrs.SetTypeAndClear(0);
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.SetTypeAndClear(1);
adrs2.SetKeyPairAddress(adrs.GetKeyPairAddress());
engine.T_l(pkSeed, adrs2, array, output);
}
}
}