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