Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ if test x$need_bundled_univalue = xyes; then
AC_CONFIG_SUBDIRS([src/univalue])
fi

ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --disable-jni"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --disable-jni"
AC_CONFIG_SUBDIRS([src/secp256k1])

AC_OUTPUT
Expand Down
13 changes: 13 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ class CMainParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

// Deployment of Taproot
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000051dc8b82f450202ecb3d471");

Expand Down Expand Up @@ -188,6 +193,11 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

// Deployment of Taproot
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000007dbe94253893cbd463");

Expand Down Expand Up @@ -271,6 +281,9 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Consensus {
enum DeploymentPos
{
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_TAPROOT, // Deployment of bip-taproot/bip-tapscript/bip-schnorr
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
18 changes: 13 additions & 5 deletions src/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ inline uint160 Hash160(const prevector<N, unsigned char>& vch)
class CHashWriter
{
private:
CHash256 ctx;
CSHA256 ctx;

const int nType;
const int nVersion;
Expand All @@ -135,17 +135,25 @@ class CHashWriter
// invalidates the object
uint256 GetHash() {
uint256 result;
ctx.Finalize((unsigned char*)&result);
unsigned char buf[CSHA256::OUTPUT_SIZE];
ctx.Finalize(buf);
ctx.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(result.begin());
return result;
}

// invalidates the object
uint256 GetSHA256() {
uint256 result;
ctx.Finalize(result.begin());
return result;
}

/**
* Returns the first 64 bits from the resulting hash.
*/
inline uint64_t GetCheapHash() {
unsigned char result[CHash256::OUTPUT_SIZE];
ctx.Finalize(result);
return ReadLE64(result);
uint256 result = GetHash();
return ReadLE64(result.begin());
}

template<typename T>
Expand Down
31 changes: 21 additions & 10 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,16 +219,27 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
return false;

// Check P2WSH standard limits
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
return false;
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
return false;
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
return false;
auto stack = tx.vin[i].scriptWitness.stack;
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
return false; // annex is non-standard
}

bool p2wsh = (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE);
bool taproot = (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && (witnessprogram[0] & 0xfe) == 0);

// Preprocessing for TAPROOT
if (taproot) {
if (stack.size() <= 1) return true;
stack.pop_back();
}

// Check P2WSH and TAPROOT standard limits
if (p2wsh || taproot) {
if (stack.back().size() > MAX_STANDARD_WITNESS_SCRIPT_SIZE) return false;
stack.pop_back();
if (stack.size() > MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS) return false;
for (const auto& item : stack) {
if (item.size() > MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE) return false;
}
}
}
Expand Down
19 changes: 12 additions & 7 deletions src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
/** The maximum number of witness stack items in a standard P2WSH script */
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
/** The maximum size of each witness stack item in a standard P2WSH script */
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
/** The maximum size of a standard witnessScript */
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
/** The maximum number of witness input stack items in a standard witness script */
static const unsigned int MAX_STANDARD_WITNESS_INPUT_STACK_ITEMS = 210;
/** The maximum size of each witness stack item in a standard witness script */
static const unsigned int MAX_STANDARD_WITNESS_INPUT_STACK_ITEM_SIZE = 80;
/** The maximum size of a standard witness script */
static const unsigned int MAX_STANDARD_WITNESS_SCRIPT_SIZE = 7100;
/** Min feerate for defining dust. Historically this has been based on the
* minRelayTxFee, however changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
Expand All @@ -68,7 +68,12 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_WITNESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
SCRIPT_VERIFY_CONST_SCRIPTCODE;
SCRIPT_VERIFY_CONST_SCRIPTCODE |
SCRIPT_VERIFY_TAPROOT |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
SCRIPT_VERIFY_DISCOURAGE_UNKNOWN_ANNEX |
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;

/** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
Expand Down
24 changes: 24 additions & 0 deletions src/pubkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <secp256k1.h>
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>

namespace
{
Expand Down Expand Up @@ -166,6 +167,17 @@ static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1
return 1;
}

bool CPubKey::VerifySchnorr(const uint256 &hash, const std::vector<unsigned char>& sigbytes) const {
if (!IsValid()) return false;
if (vch[0] != 2 && vch[0] != 3) return false; // Only compressed pubkeys
if (sigbytes.size() != 64) return false;
secp256k1_pubkey pubkey;
secp256k1_schnorrsig sig;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) return false;
if (!secp256k1_schnorrsig_parse(secp256k1_context_verify, &sig, sigbytes.data())) return false;
return secp256k1_schnorrsig_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
}

bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
Expand Down Expand Up @@ -271,6 +283,18 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);
}

bool CPubKey::CheckPayToContract(const CPubKey& base, const uint256& hash) const
{
if (!IsCompressed() || !base.IsCompressed()) return false;
secp256k1_pubkey base_point;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &base_point, base.vch, base.size())) return false;
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &base_point, hash.begin())) return false;
unsigned char out[COMPRESSED_PUBLIC_KEY_SIZE];
size_t len = COMPRESSED_PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, out, &len, &base_point, SECP256K1_EC_COMPRESSED);
return memcmp(out, vch, COMPRESSED_PUBLIC_KEY_SIZE) == 0;
}

/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
Expand Down
8 changes: 8 additions & 0 deletions src/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ class CPubKey
*/
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;

/**
* Verify a Schnorr (DLS) signature (64 bytes)
*/
bool VerifySchnorr(const uint256& hash, const std::vector<unsigned char>& sig) const;

/**
* Check whether a signature is normalized (lower-S).
*/
Expand All @@ -201,6 +206,9 @@ class CPubKey

//! Derive BIP32 child pubkey.
bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;

//! Verify a P2C derivation. Hash must be a cryptographic hash that commits to base.
bool CheckPayToContract(const CPubKey& base, const uint256& hash) const;
};

struct CExtPubKey {
Expand Down
Loading