Bitcoin Core  26.1.0
P2P Digital Currency
key.cpp
Go to the documentation of this file.
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>
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 
34 {
35  ECC_Start();
37 }
38 
40 {
41  const CKey key = [&] {
42  CKey k;
43  k.Set(buffer.begin(), buffer.end(), true);
44  return k;
45  }();
46  if (!key.IsValid()) {
47  return;
48  }
49 
50  {
51  assert(key.begin() + key.size() == key.end());
52  assert(key.IsCompressed());
53  assert(key.size() == 32);
54  assert(DecodeSecret(EncodeSecret(key)) == key);
55  }
56 
57  {
58  CKey invalid_key;
59  assert(!(invalid_key == key));
60  assert(!invalid_key.IsCompressed());
61  assert(!invalid_key.IsValid());
62  assert(invalid_key.size() == 0);
63  }
64 
65  {
66  CKey uncompressed_key;
67  uncompressed_key.Set(buffer.begin(), buffer.end(), false);
68  assert(!(uncompressed_key == key));
69  assert(!uncompressed_key.IsCompressed());
70  assert(key.size() == 32);
71  assert(uncompressed_key.begin() + uncompressed_key.size() == uncompressed_key.end());
72  assert(uncompressed_key.IsValid());
73  }
74 
75  {
76  CKey copied_key;
77  copied_key.Set(key.begin(), key.end(), key.IsCompressed());
78  assert(copied_key == key);
79  }
80 
81  {
82  CKey negated_key = key;
83  negated_key.Negate();
84  assert(negated_key.IsValid());
85  assert(!(negated_key == key));
86 
87  negated_key.Negate();
88  assert(negated_key == key);
89  }
90 
91  const uint256 random_uint256 = Hash(buffer);
92 
93  {
94  CKey child_key;
95  ChainCode child_chaincode;
96  const bool ok = key.Derive(child_key, child_chaincode, 0, random_uint256);
97  assert(ok);
98  assert(child_key.IsValid());
99  assert(!(child_key == key));
100  assert(child_chaincode != random_uint256);
101  }
102 
103  const CPubKey pubkey = key.GetPubKey();
104 
105  {
106  assert(pubkey.size() == 33);
107  assert(key.VerifyPubKey(pubkey));
108  assert(pubkey.GetHash() != random_uint256);
109  assert(pubkey.begin() + pubkey.size() == pubkey.end());
110  assert(pubkey.data() == pubkey.begin());
111  assert(pubkey.IsCompressed());
112  assert(pubkey.IsValid());
113  assert(pubkey.IsFullyValid());
114  assert(HexToPubKey(HexStr(pubkey)) == pubkey);
115  assert(GetAllDestinationsForKey(pubkey).size() == 3);
116  }
117 
118  {
119  DataStream data_stream{};
120  pubkey.Serialize(data_stream);
121 
122  CPubKey pubkey_deserialized;
123  pubkey_deserialized.Unserialize(data_stream);
124  assert(pubkey_deserialized == pubkey);
125  }
126 
127  {
128  const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey);
129  assert(!tx_pubkey_script.IsPayToScriptHash());
130  assert(!tx_pubkey_script.IsPayToWitnessScriptHash());
131  assert(!tx_pubkey_script.IsPushOnly());
132  assert(!tx_pubkey_script.IsUnspendable());
133  assert(tx_pubkey_script.HasValidOps());
134  assert(tx_pubkey_script.size() == 35);
135 
136  const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey});
137  assert(!tx_multisig_script.IsPayToScriptHash());
138  assert(!tx_multisig_script.IsPayToWitnessScriptHash());
139  assert(!tx_multisig_script.IsPushOnly());
140  assert(!tx_multisig_script.IsUnspendable());
141  assert(tx_multisig_script.HasValidOps());
142  assert(tx_multisig_script.size() == 37);
143 
144  FillableSigningProvider fillable_signing_provider;
145  assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
146  assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
147  assert(fillable_signing_provider.GetKeys().size() == 0);
148  assert(!fillable_signing_provider.HaveKey(pubkey.GetID()));
149 
150  const bool ok_add_key = fillable_signing_provider.AddKey(key);
151  assert(ok_add_key);
152  assert(fillable_signing_provider.HaveKey(pubkey.GetID()));
153 
154  FillableSigningProvider fillable_signing_provider_pub;
155  assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
156 
157  const bool ok_add_key_pubkey = fillable_signing_provider_pub.AddKeyPubKey(key, pubkey);
158  assert(ok_add_key_pubkey);
159  assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
160 
161  TxoutType which_type_tx_pubkey;
162  const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
163  assert(is_standard_tx_pubkey);
164  assert(which_type_tx_pubkey == TxoutType::PUBKEY);
165 
166  TxoutType which_type_tx_multisig;
167  const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
168  assert(is_standard_tx_multisig);
169  assert(which_type_tx_multisig == TxoutType::MULTISIG);
170 
171  std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
172  const TxoutType outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
173  assert(outtype_tx_pubkey == TxoutType::PUBKEY);
174  assert(v_solutions_ret_tx_pubkey.size() == 1);
175  assert(v_solutions_ret_tx_pubkey[0].size() == 33);
176 
177  std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
178  const TxoutType outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
179  assert(outtype_tx_multisig == TxoutType::MULTISIG);
180  assert(v_solutions_ret_tx_multisig.size() == 3);
181  assert(v_solutions_ret_tx_multisig[0].size() == 1);
182  assert(v_solutions_ret_tx_multisig[1].size() == 33);
183  assert(v_solutions_ret_tx_multisig[2].size() == 1);
184 
185  OutputType output_type{};
186  const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
187  assert(output_type == OutputType::LEGACY);
188  assert(IsValidDestination(tx_destination));
189  assert(PKHash{pubkey} == *std::get_if<PKHash>(&tx_destination));
190 
191  const CScript script_for_destination = GetScriptForDestination(tx_destination);
192  assert(script_for_destination.size() == 25);
193 
194  const std::string destination_address = EncodeDestination(tx_destination);
195  assert(DecodeDestination(destination_address) == tx_destination);
196 
197  const CPubKey pubkey_from_address_string = AddrToPubKey(fillable_signing_provider, destination_address);
198  assert(pubkey_from_address_string == pubkey);
199 
200  CKeyID key_id = pubkey.GetID();
201  assert(!key_id.IsNull());
202  assert(key_id == CKeyID{key_id});
203  assert(key_id == GetKeyForDestination(fillable_signing_provider, tx_destination));
204 
205  CPubKey pubkey_out;
206  const bool ok_get_pubkey = fillable_signing_provider.GetPubKey(key_id, pubkey_out);
207  assert(ok_get_pubkey);
208 
209  CKey key_out;
210  const bool ok_get_key = fillable_signing_provider.GetKey(key_id, key_out);
211  assert(ok_get_key);
212  assert(fillable_signing_provider.GetKeys().size() == 1);
213  assert(fillable_signing_provider.HaveKey(key_id));
214 
215  KeyOriginInfo key_origin_info;
216  const bool ok_get_key_origin = fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info);
217  assert(!ok_get_key_origin);
218  }
219 
220  {
221  const std::vector<unsigned char> vch_pubkey{pubkey.begin(), pubkey.end()};
222  assert(CPubKey::ValidSize(vch_pubkey));
223  assert(!CPubKey::ValidSize({pubkey.begin(), pubkey.begin() + pubkey.size() - 1}));
224 
225  const CPubKey pubkey_ctor_1{vch_pubkey};
226  assert(pubkey == pubkey_ctor_1);
227 
228  const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()};
229  assert(pubkey == pubkey_ctor_2);
230 
231  CPubKey pubkey_set;
232  pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end());
233  assert(pubkey == pubkey_set);
234  }
235 
236  {
237  const CPubKey invalid_pubkey{};
238  assert(!invalid_pubkey.IsValid());
239  assert(!invalid_pubkey.IsFullyValid());
240  assert(!(pubkey == invalid_pubkey));
241  assert(pubkey != invalid_pubkey);
242  assert(pubkey < invalid_pubkey);
243  }
244 
245  {
246  // Cover CPubKey's operator[](unsigned int pos)
247  unsigned int sum = 0;
248  for (size_t i = 0; i < pubkey.size(); ++i) {
249  sum += pubkey[i];
250  }
251  assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum);
252  }
253 
254  {
255  CPubKey decompressed_pubkey = pubkey;
256  assert(decompressed_pubkey.IsCompressed());
257 
258  const bool ok = decompressed_pubkey.Decompress();
259  assert(ok);
260  assert(!decompressed_pubkey.IsCompressed());
261  assert(decompressed_pubkey.size() == 65);
262  }
263 
264  {
265  std::vector<unsigned char> vch_sig;
266  const bool ok = key.Sign(random_uint256, vch_sig, false);
267  assert(ok);
268  assert(pubkey.Verify(random_uint256, vch_sig));
269  assert(CPubKey::CheckLowS(vch_sig));
270 
271  const std::vector<unsigned char> vch_invalid_sig{vch_sig.begin(), vch_sig.begin() + vch_sig.size() - 1};
272  assert(!pubkey.Verify(random_uint256, vch_invalid_sig));
273  assert(!CPubKey::CheckLowS(vch_invalid_sig));
274  }
275 
276  {
277  std::vector<unsigned char> vch_compact_sig;
278  const bool ok_sign_compact = key.SignCompact(random_uint256, vch_compact_sig);
279  assert(ok_sign_compact);
280 
281  CPubKey recover_pubkey;
282  const bool ok_recover_compact = recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig);
283  assert(ok_recover_compact);
284  assert(recover_pubkey == pubkey);
285  }
286 
287  {
288  CPubKey child_pubkey;
289  ChainCode child_chaincode;
290  const bool ok = pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256);
291  assert(ok);
292  assert(child_pubkey != pubkey);
293  assert(child_pubkey.IsCompressed());
294  assert(child_pubkey.IsFullyValid());
295  assert(child_pubkey.IsValid());
296  assert(child_pubkey.size() == 33);
297  assert(child_chaincode != random_uint256);
298  }
299 
300  const CPrivKey priv_key = key.GetPrivKey();
301 
302  {
303  for (const bool skip_check : {true, false}) {
304  CKey loaded_key;
305  const bool ok = loaded_key.Load(priv_key, pubkey, skip_check);
306  assert(ok);
307  assert(key == loaded_key);
308  }
309  }
310 }
311 
312 FUZZ_TARGET(ellswift_roundtrip, .init = initialize_key)
313 {
314  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
315 
316  CKey key = ConsumePrivateKey(fdp, /*compressed=*/true);
317  if (!key.IsValid()) return;
318 
319  auto ent32 = fdp.ConsumeBytes<std::byte>(32);
320  ent32.resize(32);
321 
322  auto encoded_ellswift = key.EllSwiftCreate(ent32);
323  auto decoded_pubkey = encoded_ellswift.Decode();
324 
325  assert(key.VerifyPubKey(decoded_pubkey));
326 }
327 
329 {
330  FuzzedDataProvider fdp{buffer.data(), buffer.size()};
331 
332  // We generate private key, k1.
333  CKey k1 = ConsumePrivateKey(fdp, /*compressed=*/true);
334  if (!k1.IsValid()) return;
335 
336  // They generate private key, k2.
337  CKey k2 = ConsumePrivateKey(fdp, /*compressed=*/true);
338  if (!k2.IsValid()) return;
339 
340  // We construct an ellswift encoding for our key, k1_ellswift.
341  auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
342  ent32_1.resize(32);
343  auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
344 
345  // They construct an ellswift encoding for their key, k2_ellswift.
346  auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
347  ent32_2.resize(32);
348  auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
349 
350  // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
351  auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
352  ent32_2_bad.resize(32);
353  auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
354  assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
355 
356  // Determine who is who.
357  bool initiating = fdp.ConsumeBool();
358 
359  // We compute our shared secret using our key and their public key.
360  auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
361  // They compute their shared secret using their key and our public key.
362  auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
363  // Those must match, as everyone is behaving correctly.
364  assert(ecdh_secret_1 == ecdh_secret_2);
365 
366  if (k1_ellswift != k2_ellswift) {
367  // Unless the two keys are exactly identical, acting as the wrong party breaks things.
368  auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
369  assert(ecdh_secret_bad != ecdh_secret_1);
370  }
371 
372  if (k2_ellswift_bad != k2_ellswift) {
373  // Unless both encodings created by them are identical, using the second one breaks things.
374  auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
375  assert(ecdh_secret_bad != ecdh_secret_1);
376  }
377 }
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: solver.cpp:214
void ECC_Start()
Initialize the elliptic curve support.
Definition: key.cpp:429
CPrivKey GetPrivKey() const
Convert the private key to a CPrivKey (serialized OpenSSL private key data).
Definition: key.cpp:175
assert(!tx.IsCoinBase())
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
bool Negate()
Negate private key.
Definition: key.cpp:169
EllSwiftPubKey EllSwiftCreate(Span< const std::byte > entropy) const
Create an ellswift-encoded public key for this key, with specified entropy.
Definition: key.cpp:336
bool IsPayToScriptHash() const
Definition: script.cpp:204
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:242
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:188
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:140
void Set(const T pbegin, const T pend)
Initialize a public key using begin/end iterators to byte data.
Definition: pubkey.h:89
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:170
CPubKey HexToPubKey(const std::string &hex_in)
Definition: util.cpp:179
static bool CheckLowS(const std::vector< unsigned char > &vchSig)
Check whether a signature is normalized (lower-S).
Definition: pubkey.cpp:405
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
bool Derive(CPubKey &pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const
Derive BIP32 child pubkey.
Definition: pubkey.cpp:325
void Unserialize(Stream &s)
Definition: pubkey.h:148
bool HasValidOps() const
Check if the script contains valid OP_CODES.
Definition: script.cpp:273
bool IsStandard(const CScript &scriptPubKey, const std::optional< unsigned > &max_datacarrier_bytes, TxoutType &whichType)
Definition: policy.cpp:70
const unsigned char * begin() const
Definition: key.h:115
ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey &their_ellswift, const EllSwiftPubKey &our_ellswift, bool initiating) const
Compute a BIP324-style ECDH shared secret.
Definition: key.cpp:352
bool IsSegWitOutput(const SigningProvider &provider, const CScript &script)
Check whether a scriptPubKey is known to be segwit.
Definition: sign.cpp:765
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:164
const unsigned char * begin() const
Definition: pubkey.h:114
OutputType
Definition: outputtype.h:17
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
Definition: outputtype.cpp:71
bool IsUnspendable() const
Returns whether the script is guaranteed to fail at execution, regardless of the initial stack...
Definition: script.h:551
bool SignCompact(const uint256 &hash, std::vector< unsigned char > &vchSig) const
Create a compact signature (65 bytes), which allows reconstructing the used public key...
Definition: key.cpp:255
void initialize_key()
Definition: key.cpp:33
volatile double sum
Definition: examples.cpp:10
void Serialize(Stream &s) const
Implement serialization, as if this was a byte vector.
Definition: pubkey.h:141
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
CPrivKey is a serialized private key, with all parameters included (SIZE bytes)
Definition: key.h:23
bool Sign(const uint256 &hash, std::vector< unsigned char > &vchSig, bool grind=true, uint32_t test_case=0) const
Create a DER-serialized signature.
Definition: key.cpp:214
static bool ValidSize(const std::vector< unsigned char > &vch)
Definition: pubkey.h:77
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid()) ...
Definition: pubkey.cpp:304
const unsigned char * end() const
Definition: pubkey.h:115
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
bool IsPushOnly(const_iterator pc) const
Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
Definition: script.cpp:239
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:192
bool RecoverCompact(const uint256 &hash, const std::vector< unsigned char > &vchSig)
Recover a public key from a compact signature.
Definition: pubkey.cpp:284
bool IsValid() const
Definition: pubkey.h:189
An encapsulated public key.
Definition: pubkey.h:33
Fillable signing provider that keeps keys in an address->secret map.
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:113
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:112
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:122
constexpr bool IsNull() const
Definition: uint256.h:42
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:99
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:129
256-bit opaque blob.
Definition: uint256.h:106
TxoutType
Definition: solver.h:22
bool Verify(const uint256 &hash, const std::vector< unsigned char > &vchSig) const
Verify a DER signature (~72 bytes).
Definition: pubkey.cpp:267
bool Derive(CKey &keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const
Derive BIP32 child key.
Definition: key.cpp:317
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:412
const unsigned char * end() const
Definition: key.h:116
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:23
FUZZ_TARGET(key,.init=initialize_key)
Definition: key.cpp:39
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:50
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:287
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:209
size_type size() const
Definition: prevector.h:291
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey)
const unsigned char * data() const
Definition: pubkey.h:113
An encapsulated private key.
Definition: key.h:32
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
Definition: hash.h:76
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:209
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:292
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:227
CPubKey Decode() const
Decode to normal compressed CPubKey (for debugging purposes).
Definition: pubkey.cpp:352
CPubKey AddrToPubKey(const FillableSigningProvider &keystore, const std::string &addr_in)
Definition: util.cpp:192
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
Definition: util.cpp:210
bool Decompress()
Turn this public key into an uncompressed public key.
Definition: pubkey.cpp:311
bool IsPayToWitnessScriptHash() const
Definition: script.cpp:213
bool Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck)
Load private key and check that public key matches.
Definition: key.cpp:303
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:119
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:204
virtual bool HaveKey(const CKeyID &address) const override