Botan 3.13.0
Crypto and TLS for C&
xmss_privatekey.cpp
Go to the documentation of this file.
1/*
2 * XMSS Private Key
3 * An XMSS: Extended Hash-Based Signature private key.
4 * The XMSS private key does not support the X509 and PKCS7 standard. Instead
5 * the raw format described in [1] is used.
6 *
7 * [1] XMSS: Extended Hash-Based Signatures,
8 * Request for Comments: 8391
9 * Release: May 2018.
10 * https://datatracker.ietf.org/doc/rfc8391/
11 *
12 * (C) 2016,2017,2018 Matthias Gierlings
13 * (C) 2019,2026 Jack Lloyd
14 * (C) 2023 René Meusel - Rohde & Schwarz Cybersecurity
15 *
16 * Botan is released under the Simplified BSD License (see license.txt)
17 **/
18
19#include <botan/xmss.h>
20
21#include <botan/ber_dec.h>
22#include <botan/der_enc.h>
23#include <botan/rng.h>
24#include <botan/internal/buffer_slicer.h>
25#include <botan/internal/concat_util.h>
26#include <botan/internal/int_utils.h>
27#include <botan/internal/loadstor.h>
28#include <botan/internal/stateful_key_index_registry.h>
29#include <botan/internal/xmss_common_ops.h>
30#include <botan/internal/xmss_hash.h>
31#include <botan/internal/xmss_signature_operation.h>
32
33#if defined(BOTAN_HAS_THREAD_UTILS)
34 #include <botan/internal/thread_pool.h>
35#endif
36
37namespace Botan {
38
39namespace {
40
41// fall back to raw decoding for previous versions, which did not encode an OCTET STRING
42secure_vector<uint8_t> extract_raw_private_key(std::span<const uint8_t> key_bits, const XMSS_Parameters& xmss_params) {
44
45 // The public part of the input key bits was already parsed, so we can
46 // decide depending on the buffer length whether this must be BER decoded.
47 if(key_bits.size() == xmss_params.raw_private_key_size() ||
48 key_bits.size() == xmss_params.raw_legacy_private_key_size()) {
49 raw_key.assign(key_bits.begin(), key_bits.end());
50 } else {
52 }
53
54 return raw_key;
55}
56
57/**
58 * Bundles the inputs needed to compute the internal nodes (and root) of the
59 * XMSS Merkle tree: the parameters and the public/private seeds. The same
60 * computation is needed both during key generation (before the immutable
61 * public key exists) and during signing (auth path computation), so it is
62 * factored out here and shared via thin wrappers on XMSS_PrivateKey.
63 */
64class XMSS_Tree_Builder final {
65 public:
66 XMSS_Tree_Builder(const XMSS_Parameters& xmss_params,
67 WOTS_Derivation_Method wots_derivation_method,
68 const secure_vector<uint8_t>& public_seed,
69 const secure_vector<uint8_t>& private_seed) :
70 m_xmss_params(xmss_params),
71 m_wots_params(xmss_params.wots_parameters()),
72 m_wots_derivation_method(wots_derivation_method),
73 m_public_seed(public_seed),
74 m_private_seed(private_seed) {}
75
76 secure_vector<uint8_t> tree_hash(size_t start_idx,
77 size_t target_node_height,
78 const XMSS_Address& adrs,
79 XMSS_Hash& hash) const;
80
81 void tree_hash_subtree(secure_vector<uint8_t>& result,
82 size_t start_idx,
83 size_t target_node_height,
84 XMSS_Address& adrs,
85 XMSS_Hash& hash) const;
86
87 XMSS_WOTS_PublicKey wots_public_key_for(const XMSS_Address& adrs, XMSS_Hash& hash) const;
88 XMSS_WOTS_PrivateKey wots_private_key_for(const XMSS_Address& adrs, XMSS_Hash& hash) const;
89
90 const XMSS_Parameters& xmss_parameters() const { return m_xmss_params; }
91
92 const secure_vector<uint8_t>& public_seed() const { return m_public_seed; }
93
94 private:
95 const XMSS_Parameters& m_xmss_params;
96 XMSS_WOTS_Parameters m_wots_params;
97 WOTS_Derivation_Method m_wots_derivation_method;
98 const secure_vector<uint8_t>& m_public_seed;
99 const secure_vector<uint8_t>& m_private_seed;
100};
101
102} // namespace
103
104class XMSS_PrivateKey_Internal final {
105 public:
106 XMSS_PrivateKey_Internal(XMSS_Parameters::xmss_algorithm_t xmss_algo_id,
107 WOTS_Derivation_Method wots_derivation_method,
108 RandomNumberGenerator& rng) :
109 m_xmss_params(XMSS_Parameters::from_id(xmss_algo_id)),
110 m_wots_params(m_xmss_params.wots_parameters()),
111 m_wots_derivation_method(wots_derivation_method),
112 m_prf(rng.random_vec(m_xmss_params.element_size())),
113 m_private_seed(rng.random_vec(m_xmss_params.element_size())),
114 m_keyid(Stateful_Key_Index_Registry::KeyId("XMSS",
115 store_be(static_cast<uint32_t>(m_xmss_params.oid())),
116 m_xmss_params.total_number_of_signatures(),
117 m_private_seed,
118 m_prf)) {}
119
120 XMSS_PrivateKey_Internal(XMSS_Parameters::xmss_algorithm_t xmss_algo_id,
121 WOTS_Derivation_Method wots_derivation_method,
122 secure_vector<uint8_t> private_seed,
124 m_xmss_params(XMSS_Parameters::from_id(xmss_algo_id)),
125 m_wots_params(m_xmss_params.wots_parameters()),
126 m_wots_derivation_method(wots_derivation_method),
127 m_prf(std::move(prf)),
128 m_private_seed(std::move(private_seed)),
129 m_keyid(Stateful_Key_Index_Registry::KeyId("XMSS",
130 store_be(static_cast<uint32_t>(m_xmss_params.oid())),
131 m_xmss_params.total_number_of_signatures(),
132 m_private_seed,
133 m_prf)) {}
134
135 XMSS_PrivateKey_Internal(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, std::span<const uint8_t> key_bits) :
136 m_xmss_params(XMSS_Parameters::from_id(xmss_algo_id)), m_wots_params(m_xmss_params.wots_parameters()) {
137 /*
138 The code requires sizeof(size_t) >= ceil(tree_height / 8)
139
140 Maximum supported tree height is 20, ceil(20/8) == 3, so 4 byte
141 size_t is sufficient for all defined parameters, or even a
142 (hypothetical) tree height 32, which would be extremely slow to
143 compute.
144 */
145 static_assert(sizeof(size_t) >= 4, "size_t is big enough to support leaf index");
146
147 const secure_vector<uint8_t> raw_key = extract_raw_private_key(key_bits, m_xmss_params);
148
149 if(raw_key.size() != m_xmss_params.raw_private_key_size() &&
150 raw_key.size() != m_xmss_params.raw_legacy_private_key_size()) {
151 throw Decoding_Error("Invalid XMSS private key size");
152 }
153
154 BufferSlicer s(raw_key);
155
156 // We're not interested in the public key here
157 s.skip(m_xmss_params.raw_public_key_size());
158
159 auto unused_leaf_bytes = s.take(sizeof(uint32_t));
160 const size_t unused_leaf = load_be<uint32_t>(unused_leaf_bytes.data(), 0);
161
162 m_prf = s.copy_as_secure_vector(m_xmss_params.element_size());
163 m_private_seed = s.copy_as_secure_vector(m_xmss_params.element_size());
164
165 m_keyid = Stateful_Key_Index_Registry::KeyId("XMSS",
166 store_be(static_cast<uint32_t>(m_xmss_params.oid())),
167 m_xmss_params.total_number_of_signatures(),
168 m_private_seed,
169 m_prf);
170
171 // Note m_keyid must be initialized before set_unused_leaf_index is called!
172 set_unused_leaf_index(unused_leaf);
173
174 // Legacy keys generated prior to Botan 3.x don't feature a
175 // WOTS+ key derivation method encoded in their private key.
176 m_wots_derivation_method =
177 (s.empty()) ? WOTS_Derivation_Method::Botan2x : static_cast<WOTS_Derivation_Method>(s.take(1).front());
178
179 BOTAN_ASSERT_NOMSG(s.empty());
180 }
181
182 secure_vector<uint8_t> serialize(std::vector<uint8_t> raw_public_key) const {
183 std::vector<uint8_t> unused_index(4);
184 store_be(checked_cast_to<uint32_t>(unused_leaf_index()), unused_index.data());
185
186 std::vector<uint8_t> wots_derivation_method;
187 wots_derivation_method.push_back(static_cast<uint8_t>(m_wots_derivation_method));
188
190 raw_public_key, unused_index, m_prf, m_private_seed, wots_derivation_method);
191 }
192
193 const secure_vector<uint8_t>& prf_value() const { return m_prf; }
194
195 const secure_vector<uint8_t>& private_seed() const { return m_private_seed; }
196
197 const XMSS_WOTS_Parameters& wots_parameters() const { return m_wots_params; }
198
199 WOTS_Derivation_Method wots_derivation_method() const { return m_wots_derivation_method; }
200
201 // The signing state (leaf index) lives in the process-wide
202 // Stateful_Key_Index_Registry keyed by m_keyid, not in this object, so the
203 // methods that advance it leave *this unchanged and are therefore const.
204 void set_unused_leaf_index(size_t idx) const {
205 // An index equal to 2^h is valid and denotes an exhausted key
206 if(idx > (1ULL << m_xmss_params.tree_height())) {
207 throw Decoding_Error("XMSS private key leaf index out of bounds");
208 } else {
210 }
211 }
212
213 size_t reserve_unused_leaf_index() const {
215 if(!idx.has_value()) {
216 throw Invalid_State("XMSS private key, one time signatures exhausted");
217 }
218 // Cast is safe even on 32 bit since total_number_of_signatures will be less
219 return static_cast<size_t>(idx.value());
220 }
221
222 size_t unused_leaf_index() const {
223 const uint64_t idx = Stateful_Key_Index_Registry::global().current_index(m_keyid);
224 return checked_cast_to<size_t>(idx);
225 }
226
227 uint64_t remaining_signatures() const {
229 }
230
231 private:
232 XMSS_Parameters m_xmss_params;
233 XMSS_WOTS_Parameters m_wots_params;
234 WOTS_Derivation_Method m_wots_derivation_method;
235
237 secure_vector<uint8_t> m_private_seed;
238 Stateful_Key_Index_Registry::KeyId m_keyid;
239};
240
241XMSS_PrivateKey::XMSS_PrivateKey(std::span<const uint8_t> key_bits) :
243
244XMSS_PrivateKey::XMSS_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
245 XMSS_PublicKey(alg_id, key_bits),
246 m_private(std::make_shared<XMSS_PrivateKey_Internal>(xmss_parameters().oid(), key_bits)) {}
247
248struct XMSS_PrivateKey::Keygen_Material {
249 secure_vector<uint8_t> private_seed;
253};
254
255XMSS_PrivateKey::Keygen_Material XMSS_PrivateKey::generate_keygen_material(
257 RandomNumberGenerator& rng,
258 WOTS_Derivation_Method wots_derivation_method) {
259 const auto params = XMSS_Parameters::from_id(xmss_algo_id);
260 const size_t n = params.element_size();
261
262 // The order in which the seeds are drawn from the RNG (public seed, then
263 // prf, then private seed) must match the historical two-phase construction
264 // so that a deterministic RNG reproduces the same key material.
265 auto public_seed = rng.random_vec(n);
266 auto prf = rng.random_vec(n);
267 auto private_seed = rng.random_vec(n);
268
269 const XMSS_Address adrs;
270 XMSS_Hash hash(params);
271 const XMSS_Tree_Builder builder(params, wots_derivation_method, public_seed, private_seed);
272 auto root = builder.tree_hash(0, params.tree_height(), adrs, hash);
273
274 return Keygen_Material{std::move(private_seed), std::move(prf), std::move(public_seed), std::move(root)};
275}
276
282
284 WOTS_Derivation_Method wots_derivation_method,
285 Keygen_Material material) :
286 XMSS_PublicKey(xmss_algo_id, std::move(material.root), std::move(material.public_seed)),
287 m_private(std::make_shared<XMSS_PrivateKey_Internal>(
288 xmss_algo_id, wots_derivation_method, std::move(material.private_seed), std::move(material.prf))) {}
289
291 size_t idx_leaf,
292 secure_vector<uint8_t> wots_priv_seed,
297 XMSS_PublicKey(xmss_algo_id, std::move(root), std::move(public_seed)),
298 m_private(std::make_shared<XMSS_PrivateKey_Internal>(
299 xmss_algo_id, wots_derivation_method, std::move(wots_priv_seed), std::move(prf))) {
300 m_private->set_unused_leaf_index(idx_leaf);
301 BOTAN_ARG_CHECK(m_private->prf_value().size() == xmss_parameters().element_size(),
302 "XMSS: unexpected byte length of PRF value");
303 BOTAN_ARG_CHECK(m_private->private_seed().size() == xmss_parameters().element_size(),
304 "XMSS: unexpected byte length of private seed");
305}
306
307namespace {
308
309secure_vector<uint8_t> XMSS_Tree_Builder::tree_hash(size_t start_idx,
310 size_t target_node_height,
311 const XMSS_Address& adrs,
312 XMSS_Hash& hash) const {
313 BOTAN_ASSERT_NOMSG(target_node_height <= 30);
314 BOTAN_ASSERT((start_idx % (static_cast<size_t>(1) << target_node_height)) == 0,
315 "Start index must be divisible by 2^{target node height}.");
316
317#if defined(BOTAN_HAS_THREAD_UTILS)
318 // determine number of parallel tasks to split the tree_hashing into.
319
321
322 const size_t split_level = std::min(target_node_height, thread_pool.worker_count());
323
324 // skip parallelization overhead for leaf nodes.
325 if(split_level == 0) {
327 XMSS_Address subtree_addr(adrs);
328 tree_hash_subtree(result, start_idx, target_node_height, subtree_addr, hash);
329 return result;
330 }
331
332 const size_t subtrees = static_cast<size_t>(1) << split_level;
333 const size_t last_idx = (static_cast<size_t>(1) << (target_node_height)) + start_idx;
334 const size_t offs = (last_idx - start_idx) / subtrees;
335 // this cast cannot overflow because target_node_height is limited
336 uint8_t level = static_cast<uint8_t>(split_level); // current level in the tree
337
338 BOTAN_ASSERT((last_idx - start_idx) % subtrees == 0,
339 "Number of worker threads in tree_hash need to divide range "
340 "of calculated nodes.");
341
342 std::vector<secure_vector<uint8_t>> nodes(subtrees, secure_vector<uint8_t>(xmss_parameters().element_size()));
343 std::vector<XMSS_Address> node_addresses(subtrees, adrs);
344 std::vector<XMSS_Hash> xmss_hash(subtrees, hash);
345 std::vector<std::future<void>> work;
346
347 // Calculate multiple subtrees in parallel.
348 for(size_t i = 0; i < subtrees; i++) {
349 using tree_hash_subtree_fn_t =
350 void (XMSS_Tree_Builder::*)(secure_vector<uint8_t>&, size_t, size_t, XMSS_Address&, XMSS_Hash&) const;
351
352 const tree_hash_subtree_fn_t work_fn = &XMSS_Tree_Builder::tree_hash_subtree;
353
354 work.push_back(thread_pool.run(work_fn,
355 this,
356 std::ref(nodes[i]),
357 start_idx + i * offs,
358 target_node_height - split_level,
359 std::ref(node_addresses[i]),
360 std::ref(xmss_hash[i])));
361 }
362
363 for(auto& w : work) {
364 w.get();
365 }
366 work.clear();
367
368 // Parallelize the top tree levels horizontally
369 while(level-- > 1) {
370 std::vector<secure_vector<uint8_t>> ro_nodes(nodes.begin(),
371 nodes.begin() + (static_cast<size_t>(1) << (level + 1)));
372
373 for(size_t i = 0; i < (static_cast<size_t>(1) << level); i++) {
374 BOTAN_ASSERT_NOMSG(xmss_hash.size() > i);
375
376 node_addresses[i].set_tree_height(static_cast<uint32_t>(target_node_height - (level + 1)));
377 node_addresses[i].set_tree_index((node_addresses[2 * i + 1].get_tree_index() - 1) >> 1);
378
379 work.push_back(thread_pool.run(&XMSS_Common_Ops::randomize_tree_hash,
380 std::ref(nodes[i]),
381 std::cref(ro_nodes[2 * i]),
382 std::cref(ro_nodes[2 * i + 1]),
383 node_addresses[i],
384 std::cref(this->public_seed()),
385 std::ref(xmss_hash[i]),
386 std::cref(xmss_parameters())));
387 }
388
389 for(auto& w : work) {
390 w.get();
391 }
392 work.clear();
393 }
394
395 // Avoid creation an extra thread to calculate root node.
396 node_addresses[0].set_tree_height(static_cast<uint32_t>(target_node_height - 1));
397 node_addresses[0].set_tree_index((node_addresses[1].get_tree_index() - 1) >> 1);
398 XMSS_Common_Ops::randomize_tree_hash(
399 nodes[0], nodes[0], nodes[1], node_addresses[0], this->public_seed(), hash, xmss_parameters());
400 return nodes[0];
401#else
402 secure_vector<uint8_t> result;
403 XMSS_Address subtree_addr(adrs);
404 tree_hash_subtree(result, start_idx, target_node_height, subtree_addr, hash);
405 return result;
406#endif
407}
408
409void XMSS_Tree_Builder::tree_hash_subtree(secure_vector<uint8_t>& result,
410 size_t start_idx,
411 size_t target_node_height,
412 XMSS_Address& adrs,
413 XMSS_Hash& hash) const {
414 const secure_vector<uint8_t>& seed = this->public_seed();
415
416 std::vector<secure_vector<uint8_t>> nodes(target_node_height + 1,
417 secure_vector<uint8_t>(xmss_parameters().element_size()));
418
419 // node stack, holds all nodes on stack and one extra "pending" node. This
420 // temporary node referred to as "node" in the XMSS standard document stays
421 // a pending element, meaning it is not regarded as element on the stack
422 // until level is increased.
423 std::vector<uint8_t> node_levels(target_node_height + 1);
424
425 uint8_t level = 0; // current level on the node stack.
426 const size_t last_idx = (static_cast<size_t>(1) << target_node_height) + start_idx;
427
428 for(size_t i = start_idx; i < last_idx; i++) {
429 adrs.set_type(XMSS_Address::Type::OTS_Hash_Address);
430 adrs.set_ots_address(static_cast<uint32_t>(i));
431
432 const XMSS_WOTS_PublicKey pk = this->wots_public_key_for(adrs, hash);
433
434 adrs.set_type(XMSS_Address::Type::LTree_Address);
435 adrs.set_ltree_address(static_cast<uint32_t>(i));
436 XMSS_Common_Ops::create_l_tree(nodes[level], pk.key_data(), adrs, seed, hash, xmss_parameters());
437 node_levels[level] = 0;
438
439 adrs.set_type(XMSS_Address::Type::Hash_Tree_Address);
440 adrs.set_tree_height(0);
441 adrs.set_tree_index(static_cast<uint32_t>(i));
442
443 while(level > 0 && node_levels[level] == node_levels[level - 1]) {
444 adrs.set_tree_index(((adrs.get_tree_index() - 1) >> 1));
445 XMSS_Common_Ops::randomize_tree_hash(
446 nodes[level - 1], nodes[level - 1], nodes[level], adrs, seed, hash, xmss_parameters());
447 node_levels[level - 1]++;
448 level--; //Pop stack top element
449 adrs.set_tree_height(adrs.get_tree_height() + 1);
450 }
451 level++; //push temporary node to stack
452 }
453 result = nodes[level - 1];
454}
455
456XMSS_WOTS_PublicKey XMSS_Tree_Builder::wots_public_key_for(const XMSS_Address& adrs, XMSS_Hash& hash) const {
457 const auto private_key = wots_private_key_for(adrs, hash);
458 return XMSS_WOTS_PublicKey(m_wots_params, public_seed(), private_key, adrs, hash);
459}
460
461XMSS_WOTS_PrivateKey XMSS_Tree_Builder::wots_private_key_for(const XMSS_Address& adrs, XMSS_Hash& hash) const {
462 switch(m_wots_derivation_method) {
463 case WOTS_Derivation_Method::NIST_SP800_208:
464 return XMSS_WOTS_PrivateKey(m_wots_params, public_seed(), m_private_seed, adrs, hash);
465 case WOTS_Derivation_Method::Botan2x:
466 return XMSS_WOTS_PrivateKey(m_wots_params, m_private_seed, adrs, hash);
467 }
468
469 throw Invalid_State("WOTS derivation method is out of the enum's range");
470}
471
472} // namespace
473
474secure_vector<uint8_t> XMSS_PrivateKey::tree_hash(size_t start_idx,
475 size_t target_node_height,
476 const XMSS_Address& adrs,
477 XMSS_Hash& hash) const {
478 return XMSS_Tree_Builder(xmss_parameters(), wots_derivation_method(), public_seed(), m_private->private_seed())
479 .tree_hash(start_idx, target_node_height, adrs, hash);
480}
481
482XMSS_WOTS_PrivateKey XMSS_PrivateKey::wots_private_key_for(const XMSS_Address& adrs, XMSS_Hash& hash) const {
483 return XMSS_Tree_Builder(xmss_parameters(), wots_derivation_method(), public_seed(), m_private->private_seed())
484 .wots_private_key_for(adrs, hash);
485}
486
490
491size_t XMSS_PrivateKey::reserve_unused_leaf_index() {
492 return m_private->reserve_unused_leaf_index();
493}
494
496 return m_private->unused_leaf_index();
497}
498
500 return checked_cast_to<size_t>(m_private->remaining_signatures());
501}
502
503std::optional<uint64_t> XMSS_PrivateKey::remaining_operations() const {
504 return m_private->remaining_signatures();
505}
506
507const secure_vector<uint8_t>& XMSS_PrivateKey::prf_value() const {
508 return m_private->prf_value();
509}
510
512 return m_private->serialize(raw_public_key());
513}
514
516 return m_private->wots_derivation_method();
517}
518
519std::unique_ptr<Public_Key> XMSS_PrivateKey::public_key() const {
520 return std::make_unique<XMSS_PublicKey>(xmss_parameters().oid(), root(), public_seed());
521}
522
523std::unique_ptr<PK_Ops::Signature> XMSS_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
524 std::string_view /*params*/,
525 std::string_view provider) const {
526 if(provider == "base" || provider.empty()) {
527 return std::make_unique<XMSS_Signature_Operation>(*this);
528 }
529
530 throw Provider_Not_Found(algo_name(), provider);
531}
532
533} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
static Limits DER()
Definition ber_dec.h:42
BER_Decoder & decode(bool &out)
Definition ber_dec.h:358
BER_Decoder & verify_end()
Definition ber_dec.cpp:471
secure_vector< uint8_t > get_contents()
Definition der_enc.cpp:161
DER_Encoder & encode(bool b)
Definition der_enc.cpp:313
uint64_t remaining_operations(const KeyId &key_id)
std::optional< uint64_t > reserve_next_index(const KeyId &key_id)
void set_index_lower_bound(const KeyId &key_id, uint64_t min)
static Stateful_Key_Index_Registry & global()
size_t worker_count() const
Definition thread_pool.h:52
auto run(F &&f, Args &&... args) -> std::future< std::invoke_result_t< F, Args... > >
Definition thread_pool.h:66
static Thread_Pool & global_instance()
static XMSS_Parameters from_id(xmss_algorithm_t id)
std::unique_ptr< Public_Key > public_key() const override
size_t remaining_signatures() const
size_t unused_leaf_index() const
std::optional< uint64_t > remaining_operations() const override
Retrieves the number of remaining operations if this is a stateful private key.
WOTS_Derivation_Method wots_derivation_method() const
secure_vector< uint8_t > raw_private_key() const
secure_vector< uint8_t > private_key_bits() const override
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, RandomNumberGenerator &rng, WOTS_Derivation_Method wots_derivation_method=WOTS_Derivation_Method::NIST_SP800_208)
const secure_vector< uint8_t > & root() const
const secure_vector< uint8_t > & public_seed() const
const XMSS_Parameters & xmss_parameters() const
std::vector< uint8_t > raw_public_key() const
std::string algo_name() const override
Definition xmss.h:81
XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, RandomNumberGenerator &rng)
Gf448Elem root(const Gf448Elem &elem)
Compute the root of elem in the field.
constexpr RT checked_cast_to(AT i)
Definition int_utils.h:104
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745
WOTS_Derivation_Method
Definition xmss.h:143
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504