MLKemEngine
class MLKemEngine
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Kems.MLKem
{
internal class MLKemEngine
{
private readonly IndCpa m_indCpa;
private readonly SecureRandom m_random;
internal const int N = 256;
internal const int Q = 3329;
internal const int QInv = 62209;
internal const int SymBytes = 32;
private const int = 32;
internal const int PolyBytes = 384;
internal const int Eta2 = 2;
internal int IndCpaMsgBytes = 32;
internal Symmetric Symmetric { get; set; }
internal int K { get; set; }
internal int PolyVecBytes { get; set; }
internal int PolyCompressedBytes { get; set; }
internal int PolyVecCompressedBytes { get; set; }
internal int Eta1 { get; set; }
internal int IndCpaPublicKeyBytes { get; set; }
internal int IndCpaSecretKeyBytes { get; set; }
internal int IndCpaBytes { get; set; }
internal int PublicKeyBytes { get; set; }
internal int SecretKeyBytes { get; set; }
internal int CipherTextBytes { get; set; }
internal int CryptoBytes { get; set; }
internal int CryptoSecretKeyBytes { get; set; }
internal int CryptoPublicKeyBytes { get; set; }
internal int CryptoCipherTextBytes { get; set; }
internal MLKemEngine(int k, SecureRandom random)
{
K = k;
switch (k) {
case 2:
Eta1 = 3;
PolyCompressedBytes = 128;
PolyVecCompressedBytes = K * 320;
break;
case 3:
Eta1 = 2;
PolyCompressedBytes = 128;
PolyVecCompressedBytes = K * 320;
break;
case 4:
Eta1 = 2;
PolyCompressedBytes = 160;
PolyVecCompressedBytes = K * 352;
break;
}
PolyVecBytes = k * 384;
IndCpaPublicKeyBytes = PolyVecBytes + 32;
IndCpaSecretKeyBytes = PolyVecBytes;
IndCpaBytes = PolyVecCompressedBytes + PolyCompressedBytes;
PublicKeyBytes = IndCpaPublicKeyBytes;
SecretKeyBytes = IndCpaSecretKeyBytes + IndCpaPublicKeyBytes + 64;
CipherTextBytes = IndCpaBytes;
CryptoBytes = 32;
CryptoSecretKeyBytes = SecretKeyBytes;
CryptoPublicKeyBytes = PublicKeyBytes;
CryptoCipherTextBytes = CipherTextBytes;
Symmetric = new Symmetric.ShakeSymmetric();
m_indCpa = new IndCpa(this);
m_random = random;
}
internal void GenerateKemKeyPair(out byte[] t, out byte[] rho, out byte[] s, out byte[] hpk, out byte[] nonce, out byte[] seed)
{
byte[] array = new byte[32];
byte[] array2 = new byte[32];
m_random.NextBytes(array);
m_random.NextBytes(array2);
GenerateKemKeyPairInternal(array, array2, out t, out rho, out s, out hpk, out nonce, out seed);
}
internal void GenerateKemKeyPairInternal(byte[] d, byte[] z, out byte[] t, out byte[] rho, out byte[] s, out byte[] hpk, out byte[] nonce, out byte[] seed)
{
m_indCpa.GenerateKeyPair(d, out byte[] pk, out s);
hpk = new byte[32];
Symmetric.Hash_h(pk, 0, pk.Length, hpk, 0);
t = Arrays.CopyOfRange(pk, 0, IndCpaPublicKeyBytes - 32);
rho = Arrays.CopyOfRange(pk, IndCpaPublicKeyBytes - 32, IndCpaPublicKeyBytes);
nonce = z;
seed = Arrays.Concatenate(d, z);
}
internal void KemDecrypt(byte[] secBuf, int secOff, byte[] encBuf, int encOff, byte[] secretKey)
{
byte[] array = new byte[64];
byte[] array2 = new byte[64];
byte[] array3 = new byte[CipherTextBytes];
byte[] pk = Arrays.CopyOfRange(secretKey, IndCpaSecretKeyBytes, secretKey.Length);
byte[] array4 = new byte[32 + CipherTextBytes];
m_indCpa.Decrypt(array, encBuf, encOff, secretKey);
Array.Copy(secretKey, SecretKeyBytes - 64, array, 32, 32);
Symmetric.Hash_g(array, array2);
m_indCpa.Encrypt(array3, 0, Arrays.CopyOf(array, 32), pk, Arrays.CopyOfRange(array2, 32, array2.Length));
bool b = !Arrays.FixedTimeEquals(array3.Length, array3, 0, encBuf, encOff);
Symmetric.Hash_h(encBuf, encOff, CipherTextBytes, array2, 32);
Array.Copy(secretKey, SecretKeyBytes - 32, array4, 0, 32);
Array.Copy(encBuf, encOff, array4, 32, CipherTextBytes);
Symmetric.Kdf(array4, array4);
CMov(array2, array4, 32, b);
Array.Copy(array2, 0, secBuf, secOff, 32);
}
internal void KemEncrypt(byte[] encBuf, int encOff, byte[] secBuf, int secOff, byte[] pk, byte[] randBytes)
{
if (pk.Length != IndCpaPublicKeyBytes)
throw new ArgumentException("Input validation Error: Type check failed for ml-kem encapsulation");
PolyVec polyVec = new PolyVec(this);
byte[] seed = m_indCpa.UnpackPublicKey(polyVec, pk);
if (!Arrays.AreEqual(m_indCpa.PackPublicKey(polyVec, seed), pk))
throw new ArgumentException("Input validation: Modulus check failed for ml-kem encapsulation");
KemEncryptInternal(encBuf, encOff, secBuf, secOff, pk, randBytes);
}
internal void KemEncryptInternal(byte[] encBuf, int encOff, byte[] secBuf, int secOff, byte[] pk, byte[] randBytes)
{
byte[] array = new byte[64];
byte[] array2 = new byte[64];
Array.Copy(randBytes, 0, array, 0, 32);
Symmetric.Hash_h(pk, 0, pk.Length, array, 32);
Symmetric.Hash_g(array, array2);
m_indCpa.Encrypt(encBuf, encOff, Arrays.CopyOfRange(array, 0, 32), pk, Arrays.CopyOfRange(array2, 32, 64));
Array.Copy(array2, 0, secBuf, secOff, 32);
}
private static void CMov(byte[] r, byte[] x, int len, bool b)
{
if (b)
Array.Copy(x, 0, r, 0, len);
else
Array.Copy(r, 0, r, 0, len);
}
internal void RandomBytes(byte[] buf, int len)
{
m_random.NextBytes(buf, 0, len);
}
}
}