18#include <botan/xmss.h>
19#include <botan/internal/xmss_signature_operation.h>
20#include <botan/internal/xmss_index_registry.h>
21#include <botan/internal/xmss_common_ops.h>
22#include <botan/ber_dec.h>
23#include <botan/der_enc.h>
26#if defined(BOTAN_HAS_THREAD_UTILS)
27 #include <botan/internal/thread_pool.h>
35secure_vector<uint8_t> extract_raw_key(
const secure_vector<uint8_t>& key_bits)
37 secure_vector<uint8_t> raw_key;
42 catch(Decoding_Error&)
53 m_wots_priv_key(m_wots_params.oid(), m_public_seed),
54 m_hash(xmss_hash_function()),
65 static_assert(
sizeof(size_t) >= 4,
"size_t is big enough to support leaf index");
75 uint64_t unused_leaf = 0;
79 for(
auto& i = begin; i != end; i++)
81 unused_leaf = ((unused_leaf << 8) | *i);
93 std::copy(begin, end, std::back_inserter(m_prf));
108 m_hash(xmss_hash_function()),
109 m_prf(rng.random_vec(
XMSS_PublicKey::m_xmss_params.element_size())),
138 size_t target_node_height,
142 BOTAN_ASSERT((start_idx % (
static_cast<size_t>(1) << target_node_height)) == 0,
143 "Start index must be divisible by 2^{target node height}.");
145#if defined(BOTAN_HAS_THREAD_UTILS)
150 const size_t split_level = std::min(target_node_height, thread_pool.
worker_count());
156 tree_hash_subtree(result, start_idx, target_node_height, adrs);
160 const size_t subtrees =
static_cast<size_t>(1) << split_level;
161 const size_t last_idx = (
static_cast<size_t>(1) << (target_node_height)) + start_idx;
162 const size_t offs = (last_idx - start_idx) / subtrees;
164 uint8_t level =
static_cast<uint8_t
>(split_level);
167 "Number of worker threads in tree_hash need to divide range "
168 "of calculated nodes.");
170 std::vector<secure_vector<uint8_t>> nodes(
173 std::vector<XMSS_Address> node_addresses(subtrees, adrs);
174 std::vector<XMSS_Hash> xmss_hash(subtrees, m_hash);
175 std::vector<std::future<void>> work;
178 for(
size_t i = 0; i < subtrees; i++)
180 using tree_hash_subtree_fn_t =
187 tree_hash_subtree_fn_t work_fn = &XMSS_PrivateKey::tree_hash_subtree;
189 work.push_back(thread_pool.
run(
193 start_idx + i * offs,
194 target_node_height - split_level,
195 std::ref(node_addresses[i]),
196 std::ref(xmss_hash[i])));
208 std::vector<secure_vector<uint8_t>> ro_nodes(
209 nodes.begin(), nodes.begin() + (
static_cast<size_t>(1) << (level+1)));
211 for(
size_t i = 0; i < (static_cast<size_t>(1) << level); i++)
215 node_addresses[i].set_tree_height(
static_cast<uint32_t
>(target_node_height - (level + 1)));
216 node_addresses[i].set_tree_index(
217 (node_addresses[2 * i + 1].get_tree_index() - 1) >> 1);
219 work.push_back(thread_pool.
run(
222 std::cref(ro_nodes[2 * i]),
223 std::cref(ro_nodes[2 * i + 1]),
224 std::ref(node_addresses[i]),
225 std::cref(this->public_seed()),
226 std::ref(xmss_hash[i]),
238 node_addresses[0].set_tree_height(
static_cast<uint32_t
>(target_node_height - 1));
239 node_addresses[0].set_tree_index(
240 (node_addresses[1].get_tree_index() - 1) >> 1);
251 tree_hash_subtree(result, start_idx, target_node_height, adrs, m_hash);
259 size_t target_node_height,
265 std::vector<secure_vector<uint8_t>> nodes(
266 target_node_height + 1,
273 std::vector<uint8_t> node_levels(target_node_height + 1);
277 const size_t last_idx = (
static_cast<size_t>(1) << target_node_height) + start_idx;
279 for(
size_t i = start_idx; i < last_idx; i++)
293 node_levels[level] = 0;
299 while(level > 0 && node_levels[level] ==
300 node_levels[level - 1])
310 node_levels[level - 1]++;
316 result = nodes[level - 1];
324std::shared_ptr<Atomic<size_t>>
325XMSS_PrivateKey::recover_global_leaf_index()
const
330 "Trying to retrieve index for partially initialized key");
338 throw Decoding_Error(
"XMSS private key leaf index out of bounds");
342 std::atomic<size_t>& index =
343 static_cast<std::atomic<size_t>&
>(*recover_global_leaf_index());
348 current = index.load();
352 while(!index.compare_exchange_strong(current, idx));
358 size_t idx = (
static_cast<std::atomic<size_t>&
>(
359 *recover_global_leaf_index())).fetch_add(1);
362 throw Decoding_Error(
"XMSS private key, one time signatures exhaused");
369 return *recover_global_leaf_index();
376 result.reserve(
size());
378 for(
int i = 3; i >= 0; i--)
381 static_cast<uint8_t
>(
385 std::copy(m_prf.begin(), m_prf.end(), std::back_inserter(result));
388 std::back_inserter(result));
393std::unique_ptr<PK_Ops::Signature>
396 const std::string& provider)
const
398 if(provider ==
"base" || provider.empty())
399 return std::unique_ptr<PK_Ops::Signature>(
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ASSERT(expr, assertion_made)
secure_vector< uint8_t > get_contents()
DER_Encoder & encode(bool b)
size_t worker_count() const
auto run(F &&f, Args &&... args) -> std::future< typename std::result_of< F(Args...)>::type >
static Thread_Pool & global_instance()
void set_ots_address(uint32_t value)
uint32_t get_tree_index() const
uint32_t get_tree_height() const
void set_tree_height(uint32_t value)
void set_tree_index(uint32_t value)
void set_ltree_address(uint32_t value)
static void create_l_tree(secure_vector< uint8_t > &result, wots_keysig_t pk, XMSS_Address &adrs, const secure_vector< uint8_t > &seed, XMSS_Hash &hash, const XMSS_Parameters ¶ms)
static void randomize_tree_hash(secure_vector< uint8_t > &result, const secure_vector< uint8_t > &left, const secure_vector< uint8_t > &right, XMSS_Address &adrs, const secure_vector< uint8_t > &seed, XMSS_Hash &hash, const XMSS_Parameters ¶ms)
std::shared_ptr< Atomic< size_t > > get(const secure_vector< uint8_t > &private_seed, const secure_vector< uint8_t > &prf)
size_t element_size() const
const secure_vector< uint8_t > & public_seed() const override
void set_unused_leaf_index(size_t idx)
secure_vector< uint8_t > tree_hash(size_t start_idx, size_t target_node_height, XMSS_Address &adrs)
size_t unused_leaf_index() const
size_t size() const override
const XMSS_WOTS_PrivateKey & wots_private_key() const
size_t reserve_unused_leaf_index()
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &, const std::string &, const std::string &provider) const override
XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, RandomNumberGenerator &rng)
secure_vector< uint8_t > raw_private_key() const
secure_vector< uint8_t > private_key_bits() const override
void set_root(const secure_vector< uint8_t > &root)
XMSS_Parameters m_xmss_params
virtual std::vector< uint8_t > raw_public_key() const
XMSS_WOTS_Parameters m_wots_params
std::string algo_name() const override
virtual size_t size() const
size_t element_size() const
ots_algorithm_t oid() const
const secure_vector< uint8_t > & private_seed() const
XMSS_WOTS_PublicKey generate_public_key(XMSS_Address &adrs)
void set_private_seed(const secure_vector< uint8_t > &private_seed)
const XMSS_WOTS_Parameters & wots_parameters() const
std::vector< T > unlock(const secure_vector< T > &in)
std::vector< T, secure_allocator< T > > secure_vector