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

PolyVec

class PolyVec
using System; namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber { internal class PolyVec { private KyberEngine m_engine; internal Poly[] m_vec; internal PolyVec(KyberEngine engine) { m_engine = engine; m_vec = new Poly[engine.K]; for (int i = 0; i < engine.K; i++) { m_vec[i] = new Poly(engine); } } internal void Ntt() { for (int i = 0; i < m_engine.K; i++) { m_vec[i].PolyNtt(); } } internal void InverseNttToMont() { for (int i = 0; i < m_engine.K; i++) { m_vec[i].PolyInverseNttToMont(); } } internal static void PointwiseAccountMontgomery(Poly r, PolyVec a, PolyVec b, KyberEngine engine) { Poly poly = new Poly(engine); Poly.BaseMultMontgomery(r, a.m_vec[0], b.m_vec[0]); for (int i = 1; i < engine.K; i++) { Poly.BaseMultMontgomery(poly, a.m_vec[i], b.m_vec[i]); r.Add(poly); } r.PolyReduce(); } internal void Add(PolyVec a) { for (int i = 0; i < m_engine.K; i++) { m_vec[i].Add(a.m_vec[i]); } } internal void Reduce() { for (int i = 0; i < m_engine.K; i++) { m_vec[i].PolyReduce(); } } internal void CompressPolyVec(byte[] r) { ConditionalSubQ(); int num = 0; if (m_engine.PolyVecCompressedBytes == m_engine.K * 320) { short[] array = new short[4]; for (int i = 0; i < m_engine.K; i++) { for (int j = 0; j < 64; j++) { for (int k = 0; k < 4; k++) { array[k] = (short)(((uint)((m_vec[i].m_coeffs[4 * j + k] << 10) + 1664) / 3329) & 1023); } r[num] = (byte)array[0]; r[num + 1] = (byte)((array[0] >> 8) | (array[1] << 2)); r[num + 2] = (byte)((array[1] >> 6) | (array[2] << 4)); r[num + 3] = (byte)((array[2] >> 4) | (array[3] << 6)); r[num + 4] = (byte)(array[3] >> 2); num += 5; } } } else { if (m_engine.PolyVecCompressedBytes != m_engine.K * 352) throw new ArgumentException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!"); short[] array2 = new short[8]; for (int l = 0; l < m_engine.K; l++) { for (int m = 0; m < 32; m++) { for (int n = 0; n < 8; n++) { array2[n] = (short)(((uint)((m_vec[l].m_coeffs[8 * m + n] << 11) + 1664) / 3329) & 2047); } r[num] = (byte)array2[0]; r[num + 1] = (byte)((array2[0] >> 8) | (array2[1] << 3)); r[num + 2] = (byte)((array2[1] >> 5) | (array2[2] << 6)); r[num + 3] = (byte)(array2[2] >> 2); r[num + 4] = (byte)((array2[2] >> 10) | (array2[3] << 1)); r[num + 5] = (byte)((array2[3] >> 7) | (array2[4] << 4)); r[num + 6] = (byte)((array2[4] >> 4) | (array2[5] << 7)); r[num + 7] = (byte)(array2[5] >> 1); r[num + 8] = (byte)((array2[5] >> 9) | (array2[6] << 2)); r[num + 9] = (byte)((array2[6] >> 6) | (array2[7] << 5)); r[num + 10] = (byte)(array2[7] >> 3); num += 11; } } } } internal void DecompressPolyVec(byte[] compressedCipherText) { int num = 0; if (m_engine.PolyVecCompressedBytes == m_engine.K * 320) { short[] array = new short[4]; for (int i = 0; i < m_engine.K; i++) { for (int j = 0; j < 64; j++) { array[0] = (short)((compressedCipherText[num] & 255) | ((ushort)(compressedCipherText[num + 1] & 255) << 8)); array[1] = (short)(((compressedCipherText[num + 1] & 255) >> 2) | ((ushort)(compressedCipherText[num + 2] & 255) << 6)); array[2] = (short)(((compressedCipherText[num + 2] & 255) >> 4) | ((ushort)(compressedCipherText[num + 3] & 255) << 4)); array[3] = (short)(((compressedCipherText[num + 3] & 255) >> 6) | ((ushort)(compressedCipherText[num + 4] & 255) << 2)); num += 5; for (int k = 0; k < 4; k++) { m_vec[i].m_coeffs[4 * j + k] = (short)((array[k] & 1023) * 3329 + 512 >> 10); } } } } else { if (m_engine.PolyVecCompressedBytes != m_engine.K * 352) throw new ArgumentException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!"); short[] array2 = new short[8]; for (int l = 0; l < m_engine.K; l++) { for (int m = 0; m < 32; m++) { array2[0] = (short)((compressedCipherText[num] & 255) | ((ushort)(compressedCipherText[num + 1] & 255) << 8)); array2[1] = (short)(((compressedCipherText[num + 1] & 255) >> 3) | ((ushort)(compressedCipherText[num + 2] & 255) << 5)); array2[2] = (short)(((compressedCipherText[num + 2] & 255) >> 6) | ((ushort)(compressedCipherText[num + 3] & 255) << 2) | (ushort)((compressedCipherText[num + 4] & 255) << 10)); array2[3] = (short)(((compressedCipherText[num + 4] & 255) >> 1) | ((ushort)(compressedCipherText[num + 5] & 255) << 7)); array2[4] = (short)(((compressedCipherText[num + 5] & 255) >> 4) | ((ushort)(compressedCipherText[num + 6] & 255) << 4)); array2[5] = (short)(((compressedCipherText[num + 6] & 255) >> 7) | ((ushort)(compressedCipherText[num + 7] & 255) << 1) | (ushort)((compressedCipherText[num + 8] & 255) << 9)); array2[6] = (short)(((compressedCipherText[num + 8] & 255) >> 2) | ((ushort)(compressedCipherText[num + 9] & 255) << 6)); array2[7] = (short)(((compressedCipherText[num + 9] & 255) >> 5) | ((ushort)(compressedCipherText[num + 10] & 255) << 3)); num += 11; for (int n = 0; n < 8; n++) { m_vec[l].m_coeffs[8 * m + n] = (short)((array2[n] & 2047) * 3329 + 1024 >> 11); } } } } } internal void ToBytes(byte[] r) { for (int i = 0; i < m_engine.K; i++) { m_vec[i].ToBytes(r, i * KyberEngine.PolyBytes); } } internal void FromBytes(byte[] pk) { for (int i = 0; i < m_engine.K; i++) { m_vec[i].FromBytes(pk, i * KyberEngine.PolyBytes); } } private void ConditionalSubQ() { for (int i = 0; i < m_engine.K; i++) { m_vec[i].CondSubQ(); } } } }