diff options
author | David Hook <dgh@cryptoworkshop.com> | 2022-09-14 05:28:35 +1000 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2022-09-14 05:28:35 +1000 |
commit | 2d8f553417bcfb1b7068405292f81518a3d51a11 (patch) | |
tree | 21d75d8c8fd9d2f26821d9ab6b69827a58aabad7 | |
parent | Use nullable DateTime instead of MinValue (diff) | |
download | BouncyCastle.NET-ed25519-2d8f553417bcfb1b7068405292f81518a3d51a11.tar.xz |
first cut of Dilithium
17 files changed, 2200 insertions, 0 deletions
diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumEngine.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumEngine.cs new file mode 100644 index 000000000..6cc3bca53 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumEngine.cs @@ -0,0 +1,547 @@ +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using static Org.BouncyCastle.Tls.DtlsReliableHandshake; + +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; // Q ^ (-1) mod 2 ^32 + public const int D = 13; + public const int RootOfUnity = 1753; + public const int SeedBytes = 32; + public const int CrhBytes = 64; + public const bool RandomizedSigning = false; + + public const int PolyT1PackedBytes = 320; + public const int PolyT0PackedBytes = 416; + + public int Mode { get; private set; } + + public int K { get; private set; } + public int L { get; private set; } + public int Eta { get; private set; } + public int Tau { get; private set; } + public int Beta { get; private set; } + public int Gamma1 { get; private set; } + public int Gamma2 { get; private set; } + public int Omega { get; private set; } + + public int PolyVecHPackedBytes { get; private set; } + + public int PolyZPackedBytes { get; private set; } + public int PolyW1PackedBytes { get; private set; } + public int PolyEtaPackedBytes { get; private set; } + + public int CryptoPublicKeyBytes { get; private set; } + public int CryptoSecretKeyBytes { get; private set; } + public int CryptoBytes { get; private set; } + public int PolyUniformGamma1NBytes { get; private set; } + + public DilithiumEngine(int mode, SecureRandom random) + { + Mode = mode; + switch (Mode) + { + case 2: + K = 4; + L = 4; + Eta = 2; + Tau = 39; + Beta = 78; + Gamma1 = (1 << 17); + Gamma2 = ((Q - 1) / 88); + Omega = 80; + PolyZPackedBytes = 576; + PolyW1PackedBytes = 192; + PolyEtaPackedBytes = 96; + break; + case 3: + K = 6; + L = 5; + Eta = 4; + Tau = 49; + Beta = 196; + Gamma1 = (1 << 19); + Gamma2 = ((Q - 1) / 32); + Omega = 55; + PolyZPackedBytes = 640; + PolyW1PackedBytes = 128; + PolyEtaPackedBytes = 128; + break; + case 5: + K = 8; + L = 7; + Eta = 2; + Tau = 60; + Beta = 120; + Gamma1 = (1 << 19); + Gamma2 = ((Q - 1) / 32); + Omega = 75; + PolyZPackedBytes = 640; + PolyW1PackedBytes = 128; + PolyEtaPackedBytes = 96; + break; + default: + throw new ArgumentException("The mode " + mode + "is not supported by Crystals Dilithium!"); + } + + _random = random; + PolyVecHPackedBytes = Omega + K; + CryptoPublicKeyBytes = SeedBytes + K * PolyT1PackedBytes; + CryptoSecretKeyBytes = 3 * SeedBytes + L * PolyEtaPackedBytes + K * PolyEtaPackedBytes + K * PolyT0PackedBytes; + CryptoBytes = SeedBytes + L * PolyZPackedBytes + PolyVecHPackedBytes; + + if (Gamma1 == (1 << 17)) + { + PolyUniformGamma1NBytes = ((576 + Symmetric.Shake256Rate - 1) / Symmetric.Shake256Rate); + } + else if (Gamma1 == (1 << 19)) + { + PolyUniformGamma1NBytes = ((640 + Symmetric.Shake256Rate - 1) / Symmetric.Shake256Rate); + } + else + { + throw new ArgumentException("Wrong Dilithium Gamma1!"); + } + } + + public void GenerateKeyPair(byte[] pk, byte[] sk) + { + byte[] SeedBuf = new byte[SeedBytes]; + byte[] buf = new byte[2 * SeedBytes + CrhBytes]; + byte[] tr = new byte[SeedBytes]; + + byte[] rho, rhoPrime, key; + + PolyVecMatrix Matrix = new PolyVecMatrix(this); + + PolyVecL s1 = new PolyVecL(this), s1Hat; + PolyVecK s2 = new PolyVecK(this), t1 = new PolyVecK(this), t0 = new PolyVecK(this); + + _random.NextBytes(SeedBuf); + + //Console.WriteLine("SeedBuf = {0}", Convert.ToHexString(SeedBuf)); + + + ShakeDigest Shake256Digest = new ShakeDigest(256); + Shake256Digest.BlockUpdate(SeedBuf, 0, SeedBytes); + Shake256Digest.DoFinal(buf, 0, 2 * SeedBytes + CrhBytes); + + rho = Arrays.CopyOfRange(buf, 0, SeedBytes); + rhoPrime = Arrays.CopyOfRange(buf, SeedBytes, SeedBytes + CrhBytes); + key = Arrays.CopyOfRange(buf, SeedBytes + CrhBytes, 2 * SeedBytes + CrhBytes); + + Matrix.ExpandMatrix(rho); + + s1.UniformEta(rhoPrime, (ushort)0); + + s2.UniformEta(rhoPrime, (ushort)L); + + s1Hat = new PolyVecL(this); + + s1.CopyPolyVecL(s1Hat); + s1Hat.Ntt(); + + Matrix.PointwiseMontgomery(t1, s1Hat); + + t1.Reduce(); + t1.InverseNttToMont(); + + t1.AddPolyVecK(s2); + t1.ConditionalAddQ(); + t1.Power2Round(t0); + + //Console.WriteLine("t1 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (short coeff in t1.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + //Console.WriteLine("rho = {0}", Convert.ToHexString(rho)); + + Packing.PackPublicKey(pk, rho, t1, this); + + Shake256Digest.BlockUpdate(pk, 0, CryptoPublicKeyBytes); + Shake256Digest.DoFinal(tr, 0, SeedBytes); + + Packing.PackSecretKey(sk, rho, tr, key, t0, s1, s2, this); + } + + public void SignSignature(byte[] sig, int siglen, byte[] msg, int msglen, byte[] sk) + { + int n; + byte[] SeedBuf = new byte[3 * SeedBytes + 2 * CrhBytes]; + byte[] rho = new byte[SeedBytes], tr = new byte[SeedBytes], key = new byte[SeedBytes], mu = new byte[CrhBytes], rhoPrime = new byte[CrhBytes]; + ushort nonce = 0; + PolyVecMatrix Matrix = new PolyVecMatrix(this); + PolyVecL s1 = new PolyVecL(this), y = new PolyVecL(this), z = new PolyVecL(this); + PolyVecK t0 = new PolyVecK(this), s2 = new PolyVecK(this), w1 = new PolyVecK(this), w0 = new PolyVecK(this), h = new PolyVecK(this); + Poly cp = new Poly(this); + + Packing.UnpackSecretKey(rho, tr, key, t0, s1, s2, sk, this); + + ShakeDigest ShakeDigest256 = new ShakeDigest(256); + ShakeDigest256.BlockUpdate(tr, 0, SeedBytes); + ShakeDigest256.BlockUpdate(msg, 0, msglen); + ShakeDigest256.DoFinal(mu, 0, CrhBytes); + + if (RandomizedSigning) + { + _random.NextBytes(rhoPrime); + } + else + { + byte[] KeyMu = Arrays.CopyOf(key, SeedBytes + CrhBytes); + Array.Copy(mu, 0, KeyMu, SeedBytes, CrhBytes); + ShakeDigest256.BlockUpdate(KeyMu, 0, SeedBytes + CrhBytes); + ShakeDigest256.DoFinal(rhoPrime, 0, CrhBytes); + } + + Matrix.ExpandMatrix(rho); + + //Console.WriteLine("Matrix = ["); + //for (int i = 0; i < K; i++) + //{ + // Console.Write("[", i); + // for (int j = 0; j < L; j++) + // { + // Console.Write("{0} {1} [", i, j); + // for (int co = 0; co < N; co++) + // { + // Console.Write("{0}, ", Matrix.Matrix[i].Vec[j].Coeffs[co]); + // } + // Console.Write("]\n"); + // } + // Console.Write("]\n"); + //} + //Console.Write("]\n"); + + s1.Ntt(); + s2.Ntt(); + t0.Ntt(); + + rej: + y.UniformGamma1(rhoPrime, nonce++); + y.CopyPolyVecL(z); + z.Ntt(); + + Matrix.PointwiseMontgomery(w1, z); + + //Console.WriteLine("w1 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in w1.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + + w1.Reduce(); + w1.InverseNttToMont(); + + w1.ConditionalAddQ(); + w1.Decompose(w0); + + //Console.WriteLine("w0 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in w0.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + w1.PackW1(sig); + + ShakeDigest256.BlockUpdate(mu, 0, CrhBytes); + ShakeDigest256.BlockUpdate(sig, 0, K * PolyW1PackedBytes); + ShakeDigest256.DoFinal(sig, 0, SeedBytes); + + cp.Challenge(sig); + + cp.PolyNtt(); + + z.PointwisePolyMontgomery(cp, s1); + z.InverseNttToMont(); + z.AddPolyVecL(y); + z.Reduce(); + if (z.CheckNorm(Gamma1 - Beta)) + { + goto rej; + } + + //Console.WriteLine("cp = "); + //Console.Write("["); + //foreach (int coeff in cp.Coeffs) + //{ + // Console.Write(String.Format("{0}, ", coeff)); + //} + //Console.Write("]\n"); + + //Console.WriteLine("s2 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in s2.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + h.PointwisePolyMontgomery(cp, s2); + h.InverseNttToMont(); + + //Console.WriteLine("h = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in h.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + w0.Subtract(h); + w0.Reduce(); + if (w0.CheckNorm(Gamma2 - Beta)) + { + goto rej; + } + + h.PointwisePolyMontgomery(cp, t0); + h.InverseNttToMont(); + h.Reduce(); + if (h.CheckNorm(Gamma2)) + { + goto rej; + } + + w0.AddPolyVecK(h); + + //Console.WriteLine("w0 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in w0.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + w0.ConditionalAddQ(); + + //Console.WriteLine("w0 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in w0.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + //Console.WriteLine("w1 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in w1.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + n = h.MakeHint(w0, w1); + if (n > Omega) + { + goto rej; + } + + + //Console.WriteLine("z = "); + //for (int i = 0; i < L; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in z.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + //Console.WriteLine("h = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in h.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + Packing.PackSignature(sig, sig, z, h, this); + } + + public void Sign(byte[] sig, int siglen, byte[] msg, int msglen, byte[] sk) + { + SignSignature(sig, siglen, msg, msglen, sk); + } + + public bool SignVerify(byte[] msg, int msglen, byte[] sig, int siglen, byte[] pk) + { + byte[] buf = new byte[K * PolyW1PackedBytes], rho = new byte[SeedBytes], mu = new byte[CrhBytes], c = new byte[SeedBytes], c2 = new byte[SeedBytes]; + Poly cp = new Poly(this); + PolyVecMatrix Matrix = new PolyVecMatrix(this); + PolyVecL z = new PolyVecL(this); + PolyVecK t1 = new PolyVecK(this), w1 = new PolyVecK(this), h = new PolyVecK(this); + + if (sig.Length != CryptoBytes + msg.Length) + { + return false; + } + + Packing.UnpackPublicKey(rho, t1, pk, this); + + //Console.WriteLine("rho = "+Convert.ToHexString(rho)); + + //Console.WriteLine("t1 = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in t1.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + + if (!Packing.UnpackSignature(c, z, h, sig, this)) + { + return false; + } + + if (z.CheckNorm(Gamma1 - Beta)) + { + return false; + } + + //Console.WriteLine("z = "); + //for (int i = 0; i < L; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in z.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + //Console.WriteLine("h = "); + //for (int i = 0; i < K; ++i) + //{ + // Console.Write(String.Format("{0} [", i)); + // foreach (int coeff in h.Vec[i].Coeffs) + // { + // Console.Write(String.Format("{0}, ", coeff)); + // } + // Console.Write("]\n"); + //} + + + + ShakeDigest Shake256Digest = new ShakeDigest(256); + Shake256Digest.BlockUpdate(pk, 0, CryptoPublicKeyBytes); + Shake256Digest.DoFinal(mu, 0, SeedBytes); + + Shake256Digest.BlockUpdate(mu, 0, SeedBytes); + Shake256Digest.BlockUpdate(msg, 0, msglen); + Shake256Digest.DoFinal(mu, 0); + + cp.Challenge(c); + + Matrix.ExpandMatrix(rho); + + z.Ntt(); + Matrix.PointwiseMontgomery(w1, z); + + cp.PolyNtt(); + + t1.ShiftLeft(); + t1.Ntt(); + t1.PointwisePolyMontgomery(cp, t1); + + w1.Subtract(t1); + w1.Reduce(); + w1.InverseNttToMont(); + + w1.ConditionalAddQ(); + w1.UseHint(w1, h); + + w1.PackW1(buf); + + Shake256Digest.BlockUpdate(mu, 0, CrhBytes); + Shake256Digest.BlockUpdate(buf, 0, K * PolyW1PackedBytes); + Shake256Digest.DoFinal(c2, 0, SeedBytes); + + for (int i = 0; i < SeedBytes; ++i) + { + if (c[i] != c2[i]) + { + return false; + } + } + return true; + } + + public bool SignOpen(byte[] msg, int msglen, byte[] sig, int siglen, byte[] pk) + { + int i; + if (siglen < CryptoBytes) + { + goto badsig; + } + + Array.Copy(sig, CryptoBytes, msg, 0, siglen - CryptoBytes); + if (SignVerify(msg, siglen - CryptoBytes, sig, siglen, pk)) + { + return true; + } + + badsig: + for (i = 0; i < msg.Length; i++) + { + msg[i] = 0; + } + return false; + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyGenerationParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyGenerationParameters.cs new file mode 100644 index 000000000..a5883bf78 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyGenerationParameters.cs @@ -0,0 +1,18 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumKeyGenerationParameters + : KeyGenerationParameters + { + private DilithiumParameters parameters; + + public DilithiumKeyGenerationParameters(SecureRandom random, DilithiumParameters parameters) : base(random, 255) + { + this.parameters = parameters; + } + + public DilithiumParameters Parameters => parameters; + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyPairGenerator.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyPairGenerator.cs new file mode 100644 index 000000000..57e2e3629 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyPairGenerator.cs @@ -0,0 +1,35 @@ + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + + { + private SecureRandom random; + private DilithiumParameters parameters; + + public void Init(KeyGenerationParameters param) + { + random = param.Random; + parameters = ((DilithiumKeyGenerationParameters)param).Parameters; + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + DilithiumEngine engine = parameters.GetEngine(random); + byte[] sk = new byte[engine.CryptoSecretKeyBytes]; + byte[] pk = new byte[engine.CryptoPublicKeyBytes]; + engine.GenerateKeyPair(pk, sk); + + DilithiumPublicKeyParameters pubKey = new DilithiumPublicKeyParameters(parameters, pk); + DilithiumPrivateKeyParameters privKey = new DilithiumPrivateKeyParameters(parameters, sk); + + + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyParameters.cs new file mode 100644 index 000000000..7e0054747 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumKeyParameters.cs @@ -0,0 +1,18 @@ + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumKeyParameters + : AsymmetricKeyParameter + { + DilithiumParameters parameters; + + public DilithiumKeyParameters(bool isPrivate, DilithiumParameters parameters) : base(isPrivate) + { + this.parameters = parameters; + } + + public DilithiumParameters Parameters => parameters; + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumParameters.cs new file mode 100644 index 000000000..48c697b55 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumParameters.cs @@ -0,0 +1,28 @@ + +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumParameters + : ICipherParameters + { + public static DilithiumParameters Dilithium2 = new DilithiumParameters(2); + public static DilithiumParameters Dilithium3 = new DilithiumParameters(3); + public static DilithiumParameters Dilithium5 = new DilithiumParameters(5); + + private int k; + + private DilithiumParameters(int param) + { + k = param; + } + + public DilithiumEngine GetEngine(SecureRandom Random) + { + return new DilithiumEngine(k, Random); + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs new file mode 100644 index 000000000..510e46eea --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs @@ -0,0 +1,22 @@ + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumPrivateKeyParameters + : DilithiumKeyParameters + { + private byte[] privateKey; + + public DilithiumPrivateKeyParameters(DilithiumParameters parameters, byte[] skEncoded) + : base(true, parameters) + { + privateKey = Arrays.Clone(skEncoded); + } + + public byte[] GetEncoded() + { + return Arrays.Clone(privateKey); + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs new file mode 100644 index 000000000..c2891ba3d --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs @@ -0,0 +1,24 @@ + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumPublicKeyParameters + : DilithiumKeyParameters + { + + private byte[] publicKey; + + public DilithiumPublicKeyParameters(DilithiumParameters parameters, byte[] pkEncoded) + : base(false, parameters) + { + publicKey = Arrays.Clone(pkEncoded); + } + + public byte[] GetEncoded() + { + return Arrays.Clone(publicKey); + } + + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs new file mode 100644 index 000000000..3c7ad7d60 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs @@ -0,0 +1,60 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using System; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + public class DilithiumSigner + : IMessageSigner + { + private DilithiumPrivateKeyParameters privKey; + private DilithiumPublicKeyParameters pubKey; + + private SecureRandom random; + + public DilithiumSigner(SecureRandom random) + { + this.random = random; + } + + public void Init(bool forSigning, ICipherParameters param) + { + if (forSigning) + { + if (param is ParametersWithRandom) + { + privKey = (DilithiumPrivateKeyParameters)((ParametersWithRandom)param).Parameters; + random = ((ParametersWithRandom)param).Random; + } + else + { + privKey = (DilithiumPrivateKeyParameters)param; + random = new SecureRandom(); + } + } + else + { + pubKey = (DilithiumPublicKeyParameters) param; + } + + } + + public byte[] GenerateSignature(byte[] message) + { + DilithiumEngine engine = privKey.Parameters.GetEngine(random); + byte[] sig = new byte[engine.CryptoBytes]; + engine.Sign(sig, sig.Length, message, message.Length, privKey.GetEncoded()); + return sig; + } + + public bool VerifySignature(byte[] message, byte[] signature) + { + DilithiumEngine engine = pubKey.Parameters.GetEngine(random); + return engine.SignOpen(message, message.Length, signature, signature.Length, pubKey.GetEncoded()); + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Ntt.cs b/crypto/src/pqc/crypto/crystals/dilithium/Ntt.cs new file mode 100644 index 000000000..5ca7f8b6b --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Ntt.cs @@ -0,0 +1,98 @@ +using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; +using Org.BouncyCastle.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class Ntt + { + private static int[] Zetas = { + 0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, + 1826347, 2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103, + 2725464, 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549, + -2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005, + 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, + -3861115, -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, + -1699267, -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, + 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779, + -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221, + -1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922, + 3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, + -671102, -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430, + -3343383, 264944, 508951, 3097992, 44288, -1100098, 904516, 3958618, + -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, + 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330, + 1285669, -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961, + 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, + 266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, + 900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500, + -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, + 342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, + -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, + -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642, + -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, + -542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, + -2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385, + -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078, + -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, + -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, + -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782 + }; + public static void NTT(int[] r) + { + uint len, start, j, k; + int zeta, t; + + k = 0; + for (len = 128; len > 0; len >>= 1) + { + for (start = 0; start < DilithiumEngine.N; start = j + len) + { + zeta = Ntt.Zetas[++k]; + for (j = start; j < start + len; ++j) + { + t = Reduce.MontgomeryReduce((long)((long)zeta * (long)r[j + len])); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } + } + } + } + + public static void InverseNttToMont(int[] a) + { + uint start, len, j, k; + int t, zeta; + const int f = 41978; // (mont^2)/256 + + + k = 256; + for (len = 1; len < DilithiumEngine.N; len <<= 1) + { + for (start = 0; start < DilithiumEngine.N; start = j + len) + { + zeta = (-1) * Ntt.Zetas[--k]; + for (j = start; j < start + len; ++j) + { + t = a[j]; + a[j] = t + a[j + len]; + a[j + len] = t - a[j + len]; + a[j + len] = Reduce.MontgomeryReduce((long)((long)zeta * (long)a[j + len])); + } + + } + } + + for (j = 0; j < DilithiumEngine.N; ++j) + { + a[j] = Reduce.MontgomeryReduce((long)((long)f * (long)a[j])); + } + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Packing.cs b/crypto/src/pqc/crypto/crystals/dilithium/Packing.cs new file mode 100644 index 000000000..caed99a30 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Packing.cs @@ -0,0 +1,177 @@ +using Org.BouncyCastle.Pqc.Crypto.SphincsPlus; +using Org.BouncyCastle.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class Packing + { + public static void PackPublicKey(byte[] pk, byte[] rho, PolyVecK t1, DilithiumEngine Engine) + { + Array.Copy(rho, 0, pk, 0, DilithiumEngine.SeedBytes); + for (int i = 0; i < Engine.K; i++) + { + t1.Vec[i].PolyT1Pack(pk, DilithiumEngine.SeedBytes + i * DilithiumEngine.PolyT1PackedBytes); + } + } + + public static void UnpackPublicKey(byte[] rho, PolyVecK t1, byte[] pk, DilithiumEngine Engine) + { + int i; + + Array.Copy(pk, 0, rho, 0, DilithiumEngine.SeedBytes); + + for (i = 0; i < Engine.K; ++i) + { + t1.Vec[i].PolyT1Unpack(pk, DilithiumEngine.SeedBytes + i * DilithiumEngine.PolyT1PackedBytes); + } + } + + public static void PackSecretKey(byte[] sk, byte[] rho, byte[] tr, byte[] key, PolyVecK t0, PolyVecL s1, PolyVecK s2, DilithiumEngine Engine) + { + int i, end = 0; + Array.Copy(rho, sk, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + Array.Copy(key, 0, sk, end, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + Array.Copy(tr, 0, sk, end, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + for (i = 0; i < Engine.L; ++i) + { + s1.Vec[i].PolyEtaPack(sk, end + i * Engine.PolyEtaPackedBytes); + } + end += Engine.L * Engine.PolyEtaPackedBytes; + + for (i = 0; i < Engine.K; ++i) + { + s2.Vec[i].PolyEtaPack(sk, end + i * Engine.PolyEtaPackedBytes); + } + end += Engine.K * Engine.PolyEtaPackedBytes; + + for (i = 0; i < Engine.K; ++i) + { + t0.Vec[i].PolyT0Pack(sk, end + i * DilithiumEngine.PolyT0PackedBytes); + } + } + + public static void UnpackSecretKey(byte[] rho, byte[] tr, byte[] key, PolyVecK t0, PolyVecL s1, PolyVecK s2, byte[] sk, DilithiumEngine Engine) + { + int i, end = 0; + Array.Copy(sk, 0, rho, 0, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + Array.Copy(sk, end, key, 0, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + Array.Copy(sk, end, tr, 0, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + for (i = 0; i < Engine.L; ++i) + { + s1.Vec[i].PolyEtaUnpack(sk, end + i * Engine.PolyEtaPackedBytes); + } + end += Engine.L * Engine.PolyEtaPackedBytes; + + for (i = 0; i < Engine.K; ++i) + { + s2.Vec[i].PolyEtaUnpack(sk, end + i * Engine.PolyEtaPackedBytes); + } + end += Engine.K * Engine.PolyEtaPackedBytes; + + for (i = 0; i < Engine.K; ++i) + { + t0.Vec[i].PolyT0Unpack(sk, end + i * DilithiumEngine.PolyT0PackedBytes); + } + } + + public static void PackSignature(byte[] sig, byte[] c, PolyVecL z, PolyVecK h, DilithiumEngine engine) + { + int i, j, k, end = 0; + + Array.Copy(c, 0, sig, 0, DilithiumEngine.SeedBytes); + end += DilithiumEngine.SeedBytes; + + for (i = 0; i < engine.L; ++i) + { + z.Vec[i].PackZ(sig, end + i * engine.PolyZPackedBytes); + } + end += engine.L * engine.PolyZPackedBytes; + + for (i = 0; i < engine.Omega + engine.K; ++i) + { + sig[end + i] = 0; + } + + + k = 0; + for (i = 0; i < engine.K; ++i) + { + for (j = 0; j < DilithiumEngine.N; ++j) + { + if (h.Vec[i].Coeffs[j] != 0) + { + sig[end + k++] = (byte)j; + } + } + sig[end + engine.Omega + i] = (byte)k; + } + //Console.WriteLine("sig = " + Convert.ToHexString(sig)); + + } + + public static bool UnpackSignature(byte[] c, PolyVecL z, PolyVecK h, byte[] sig, DilithiumEngine Engine) + { + int i, j, k; + + Array.Copy(sig, c, DilithiumEngine.SeedBytes); + + int end = DilithiumEngine.SeedBytes; + for (i = 0; i < Engine.L; ++i) + { + z.Vec[i].UnpackZ(sig, end + i * Engine.PolyZPackedBytes); + } + end += Engine.L * Engine.PolyZPackedBytes; + + k = 0; + for (i = 0; i < Engine.K; ++i) + { + for (j = 0; j < DilithiumEngine.N; ++j) + { + h.Vec[i].Coeffs[j] = 0; + } + + if ((sig[end + Engine.Omega + i] & 0xFF) < k || (sig[end + Engine.Omega + i] & 0xFF) > Engine.Omega) + { + return false; + } + + for (j = k; j < (sig[end + Engine.Omega + i] & 0xFF); ++j) + { + if (j > k && (sig[end + j] & 0xFF) <= (sig[end + j - 1] & 0xFF)) + { + return false; + } + h.Vec[i].Coeffs[sig[end + j] & 0xFF] = 1; + } + + k = (int)(sig[end + Engine.Omega + i]); + } + for (j = k; j < Engine.Omega; ++j) + { + if ((sig[end + j] & 0xFF) != 0) + { + return false; + } + } + return true; + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Poly.cs b/crypto/src/pqc/crypto/crystals/dilithium/Poly.cs new file mode 100644 index 000000000..8ee9676e3 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Poly.cs @@ -0,0 +1,695 @@ +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class Poly + { + public int[] Coeffs { get; set; } + + private int N; + private DilithiumEngine Engine; + private int PolyUniformNBlocks = (768 + Symmetric.Shake128Rate - 1) / Symmetric.Shake128Rate; + + public Poly(DilithiumEngine engine) + { + N = DilithiumEngine.N; + Coeffs = new int[N]; + Engine = engine; + } + + public void UniformBlocks(byte[] seed, ushort nonce) + { + int i, ctr, off, + buflen = PolyUniformNBlocks * Symmetric.Shake128Rate; + byte[] buf = new byte[buflen + 2]; + ShakeDigest Shake128Digest = new ShakeDigest(128); + + Symmetric.ShakeStreamInit(Shake128Digest, seed, nonce); + + Shake128Digest.DoOutput(buf, 0, buflen + 2); + + ctr = RejectUniform(Coeffs, 0, N, buf, buflen); + + while (ctr < N) + { + off = buflen % 3; + for (i = 0; i < off; ++i) + { + buf[i] = buf[buflen - off + i]; + } + Shake128Digest.DoOutput(buf, buflen + off, 1); + buflen = Symmetric.Shake128Rate + off; + ctr += RejectUniform(Coeffs, ctr, N, buf, buflen); + } + + + } + + private static int RejectUniform(int[] coeffs, int off, int len, byte[] buf, int buflen) + { + int ctr, pos; + uint t; + + + ctr = pos = 0; + while (ctr < len && pos + 3 <= buflen) + { + t = (uint)(buf[pos++] & 0xFF); + t |= (uint)(buf[pos++] & 0xFF) << 8; + t |= (uint)(buf[pos++] & 0xFF) << 16; + t &= 0x7FFFFF; + + if (t < DilithiumEngine.Q) + { + coeffs[off + ctr++] = (int)t; + } + } + return ctr; + + } + + public void UniformEta(byte[] seed, ushort nonce) + { + int ctr, PolyUniformEtaNBlocks, eta = Engine.Eta; + + + if (Engine.Eta == 2) + { + PolyUniformEtaNBlocks = ((136 + Symmetric.Shake128Rate - 1) / Symmetric.Shake256Rate); + } + else if (Engine.Eta == 4) + { + PolyUniformEtaNBlocks = ((227 + Symmetric.Shake128Rate - 1) / Symmetric.Shake256Rate); + } + else + { + throw new ArgumentException("Wrong Dilithium Eta!"); + } + + int buflen = PolyUniformEtaNBlocks * Symmetric.Shake128Rate; + + byte[] buf = new byte[buflen]; + ShakeDigest Shake256Digest = new ShakeDigest(256); + + Symmetric.ShakeStreamInit(Shake256Digest, seed, nonce); + Shake256Digest.DoOutput(buf, 0, buflen); + ctr = RejectEta(Coeffs, 0, N, buf, buflen, eta); + + while (ctr < DilithiumEngine.N) + { + Shake256Digest.DoOutput(buf, buflen, Symmetric.Shake128Rate); + ctr += RejectEta(Coeffs, ctr, N - ctr, buf, Symmetric.Shake128Rate, eta); + } + } + + private static int RejectEta(int[] coeffs, int off, int len, byte[] buf, int buflen, int eta) + { + int ctr, pos; + uint t0, t1; + + ctr = pos = 0; + + while (ctr < len && pos < buflen) + { + t0 = (uint)(buf[pos] & 0xFF) & 0x0F; + t1 = (uint)(buf[pos++] & 0xFF) >> 4; + if (eta == 2) + { + if (t0 < 15) + { + t0 = t0 - (205 * t0 >> 10) * 5; + coeffs[off + ctr++] = (int)(2 - t0); + } + if (t1 < 15 && ctr < len) + { + t1 = t1 - (205 * t1 >> 10) * 5; + coeffs[off + ctr++] = (int)(2 - t1); + } + } + else if (eta == 4) + { + if (t0 < 9) + { + coeffs[off + ctr++] = (int)(4 - t0); + } + if (t1 < 9 && ctr < len) + { + coeffs[off + ctr++] = (int)(4 - t1); + } + } + } + return ctr; + } + + public void PointwiseMontgomery(Poly v, Poly w) + { + int i; + for (i = 0; i < N; ++i) + { + Coeffs[i] = Reduce.MontgomeryReduce((long)((long)v.Coeffs[i] * (long)w.Coeffs[i])); + } + } + + public void PointwiseAccountMontgomery(PolyVecL u, PolyVecL v) + { + int i; + Poly t = new Poly(Engine); + + PointwiseMontgomery(u.Vec[0], v.Vec[0]); + //Console.Write("temp = ["); + //for (int j = 0; j < N; ++j) + //{ + // Console.Write("{0}, ", Coeffs[j]); + //} + //Console.Write("]\n"); + + + + for (i = 1; i < Engine.L; ++i) + { + t.PointwiseMontgomery(u.Vec[i], v.Vec[i]); + AddPoly(t); + } + //Console.Write("temp = ["); + //for (int j = 0; j < N; ++j) + //{ + // Console.Write("{0}, ", Coeffs[j]); + //} + //Console.Write("]\n"); + } + + public void AddPoly(Poly a) + { + int i; + for (i = 0; i < N; i++) + { + Coeffs[i] += a.Coeffs[i]; + } + } + + public void Subtract(Poly b) + { + for (int i = 0; i < N; ++i) + { + Coeffs[i] -= b.Coeffs[i]; + } + } + + public void ReducePoly() + { + for (int i = 0; i < N; ++i) + { + Coeffs[i] = Reduce.Reduce32(Coeffs[i]); + } + } + + public void PolyNtt() + { + Ntt.NTT(Coeffs); + } + + public void InverseNttToMont() + { + Ntt.InverseNttToMont(Coeffs); + } + + public void ConditionalAddQ() + { + for (int i = 0; i < N; ++i) + { + Coeffs[i] = Reduce.ConditionalAddQ(Coeffs[i]); + } + } + + public void Power2Round(Poly a) + { + for (int i = 0; i < N; ++i) + { + int[] Power2Round = Rounding.Power2Round(Coeffs[i]); + Coeffs[i] = Power2Round[0]; + a.Coeffs[i] = Power2Round[1]; + } + } + + public void PolyT0Pack(byte[] r, int off) + { + int i; + int[] t = new int[8]; + for (i = 0; i < N / 8; ++i) + { + t[0] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 0]; + t[1] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 1]; + t[2] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 2]; + t[3] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 3]; + t[4] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 4]; + t[5] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 5]; + t[6] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 6]; + t[7] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 7]; + + r[off + 13 * i + 0] = (byte)(t[0]); + + r[off + 13 * i + 1] = (byte)(t[0] >> 8); + r[off + 13 * i + 1] = (byte)(r[off + 13 * i + 1] | (byte)(t[1] << 5)); + r[off + 13 * i + 2] = (byte)(t[1] >> 3); + r[off + 13 * i + 3] = (byte)(t[1] >> 11); + r[off + 13 * i + 3] = (byte)(r[off + 13 * i + 3] | (byte)(t[2] << 2)); + r[off + 13 * i + 4] = (byte)(t[2] >> 6); + r[off + 13 * i + 4] = (byte)(r[off + 13 * i + 4] | (byte)(t[3] << 7)); + r[off + 13 * i + 5] = (byte)(t[3] >> 1); + r[off + 13 * i + 6] = (byte)(t[3] >> 9); + r[off + 13 * i + 6] = (byte)(r[off + 13 * i + 6] | (byte)(t[4] << 4)); + r[off + 13 * i + 7] = (byte)(t[4] >> 4); + r[off + 13 * i + 8] = (byte)(t[4] >> 12); + r[off + 13 * i + 8] = (byte)(r[off + 13 * i + 8] | (byte)(t[5] << 1)); + r[off + 13 * i + 9] = (byte)(t[5] >> 7); + r[off + 13 * i + 9] = (byte)(r[off + 13 * i + 9] | (byte)(t[6] << 6)); + r[off + 13 * i + 10] = (byte)(t[6] >> 2); + r[off + 13 * i + 11] = (byte)(t[6] >> 10); + r[off + 13 * i + 11] = (byte)(r[off + 13 * i + 11] | (byte)(t[7] << 3)); + r[off + 13 * i + 12] = (byte)(t[7] >> 5); + } + } + + public void PolyT0Unpack(byte[] a, int off) + { + int i; + for (i = 0; i < N / 8; ++i) + { + Coeffs[8 * i + 0] = + ( + (a[off + 13 * i + 0] & 0xFF) | + ((a[off + 13 * i + 1] & 0xFF) << 8) + ) & 0x1FFF; + Coeffs[8 * i + 1] = + ( + (((a[off + 13 * i + 1] & 0xFF) >> 5) | + ((a[off + 13 * i + 2] & 0xFF) << 3)) | + ((a[off + 13 * i + 3] & 0xFF) << 11) + ) & 0x1FFF; + + Coeffs[8 * i + 2] = + ( + (((a[off + 13 * i + 3] & 0xFF) >> 2) | + ((a[off + 13 * i + 4] & 0xFF) << 6)) + ) & 0x1FFF; + + Coeffs[8 * i + 3] = + ( + (((a[off + 13 * i + 4] & 0xFF) >> 7) | + ((a[off + 13 * i + 5] & 0xFF) << 1)) | + ((a[off + 13 * i + 6] & 0xFF) << 9) + ) & 0x1FFF; + + Coeffs[8 * i + 4] = + ( + (((a[off + 13 * i + 6] & 0xFF) >> 4) | + ((a[off + 13 * i + 7] & 0xFF) << 4)) | + ((a[off + 13 * i + 8] & 0xFF) << 12) + ) & 0x1FFF; + + Coeffs[8 * i + 5] = + ( + (((a[off + 13 * i + 8] & 0xFF) >> 1) | + ((a[off + 13 * i + 9] & 0xFF) << 7)) + ) & 0x1FFF; + + Coeffs[8 * i + 6] = + ( + (((a[off + 13 * i + 9] & 0xFF) >> 6) | + ((a[off + 13 * i + 10] & 0xFF) << 2)) | + ((a[off + 13 * i + 11] & 0xFF) << 10) + ) & 0x1FFF; + + Coeffs[8 * i + 7] = + ( + ((a[off + 13 * i + 11] & 0xFF) >> 3 | + ((a[off + 13 * i + 12] & 0xFF) << 5)) + ) & 0x1FFF; + + + Coeffs[8 * i + 0] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 0]; + Coeffs[8 * i + 1] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 1]; + Coeffs[8 * i + 2] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 2]; + Coeffs[8 * i + 3] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 3]; + Coeffs[8 * i + 4] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 4]; + Coeffs[8 * i + 5] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 5]; + Coeffs[8 * i + 6] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 6]; + Coeffs[8 * i + 7] = (1 << (DilithiumEngine.D - 1)) - Coeffs[8 * i + 7]; + } + } + + public void PolyT1Pack(byte[] r, int off) + { + for (int i = 0; i < N / 4; ++i) + { + r[off + 5 * i + 0] = (byte)(Coeffs[4 * i + 0] >> 0); + r[off + 5 * i + 1] = (byte)((Coeffs[4 * i + 0] >> 8) | (Coeffs[4 * i + 1] << 2)); + r[off + 5 * i + 2] = (byte)((Coeffs[4 * i + 1] >> 6) | (Coeffs[4 * i + 2] << 4)); + r[off + 5 * i + 3] = (byte)((Coeffs[4 * i + 2] >> 4) | (Coeffs[4 * i + 3] << 6)); + r[off + 5 * i + 4] = (byte)(Coeffs[4 * i + 3] >> 2); + } + } + + public void PolyT1Unpack(byte[] a, int off) + { + int i; + + for (i = 0; i < N / 4; ++i) + { + Coeffs[4 * i + 0] = (((a[off + 5 * i + 0] & 0xFF) >> 0) | ((int)(a[off + 5 * i + 1] & 0xFF) << 8)) & 0x3FF; + Coeffs[4 * i + 1] = (((a[off + 5 * i + 1] & 0xFF) >> 2) | ((int)(a[off + 5 * i + 2] & 0xFF) << 6)) & 0x3FF; + Coeffs[4 * i + 2] = (((a[off + 5 * i + 2] & 0xFF) >> 4) | ((int)(a[off + 5 * i + 3] & 0xFF) << 4)) & 0x3FF; + Coeffs[4 * i + 3] = (((a[off + 5 * i + 3] & 0xFF) >> 6) | ((int)(a[off + 5 * i + 4] & 0xFF) << 2)) & 0x3FF; + } + } + + public void PolyEtaPack(byte[] r, int off) + { + int i; + byte[] t = new byte[8]; + + if (Engine.Eta == 2) + { + for (i = 0; i < N / 8; ++i) + { + t[0] = (byte)(Engine.Eta - Coeffs[8 * i + 0]); + t[1] = (byte)(Engine.Eta - Coeffs[8 * i + 1]); + t[2] = (byte)(Engine.Eta - Coeffs[8 * i + 2]); + t[3] = (byte)(Engine.Eta - Coeffs[8 * i + 3]); + t[4] = (byte)(Engine.Eta - Coeffs[8 * i + 4]); + t[5] = (byte)(Engine.Eta - Coeffs[8 * i + 5]); + t[6] = (byte)(Engine.Eta - Coeffs[8 * i + 6]); + t[7] = (byte)(Engine.Eta - Coeffs[8 * i + 7]); + + r[off + 3 * i + 0] = (byte)((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)); + r[off + 3 * i + 1] = (byte)((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); + r[off + 3 * i + 2] = (byte)((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); + } + } + else if (Engine.Eta == 4) + { + for (i = 0; i < N / 2; ++i) + { + t[0] = (byte)(Engine.Eta - Coeffs[2 * i + 0]); + t[1] = (byte)(Engine.Eta - Coeffs[2 * i + 1]); + r[off + i] = (byte)(t[0] | t[1] << 4); + } + } + else + { + throw new ArgumentException("Eta needs to be 2 or 4!"); + } + } + + public void PolyEtaUnpack(byte[] a, int off) + { + int i, eta = Engine.Eta; + + if (eta == 2) + { + for (i = 0; i < N / 8; ++i) + { + Coeffs[8 * i + 0] = (((a[off + 3 * i + 0] & 0xFF) >> 0) & 7); + Coeffs[8 * i + 1] = ((((a[off + 3 * i + 0] & 0xFF) >> 3)) & 7); + Coeffs[8 * i + 2] = (((a[off + 3 * i + 0] & 0xFF) >> 6) | ((a[off + 3 * i + 1] & 0xFF) << 2) & 7); + Coeffs[8 * i + 3] = ((((a[off + 3 * i + 1] & 0xFF) >> 1)) & 7); + Coeffs[8 * i + 4] = ((((a[off + 3 * i + 1] & 0xFF) >> 4)) & 7); + Coeffs[8 * i + 5] = (((a[off + 3 * i + 1] & 0xFF) >> 7) | ((a[off + 3 * i + 2] & 0xFF) << 1) & 7); + Coeffs[8 * i + 6] = ((((a[off + 3 * i + 2] & 0xFF) >> 2)) & 7); + Coeffs[8 * i + 7] = ((((a[off + 3 * i + 2] & 0xFF) >> 5)) & 7); + + Coeffs[8 * i + 0] = eta - Coeffs[8 * i + 0]; + Coeffs[8 * i + 1] = eta - Coeffs[8 * i + 1]; + Coeffs[8 * i + 2] = eta - Coeffs[8 * i + 2]; + Coeffs[8 * i + 3] = eta - Coeffs[8 * i + 3]; + Coeffs[8 * i + 4] = eta - Coeffs[8 * i + 4]; + Coeffs[8 * i + 5] = eta - Coeffs[8 * i + 5]; + Coeffs[8 * i + 6] = eta - Coeffs[8 * i + 6]; + Coeffs[8 * i + 7] = eta - Coeffs[8 * i + 7]; + } + } + else if (eta == 4) + { + for (i = 0; i < N / 2; ++i) + { + Coeffs[2 * i + 0] = ((a[off + i] & 0xFF) & 0x0F); + Coeffs[2 * i + 1] = ((a[off + i] & 0xFF) >> 4); + Coeffs[2 * i + 0] = eta - Coeffs[2 * i + 0]; + Coeffs[2 * i + 1] = eta - Coeffs[2 * i + 1]; + } + } + } + + public void UniformGamma1(byte[] seed, ushort nonce) + { + byte[] buf = new byte[Engine.PolyUniformGamma1NBytes * Symmetric.Shake256Rate]; + ShakeDigest ShakeDigest256 = new ShakeDigest(256); + Symmetric.ShakeStreamInit(ShakeDigest256, seed, nonce); + ShakeDigest256.DoFinal(buf, 0, buf.Length); + UnpackZ(buf, 0); + + } + + public void PackZ(byte[] r, int offset) + { + int i; + uint[] t = new uint[4]; + if (Engine.Gamma1 == (1 << 17)) + { + for (i = 0; i < N / 4; ++i) + { + t[0] = (uint)(Engine.Gamma1 - Coeffs[4 * i + 0]); + t[1] = (uint)(Engine.Gamma1 - Coeffs[4 * i + 1]); + t[2] = (uint)(Engine.Gamma1 - Coeffs[4 * i + 2]); + t[3] = (uint)(Engine.Gamma1 - Coeffs[4 * i + 3]); + + r[offset + 9 * i + 0] = (byte)t[0]; + r[offset + 9 * i + 1] = (byte)(t[0] >> 8); + r[offset + 9 * i + 2] = (byte)((byte)(t[0] >> 16) | (t[1] << 2)); + r[offset + 9 * i + 3] = (byte)(t[1] >> 6); + r[offset + 9 * i + 4] = (byte)((byte)(t[1] >> 14) | (t[2] << 4)); + r[offset + 9 * i + 5] = (byte)(t[2] >> 4); + r[offset + 9 * i + 6] = (byte)((byte)(t[2] >> 12) | (t[3] << 6)); + r[offset + 9 * i + 7] = (byte)(t[3] >> 2); + r[offset + 9 * i + 8] = (byte)(t[3] >> 10); + } + } + else if (Engine.Gamma1 == (1 << 19)) + { + for (i = 0; i < N / 2; ++i) + { + t[0] = (uint)(Engine.Gamma1 - Coeffs[2 * i + 0]); + t[1] = (uint)(Engine.Gamma1 - Coeffs[2 * i + 1]); + + r[offset + 5 * i + 0] = (byte)t[0]; + r[offset + 5 * i + 1] = (byte)(t[0] >> 8); + r[offset + 5 * i + 2] = (byte)((byte)(t[0] >> 16) | (t[1] << 4)); + r[offset + 5 * i + 3] = (byte)(t[1] >> 4); + r[offset + 5 * i + 4] = (byte)(t[1] >> 12); + + } + } + else + { + throw new ArgumentException("Wrong Dilithium Gamma1!"); + } + } + + public void UnpackZ(byte[] a, int off) + { + int i; + if (Engine.Gamma1 == (1 << 17)) + { + for (i = 0; i < N / 4; ++i) + { + Coeffs[4 * i + 0] = + ( + (((a[off + 9 * i + 0] & 0xFF)) | + ((a[off + 9 * i + 1] & 0xFF) << 8)) | + ((a[off + 9 * i + 2] & 0xFF) << 16) + ) & 0x3FFFF; + Coeffs[4 * i + 1] = + ( + (((a[off + 9 * i + 2] & 0xFF) >> 2) | + ((a[off + 9 * i + 3] & 0xFF) << 6)) | + ((a[off + 9 * i + 4] & 0xFF) << 14) + ) & 0x3FFFF; + Coeffs[4 * i + 2] = + ( + (((a[off + 9 * i + 4] & 0xFF) >> 4) | + ((a[off + 9 * i + 5] & 0xFF) << 4)) | + ((a[off + 9 * i + 6] & 0xFF) << 12) + ) & 0x3FFFF; + Coeffs[4 * i + 3] = + ( + (((a[off + 9 * i + 6] & 0xFF) >> 6) | + ((a[off + 9 * i + 7] & 0xFF) << 2)) | + ((a[off + 9 * i + 8] & 0xFF) << 10) + ) & 0x3FFFF; + + + Coeffs[4 * i + 0] = Engine.Gamma1 - Coeffs[4 * i + 0]; + Coeffs[4 * i + 1] = Engine.Gamma1 - Coeffs[4 * i + 1]; + Coeffs[4 * i + 2] = Engine.Gamma1 - Coeffs[4 * i + 2]; + Coeffs[4 * i + 3] = Engine.Gamma1 - Coeffs[4 * i + 3]; + } + } + else if (Engine.Gamma1 == (1 << 19)) + { + for (i = 0; i < N / 2; ++i) + { + Coeffs[2 * i + 0] = + ( + (((a[off + 5 * i + 0] & 0xFF)) | + ((a[off + 5 * i + 1] & 0xFF) << 8)) | + ((a[off + 5 * i + 2] & 0xFF) << 16) + ) & 0xFFFFF; + Coeffs[2 * i + 1] = + ( + (((a[off + 5 * i + 2] & 0xFF) >> 4) | + ((a[off + 5 * i + 3] & 0xFF) << 4)) | + ((a[off + 5 * i + 4] & 0xFF) << 12) + ) & 0xFFFFF; + + Coeffs[2 * i + 0] = Engine.Gamma1 - Coeffs[2 * i + 0]; + Coeffs[2 * i + 1] = Engine.Gamma1 - Coeffs[2 * i + 1]; + } + } + else + { + throw new ArgumentException("Wrong Dilithiumn Gamma1!"); + } + } + + public void Decompose(Poly a) + { + int i; + for (i = 0; i < N; ++i) + { + int[] decomp = Rounding.Decompose(Coeffs[i], Engine.Gamma2); + a.Coeffs[i] = decomp[0]; + Coeffs[i] = decomp[1]; + } + } + + public void PackW1(byte[] r, int off) + { + int i; + + if (Engine.Gamma2 == (DilithiumEngine.Q - 1) / 88) + { + for (i = 0; i < N / 4; ++i) + { + r[off + 3 * i + 0] = (byte)(((byte)Coeffs[4 * i + 0]) | (Coeffs[4 * i + 1] << 6)); + r[off + 3 * i + 1] = (byte)((byte)(Coeffs[4 * i + 1] >> 2) | (Coeffs[4 * i + 2] << 4)); + r[off + 3 * i + 2] = (byte)((byte)(Coeffs[4 * i + 2] >> 4) | (Coeffs[4 * i + 3] << 2)); + } + } + else if (Engine.Gamma2 == (DilithiumEngine.Q - 1) / 32) + { + for (i = 0; i < N / 2; ++i) + { + r[off + i] = (byte)(Coeffs[2 * i + 0] | (Coeffs[2 * i + 1] << 4)); + } + } + } + + public void Challenge(byte[] seed) + { + int i, b, pos; + ulong signs; + byte[] buf = new byte[Symmetric.Shake256Rate]; + + ShakeDigest ShakeDigest256 = new ShakeDigest(256); + ShakeDigest256.BlockUpdate(seed, 0, DilithiumEngine.SeedBytes); + ShakeDigest256.DoOutput(buf, 0, Symmetric.Shake256Rate); + + signs = 0; + for (i = 0; i < 8; ++i) + { + signs |= (ulong)(buf[i] & 0xFF) << 8 * i; + } + + pos = 8; + + for (i = 0; i < N; ++i) + { + Coeffs[i] = 0; + } + + for (i = N - Engine.Tau; i < N; ++i) + { + do + { + if (pos >= Symmetric.Shake256Rate) + { + ShakeDigest256.DoOutput(buf, 0, Symmetric.Shake256Rate); + pos = 0; + } + b = (buf[pos++] & 0xFF); + } + while (b > i); + + Coeffs[i] = Coeffs[b]; + Coeffs[b] = (int)(1 - 2 * (signs & 1)); + signs = signs >> 1; + } + } + + public bool CheckNorm(int B) + { + int i, t; + + if (B > (DilithiumEngine.Q - 1) / 8) + { + return true; + } + + for (i = 0; i < N; ++i) + { + t = Coeffs[i] >> 31; + t = Coeffs[i] - (t & 2 * Coeffs[i]); + + if (t >= B) + { + return true; + } + } + return false; + } + public int PolyMakeHint(Poly a0, Poly a1) + { + int i, s = 0; + + for (i = 0; i < N; ++i) + { + Coeffs[i] = Rounding.MakeHint(a0.Coeffs[i], a1.Coeffs[i], Engine); + s += Coeffs[i]; + } + return s; + } + + public void PolyUseHint(Poly a, Poly h) + { + for (int i = 0; i < DilithiumEngine.N; ++i) + { + Coeffs[i] = Rounding.UseHint(a.Coeffs[i], h.Coeffs[i], Engine.Gamma2); + } + } + + public void ShiftLeft() + { + for (int i = 0; i < N; ++i) + { + Coeffs[i] <<= DilithiumEngine.D; + } + } + + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs new file mode 100644 index 000000000..506200936 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecK.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class PolyVecK + { + public Poly[] Vec; + private DilithiumEngine Engine; + private int Mode; + private int PolyVecBytes; + private int K; + private int L; + + public PolyVecK(DilithiumEngine Engine) + { + this.Engine = Engine; + Mode = Engine.Mode; + K = Engine.K; + L = Engine.L; + Vec = new Poly[K]; + + for (int i = 0; i < K; i++) + { + Vec[i] = new Poly(Engine); + } + } + + public void UniformEta(byte[] seed, ushort nonce) + { + int i; + ushort n = nonce; + for (i = 0; i < K; i++) + { + Vec[i].UniformEta(seed, n++); + } + } + + public void Reduce() + { + for (int i = 0; i < K; i++) + { + Vec[i].ReducePoly(); + } + } + + public void Ntt() + { + for (int i= 0; i < K; ++i) + { + Vec[i].PolyNtt(); + } + } + + public void InverseNttToMont() + { + for (int i = 0; i < K; ++i) + { + Vec[i].InverseNttToMont(); + } + } + + public void AddPolyVecK(PolyVecK b) + { + for (int i = 0; i < K; ++i) + { + Vec[i].AddPoly(b.Vec[i]); + } + } + + public void Subtract(PolyVecK v) + { + for (int i = 0; i < K; ++i) + { + Vec[i].Subtract(v.Vec[i]); + } + } + + public void ConditionalAddQ() + { + for (int i = 0; i < K; ++i) + { + Vec[i].ConditionalAddQ(); + } + } + + public void Power2Round(PolyVecK v) + { + for (int i = 0; i < K; ++i) + { + Vec[i].Power2Round(v.Vec[i]); + } + } + + public void Decompose(PolyVecK v) + { + for (int i = 0; i < K; ++i) + { + Vec[i].Decompose(v.Vec[i]); + } + } + + public void PackW1(byte[] r) + { + int i; + for (i = 0; i < K; i++) + { + Vec[i].PackW1(r, i * Engine.PolyW1PackedBytes); + } + } + + public void PointwisePolyMontgomery(Poly a, PolyVecK v) + { + for (int i = 0; i < K; ++i) + { + Vec[i].PointwiseMontgomery(a, v.Vec[i]); + } + } + + public bool CheckNorm(int bound) + { + for (int i = 0; i < K; ++i) + { + if (Vec[i].CheckNorm(bound)) + { + return true; + } + } + return false; + } + + public int MakeHint(PolyVecK v0, PolyVecK v1) + { + int i, s = 0; + for (i = 0; i < K; ++i) + { + s += Vec[i].PolyMakeHint(v0.Vec[i], v1.Vec[i]); + } + + return s; + } + + public void UseHint(PolyVecK a, PolyVecK h) + { + for (int i = 0; i < K; ++i) + { + Vec[i].PolyUseHint(a.Vec[i], h.Vec[i]); + } + } + + public void ShiftLeft() + { + for (int i = 0; i < K; ++i) + { + Vec[i].ShiftLeft(); + } + } + + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs new file mode 100644 index 000000000..75309b374 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecL.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class PolyVecL + { + public Poly[] Vec; + private DilithiumEngine Engine; + private int Mode; + private int PolyVecBytes; + private int L; + private int K; + + public PolyVecL(DilithiumEngine Engine) + { + this.Engine = Engine; + Mode = Engine.Mode; + L = Engine.L; + K = Engine.K; + Vec = new Poly[L]; + for (int i = 0; i < L; i++) + { + Vec[i] = new Poly(Engine); + } + } + + public void UniformEta(byte[] seed, ushort nonce) + { + int i; + for (i = 0; i < L; i++) + { + Vec[i].UniformEta(seed, nonce++); + } + } + + public void CopyPolyVecL(PolyVecL OutPoly) + { + for (int i = 0; i < L; i++) + { + for (int j = 0; j < DilithiumEngine.N; j++) + { + OutPoly.Vec[i].Coeffs[j] = Vec[i].Coeffs[j]; + } + } + } + + public void InverseNttToMont() + { + for (int i = 0; i < L; i++) + { + Vec[i].InverseNttToMont(); + } + } + + public void Ntt() + { + for (int i = 0; i < L; i++) + { + Vec[i].PolyNtt(); + } + } + + public void UniformGamma1(byte[] seed, ushort nonce) + { + for (int i = 0; i < L; i++) + { + Vec[i].UniformGamma1(seed, (ushort)(L * nonce + i)); + } + } + + public void PointwisePolyMontgomery(Poly a, PolyVecL v) + { + for (int i = 0; i < L; ++i) + { + Vec[i].PointwiseMontgomery(a, v.Vec[i]); + } + } + + public void AddPolyVecL(PolyVecL b) + { + for (int i = 0; i < L; i++) + { + Vec[i].AddPoly(b.Vec[i]); + } + } + + public void Reduce() + { + for (int i = 0; i < L; i++) + { + Vec[i].ReducePoly(); + } + } + + public bool CheckNorm(int bound) + { + for (int i = 0; i < L; ++i) + { + if (Vec[i].CheckNorm(bound)) + { + return true; + } + } + return false; + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/PolyVecMatrix.cs b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecMatrix.cs new file mode 100644 index 000000000..4f3868239 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/PolyVecMatrix.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class PolyVecMatrix + { + private int K, L; + public PolyVecL[] Matrix; + + public PolyVecMatrix(DilithiumEngine Engine) + { + K = Engine.K; + L = Engine.L; + Matrix = new PolyVecL[K]; + + for (int i = 0; i < K; i++) + { + Matrix[i] = new PolyVecL(Engine); + } + } + + public void ExpandMatrix(byte[] rho) + { + int i, j; + for (i = 0; i < K; ++i) + { + for (j = 0; j < L; ++j) + { + Matrix[i].Vec[j].UniformBlocks(rho, (ushort)((ushort) (i << 8) + j)); + } + } + } + + public void PointwiseMontgomery(PolyVecK t, PolyVecL v) + { + int i; + for (i = 0; i < K; ++i) + { + t.Vec[i].PointwiseAccountMontgomery(Matrix[i], v); + } + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Reduce.cs b/crypto/src/pqc/crypto/crystals/dilithium/Reduce.cs new file mode 100644 index 000000000..4efcdb49e --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Reduce.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class Reduce + { + public static int MontgomeryReduce(long a) + { + int t; + t = (int)(a * DilithiumEngine.QInv); + t = (int)((a - (long)((long)t * (long)DilithiumEngine.Q)) >> 32); + //Console.Write("{0}, ", t); + return t; + } + + public static int Reduce32(int a) + { + int t; + t = (a + (1 << 22)) >> 23; + t = a - t * DilithiumEngine.Q; + return t; + } + + public static int ConditionalAddQ(int a) + { + a += (a >> 31) & DilithiumEngine.Q; + return a; + } + + + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Rounding.cs b/crypto/src/pqc/crypto/crystals/dilithium/Rounding.cs new file mode 100644 index 000000000..625b60cf5 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Rounding.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + internal class Rounding + { + public static int[] Power2Round(int a) + { + int[] r = new int[2]; + + r[0] = (a + (1 << (DilithiumEngine.D - 1)) - 1) >> DilithiumEngine.D; + r[1] = a - (r[0] << DilithiumEngine.D); + return r; + } + + public static int[] Decompose(int a, int gamma2) + { + int a0, a1; + a1 = (a + 127) >> 7; + if (gamma2 == (DilithiumEngine.Q - 1) / 32) + { + a1 = (a1 * 1025 + (1 << 21)) >> 22; + a1 &= 15; + } + else if (gamma2 == (DilithiumEngine.Q - 1) / 88) + { + a1 = (a1 * 11275 + (1 << 23)) >> 24; + a1 ^= ((43 - a1) >> 31) & a1; + } + else + { + throw new ArgumentException("Wrong Gamma2!"); + } + + a0 = a - a1 * 2 * gamma2; + a0 -= (((DilithiumEngine.Q - 1) / 2 - a0) >> 31) & DilithiumEngine.Q; + return new int[] { a0, a1 }; + } + + public static int MakeHint(int a0, int a1, DilithiumEngine engine) + { + int g2 = engine.Gamma2, q = DilithiumEngine.Q; + if (a0 <= g2 || a0 > q - g2 || (a0 == q - g2 && a1 == 0)) + { + return 0; + } + return 1; + } + + public static int UseHint(int a, int hint, int gamma2) + { + int a0, a1; + + int[] intArray = Decompose(a, gamma2); + a0 = intArray[0]; + a1 = intArray[1]; + + if (hint == 0) + { + return a1; + } + + if (gamma2 == (DilithiumEngine.Q - 1) / 32) + { + if (a0 > 0) + { + return (a1 + 1) & 15; + } + else + { + return (a1 - 1) & 15; + } + } + else if (gamma2 == (DilithiumEngine.Q - 1) / 88) + { + if (a0 > 0) + { + return (a1 == 43) ? 0 : a1 + 1; + } + else + { + return (a1 == 0) ? 43 : a1 - 1; + } + } + else + { + throw new ArgumentException("Wrong Gamma2!"); + } + } + } +} diff --git a/crypto/src/pqc/crypto/crystals/dilithium/Symmetric.cs b/crypto/src/pqc/crypto/crystals/dilithium/Symmetric.cs new file mode 100644 index 000000000..46d59a667 --- /dev/null +++ b/crypto/src/pqc/crypto/crystals/dilithium/Symmetric.cs @@ -0,0 +1,26 @@ +using Org.BouncyCastle.Crypto.Digests; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium +{ + static class Symmetric + { + public const int Shake128Rate = 168; + public const int Shake256Rate = 136; + public const int Sha3Rate256 = 136; + public const int Sha3Rate512 = 72; + + public static void ShakeStreamInit(ShakeDigest Digest, byte[] seed, ushort nonce) + { + byte[] temp = new byte[2]; + temp[0] = (byte)nonce; + temp[1] = (byte)(nonce >> 8); + Digest.BlockUpdate(seed, 0, seed.Length); + Digest.BlockUpdate(temp, 0, temp.Length); + } + } +} |