Botan 3.5.0
Crypto and TLS for C&
lm_ots.h
Go to the documentation of this file.
1/**
2 * LM-OTS - Leighton-Micali One-Time Signatures (RFC 8554 Section 4)
3 * (C) 2023 Jack Lloyd
4 * 2023 Fabian Albert, Philippe Lieser - Rohde & Schwarz Cybersecurity GmbH
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9#ifndef BOTAN_LM_OTS_H_
10#define BOTAN_LM_OTS_H_
11
12#include <botan/hash.h>
13#include <botan/internal/stl_util.h>
14
15#include <span>
16#include <string>
17#include <string_view>
18#include <vector>
19
20namespace Botan {
21
22/**
23 * @brief Seed of the LMS tree, used to generate the LM-OTS private keys.
24 */
25using LMS_Seed = Strong<secure_vector<uint8_t>, struct LMS_SEED_>;
26
27/**
28 * @brief One node within one LM-OTS hash chain.
29 */
30using LMOTS_Node = Strong<secure_vector<uint8_t>, struct LMOTS_Node_>;
31
32/**
33 * @brief The K value from the LM-OTS public key.
34 */
35using LMOTS_K = Strong<std::vector<uint8_t>, struct LMOTS_K_>;
36
37/**
38 * @brief Byte vector of an LM-OTS signature.
39 */
40using LMOTS_Signature_Bytes = Strong<std::vector<uint8_t>, struct LMOTS_Signature_Bytes_>;
41
42/**
43 * @brief The index of a node within a specific LMS tree layer
44 */
46
47/**
48 * @brief The identifier of an LMS tree (I in RFC 8554)
49 */
50using LMS_Identifier = Strong<std::vector<uint8_t>, struct LMS_Identifier_>;
51
52/**
53 * @brief A message that is signed with an LMS tree
54 */
55using LMS_Message = Strong<std::vector<uint8_t>, struct LMS_Message_>;
56
57/**
58 * @brief Enum of available LM-OTS algorithm types.
59 *
60 * The supported parameter sets are defined in RFC 8554 Section 4.1. and
61 * draft-fluhrer-lms-more-parm-sets-11 Section 4. HSS/LMS typecodes are
62 * introduced in RFC 8554 Section 3.2. and their format specified in
63 * Section 3.3.
64 */
65enum class LMOTS_Algorithm_Type : uint32_t {
66 // --- RFC 8554 ---
67 RESERVED = 0x00,
68
69 // SHA-256 based
70 SHA256_N32_W1 = 0x01,
71 SHA256_N32_W2 = 0x02,
72 SHA256_N32_W4 = 0x03,
73 SHA256_N32_W8 = 0x04,
74
75 // --- draft-fluhrer-lms-more-parm-sets-11 ---
76 // SHA-256/192 based
77 SHA256_N24_W1 = 0x05,
78 SHA256_N24_W2 = 0x06,
79 SHA256_N24_W4 = 0x07,
80 SHA256_N24_W8 = 0x08,
81
82 // SHAKE-256/256 based
83 SHAKE_N32_W1 = 0x09,
84 SHAKE_N32_W2 = 0x0a,
85 SHAKE_N32_W4 = 0x0b,
86 SHAKE_N32_W8 = 0x0c,
87
88 // SHAKE-256/192 based
89 SHAKE_N24_W1 = 0x0d,
90 SHAKE_N24_W2 = 0x0e,
91 SHAKE_N24_W4 = 0x0f,
92 SHAKE_N24_W8 = 0x10,
93};
94
95/**
96 * @brief The LM-OTS parameters.
97 *
98 * See RFC 8554 Section 4.1.
99 */
101 public:
102 /**
103 * @brief Create the LM-OTS parameters from a known algorithm type.
104 * @throws Decoding_Error If the algorithm type is unknown
105 */
106 static LMOTS_Params create_or_throw(LMOTS_Algorithm_Type type);
107
108 /**
109 * @brief Create the LM-OTS parameters from a hash function and width.
110 *
111 * @param hash_name tha name of the hash function to use.
112 * @param w the width (in bits) of the Winternitz coefficients.
113 * @throws Decoding_Error If the algorithm type is unknown
114 */
115 static LMOTS_Params create_or_throw(std::string_view hash_name, uint8_t w);
116
117 /**
118 * @brief Returns the LM-OTS algorithm type.
119 */
120 LMOTS_Algorithm_Type algorithm_type() const { return m_algorithm_type; }
121
122 /**
123 * @brief The number of bytes of the output of the hash function.
124 */
125 size_t n() const { return m_n; }
126
127 /**
128 * @brief The width (in bits) of the Winternitz coefficients.
129 */
130 uint8_t w() const { return m_w; }
131
132 /**
133 * @brief The maximum the winternitz coefficients can have.
134 */
135 uint8_t coef_max() const { return (1 << m_w) - 1; }
136
137 /**
138 * @brief The number of n-byte string elements that make up the LM-OTS signature.
139 */
140 uint16_t p() const { return m_p; }
141
142 /**
143 * @brief The number of left-shift bits used in the checksum function Cksm.
144 */
145 uint8_t ls() const { return m_ls; }
146
147 /**
148 * @brief Name of the hash function to use.
149 */
150 const std::string& hash_name() const { return m_hash_name; }
151
152 /**
153 * @brief Construct a new hash instance for the OTS instance.
154 */
155 std::unique_ptr<HashFunction> hash() const { return HashFunction::create_or_throw(hash_name()); }
156
157 private:
158 /**
159 * @brief Construct a new LM-OTS parameter object.
160 *
161 * @param algorithm_type The algorithm type.
162 * @param hash_name The name of the hash function to use.
163 * @param w The width (in bits) of the Winternitz coefficients.
164 */
165 LMOTS_Params(LMOTS_Algorithm_Type algorithm_type, std::string_view hash_name, uint8_t w);
166
167 LMOTS_Algorithm_Type m_algorithm_type;
168 size_t m_n;
169 uint8_t m_w;
170 uint16_t m_p;
171 uint8_t m_ls;
172 std::string m_hash_name;
173};
174
175/**
176 * @brief Representation of a LM-OTS signature.
177 */
179 public:
180 /**
181 * @brief Parse a LM-OTS signature.
182 *
183 * @param slicer The private key bytes to parse.
184 * @return The LM-OTS signature.
185 * @throws Decoding_Error If parsing the signature fails.
186 */
187 static LMOTS_Signature from_bytes_or_throw(BufferSlicer& slicer);
188
189 /**
190 * @brief Returns the LM-OTS algorithm type.
191 */
192 LMOTS_Algorithm_Type algorithm_type() const { return m_algorithm_type; }
193
194 /**
195 * @brief The n-byte randomizer of the signature.
196 */
197 std::span<const uint8_t> C() const { return m_C; }
198
199 /**
200 * @brief Returns the part of the signature for @p chain_idx.
201 */
202 StrongSpan<const LMOTS_Node> y(uint16_t chain_idx) const { return m_y.at(chain_idx); }
203
204 /**
205 * @brief The expected size of the signature.
206 */
207 static size_t size(const LMOTS_Params& params) { return 4 + params.n() * (params.p() + 1); }
208
209 private:
210 LMOTS_Signature(LMOTS_Algorithm_Type lmots_type, std::vector<uint8_t> C, std::vector<uint8_t> y_buffer);
211
212 LMOTS_Algorithm_Type m_algorithm_type;
213 std::vector<uint8_t> m_C;
214 std::vector<uint8_t> m_y_buffer;
215 std::vector<StrongSpan<const LMOTS_Node>> m_y;
216};
217
218/**
219 * @brief Base class for LMOTS private and public key. Contains the parameters for
220 * the specific OTS instance
221 */
223 public:
224 /**
225 * @brief Constructor storing the specific OTS parameters
226 */
227 OTS_Instance(const LMOTS_Params& params, const LMS_Identifier& identifier, LMS_Tree_Node_Idx q) :
228 m_params(params), m_identifier(identifier), m_q(q) {}
229
230 /**
231 * @brief The LMOTS parameters
232 */
233 const LMOTS_Params& params() const { return m_params; }
234
235 /**
236 * @brief The LMS identifier of the LMS tree containing this OTS instance ('I' in RFC 8554)
237 */
238 const LMS_Identifier& identifier() const { return m_identifier; }
239
240 /**
241 * @brief The index of the LMS tree leaf associated with this OTS instance
242 */
243 LMS_Tree_Node_Idx q() const { return m_q; }
244
245 private:
246 LMOTS_Params m_params;
247 LMS_Identifier m_identifier;
249};
250
251/**
252 * @brief Representation of an LMOTS private key.
253 *
254 * Contains the OTS params, I, q, the secret LMS seed and its derived
255 * secret chain inputs (x[] in RFC 8554 4.2)
256 */
258 public:
259 /**
260 * @brief Derive a LMOTS private key for a given @p seed.
261 *
262 * Implements RFC 8554 4.2 using derivation of Appendix A
263 */
264 LMOTS_Private_Key(const LMOTS_Params& params,
265 const LMS_Identifier& identifier,
267 const LMS_Seed& seed);
268
269 /**
270 * @brief The secret chain input at a given chain index. (x[] in RFC 8554 4.2).
271 */
272 const LMOTS_Node& chain_input(uint16_t chain_idx) const { return m_ots_sk.at(chain_idx); }
273
274 /**
275 * @brief Generate a new LMOTS signature.
276 *
277 * Defined in RFC 8554 4.5
278 */
279 void sign(StrongSpan<LMOTS_Signature_Bytes> out_sig, const LMS_Message& msg) const;
280
281 private:
282 /**
283 * @brief Derive random value C
284 *
285 * Derive the randomized value C as in the reference implementation (cisco):
286 * C = HASH(I || Q || 0xFFFD || 0xFF || SEED)
287 *
288 * Note that this derivation is important if we do not store the signature of root LMS nodes
289 * in the private key. Otherwise these root nodes are signed twice with different C values,
290 * resulting in a broken OTS signature.
291 */
292 void derive_random_C(std::span<uint8_t> out, HashFunction& hash) const;
293
294 LMS_Seed m_seed;
295 std::vector<LMOTS_Node> m_ots_sk;
296};
297
298/**
299 * @brief Representation of an OTS public key.
300 *
301 * Contains the public key bytes
302 * as defined in RFC 8554 4.3:
303 *
304 * u32str(type) || I || u32str(q) || K
305 */
307 public:
308 /**
309 * @brief Derivivation of an LMOTS public key using an LMOTS_Private_Key as defined
310 * in RFC 8554 4.3
311 */
312 LMOTS_Public_Key(const LMOTS_Private_Key& lmots_sk);
313
314 /**
315 * @brief Construct a new LMOTS public key object using the bytes.
316 *
317 * Note that the passed params, identifier and
318 * q value should match with the prefix in @p pub_key_bytes.
319 */
320 LMOTS_Public_Key(const LMOTS_Params& params, const LMS_Identifier& identifier, LMS_Tree_Node_Idx q, LMOTS_K K) :
321 OTS_Instance(params, identifier, q), m_K(std::move(K)) {}
322
323 /**
324 * @brief The public key final hash value (K in RFC 8554 4.3 )
325 *
326 * @return const LMOTS_K&
327 */
328 const LMOTS_K& K() const { return m_K; }
329
330 private:
331 LMOTS_K m_K;
332};
333
334/**
335 * @brief Compute a public key candidate for an OTS-signature-message pair and the OTS instance parameters.
336 *
337 * Defined in RFC 8554 4.6 - Algorithm 4b
338 */
339BOTAN_TEST_API LMOTS_K lmots_compute_pubkey_from_sig(const LMOTS_Signature& sig,
340 const LMS_Message& msg,
341 const LMS_Identifier& identifier,
343
344} // namespace Botan
345
346#endif
The LM-OTS parameters.
Definition lm_ots.h:100
uint8_t coef_max() const
The maximum the winternitz coefficients can have.
Definition lm_ots.h:135
std::unique_ptr< HashFunction > hash() const
Construct a new hash instance for the OTS instance.
Definition lm_ots.h:155
LMOTS_Algorithm_Type algorithm_type() const
Returns the LM-OTS algorithm type.
Definition lm_ots.h:120
size_t n() const
The number of bytes of the output of the hash function.
Definition lm_ots.h:125
uint8_t w() const
The width (in bits) of the Winternitz coefficients.
Definition lm_ots.h:130
const std::string & hash_name() const
Name of the hash function to use.
Definition lm_ots.h:150
uint8_t ls() const
The number of left-shift bits used in the checksum function Cksm.
Definition lm_ots.h:145
uint16_t p() const
The number of n-byte string elements that make up the LM-OTS signature.
Definition lm_ots.h:140
Representation of an LMOTS private key.
Definition lm_ots.h:257
const LMOTS_Node & chain_input(uint16_t chain_idx) const
The secret chain input at a given chain index. (x[] in RFC 8554 4.2).
Definition lm_ots.h:272
Representation of an OTS public key.
Definition lm_ots.h:306
const LMOTS_K & K() const
The public key final hash value (K in RFC 8554 4.3 )
Definition lm_ots.h:328
LMOTS_Public_Key(const LMOTS_Params &params, const LMS_Identifier &identifier, LMS_Tree_Node_Idx q, LMOTS_K K)
Construct a new LMOTS public key object using the bytes.
Definition lm_ots.h:320
Representation of a LM-OTS signature.
Definition lm_ots.h:178
static size_t size(const LMOTS_Params &params)
The expected size of the signature.
Definition lm_ots.h:207
StrongSpan< const LMOTS_Node > y(uint16_t chain_idx) const
Returns the part of the signature for chain_idx.
Definition lm_ots.h:202
LMOTS_Algorithm_Type algorithm_type() const
Returns the LM-OTS algorithm type.
Definition lm_ots.h:192
std::span< const uint8_t > C() const
The n-byte randomizer of the signature.
Definition lm_ots.h:197
Base class for LMOTS private and public key. Contains the parameters for the specific OTS instance.
Definition lm_ots.h:222
const LMS_Identifier & identifier() const
The LMS identifier of the LMS tree containing this OTS instance ('I' in RFC 8554)
Definition lm_ots.h:238
OTS_Instance(const LMOTS_Params &params, const LMS_Identifier &identifier, LMS_Tree_Node_Idx q)
Constructor storing the specific OTS parameters.
Definition lm_ots.h:227
LMS_Tree_Node_Idx q() const
The index of the LMS tree leaf associated with this OTS instance.
Definition lm_ots.h:243
const LMOTS_Params & params() const
The LMOTS parameters.
Definition lm_ots.h:233
#define BOTAN_TEST_API
Definition compiler.h:51
LMOTS_K lmots_compute_pubkey_from_sig(const LMOTS_Signature &sig, const LMS_Message &msg, const LMS_Identifier &identifier, LMS_Tree_Node_Idx q)
Compute a public key candidate for an OTS-signature-message pair and the OTS instance parameters.
Definition lm_ots.cpp:325
Strong< std::vector< uint8_t >, struct LMOTS_K_ > LMOTS_K
The K value from the LM-OTS public key.
Definition lm_ots.h:35
Strong< std::vector< uint8_t >, struct LMS_Identifier_ > LMS_Identifier
The identifier of an LMS tree (I in RFC 8554)
Definition lm_ots.h:50
LMOTS_Algorithm_Type
Enum of available LM-OTS algorithm types.
Definition lm_ots.h:65
Strong< std::vector< uint8_t >, struct LMS_Message_ > LMS_Message
A message that is signed with an LMS tree.
Definition lm_ots.h:55
Strong< uint32_t, struct LMS_Tree_Node_Idx_, EnableArithmeticWithPlainNumber > LMS_Tree_Node_Idx
The index of a node within a specific LMS tree layer.
Definition lm_ots.h:45