IndCpa
class IndCpa
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Kems.MLKem
{
internal class IndCpa
{
private readonly MLKemEngine m_engine;
private readonly Symmetric m_symmetric;
private int GenerateMatrixNBlocks => (472 + m_symmetric.XofBlockBytes) / m_symmetric.XofBlockBytes;
internal IndCpa(MLKemEngine engine)
{
m_engine = engine;
m_symmetric = engine.Symmetric;
}
private void GenerateMatrix(PolyVec[] a, ReadOnlySpan<byte> seed, bool transposed)
{
int k = m_engine.K;
byte[] array = new byte[GenerateMatrixNBlocks * m_symmetric.XofBlockBytes + 2];
for (int i = 0; i < k; i++) {
for (int j = 0; j < k; j++) {
if (transposed)
m_symmetric.XofAbsorb(seed, (byte)i, (byte)j);
else
m_symmetric.XofAbsorb(seed, (byte)j, (byte)i);
m_symmetric.XofSqueezeBlocks(array.AsSpan(0, GenerateMatrixNBlocks * m_symmetric.XofBlockBytes));
int num = GenerateMatrixNBlocks * m_symmetric.XofBlockBytes;
for (int l = RejectionSampling(a[i].m_vec[j].m_coeffs, 0, 256, array, num); l < 256; l += RejectionSampling(a[i].m_vec[j].m_coeffs, l, 256 - l, array, num)) {
int num2 = num % 3;
for (int m = 0; m < num2; m++) {
array[m] = array[num - num2 + m];
}
m_symmetric.XofSqueezeBlocks(array.AsSpan(num2, m_symmetric.XofBlockBytes * 2));
num = num2 + m_symmetric.XofBlockBytes;
}
}
}
}
private int RejectionSampling(short[] r, int off, int len, byte[] buf, int buflen)
{
int num = 0;
int num2 = 0;
while (num < len && num2 + 3 <= buflen) {
ushort num3 = (ushort)(((ushort)(buf[num2] & 255) | ((ushort)(buf[num2 + 1] & 255) << 8)) & 4095);
ushort num4 = (ushort)((((ushort)(buf[num2 + 1] & 255) >> 4) | ((ushort)(buf[num2 + 2] & 255) << 4)) & 4095);
num2 += 3;
if (num3 < 3329)
r[off + num++] = (short)num3;
if (num < len && num4 < 3329)
r[off + num++] = (short)num4;
}
return num;
}
internal void GenerateKeyPair(byte[] d, out byte[] pk, out byte[] sk)
{
int k = m_engine.K;
byte[] array = new byte[64];
byte b = 0;
PolyVec[] array2 = new PolyVec[k];
PolyVec polyVec = new PolyVec(m_engine);
PolyVec polyVec2 = new PolyVec(m_engine);
PolyVec polyVec3 = new PolyVec(m_engine);
m_symmetric.Hash_g(Arrays.Append(d, (byte)k), array);
Span<byte> span = array.AsSpan(0, 32);
Span<byte> span2 = array.AsSpan(32, 32);
for (int i = 0; i < k; i++) {
array2[i] = new PolyVec(m_engine);
}
GenerateMatrix(array2, span, false);
for (int j = 0; j < k; j++) {
Poly obj = polyVec3.m_vec[j];
ReadOnlySpan<byte> seed = span2;
byte num = b;
b = (byte)(num + 1);
obj.GetNoiseEta1(seed, num);
}
for (int l = 0; l < k; l++) {
Poly obj2 = polyVec.m_vec[l];
ReadOnlySpan<byte> seed2 = span2;
byte num2 = b;
b = (byte)(num2 + 1);
obj2.GetNoiseEta1(seed2, num2);
}
polyVec3.Ntt();
polyVec.Ntt();
for (int m = 0; m < k; m++) {
PolyVec.PointwiseAccountMontgomery(polyVec2.m_vec[m], array2[m], polyVec3, m_engine);
polyVec2.m_vec[m].ToMont();
}
polyVec2.Add(polyVec);
polyVec2.Reduce();
PackSecretKey(out sk, polyVec3);
PackPublicKey(out pk, polyVec2, span);
}
private void PackSecretKey(out byte[] sk, PolyVec skpv)
{
sk = new byte[m_engine.PolyVecBytes];
skpv.ToBytes(sk);
}
private void PackPublicKey(out byte[] pk, PolyVec pkpv, ReadOnlySpan<byte> seed)
{
pk = new byte[m_engine.IndCpaPublicKeyBytes];
pkpv.ToBytes(pk);
seed.Slice(0, 32).CopyTo(pk.AsSpan(m_engine.PolyVecBytes));
}
private void UnpackSecretKey(PolyVec skpv, ReadOnlySpan<byte> sk)
{
skpv.FromBytes(sk);
}
private void UnpackPublicKey(PolyVec pkpv, Span<byte> seed, ReadOnlySpan<byte> pk)
{
pkpv.FromBytes(pk);
pk.Slice(m_engine.PolyVecBytes, 32).CopyTo(seed);
}
public void Encrypt(Span<byte> encapsulation, ReadOnlySpan<byte> m, ReadOnlySpan<byte> pk, ReadOnlySpan<byte> coins)
{
int k = m_engine.K;
byte[] array = new byte[32];
byte b = 0;
PolyVec polyVec = new PolyVec(m_engine);
PolyVec polyVec2 = new PolyVec(m_engine);
PolyVec polyVec3 = new PolyVec(m_engine);
PolyVec polyVec4 = new PolyVec(m_engine);
PolyVec[] array2 = new PolyVec[k];
Poly poly = new Poly(m_engine);
Poly poly2 = new Poly(m_engine);
Poly poly3 = new Poly(m_engine);
UnpackPublicKey(polyVec2, array, pk);
poly2.FromMsg(m);
for (int i = 0; i < k; i++) {
array2[i] = new PolyVec(m_engine);
}
GenerateMatrix(array2, array, true);
for (int j = 0; j < k; j++) {
Poly obj = polyVec.m_vec[j];
byte num = b;
b = (byte)(num + 1);
obj.GetNoiseEta1(coins, num);
}
for (int l = 0; l < k; l++) {
Poly obj2 = polyVec3.m_vec[l];
byte num2 = b;
b = (byte)(num2 + 1);
obj2.GetNoiseEta2(coins, num2);
}
Poly poly4 = poly3;
byte num3 = b;
b = (byte)(num3 + 1);
poly4.GetNoiseEta2(coins, num3);
polyVec.Ntt();
for (int n = 0; n < k; n++) {
PolyVec.PointwiseAccountMontgomery(polyVec4.m_vec[n], array2[n], polyVec, m_engine);
}
PolyVec.PointwiseAccountMontgomery(poly, polyVec2, polyVec, m_engine);
polyVec4.InverseNttToMont();
poly.PolyInverseNttToMont();
polyVec4.Add(polyVec3);
poly.Add(poly3);
poly.Add(poly2);
polyVec4.Reduce();
poly.PolyReduce();
PackCipherText(encapsulation, polyVec4, poly);
}
private void PackCipherText(Span<byte> r, PolyVec b, Poly v)
{
b.CompressPolyVec(r);
int polyVecCompressedBytes = m_engine.PolyVecCompressedBytes;
v.CompressPoly(r.Slice(polyVecCompressedBytes, r.Length - polyVecCompressedBytes));
}
private void UnpackCipherText(PolyVec b, Poly v, ReadOnlySpan<byte> c)
{
b.DecompressPolyVec(c);
int polyVecCompressedBytes = m_engine.PolyVecCompressedBytes;
v.DecompressPoly(c.Slice(polyVecCompressedBytes, c.Length - polyVecCompressedBytes));
}
internal void Decrypt(Span<byte> m, ReadOnlySpan<byte> encapsulation, ReadOnlySpan<byte> sk)
{
PolyVec polyVec = new PolyVec(m_engine);
PolyVec polyVec2 = new PolyVec(m_engine);
Poly poly = new Poly(m_engine);
Poly poly2 = new Poly(m_engine);
UnpackCipherText(polyVec, poly, encapsulation);
UnpackSecretKey(polyVec2, sk);
polyVec.Ntt();
PolyVec.PointwiseAccountMontgomery(poly2, polyVec2, polyVec, m_engine);
poly2.PolyInverseNttToMont();
poly2.Subtract(poly);
poly2.PolyReduce();
poly2.ToMsg(m);
}
internal byte[] PackPublicKey(PolyVec polyVec, ReadOnlySpan<byte> seed)
{
byte[] array = new byte[m_engine.IndCpaPublicKeyBytes];
polyVec.ToBytes(array);
seed.Slice(0, 32).CopyTo(array.AsSpan(m_engine.PolyVecBytes));
return array;
}
internal byte[] UnpackPublicKey(PolyVec polyVec, ReadOnlySpan<byte> pk)
{
byte[] array = new byte[32];
polyVec.FromBytes(pk);
pk.Slice(m_engine.PolyVecBytes, 32).CopyTo(array);
return array;
}
}
}