Changeset View
Changeset View
Standalone View
Standalone View
src/test/fuzz/key.cpp
- This file was added.
// Copyright (c) 2020 The Bitcoin Core developers | |||||
// Distributed under the MIT software license, see the accompanying | |||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |||||
#include <chainparams.h> | |||||
#include <chainparamsbase.h> | |||||
#include <config.h> | |||||
#include <key.h> | |||||
#include <key_io.h> | |||||
#include <outputtype.h> | |||||
#include <policy/policy.h> | |||||
#include <pubkey.h> | |||||
#include <rpc/util.h> | |||||
#include <script/keyorigin.h> | |||||
#include <script/script.h> | |||||
#include <script/sign.h> | |||||
#include <script/signingprovider.h> | |||||
#include <script/standard.h> | |||||
#include <streams.h> | |||||
#include <util/strencodings.h> | |||||
#include <test/fuzz/fuzz.h> | |||||
#include <cassert> | |||||
#include <cstdint> | |||||
#include <numeric> | |||||
#include <string> | |||||
#include <vector> | |||||
void initialize() { | |||||
static const ECCVerifyHandle ecc_verify_handle; | |||||
ECC_Start(); | |||||
SelectParams(CBaseChainParams::REGTEST); | |||||
} | |||||
void test_one_input(const std::vector<uint8_t> &buffer) { | |||||
const CKey key = [&] { | |||||
CKey k; | |||||
k.Set(buffer.begin(), buffer.end(), true); | |||||
return k; | |||||
}(); | |||||
if (!key.IsValid()) { | |||||
return; | |||||
} | |||||
{ | |||||
assert(key.begin() + key.size() == key.end()); | |||||
assert(key.IsCompressed()); | |||||
assert(key.size() == 32); | |||||
assert(DecodeSecret(EncodeSecret(key)) == key); | |||||
} | |||||
{ | |||||
CKey invalid_key; | |||||
assert(!(invalid_key == key)); | |||||
assert(!invalid_key.IsCompressed()); | |||||
assert(!invalid_key.IsValid()); | |||||
assert(invalid_key.size() == 0); | |||||
} | |||||
{ | |||||
CKey uncompressed_key; | |||||
uncompressed_key.Set(buffer.begin(), buffer.end(), false); | |||||
assert(!(uncompressed_key == key)); | |||||
assert(!uncompressed_key.IsCompressed()); | |||||
assert(key.size() == 32); | |||||
assert(uncompressed_key.begin() + uncompressed_key.size() == | |||||
uncompressed_key.end()); | |||||
assert(uncompressed_key.IsValid()); | |||||
} | |||||
{ | |||||
CKey copied_key; | |||||
copied_key.Set(key.begin(), key.end(), key.IsCompressed()); | |||||
assert(copied_key == key); | |||||
} | |||||
{ | |||||
CKey negated_key = key; | |||||
negated_key.Negate(); | |||||
assert(negated_key.IsValid()); | |||||
assert(!(negated_key == key)); | |||||
negated_key.Negate(); | |||||
assert(negated_key == key); | |||||
} | |||||
const uint256 random_uint256 = Hash(buffer.begin(), buffer.end()); | |||||
{ | |||||
CKey child_key; | |||||
ChainCode child_chaincode; | |||||
const bool ok = | |||||
key.Derive(child_key, child_chaincode, 0, random_uint256); | |||||
assert(ok); | |||||
assert(child_key.IsValid()); | |||||
assert(!(child_key == key)); | |||||
assert(child_chaincode != random_uint256); | |||||
} | |||||
const CPubKey pubkey = key.GetPubKey(); | |||||
{ | |||||
assert(pubkey.size() == 33); | |||||
assert(key.VerifyPubKey(pubkey)); | |||||
assert(pubkey.GetHash() != random_uint256); | |||||
assert(pubkey.begin() + pubkey.size() == pubkey.end()); | |||||
assert(pubkey.data() == pubkey.begin()); | |||||
assert(pubkey.IsCompressed()); | |||||
assert(pubkey.IsValid()); | |||||
assert(pubkey.IsFullyValid()); | |||||
assert(HexToPubKey(HexStr(pubkey.begin(), pubkey.end())) == pubkey); | |||||
assert(GetAllDestinationsForKey(pubkey).size() == 1); | |||||
} | |||||
{ | |||||
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION}; | |||||
pubkey.Serialize(data_stream); | |||||
CPubKey pubkey_deserialized; | |||||
pubkey_deserialized.Unserialize(data_stream); | |||||
assert(pubkey_deserialized == pubkey); | |||||
} | |||||
{ | |||||
const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey); | |||||
assert(!tx_pubkey_script.IsPayToScriptHash()); | |||||
assert(!tx_pubkey_script.IsPushOnly()); | |||||
assert(!tx_pubkey_script.IsUnspendable()); | |||||
assert(tx_pubkey_script.HasValidOps()); | |||||
assert(tx_pubkey_script.size() == 35); | |||||
const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey}); | |||||
assert(!tx_multisig_script.IsPayToScriptHash()); | |||||
assert(!tx_multisig_script.IsPushOnly()); | |||||
assert(!tx_multisig_script.IsUnspendable()); | |||||
assert(tx_multisig_script.HasValidOps()); | |||||
assert(tx_multisig_script.size() == 37); | |||||
FillableSigningProvider fillable_signing_provider; | |||||
assert(IsSolvable(fillable_signing_provider, tx_pubkey_script)); | |||||
assert(IsSolvable(fillable_signing_provider, tx_multisig_script)); | |||||
assert(fillable_signing_provider.GetKeys().size() == 0); | |||||
assert(!fillable_signing_provider.HaveKey(pubkey.GetID())); | |||||
const bool ok_add_key = fillable_signing_provider.AddKey(key); | |||||
assert(ok_add_key); | |||||
assert(fillable_signing_provider.HaveKey(pubkey.GetID())); | |||||
FillableSigningProvider fillable_signing_provider_pub; | |||||
assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID())); | |||||
const bool ok_add_key_pubkey = | |||||
fillable_signing_provider_pub.AddKeyPubKey(key, pubkey); | |||||
assert(ok_add_key_pubkey); | |||||
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID())); | |||||
txnouttype which_type_tx_pubkey; | |||||
const bool is_standard_tx_pubkey = | |||||
IsStandard(tx_pubkey_script, which_type_tx_pubkey); | |||||
assert(is_standard_tx_pubkey); | |||||
assert(which_type_tx_pubkey == txnouttype::TX_PUBKEY); | |||||
txnouttype which_type_tx_multisig; | |||||
const bool is_standard_tx_multisig = | |||||
IsStandard(tx_multisig_script, which_type_tx_multisig); | |||||
assert(is_standard_tx_multisig); | |||||
assert(which_type_tx_multisig == txnouttype::TX_MULTISIG); | |||||
std::vector<std::vector<uint8_t>> v_solutions_ret_tx_pubkey; | |||||
const txnouttype outtype_tx_pubkey = | |||||
Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey); | |||||
assert(outtype_tx_pubkey == txnouttype::TX_PUBKEY); | |||||
assert(v_solutions_ret_tx_pubkey.size() == 1); | |||||
assert(v_solutions_ret_tx_pubkey[0].size() == 33); | |||||
std::vector<std::vector<uint8_t>> v_solutions_ret_tx_multisig; | |||||
const txnouttype outtype_tx_multisig = | |||||
Solver(tx_multisig_script, v_solutions_ret_tx_multisig); | |||||
assert(outtype_tx_multisig == txnouttype::TX_MULTISIG); | |||||
assert(v_solutions_ret_tx_multisig.size() == 3); | |||||
assert(v_solutions_ret_tx_multisig[0].size() == 1); | |||||
assert(v_solutions_ret_tx_multisig[1].size() == 33); | |||||
assert(v_solutions_ret_tx_multisig[2].size() == 1); | |||||
OutputType output_type{}; | |||||
const CTxDestination tx_destination = | |||||
GetDestinationForKey(pubkey, output_type); | |||||
assert(output_type == OutputType::LEGACY); | |||||
assert(IsValidDestination(tx_destination)); | |||||
assert(CTxDestination{PKHash{pubkey}} == tx_destination); | |||||
const CScript script_for_destination = | |||||
GetScriptForDestination(tx_destination); | |||||
assert(script_for_destination.size() == 25); | |||||
const Config &config = GetConfig(); | |||||
const CChainParams ¶ms = config.GetChainParams(); | |||||
const std::string destination_address = | |||||
EncodeDestination(tx_destination, config); | |||||
assert(DecodeDestination(destination_address, params) == | |||||
tx_destination); | |||||
const CPubKey pubkey_from_address_string = AddrToPubKey( | |||||
params, fillable_signing_provider, destination_address); | |||||
assert(pubkey_from_address_string == pubkey); | |||||
CKeyID key_id = pubkey.GetID(); | |||||
assert(!key_id.IsNull()); | |||||
assert(key_id == CKeyID{key_id}); | |||||
assert(key_id == | |||||
GetKeyForDestination(fillable_signing_provider, tx_destination)); | |||||
CPubKey pubkey_out; | |||||
const bool ok_get_pubkey = | |||||
fillable_signing_provider.GetPubKey(key_id, pubkey_out); | |||||
assert(ok_get_pubkey); | |||||
CKey key_out; | |||||
const bool ok_get_key = | |||||
fillable_signing_provider.GetKey(key_id, key_out); | |||||
assert(ok_get_key); | |||||
assert(fillable_signing_provider.GetKeys().size() == 1); | |||||
assert(fillable_signing_provider.HaveKey(key_id)); | |||||
KeyOriginInfo key_origin_info; | |||||
const bool ok_get_key_origin = | |||||
fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info); | |||||
assert(!ok_get_key_origin); | |||||
} | |||||
{ | |||||
const std::vector<uint8_t> vch_pubkey{pubkey.begin(), pubkey.end()}; | |||||
assert(CPubKey::ValidSize(vch_pubkey)); | |||||
assert(!CPubKey::ValidSize( | |||||
{pubkey.begin(), pubkey.begin() + pubkey.size() - 1})); | |||||
const CPubKey pubkey_ctor_1{vch_pubkey}; | |||||
assert(pubkey == pubkey_ctor_1); | |||||
const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()}; | |||||
assert(pubkey == pubkey_ctor_2); | |||||
CPubKey pubkey_set; | |||||
pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end()); | |||||
assert(pubkey == pubkey_set); | |||||
} | |||||
{ | |||||
const CPubKey invalid_pubkey{}; | |||||
assert(!invalid_pubkey.IsValid()); | |||||
assert(!invalid_pubkey.IsFullyValid()); | |||||
assert(!(pubkey == invalid_pubkey)); | |||||
assert(pubkey != invalid_pubkey); | |||||
assert(pubkey < invalid_pubkey); | |||||
} | |||||
{ | |||||
// Cover CPubKey's operator[](unsigned int pos) | |||||
unsigned int sum = 0; | |||||
for (size_t i = 0; i < pubkey.size(); ++i) { | |||||
sum += pubkey[i]; | |||||
} | |||||
assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum); | |||||
} | |||||
{ | |||||
CPubKey decompressed_pubkey = pubkey; | |||||
assert(decompressed_pubkey.IsCompressed()); | |||||
const bool ok = decompressed_pubkey.Decompress(); | |||||
assert(ok); | |||||
assert(!decompressed_pubkey.IsCompressed()); | |||||
assert(decompressed_pubkey.size() == 65); | |||||
} | |||||
{ | |||||
std::vector<uint8_t> vch_sig_ecdsa; | |||||
const bool ecdsa_ok = | |||||
key.SignECDSA(random_uint256, vch_sig_ecdsa, false); | |||||
assert(ecdsa_ok); | |||||
assert(pubkey.VerifyECDSA(random_uint256, vch_sig_ecdsa)); | |||||
assert(CPubKey::CheckLowS(vch_sig_ecdsa)); | |||||
const std::vector<uint8_t> vch_invalid_sig_ecdsa{ | |||||
vch_sig_ecdsa.begin(), | |||||
vch_sig_ecdsa.begin() + vch_sig_ecdsa.size() - 1}; | |||||
assert(!pubkey.VerifyECDSA(random_uint256, vch_invalid_sig_ecdsa)); | |||||
assert(!CPubKey::CheckLowS(vch_invalid_sig_ecdsa)); | |||||
std::vector<uint8_t> vch_sig_schnorr; | |||||
const bool schnorr_ok = | |||||
key.SignSchnorr(random_uint256, vch_sig_schnorr); | |||||
assert(schnorr_ok); | |||||
assert(vch_sig_schnorr.size() == 64); | |||||
assert(pubkey.VerifySchnorr(random_uint256, vch_sig_schnorr)); | |||||
const std::vector<uint8_t> vch_invalid_sig_schnorr{ | |||||
vch_sig_schnorr.begin(), | |||||
vch_sig_schnorr.begin() + vch_sig_schnorr.size() - 1}; | |||||
assert(!pubkey.VerifySchnorr(random_uint256, vch_invalid_sig_schnorr)); | |||||
} | |||||
{ | |||||
std::vector<uint8_t> vch_compact_sig; | |||||
const bool ok_sign_compact = | |||||
key.SignCompact(random_uint256, vch_compact_sig); | |||||
assert(ok_sign_compact); | |||||
CPubKey recover_pubkey; | |||||
const bool ok_recover_compact = | |||||
recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig); | |||||
assert(ok_recover_compact); | |||||
assert(recover_pubkey == pubkey); | |||||
} | |||||
{ | |||||
CPubKey child_pubkey; | |||||
ChainCode child_chaincode; | |||||
const bool ok = | |||||
pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256); | |||||
assert(ok); | |||||
assert(child_pubkey != pubkey); | |||||
assert(child_pubkey.IsCompressed()); | |||||
assert(child_pubkey.IsFullyValid()); | |||||
assert(child_pubkey.IsValid()); | |||||
assert(child_pubkey.size() == 33); | |||||
assert(child_chaincode != random_uint256); | |||||
} | |||||
const CPrivKey priv_key = key.GetPrivKey(); | |||||
{ | |||||
for (const bool skip_check : {true, false}) { | |||||
CKey loaded_key; | |||||
const bool ok = loaded_key.Load(priv_key, pubkey, skip_check); | |||||
assert(ok); | |||||
assert(key == loaded_key); | |||||
} | |||||
} | |||||
} |