Branch data Line data Source code
1 : : // Copyright (c) 2020-2022 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <chainparams.h>
6 : : #include <key.h>
7 : : #include <key_io.h>
8 : : #include <outputtype.h>
9 : : #include <policy/policy.h>
10 : : #include <pubkey.h>
11 : : #include <rpc/util.h>
12 : : #include <script/keyorigin.h>
13 : : #include <script/script.h>
14 : : #include <script/sign.h>
15 : : #include <script/signingprovider.h>
16 : : #include <script/solver.h>
17 : : #include <streams.h>
18 : : #include <test/fuzz/FuzzedDataProvider.h>
19 : : #include <test/fuzz/fuzz.h>
20 : : #include <test/fuzz/util.h>
21 : : #include <util/chaintype.h>
22 : : #include <util/strencodings.h>
23 : :
24 : : #include <array>
25 : : #include <cassert>
26 : : #include <cstddef>
27 : : #include <cstdint>
28 : : #include <numeric>
29 : : #include <optional>
30 : : #include <string>
31 : : #include <vector>
32 : :
33 : 3 : void initialize_key()
34 : : {
35 [ + - + - : 3 : static ECC_Context ecc_context{};
+ - ]
36 : 3 : SelectParams(ChainType::REGTEST);
37 : 3 : }
38 : :
39 [ + - ]: 912 : FUZZ_TARGET(key, .init = initialize_key)
40 : : {
41 : 1000 : const CKey key = [&] {
42 : 500 : CKey k;
43 [ + - ]: 500 : k.Set(buffer.begin(), buffer.end(), true);
44 : 500 : return k;
45 : 500 : }();
46 [ + + ]: 500 : if (!key.IsValid()) {
47 : 4 : return;
48 : : }
49 : :
50 : 496 : {
51 [ - + ]: 496 : assert(key.begin() + key.size() == key.end());
52 [ - + ]: 496 : assert(key.IsCompressed());
53 [ + - ]: 496 : assert(key.size() == 32);
54 [ + - + - : 992 : assert(DecodeSecret(EncodeSecret(key)) == key);
- + ]
55 : : }
56 : :
57 : 496 : {
58 : 496 : CKey invalid_key;
59 [ - + ]: 496 : assert(!(invalid_key == key));
60 : 496 : assert(!invalid_key.IsCompressed());
61 : 496 : assert(!invalid_key.IsValid());
62 : 496 : assert(invalid_key.size() == 0);
63 : 496 : }
64 : :
65 : 496 : {
66 : 496 : CKey uncompressed_key;
67 [ + - ]: 496 : uncompressed_key.Set(buffer.begin(), buffer.end(), false);
68 [ - + ]: 496 : assert(!(uncompressed_key == key));
69 [ - + ]: 496 : assert(!uncompressed_key.IsCompressed());
70 [ - + ]: 496 : assert(key.size() == 32);
71 [ + - - + : 1488 : assert(uncompressed_key.begin() + uncompressed_key.size() == uncompressed_key.end());
+ - - + ]
72 [ - + ]: 496 : assert(uncompressed_key.IsValid());
73 : 0 : }
74 : :
75 : 496 : {
76 : 496 : CKey copied_key;
77 [ + - + - : 1488 : copied_key.Set(key.begin(), key.end(), key.IsCompressed());
+ - ]
78 [ - + ]: 496 : assert(copied_key == key);
79 : 0 : }
80 : :
81 [ + - ]: 496 : const uint256 random_uint256 = Hash(buffer);
82 : :
83 : 496 : {
84 : 496 : CKey child_key;
85 : 496 : ChainCode child_chaincode;
86 [ + - ]: 496 : const bool ok = key.Derive(child_key, child_chaincode, 0, random_uint256);
87 [ - + ]: 496 : assert(ok);
88 [ - + ]: 496 : assert(child_key.IsValid());
89 [ - + ]: 496 : assert(!(child_key == key));
90 [ - + ]: 496 : assert(child_chaincode != random_uint256);
91 : 0 : }
92 : :
93 [ + - ]: 496 : const CPubKey pubkey = key.GetPubKey();
94 : :
95 : 496 : {
96 [ - + ]: 496 : assert(pubkey.size() == 33);
97 [ + - - + ]: 496 : assert(key.VerifyPubKey(pubkey));
98 [ + - - + ]: 496 : assert(pubkey.GetHash() != random_uint256);
99 [ - + ]: 496 : assert(pubkey.begin() + pubkey.size() == pubkey.end());
100 : 496 : assert(pubkey.data() == pubkey.begin());
101 [ - + ]: 496 : assert(pubkey.IsCompressed());
102 [ - + ]: 496 : assert(pubkey.IsValid());
103 [ + - - + ]: 496 : assert(pubkey.IsFullyValid());
104 [ + - + - : 496 : assert(HexToPubKey(HexStr(pubkey)) == pubkey);
- + ]
105 [ + - - + ]: 496 : assert(GetAllDestinationsForKey(pubkey).size() == 3);
106 : : }
107 : :
108 : 496 : {
109 : 496 : DataStream data_stream{};
110 [ + - ]: 496 : pubkey.Serialize(data_stream);
111 : :
112 [ + - ]: 496 : CPubKey pubkey_deserialized;
113 [ + - ]: 496 : pubkey_deserialized.Unserialize(data_stream);
114 [ - + ]: 496 : assert(pubkey_deserialized == pubkey);
115 : 0 : }
116 : :
117 : 496 : {
118 [ + - ]: 496 : const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey);
119 [ + - - + ]: 496 : assert(!tx_pubkey_script.IsPayToScriptHash());
120 [ + - - + ]: 496 : assert(!tx_pubkey_script.IsPayToWitnessScriptHash());
121 [ + - - + ]: 496 : assert(!tx_pubkey_script.IsPushOnly());
122 [ - + ]: 496 : assert(!tx_pubkey_script.IsUnspendable());
123 [ + - - + ]: 496 : assert(tx_pubkey_script.HasValidOps());
124 [ + - - + ]: 496 : assert(tx_pubkey_script.size() == 35);
125 : :
126 [ + - + - : 992 : const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey});
+ - ]
127 [ + - - + ]: 496 : assert(!tx_multisig_script.IsPayToScriptHash());
128 [ + - - + ]: 496 : assert(!tx_multisig_script.IsPayToWitnessScriptHash());
129 [ + - - + ]: 496 : assert(!tx_multisig_script.IsPushOnly());
130 [ - + ]: 496 : assert(!tx_multisig_script.IsUnspendable());
131 [ + - - + ]: 496 : assert(tx_multisig_script.HasValidOps());
132 [ + - - + ]: 496 : assert(tx_multisig_script.size() == 37);
133 : :
134 : 496 : FillableSigningProvider fillable_signing_provider;
135 [ + - - + ]: 496 : assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
136 [ + - - + ]: 496 : assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
137 [ + - - + ]: 496 : assert(fillable_signing_provider.GetKeys().size() == 0);
138 [ + - + - : 496 : assert(!fillable_signing_provider.HaveKey(pubkey.GetID()));
- + ]
139 : :
140 [ + - ]: 496 : const bool ok_add_key = fillable_signing_provider.AddKey(key);
141 [ - + ]: 496 : assert(ok_add_key);
142 [ + - + - : 496 : assert(fillable_signing_provider.HaveKey(pubkey.GetID()));
- + ]
143 : :
144 : 496 : FillableSigningProvider fillable_signing_provider_pub;
145 [ + - + - : 496 : assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
- + ]
146 : :
147 [ + - ]: 496 : const bool ok_add_key_pubkey = fillable_signing_provider_pub.AddKeyPubKey(key, pubkey);
148 [ - + ]: 496 : assert(ok_add_key_pubkey);
149 [ + - + - : 496 : assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
- + ]
150 : :
151 : 496 : TxoutType which_type_tx_pubkey;
152 [ + - ]: 496 : const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
153 [ - + ]: 496 : assert(is_standard_tx_pubkey);
154 [ - + ]: 496 : assert(which_type_tx_pubkey == TxoutType::PUBKEY);
155 : :
156 : 496 : TxoutType which_type_tx_multisig;
157 [ + - ]: 496 : const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
158 [ - + ]: 496 : assert(is_standard_tx_multisig);
159 [ - + ]: 496 : assert(which_type_tx_multisig == TxoutType::MULTISIG);
160 : :
161 : 496 : std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
162 [ + - ]: 496 : const TxoutType outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
163 [ - + ]: 496 : assert(outtype_tx_pubkey == TxoutType::PUBKEY);
164 [ - + ]: 496 : assert(v_solutions_ret_tx_pubkey.size() == 1);
165 [ - + ]: 496 : assert(v_solutions_ret_tx_pubkey[0].size() == 33);
166 : :
167 : 496 : std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
168 [ + - ]: 496 : const TxoutType outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
169 [ - + ]: 496 : assert(outtype_tx_multisig == TxoutType::MULTISIG);
170 [ - + ]: 496 : assert(v_solutions_ret_tx_multisig.size() == 3);
171 [ - + ]: 496 : assert(v_solutions_ret_tx_multisig[0].size() == 1);
172 [ - + ]: 496 : assert(v_solutions_ret_tx_multisig[1].size() == 33);
173 [ - + ]: 496 : assert(v_solutions_ret_tx_multisig[2].size() == 1);
174 : :
175 : 496 : OutputType output_type{};
176 [ + - ]: 496 : const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
177 : 496 : assert(output_type == OutputType::LEGACY);
178 [ + - - + ]: 496 : assert(IsValidDestination(tx_destination));
179 [ + - + - : 992 : assert(PKHash{pubkey} == *std::get_if<PKHash>(&tx_destination));
- + ]
180 : :
181 [ + - ]: 496 : const CScript script_for_destination = GetScriptForDestination(tx_destination);
182 [ - + - + ]: 496 : assert(script_for_destination.size() == 25);
183 : :
184 [ + - ]: 496 : const std::string destination_address = EncodeDestination(tx_destination);
185 [ + - - + ]: 992 : assert(DecodeDestination(destination_address) == tx_destination);
186 : :
187 [ + - ]: 496 : const CPubKey pubkey_from_address_string = AddrToPubKey(fillable_signing_provider, destination_address);
188 [ - + ]: 496 : assert(pubkey_from_address_string == pubkey);
189 : :
190 [ + - ]: 496 : CKeyID key_id = pubkey.GetID();
191 [ - + ]: 496 : assert(!key_id.IsNull());
192 [ - + ]: 496 : assert(key_id == CKeyID{key_id});
193 [ + - - + ]: 496 : assert(key_id == GetKeyForDestination(fillable_signing_provider, tx_destination));
194 : :
195 [ + - ]: 496 : CPubKey pubkey_out;
196 [ + - ]: 496 : const bool ok_get_pubkey = fillable_signing_provider.GetPubKey(key_id, pubkey_out);
197 [ - + ]: 496 : assert(ok_get_pubkey);
198 : :
199 : 496 : CKey key_out;
200 [ + - ]: 496 : const bool ok_get_key = fillable_signing_provider.GetKey(key_id, key_out);
201 [ - + ]: 496 : assert(ok_get_key);
202 [ + - - + ]: 496 : assert(fillable_signing_provider.GetKeys().size() == 1);
203 [ + - - + ]: 496 : assert(fillable_signing_provider.HaveKey(key_id));
204 : :
205 : 496 : KeyOriginInfo key_origin_info;
206 : 496 : const bool ok_get_key_origin = fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info);
207 : 496 : assert(!ok_get_key_origin);
208 : 496 : }
209 : :
210 : 496 : {
211 [ + - ]: 496 : const std::vector<unsigned char> vch_pubkey{pubkey.begin(), pubkey.end()};
212 [ - + ]: 496 : assert(CPubKey::ValidSize(vch_pubkey));
213 [ + - - + ]: 992 : assert(!CPubKey::ValidSize({pubkey.begin(), pubkey.begin() + pubkey.size() - 1}));
214 : :
215 : 496 : const CPubKey pubkey_ctor_1{vch_pubkey};
216 [ - + ]: 496 : assert(pubkey == pubkey_ctor_1);
217 : :
218 : 496 : const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()};
219 [ - + ]: 496 : assert(pubkey == pubkey_ctor_2);
220 : :
221 : 496 : CPubKey pubkey_set;
222 : 496 : pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end());
223 [ - + ]: 496 : assert(pubkey == pubkey_set);
224 : 0 : }
225 : :
226 : 496 : {
227 [ - + ]: 496 : const CPubKey invalid_pubkey{};
228 [ - + ]: 496 : assert(!invalid_pubkey.IsValid());
229 [ + - - + ]: 496 : assert(!invalid_pubkey.IsFullyValid());
230 [ - + ]: 496 : assert(!(pubkey == invalid_pubkey));
231 : 496 : assert(pubkey != invalid_pubkey);
232 [ - + ]: 496 : assert(pubkey < invalid_pubkey);
233 : : }
234 : :
235 : : {
236 : : // Cover CPubKey's operator[](unsigned int pos)
237 : : unsigned int sum = 0;
238 [ + + ]: 16864 : for (size_t i = 0; i < pubkey.size(); ++i) {
239 : 16368 : sum += pubkey[i];
240 : : }
241 [ - + ]: 992 : assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum);
242 : : }
243 : :
244 : 496 : {
245 : 496 : CPubKey decompressed_pubkey = pubkey;
246 [ - + ]: 496 : assert(decompressed_pubkey.IsCompressed());
247 : :
248 [ + - ]: 496 : const bool ok = decompressed_pubkey.Decompress();
249 [ - + ]: 496 : assert(ok);
250 [ - + ]: 496 : assert(!decompressed_pubkey.IsCompressed());
251 [ - + ]: 496 : assert(decompressed_pubkey.size() == 65);
252 : : }
253 : :
254 : 496 : {
255 : 496 : std::vector<unsigned char> vch_sig;
256 [ + - ]: 496 : const bool ok = key.Sign(random_uint256, vch_sig, false);
257 [ - + ]: 496 : assert(ok);
258 [ + - - + ]: 496 : assert(pubkey.Verify(random_uint256, vch_sig));
259 [ + - - + ]: 496 : assert(CPubKey::CheckLowS(vch_sig));
260 : :
261 [ + - ]: 496 : const std::vector<unsigned char> vch_invalid_sig{vch_sig.begin(), vch_sig.begin() + vch_sig.size() - 1};
262 [ + - - + ]: 496 : assert(!pubkey.Verify(random_uint256, vch_invalid_sig));
263 [ + - - + ]: 496 : assert(!CPubKey::CheckLowS(vch_invalid_sig));
264 : 496 : }
265 : :
266 : 496 : {
267 : 496 : std::vector<unsigned char> vch_compact_sig;
268 [ + - ]: 496 : const bool ok_sign_compact = key.SignCompact(random_uint256, vch_compact_sig);
269 [ - + ]: 496 : assert(ok_sign_compact);
270 : :
271 [ + - ]: 496 : CPubKey recover_pubkey;
272 [ + - ]: 496 : const bool ok_recover_compact = recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig);
273 [ - + ]: 496 : assert(ok_recover_compact);
274 [ - + ]: 496 : assert(recover_pubkey == pubkey);
275 : 0 : }
276 : :
277 : 496 : {
278 [ + - ]: 496 : CPubKey child_pubkey;
279 : 496 : ChainCode child_chaincode;
280 [ + - ]: 496 : const bool ok = pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256);
281 [ - + ]: 496 : assert(ok);
282 [ - + ]: 496 : assert(child_pubkey != pubkey);
283 [ - + ]: 496 : assert(child_pubkey.IsCompressed());
284 [ + - - + ]: 496 : assert(child_pubkey.IsFullyValid());
285 [ - + ]: 496 : assert(child_pubkey.IsValid());
286 [ - + ]: 496 : assert(child_pubkey.size() == 33);
287 [ - + ]: 496 : assert(child_chaincode != random_uint256);
288 : : }
289 : :
290 [ + - ]: 496 : const CPrivKey priv_key = key.GetPrivKey();
291 : :
292 : 496 : {
293 [ + + ]: 1488 : for (const bool skip_check : {true, false}) {
294 : 992 : CKey loaded_key;
295 [ + - ]: 992 : const bool ok = loaded_key.Load(priv_key, pubkey, skip_check);
296 [ - + ]: 992 : assert(ok);
297 [ - + ]: 992 : assert(key == loaded_key);
298 : 992 : }
299 : : }
300 : 500 : }
301 : :
302 [ + - ]: 765 : FUZZ_TARGET(ellswift_roundtrip, .init = initialize_key)
303 : : {
304 : 353 : FuzzedDataProvider fdp{buffer.data(), buffer.size()};
305 : :
306 : 353 : CKey key = ConsumePrivateKey(fdp, /*compressed=*/true);
307 [ + + ]: 353 : if (!key.IsValid()) return;
308 : :
309 [ + - ]: 351 : auto ent32 = fdp.ConsumeBytes<std::byte>(32);
310 [ + - ]: 351 : ent32.resize(32);
311 : :
312 [ + - ]: 351 : auto encoded_ellswift = key.EllSwiftCreate(ent32);
313 [ + - ]: 351 : auto decoded_pubkey = encoded_ellswift.Decode();
314 : :
315 : 351 : uint256 hash{ConsumeUInt256(fdp)};
316 : 351 : std::vector<unsigned char> sig;
317 [ + - ]: 351 : key.Sign(hash, sig);
318 [ + - - + ]: 351 : assert(decoded_pubkey.Verify(hash, sig));
319 : 353 : }
320 : :
321 [ + - ]: 666 : FUZZ_TARGET(bip324_ecdh, .init = initialize_key)
322 : : {
323 : 254 : FuzzedDataProvider fdp{buffer.data(), buffer.size()};
324 : :
325 : : // We generate private key, k1.
326 : 254 : CKey k1 = ConsumePrivateKey(fdp, /*compressed=*/true);
327 [ + + ]: 254 : if (!k1.IsValid()) return;
328 : :
329 : : // They generate private key, k2.
330 : 253 : CKey k2 = ConsumePrivateKey(fdp, /*compressed=*/true);
331 [ + + ]: 253 : if (!k2.IsValid()) return;
332 : :
333 : : // We construct an ellswift encoding for our key, k1_ellswift.
334 [ + - ]: 251 : auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
335 [ + - ]: 251 : ent32_1.resize(32);
336 [ + - ]: 251 : auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
337 : :
338 : : // They construct an ellswift encoding for their key, k2_ellswift.
339 [ + - ]: 251 : auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
340 [ + - ]: 251 : ent32_2.resize(32);
341 [ + - ]: 251 : auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
342 : :
343 : : // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
344 [ + - ]: 251 : auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
345 [ + - ]: 251 : ent32_2_bad.resize(32);
346 [ + - ]: 251 : auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
347 [ - + ]: 502 : assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
348 : :
349 : : // Determine who is who.
350 : 251 : bool initiating = fdp.ConsumeBool();
351 : :
352 : : // We compute our shared secret using our key and their public key.
353 [ + - ]: 251 : auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
354 : : // They compute their shared secret using their key and our public key.
355 [ + - ]: 251 : auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
356 : : // Those must match, as everyone is behaving correctly.
357 [ - + ]: 251 : assert(ecdh_secret_1 == ecdh_secret_2);
358 : :
359 [ + + ]: 251 : if (k1_ellswift != k2_ellswift) {
360 : : // Unless the two keys are exactly identical, acting as the wrong party breaks things.
361 [ + - ]: 243 : auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
362 [ - + ]: 243 : assert(ecdh_secret_bad != ecdh_secret_1);
363 : : }
364 : :
365 [ + + ]: 502 : if (k2_ellswift_bad != k2_ellswift) {
366 : : // Unless both encodings created by them are identical, using the second one breaks things.
367 [ + - ]: 68 : auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
368 [ - + ]: 68 : assert(ecdh_secret_bad != ecdh_secret_1);
369 : : }
370 : 256 : }
|