1 // Copyright (c) 2020 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 <chainparamsbase.h>
7 #include <key.h>
8 #include <key_io.h>
9 #include <outputtype.h>
10 #include <policy/policy.h>
11 #include <pubkey.h>
12 #include <rpc/util.h>
13 #include <script/keyorigin.h>
14 #include <script/script.h>
15 #include <script/sign.h>
16 #include <script/signingprovider.h>
17 #include <script/standard.h>
18 #include <streams.h>
19 #include <test/fuzz/fuzz.h>
20 #include <util/memory.h>
21 #include <util/strencodings.h>
22 
23 #include <cassert>
24 #include <cstdint>
25 #include <numeric>
26 #include <string>
27 #include <vector>
28 
initialize()29 void initialize()
30 {
31     static const ECCVerifyHandle ecc_verify_handle;
32     ECC_Start();
33     SelectParams(CBaseChainParams::REGTEST);
34 }
35 
test_one_input(const std::vector<uint8_t> & buffer)36 void test_one_input(const std::vector<uint8_t>& buffer)
37 {
38     const CKey key = [&] {
39         CKey k;
40         k.Set(buffer.begin(), buffer.end(), true);
41         return k;
42     }();
43     if (!key.IsValid()) {
44         return;
45     }
46 
47     {
48         assert(key.begin() + key.size() == key.end());
49         assert(key.IsCompressed());
50         assert(key.size() == 32);
51         assert(DecodeSecret(EncodeSecret(key)) == key);
52     }
53 
54     {
55         CKey invalid_key;
56         assert(!(invalid_key == key));
57         assert(!invalid_key.IsCompressed());
58         assert(!invalid_key.IsValid());
59         assert(invalid_key.size() == 0);
60     }
61 
62     {
63         CKey uncompressed_key;
64         uncompressed_key.Set(buffer.begin(), buffer.end(), false);
65         assert(!(uncompressed_key == key));
66         assert(!uncompressed_key.IsCompressed());
67         assert(key.size() == 32);
68         assert(uncompressed_key.begin() + uncompressed_key.size() == uncompressed_key.end());
69         assert(uncompressed_key.IsValid());
70     }
71 
72     {
73         CKey copied_key;
74         copied_key.Set(key.begin(), key.end(), key.IsCompressed());
75         assert(copied_key == key);
76     }
77 
78     {
79         CKey negated_key = key;
80         negated_key.Negate();
81         assert(negated_key.IsValid());
82         assert(!(negated_key == key));
83 
84         negated_key.Negate();
85         assert(negated_key == key);
86     }
87 
88     const uint256 random_uint256 = Hash(buffer);
89 
90     {
91         CKey child_key;
92         ChainCode child_chaincode;
93         const bool ok = key.Derive(child_key, child_chaincode, 0, random_uint256);
94         assert(ok);
95         assert(child_key.IsValid());
96         assert(!(child_key == key));
97         assert(child_chaincode != random_uint256);
98     }
99 
100     const CPubKey pubkey = key.GetPubKey();
101 
102     {
103         assert(pubkey.size() == 33);
104         assert(key.VerifyPubKey(pubkey));
105         assert(pubkey.GetHash() != random_uint256);
106         assert(pubkey.begin() + pubkey.size() == pubkey.end());
107         assert(pubkey.data() == pubkey.begin());
108         assert(pubkey.IsCompressed());
109         assert(pubkey.IsValid());
110         assert(pubkey.IsFullyValid());
111         assert(HexToPubKey(HexStr(pubkey)) == pubkey);
112         assert(GetAllDestinationsForKey(pubkey).size() == 3);
113     }
114 
115     {
116         CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
117         pubkey.Serialize(data_stream);
118 
119         CPubKey pubkey_deserialized;
120         pubkey_deserialized.Unserialize(data_stream);
121         assert(pubkey_deserialized == pubkey);
122     }
123 
124     {
125         const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey);
126         assert(!tx_pubkey_script.IsPayToScriptHash());
127         assert(!tx_pubkey_script.IsPayToWitnessScriptHash());
128         assert(!tx_pubkey_script.IsPushOnly());
129         assert(!tx_pubkey_script.IsUnspendable());
130         assert(tx_pubkey_script.HasValidOps());
131         assert(tx_pubkey_script.size() == 35);
132 
133         const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey});
134         assert(!tx_multisig_script.IsPayToScriptHash());
135         assert(!tx_multisig_script.IsPayToWitnessScriptHash());
136         assert(!tx_multisig_script.IsPushOnly());
137         assert(!tx_multisig_script.IsUnspendable());
138         assert(tx_multisig_script.HasValidOps());
139         assert(tx_multisig_script.size() == 37);
140 
141         FillableSigningProvider fillable_signing_provider;
142         assert(IsSolvable(fillable_signing_provider, tx_pubkey_script));
143         assert(IsSolvable(fillable_signing_provider, tx_multisig_script));
144         assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
145         assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
146         assert(fillable_signing_provider.GetKeys().size() == 0);
147         assert(!fillable_signing_provider.HaveKey(pubkey.GetID()));
148 
149         const bool ok_add_key = fillable_signing_provider.AddKey(key);
150         assert(ok_add_key);
151         assert(fillable_signing_provider.HaveKey(pubkey.GetID()));
152 
153         FillableSigningProvider fillable_signing_provider_pub;
154         assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
155 
156         const bool ok_add_key_pubkey = fillable_signing_provider_pub.AddKeyPubKey(key, pubkey);
157         assert(ok_add_key_pubkey);
158         assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
159 
160         TxoutType which_type_tx_pubkey;
161         const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
162         assert(is_standard_tx_pubkey);
163         assert(which_type_tx_pubkey == TxoutType::PUBKEY);
164 
165         TxoutType which_type_tx_multisig;
166         const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
167         assert(is_standard_tx_multisig);
168         assert(which_type_tx_multisig == TxoutType::MULTISIG);
169 
170         std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
171         const TxoutType outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
172         assert(outtype_tx_pubkey == TxoutType::PUBKEY);
173         assert(v_solutions_ret_tx_pubkey.size() == 1);
174         assert(v_solutions_ret_tx_pubkey[0].size() == 33);
175 
176         std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
177         const TxoutType outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
178         assert(outtype_tx_multisig == TxoutType::MULTISIG);
179         assert(v_solutions_ret_tx_multisig.size() == 3);
180         assert(v_solutions_ret_tx_multisig[0].size() == 1);
181         assert(v_solutions_ret_tx_multisig[1].size() == 33);
182         assert(v_solutions_ret_tx_multisig[2].size() == 1);
183 
184         OutputType output_type{};
185         const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
186         assert(output_type == OutputType::LEGACY);
187         assert(IsValidDestination(tx_destination));
188         assert(CTxDestination{PKHash{pubkey}} == tx_destination);
189 
190         const CScript script_for_destination = GetScriptForDestination(tx_destination);
191         assert(script_for_destination.size() == 25);
192 
193         const std::string destination_address = EncodeDestination(tx_destination);
194         assert(DecodeDestination(destination_address) == tx_destination);
195 
196         const CPubKey pubkey_from_address_string = AddrToPubKey(fillable_signing_provider, destination_address);
197         assert(pubkey_from_address_string == pubkey);
198 
199         CKeyID key_id = pubkey.GetID();
200         assert(!key_id.IsNull());
201         assert(key_id == CKeyID{key_id});
202         assert(key_id == GetKeyForDestination(fillable_signing_provider, tx_destination));
203 
204         CPubKey pubkey_out;
205         const bool ok_get_pubkey = fillable_signing_provider.GetPubKey(key_id, pubkey_out);
206         assert(ok_get_pubkey);
207 
208         CKey key_out;
209         const bool ok_get_key = fillable_signing_provider.GetKey(key_id, key_out);
210         assert(ok_get_key);
211         assert(fillable_signing_provider.GetKeys().size() == 1);
212         assert(fillable_signing_provider.HaveKey(key_id));
213 
214         KeyOriginInfo key_origin_info;
215         const bool ok_get_key_origin = fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info);
216         assert(!ok_get_key_origin);
217     }
218 
219     {
220         const std::vector<unsigned char> vch_pubkey{pubkey.begin(), pubkey.end()};
221         assert(CPubKey::ValidSize(vch_pubkey));
222         assert(!CPubKey::ValidSize({pubkey.begin(), pubkey.begin() + pubkey.size() - 1}));
223 
224         const CPubKey pubkey_ctor_1{vch_pubkey};
225         assert(pubkey == pubkey_ctor_1);
226 
227         const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()};
228         assert(pubkey == pubkey_ctor_2);
229 
230         CPubKey pubkey_set;
231         pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end());
232         assert(pubkey == pubkey_set);
233     }
234 
235     {
236         const CPubKey invalid_pubkey{};
237         assert(!invalid_pubkey.IsValid());
238         assert(!invalid_pubkey.IsFullyValid());
239         assert(!(pubkey == invalid_pubkey));
240         assert(pubkey != invalid_pubkey);
241         assert(pubkey < invalid_pubkey);
242     }
243 
244     {
245         // Cover CPubKey's operator[](unsigned int pos)
246         unsigned int sum = 0;
247         for (size_t i = 0; i < pubkey.size(); ++i) {
248             sum += pubkey[i];
249         }
250         assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum);
251     }
252 
253     {
254         CPubKey decompressed_pubkey = pubkey;
255         assert(decompressed_pubkey.IsCompressed());
256 
257         const bool ok = decompressed_pubkey.Decompress();
258         assert(ok);
259         assert(!decompressed_pubkey.IsCompressed());
260         assert(decompressed_pubkey.size() == 65);
261     }
262 
263     {
264         std::vector<unsigned char> vch_sig;
265         const bool ok = key.Sign(random_uint256, vch_sig, false);
266         assert(ok);
267         assert(pubkey.Verify(random_uint256, vch_sig));
268         assert(CPubKey::CheckLowS(vch_sig));
269 
270         const std::vector<unsigned char> vch_invalid_sig{vch_sig.begin(), vch_sig.begin() + vch_sig.size() - 1};
271         assert(!pubkey.Verify(random_uint256, vch_invalid_sig));
272         assert(!CPubKey::CheckLowS(vch_invalid_sig));
273     }
274 
275     {
276         std::vector<unsigned char> vch_compact_sig;
277         const bool ok_sign_compact = key.SignCompact(random_uint256, vch_compact_sig);
278         assert(ok_sign_compact);
279 
280         CPubKey recover_pubkey;
281         const bool ok_recover_compact = recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig);
282         assert(ok_recover_compact);
283         assert(recover_pubkey == pubkey);
284     }
285 
286     {
287         CPubKey child_pubkey;
288         ChainCode child_chaincode;
289         const bool ok = pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256);
290         assert(ok);
291         assert(child_pubkey != pubkey);
292         assert(child_pubkey.IsCompressed());
293         assert(child_pubkey.IsFullyValid());
294         assert(child_pubkey.IsValid());
295         assert(child_pubkey.size() == 33);
296         assert(child_chaincode != random_uint256);
297     }
298 
299     const CPrivKey priv_key = key.GetPrivKey();
300 
301     {
302         for (const bool skip_check : {true, false}) {
303             CKey loaded_key;
304             const bool ok = loaded_key.Load(priv_key, pubkey, skip_check);
305             assert(ok);
306             assert(key == loaded_key);
307         }
308     }
309 }
310