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

GF2PolynomialCalculator

namespace Org.BouncyCastle.Pqc.Crypto.Hqc { internal class GF2PolynomialCalculator { private readonly int _vecNSize64; private readonly int _paramN; private readonly long _redMask; public GF2PolynomialCalculator(int vecNSize64, int paramN, ulong redMask) { _vecNSize64 = vecNSize64; _paramN = paramN; _redMask = (long)redMask; } internal void MultLongs(long[] res, long[] a, long[] b) { long[] stack = new long[_vecNSize64 << 3]; long[] array = new long[(_vecNSize64 << 1) + 1]; karatsuba(array, 0, a, 0, b, 0, _vecNSize64, stack, 0); reduce(res, array); } private void base_mul(long[] c, int cOffset, long a, long b) { long num = 0; long num2 = 0; long[] array = new long[16]; long[] array2 = new long[4]; array[0] = 0; array[1] = (b & 1152921504606846975); array[2] = array[1] << 1; array[3] = (array[2] ^ array[1]); array[4] = array[2] << 1; array[5] = (array[4] ^ array[1]); array[6] = array[3] << 1; array[7] = (array[6] ^ array[1]); array[8] = array[4] << 1; array[9] = (array[8] ^ array[1]); array[10] = array[5] << 1; array[11] = (array[10] ^ array[1]); array[12] = array[6] << 1; array[13] = (array[12] ^ array[1]); array[14] = array[7] << 1; array[15] = (array[14] ^ array[1]); long num3 = 0; long num4 = a & 15; for (int i = 0; i < 16; i++) { long num5 = num4 - i; num3 ^= (array[i] & (long)(0 - (1 - ((ulong)(num5 | -num5) >> 63)))); } num2 = num3; num = 0; for (byte b2 = 4; b2 < 64; b2 = (byte)(b2 + 4)) { num3 = 0; long num6 = (a >> (int)b2) & 15; for (int j = 0; j < 16; j++) { long num7 = num6 - j; num3 ^= (array[j] & (long)(0 - (1 - ((ulong)(num7 | -num7) >> 63)))); } num2 ^= num3 << (int)b2; num ^= num3 >> 64 - b2; } array2[0] = -((b >> 60) & 1); array2[1] = -((b >> 61) & 1); array2[2] = -((b >> 62) & 1); array2[3] = -((b >> 63) & 1); num2 ^= ((a << 60) & array2[0]); num ^= ((long)((ulong)a >> 4) & array2[0]); num2 ^= ((a << 61) & array2[1]); num ^= ((long)((ulong)a >> 3) & array2[1]); num2 ^= ((a << 62) & array2[2]); num ^= ((long)((ulong)a >> 2) & array2[2]); num2 ^= ((a << 63) & array2[3]); num ^= ((long)((ulong)a >> 1) & array2[3]); c[cOffset] = num2; c[1 + cOffset] = num; } private void karatsuba_add1(long[] alh, int alhOffset, long[] blh, int blhOffset, long[] a, int aOffset, long[] b, int bOffset, int size_l, int size_h) { for (int i = 0; i < size_h; i++) { alh[i + alhOffset] = (a[i + aOffset] ^ a[i + size_l + aOffset]); blh[i + blhOffset] = (b[i + bOffset] ^ b[i + size_l + bOffset]); } if (size_h < size_l) { alh[size_h + alhOffset] = a[size_h + aOffset]; blh[size_h + blhOffset] = b[size_h + bOffset]; } } private void karatsuba_add2(long[] o, int oOffset, long[] tmp1, int tmp1Offset, long[] tmp2, int tmp2Offset, int size_l, int size_h) { for (int i = 0; i < 2 * size_l; i++) { tmp1[i + tmp1Offset] ^= o[i + oOffset]; } for (int j = 0; j < 2 * size_h; j++) { tmp1[j + tmp1Offset] ^= tmp2[j + tmp2Offset]; } for (int k = 0; k < 2 * size_l; k++) { o[k + size_l + oOffset] ^= tmp1[k + tmp1Offset]; } } private void karatsuba(long[] o, int oOffset, long[] a, int aOffset, long[] b, int bOffset, int size, long[] stack, int stackOffset) { if (size == 1) base_mul(o, oOffset, a[aOffset], b[bOffset]); else { int num = size / 2; int num2 = (size + 1) / 2; int num3 = stackOffset; int num4 = num3 + num2; int num5 = num4 + num2; int num6 = oOffset + num2 * 2; stackOffset += 4 * num2; int aOffset2 = aOffset + num2; int bOffset2 = bOffset + num2; karatsuba(o, oOffset, a, aOffset, b, bOffset, num2, stack, stackOffset); karatsuba(o, num6, a, aOffset2, b, bOffset2, num, stack, stackOffset); karatsuba_add1(stack, num3, stack, num4, a, aOffset, b, bOffset, num2, num); karatsuba(stack, num5, stack, num3, stack, num4, num2, stack, stackOffset); karatsuba_add2(o, oOffset, stack, num5, o, num6, num2, num); } } private void reduce(long[] o, long[] a) { for (int i = 0; i < _vecNSize64; i++) { long num = (long)((ulong)a[i + _vecNSize64 - 1] >> _paramN); long num2 = a[i + _vecNSize64] << (int)(64 - ((long)_paramN & 63)); o[i] = (a[i] ^ num ^ num2); } o[_vecNSize64 - 1] &= _redMask; } internal static void AddLongs(long[] res, long[] a, long[] b) { for (int i = 0; i < a.Length; i++) { res[i] = (a[i] ^ b[i]); } } } }