Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/pubkey/xmss/xmss_wots.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * XMSS WOTS Public and Private Key
3
4
 * A Winternitz One Time Signature public/private key for use with
5
 * Extended Hash-Based Signatures.
6
 *
7
 * (C) 2016,2017,2018 Matthias Gierlings
8
 *     2023           René Meusel - Rohde & Schwarz Cybersecurity
9
 *
10
 * Botan is released under the Simplified BSD License (see license.txt)
11
 **/
12
13
#include <botan/internal/xmss_wots.h>
14
15
#include <botan/mem_ops.h>
16
#include <botan/internal/stl_util.h>
17
#include <botan/internal/xmss_address.h>
18
#include <botan/internal/xmss_tools.h>
19
20
namespace Botan {
21
22
namespace {
23
24
/**
25
 * Algorithm 2: Chaining Function.
26
 *
27
 * Takes an n-byte input string and transforms it into a the function
28
 * result iterating the cryptographic hash function "F" steps times on
29
 * the input x using the outputs of the PRNG "G".
30
 *
31
 * This overload is used in multithreaded scenarios, where it is
32
 * required to provide seperate instances of XMSS_Hash to each
33
 * thread.
34
 *
35
 * @param params      The WOTS parameters to use
36
 * @param[out] result An n-byte input string, that will be transformed into
37
 *                    the chaining function result.
38
 * @param start_idx The start index.
39
 * @param steps A number of steps.
40
 * @param adrs An OTS Hash Address.
41
 * @param seed A seed.
42
 * @param hash Instance of XMSS_Hash, that may only by the thread
43
 *             executing chain.
44
 **/
45
void chain(const XMSS_WOTS_Parameters& params,
46
           secure_vector<uint8_t>& result,
47
           size_t start_idx,
48
           size_t steps,
49
           XMSS_Address& adrs,
50
           std::span<const uint8_t> seed,
51
0
           XMSS_Hash& hash) {
52
0
   BOTAN_ASSERT_NOMSG(result.size() == hash.output_length());
53
0
   BOTAN_ASSERT_NOMSG(start_idx + steps < params.wots_parameter());
54
0
   secure_vector<uint8_t> prf_output(hash.output_length());
55
56
   // Note that RFC 8391 defines this algorithm recursively (building up the
57
   // iterations before any calculation) using 'steps' as the iterator and a
58
   // recursion base with 'steps == 0'.
59
   // Instead, we implement it iteratively using 'i' as iterator. This makes
60
   // 'adrs.set_hash_address(i)' equivalent to 'ADRS.setHashAddress(i + s - 1)'.
61
0
   for(size_t i = start_idx; i < (start_idx + steps) && i < params.wots_parameter(); i++) {
62
0
      adrs.set_hash_address(static_cast<uint32_t>(i));
63
64
      // Calculate tmp XOR bitmask
65
0
      adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_Mode);
66
0
      hash.prf(prf_output, seed, adrs.bytes());
67
0
      xor_buf(result.data(), prf_output.data(), result.size());
68
69
      // Calculate key
70
0
      adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode);
71
72
      // Calculate f(key, tmp XOR bitmask)
73
0
      hash.prf(prf_output, seed, adrs.bytes());
74
0
      hash.f(result, prf_output, result);
75
0
   }
76
0
}
77
78
}  // namespace
79
80
XMSS_WOTS_PublicKey::XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters params,
81
                                         std::span<const uint8_t> public_seed,
82
                                         const XMSS_WOTS_PrivateKey& private_key,
83
                                         XMSS_Address& adrs,
84
                                         XMSS_Hash& hash) :
85
0
      XMSS_WOTS_Base(std::move(params), private_key.key_data()) {
86
0
   for(size_t i = 0; i < m_params.len(); ++i) {
87
0
      adrs.set_chain_address(static_cast<uint32_t>(i));
88
0
      chain(m_params, m_key_data[i], 0, m_params.wots_parameter() - 1, adrs, public_seed, hash);
89
0
   }
90
0
}
91
92
XMSS_WOTS_PublicKey::XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters params,
93
                                         std::span<const uint8_t> public_seed,
94
                                         wots_keysig_t signature,
95
                                         const secure_vector<uint8_t>& msg,
96
                                         XMSS_Address& adrs,
97
                                         XMSS_Hash& hash) :
98
0
      XMSS_WOTS_Base(std::move(params), std::move(signature)) {
99
0
   secure_vector<uint8_t> msg_digest{m_params.base_w(msg, m_params.len_1())};
100
101
0
   m_params.append_checksum(msg_digest);
102
103
0
   for(size_t i = 0; i < m_params.len(); i++) {
104
0
      adrs.set_chain_address(static_cast<uint32_t>(i));
105
0
      chain(m_params,
106
0
            m_key_data[i],
107
0
            msg_digest[i],
108
0
            m_params.wots_parameter() - 1 - msg_digest[i],
109
0
            adrs,
110
0
            public_seed,
111
0
            hash);
112
0
   }
113
0
}
114
115
wots_keysig_t XMSS_WOTS_PrivateKey::sign(const secure_vector<uint8_t>& msg,
116
                                         std::span<const uint8_t> public_seed,
117
                                         XMSS_Address& adrs,
118
0
                                         XMSS_Hash& hash) {
119
0
   secure_vector<uint8_t> msg_digest{m_params.base_w(msg, m_params.len_1())};
120
121
0
   m_params.append_checksum(msg_digest);
122
0
   auto sig = this->key_data();
123
124
0
   for(size_t i = 0; i < m_params.len(); i++) {
125
0
      adrs.set_chain_address(static_cast<uint32_t>(i));
126
0
      chain(m_params, sig[i], 0, msg_digest[i], adrs, public_seed, hash);
127
0
   }
128
129
0
   return sig;
130
0
}
131
132
XMSS_WOTS_PrivateKey::XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters params,
133
                                           std::span<const uint8_t> public_seed,
134
                                           std::span<const uint8_t> private_seed,
135
                                           XMSS_Address adrs,
136
                                           XMSS_Hash& hash) :
137
0
      XMSS_WOTS_Base(std::move(params)) {
138
0
   m_key_data.resize(m_params.len());
139
0
   for(size_t i = 0; i < m_params.len(); ++i) {
140
0
      adrs.set_chain_address(static_cast<uint32_t>(i));
141
0
      const auto data = concat<std::vector<uint8_t>>(public_seed, adrs.bytes());
142
0
      hash.prf_keygen(m_key_data[i], private_seed, data);
143
0
   }
144
0
}
145
146
// Constructor for legacy XMSS_PrivateKeys
147
XMSS_WOTS_PrivateKey::XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters params,
148
                                           std::span<const uint8_t> private_seed,
149
                                           XMSS_Address adrs,
150
                                           XMSS_Hash& hash) :
151
0
      XMSS_WOTS_Base(std::move(params)) {
152
0
   m_key_data.resize(m_params.len());
153
154
0
   secure_vector<uint8_t> r;
155
0
   hash.prf(r, private_seed, adrs.bytes());
156
157
0
   for(size_t i = 0; i < m_params.len(); ++i) {
158
0
      XMSS_Tools::concat<size_t>(m_key_data[i], i, 32);
159
0
      hash.prf(m_key_data[i], r, m_key_data[i]);
160
0
   }
161
0
}
162
163
}  // namespace Botan