From 060b2b6c2fa5c41eb774db896abb2f6d282a48e4 Mon Sep 17 00:00:00 2001 From: David Hook Date: Sun, 24 Jul 2022 19:46:56 +1000 Subject: moved ntrup to ntruprime, reduced accessors on keys, marked key fields internal --- crypto/src/pqc/crypto/ntrup/NtruPEngine.cs | 1284 -------------------- crypto/src/pqc/crypto/ntrup/NtruPKemExtractor.cs | 35 - crypto/src/pqc/crypto/ntrup/NtruPKemGenerator.cs | 77 -- .../crypto/ntrup/NtruPKeyGenerationParameters.cs | 18 - .../src/pqc/crypto/ntrup/NtruPKeyPairGenerator.cs | 69 -- crypto/src/pqc/crypto/ntrup/NtruPKeyParameters.cs | 17 - crypto/src/pqc/crypto/ntrup/NtruPParameters.cs | 72 -- .../pqc/crypto/ntrup/NtruPPrivateKeyParameters.cs | 21 - .../pqc/crypto/ntrup/NtruPPublicKeyParameters.cs | 21 - crypto/src/pqc/crypto/ntruprime/NtruPrimeEngine.cs | 1284 ++++++++++++++++++++ .../pqc/crypto/ntruprime/NtruPrimeKemExtractor.cs | 35 + .../pqc/crypto/ntruprime/NtruPrimeKemGenerator.cs | 77 ++ .../ntruprime/NtruPrimeKeyGenerationParameters.cs | 18 + .../crypto/ntruprime/NtruPrimeKeyPairGenerator.cs | 69 ++ .../pqc/crypto/ntruprime/NtruPrimeKeyParameters.cs | 17 + .../pqc/crypto/ntruprime/NtruPrimeParameters.cs | 72 ++ .../ntruprime/NtruPrimePrivateKeyParameters.cs | 20 + .../ntruprime/NtruPrimePublicKeyParameters.cs | 19 + 18 files changed, 1611 insertions(+), 1614 deletions(-) delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPEngine.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPKemExtractor.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPKemGenerator.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPKeyGenerationParameters.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPKeyPairGenerator.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPKeyParameters.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPParameters.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPPrivateKeyParameters.cs delete mode 100644 crypto/src/pqc/crypto/ntrup/NtruPPublicKeyParameters.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeEngine.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeKemExtractor.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeKemGenerator.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyGenerationParameters.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyPairGenerator.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyParameters.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimeParameters.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimePrivateKeyParameters.cs create mode 100644 crypto/src/pqc/crypto/ntruprime/NtruPrimePublicKeyParameters.cs (limited to 'crypto/src') diff --git a/crypto/src/pqc/crypto/ntrup/NtruPEngine.cs b/crypto/src/pqc/crypto/ntrup/NtruPEngine.cs deleted file mode 100644 index f78abbf7c..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPEngine.cs +++ /dev/null @@ -1,1284 +0,0 @@ -using System; -using System.Collections.Generic; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - internal class NtruPEngine - { - // Key Sizes - private readonly int _skBytes; // [KEM] Size of secret key - private readonly int _pkBytes; // [KEM] Size of public key - private readonly int _ctBytes; // [KEM] Size of ciphertext - - private readonly int _secretKeyBytes; // C Reference: SecretKey_bytes - private readonly int _publicKeyBytes; // C Reference: PublicKey_bytes - private readonly int _ciphertextsBytes; // C Reference: Ciphertext_bytes - - private readonly int _confirmBytes; - private readonly int _inputsBytes; // For encoding _I-bit inputs - private readonly int _topBytes; - private readonly int _seedBytes; - private readonly int _smallBytes; - private readonly int _hashBytes; - - private const int SessionKeyBytes = 32; - - // Parameters for NTRU - private readonly int _p; - private readonly int _q; - - private readonly int _roundedBytes; // Defined in params.h - - // private readonly int _rqBytes; // Defined in params.h - Public key bytes for streamlined nTRU - private readonly bool _lpr; - private readonly int _w; - private readonly int _tau0; - private readonly int _tau1; - private readonly int _tau2; - private readonly int _tau3; - - private readonly int _I; - - private readonly int _q12; - - public int PrivateKeySize => _skBytes; - public int PublicKeySize => _pkBytes; - public int CipherTextSize => _ctBytes; - public int SessionKeySize => SessionKeyBytes; - - public NtruPEngine(int p, int q, bool lpr, int w, int tau0, - int tau1, int tau2, int tau3, int skBytes, int pkBytes, int ctBytes, int roundedBytes, int rqBytes) - { - this._p = p; - this._q = q; - this._w = w; - this._tau0 = tau0; - this._tau1 = tau1; - this._tau2 = tau2; - this._tau3 = tau3; - - // KEM parameters - this._roundedBytes = roundedBytes; - this._skBytes = skBytes; - this._pkBytes = pkBytes; - this._ctBytes = ctBytes; - - this._lpr = lpr; - - this._confirmBytes = 32; - - _smallBytes = ((p + 3) / 4); - _q12 = ((q - 1) / 2); - _hashBytes = 32; - - if (lpr) - { - _seedBytes = 32; - _I = 256; - _inputsBytes = _I / 8; - _topBytes = _I / 2; - _ciphertextsBytes = roundedBytes + _topBytes; - _secretKeyBytes = _smallBytes; - _publicKeyBytes = _seedBytes + roundedBytes; - } - else - { - _inputsBytes = _smallBytes; - _ciphertextsBytes = _roundedBytes; - _secretKeyBytes = (2*_smallBytes); - _publicKeyBytes = rqBytes; - } - } - - - public void kem_keypair(byte[] pk, byte[] sk, SecureRandom random) //KEM_KeyGen - { - - KeyGen(random, ref pk, ref sk); - Array.Copy(pk, 0, sk, _secretKeyBytes, _publicKeyBytes); - byte[] rand = new byte[_inputsBytes]; - random.NextBytes(rand); - Array.Copy(rand, 0, sk, _secretKeyBytes+_publicKeyBytes, _inputsBytes); - HashPrefix(ref sk, 4, ref pk, _publicKeyBytes); - } - - - public void kem_enc(byte[] ct, byte[] ss, byte[] pk, SecureRandom random) - { - sbyte[] inputs; - - if (_lpr) - { - inputs = new sbyte[_I]; - } - else - { - inputs = new sbyte[_p]; - } - - byte[] r_enc = new byte[_inputsBytes]; - byte[] cache = new byte[_hashBytes]; - - HashPrefix(ref cache, 4, ref pk, _publicKeyBytes); - - if (_lpr) - { - InputsRandom(ref inputs, random); - } - else - { - ShortRandom(ref inputs, random); - } - - Hide(ref ct, r_enc, inputs, pk, cache); - HashSession(ref ss, 1, r_enc, ct); - } - - public void kem_dec(byte[] ss, byte[] ct, byte[] sk) - { - byte[] pk = new byte[sk.Length - _secretKeyBytes]; - - // Shift sk by _secretKeyBytes and copy to pk - - Array.Copy(sk, _secretKeyBytes, pk, 0, pk.Length); - - byte[] rho = new byte[pk.Length - _publicKeyBytes]; - - // Shift pk by _publicKeyBytes and fill rho - Array.Copy(pk, _publicKeyBytes, rho, 0, rho.Length); - - byte[] cache = new byte[rho.Length - _inputsBytes]; - - // Shift rho by _inputsBytes and fill cache - - Array.Copy(rho, _inputsBytes, cache, 0, cache.Length); - - sbyte[] r; - - if (_lpr) - { - r = new sbyte[_I]; - } - else - { - r = new sbyte[_p]; - } - - byte[] r_enc = new byte[_inputsBytes]; - byte[] cnew = new byte[_ciphertextsBytes + _confirmBytes]; - - byte[] ct_dec = Arrays.Clone(ct); // ct somehow gets modified in Decrypt - - Decrypt(ref r, ct_dec, sk); - - Hide(ref cnew, r_enc, r, pk, cache); - - int mask = ctDiffMask(ct, cnew); - - for (int i = 0; i < _inputsBytes; ++i) - { - r_enc[i] ^= (byte)(mask & (r_enc[i] ^ rho[i])); - } - - HashSession(ref ss, 1 + mask, r_enc, ct); - } - - // --------------------------------------------------------------------- - - private void KeyGen(SecureRandom random, ref byte[] pk, ref byte[] sk) // ZKeyGen - { - if (_lpr) - { - short[] A = new short[_p]; - sbyte[] a = new sbyte[_p]; - - // BEGIN: XKeyGen - byte[] seedOut = new byte[_seedBytes]; - random.NextBytes(seedOut); - Array.Copy(seedOut, 0, pk, 0, _seedBytes); - short[] genOut = new short[_p]; - Generator(ref genOut, seedOut); - - // BEGIN: XKeyGen > KeyGen - ShortRandom(ref a, random); - short[] aG = new short[_p]; - RqMult(ref aG, genOut, ref a); - Round(ref A, aG); - // END XKeyGen > KeyGen - // END: XKeyGen - - byte[] roundedEncOut = new byte[pk.Length]; - RoundedEncode(ref roundedEncOut, A); - - Array.Copy(roundedEncOut, 0, pk, _seedBytes, pk.Length - _seedBytes); - - ByteEncode(ref sk, a); - } - else - { - // KeyGen - short[] h = new short[_p]; - sbyte[] f = new sbyte[_p]; - - sbyte[] ginv = new sbyte[_p]; - sbyte[] g = new sbyte[_p]; - short[] finv = new short[_p]; - - while (true) - { - ByteRandom(ref g, random); - - if (R3Recip(ref ginv, g) == 0) - { - break; - } - - } - - ShortRandom(ref f, random); - RqRecip3(ref finv, f); - RqMult(ref h, finv, g); - // END KeyGen - - RqEncode(ref pk, h); - - ByteEncode(ref sk, f); - - byte[] smallEncOut = new byte[sk.Length]; - ByteEncode(ref smallEncOut, ginv); - - Array.Copy(smallEncOut, 0, sk, _smallBytes, sk.Length - _smallBytes); - - } - - } - - //----------------------- Streamlined -------------------------------- - - private void ByteRandom(ref sbyte[] output, SecureRandom random) - { - for (int i = 0;i < _p;++i) - { - byte[] smallRandom = new byte[4]; - random.NextBytes(smallRandom); - output[i] = (sbyte)((((BitConverter.ToUInt32(smallRandom, 0) & 0x3fffffff) * 3) >> 30)-1); - }; - } - - private int R3Recip(ref sbyte[] output, sbyte[] input) - { - sbyte[] f = new sbyte[_p+1]; - sbyte[] g = new sbyte[_p+1]; - sbyte[] v = new sbyte[_p+1]; - sbyte[] r = new sbyte[_p+1]; - - for (int i = 0; i < _p+1; ++i) - { - v[i] = 0; - r[i] = 0; - } - - r[0] = 1; - - for (int i = 0; i < _p; ++i) - { - f[i] = 0; - } - - f[0] = 1; - f[_p - 1] = f[_p] = -1; - - for (int i = 0; i < _p; ++i) - { - g[_p-1-i] = input[i]; - } - - g[_p] = 0; - - int delta = 1; - - int sign, swap, t; - - for (int i = 0; i < 2*_p-1; ++i) - { - for (int j = _p; j > 0; --j) - { - v[j] = v[j - 1]; - } - - v[0] = 0; - - sign = -g[0] * f[0]; - - - swap = NegativeMask((short)-delta) & ((g[0] != 0) ? -1 : 0); - - - delta ^= swap & (delta ^ -delta); - delta +=1; - - for (int j = 0; j < _p + 1; ++j) - { - t = swap&(f[j]^g[j]); - f[j] ^= (sbyte)t; - g[j] ^= (sbyte)t; - t = swap&(v[j]^r[j]); - v[j] ^= (sbyte)t; - r[j] ^= (sbyte)t; - - } - for (int j = 0; j < _p+1; ++j) - { - g[j] =(sbyte)(mod(((g[j] + sign * f[j]) + 1), 3) - 1); - } - - for (int j = 0; j < _p+1; ++j) - { - r[j] =(sbyte)(mod(((r[j] + sign * v[j]) + 1), 3) - 1); - } - - for (int j = 0; j < _p; ++j) - { - g[j] = g[j + 1]; - } - g[_p] = 0; - } - - sign = f[0]; - - for (int i = 0; i < _p; ++i) - { - output[i] = (sbyte)(sign * v[_p - 1 - i]); - } - - return (delta != 0) ? -1 : 0; - - } - - private int RqRecip3(ref short[] output, sbyte[] input) - { - short[] f = new short[_p + 1]; - short[] g = new short[_p + 1]; - short[] v = new short[_p + 1]; - short[] r = new short[_p + 1]; - int swap, t; - short scale; - int f0, g0; - - for (int i = 0; i < _p + 1; ++i) - { - v[i] = 0; - r[i] = 0; - } - - r[0] = FqRecip(3); - - for (int i = 0; i < _p; ++i) - { - f[i] = 0; - } - - f[0] = 1; - f[_p - 1] = f[_p] = -1; - - for (int i = 0; i < _p; ++i) - { - g[_p - 1 - i] = input[i]; - } - - g[_p] = 0; - - int delta = 1; - - for (int i = 0; i < 2 * _p - 1; ++i) - { - - for (int j = _p; j > 0; --j) - { - v[j] = v[j - 1]; - } - - v[0] = 0; - - - swap = NegativeMask((short)-delta) & ((g[0] != 0) ? -1 : 0); - - delta ^= swap & (delta ^ -delta); - delta += 1; - - for (int j = 0; j < _p + 1; ++j) - { - t = swap & (f[j] ^ g[j]); - f[j] ^= (short)t; - g[j] ^= (short)t; - t = swap & (v[j] ^ r[j]); - v[j] ^= (short)t; - r[j] ^= (short)t; - } - - f0 = f[0]; - g0 = g[0]; - - for (int j = 0; j < _p + 1; ++j) - { - g[j] = ArithmeticMod_q(f0 * g[j] - g0 * f[j]); - } - - for (int j = 0; j < _p + 1; ++j) - { - r[j] = ArithmeticMod_q(f0 * r[j] - g0 * v[j]); - } - - for (int j = 0; j < _p; ++j) - { - g[j] = g[j + 1]; - } - - g[_p] = 0; - } - - scale = FqRecip(f[0]); - - for (int i = 0; i < _p; ++i) - { - output[i] = ArithmeticMod_q(scale * v[_p - 1 - i]); - } - - return (delta != 0) ? -1 : 0; - } - - private short FqRecip(short a1) - { - int i = 1; - short ai = a1; - - while (i < _q - 2) - { - ai = ArithmeticMod_q(a1 * ai); - i++; - } - - return ai; - } - - private void RqMult(ref short[] output, short[] f, sbyte[] g) - { - // h = f * g in the ring Rq - - short[] fg = new short[_p + _p + 1]; // Can directly modify h - short result; - - for (int i = 0; i < _p; ++i) - { - result = 0; - for (int j = 0; j <= i; ++j) - { - result = ArithmeticMod_q(result + f[j] * g[i - j]); - } - fg[i] = result; - } - - for (int i = _p;i < _p+_p-1;++i) - { - result = 0; - for (int j = i-_p+1;j < _p;++j) - { - result = ArithmeticMod_q(result + f[j] * g[i - j]); - } - fg[i] = result; - } - - for (int i = _p+_p-2; i >= _p; --i) - { - fg[i - _p] = ArithmeticMod_q(fg[i - _p] + fg[i]); - fg[i-_p+1] = ArithmeticMod_q(fg[i-_p+1] + fg[i]); - } - - for (int i = 0; i < _p; ++i) - { - output[i] = fg[i]; - } - } - - private void RqEncode(ref byte[] output, short[] r) - { - ushort[] R = new ushort[_p]; - ushort[] M = new ushort[_p]; - - for (int i = 0; i < _p; ++i) - { - R[i] = (ushort)(r[i] + _q12); - M[i] = (ushort)_q; - } - - List sList = new List(); - - Encode(ref sList, R, M, _p); - - Array.Copy(sList.ToArray(), 0, output, 0, sList.Count); - } - - private void RqDecode(ref short[] output, byte[] s) - { - ushort[] R = new ushort[_p]; - ushort[] M = new ushort[_p]; - - for (int i = 0; i < _p; ++i) - { - M[i] = (ushort)_q; - } - - List rList = new List(s); - List mList = new List(M); - - List decoded = Decode(rList, mList); - - for (int i = 0; i < _p; ++i) - { - output[i] = (short)(decoded[i] - _q12); - } - } - - private void RqMult3(ref short[] output, short[] f) - { - for (int i = 0; i < _p; ++i) - { - output[i] = ArithmeticMod_q(f[i] * 3); - } - } - - private void R3FromRq(ref sbyte[] output, short[] r) - { - for (int i = 0; i < _p; ++i) - { - output[i] = (sbyte)ArithmeticMod_3(r[i]); - } - } - - private void R3Mult(ref sbyte[] output, sbyte[] f, sbyte[] g) - { - sbyte[] fg = new sbyte[_p + _p + 1]; - sbyte result; - - for (int i = 0; i < _p; ++i) - { - result = 0; - for (int j = 0; j <= i; ++j) - { - result = (sbyte)(ArithmeticMod_3(result + f[j] * g[i - j])); - } - fg[i] = result; - } - - for (int i = _p;i < _p+_p-1;++i) - { - result = 0; - - for (int j = i-_p+1;j < _p;++j) - { - result = (sbyte)(ArithmeticMod_3(result+f[j]*g[i-j])); - } - fg[i] = result; - } - - for (int i = _p+_p-2;i >= _p;--i) - { - fg[i - _p] = (sbyte)(ArithmeticMod_3(fg[i - _p] + fg[i])); - fg[i - _p + 1] = (sbyte)(ArithmeticMod_3(fg[i - _p + 1] + fg[i])); - } - - for (int i = 0; i < _p; ++i) - { - output[i] = fg[i]; - } - } - - private int WeightMask(sbyte[] r) - { - int weight = 0; - - for (int i = 0; i < _p; ++i) - { - weight += r[i]&1; - } - - return NonZeroMask((short)(weight - _w)); - - } - - private int NonZeroMask(short x) - { - /* return -1 if x!=0; else return 0 */ - return (x == 0) ? 0 : -1; - } - - //--------------------------------------------------------------------- - - private List Decode(List S, List M) - { - int limit = 16384; - - if (M.Count == 0) - { - return new List(); - } - - if (M.Count == 1) - { - if (M[0] == 1) - { - return new List() { 0 }; - } - if (M[0] <= 256) - { - return new List() { (ushort)mod(S[0], M[0]) }; - } else - { - return new List() { (ushort)mod(S[0] + (((uint)S[1]) << 8), M[0]) }; - } - } - - int k = 0; - List bottomr = new List(); - List bottomt = new List(); - List M2 = new List(); - - for (int i = 0; i < M.Count - 1; i += 2) - { - uint m = (uint)(M[i] * M[i + 1]); - ushort r = 0; - uint t = 1; - - while (m >= limit) - { - r = (ushort)(r + S[k] * t); - t = t * 256; - k = k + 1; - m = (uint)System.Math.Floor((double)((m + 255) / 256)); - } - bottomr.Add(r); - bottomt.Add(t); - M2.Add((ushort)m); - } - - if (M.Count % 2 != 0) - { - M2.Add(M[M.Count - 1]); - } - - List S2 = new List(); - - S2 = S.GetRange(k, S.Count - k); - - List R2 = Decode(S2, M2); - - List R = new List(); - - for (int i = 0; i < M.Count - 1; i += 2) - { - uint r = bottomr[i / 2]; - uint t = bottomt[i / 2]; - r += (uint)(t * R2[i / 2]); - R.Add((ushort)mod(r, M[i])); - R.Add((ushort)(mod(System.Math.Floor((double)r / M[i]), M[i + 1]))); - } - if (M.Count % 2 != 0) - { - R.Add(R2[M2.Count - 1]); - } - return R; - } - - private void Encode(ref List output, ushort[] R, ushort[] M, long len) - { - int limit = 16384; - if (len == 1) - { - ushort r = R[0]; - ushort m = M[0]; - - while (m > 1) - { - output.Add(Decimal.ToByte(r % 256)); - r >>= 8; - m = (ushort)((m + 255) >> 8); - } - } - - if (len > 1) - { - ushort[] R2 = new ushort[(len + 1) / 2]; - ushort[] M2 = new ushort[(len + 1) / 2]; - - int i; - for (i = 0; i < len - 1; i += 2) - { - uint m0 = M[i]; - uint r = R[i] + R[i + 1] * m0; - uint m = M[i + 1] * m0; - - while (m >= limit) - { - output.Add(Decimal.ToByte(r % 256)); - r >>= 8; - m = (m + 255) >> 8; - } - - R2[i / 2] = (ushort)r; - M2[i / 2] = (ushort)m; - } - - if (i < len) - { - R2[i / 2] = R[i]; - M2[i / 2] = M[i]; - } - - Encode(ref output, R2, M2, (len + 1) / 2); - } - } - - private void Encrypt(ref byte[] output, sbyte[] r, byte[] pk) // ZEncrypt - { - if (_lpr) - { - short[] A = new short[_p]; - short[] B = new short[_p]; - sbyte[] T = new sbyte[_I]; - - byte[] pkMinusSeed = new byte[pk.Length - _seedBytes]; - Array.Copy(pk, _seedBytes, pkMinusSeed, 0, pkMinusSeed.Length); - - RoundedDecode(ref A, pkMinusSeed); - - // BEGIN: XEncrypt - short[] G = new short[_p]; - sbyte[] b = new sbyte[_p]; - byte[] seedOut = new byte[_seedBytes]; - - Array.Copy(pk, 0, seedOut, 0, _seedBytes); - - Generator(ref G, seedOut); - HashShort(ref b, r); - - // BEGIN: Encrypt - short[] bG = new short[_p]; - short[] bA = new short[_p]; - - RqMult(ref bG, G, ref b); - - Round(ref B, bG); - - RqMult(ref bA, A, ref b); - - for (int i = 0; i < _I; ++i) - { - T[i] = Top(ArithmeticMod_q(bA[i] + r[i] * _q12)); - } - // END: Encrypt - // END: XEncrypt - - RoundedEncode(ref output, B); - byte[] topEncOut = new byte[output.Length]; - TopEncode(ref topEncOut, T); - Array.Copy(topEncOut, 0, output, _roundedBytes, output.Length - _roundedBytes); - } - else - { - short[] h = new short[_p]; - short[] c = new short[_p]; - - RqDecode(ref h, pk); - - // Encrypt - short[] hr = new short[_p]; - RqMult(ref hr, h, r); - Round(ref c, hr); - // END Encrypt - - RoundedEncode(ref output, c); - - } - } - - private void Decrypt(ref sbyte[] output, byte[] c, byte[] sk) // ZDecrypt - { - if (_lpr) - { - sbyte[] a = new sbyte[_p]; - short[] B = new short[_p]; - sbyte[] T = new sbyte[_I]; - - ByteDecode(ref a, sk); - RoundedDecode(ref B, c); - - Array.Copy(c, _roundedBytes, c, 0, c.Length - _roundedBytes); - - TopDecode(ref T, c); - - // BEGIN: XDecrypt - short[] aB = new short[_p]; - - RqMult(ref aB, B, ref a); - - for (int i = 0; i < _I; ++i) - { - int freeze = Right(T[i]) - aB[i] + 4 * _w + 1; - output[i] = (sbyte)(-NegativeMask((short)(mod(freeze + _q12, _q) - _q12))); - } - // END: XDecrypt - } - else - { - sbyte[] f = new sbyte[_p]; - sbyte[] v = new sbyte[_p]; - - short[] c2 = new short[_p]; - - ByteDecode(ref f, sk); - - byte[] skShift = new byte[sk.Length]; - - Array.Copy(sk, _smallBytes, skShift, 0, skShift.Length - _smallBytes); - - ByteDecode(ref v, skShift); - - RoundedDecode(ref c2, c); - - short[] cf = new short[_p]; - short[] cf3 = new short[_p]; - sbyte[] e = new sbyte[_p]; - sbyte[] ev = new sbyte[_p]; - - RqMult(ref cf, c2, f); - RqMult3(ref cf3, cf); - R3FromRq(ref e, cf3); - R3Mult(ref ev, e, v); - - int mask = WeightMask(ev); - - for (int i = 0; i < _w; ++i) - { - output[i] = (sbyte)(((ev[i] ^ 1) & ~mask) ^ 1); - } - - for (int i = _w; i < _p; ++i) - { - output[i] = (sbyte)(ev[i] & ~mask); - } - } - - } - - private void Hide(ref byte[] output, byte[] r_enc, sbyte[] r, byte[] pk, byte[] cache) - { - /* c,r_enc = Hide(r,pk,cache); cache is Hash4(pk) */ - - if (_lpr) - { - InputsEncode(ref r_enc, r); - } - else - { - ByteEncode(ref r_enc, r); - } - - Encrypt(ref output, r, pk); - - Array.Copy(output, 0, output, _ctBytes, output.Length - _ctBytes); - - HashConfirm(ref output, ref r_enc, ref pk, ref cache); - - } - - private void Generator(ref short[] output, byte[] seed) - { - uint[] L = Expand(seed); - - for (int i = 0; i < _p; i++) - { - output[i] = (short)((L[i] % _q) - _q12); - } - } - - private uint[] Expand(byte[] k) - { - byte[] L = new byte[_p * 4]; - byte[] cipherInput = new byte[_p * 4]; - uint[] L_uint = new uint[_p]; - - // AES256 CTR - BufferedBlockCipher cipher = new BufferedBlockCipher(new SicBlockCipher(new AesEngine())); - KeyParameter kp = new KeyParameter(k); - cipher.Init(true, new ParametersWithIV(kp, new byte[16])); - int len = cipher.ProcessBytes(cipherInput, 0, 4 * _p, L, 0); - len += cipher.DoFinal(L, len); - - for (int i = 0; i < _p; ++i) - { - uint L0 = L[4 * i]; - uint L1 = L[4 * i + 1]; - uint L2 = L[4 * i + 2]; - uint L3 = L[4 * i + 3]; - - L_uint[i] = L0 + (L1 << 8) + (L2 << 16) + (L3 << 24); - } - return L_uint; - } - - private void ShortRandom(ref sbyte[] output, SecureRandom random) - { - uint[] L = new uint[_p]; - - for (int i = 0; i < _p; ++i) - { - byte[] shortRandom = new byte[4]; - random.NextBytes(shortRandom); - L[i] = BitConverter.ToUInt32(shortRandom, 0); - } - ShortFromList(ref output, L); - } - - private void ShortFromList(ref sbyte[] output, uint[] L_in) - { - uint[] L = new uint[_p]; - - for (int i = 0; i < _w; ++i) - { - L[i] = (uint)(L_in[i] & -2); - } - - for (int i = _w; i < _p; ++i) - { - L[i] = (uint)(L_in[i] & -3) | 1; - } - - Array.Sort(L); - - for (int i = 0; i < _p; ++i) - { - output[i] = (sbyte)((L[i] & 3) - 1); - } - } - - private void RqMult(ref short[] output, short[] G, ref sbyte[] a) // aG, G, a -> h, f, g - { - short[] fg = new short[_p + _p - 1]; - short result; - - for (int i = 0; i < _p; ++i) - { - result = 0; - for (int j = 0; j <= i; ++j) - { - result = ArithmeticMod_q(result + (G[j] * a[i - j])); - } - - fg[i] = result; - } - - for (int i = _p; i < _p + _p - 1; ++i) - { - result = 0; - for (int j = i - _p + 1; j < _p; ++j) - { - result = ArithmeticMod_q(result + (G[j] * a[i - j])); - } - - fg[i] = result; - } - - for (int i = _p + _p - 2; i >= _p; --i) - { - fg[i - _p] = ArithmeticMod_q(fg[i - _p] + fg[i]); - fg[i - _p + 1] = ArithmeticMod_q(fg[i - _p + 1] + fg[i]); - } - - for (int i = 0; i < _p; ++i) - { - output[i] = fg[i]; - } - } - - private void Round(ref short[] output, short[] aG) - { - for (int i = 0; i < _p; ++i) - { - output[i] = (short)(aG[i] - ArithmeticMod_3(aG[i])); - } - } - - private void InputsRandom(ref sbyte[] output, SecureRandom random) - { - byte[] s = new byte[_inputsBytes]; - random.NextBytes(s); - for (int i = 0; i < _I; ++i) - { - output[i] = (sbyte)(1 & (s[i >> 3] >> (i & 7))); - } - } - - private void InputsEncode(ref byte[] output, sbyte[] r) - { - for (int i = 0; i < _inputsBytes; ++i) - { - output[i] = 0; - } - - for (int i = 0; i < _I; ++i) - { - output[i >> 3] |= (byte)(r[i] << (i & 7)); - } - } - - private void RoundedEncode(ref byte[] output, short[] A) - { - ushort[] R = new ushort[_p]; - ushort[] M = new ushort[_p]; - - for (int i = 0; i < _p; ++i) - { - R[i] = (ushort)(((A[i] + _q12) * 10923) >> 15); - } - - for (int i = 0; i < _p; ++i) - { - M[i] = (ushort)((_q + 2) / 3); - } - - List outputList = new List(); - - Encode(ref outputList, R, M, _p); - - Array.Copy(outputList.ToArray(), 0, output, 0, outputList.Count); - } - - private void RoundedDecode(ref short[] output, byte[] s) - { - List M = new List(_p); - List S = new List(s); - - for (int i = 0; i < _p; ++i) - { - M.Add((ushort)((_q + 2) / 3)); - } - - List decoded = Decode(S, M); - - for (int i = 0; i < _p; ++i) - { - output[i] = (short)((decoded[i] * 3) - _q12); - } - } - - private void ByteEncode(ref byte[] output, sbyte[] a) - { - sbyte x; - for (int i = 0; i < _p / 4; ++i) - { - int x0 = a[4 * i] + 1; - int x1 = (a[4 * i + 1] + 1) << 2; - int x2 = (a[4 * i + 2] + 1) << 4; - int x3 = (a[4 * i + 3] + 1) << 6; - x = (sbyte)(x0 + x1 + x2 + x3); - output[i] = (byte)x; - } - output[_p / 4] = (byte)(a[_p - 1] + 1); - } - - private void ByteDecode(ref sbyte[] output, byte[] s) - { - byte x; - for (int i = 0; i < _p / 4; ++i) - { - x = s[i]; - output[i * 4] = (sbyte)((x & 3) - 1); - x >>= 2; - output[i * 4 + 1] = (sbyte)((x & 3) - 1); - x >>= 2; - output[i * 4 + 2] = (sbyte)((x & 3) - 1); - x >>= 2; - output[i * 4 + 3] = (sbyte)((x & 3) - 1); - } - - x = s[_p / 4]; - output[_p / 4 * 4] = (sbyte)((x & 3) - 1); - } - - private void TopEncode(ref byte[] output, sbyte[] T) - { - for (int i = 0; i < _topBytes; ++i) - { - output[i] = (byte)(T[2 * i] + (T[2 * i + 1] << 4)); - } - } - - private void TopDecode(ref sbyte[] output, byte[] s) - { - for (int i = 0; i < _topBytes; ++i) - { - output[2 * i] = (sbyte)(s[i] & 15); - output[2 * i + 1] = (sbyte)(s[i] >> 4); - } - } - - private void HashShort(ref sbyte[] output, sbyte[] r) - { - byte[] s = new byte[_inputsBytes]; - byte[] h = new byte[_hashBytes]; - uint[] L = new uint[_p]; - - InputsEncode(ref s, r); - HashPrefix(ref h, 5, ref s, s.Length); - L = Expand(h); - ShortFromList(ref output, L); - } - - private void HashPrefix(ref byte[] output, int b, ref byte[] input, int inlen) - { - byte[] x = new byte[inlen + 1]; - byte[] h = new byte[64]; - - x[0] = (byte)b; - - for (int i = 0; i < inlen; ++i) - { - x[i + 1] = input[i]; - } - - Sha512Digest sha512 = new Sha512Digest(); - sha512.BlockUpdate(x, 0, x.Length); - sha512.DoFinal(h, 0); - - Array.Copy(h, 0, output, output.Length - 32, 32); - } - - private void HashConfirm(ref byte[] output, ref byte[] r, ref byte[] pk, ref byte[] cache) - { - - byte[] x; - - if (_lpr) - { - - x = new byte[_inputsBytes + _hashBytes]; - - - for (int i = 0; i < _inputsBytes; ++i) - { - x[i] = r[i]; - } - - for (int i = 0; i < _hashBytes; ++i) - { - x[_inputsBytes + i] = cache[i]; - } - - } - else - { - x = new byte[_hashBytes*2]; - - byte[] prefix = new byte[_hashBytes]; - - HashPrefix(ref prefix, 3, ref r, _inputsBytes); - - Array.Copy(prefix, 0, x, 0, _hashBytes); - - for (int i = 0; i < _hashBytes; ++i) - { - x[_hashBytes + i] = cache[i]; - } - } - HashPrefix(ref output, 2, ref x, x.Length); - - } - - private void HashSession(ref byte[] output, int b, byte[] y, byte[] z) - { - byte[] x; - - if (_lpr) - { - x = new byte[_inputsBytes + _ciphertextsBytes + _confirmBytes]; - - for (int i = 0; i < _inputsBytes; ++i) - { - x[i] = y[i]; - } - - for (int i = 0; i < _ciphertextsBytes + _confirmBytes; ++i) - { - x[_inputsBytes + i] = z[i]; - } - } - else - { - x = new byte[_hashBytes + _ciphertextsBytes + _confirmBytes]; - - byte[] prefix = new byte[_hashBytes]; - HashPrefix(ref prefix, 3, ref y, _inputsBytes); - Array.Copy(prefix, 0, x, 0, _hashBytes); - - for (int i = 0; i < _ciphertextsBytes + _confirmBytes; ++i) - { - x[_hashBytes + i] = z[i]; - } - } - - HashPrefix(ref output, b, ref x, x.Length); - } - - private int NegativeMask(short x) - { - return (x < 0) ? -1 : 0; - } - - private int ctDiffMask(byte[] c, byte[] c2) - { - int x = c.Length ^ c2.Length; - for (int i = 0; i < c.Length && i < c2.Length; ++i) - { - x |= c[i] ^ c2[i]; - } - - // Return 0 if matching, else -1 - return x == 0 ? 0 : -1; - } - - // Arithmetics - double mod(double a, double b) - { - return a - b * System.Math.Floor(a / b); - } - - private short ArithmeticMod_q(int x) // Fq_freeze - { - return (short)((mod(x + _q12, _q)) - _q12); - } - - private short ArithmeticMod_3(int x) // F3_freeze - { - return (short)(mod(x + 1, 3) - 1); - } - - private sbyte Top(int C) - { - return (sbyte)((_tau1 * (C + _tau0) + 16384) >> 15); - } - - private short Right(sbyte T) - { - int freeze = _tau3 * T - _tau2; - return (short)(mod(freeze + _q12, _q) - _q12); - } - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPKemExtractor.cs b/crypto/src/pqc/crypto/ntrup/NtruPKemExtractor.cs deleted file mode 100644 index 6149e1112..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPKemExtractor.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Pqc.Crypto.Frodo; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPKEMExtractor : IEncapsulatedSecretExtractor - { - private NtruPEngine _pEngine; - private NtruPKeyParameters _pKey; - - public NtruPKEMExtractor(NtruPKeyParameters privParams) - { - this._pKey = privParams; - InitCipher(_pKey.PParameters); - } - - private void InitCipher(NtruPParameters param) - { - _pEngine = param.PEngine; - } - - public byte[] ExtractSecret(byte[] encapsulation) - { - byte[] session_key = new byte[_pEngine.SessionKeySize]; - _pEngine.kem_dec(session_key, encapsulation, ((NtruPPrivateKeyParameters)_pKey).PrivateKey); - return session_key; - } - - public int GetInputSize() - { - return _pEngine.CipherTextSize; - } - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPKemGenerator.cs b/crypto/src/pqc/crypto/ntrup/NtruPKemGenerator.cs deleted file mode 100644 index 0fb2633e8..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPKemGenerator.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPKemGenerator : IEncapsulatedSecretGenerator - { - private SecureRandom sr; - - public NtruPKemGenerator(SecureRandom sr) - { - this.sr = sr; - } - - public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey) - { - NtruPPublicKeyParameters key = (NtruPPublicKeyParameters)recipientKey; - NtruPEngine pEngine = key.PParameters.PEngine; - byte[] cipherText = new byte[pEngine.CipherTextSize]; - byte[] sessionKey = new byte[pEngine.SessionKeySize]; - pEngine.kem_enc(cipherText, sessionKey,key.PublicKey, sr); - return new NtruPKemGenerator.SecretWithEncapsulationImpl(sessionKey, cipherText); - } - - public class SecretWithEncapsulationImpl : ISecretWithEncapsulation - { - private volatile bool hasBeenDestroyed = false; - - private byte[] sessionKey; - private byte[] cipherText; - - public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipherText) - { - this.sessionKey = sessionKey; - this.cipherText = cipherText; - } - - public byte[] GetSecret() - { - CheckDestroyed(); - return Arrays.Clone(sessionKey); - } - - public byte[] GetEncapsulation() - { - return Arrays.Clone(cipherText); - } - - public void Dispose() - { - if (!hasBeenDestroyed) - { - hasBeenDestroyed = true; - Arrays.Clear(sessionKey); - Arrays.Clear(cipherText); - } - } - - public bool IsDestroyed() - { - return hasBeenDestroyed; - } - - void CheckDestroyed() - { - if (IsDestroyed()) - { - throw new Exception("data has been destroyed"); - } - } - - } - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPKeyGenerationParameters.cs b/crypto/src/pqc/crypto/ntrup/NtruPKeyGenerationParameters.cs deleted file mode 100644 index 7f96dfce6..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPKeyGenerationParameters.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruKeyGenerationParameters : KeyGenerationParameters - { - private NtruPParameters _pParameters; - - public NtruKeyGenerationParameters(SecureRandom random, NtruPParameters ntruPParameters) : base(random,256) - { - this._pParameters = ntruPParameters; - } - - public NtruPParameters PParameters => _pParameters; - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPKeyPairGenerator.cs b/crypto/src/pqc/crypto/ntrup/NtruPKeyPairGenerator.cs deleted file mode 100644 index fbbd66281..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPKeyPairGenerator.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruKeyPairGenerator - { - private NtruKeyGenerationParameters ntruParams; - - private int p; - private int q; - - private SecureRandom random; - - private void Initialize(KeyGenerationParameters param) - { - ntruParams = (NtruKeyGenerationParameters) param; - random = param.Random; - - // n = ntruParams.Parameters.N; - - p = ntruParams.PParameters.P; - q = ntruParams.PParameters.Q; - - } - - private AsymmetricCipherKeyPair GenKeyPair() - { - NtruPEngine pEngine = ntruParams.PParameters.PEngine; - byte[] sk = new byte[pEngine.PrivateKeySize]; - byte[] pk = new byte[pEngine.PublicKeySize]; - pEngine.kem_keypair( pk,sk,random); - - NtruPPublicKeyParameters pubKey = new NtruPPublicKeyParameters(ntruParams.PParameters, pk); - NtruPPrivateKeyParameters privKey = new NtruPPrivateKeyParameters(ntruParams.PParameters, sk); - return new AsymmetricCipherKeyPair(pubKey, privKey); - } - - public void Init(KeyGenerationParameters param) - { - this.Initialize(param); - } - - public AsymmetricCipherKeyPair GenerateKeyPair() - { - return GenKeyPair(); - } - - // private AsymmetricCipherKeyPair GenKeyPair() - // { - // NtruEngine engine = ntruParams.Parameters.Engine; - // byte[] sk = new byte[engine.PrivateKeySize]; - // byte[] pk = new byte[engine.PublicKeySize]; - // - // - // } - // - // public void Init(KeyGenerationParameters param) - // { - // this.Initialize(param); - // } - // - // public AsymmetricCipherKeyPair GenerateKeyPair() - // { - // return GenKeyPair(); - // } - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPKeyParameters.cs b/crypto/src/pqc/crypto/ntrup/NtruPKeyParameters.cs deleted file mode 100644 index 96bd4ca8e..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPKeyParameters.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Org.BouncyCastle.Crypto; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPKeyParameters : AsymmetricKeyParameter - { - private NtruPParameters _pParameters; - - public NtruPKeyParameters(bool isPrivate, NtruPParameters pParameters) : base(isPrivate) - { - this._pParameters = pParameters; - } - - public NtruPParameters PParameters => _pParameters; - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPParameters.cs b/crypto/src/pqc/crypto/ntrup/NtruPParameters.cs deleted file mode 100644 index 82c7c8e13..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPParameters.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.ComponentModel; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Modes; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPParameters : ICipherParameters - { - - private String name; - private int p; - private int q; - private int _roundedBytes; - private bool LPR; - private int _w; - private int _rqBytes; - private int _tau0; - private int _tau1; - private int _tau2; - private int _tau3; - private int _skBytes; - private int _pkBytes; - private int _ctBytes; - private NtruPEngine _pEngine; - - public NtruPParameters(String name, int p, int q, bool LPR, int w, int tau0, - int tau1, int tau2, int tau3, int skBytes, int pkBytes, int ctBytes, int roundedBytes, int rqBytes) - { - this.name = name; - this.p = p; - this.q = q; - this.LPR = LPR; - this._w = w; - this._tau0 = tau0; - this._tau1 = tau1; - this._tau2 = tau2; - this._tau3 = tau3; - - // KEM Parameters - this._roundedBytes = roundedBytes; - this._rqBytes = rqBytes; - this._skBytes = skBytes; - this._pkBytes = pkBytes; - this._ctBytes = ctBytes; - this._pEngine = new NtruPEngine(p,q, LPR, w, tau0, tau1, tau2, tau3, skBytes, pkBytes, ctBytes, roundedBytes, rqBytes); - } - - public static NtruPParameters ntrulpr653 = new NtruPParameters("NTRU_LPRime_653", 653, 4621, true, 252, 2175,113,2031,290,1125,897,1025, 865, -1); - public static NtruPParameters ntrulpr761 = new NtruPParameters("NTRU_LPRime_761", 761, 4591, true, 250, 2156,114,2007,287,1294,1039,1167, 1007, -1); - public static NtruPParameters ntrulpr857 = new NtruPParameters("NTRU_LPRime_857", 857, 5167, true, 281, 2433,101,2265,324,1463,1184,1312, 1152, -1); - public static NtruPParameters ntrulpr953 = new NtruPParameters("NTRU_LPRime_953", 953, 6343, true, 345, 2997,82,2798,400,1652,1349,1477, 1317, -1); - public static NtruPParameters ntrulpr1013 = new NtruPParameters("NTRU_LPRime_1013", 1013, 7177, true, 392, 3367,73,3143,449,1773,1455,1583, 1423, -1); - public static NtruPParameters ntrulpr1277 = new NtruPParameters("NTRU_LPRime_1277", 1277, 7879, true, 429, 3724,66,3469,496,2231,1847,1975, 1815, -1); - - public static NtruPParameters sntrup653 = new NtruPParameters("SNTRU_Prime_653", 653, 4621, false, 288, -1,-1,-1,-1,1518,994,897, 865, 994); - public static NtruPParameters sntrup761 = new NtruPParameters("SNTRU_Prime_761", 761, 4591, false, 286, -1,-1,-1,-1,1763,1158,1039, 1007, 1158); - public static NtruPParameters sntrup857 = new NtruPParameters("SNTRU_Prime_857", 857, 5167, false, 322, -1,-1,-1,-1,1999,1322,1184, 1152, 1322); - public static NtruPParameters sntrup953 = new NtruPParameters("SNTRU_Prime_953", 953, 6343, false, 396, -1,-1,-1,-1,2254,1505,1349, 1317, 1505); - public static NtruPParameters sntrup1013 = new NtruPParameters("SNTRU_Prime_1013", 1013, 7177, false, 448, -1,-1,-1,-1,2417,1623,1455, 1423, 1623); - public static NtruPParameters sntrup1277 = new NtruPParameters("SNTRU_Prime_1277", 1277, 7879, false, 492, -1,-1,-1,-1,3059,2067,1847, 1815, 2067); - - public int P => p; - public bool lpr => LPR; - - public int Q => q; - - internal NtruPEngine PEngine => _pEngine; - - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPPrivateKeyParameters.cs b/crypto/src/pqc/crypto/ntrup/NtruPPrivateKeyParameters.cs deleted file mode 100644 index ff70aa241..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPPrivateKeyParameters.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPPrivateKeyParameters : NtruPKeyParameters - { - private byte[] privKey; - public byte[] PrivateKey => Arrays.Clone(privKey); - - public NtruPPrivateKeyParameters(NtruPParameters pParameters, byte[] privKey) : base(true, pParameters) - { - this.privKey = Arrays.Clone(privKey); - } - - public byte[] GetEncoded() - { - return PrivateKey; - } - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntrup/NtruPPublicKeyParameters.cs b/crypto/src/pqc/crypto/ntrup/NtruPPublicKeyParameters.cs deleted file mode 100644 index c7a00d9f3..000000000 --- a/crypto/src/pqc/crypto/ntrup/NtruPPublicKeyParameters.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.pqc.crypto.NtruP -{ - public class NtruPPublicKeyParameters : NtruPKeyParameters - { - public byte[] pubKey; - - public byte[] PublicKey => Arrays.Clone(pubKey); - - public byte[] GetEncoded() - { - return PublicKey; - } - - public NtruPPublicKeyParameters(NtruPParameters pParameters, byte[] pubKey) : base(false,pParameters) - { - this.pubKey = Arrays.Clone(pubKey); - } - } -} \ No newline at end of file diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeEngine.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeEngine.cs new file mode 100644 index 000000000..701a53cee --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeEngine.cs @@ -0,0 +1,1284 @@ +using System; +using System.Collections.Generic; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + internal class NtruPrimeEngine + { + // Key Sizes + private readonly int _skBytes; // [KEM] Size of secret key + private readonly int _pkBytes; // [KEM] Size of public key + private readonly int _ctBytes; // [KEM] Size of ciphertext + + private readonly int _secretKeyBytes; // C Reference: SecretKey_bytes + private readonly int _publicKeyBytes; // C Reference: PublicKey_bytes + private readonly int _ciphertextsBytes; // C Reference: Ciphertext_bytes + + private readonly int _confirmBytes; + private readonly int _inputsBytes; // For encoding _I-bit inputs + private readonly int _topBytes; + private readonly int _seedBytes; + private readonly int _smallBytes; + private readonly int _hashBytes; + + private const int SessionKeyBytes = 32; + + // Parameters for NTRU + private readonly int _p; + private readonly int _q; + + private readonly int _roundedBytes; // Defined in params.h + + // private readonly int _rqBytes; // Defined in params.h - Public key bytes for streamlined nTRU + private readonly bool _lpr; + private readonly int _w; + private readonly int _tau0; + private readonly int _tau1; + private readonly int _tau2; + private readonly int _tau3; + + private readonly int _I; + + private readonly int _q12; + + public int PrivateKeySize => _skBytes; + public int PublicKeySize => _pkBytes; + public int CipherTextSize => _ctBytes; + public int SessionKeySize => SessionKeyBytes; + + public NtruPrimeEngine(int p, int q, bool lpr, int w, int tau0, + int tau1, int tau2, int tau3, int skBytes, int pkBytes, int ctBytes, int roundedBytes, int rqBytes) + { + this._p = p; + this._q = q; + this._w = w; + this._tau0 = tau0; + this._tau1 = tau1; + this._tau2 = tau2; + this._tau3 = tau3; + + // KEM parameters + this._roundedBytes = roundedBytes; + this._skBytes = skBytes; + this._pkBytes = pkBytes; + this._ctBytes = ctBytes; + + this._lpr = lpr; + + this._confirmBytes = 32; + + _smallBytes = ((p + 3) / 4); + _q12 = ((q - 1) / 2); + _hashBytes = 32; + + if (lpr) + { + _seedBytes = 32; + _I = 256; + _inputsBytes = _I / 8; + _topBytes = _I / 2; + _ciphertextsBytes = roundedBytes + _topBytes; + _secretKeyBytes = _smallBytes; + _publicKeyBytes = _seedBytes + roundedBytes; + } + else + { + _inputsBytes = _smallBytes; + _ciphertextsBytes = _roundedBytes; + _secretKeyBytes = (2*_smallBytes); + _publicKeyBytes = rqBytes; + } + } + + + public void kem_keypair(byte[] pk, byte[] sk, SecureRandom random) //KEM_KeyGen + { + + KeyGen(random, ref pk, ref sk); + Array.Copy(pk, 0, sk, _secretKeyBytes, _publicKeyBytes); + byte[] rand = new byte[_inputsBytes]; + random.NextBytes(rand); + Array.Copy(rand, 0, sk, _secretKeyBytes+_publicKeyBytes, _inputsBytes); + HashPrefix(ref sk, 4, ref pk, _publicKeyBytes); + } + + + public void kem_enc(byte[] ct, byte[] ss, byte[] pk, SecureRandom random) + { + sbyte[] inputs; + + if (_lpr) + { + inputs = new sbyte[_I]; + } + else + { + inputs = new sbyte[_p]; + } + + byte[] r_enc = new byte[_inputsBytes]; + byte[] cache = new byte[_hashBytes]; + + HashPrefix(ref cache, 4, ref pk, _publicKeyBytes); + + if (_lpr) + { + InputsRandom(ref inputs, random); + } + else + { + ShortRandom(ref inputs, random); + } + + Hide(ref ct, r_enc, inputs, pk, cache); + HashSession(ref ss, 1, r_enc, ct); + } + + public void kem_dec(byte[] ss, byte[] ct, byte[] sk) + { + byte[] pk = new byte[sk.Length - _secretKeyBytes]; + + // Shift sk by _secretKeyBytes and copy to pk + + Array.Copy(sk, _secretKeyBytes, pk, 0, pk.Length); + + byte[] rho = new byte[pk.Length - _publicKeyBytes]; + + // Shift pk by _publicKeyBytes and fill rho + Array.Copy(pk, _publicKeyBytes, rho, 0, rho.Length); + + byte[] cache = new byte[rho.Length - _inputsBytes]; + + // Shift rho by _inputsBytes and fill cache + + Array.Copy(rho, _inputsBytes, cache, 0, cache.Length); + + sbyte[] r; + + if (_lpr) + { + r = new sbyte[_I]; + } + else + { + r = new sbyte[_p]; + } + + byte[] r_enc = new byte[_inputsBytes]; + byte[] cnew = new byte[_ciphertextsBytes + _confirmBytes]; + + byte[] ct_dec = Arrays.Clone(ct); // ct somehow gets modified in Decrypt + + Decrypt(ref r, ct_dec, sk); + + Hide(ref cnew, r_enc, r, pk, cache); + + int mask = ctDiffMask(ct, cnew); + + for (int i = 0; i < _inputsBytes; ++i) + { + r_enc[i] ^= (byte)(mask & (r_enc[i] ^ rho[i])); + } + + HashSession(ref ss, 1 + mask, r_enc, ct); + } + + // --------------------------------------------------------------------- + + private void KeyGen(SecureRandom random, ref byte[] pk, ref byte[] sk) // ZKeyGen + { + if (_lpr) + { + short[] A = new short[_p]; + sbyte[] a = new sbyte[_p]; + + // BEGIN: XKeyGen + byte[] seedOut = new byte[_seedBytes]; + random.NextBytes(seedOut); + Array.Copy(seedOut, 0, pk, 0, _seedBytes); + short[] genOut = new short[_p]; + Generator(ref genOut, seedOut); + + // BEGIN: XKeyGen > KeyGen + ShortRandom(ref a, random); + short[] aG = new short[_p]; + RqMult(ref aG, genOut, ref a); + Round(ref A, aG); + // END XKeyGen > KeyGen + // END: XKeyGen + + byte[] roundedEncOut = new byte[pk.Length]; + RoundedEncode(ref roundedEncOut, A); + + Array.Copy(roundedEncOut, 0, pk, _seedBytes, pk.Length - _seedBytes); + + ByteEncode(ref sk, a); + } + else + { + // KeyGen + short[] h = new short[_p]; + sbyte[] f = new sbyte[_p]; + + sbyte[] ginv = new sbyte[_p]; + sbyte[] g = new sbyte[_p]; + short[] finv = new short[_p]; + + while (true) + { + ByteRandom(ref g, random); + + if (R3Recip(ref ginv, g) == 0) + { + break; + } + + } + + ShortRandom(ref f, random); + RqRecip3(ref finv, f); + RqMult(ref h, finv, g); + // END KeyGen + + RqEncode(ref pk, h); + + ByteEncode(ref sk, f); + + byte[] smallEncOut = new byte[sk.Length]; + ByteEncode(ref smallEncOut, ginv); + + Array.Copy(smallEncOut, 0, sk, _smallBytes, sk.Length - _smallBytes); + + } + + } + + //----------------------- Streamlined -------------------------------- + + private void ByteRandom(ref sbyte[] output, SecureRandom random) + { + for (int i = 0;i < _p;++i) + { + byte[] smallRandom = new byte[4]; + random.NextBytes(smallRandom); + output[i] = (sbyte)((((BitConverter.ToUInt32(smallRandom, 0) & 0x3fffffff) * 3) >> 30)-1); + }; + } + + private int R3Recip(ref sbyte[] output, sbyte[] input) + { + sbyte[] f = new sbyte[_p+1]; + sbyte[] g = new sbyte[_p+1]; + sbyte[] v = new sbyte[_p+1]; + sbyte[] r = new sbyte[_p+1]; + + for (int i = 0; i < _p+1; ++i) + { + v[i] = 0; + r[i] = 0; + } + + r[0] = 1; + + for (int i = 0; i < _p; ++i) + { + f[i] = 0; + } + + f[0] = 1; + f[_p - 1] = f[_p] = -1; + + for (int i = 0; i < _p; ++i) + { + g[_p-1-i] = input[i]; + } + + g[_p] = 0; + + int delta = 1; + + int sign, swap, t; + + for (int i = 0; i < 2*_p-1; ++i) + { + for (int j = _p; j > 0; --j) + { + v[j] = v[j - 1]; + } + + v[0] = 0; + + sign = -g[0] * f[0]; + + + swap = NegativeMask((short)-delta) & ((g[0] != 0) ? -1 : 0); + + + delta ^= swap & (delta ^ -delta); + delta +=1; + + for (int j = 0; j < _p + 1; ++j) + { + t = swap&(f[j]^g[j]); + f[j] ^= (sbyte)t; + g[j] ^= (sbyte)t; + t = swap&(v[j]^r[j]); + v[j] ^= (sbyte)t; + r[j] ^= (sbyte)t; + + } + for (int j = 0; j < _p+1; ++j) + { + g[j] =(sbyte)(mod(((g[j] + sign * f[j]) + 1), 3) - 1); + } + + for (int j = 0; j < _p+1; ++j) + { + r[j] =(sbyte)(mod(((r[j] + sign * v[j]) + 1), 3) - 1); + } + + for (int j = 0; j < _p; ++j) + { + g[j] = g[j + 1]; + } + g[_p] = 0; + } + + sign = f[0]; + + for (int i = 0; i < _p; ++i) + { + output[i] = (sbyte)(sign * v[_p - 1 - i]); + } + + return (delta != 0) ? -1 : 0; + + } + + private int RqRecip3(ref short[] output, sbyte[] input) + { + short[] f = new short[_p + 1]; + short[] g = new short[_p + 1]; + short[] v = new short[_p + 1]; + short[] r = new short[_p + 1]; + int swap, t; + short scale; + int f0, g0; + + for (int i = 0; i < _p + 1; ++i) + { + v[i] = 0; + r[i] = 0; + } + + r[0] = FqRecip(3); + + for (int i = 0; i < _p; ++i) + { + f[i] = 0; + } + + f[0] = 1; + f[_p - 1] = f[_p] = -1; + + for (int i = 0; i < _p; ++i) + { + g[_p - 1 - i] = input[i]; + } + + g[_p] = 0; + + int delta = 1; + + for (int i = 0; i < 2 * _p - 1; ++i) + { + + for (int j = _p; j > 0; --j) + { + v[j] = v[j - 1]; + } + + v[0] = 0; + + + swap = NegativeMask((short)-delta) & ((g[0] != 0) ? -1 : 0); + + delta ^= swap & (delta ^ -delta); + delta += 1; + + for (int j = 0; j < _p + 1; ++j) + { + t = swap & (f[j] ^ g[j]); + f[j] ^= (short)t; + g[j] ^= (short)t; + t = swap & (v[j] ^ r[j]); + v[j] ^= (short)t; + r[j] ^= (short)t; + } + + f0 = f[0]; + g0 = g[0]; + + for (int j = 0; j < _p + 1; ++j) + { + g[j] = ArithmeticMod_q(f0 * g[j] - g0 * f[j]); + } + + for (int j = 0; j < _p + 1; ++j) + { + r[j] = ArithmeticMod_q(f0 * r[j] - g0 * v[j]); + } + + for (int j = 0; j < _p; ++j) + { + g[j] = g[j + 1]; + } + + g[_p] = 0; + } + + scale = FqRecip(f[0]); + + for (int i = 0; i < _p; ++i) + { + output[i] = ArithmeticMod_q(scale * v[_p - 1 - i]); + } + + return (delta != 0) ? -1 : 0; + } + + private short FqRecip(short a1) + { + int i = 1; + short ai = a1; + + while (i < _q - 2) + { + ai = ArithmeticMod_q(a1 * ai); + i++; + } + + return ai; + } + + private void RqMult(ref short[] output, short[] f, sbyte[] g) + { + // h = f * g in the ring Rq + + short[] fg = new short[_p + _p + 1]; // Can directly modify h + short result; + + for (int i = 0; i < _p; ++i) + { + result = 0; + for (int j = 0; j <= i; ++j) + { + result = ArithmeticMod_q(result + f[j] * g[i - j]); + } + fg[i] = result; + } + + for (int i = _p;i < _p+_p-1;++i) + { + result = 0; + for (int j = i-_p+1;j < _p;++j) + { + result = ArithmeticMod_q(result + f[j] * g[i - j]); + } + fg[i] = result; + } + + for (int i = _p+_p-2; i >= _p; --i) + { + fg[i - _p] = ArithmeticMod_q(fg[i - _p] + fg[i]); + fg[i-_p+1] = ArithmeticMod_q(fg[i-_p+1] + fg[i]); + } + + for (int i = 0; i < _p; ++i) + { + output[i] = fg[i]; + } + } + + private void RqEncode(ref byte[] output, short[] r) + { + ushort[] R = new ushort[_p]; + ushort[] M = new ushort[_p]; + + for (int i = 0; i < _p; ++i) + { + R[i] = (ushort)(r[i] + _q12); + M[i] = (ushort)_q; + } + + List sList = new List(); + + Encode(ref sList, R, M, _p); + + Array.Copy(sList.ToArray(), 0, output, 0, sList.Count); + } + + private void RqDecode(ref short[] output, byte[] s) + { + ushort[] R = new ushort[_p]; + ushort[] M = new ushort[_p]; + + for (int i = 0; i < _p; ++i) + { + M[i] = (ushort)_q; + } + + List rList = new List(s); + List mList = new List(M); + + List decoded = Decode(rList, mList); + + for (int i = 0; i < _p; ++i) + { + output[i] = (short)(decoded[i] - _q12); + } + } + + private void RqMult3(ref short[] output, short[] f) + { + for (int i = 0; i < _p; ++i) + { + output[i] = ArithmeticMod_q(f[i] * 3); + } + } + + private void R3FromRq(ref sbyte[] output, short[] r) + { + for (int i = 0; i < _p; ++i) + { + output[i] = (sbyte)ArithmeticMod_3(r[i]); + } + } + + private void R3Mult(ref sbyte[] output, sbyte[] f, sbyte[] g) + { + sbyte[] fg = new sbyte[_p + _p + 1]; + sbyte result; + + for (int i = 0; i < _p; ++i) + { + result = 0; + for (int j = 0; j <= i; ++j) + { + result = (sbyte)(ArithmeticMod_3(result + f[j] * g[i - j])); + } + fg[i] = result; + } + + for (int i = _p;i < _p+_p-1;++i) + { + result = 0; + + for (int j = i-_p+1;j < _p;++j) + { + result = (sbyte)(ArithmeticMod_3(result+f[j]*g[i-j])); + } + fg[i] = result; + } + + for (int i = _p+_p-2;i >= _p;--i) + { + fg[i - _p] = (sbyte)(ArithmeticMod_3(fg[i - _p] + fg[i])); + fg[i - _p + 1] = (sbyte)(ArithmeticMod_3(fg[i - _p + 1] + fg[i])); + } + + for (int i = 0; i < _p; ++i) + { + output[i] = fg[i]; + } + } + + private int WeightMask(sbyte[] r) + { + int weight = 0; + + for (int i = 0; i < _p; ++i) + { + weight += r[i]&1; + } + + return NonZeroMask((short)(weight - _w)); + + } + + private int NonZeroMask(short x) + { + /* return -1 if x!=0; else return 0 */ + return (x == 0) ? 0 : -1; + } + + //--------------------------------------------------------------------- + + private List Decode(List S, List M) + { + int limit = 16384; + + if (M.Count == 0) + { + return new List(); + } + + if (M.Count == 1) + { + if (M[0] == 1) + { + return new List() { 0 }; + } + if (M[0] <= 256) + { + return new List() { (ushort)mod(S[0], M[0]) }; + } else + { + return new List() { (ushort)mod(S[0] + (((uint)S[1]) << 8), M[0]) }; + } + } + + int k = 0; + List bottomr = new List(); + List bottomt = new List(); + List M2 = new List(); + + for (int i = 0; i < M.Count - 1; i += 2) + { + uint m = (uint)(M[i] * M[i + 1]); + ushort r = 0; + uint t = 1; + + while (m >= limit) + { + r = (ushort)(r + S[k] * t); + t = t * 256; + k = k + 1; + m = (uint)System.Math.Floor((double)((m + 255) / 256)); + } + bottomr.Add(r); + bottomt.Add(t); + M2.Add((ushort)m); + } + + if (M.Count % 2 != 0) + { + M2.Add(M[M.Count - 1]); + } + + List S2 = new List(); + + S2 = S.GetRange(k, S.Count - k); + + List R2 = Decode(S2, M2); + + List R = new List(); + + for (int i = 0; i < M.Count - 1; i += 2) + { + uint r = bottomr[i / 2]; + uint t = bottomt[i / 2]; + r += (uint)(t * R2[i / 2]); + R.Add((ushort)mod(r, M[i])); + R.Add((ushort)(mod(System.Math.Floor((double)r / M[i]), M[i + 1]))); + } + if (M.Count % 2 != 0) + { + R.Add(R2[M2.Count - 1]); + } + return R; + } + + private void Encode(ref List output, ushort[] R, ushort[] M, long len) + { + int limit = 16384; + if (len == 1) + { + ushort r = R[0]; + ushort m = M[0]; + + while (m > 1) + { + output.Add(Decimal.ToByte(r % 256)); + r >>= 8; + m = (ushort)((m + 255) >> 8); + } + } + + if (len > 1) + { + ushort[] R2 = new ushort[(len + 1) / 2]; + ushort[] M2 = new ushort[(len + 1) / 2]; + + int i; + for (i = 0; i < len - 1; i += 2) + { + uint m0 = M[i]; + uint r = R[i] + R[i + 1] * m0; + uint m = M[i + 1] * m0; + + while (m >= limit) + { + output.Add(Decimal.ToByte(r % 256)); + r >>= 8; + m = (m + 255) >> 8; + } + + R2[i / 2] = (ushort)r; + M2[i / 2] = (ushort)m; + } + + if (i < len) + { + R2[i / 2] = R[i]; + M2[i / 2] = M[i]; + } + + Encode(ref output, R2, M2, (len + 1) / 2); + } + } + + private void Encrypt(ref byte[] output, sbyte[] r, byte[] pk) // ZEncrypt + { + if (_lpr) + { + short[] A = new short[_p]; + short[] B = new short[_p]; + sbyte[] T = new sbyte[_I]; + + byte[] pkMinusSeed = new byte[pk.Length - _seedBytes]; + Array.Copy(pk, _seedBytes, pkMinusSeed, 0, pkMinusSeed.Length); + + RoundedDecode(ref A, pkMinusSeed); + + // BEGIN: XEncrypt + short[] G = new short[_p]; + sbyte[] b = new sbyte[_p]; + byte[] seedOut = new byte[_seedBytes]; + + Array.Copy(pk, 0, seedOut, 0, _seedBytes); + + Generator(ref G, seedOut); + HashShort(ref b, r); + + // BEGIN: Encrypt + short[] bG = new short[_p]; + short[] bA = new short[_p]; + + RqMult(ref bG, G, ref b); + + Round(ref B, bG); + + RqMult(ref bA, A, ref b); + + for (int i = 0; i < _I; ++i) + { + T[i] = Top(ArithmeticMod_q(bA[i] + r[i] * _q12)); + } + // END: Encrypt + // END: XEncrypt + + RoundedEncode(ref output, B); + byte[] topEncOut = new byte[output.Length]; + TopEncode(ref topEncOut, T); + Array.Copy(topEncOut, 0, output, _roundedBytes, output.Length - _roundedBytes); + } + else + { + short[] h = new short[_p]; + short[] c = new short[_p]; + + RqDecode(ref h, pk); + + // Encrypt + short[] hr = new short[_p]; + RqMult(ref hr, h, r); + Round(ref c, hr); + // END Encrypt + + RoundedEncode(ref output, c); + + } + } + + private void Decrypt(ref sbyte[] output, byte[] c, byte[] sk) // ZDecrypt + { + if (_lpr) + { + sbyte[] a = new sbyte[_p]; + short[] B = new short[_p]; + sbyte[] T = new sbyte[_I]; + + ByteDecode(ref a, sk); + RoundedDecode(ref B, c); + + Array.Copy(c, _roundedBytes, c, 0, c.Length - _roundedBytes); + + TopDecode(ref T, c); + + // BEGIN: XDecrypt + short[] aB = new short[_p]; + + RqMult(ref aB, B, ref a); + + for (int i = 0; i < _I; ++i) + { + int freeze = Right(T[i]) - aB[i] + 4 * _w + 1; + output[i] = (sbyte)(-NegativeMask((short)(mod(freeze + _q12, _q) - _q12))); + } + // END: XDecrypt + } + else + { + sbyte[] f = new sbyte[_p]; + sbyte[] v = new sbyte[_p]; + + short[] c2 = new short[_p]; + + ByteDecode(ref f, sk); + + byte[] skShift = new byte[sk.Length]; + + Array.Copy(sk, _smallBytes, skShift, 0, skShift.Length - _smallBytes); + + ByteDecode(ref v, skShift); + + RoundedDecode(ref c2, c); + + short[] cf = new short[_p]; + short[] cf3 = new short[_p]; + sbyte[] e = new sbyte[_p]; + sbyte[] ev = new sbyte[_p]; + + RqMult(ref cf, c2, f); + RqMult3(ref cf3, cf); + R3FromRq(ref e, cf3); + R3Mult(ref ev, e, v); + + int mask = WeightMask(ev); + + for (int i = 0; i < _w; ++i) + { + output[i] = (sbyte)(((ev[i] ^ 1) & ~mask) ^ 1); + } + + for (int i = _w; i < _p; ++i) + { + output[i] = (sbyte)(ev[i] & ~mask); + } + } + + } + + private void Hide(ref byte[] output, byte[] r_enc, sbyte[] r, byte[] pk, byte[] cache) + { + /* c,r_enc = Hide(r,pk,cache); cache is Hash4(pk) */ + + if (_lpr) + { + InputsEncode(ref r_enc, r); + } + else + { + ByteEncode(ref r_enc, r); + } + + Encrypt(ref output, r, pk); + + Array.Copy(output, 0, output, _ctBytes, output.Length - _ctBytes); + + HashConfirm(ref output, ref r_enc, ref pk, ref cache); + + } + + private void Generator(ref short[] output, byte[] seed) + { + uint[] L = Expand(seed); + + for (int i = 0; i < _p; i++) + { + output[i] = (short)((L[i] % _q) - _q12); + } + } + + private uint[] Expand(byte[] k) + { + byte[] L = new byte[_p * 4]; + byte[] cipherInput = new byte[_p * 4]; + uint[] L_uint = new uint[_p]; + + // AES256 CTR + BufferedBlockCipher cipher = new BufferedBlockCipher(new SicBlockCipher(new AesEngine())); + KeyParameter kp = new KeyParameter(k); + cipher.Init(true, new ParametersWithIV(kp, new byte[16])); + int len = cipher.ProcessBytes(cipherInput, 0, 4 * _p, L, 0); + len += cipher.DoFinal(L, len); + + for (int i = 0; i < _p; ++i) + { + uint L0 = L[4 * i]; + uint L1 = L[4 * i + 1]; + uint L2 = L[4 * i + 2]; + uint L3 = L[4 * i + 3]; + + L_uint[i] = L0 + (L1 << 8) + (L2 << 16) + (L3 << 24); + } + return L_uint; + } + + private void ShortRandom(ref sbyte[] output, SecureRandom random) + { + uint[] L = new uint[_p]; + + for (int i = 0; i < _p; ++i) + { + byte[] shortRandom = new byte[4]; + random.NextBytes(shortRandom); + L[i] = BitConverter.ToUInt32(shortRandom, 0); + } + ShortFromList(ref output, L); + } + + private void ShortFromList(ref sbyte[] output, uint[] L_in) + { + uint[] L = new uint[_p]; + + for (int i = 0; i < _w; ++i) + { + L[i] = (uint)(L_in[i] & -2); + } + + for (int i = _w; i < _p; ++i) + { + L[i] = (uint)(L_in[i] & -3) | 1; + } + + Array.Sort(L); + + for (int i = 0; i < _p; ++i) + { + output[i] = (sbyte)((L[i] & 3) - 1); + } + } + + private void RqMult(ref short[] output, short[] G, ref sbyte[] a) // aG, G, a -> h, f, g + { + short[] fg = new short[_p + _p - 1]; + short result; + + for (int i = 0; i < _p; ++i) + { + result = 0; + for (int j = 0; j <= i; ++j) + { + result = ArithmeticMod_q(result + (G[j] * a[i - j])); + } + + fg[i] = result; + } + + for (int i = _p; i < _p + _p - 1; ++i) + { + result = 0; + for (int j = i - _p + 1; j < _p; ++j) + { + result = ArithmeticMod_q(result + (G[j] * a[i - j])); + } + + fg[i] = result; + } + + for (int i = _p + _p - 2; i >= _p; --i) + { + fg[i - _p] = ArithmeticMod_q(fg[i - _p] + fg[i]); + fg[i - _p + 1] = ArithmeticMod_q(fg[i - _p + 1] + fg[i]); + } + + for (int i = 0; i < _p; ++i) + { + output[i] = fg[i]; + } + } + + private void Round(ref short[] output, short[] aG) + { + for (int i = 0; i < _p; ++i) + { + output[i] = (short)(aG[i] - ArithmeticMod_3(aG[i])); + } + } + + private void InputsRandom(ref sbyte[] output, SecureRandom random) + { + byte[] s = new byte[_inputsBytes]; + random.NextBytes(s); + for (int i = 0; i < _I; ++i) + { + output[i] = (sbyte)(1 & (s[i >> 3] >> (i & 7))); + } + } + + private void InputsEncode(ref byte[] output, sbyte[] r) + { + for (int i = 0; i < _inputsBytes; ++i) + { + output[i] = 0; + } + + for (int i = 0; i < _I; ++i) + { + output[i >> 3] |= (byte)(r[i] << (i & 7)); + } + } + + private void RoundedEncode(ref byte[] output, short[] A) + { + ushort[] R = new ushort[_p]; + ushort[] M = new ushort[_p]; + + for (int i = 0; i < _p; ++i) + { + R[i] = (ushort)(((A[i] + _q12) * 10923) >> 15); + } + + for (int i = 0; i < _p; ++i) + { + M[i] = (ushort)((_q + 2) / 3); + } + + List outputList = new List(); + + Encode(ref outputList, R, M, _p); + + Array.Copy(outputList.ToArray(), 0, output, 0, outputList.Count); + } + + private void RoundedDecode(ref short[] output, byte[] s) + { + List M = new List(_p); + List S = new List(s); + + for (int i = 0; i < _p; ++i) + { + M.Add((ushort)((_q + 2) / 3)); + } + + List decoded = Decode(S, M); + + for (int i = 0; i < _p; ++i) + { + output[i] = (short)((decoded[i] * 3) - _q12); + } + } + + private void ByteEncode(ref byte[] output, sbyte[] a) + { + sbyte x; + for (int i = 0; i < _p / 4; ++i) + { + int x0 = a[4 * i] + 1; + int x1 = (a[4 * i + 1] + 1) << 2; + int x2 = (a[4 * i + 2] + 1) << 4; + int x3 = (a[4 * i + 3] + 1) << 6; + x = (sbyte)(x0 + x1 + x2 + x3); + output[i] = (byte)x; + } + output[_p / 4] = (byte)(a[_p - 1] + 1); + } + + private void ByteDecode(ref sbyte[] output, byte[] s) + { + byte x; + for (int i = 0; i < _p / 4; ++i) + { + x = s[i]; + output[i * 4] = (sbyte)((x & 3) - 1); + x >>= 2; + output[i * 4 + 1] = (sbyte)((x & 3) - 1); + x >>= 2; + output[i * 4 + 2] = (sbyte)((x & 3) - 1); + x >>= 2; + output[i * 4 + 3] = (sbyte)((x & 3) - 1); + } + + x = s[_p / 4]; + output[_p / 4 * 4] = (sbyte)((x & 3) - 1); + } + + private void TopEncode(ref byte[] output, sbyte[] T) + { + for (int i = 0; i < _topBytes; ++i) + { + output[i] = (byte)(T[2 * i] + (T[2 * i + 1] << 4)); + } + } + + private void TopDecode(ref sbyte[] output, byte[] s) + { + for (int i = 0; i < _topBytes; ++i) + { + output[2 * i] = (sbyte)(s[i] & 15); + output[2 * i + 1] = (sbyte)(s[i] >> 4); + } + } + + private void HashShort(ref sbyte[] output, sbyte[] r) + { + byte[] s = new byte[_inputsBytes]; + byte[] h = new byte[_hashBytes]; + uint[] L = new uint[_p]; + + InputsEncode(ref s, r); + HashPrefix(ref h, 5, ref s, s.Length); + L = Expand(h); + ShortFromList(ref output, L); + } + + private void HashPrefix(ref byte[] output, int b, ref byte[] input, int inlen) + { + byte[] x = new byte[inlen + 1]; + byte[] h = new byte[64]; + + x[0] = (byte)b; + + for (int i = 0; i < inlen; ++i) + { + x[i + 1] = input[i]; + } + + Sha512Digest sha512 = new Sha512Digest(); + sha512.BlockUpdate(x, 0, x.Length); + sha512.DoFinal(h, 0); + + Array.Copy(h, 0, output, output.Length - 32, 32); + } + + private void HashConfirm(ref byte[] output, ref byte[] r, ref byte[] pk, ref byte[] cache) + { + + byte[] x; + + if (_lpr) + { + + x = new byte[_inputsBytes + _hashBytes]; + + + for (int i = 0; i < _inputsBytes; ++i) + { + x[i] = r[i]; + } + + for (int i = 0; i < _hashBytes; ++i) + { + x[_inputsBytes + i] = cache[i]; + } + + } + else + { + x = new byte[_hashBytes*2]; + + byte[] prefix = new byte[_hashBytes]; + + HashPrefix(ref prefix, 3, ref r, _inputsBytes); + + Array.Copy(prefix, 0, x, 0, _hashBytes); + + for (int i = 0; i < _hashBytes; ++i) + { + x[_hashBytes + i] = cache[i]; + } + } + HashPrefix(ref output, 2, ref x, x.Length); + + } + + private void HashSession(ref byte[] output, int b, byte[] y, byte[] z) + { + byte[] x; + + if (_lpr) + { + x = new byte[_inputsBytes + _ciphertextsBytes + _confirmBytes]; + + for (int i = 0; i < _inputsBytes; ++i) + { + x[i] = y[i]; + } + + for (int i = 0; i < _ciphertextsBytes + _confirmBytes; ++i) + { + x[_inputsBytes + i] = z[i]; + } + } + else + { + x = new byte[_hashBytes + _ciphertextsBytes + _confirmBytes]; + + byte[] prefix = new byte[_hashBytes]; + HashPrefix(ref prefix, 3, ref y, _inputsBytes); + Array.Copy(prefix, 0, x, 0, _hashBytes); + + for (int i = 0; i < _ciphertextsBytes + _confirmBytes; ++i) + { + x[_hashBytes + i] = z[i]; + } + } + + HashPrefix(ref output, b, ref x, x.Length); + } + + private int NegativeMask(short x) + { + return (x < 0) ? -1 : 0; + } + + private int ctDiffMask(byte[] c, byte[] c2) + { + int x = c.Length ^ c2.Length; + for (int i = 0; i < c.Length && i < c2.Length; ++i) + { + x |= c[i] ^ c2[i]; + } + + // Return 0 if matching, else -1 + return x == 0 ? 0 : -1; + } + + // Arithmetics + double mod(double a, double b) + { + return a - b * System.Math.Floor(a / b); + } + + private short ArithmeticMod_q(int x) // Fq_freeze + { + return (short)((mod(x + _q12, _q)) - _q12); + } + + private short ArithmeticMod_3(int x) // F3_freeze + { + return (short)(mod(x + 1, 3) - 1); + } + + private sbyte Top(int C) + { + return (sbyte)((_tau1 * (C + _tau0) + 16384) >> 15); + } + + private short Right(sbyte T) + { + int freeze = _tau3 * T - _tau2; + return (short)(mod(freeze + _q12, _q) - _q12); + } + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemExtractor.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemExtractor.cs new file mode 100644 index 000000000..9e3c65b10 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemExtractor.cs @@ -0,0 +1,35 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Pqc.Crypto.Frodo; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimeKEMExtractor : IEncapsulatedSecretExtractor + { + private NtruPrimeEngine _pEngine; + private NtruPrimeKeyParameters _pKey; + + public NtruPrimeKEMExtractor(NtruPrimeKeyParameters privParams) + { + this._pKey = privParams; + InitCipher(_pKey.Parameters); + } + + private void InitCipher(NtruPrimeParameters param) + { + _pEngine = param.PEngine; + } + + public byte[] ExtractSecret(byte[] encapsulation) + { + byte[] session_key = new byte[_pEngine.SessionKeySize]; + _pEngine.kem_dec(session_key, encapsulation, ((NtruPrimePrivateKeyParameters)_pKey).privKey); + return session_key; + } + + public int GetInputSize() + { + return _pEngine.CipherTextSize; + } + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemGenerator.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemGenerator.cs new file mode 100644 index 000000000..9c2e0461b --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKemGenerator.cs @@ -0,0 +1,77 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimeKemGenerator : IEncapsulatedSecretGenerator + { + private SecureRandom sr; + + public NtruPrimeKemGenerator(SecureRandom sr) + { + this.sr = sr; + } + + public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey) + { + NtruPrimePublicKeyParameters key = (NtruPrimePublicKeyParameters)recipientKey; + NtruPrimeEngine pEngine = key.Parameters.PEngine; + byte[] cipherText = new byte[pEngine.CipherTextSize]; + byte[] sessionKey = new byte[pEngine.SessionKeySize]; + pEngine.kem_enc(cipherText, sessionKey,key.pubKey, sr); + return new NtruPrimeKemGenerator.SecretWithEncapsulationImpl(sessionKey, cipherText); + } + + public class SecretWithEncapsulationImpl : ISecretWithEncapsulation + { + private volatile bool hasBeenDestroyed = false; + + private byte[] sessionKey; + private byte[] cipherText; + + public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipherText) + { + this.sessionKey = sessionKey; + this.cipherText = cipherText; + } + + public byte[] GetSecret() + { + CheckDestroyed(); + return Arrays.Clone(sessionKey); + } + + public byte[] GetEncapsulation() + { + return Arrays.Clone(cipherText); + } + + public void Dispose() + { + if (!hasBeenDestroyed) + { + hasBeenDestroyed = true; + Arrays.Clear(sessionKey); + Arrays.Clear(cipherText); + } + } + + public bool IsDestroyed() + { + return hasBeenDestroyed; + } + + void CheckDestroyed() + { + if (IsDestroyed()) + { + throw new Exception("data has been destroyed"); + } + } + + } + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyGenerationParameters.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyGenerationParameters.cs new file mode 100644 index 000000000..56e7315ae --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyGenerationParameters.cs @@ -0,0 +1,18 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruKeyGenerationParameters : KeyGenerationParameters + { + private NtruPrimeParameters _pParameters; + + public NtruKeyGenerationParameters(SecureRandom random, NtruPrimeParameters ntruPParameters) : base(random,256) + { + this._pParameters = ntruPParameters; + } + + public NtruPrimeParameters PParameters => _pParameters; + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyPairGenerator.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyPairGenerator.cs new file mode 100644 index 000000000..eff4828f8 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyPairGenerator.cs @@ -0,0 +1,69 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruKeyPairGenerator + { + private NtruKeyGenerationParameters ntruParams; + + private int p; + private int q; + + private SecureRandom random; + + private void Initialize(KeyGenerationParameters param) + { + ntruParams = (NtruKeyGenerationParameters) param; + random = param.Random; + + // n = ntruParams.Parameters.N; + + p = ntruParams.PParameters.P; + q = ntruParams.PParameters.Q; + + } + + private AsymmetricCipherKeyPair GenKeyPair() + { + NtruPrimeEngine pEngine = ntruParams.PParameters.PEngine; + byte[] sk = new byte[pEngine.PrivateKeySize]; + byte[] pk = new byte[pEngine.PublicKeySize]; + pEngine.kem_keypair( pk,sk,random); + + NtruPrimePublicKeyParameters pubKey = new NtruPrimePublicKeyParameters(ntruParams.PParameters, pk); + NtruPrimePrivateKeyParameters privKey = new NtruPrimePrivateKeyParameters(ntruParams.PParameters, sk); + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + + public void Init(KeyGenerationParameters param) + { + this.Initialize(param); + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + return GenKeyPair(); + } + + // private AsymmetricCipherKeyPair GenKeyPair() + // { + // NtruEngine engine = ntruParams.Parameters.Engine; + // byte[] sk = new byte[engine.PrivateKeySize]; + // byte[] pk = new byte[engine.PublicKeySize]; + // + // + // } + // + // public void Init(KeyGenerationParameters param) + // { + // this.Initialize(param); + // } + // + // public AsymmetricCipherKeyPair GenerateKeyPair() + // { + // return GenKeyPair(); + // } + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyParameters.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyParameters.cs new file mode 100644 index 000000000..fb77d8567 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeKeyParameters.cs @@ -0,0 +1,17 @@ +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimeKeyParameters : AsymmetricKeyParameter + { + private NtruPrimeParameters _pParameters; + + public NtruPrimeKeyParameters(bool isPrivate, NtruPrimeParameters pParameters) : base(isPrivate) + { + this._pParameters = pParameters; + } + + public NtruPrimeParameters Parameters => _pParameters; + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimeParameters.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimeParameters.cs new file mode 100644 index 000000000..3cf691565 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimeParameters.cs @@ -0,0 +1,72 @@ +using System; +using System.ComponentModel; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Modes; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimeParameters : ICipherParameters + { + + private String name; + private int p; + private int q; + private int _roundedBytes; + private bool LPR; + private int _w; + private int _rqBytes; + private int _tau0; + private int _tau1; + private int _tau2; + private int _tau3; + private int _skBytes; + private int _pkBytes; + private int _ctBytes; + private NtruPrimeEngine _pEngine; + + public NtruPrimeParameters(String name, int p, int q, bool LPR, int w, int tau0, + int tau1, int tau2, int tau3, int skBytes, int pkBytes, int ctBytes, int roundedBytes, int rqBytes) + { + this.name = name; + this.p = p; + this.q = q; + this.LPR = LPR; + this._w = w; + this._tau0 = tau0; + this._tau1 = tau1; + this._tau2 = tau2; + this._tau3 = tau3; + + // KEM Parameters + this._roundedBytes = roundedBytes; + this._rqBytes = rqBytes; + this._skBytes = skBytes; + this._pkBytes = pkBytes; + this._ctBytes = ctBytes; + this._pEngine = new NtruPrimeEngine(p,q, LPR, w, tau0, tau1, tau2, tau3, skBytes, pkBytes, ctBytes, roundedBytes, rqBytes); + } + + public static NtruPrimeParameters ntrulpr653 = new NtruPrimeParameters("NTRU_LPRime_653", 653, 4621, true, 252, 2175,113,2031,290,1125,897,1025, 865, -1); + public static NtruPrimeParameters ntrulpr761 = new NtruPrimeParameters("NTRU_LPRime_761", 761, 4591, true, 250, 2156,114,2007,287,1294,1039,1167, 1007, -1); + public static NtruPrimeParameters ntrulpr857 = new NtruPrimeParameters("NTRU_LPRime_857", 857, 5167, true, 281, 2433,101,2265,324,1463,1184,1312, 1152, -1); + public static NtruPrimeParameters ntrulpr953 = new NtruPrimeParameters("NTRU_LPRime_953", 953, 6343, true, 345, 2997,82,2798,400,1652,1349,1477, 1317, -1); + public static NtruPrimeParameters ntrulpr1013 = new NtruPrimeParameters("NTRU_LPRime_1013", 1013, 7177, true, 392, 3367,73,3143,449,1773,1455,1583, 1423, -1); + public static NtruPrimeParameters ntrulpr1277 = new NtruPrimeParameters("NTRU_LPRime_1277", 1277, 7879, true, 429, 3724,66,3469,496,2231,1847,1975, 1815, -1); + + public static NtruPrimeParameters sntrup653 = new NtruPrimeParameters("SNTRU_Prime_653", 653, 4621, false, 288, -1,-1,-1,-1,1518,994,897, 865, 994); + public static NtruPrimeParameters sntrup761 = new NtruPrimeParameters("SNTRU_Prime_761", 761, 4591, false, 286, -1,-1,-1,-1,1763,1158,1039, 1007, 1158); + public static NtruPrimeParameters sntrup857 = new NtruPrimeParameters("SNTRU_Prime_857", 857, 5167, false, 322, -1,-1,-1,-1,1999,1322,1184, 1152, 1322); + public static NtruPrimeParameters sntrup953 = new NtruPrimeParameters("SNTRU_Prime_953", 953, 6343, false, 396, -1,-1,-1,-1,2254,1505,1349, 1317, 1505); + public static NtruPrimeParameters sntrup1013 = new NtruPrimeParameters("SNTRU_Prime_1013", 1013, 7177, false, 448, -1,-1,-1,-1,2417,1623,1455, 1423, 1623); + public static NtruPrimeParameters sntrup1277 = new NtruPrimeParameters("SNTRU_Prime_1277", 1277, 7879, false, 492, -1,-1,-1,-1,3059,2067,1847, 1815, 2067); + + public int P => p; + public bool lpr => LPR; + + public int Q => q; + + internal NtruPrimeEngine PEngine => _pEngine; + + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimePrivateKeyParameters.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimePrivateKeyParameters.cs new file mode 100644 index 000000000..69cfc4744 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimePrivateKeyParameters.cs @@ -0,0 +1,20 @@ +using System; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimePrivateKeyParameters : NtruPrimeKeyParameters + { + internal byte[] privKey; + + public NtruPrimePrivateKeyParameters(NtruPrimeParameters pParameters, byte[] privKey) : base(true, pParameters) + { + this.privKey = Arrays.Clone(privKey); + } + + public byte[] GetEncoded() + { + return Arrays.Clone(privKey); + } + } +} diff --git a/crypto/src/pqc/crypto/ntruprime/NtruPrimePublicKeyParameters.cs b/crypto/src/pqc/crypto/ntruprime/NtruPrimePublicKeyParameters.cs new file mode 100644 index 000000000..265382455 --- /dev/null +++ b/crypto/src/pqc/crypto/ntruprime/NtruPrimePublicKeyParameters.cs @@ -0,0 +1,19 @@ +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pqc.Crypto.NtruPrime +{ + public class NtruPrimePublicKeyParameters : NtruPrimeKeyParameters + { + internal byte[] pubKey; + + public byte[] GetEncoded() + { + return Arrays.Clone(pubKey); + } + + public NtruPrimePublicKeyParameters(NtruPrimeParameters pParameters, byte[] pubKey) : base(false,pParameters) + { + this.pubKey = Arrays.Clone(pubKey); + } + } +} -- cgit 1.5.1