Botan  2.1.0
Crypto and TLS for C++11
xmss_privatekey.cpp
Go to the documentation of this file.
1 /*
2  * XMSS Private Key
3  * An XMSS: Extended Hash-Based Siganture 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  * draft-itrf-cfrg-xmss-hash-based-signatures-06
9  * Release: July 2016.
10  * https://datatracker.ietf.org/doc/
11  * draft-irtf-cfrg-xmss-hash-based-signatures/?include_text=1
12  *
13  * (C) 2016 Matthias Gierlings
14  *
15  * Botan is released under the Simplified BSD License (see license.txt)
16  **/
17 
18 #include <botan/internal/xmss_signature_operation.h>
19 #include <botan/xmss_privatekey.h>
20 
21 namespace Botan {
22 
24  : XMSS_PublicKey(unlock(raw_key)),
25  XMSS_Common_Ops(XMSS_PublicKey::m_xmss_params.oid()),
26  m_wots_priv_key(m_wots_params.oid(), m_public_seed),
27  m_index_reg(XMSS_Index_Registry::get_instance())
28  {
29  BOTAN_ASSERT(sizeof(size_t) >= ceil(
30  static_cast<float>(XMSS_PublicKey::m_xmss_params.tree_height()) / 8.f),
31  "System type \"size_t\" not big enough to support"
32  " leaf index.");
33 
34  if(raw_key.size() != size())
35  {
36  throw Integrity_Failure("Invalid XMSS private key size detected.");
37  }
38 
39  // extract & copy unused leaf index from raw_key.
40  uint64_t unused_leaf = 0;
41  auto begin = (raw_key.begin() + XMSS_PublicKey::size());
42  auto end = raw_key.begin() + XMSS_PublicKey::size() + sizeof(uint64_t);
43 
44  for(auto& i = begin; i != end; i++)
45  unused_leaf = ((unused_leaf << 8) | *i);
46 
47  if(unused_leaf >= (1ull << (XMSS_PublicKey::m_xmss_params.tree_height() - 1)))
48  {
49  throw Integrity_Failure("XMSS private key leaf index out of "
50  "bounds.");
51  }
52 
53  begin = end;
55  m_prf.clear();
56  m_prf.reserve(XMSS_PublicKey::m_xmss_params.element_size());
57  std::copy(begin, end, std::back_inserter(m_prf));
58 
59  begin = end;
60  end = begin + m_wots_params.element_size();
61  m_wots_priv_key.set_private_seed(secure_vector<uint8_t>(begin, end));
62  set_unused_leaf_index(static_cast<size_t>(unused_leaf));
63  }
64 
68  : XMSS_PublicKey(xmss_algo_id, rng),
69  XMSS_Common_Ops(xmss_algo_id),
70  m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(),
71  public_seed(),
72  rng),
73  m_prf(rng.random_vec(XMSS_PublicKey::m_xmss_params.element_size())),
74  m_index_reg(XMSS_Index_Registry::get_instance())
75  {
76  XMSS_Address adrs;
78  XMSS_PublicKey::m_xmss_params.tree_height(),
79  adrs));
80  }
81 
83 XMSS_PrivateKey::tree_hash(size_t start_idx,
84  size_t target_node_height,
85  XMSS_Address& adrs)
86  {
87  const secure_vector<uint8_t>& seed = this->public_seed();
88 
89  BOTAN_ASSERT((start_idx % (1 << target_node_height)) == 0,
90  "Start index must be divisible by 2^{target node height}.");
91 
92  std::vector<secure_vector<uint8_t>> nodes(
93  XMSS_PublicKey::m_xmss_params.tree_height() + 1,
95 
96  // node stack, holds all nodes on stack and one extra "pending" node. This
97  // temporary node referred to as "node" in the XMSS standard document stays
98  // a pending element, meaning it is not regarded as element on the stack
99  // until level is increased.
100  std::vector<uint8_t> node_levels(XMSS_PublicKey::m_xmss_params.tree_height() + 1);
101 
102  uint8_t level = 0;
103  XMSS_WOTS_PublicKey pk(m_wots_priv_key.wots_parameters().oid(), seed);
104 
105  size_t last_idx = static_cast<size_t>(1 << target_node_height) + start_idx;
106  for(size_t i = start_idx; i < last_idx; i++)
107  {
109  adrs.set_ots_address(i);
111  pk,
112  // getWOTS_SK(SK, s + i), reference implementation uses adrs
113  // instead of zero padded index s + i.
114  this->wots_private_key()[adrs],
115  adrs);
117  adrs.set_ltree_address(i);
118  create_l_tree(nodes[level], pk, adrs, seed);
119  node_levels[level] = 0;
120 
122  adrs.set_tree_height(0);
123  adrs.set_tree_index(i);
124 
125  while(level > 0 && node_levels[level] ==
126  node_levels[level - 1])
127  {
128  adrs.set_tree_index(((adrs.get_tree_index() - 1) >> 1));
129  randomize_tree_hash(nodes[level - 1],
130  nodes[level - 1],
131  nodes[level],
132  adrs,
133  seed);
134  node_levels[level - 1]++;
135  level--; //Pop stack top element
136  adrs.set_tree_height(adrs.get_tree_height() + 1);
137  }
138  level++; //push temporary node to stack
139  }
140  return nodes[level - 1];
141  }
142 
143 std::shared_ptr<Atomic<size_t>>
144 XMSS_PrivateKey::recover_global_leaf_index() const
145  {
146  BOTAN_ASSERT(m_wots_priv_key.private_seed().size() ==
149  "Trying to retrieve index for partially initialized "
150  "key.");
151  return m_index_reg.get(m_wots_priv_key.private_seed(),
152  m_prf);
153  }
154 
156  {
157  std::vector<uint8_t> pk { raw_public_key() };
158  secure_vector<uint8_t> result(pk.begin(), pk.end());
159  result.reserve(size());
160 
161  for(int i = 7; i >= 0; i--)
162  {
163  result.push_back(
164  static_cast<uint8_t>(
165  static_cast<uint64_t>(unused_leaf_index()) >> 8 * i));
166  }
167 
168  std::copy(m_prf.begin(), m_prf.end(), std::back_inserter(result));
169  std::copy(m_wots_priv_key.private_seed().begin(),
170  m_wots_priv_key.private_seed().end(),
171  std::back_inserter(result));
172 
173  return result;
174  }
175 
176 std::unique_ptr<PK_Ops::Signature>
178  const std::string&,
179  const std::string& provider) const
180  {
181  if(provider == "base" || provider.empty())
182  return std::unique_ptr<PK_Ops::Signature>(
183  new XMSS_Signature_Operation(*this));
184 
185  throw Provider_Not_Found(algo_name(), provider);
186  }
187 
188 }
secure_vector< uint8_t > tree_hash(size_t start_idx, size_t target_node_height, XMSS_Address &adrs)
size_t element_size() const
void create_l_tree(secure_vector< uint8_t > &result, wots_keysig_t pk, XMSS_Address &adrs, const secure_vector< uint8_t > &seed)
virtual const secure_vector< uint8_t > & public_seed() const override
void set_ots_address(uint32_t value)
Definition: xmss_address.h:166
void set_tree_height(uint32_t value)
Definition: xmss_address.h:255
const secure_vector< uint8_t > & private_seed() const
virtual secure_vector< uint8_t > raw_private_key() const
void set_ltree_address(uint32_t value)
Definition: xmss_address.h:196
void set_root(const secure_vector< uint8_t > &root)
void set_unused_leaf_index(size_t idx)
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, RandomNumberGenerator &rng)
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
virtual std::vector< uint8_t > raw_public_key() const
void set_type(Type type)
Definition: xmss_address.h:113
virtual size_t size() const
std::shared_ptr< Atomic< size_t > > get(const secure_vector< uint8_t > &private_seed, const secure_vector< uint8_t > &prf)
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_WOTS_PublicKey generate_public_key(XMSS_Address &adrs)
Definition: alg_id.cpp:13
virtual size_t size() const override
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:125
const XMSS_WOTS_Parameters & wots_parameters() const
virtual std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &, const std::string &, const std::string &provider) const override
std::string algo_name() const override
XMSS_WOTS_Parameters m_wots_params
uint32_t get_tree_index() const
Definition: xmss_address.h:301
void set_tree_index(uint32_t value)
Definition: xmss_address.h:317
void set_private_seed(const secure_vector< uint8_t > &private_seed)
XMSS_Parameters m_xmss_params
uint32_t get_tree_height() const
Definition: xmss_address.h:239
size_t unused_leaf_index() const
const XMSS_WOTS_PrivateKey & wots_private_key() const
ots_algorithm_t oid() const