/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 |