DilithiumEngine
class DilithiumEngine
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
{
internal class DilithiumEngine
{
private SecureRandom _random;
public const int N = 256;
public const int Q = 8380417;
public const int QInv = 58728449;
public const int D = 13;
public const int RootOfUnity = 1753;
public const int SeedBytes = 32;
public const int CrhBytes = 64;
public const int RndBytes = 32;
public const int TrBytes = 64;
public const int PolyT1PackedBytes = 320;
public const int PolyT0PackedBytes = 416;
public int Mode { get; set; }
public int K { get; set; }
public int L { get; set; }
public int Eta { get; set; }
public int Tau { get; set; }
public int Beta { get; set; }
public int Gamma1 { get; set; }
public int Gamma2 { get; set; }
public int Omega { get; set; }
public int CTilde { get; set; }
public int PolyVecHPackedBytes { get; set; }
public int PolyZPackedBytes { get; set; }
public int PolyW1PackedBytes { get; set; }
public int PolyEtaPackedBytes { get; set; }
public int CryptoPublicKeyBytes { get; set; }
public int CryptoSecretKeyBytes { get; set; }
public int CryptoBytes { get; set; }
public int PolyUniformGamma1NBytes { get; set; }
public Symmetric Symmetric { get; set; }
public DilithiumEngine(int mode, SecureRandom random, bool usingAes)
{
Mode = mode;
switch (Mode) {
case 2:
K = 4;
L = 4;
Eta = 2;
Tau = 39;
Beta = 78;
Gamma1 = 131072;
Gamma2 = 95232;
Omega = 80;
PolyZPackedBytes = 576;
PolyW1PackedBytes = 192;
PolyEtaPackedBytes = 96;
CTilde = 32;
break;
case 3:
K = 6;
L = 5;
Eta = 4;
Tau = 49;
Beta = 196;
Gamma1 = 524288;
Gamma2 = 261888;
Omega = 55;
PolyZPackedBytes = 640;
PolyW1PackedBytes = 128;
PolyEtaPackedBytes = 128;
CTilde = 48;
break;
case 5:
K = 8;
L = 7;
Eta = 2;
Tau = 60;
Beta = 120;
Gamma1 = 524288;
Gamma2 = 261888;
Omega = 75;
PolyZPackedBytes = 640;
PolyW1PackedBytes = 128;
PolyEtaPackedBytes = 96;
CTilde = 64;
break;
default:
throw new ArgumentException("The mode " + mode.ToString() + "is not supported by Crystals Dilithium!");
}
if (usingAes)
Symmetric = new Symmetric.AesSymmetric();
else
Symmetric = new Symmetric.ShakeSymmetric();
_random = random;
PolyVecHPackedBytes = Omega + K;
CryptoPublicKeyBytes = 32 + K * 320;
CryptoSecretKeyBytes = 96 + L * PolyEtaPackedBytes + K * PolyEtaPackedBytes + K * 416;
CryptoBytes = CTilde + L * PolyZPackedBytes + PolyVecHPackedBytes;
if (Gamma1 == 131072)
PolyUniformGamma1NBytes = (576 + Symmetric.Stream256BlockBytes - 1) / Symmetric.Stream256BlockBytes;
else {
if (Gamma1 != 524288)
throw new ArgumentException("Wrong Dilithium Gamma1!");
PolyUniformGamma1NBytes = (640 + Symmetric.Stream256BlockBytes - 1) / Symmetric.Stream256BlockBytes;
}
}
public void GenerateKeyPair(out byte[] rho, out byte[] key, out byte[] tr, out byte[] s1_, out byte[] s2_, out byte[] t0_, out byte[] encT1)
{
byte[] array = new byte[32];
byte[] array2 = new byte[128];
byte[] array3 = new byte[64];
tr = new byte[64];
rho = new byte[32];
key = new byte[32];
s1_ = new byte[L * PolyEtaPackedBytes];
s2_ = new byte[K * PolyEtaPackedBytes];
t0_ = new byte[K * 416];
PolyVecMatrix polyVecMatrix = new PolyVecMatrix(this);
PolyVecL polyVecL = new PolyVecL(this);
PolyVecK polyVecK = new PolyVecK(this);
PolyVecK polyVecK2 = new PolyVecK(this);
PolyVecK polyVecK3 = new PolyVecK(this);
_random.NextBytes(array);
ShakeDigest shakeDigest = new ShakeDigest(256);
shakeDigest.BlockUpdate(array, 0, 32);
shakeDigest.OutputFinal(array2, 0, 128);
rho = Arrays.CopyOfRange(array2, 0, 32);
array3 = Arrays.CopyOfRange(array2, 32, 96);
key = Arrays.CopyOfRange(array2, 96, 128);
polyVecMatrix.ExpandMatrix(rho);
polyVecL.UniformEta(array3, 0);
polyVecK.UniformEta(array3, (ushort)L);
PolyVecL polyVecL2 = new PolyVecL(this);
polyVecL.CopyPolyVecL(polyVecL2);
polyVecL2.Ntt();
polyVecMatrix.PointwiseMontgomery(polyVecK2, polyVecL2);
polyVecK2.Reduce();
polyVecK2.InverseNttToMont();
polyVecK2.AddPolyVecK(polyVecK);
polyVecK2.ConditionalAddQ();
polyVecK2.Power2Round(polyVecK3);
encT1 = Packing.PackPublicKey(polyVecK2, this);
shakeDigest.BlockUpdate(rho, 0, rho.Length);
shakeDigest.BlockUpdate(encT1, 0, encT1.Length);
shakeDigest.OutputFinal(tr, 0, 64);
Packing.PackSecretKey(t0_, s1_, s2_, polyVecK3, polyVecL, polyVecK, this);
}
public void SignSignature(byte[] sig, int siglen, byte[] msg, int msglen, byte[] rho, byte[] key, byte[] tr, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc)
{
byte[] array4 = new byte[224];
byte[] array = new byte[64];
byte[] array2 = new byte[64];
ushort num = 0;
PolyVecMatrix polyVecMatrix = new PolyVecMatrix(this);
PolyVecL polyVecL = new PolyVecL(this);
PolyVecL polyVecL2 = new PolyVecL(this);
PolyVecL polyVecL3 = new PolyVecL(this);
PolyVecK polyVecK = new PolyVecK(this);
PolyVecK polyVecK2 = new PolyVecK(this);
PolyVecK polyVecK3 = new PolyVecK(this);
PolyVecK polyVecK4 = new PolyVecK(this);
PolyVecK polyVecK5 = new PolyVecK(this);
Poly poly = new Poly(this);
Packing.UnpackSecretKey(polyVecK, polyVecL, polyVecK2, t0Enc, s1Enc, s2Enc, this);
ShakeDigest shakeDigest = new ShakeDigest(256);
shakeDigest.BlockUpdate(tr, 0, 64);
shakeDigest.BlockUpdate(msg, 0, msglen);
shakeDigest.OutputFinal(array, 0, 64);
byte[] sourceArray = new byte[32];
if (_random != null)
_random.NextBytes(array2);
byte[] array3 = Arrays.CopyOf(key, 128);
Array.Copy(sourceArray, 0, array3, 32, 32);
Array.Copy(array, 0, array3, 64, 64);
shakeDigest.BlockUpdate(array3, 0, 128);
shakeDigest.OutputFinal(array2, 0, 64);
polyVecMatrix.ExpandMatrix(rho);
polyVecL.Ntt();
polyVecK2.Ntt();
polyVecK.Ntt();
while (true) {
PolyVecL polyVecL4 = polyVecL2;
byte[] seed = array2;
ushort num2 = num;
num = (ushort)(num2 + 1);
polyVecL4.UniformGamma1(seed, num2);
polyVecL2.CopyPolyVecL(polyVecL3);
polyVecL3.Ntt();
polyVecMatrix.PointwiseMontgomery(polyVecK3, polyVecL3);
polyVecK3.Reduce();
polyVecK3.InverseNttToMont();
polyVecK3.ConditionalAddQ();
polyVecK3.Decompose(polyVecK4);
polyVecK3.PackW1(sig);
shakeDigest.BlockUpdate(array, 0, 64);
shakeDigest.BlockUpdate(sig, 0, K * PolyW1PackedBytes);
shakeDigest.OutputFinal(sig, 0, CTilde);
poly.Challenge(sig);
poly.PolyNtt();
polyVecL3.PointwisePolyMontgomery(poly, polyVecL);
polyVecL3.InverseNttToMont();
polyVecL3.AddPolyVecL(polyVecL2);
polyVecL3.Reduce();
if (!polyVecL3.CheckNorm(Gamma1 - Beta)) {
polyVecK5.PointwisePolyMontgomery(poly, polyVecK2);
polyVecK5.InverseNttToMont();
polyVecK4.Subtract(polyVecK5);
polyVecK4.Reduce();
if (!polyVecK4.CheckNorm(Gamma2 - Beta)) {
polyVecK5.PointwisePolyMontgomery(poly, polyVecK);
polyVecK5.InverseNttToMont();
polyVecK5.Reduce();
if (!polyVecK5.CheckNorm(Gamma2)) {
polyVecK4.AddPolyVecK(polyVecK5);
polyVecK4.ConditionalAddQ();
if (polyVecK5.MakeHint(polyVecK4, polyVecK3) <= Omega)
break;
}
}
}
}
Packing.PackSignature(sig, sig, polyVecL3, polyVecK5, this);
}
public void Sign(byte[] sig, int siglen, byte[] msg, int mlen, byte[] rho, byte[] key, byte[] tr, byte[] t0, byte[] s1, byte[] s2)
{
SignSignature(sig, siglen, msg, mlen, rho, key, tr, t0, s1, s2);
}
public bool SignVerify(byte[] sig, int siglen, byte[] msg, int msglen, byte[] rho, byte[] encT1)
{
byte[] array = new byte[K * PolyW1PackedBytes];
byte[] array2 = new byte[64];
byte[] array3 = new byte[CTilde];
Poly poly = new Poly(this);
PolyVecMatrix polyVecMatrix = new PolyVecMatrix(this);
PolyVecL polyVecL = new PolyVecL(this);
PolyVecK t = new PolyVecK(this);
PolyVecK polyVecK = new PolyVecK(this);
PolyVecK h = new PolyVecK(this);
if (siglen != CryptoBytes)
return false;
t = Packing.UnpackPublicKey(t, encT1, this);
if (!Packing.UnpackSignature(polyVecL, h, sig, this))
return false;
byte[] array4 = Arrays.CopyOfRange(sig, 0, CTilde);
if (polyVecL.CheckNorm(Gamma1 - Beta))
return false;
ShakeDigest shakeDigest = new ShakeDigest(256);
shakeDigest.BlockUpdate(rho, 0, rho.Length);
shakeDigest.BlockUpdate(encT1, 0, encT1.Length);
shakeDigest.OutputFinal(array2, 0, 64);
shakeDigest.BlockUpdate(array2, 0, 64);
shakeDigest.BlockUpdate(msg, 0, msglen);
shakeDigest.DoFinal(array2, 0);
poly.Challenge(array4);
polyVecMatrix.ExpandMatrix(rho);
polyVecL.Ntt();
polyVecMatrix.PointwiseMontgomery(polyVecK, polyVecL);
poly.PolyNtt();
t.ShiftLeft();
t.Ntt();
t.PointwisePolyMontgomery(poly, t);
polyVecK.Subtract(t);
polyVecK.Reduce();
polyVecK.InverseNttToMont();
polyVecK.ConditionalAddQ();
polyVecK.UseHint(polyVecK, h);
polyVecK.PackW1(array);
shakeDigest.BlockUpdate(array2, 0, 64);
shakeDigest.BlockUpdate(array, 0, K * PolyW1PackedBytes);
shakeDigest.OutputFinal(array3, 0, CTilde);
for (int i = 0; i < CTilde; i++) {
if (array4[i] != array3[i])
return false;
}
return true;
}
public bool SignOpen(byte[] msg, byte[] sig, int siglen, byte[] rho, byte[] t1)
{
return SignVerify(sig, siglen, msg, msg.Length, rho, t1);
}
}
}