summary refs log tree commit diff
path: root/crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs')
-rw-r--r--crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs87
1 files changed, 87 insertions, 0 deletions
diff --git a/crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs b/crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs
new file mode 100644
index 000000000..4d730a3f1
--- /dev/null
+++ b/crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Diagnostics;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Pqc.Crypto.Ntru.Owcpa;
+using Org.BouncyCastle.Pqc.Crypto.Ntru.ParameterSets;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Ntru
+{
+    /// <summary>
+    /// NTRU secret encapsulation extractor.
+    /// </summary>
+    public class NtruKemExtractor : IEncapsulatedSecretExtractor
+    {
+        private readonly NtruParameters _parameters;
+        private readonly NtruPrivateKeyParameters _ntruPrivateKey;
+
+        public NtruKemExtractor(NtruPrivateKeyParameters ntruPrivateKey)
+        {
+            _parameters = ntruPrivateKey.Parameters;
+            _ntruPrivateKey = ntruPrivateKey;
+        }
+
+
+        public byte[] ExtractSecret(byte[] encapsulation)
+        {
+            Debug.Assert(_ntruPrivateKey != null);
+
+            NtruParameterSet parameterSet = _parameters.ParameterSet;
+
+            byte[] sk = _ntruPrivateKey.PrivateKey;
+            int i, fail;
+            byte[] rm;
+            byte[] buf = new byte[parameterSet.PrfKeyBytes + parameterSet.NtruCiphertextBytes()];
+
+            NtruOwcpa owcpa = new NtruOwcpa(parameterSet);
+            OwcpaDecryptResult owcpaResult = owcpa.Decrypt(encapsulation, _ntruPrivateKey.PrivateKey);
+            rm = owcpaResult.Rm;
+            fail = owcpaResult.Fail;
+
+            Sha3Digest sha3256 = new Sha3Digest(256);
+
+            byte[] k = new byte[sha3256.GetDigestSize()];
+
+            sha3256.BlockUpdate(rm, 0, rm.Length);
+            sha3256.DoFinal(k, 0);
+
+            /* shake(secret PRF key || input ciphertext) */
+            for (i = 0; i < parameterSet.PrfKeyBytes; i++)
+            {
+                buf[i] = sk[i + parameterSet.OwcpaSecretKeyBytes()];
+            }
+
+            for (i = 0; i < parameterSet.NtruCiphertextBytes(); i++)
+            {
+                buf[parameterSet.PrfKeyBytes + i] = encapsulation[i];
+            }
+
+            sha3256.Reset();
+            sha3256.BlockUpdate(buf, 0, buf.Length);
+            sha3256.DoFinal(rm, 0);
+
+            Cmov(k, rm, (byte)fail);
+
+            byte[] sharedKey = new byte[parameterSet.SharedKeyBytes];
+            Array.Copy(k, 0, sharedKey, 0, parameterSet.SharedKeyBytes);
+
+            Array.Clear(k, 0, k.Length);
+
+            return sharedKey;
+        }
+
+        private static void Cmov(byte[] r, byte[] x, byte b)
+        {
+            b = (byte)(~b + 1);
+            for (int i = 0; i < r.Length; i++)
+            {
+                r[i] ^= (byte)(b & (x[i] ^ r[i]));
+            }
+        }
+
+        public int GetInputSize()
+        {
+            return _parameters.ParameterSet.NtruCiphertextBytes();
+        }
+    }
+}
\ No newline at end of file