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