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