Poly
class Poly
using System;
namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
{
internal class Poly
{
private KyberEngine m_engine;
public short[] m_coeffs = new short[256];
private Symmetric m_symmetric;
internal short[] Coeffs => m_coeffs;
public Poly(KyberEngine mEngine)
{
m_engine = mEngine;
m_symmetric = mEngine.Symmetric;
}
internal void GetNoiseEta1(byte[] seed, byte nonce)
{
byte[] array = new byte[m_engine.Eta1 * 256 / 4];
m_symmetric.Prf(array, seed, nonce);
Cbd.Eta(this, array, m_engine.Eta1);
}
internal void GetNoiseEta2(byte[] seed, byte nonce)
{
byte[] array = new byte[128];
m_symmetric.Prf(array, seed, nonce);
Cbd.Eta(this, array, 2);
}
internal void PolyNtt()
{
Ntt.NTT(Coeffs);
PolyReduce();
}
internal void PolyInverseNttToMont()
{
Ntt.InvNTT(Coeffs);
}
internal static void BaseMultMontgomery(Poly r, Poly a, Poly b)
{
for (int i = 0; i < 64; i++) {
Ntt.BaseMult(r.Coeffs, 4 * i, a.Coeffs[4 * i], a.Coeffs[4 * i + 1], b.Coeffs[4 * i], b.Coeffs[4 * i + 1], Ntt.Zetas[64 + i]);
Ntt.BaseMult(r.Coeffs, 4 * i + 2, a.Coeffs[4 * i + 2], a.Coeffs[4 * i + 3], b.Coeffs[4 * i + 2], b.Coeffs[4 * i + 3], (short)(-1 * Ntt.Zetas[64 + i]));
}
}
internal void ToMont()
{
for (int i = 0; i < 256; i++) {
Coeffs[i] = Reduce.MontgomeryReduce(Coeffs[i] * 1353);
}
}
internal void Add(Poly a)
{
for (int i = 0; i < 256; i++) {
Coeffs[i] += a.Coeffs[i];
}
}
internal void Subtract(Poly a)
{
for (int i = 0; i < 256; i++) {
Coeffs[i] = (short)(a.Coeffs[i] - Coeffs[i]);
}
}
internal void PolyReduce()
{
for (int i = 0; i < 256; i++) {
Coeffs[i] = Reduce.BarrettReduce(Coeffs[i]);
}
}
internal void CompressPoly(byte[] r, int off)
{
byte[] array = new byte[8];
int num = 0;
CondSubQ();
if (m_engine.PolyCompressedBytes == 128) {
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 8; j++) {
array[j] = (byte)((((Coeffs[8 * i + j] << 4) + 1664) / 3329) & 15);
}
r[off + num] = (byte)(array[0] | (array[1] << 4));
r[off + num + 1] = (byte)(array[2] | (array[3] << 4));
r[off + num + 2] = (byte)(array[4] | (array[5] << 4));
r[off + num + 3] = (byte)(array[6] | (array[7] << 4));
num += 4;
}
} else {
if (m_engine.PolyCompressedBytes != 160)
throw new ArgumentException("PolyCompressedBytes is neither 128 or 160!");
for (int k = 0; k < 32; k++) {
for (int l = 0; l < 8; l++) {
array[l] = (byte)((((Coeffs[8 * k + l] << 5) + 1664) / 3329) & 31);
}
r[off + num] = (byte)(array[0] | (array[1] << 5));
r[off + num + 1] = (byte)((array[1] >> 3) | (array[2] << 2) | (array[3] << 7));
r[off + num + 2] = (byte)((array[3] >> 1) | (array[4] << 4));
r[off + num + 3] = (byte)((array[4] >> 4) | (array[5] << 1) | (array[6] << 6));
r[off + num + 4] = (byte)((array[6] >> 2) | (array[7] << 3));
num += 5;
}
}
}
internal void DecompressPoly(byte[] CompressedCipherText, int off)
{
int num = off;
if (m_engine.PolyCompressedBytes == 128) {
for (int i = 0; i < 128; i++) {
Coeffs[2 * i] = (short)((short)(CompressedCipherText[num] & 255 & 15) * 3329 + 8 >> 4);
Coeffs[2 * i + 1] = (short)((short)((CompressedCipherText[num] & 255) >> 4) * 3329 + 8 >> 4);
num++;
}
} else {
if (m_engine.PolyCompressedBytes != 160)
throw new ArgumentException("PolyCompressedBytes is neither 128 or 160!");
byte[] array = new byte[8];
for (int j = 0; j < 32; j++) {
array[0] = (byte)(CompressedCipherText[num] & 255);
array[1] = (byte)(((CompressedCipherText[num] & 255) >> 5) | ((CompressedCipherText[num + 1] & 255) << 3));
array[2] = (byte)((CompressedCipherText[num + 1] & 255) >> 2);
array[3] = (byte)(((CompressedCipherText[num + 1] & 255) >> 7) | ((CompressedCipherText[num + 2] & 255) << 1));
array[4] = (byte)(((CompressedCipherText[num + 2] & 255) >> 4) | ((CompressedCipherText[num + 3] & 255) << 4));
array[5] = (byte)((CompressedCipherText[num + 3] & 255) >> 1);
array[6] = (byte)(((CompressedCipherText[num + 3] & 255) >> 6) | ((CompressedCipherText[num + 4] & 255) << 2));
array[7] = (byte)((CompressedCipherText[num + 4] & 255) >> 3);
num += 5;
for (int k = 0; k < 8; k++) {
Coeffs[8 * j + k] = (short)((array[k] & 31) * 3329 + 16 >> 5);
}
}
}
}
internal void ToBytes(byte[] r, int off)
{
CondSubQ();
for (int i = 0; i < 128; i++) {
ushort num = (ushort)Coeffs[2 * i];
ushort num2 = (ushort)Coeffs[2 * i + 1];
r[off + 3 * i] = (byte)num;
r[off + 3 * i + 1] = (byte)((num >> 8) | (ushort)(num2 << 4));
r[off + 3 * i + 2] = (byte)(ushort)(num2 >> 4);
}
}
internal void FromBytes(byte[] a, int off)
{
for (int i = 0; i < 128; i++) {
Coeffs[2 * i] = (short)(((a[off + 3 * i] & 255) | (ushort)((a[off + 3 * i + 1] & 255) << 8)) & 4095);
Coeffs[2 * i + 1] = (short)((((a[off + 3 * i + 1] & 255) >> 4) | (ushort)((a[off + 3 * i + 2] & 255) << 4)) & 4095);
}
}
internal void ToMsg(byte[] msg)
{
CondSubQ();
for (int i = 0; i < 32; i++) {
msg[i] = 0;
for (int j = 0; j < 8; j++) {
int num = Coeffs[8 * i + j] & 65535;
num <<= 1;
num += 1665;
num *= 80635;
num >>= 28;
num &= 1;
msg[i] |= (byte)(num << j);
}
}
}
internal void FromMsg(byte[] m)
{
if (m.Length != 32)
throw new ArgumentException("KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!");
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 8; j++) {
short num = (short)(-1 * (short)(((m[i] & 255) >> j) & 1));
Coeffs[8 * i + j] = (short)(num & 1665);
}
}
}
internal void CondSubQ()
{
for (int i = 0; i < 256; i++) {
Coeffs[i] = Reduce.CondSubQ(Coeffs[i]);
}
}
}
}