summary refs log tree commit diff
path: root/crypto/src/pqc/crypto/ntru/NtruKemExtractor.cs
blob: aba22a0f4fc0736cee992b3976af4efd646b7ac0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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 EncapsulationLength => _parameters.ParameterSet.NtruCiphertextBytes();
    }
}