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