summary refs log tree commit diff
path: root/crypto/src/pqc/crypto/lms/HSSSignature.cs
blob: bbf0c6f0f44f0dcc7d62bc36f8d22e2cf8452a0d (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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using System;
using System.IO;
using System.Text;

using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;

namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
    public sealed class HssSignature
        : IEncodable
    {
        private readonly int m_lMinus1;
        private readonly LmsSignedPubKey[] m_signedPubKey;
        private readonly LmsSignature m_signature;

        // TODO[api] signedPubKeys
        public HssSignature(int lMinus1, LmsSignedPubKey[] signedPubKey, LmsSignature signature)
        {
            m_lMinus1 = lMinus1;
            m_signedPubKey = signedPubKey;
            m_signature = signature;
        }

        /**
         * @param src byte[], InputStream or HSSSignature
         * @param L   The HSS depth, available from public key.
         * @return An HSSSignature instance.
         * @throws IOException
         */
        public static HssSignature GetInstance(object src, int L)
        {
            if (src is HssSignature hssSignature)
                return hssSignature;

            if (src is BinaryReader binaryReader)
                return Parse(L, binaryReader);

            if (src is Stream stream)
                return Parse(L, stream, leaveOpen: true);

            if (src is byte[] bytes)
                return Parse(L, new MemoryStream(bytes, false), leaveOpen: false);

            throw new ArgumentException($"cannot parse {src}");
        }

        internal static HssSignature Parse(int L, BinaryReader binaryReader)
        {
            int lMinus1 = BinaryReaders.ReadInt32BigEndian(binaryReader);
            if (lMinus1 != L - 1)
                throw new Exception("nspk exceeded maxNspk");

            var signedPubKeys = new LmsSignedPubKey[lMinus1];
            for (int t = 0; t < lMinus1; t++)
            {
                var signature = LmsSignature.Parse(binaryReader);
                var publicKey = LmsPublicKeyParameters.Parse(binaryReader);

                signedPubKeys[t] = new LmsSignedPubKey(signature, publicKey);
            }

            {
                var signature = LmsSignature.Parse(binaryReader);

                return new HssSignature(lMinus1, signedPubKeys, signature);
            }
        }

        private static HssSignature Parse(int L, Stream stream, bool leaveOpen)
        {
            using (var binaryReader = new BinaryReader(stream, Encoding.UTF8, leaveOpen))
            {
                return Parse(L, binaryReader);
            }
        }

        public int GetLMinus1()
        {
            return m_lMinus1;
        }

        // FIXME
        public LmsSignedPubKey[] GetSignedPubKeys()
        {
            return m_signedPubKey;
        }

        public LmsSignature Signature => m_signature;

        public override bool Equals(object other)
        {
            if (this == other)
                return true;
            if (!(other is HssSignature that))
                return false;

            if (this.m_lMinus1 != that.m_lMinus1)
                return false;

            if (this.m_signedPubKey.Length != that.m_signedPubKey.Length)
                return false;

            for (int t = 0; t < m_signedPubKey.Length; t++)
            {
                if (!this.m_signedPubKey[t].Equals(that.m_signedPubKey[t]))
                    return false;
            }

            return Equals(this.m_signature, that.m_signature);
        }

        public override int GetHashCode()
        {
            int result = m_lMinus1;
            result = 31 * result + m_signedPubKey.GetHashCode();
            result = 31 * result + (m_signature != null ? m_signature.GetHashCode() : 0);
            return result;
        }

        public byte[] GetEncoded()
        {
            Composer composer = Composer.Compose();
            composer.U32Str(m_lMinus1);
            if (m_signedPubKey != null)
            {
                foreach (LmsSignedPubKey sigPub in m_signedPubKey)
                {
                    composer.Bytes(sigPub);
                }
            }

            composer.Bytes(m_signature);
            return composer.Build();
        }
    }
}