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

Polynomial

abstract class Polynomial
using Org.BouncyCastle.Pqc.Crypto.Ntru.ParameterSets; using System; namespace Org.BouncyCastle.Pqc.Crypto.Ntru.Polynomials { internal abstract class Polynomial { internal ushort[] coeffs; private protected readonly NtruParameterSet ParameterSet; internal Polynomial(NtruParameterSet parameterSet) { coeffs = new ushort[parameterSet.N]; ParameterSet = parameterSet; } internal static short BothNegativeMask(short x, short y) { return (short)((x & y) >> 15); } internal static ushort Mod3(ushort a) { return Mod((double)(int)a, 3); } internal static byte Mod3(byte a) { return (byte)Mod((double)(int)a, 3); } internal static uint ModQ(uint x, uint q) { return Mod((double)x, (double)q); } internal void Mod3PhiN() { int n = ParameterSet.N; for (int i = 0; i < n; i++) { coeffs[i] = Mod3((ushort)(coeffs[i] + 2 * coeffs[n - 1])); } } internal void ModQPhiN() { int n = ParameterSet.N; for (int i = 0; i < n; i++) { coeffs[i] = (ushort)(coeffs[i] - coeffs[n - 1]); } } internal static ushort Mod(double a, double b) { return (ushort)(a - b * System.Math.Floor(a / b)); } public abstract byte[] SqToBytes(int len); public abstract void SqFromBytes(byte[] a); public byte[] RqSumZeroToBytes(int len) { return SqToBytes(len); } public void RqSumZeroFromBytes(byte[] a) { int num = coeffs.Length; SqFromBytes(a); coeffs[num - 1] = 0; for (int i = 0; i < ParameterSet.PackDegree(); i++) { coeffs[num - 1] -= coeffs[i]; } } public void S3ToBytes(byte[] msg, int msgOff) { int num = ParameterSet.PackDegree(); int num2 = num - 5; int i; for (i = 0; i <= num2; i += 5) { uint num3 = coeffs[i]; uint num4 = (uint)(coeffs[i + 1] * 3); uint num5 = (uint)(coeffs[i + 2] * 9); uint num6 = (uint)(coeffs[i + 3] * 27); uint num7 = (uint)(coeffs[i + 4] * 81); msg[msgOff++] = (byte)(num3 + num4 + num5 + num6 + num7); } if (i < num) { int num9 = num - 1; uint num10 = coeffs[num9]; while (--num9 >= i) { num10 *= 3; num10 += coeffs[num9]; } msg[msgOff++] = (byte)num10; } } public void S3FromBytes(byte[] msg) { int num = coeffs.Length; for (int i = 0; i < ParameterSet.PackDegree() / 5; i++) { byte b = msg[i]; coeffs[5 * i] = b; coeffs[5 * i + 1] = (ushort)(b * 171 >> 9); coeffs[5 * i + 2] = (ushort)(b * 57 >> 9); coeffs[5 * i + 3] = (ushort)(b * 19 >> 9); coeffs[5 * i + 4] = (ushort)(b * 203 >> 14); } if (ParameterSet.PackDegree() > ParameterSet.PackDegree() / 5 * 5) { int num2 = ParameterSet.PackDegree() / 5; byte b = msg[num2]; for (int j = 0; 5 * num2 + j < ParameterSet.PackDegree(); j++) { coeffs[5 * num2 + j] = b; b = (byte)(b * 171 >> 9); } } coeffs[num - 1] = 0; Mod3PhiN(); } public void RqMul(Polynomial a, Polynomial b) { int num = coeffs.Length; for (int i = 0; i < num; i++) { coeffs[i] = 0; for (int j = 1; j < num - i; j++) { coeffs[i] += (ushort)(a.coeffs[i + j] * b.coeffs[num - j]); } for (int j = 0; j < i + 1; j++) { coeffs[i] += (ushort)(a.coeffs[i - j] * b.coeffs[j]); } } } public void SqMul(Polynomial a, Polynomial b) { RqMul(a, b); ModQPhiN(); } public void S3Mul(Polynomial a, Polynomial b) { RqMul(a, b); Mod3PhiN(); } public abstract void Lift(Polynomial a); public void RqToS3(Polynomial a) { int num = coeffs.Length; for (int i = 0; i < num; i++) { coeffs[i] = (ushort)ModQ(a.coeffs[i], (uint)ParameterSet.Q()); ushort num2 = (ushort)(coeffs[i] >> ParameterSet.LogQ - 1); coeffs[i] += (ushort)(num2 << 1 - (ParameterSet.LogQ & 1)); } Mod3PhiN(); } public abstract void R2Inv(Polynomial a); internal void R2Inv(Polynomial a, Polynomial f, Polynomial g, Polynomial v, Polynomial w) { int num = coeffs.Length; w.coeffs[0] = 1; for (int i = 0; i < num; i++) { f.coeffs[i] = 1; } for (int i = 0; i < num - 1; i++) { g.coeffs[num - 2 - i] = (ushort)((a.coeffs[i] ^ a.coeffs[num - 1]) & 1); } g.coeffs[num - 1] = 0; short num2 = 1; for (int j = 0; j < 2 * (num - 1) - 1; j++) { for (int i = num - 1; i > 0; i--) { v.coeffs[i] = v.coeffs[i - 1]; } v.coeffs[0] = 0; short num3 = (short)(g.coeffs[0] & f.coeffs[0]); short num4 = BothNegativeMask((short)(-num2), (short)(-g.coeffs[0])); num2 = (short)(num2 ^ (short)(num4 & (num2 ^ -num2))); num2 = (short)(num2 + 1); for (int i = 0; i < num; i++) { short num5 = (short)(num4 & (f.coeffs[i] ^ g.coeffs[i])); f.coeffs[i] ^= (ushort)num5; g.coeffs[i] ^= (ushort)num5; num5 = (short)(num4 & (v.coeffs[i] ^ w.coeffs[i])); v.coeffs[i] ^= (ushort)num5; w.coeffs[i] ^= (ushort)num5; } for (int i = 0; i < num; i++) { g.coeffs[i] = (ushort)(g.coeffs[i] ^ (num3 & f.coeffs[i])); } for (int i = 0; i < num; i++) { w.coeffs[i] = (ushort)(w.coeffs[i] ^ (num3 & v.coeffs[i])); } for (int i = 0; i < num - 1; i++) { g.coeffs[i] = g.coeffs[i + 1]; } g.coeffs[num - 1] = 0; } for (int i = 0; i < num - 1; i++) { coeffs[i] = v.coeffs[num - 2 - i]; } coeffs[num - 1] = 0; } public abstract void RqInv(Polynomial a); internal void RqInv(Polynomial a, Polynomial ai2, Polynomial b, Polynomial c, Polynomial s) { ai2.R2Inv(a); R2InvToRqInv(ai2, a, b, c, s); } private void R2InvToRqInv(Polynomial ai, Polynomial a, Polynomial b, Polynomial c, Polynomial s) { int num = coeffs.Length; for (int i = 0; i < num; i++) { b.coeffs[i] = (ushort)(-a.coeffs[i]); } for (int i = 0; i < num; i++) { coeffs[i] = ai.coeffs[i]; } c.RqMul(this, b); c.coeffs[0] += 2; s.RqMul(c, this); c.RqMul(s, b); c.coeffs[0] += 2; RqMul(c, s); c.RqMul(this, b); c.coeffs[0] += 2; s.RqMul(c, this); c.RqMul(s, b); c.coeffs[0] += 2; RqMul(c, s); } public abstract void S3Inv(Polynomial a); internal void S3Inv(Polynomial a, Polynomial f, Polynomial g, Polynomial v, Polynomial w) { int num = coeffs.Length; w.coeffs[0] = 1; for (int i = 0; i < num; i++) { f.coeffs[i] = 1; } for (int i = 0; i < num - 1; i++) { g.coeffs[num - 2 - i] = Mod3((ushort)((a.coeffs[i] & 3) + 2 * (a.coeffs[num - 1] & 3))); } g.coeffs[num - 1] = 0; short num2 = 1; short num3; for (int j = 0; j < 2 * (num - 1) - 1; j++) { for (int i = num - 1; i > 0; i--) { v.coeffs[i] = v.coeffs[i - 1]; } v.coeffs[0] = 0; num3 = Mod3((byte)(2 * g.coeffs[0] * f.coeffs[0])); short num4 = BothNegativeMask((short)(-num2), (short)(-g.coeffs[0])); num2 = (short)(num2 ^ (short)(num4 & (num2 ^ -num2))); num2 = (short)(num2 + 1); for (int i = 0; i < num; i++) { short num5 = (short)(num4 & (f.coeffs[i] ^ g.coeffs[i])); f.coeffs[i] ^= (ushort)num5; g.coeffs[i] ^= (ushort)num5; num5 = (short)(num4 & (v.coeffs[i] ^ w.coeffs[i])); v.coeffs[i] ^= (ushort)num5; w.coeffs[i] ^= (ushort)num5; } for (int i = 0; i < num; i++) { g.coeffs[i] = Mod3((byte)(g.coeffs[i] + num3 * f.coeffs[i])); } for (int i = 0; i < num; i++) { w.coeffs[i] = Mod3((byte)(w.coeffs[i] + num3 * v.coeffs[i])); } for (int i = 0; i < num - 1; i++) { g.coeffs[i] = g.coeffs[i + 1]; } g.coeffs[num - 1] = 0; } num3 = (short)f.coeffs[0]; for (int i = 0; i < num - 1; i++) { coeffs[i] = Mod3((byte)(num3 * v.coeffs[num - 2 - i])); } coeffs[num - 1] = 0; } public void Z3ToZq() { int num = coeffs.Length; for (int i = 0; i < num; i++) { coeffs[i] = (ushort)(coeffs[i] | (-(coeffs[i] >> 1) & (ParameterSet.Q() - 1))); } } public void TrinaryZqToZ3() { int num = coeffs.Length; for (int i = 0; i < num; i++) { coeffs[i] = (ushort)ModQ((uint)(coeffs[i] & 65535), (uint)ParameterSet.Q()); coeffs[i] = (ushort)(3 & (coeffs[i] ^ (coeffs[i] >> ParameterSet.LogQ - 1))); } } } }