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)));
}
}
}
}