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

HqcKeccakRandomGenerator

using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Pqc.Crypto.Hqc { internal sealed class HqcKeccakRandomGenerator { private static readonly ulong[] KeccakRoundConstants = new ulong[24] { 1, 32898, 9223372036854808714, 9223372039002292224, 32907, 2147483649, 9223372039002292353, 9223372036854808585, 138, 136, 2147516425, 2147483658, 2147516555, 9223372036854775947, 9223372036854808713, 9223372036854808579, 9223372036854808578, 9223372036854775936, 32778, 9223372039002259466, 9223372039002292353, 9223372036854808704, 2147483649, 9223372039002292232 }; private readonly ulong[] state = new ulong[26]; private readonly byte[] dataQueue = new byte[192]; private int rate; private int fixedOutputLength; public HqcKeccakRandomGenerator() { Init(288); } public HqcKeccakRandomGenerator(int bitLength) { Init(bitLength); } private void Init(int bitLength) { switch (bitLength) { case 128: case 224: case 256: case 288: case 384: case 512: InitSponge(1600 - (bitLength << 1)); break; default: throw new ArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512."); } } private void InitSponge(int rate) { if (rate <= 0 || rate >= 1600 || rate % 64 != 0) throw new InvalidOperationException("invalid rate value"); this.rate = rate; Arrays.Fill(state, 0); Arrays.Fill(dataQueue, 0); fixedOutputLength = (1600 - rate) / 2; } private void KeccakIncAbsorb(byte[] input, int inputLen) { int num = 0; int num2 = rate >> 3; while ((long)inputLen + (long)state[25] >= num2) { for (int i = 0; i < (long)num2 - (long)state[25]; i++) { int num3 = (int)((long)state[25] + (long)i) >> 3; state[num3] ^= (ulong)input[i + num] << 8 * (((int)state[25] + i) & 7); } inputLen -= (int)((long)num2 - (long)state[25]); num += (int)((long)num2 - (long)state[25]); state[25] = 0; KeccakDigest.KeccakPermutation(state); } for (int j = 0; j < inputLen; j++) { int num4 = (int)((long)state[25] + (long)j) >> 3; state[num4] ^= (ulong)input[j + num] << 8 * (((int)state[25] + j) & 7); } state[25] = (ulong)((long)state[25] + (long)inputLen); } private void KeccakIncFinalize(int p) { int num = rate >> 3; state[(int)state[25] >> 3] ^= (ulong)((long)p << (int)(8 * (state[25] & 7))); state[num - 1 >> 3] ^= (ulong)(128 << 8 * ((num - 1) & 7)); state[25] = 0; } private void KeccakIncSqueeze(byte[] output, int outLen) { int num = rate >> 3; int i; for (i = 0; i < outLen && (long)i < (long)state[25]; i++) { output[i] = (byte)(state[(int)((long)num - (long)state[25] + i >> 3)] >> (int)(8 * (((long)num - (long)state[25] + i) & 7))); } int num2 = i; outLen -= i; state[25] = (ulong)((long)state[25] - (long)i); while (outLen > 0) { KeccakDigest.KeccakPermutation(state); for (i = 0; i < outLen && i < num; i++) { output[num2 + i] = (byte)(state[i >> 3] >> 8 * (i & 7)); } num2 += i; outLen -= i; state[25] = (ulong)(num - i); } } public void Squeeze(byte[] output, int outLen) { KeccakIncSqueeze(output, outLen); } public void RandomGeneratorInit(byte[] entropyInput, byte[] personalizationString, int entropyLen, int perLen) { byte[] array = new byte[1] { 1 }; KeccakIncAbsorb(entropyInput, entropyLen); KeccakIncAbsorb(personalizationString, perLen); KeccakIncAbsorb(array, array.Length); KeccakIncFinalize(31); } public void SeedExpanderInit(byte[] seed, int seedLen) { byte[] input = new byte[1] { 2 }; KeccakIncAbsorb(seed, seedLen); KeccakIncAbsorb(input, 1); KeccakIncFinalize(31); } public void ExpandSeed(byte[] output, int outLen) { int num = outLen & 7; KeccakIncSqueeze(output, outLen - num); if (num != 0) { byte[] array = new byte[8]; KeccakIncSqueeze(array, 8); Array.Copy(array, 0, output, outLen - num, num); } } public void SHAKE256_512_ds(byte[] output, byte[] input, int inLen, byte[] domain) { Arrays.Fill(state, 0); KeccakIncAbsorb(input, inLen); KeccakIncAbsorb(domain, domain.Length); KeccakIncFinalize(31); KeccakIncSqueeze(output, 64); } } }