Skip to content

Commit

Permalink
Port solver
Browse files Browse the repository at this point in the history
  • Loading branch information
timemarkovqtum committed Jun 10, 2024
1 parent 37fe841 commit 2f80fae
Show file tree
Hide file tree
Showing 8 changed files with 499 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ FUZZ_SUITE_LD_COMMON = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
$(LIBLEVELDB) \
$(BOOST_LIBS) \
$(SSL_LIBS) \
$(CRYPTO_LIBS) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
$(MINISKETCH_LIBS) \
Expand Down
114 changes: 112 additions & 2 deletions src/addresstype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
#include <script/solver.h>
#include <uint256.h>
#include <util/hash_type.h>
#include <qtum/qtumstate.h>

#include <cassert>
#include <vector>

typedef std::vector<unsigned char> valtype;

ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
ScriptHash::ScriptHash(const CScriptID& in) : BaseHash{in} {}
Expand Down Expand Up @@ -46,16 +46,23 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
CSHA256().Write(in.data(), in.size()).Finalize(begin());
}

bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet, TxoutType* typeRet, bool convertPublicKeyToHash)
{
std::vector<valtype> vSolutions;
TxoutType whichType = Solver(scriptPubKey, vSolutions);

if(typeRet){
*typeRet = whichType;
}

switch (whichType) {
case TxoutType::PUBKEY: {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid()) {
addressRet = CNoDestination(scriptPubKey);
} else if (convertPublicKeyToHash) {
addressRet = PKHash(pubKey);
return true;
} else {
addressRet = PubKeyDestination(pubKey);
}
Expand Down Expand Up @@ -94,6 +101,10 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
case TxoutType::MULTISIG:
case TxoutType::NULL_DATA:
case TxoutType::NONSTANDARD:
case TxoutType::CREATE_SENDER:
case TxoutType::CALL_SENDER:
case TxoutType::CREATE:
case TxoutType::CALL:
addressRet = CNoDestination(scriptPubKey);
return false;
} // no default case, so the compiler can warn about missing cases
Expand Down Expand Up @@ -167,3 +178,102 @@ CScript GetScriptForDestination(const CTxDestination& dest)
bool IsValidDestination(const CTxDestination& dest) {
return std::visit(ValidDestinationVisitor(), dest);
}

PKHash ExtractPublicKeyHash(const CScript& scriptPubKey, bool* OK)
{
if(OK) *OK = false;
CTxDestination address;
TxoutType txType=TxoutType::NONSTANDARD;
if(ExtractDestination(scriptPubKey, address, &txType, true)){
if ((txType == TxoutType::PUBKEY || txType == TxoutType::PUBKEYHASH) && std::holds_alternative<PKHash>(address)) {
if(OK) *OK = true;
return std::get<PKHash>(address);
}
}

return PKHash();
}

bool IsValidContractSenderAddress(const CTxDestination& dest) {
return std::holds_alternative<PKHash>(dest);
}

valtype DataVisitor::operator()(const CNoDestination& noDest) const { return valtype(); }
valtype DataVisitor::operator()(const PKHash& keyID) const { return valtype(keyID.begin(), keyID.end()); }
valtype DataVisitor::operator()(const PubKeyDestination& pubKey) const {
PKHash keyID(pubKey.GetPubKey());
return valtype(keyID.begin(), keyID.end());
}
valtype DataVisitor::operator()(const ScriptHash& scriptID) const { return valtype(scriptID.begin(), scriptID.end()); }
valtype DataVisitor::operator()(const WitnessV0ScriptHash& witnessScriptHash) const { return valtype(witnessScriptHash.begin(), witnessScriptHash.end()); }
valtype DataVisitor::operator()(const WitnessV0KeyHash& witnessKeyHash) const { return valtype(witnessKeyHash.begin(), witnessKeyHash.end()); }
valtype DataVisitor::operator()(const WitnessV1Taproot& witnessTaproot) const { return valtype(witnessTaproot.begin(), witnessTaproot.end()); }
valtype DataVisitor::operator()(const WitnessUnknown&) const { return valtype(); }

bool ExtractDestination(const COutPoint& prevout, const CScript& scriptPubKey, CTxDestination& addressRet, TxoutType* typeRet)
{
std::vector<valtype> vSolutions;
TxoutType whichType = Solver(scriptPubKey, vSolutions);

if(typeRet){
*typeRet = whichType;
}


if (whichType == TxoutType::PUBKEY)
{
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;

addressRet = PKHash(pubKey);
return true;
}
else if (whichType == TxoutType::PUBKEYHASH)
{
addressRet = PKHash(uint160(vSolutions[0]));
return true;
}
else if (whichType == TxoutType::SCRIPTHASH)
{
addressRet = ScriptHash(uint160(vSolutions[0]));
return true;
}
else if(whichType == TxoutType::CALL){
addressRet = PKHash(uint160(vSolutions[0]));
return true;
}
else if(whichType == TxoutType::WITNESS_V0_KEYHASH)
{
addressRet = WitnessV0KeyHash(uint160(vSolutions[0]));
return true;
}
else if(whichType == TxoutType::WITNESS_V0_SCRIPTHASH)
{
addressRet = WitnessV0ScriptHash(uint256(vSolutions[0]));
return true;
}
else if(whichType == TxoutType::WITNESS_V1_TAPROOT)
{
WitnessV1Taproot tap;
std::copy(vSolutions[0].begin(), vSolutions[0].end(), tap.begin());
addressRet = tap;
return true;
}
else if (whichType == TxoutType::WITNESS_UNKNOWN) {
addressRet = WitnessUnknown{vSolutions[0][0], vSolutions[1]};
return true;
}
else if (whichType == TxoutType::CREATE) {
addressRet = PKHash(uint160(QtumState::createQtumAddress(uintToh256(prevout.hash), prevout.n).asBytes()));
return true;
}
return false;
}

int GetAddressIndexType(const CTxDestination &dest)
{
if(dest.index() > 1)
return dest.index() - 1; // PubKeyDestination and PKHash are considered the same
return dest.index();
}
39 changes: 38 additions & 1 deletion src/addresstype.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
#include <script/script.h>
#include <uint256.h>
#include <util/hash_type.h>
#include <primitives/transaction.h>

#include <algorithm>
#include <variant>
#include <vector>
enum class TxoutType;

typedef std::vector<unsigned char> valtype;

class CNoDestination
{
Expand Down Expand Up @@ -143,7 +147,7 @@ bool IsValidDestination(const CTxDestination& dest);
* Returns true for standard destinations with addresses - P2PKH, P2SH, P2WPKH, P2WSH, P2TR and P2W??? scripts.
* Returns false for non-standard destinations and those without addresses - P2PK, bare multisig, null data, and nonstandard scripts.
*/
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet, TxoutType* typeRet = NULL, bool convertPublicKeyToHash = false);

/**
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
Expand All @@ -152,4 +156,37 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
*/
CScript GetScriptForDestination(const CTxDestination& dest);

inline bool operator!=(const CTxDestination& lhs, const CTxDestination& rhs){ return !(lhs == rhs); }

enum addresstype
{
PUBKEYHASH = 1,
SCRIPTHASH = 2,
WITNESSSCRIPTHASH = 3,
WITNESSPUBKEYHASH = 4,
WITNESSTAPROOT = 5,
NONSTANDARD = 6
};

/** Check whether a CTxDestination can be used as contract sender address. */
bool IsValidContractSenderAddress(const CTxDestination& dest);

PKHash ExtractPublicKeyHash(const CScript& scriptPubKey, bool* OK = nullptr);

struct DataVisitor
{
valtype operator()(const CNoDestination& noDest) const;
valtype operator()(const PKHash& keyID) const;
valtype operator()(const PubKeyDestination& pubKey) const;
valtype operator()(const ScriptHash& scriptID) const;
valtype operator()(const WitnessV0ScriptHash& witnessScriptHash) const;
valtype operator()(const WitnessV0KeyHash& witnessKeyHash) const;
valtype operator()(const WitnessV1Taproot& witnessTaproot) const;
valtype operator()(const WitnessUnknown& witnessUnknown) const;
};

bool ExtractDestination(const COutPoint& prevout, const CScript& scriptPubKey, CTxDestination& addressRet, TxoutType* typeRet = NULL);

int GetAddressIndexType(const CTxDestination& dest);

#endif // BITCOIN_ADDRESSTYPE_H
58 changes: 57 additions & 1 deletion src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,25 @@
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>

#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <openssl/obj_mac.h>
#include <openssl/opensslv.h>

static secp256k1_context* secp256k1_context_sign = nullptr;

#if OPENSSL_VERSION_NUMBER < 0x10100000L
// Compatibility Layer for older versions of Open SSL
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
#endif

/** These functions are taken from the libsecp256k1 distribution and are very ugly. */

/**
Expand Down Expand Up @@ -154,6 +171,45 @@ int ec_seckey_export_der(const secp256k1_context *ctx, unsigned char *seckey, si
return 1;
}

const unsigned char vchOrder[32] = {
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41
};

const unsigned char vchHalfOrder[32] = {
0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0
};

bool EnsureLowS(std::vector<unsigned char>& vchSig) {
unsigned char *pos;

if (vchSig.empty())
return false;

pos = &vchSig[0];
ECDSA_SIG *sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&pos, vchSig.size());
if (sig == NULL)
return false;

BIGNUM *order = BN_bin2bn(vchOrder, sizeof(vchOrder), NULL);
BIGNUM *halforder = BN_bin2bn(vchHalfOrder, sizeof(vchHalfOrder), NULL);

BIGNUM *s = 0;
ECDSA_SIG_get0(sig, 0, (const BIGNUM **)&s);
if (BN_cmp(s, halforder) > 0) {
// enforce low S values, by negating the value (modulo the order) if above order/2.
BN_sub(s, order, s);
}

BN_free(halforder);
BN_free(order);

pos = &vchSig[0];
unsigned int nSize = i2d_ECDSA_SIG(sig, &pos);
ECDSA_SIG_free(sig);
vchSig.resize(nSize); // Shrink to fit actual size
return true;
}

bool CKey::Check(const unsigned char *vch) {
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
}
Expand Down Expand Up @@ -244,7 +300,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
return false;
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
std::string str = "Qtum key verification\n";
GetRandBytes(rnd);
uint256 hash{Hash(str, rnd)};
std::vector<unsigned char> vchSig;
Expand Down
3 changes: 3 additions & 0 deletions src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,7 @@ void ECC_Stop();
/** Check that required EC support is available at runtime. */
bool ECC_InitSanityCheck();

/** Ensure that the signature is LowS */
bool EnsureLowS(std::vector<unsigned char>& vchSig);

#endif // BITCOIN_KEY_H
Loading

0 comments on commit 2f80fae

Please sign in to comment.