<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

NtruPrimeEngine

using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; using System.Collections.Generic; namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime { internal class NtruPrimeEngine { private readonly int _skBytes; private readonly int _pkBytes; private readonly int _ctBytes; private readonly int _secretKeyBytes; private readonly int _publicKeyBytes; private readonly int _ciphertextsBytes; private readonly int _confirmBytes; private readonly int _inputsBytes; private readonly int _topBytes; private readonly int _seedBytes; private readonly int _smallBytes; private readonly int _hashBytes; private readonly int SessionKeyBytes; private readonly int _p; private readonly int _q; private readonly int _roundedBytes; private readonly bool _lpr; private readonly int _w; private readonly int _tau0; private readonly int _tau1; private readonly int _tau2; private readonly int _tau3; private readonly int _I; private readonly int _q12; public int PrivateKeySize => _skBytes; public int PublicKeySize => _pkBytes; public int CipherTextSize => _ctBytes; public int SessionKeySize => SessionKeyBytes; public NtruPrimeEngine(int p, int q, bool lpr, int w, int tau0, int tau1, int tau2, int tau3, int skBytes, int pkBytes, int ctBytes, int roundedBytes, int rqBytes, int defaultKeyLen) { _p = p; _q = q; _w = w; _tau0 = tau0; _tau1 = tau1; _tau2 = tau2; _tau3 = tau3; _roundedBytes = roundedBytes; _skBytes = skBytes; _pkBytes = pkBytes; _ctBytes = ctBytes; _lpr = lpr; _confirmBytes = 32; SessionKeyBytes = defaultKeyLen; _smallBytes = (p + 3) / 4; _q12 = (q - 1) / 2; _hashBytes = 32; if (lpr) { _seedBytes = 32; _I = 256; _inputsBytes = _I / 8; _topBytes = _I / 2; _ciphertextsBytes = roundedBytes + _topBytes; _secretKeyBytes = _smallBytes; _publicKeyBytes = _seedBytes + roundedBytes; } else { _inputsBytes = _smallBytes; _ciphertextsBytes = _roundedBytes; _secretKeyBytes = 2 * _smallBytes; _publicKeyBytes = rqBytes; } } public void kem_keypair(byte[] pk, byte[] sk, SecureRandom random) { KeyGen(random, pk, sk); Array.Copy(pk, 0, sk, _secretKeyBytes, _publicKeyBytes); random.NextBytes(sk, _secretKeyBytes + _publicKeyBytes, _inputsBytes); HashPrefix(sk, 4, pk, _publicKeyBytes); } public void kem_enc(byte[] ct, byte[] ss, byte[] pk, SecureRandom random) { sbyte[] array = (!_lpr) ? new sbyte[_p] : new sbyte[_I]; byte[] array2 = new byte[_inputsBytes]; byte[] array3 = new byte[_hashBytes]; HashPrefix(array3, 4, pk, _publicKeyBytes); if (_lpr) InputsRandom(array, random); else ShortRandom(array, random); Hide(ct, array2, array, pk, array3); HashSession(ss, 1, array2, ct); } public void kem_dec(byte[] ss, byte[] ct, byte[] sk) { byte[] array = new byte[sk.Length - _secretKeyBytes]; Array.Copy(sk, _secretKeyBytes, array, 0, array.Length); byte[] array2 = new byte[array.Length - _publicKeyBytes]; Array.Copy(array, _publicKeyBytes, array2, 0, array2.Length); byte[] array3 = new byte[array2.Length - _inputsBytes]; Array.Copy(array2, _inputsBytes, array3, 0, array3.Length); sbyte[] array4 = (!_lpr) ? new sbyte[_p] : new sbyte[_I]; byte[] array5 = new byte[_inputsBytes]; byte[] array6 = new byte[_ciphertextsBytes + _confirmBytes]; byte[] c = Arrays.Clone(ct); Decrypt(array4, c, sk); Hide(array6, array5, array4, array, array3); int num = ctDiffMask(ct, array6); for (int i = 0; i < _inputsBytes; i++) { array5[i] ^= (byte)(num & (array5[i] ^ array2[i])); } HashSession(ss, 1 + num, array5, ct); } private void KeyGen(SecureRandom random, byte[] pk, byte[] sk) { if (_lpr) { short[] array = new short[_p]; sbyte[] a = new sbyte[_p]; byte[] array2 = new byte[_seedBytes]; random.NextBytes(array2); Array.Copy(array2, 0, pk, 0, _seedBytes); short[] array3 = new short[_p]; Generator(array3, array2); ShortRandom(a, random); short[] output = new short[_p]; RqMult(ref output, array3, ref a); Round(array, output); byte[] array4 = new byte[pk.Length]; RoundedEncode(array4, array); Array.Copy(array4, 0, pk, _seedBytes, pk.Length - _seedBytes); ByteEncode(sk, a); } else { short[] output2 = new short[_p]; sbyte[] array5 = new sbyte[_p]; sbyte[] array6 = new sbyte[_p]; sbyte[] array7 = new sbyte[_p]; short[] array8 = new short[_p]; do { ByteRandom(array7, random); } while (R3Recip(array6, array7) != 0); ShortRandom(array5, random); RqRecip3(array8, array5); RqMult(ref output2, array8, array7); RqEncode(pk, output2); ByteEncode(sk, array5); byte[] array9 = new byte[sk.Length]; ByteEncode(array9, array6); Array.Copy(array9, 0, sk, _smallBytes, sk.Length - _smallBytes); } } private void ByteRandom(sbyte[] output, SecureRandom random) { byte[] array = new byte[4]; for (int i = 0; i < _p; i++) { random.NextBytes(array); output[i] = (sbyte)(((BitConverter.ToUInt32(array, 0) & 1073741823) * 3 >> 30) - 1); } } private int R3Recip(sbyte[] output, sbyte[] input) { sbyte[] array = new sbyte[_p + 1]; sbyte[] array2 = new sbyte[_p + 1]; sbyte[] array3 = new sbyte[_p + 1]; sbyte[] array4 = new sbyte[_p + 1]; for (int i = 0; i <= _p; i++) { array3[i] = 0; array4[i] = 0; } array4[0] = 1; for (int j = 0; j < _p; j++) { array[j] = 0; } array[0] = 1; array[_p - 1] = (array[_p] = -1); for (int k = 0; k < _p; k++) { array2[_p - 1 - k] = input[k]; } array2[_p] = 0; int num = 1; int num3; for (int l = 0; l < 2 * _p - 1; l++) { for (int num2 = _p; num2 > 0; num2--) { array3[num2] = array3[num2 - 1]; } array3[0] = 0; num3 = -array2[0] * array[0]; int num4 = NegativeMask((short)(-num)) & ((array2[0] != 0) ? (-1) : 0); num ^= (num4 & (num ^ -num)); num++; for (int m = 0; m < _p + 1; m++) { int num5 = num4 & (array[m] ^ array2[m]); array[m] ^= (sbyte)num5; array2[m] ^= (sbyte)num5; num5 = (num4 & (array3[m] ^ array4[m])); array3[m] ^= (sbyte)num5; array4[m] ^= (sbyte)num5; } for (int n = 0; n < _p + 1; n++) { array2[n] = (sbyte)(Mod((double)(array2[n] + num3 * array[n] + 1), 3) - 1); } for (int num6 = 0; num6 < _p + 1; num6++) { array4[num6] = (sbyte)(Mod((double)(array4[num6] + num3 * array3[num6] + 1), 3) - 1); } for (int num7 = 0; num7 < _p; num7++) { array2[num7] = array2[num7 + 1]; } array2[_p] = 0; } num3 = array[0]; for (int num8 = 0; num8 < _p; num8++) { output[num8] = (sbyte)(num3 * array3[_p - 1 - num8]); } if (num == 0) return 0; return -1; } private int RqRecip3(short[] output, sbyte[] input) { short[] array = new short[_p + 1]; short[] array2 = new short[_p + 1]; short[] array3 = new short[_p + 1]; short[] array4 = new short[_p + 1]; for (int i = 0; i < _p + 1; i++) { array3[i] = 0; array4[i] = 0; } array4[0] = FqRecip(3); for (int j = 0; j < _p; j++) { array[j] = 0; } array[0] = 1; array[_p - 1] = (array[_p] = -1); for (int k = 0; k < _p; k++) { array2[_p - 1 - k] = input[k]; } array2[_p] = 0; int num = 1; for (int l = 0; l < 2 * _p - 1; l++) { for (int num2 = _p; num2 > 0; num2--) { array3[num2] = array3[num2 - 1]; } array3[0] = 0; int num3 = NegativeMask((short)(-num)) & ((array2[0] != 0) ? (-1) : 0); num ^= (num3 & (num ^ -num)); num++; for (int m = 0; m < _p + 1; m++) { int num4 = num3 & (array[m] ^ array2[m]); array[m] ^= (short)num4; array2[m] ^= (short)num4; num4 = (num3 & (array3[m] ^ array4[m])); array3[m] ^= (short)num4; array4[m] ^= (short)num4; } int num5 = array[0]; int num6 = array2[0]; for (int n = 0; n < _p + 1; n++) { array2[n] = ArithmeticMod_q(num5 * array2[n] - num6 * array[n]); } for (int num7 = 0; num7 < _p + 1; num7++) { array4[num7] = ArithmeticMod_q(num5 * array4[num7] - num6 * array3[num7]); } for (int num8 = 0; num8 < _p; num8++) { array2[num8] = array2[num8 + 1]; } array2[_p] = 0; } short num9 = FqRecip(array[0]); for (int num10 = 0; num10 < _p; num10++) { output[num10] = ArithmeticMod_q(num9 * array3[_p - 1 - num10]); } if (num == 0) return 0; return -1; } private short FqRecip(short a1) { int i = 1; short num = a1; for (; i < _q - 2; i++) { num = ArithmeticMod_q(a1 * num); } return num; } private void RqMult(ref short[] output, short[] f, sbyte[] g) { short[] array = new short[_p + _p + 1]; for (int i = 0; i < _p; i++) { short num = 0; for (int j = 0; j <= i; j++) { num = ArithmeticMod_q(num + f[j] * g[i - j]); } array[i] = num; } for (int k = _p; k < _p + _p - 1; k++) { short num = 0; for (int l = k - _p + 1; l < _p; l++) { num = ArithmeticMod_q(num + f[l] * g[k - l]); } array[k] = num; } for (int num2 = _p + _p - 2; num2 >= _p; num2--) { array[num2 - _p] = ArithmeticMod_q(array[num2 - _p] + array[num2]); array[num2 - _p + 1] = ArithmeticMod_q(array[num2 - _p + 1] + array[num2]); } Array.Copy(array, 0, output, 0, _p); } private void RqEncode(byte[] output, short[] r) { ushort[] array = new ushort[_p]; ushort[] array2 = new ushort[_p]; for (int i = 0; i < _p; i++) { array[i] = (ushort)(r[i] + _q12); array2[i] = (ushort)_q; } Encode(output, 0, array, array2, _p); } private void RqDecode(short[] output, byte[] s) { ushort[] array2 = new ushort[_p]; ushort[] array = new ushort[_p]; for (int i = 0; i < _p; i++) { array[i] = (ushort)_q; } List<byte> s2 = new List<byte>(s); List<ushort> m = new List<ushort>(array); List<ushort> list = Decode(s2, m); for (int j = 0; j < _p; j++) { output[j] = (short)(list[j] - _q12); } } private void RqMult3(short[] output, short[] f) { for (int i = 0; i < _p; i++) { output[i] = ArithmeticMod_q(f[i] * 3); } } private void R3FromRq(sbyte[] output, short[] r) { for (int i = 0; i < _p; i++) { output[i] = (sbyte)ArithmeticMod_3(r[i]); } } private void R3Mult(sbyte[] output, sbyte[] f, sbyte[] g) { sbyte[] array = new sbyte[_p + _p + 1]; for (int i = 0; i < _p; i++) { sbyte b = 0; for (int j = 0; j <= i; j++) { b = (sbyte)ArithmeticMod_3(b + f[j] * g[i - j]); } array[i] = b; } for (int k = _p; k < _p + _p - 1; k++) { sbyte b = 0; for (int l = k - _p + 1; l < _p; l++) { b = (sbyte)ArithmeticMod_3(b + f[l] * g[k - l]); } array[k] = b; } for (int num = _p + _p - 2; num >= _p; num--) { array[num - _p] = (sbyte)ArithmeticMod_3(array[num - _p] + array[num]); array[num - _p + 1] = (sbyte)ArithmeticMod_3(array[num - _p + 1] + array[num]); } Array.Copy(array, 0, output, 0, _p); } private int WeightMask(sbyte[] r) { int num = 0; for (int i = 0; i < _p; i++) { num += (r[i] & 1); } return NonZeroMask((short)(num - _w)); } private int NonZeroMask(short x) { if (x != 0) return -1; return 0; } private List<ushort> Decode(List<byte> S, List<ushort> M) { int num = 16384; if (M.Count == 0) return new List<ushort>(); if (M.Count == 1) { if (M[0] == 1) return new List<ushort> { 0 }; if (M[0] <= 256) return new List<ushort> { (ushort)Mod((double)(int)S[0], (double)(int)M[0]) }; return new List<ushort> { (ushort)Mod((double)(uint)(S[0] + (S[1] << 8)), (double)(int)M[0]) }; } int num2 = 0; List<ushort> list = new List<ushort>(); List<uint> list2 = new List<uint>(); List<ushort> list3 = new List<ushort>(); for (int i = 0; i < M.Count - 1; i += 2) { uint num3 = (uint)(M[i] * M[i + 1]); ushort num4 = 0; uint num5 = 1; while (num3 >= num) { num4 = (ushort)(num4 + S[num2] * num5); num5 *= 256; num2++; num3 = (uint)System.Math.Floor((double)((num3 + 255) / 256)); } list.Add(num4); list2.Add(num5); list3.Add((ushort)num3); } if (M.Count % 2 != 0) list3.Add(M[M.Count - 1]); List<byte> list4 = new List<byte>(); list4 = S.GetRange(num2, S.Count - num2); List<ushort> list5 = Decode(list4, list3); List<ushort> list6 = new List<ushort>(); for (int j = 0; j < M.Count - 1; j += 2) { uint num6 = list[j / 2]; uint num7 = list2[j / 2]; num6 += num7 * list5[j / 2]; list6.Add((ushort)Mod((double)num6, (double)(int)M[j])); list6.Add((ushort)Mod(System.Math.Floor((double)num6 / (double)(int)M[j]), (double)(int)M[j + 1])); } if (M.Count % 2 != 0) list6.Add(list5[list3.Count - 1]); return list6; } private int Encode(byte[] output, int outputPos, ushort[] R, ushort[] M, long len) { int num = 16384; if (len == 1) { ushort num2 = R[0]; for (ushort num3 = M[0]; num3 > 1; num3 = (ushort)(num3 + 255 >> 8)) { output[outputPos++] = decimal.ToByte((int)num2 % 256); num2 = (ushort)(num2 >> 8); } } if (len > 1) { ushort[] array = new ushort[(len + 1) / 2]; ushort[] array2 = new ushort[(len + 1) / 2]; int i; for (i = 0; i < len - 1; i += 2) { uint num5 = M[i]; uint num6 = R[i] + R[i + 1] * num5; uint num7; for (num7 = M[i + 1] * num5; num7 >= num; num7 = num7 + 255 >> 8) { output[outputPos++] = decimal.ToByte(num6 % 256); num6 >>= 8; } array[i / 2] = (ushort)num6; array2[i / 2] = (ushort)num7; } if (i < len) { array[i / 2] = R[i]; array2[i / 2] = M[i]; } outputPos = Encode(output, outputPos, array, array2, (len + 1) / 2); } return outputPos; } private void Encrypt(byte[] output, sbyte[] r, byte[] pk) { if (_lpr) { short[] array = new short[_p]; short[] array2 = new short[_p]; sbyte[] array3 = new sbyte[_I]; byte[] array4 = new byte[pk.Length - _seedBytes]; Array.Copy(pk, _seedBytes, array4, 0, array4.Length); RoundedDecode(array, array4); short[] array5 = new short[_p]; sbyte[] a = new sbyte[_p]; byte[] array6 = new byte[_seedBytes]; Array.Copy(pk, 0, array6, 0, _seedBytes); Generator(array5, array6); HashShort(a, r); short[] output2 = new short[_p]; short[] output3 = new short[_p]; RqMult(ref output2, array5, ref a); Round(array2, output2); RqMult(ref output3, array, ref a); for (int i = 0; i < _I; i++) { array3[i] = Top(ArithmeticMod_q(output3[i] + r[i] * _q12)); } RoundedEncode(output, array2); byte[] array7 = new byte[output.Length]; TopEncode(array7, array3); Array.Copy(array7, 0, output, _roundedBytes, output.Length - _roundedBytes); } else { short[] array8 = new short[_p]; short[] array9 = new short[_p]; RqDecode(array8, pk); short[] output4 = new short[_p]; RqMult(ref output4, array8, r); Round(array9, output4); RoundedEncode(output, array9); } } private void Decrypt(sbyte[] output, byte[] c, byte[] sk) { if (_lpr) { sbyte[] a = new sbyte[_p]; short[] array = new short[_p]; sbyte[] array2 = new sbyte[_I]; ByteDecode(a, sk); RoundedDecode(array, c); Array.Copy(c, _roundedBytes, c, 0, c.Length - _roundedBytes); TopDecode(array2, c); short[] output2 = new short[_p]; RqMult(ref output2, array, ref a); for (int i = 0; i < _I; i++) { int num = Right(array2[i]) - output2[i] + 4 * _w + 1; output[i] = (sbyte)(-NegativeMask((short)(Mod((double)(num + _q12), (double)_q) - (double)_q12))); } } else { sbyte[] array3 = new sbyte[_p]; sbyte[] array4 = new sbyte[_p]; short[] array5 = new short[_p]; ByteDecode(array3, sk); byte[] array6 = new byte[sk.Length]; Array.Copy(sk, _smallBytes, array6, 0, array6.Length - _smallBytes); ByteDecode(array4, array6); RoundedDecode(array5, c); short[] output3 = new short[_p]; short[] array7 = new short[_p]; sbyte[] array8 = new sbyte[_p]; sbyte[] array9 = new sbyte[_p]; RqMult(ref output3, array5, array3); RqMult3(array7, output3); R3FromRq(array8, array7); R3Mult(array9, array8, array4); int num2 = WeightMask(array9); for (int j = 0; j < _w; j++) { output[j] = (sbyte)(((array9[j] ^ 1) & ~num2) ^ 1); } for (int k = _w; k < _p; k++) { output[k] = (sbyte)(array9[k] & ~num2); } } } private void Hide(byte[] output, byte[] r_enc, sbyte[] r, byte[] pk, byte[] cache) { if (_lpr) InputsEncode(r_enc, r); else ByteEncode(r_enc, r); Encrypt(output, r, pk); Array.Copy(output, 0, output, _ctBytes, output.Length - _ctBytes); HashConfirm(output, r_enc, pk, cache); } private void Generator(short[] output, byte[] seed) { uint[] array = Expand(seed); for (int i = 0; i < _p; i++) { output[i] = (short)((long)array[i] % (long)_q - _q12); } } private uint[] Expand(byte[] k) { byte[] array = new byte[_p * 4]; BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(new SicBlockCipher(AesUtilities.CreateEngine())); KeyParameter parameters = new KeyParameter(k); bufferedBlockCipher.Init(true, new ParametersWithIV(parameters, new byte[16])); int num = bufferedBlockCipher.ProcessBytes(array, 0, _p * 4, array, 0); num += bufferedBlockCipher.DoFinal(array, num); return Pack.LE_To_UInt32(array, 0, _p); } private void ShortRandom(sbyte[] output, SecureRandom random) { uint[] array = new uint[_p]; byte[] array2 = new byte[4]; for (int i = 0; i < _p; i++) { random.NextBytes(array2); array[i] = BitConverter.ToUInt32(array2, 0); } ShortFromList(output, array); } private void ShortFromList(sbyte[] output, uint[] L_in) { uint[] array = new uint[_p]; for (int i = 0; i < _w; i++) { array[i] = (uint)(L_in[i] & -2); } for (int j = _w; j < _p; j++) { array[j] = (uint)((int)(L_in[j] & -3) | 1); } Array.Sort(array); for (int k = 0; k < _p; k++) { output[k] = (sbyte)((array[k] & 3) - 1); } } private void RqMult(ref short[] output, short[] G, ref sbyte[] a) { short[] array = new short[_p + _p - 1]; for (int i = 0; i < _p; i++) { short num = 0; for (int j = 0; j <= i; j++) { num = ArithmeticMod_q(num + G[j] * a[i - j]); } array[i] = num; } for (int k = _p; k < _p + _p - 1; k++) { short num = 0; for (int l = k - _p + 1; l < _p; l++) { num = ArithmeticMod_q(num + G[l] * a[k - l]); } array[k] = num; } for (int num2 = _p + _p - 2; num2 >= _p; num2--) { array[num2 - _p] = ArithmeticMod_q(array[num2 - _p] + array[num2]); array[num2 - _p + 1] = ArithmeticMod_q(array[num2 - _p + 1] + array[num2]); } for (int m = 0; m < _p; m++) { output[m] = array[m]; } } private void Round(short[] output, short[] aG) { for (int i = 0; i < _p; i++) { output[i] = (short)(aG[i] - ArithmeticMod_3(aG[i])); } } private void InputsRandom(sbyte[] output, SecureRandom random) { byte[] array = new byte[_inputsBytes]; random.NextBytes(array); for (int i = 0; i < _I; i++) { output[i] = (sbyte)(1 & (array[i >> 3] >> (i & 7))); } } private void InputsEncode(byte[] output, sbyte[] r) { for (int i = 0; i < _inputsBytes; i++) { output[i] = 0; } for (int j = 0; j < _I; j++) { output[j >> 3] |= (byte)(r[j] << (j & 7)); } } private void RoundedEncode(byte[] output, short[] A) { ushort[] array = new ushort[_p]; ushort[] array2 = new ushort[_p]; for (int i = 0; i < _p; i++) { array[i] = (ushort)((A[i] + _q12) * 10923 >> 15); } for (int j = 0; j < _p; j++) { array2[j] = (ushort)((_q + 2) / 3); } Encode(output, 0, array, array2, _p); } private void RoundedDecode(short[] output, byte[] s) { List<ushort> list = new List<ushort>(_p); List<byte> s2 = new List<byte>(s); for (int i = 0; i < _p; i++) { list.Add((ushort)((_q + 2) / 3)); } List<ushort> list2 = Decode(s2, list); for (int j = 0; j < _p; j++) { output[j] = (short)(list2[j] * 3 - _q12); } } private void ByteEncode(byte[] output, sbyte[] a) { for (int i = 0; i < _p / 4; i++) { int num = a[4 * i] + 1; int num2 = a[4 * i + 1] + 1 << 2; int num3 = a[4 * i + 2] + 1 << 4; int num4 = a[4 * i + 3] + 1 << 6; sbyte b = (sbyte)(num + num2 + num3 + num4); output[i] = (byte)b; } output[_p / 4] = (byte)(a[_p - 1] + 1); } private void ByteDecode(sbyte[] output, byte[] s) { byte b; for (int i = 0; i < _p / 4; i++) { b = s[i]; output[i * 4] = (sbyte)((b & 3) - 1); b = (byte)(b >> 2); output[i * 4 + 1] = (sbyte)((b & 3) - 1); b = (byte)(b >> 2); output[i * 4 + 2] = (sbyte)((b & 3) - 1); b = (byte)(b >> 2); output[i * 4 + 3] = (sbyte)((b & 3) - 1); } b = s[_p / 4]; output[_p / 4 * 4] = (sbyte)((b & 3) - 1); } private void TopEncode(byte[] output, sbyte[] T) { for (int i = 0; i < _topBytes; i++) { output[i] = (byte)(T[2 * i] + (T[2 * i + 1] << 4)); } } private void TopDecode(sbyte[] output, byte[] s) { for (int i = 0; i < _topBytes; i++) { output[2 * i] = (sbyte)(s[i] & 15); output[2 * i + 1] = (sbyte)(s[i] >> 4); } } private void HashShort(sbyte[] output, sbyte[] r) { byte[] array = new byte[_inputsBytes]; byte[] array2 = new byte[_hashBytes]; uint[] array3 = new uint[_p]; InputsEncode(array, r); HashPrefix(array2, 5, array, array.Length); array3 = Expand(array2); ShortFromList(output, array3); } private void HashPrefix(byte[] output, int b, byte[] input, int inlen) { byte[] array = new byte[64]; Sha512Digest sha512Digest = new Sha512Digest(); sha512Digest.Update((byte)b); sha512Digest.BlockUpdate(input, 0, inlen); sha512Digest.DoFinal(array, 0); Array.Copy(array, 0, output, output.Length - 32, 32); } private void HashConfirm(byte[] output, byte[] r, byte[] pk, byte[] cache) { byte[] array; if (_lpr) { array = new byte[_inputsBytes + _hashBytes]; Array.Copy(r, 0, array, 0, _inputsBytes); Array.Copy(cache, 0, array, _inputsBytes, _hashBytes); } else { array = new byte[_hashBytes * 2]; byte[] array2 = new byte[_hashBytes]; HashPrefix(array2, 3, r, _inputsBytes); Array.Copy(array2, 0, array, 0, _hashBytes); Array.Copy(cache, 0, array, _hashBytes, _hashBytes); } HashPrefix(output, 2, array, array.Length); } private void HashSession(byte[] output, int b, byte[] y, byte[] z) { byte[] array; if (_lpr) { array = new byte[_inputsBytes + _ciphertextsBytes + _confirmBytes]; Array.Copy(y, 0, array, 0, _inputsBytes); Array.Copy(z, 0, array, _inputsBytes, _ciphertextsBytes + _confirmBytes); } else { array = new byte[_hashBytes + _ciphertextsBytes + _confirmBytes]; byte[] array2 = new byte[_hashBytes]; HashPrefix(array2, 3, y, _inputsBytes); Array.Copy(array2, 0, array, 0, _hashBytes); Array.Copy(z, 0, array, _hashBytes, _ciphertextsBytes + _confirmBytes); } byte[] array3 = new byte[32]; HashPrefix(array3, b, array, array.Length); Array.Copy(array3, 0, output, 0, output.Length); } private int NegativeMask(short x) { return x >> 31; } private int ctDiffMask(byte[] c, byte[] c2) { int num = c.Length ^ c2.Length; for (int i = 0; i < c.Length && i < c2.Length; i++) { num |= (c[i] ^ c2[i]); } if (num != 0) return -1; return 0; } private double Mod(double a, double b) { return a - b * System.Math.Floor(a / b); } private short ArithmeticMod_q(int x) { return (short)(Mod((double)(x + _q12), (double)_q) - (double)_q12); } private short ArithmeticMod_3(int x) { return (short)(Mod((double)(x + 1), 3) - 1); } private sbyte Top(int C) { return (sbyte)(_tau1 * (C + _tau0) + 16384 >> 15); } private short Right(sbyte T) { int num = _tau3 * T - _tau2; return (short)(Mod((double)(num + _q12), (double)_q) - (double)_q12); } } }