Skip to content

Commit

Permalink
OP_MERKLESUB + SIGHASH_GROUP implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
ariard committed Feb 20, 2022
1 parent 57cb124 commit d063925
Show file tree
Hide file tree
Showing 24 changed files with 846 additions and 56 deletions.
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ class SigNetParams : public CChainParams {
consensus.CSVHeight = 1;
consensus.SegwitHeight = 1;
consensus.AnyprevoutHeight = 1;
consensus.MSBHeight = 1;
consensus.BundleHeight = 1;
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
Expand Down Expand Up @@ -398,6 +400,8 @@ class CRegTestParams : public CChainParams {
consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
consensus.AnyprevoutHeight = 0; // ANYPREVOUT is always activated on regtest
consensus.MSBHeight = 0; // MSB is always activated on regtest unless overriden
consensus.BundleHeight = 0; // Bundle is always activated on regtest unless overriden
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down
12 changes: 11 additions & 1 deletion src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ enum BuriedDeployment : int16_t
DEPLOYMENT_CSV,
DEPLOYMENT_SEGWIT,
DEPLOYMENT_ANYPREVOUT,
DEPLOYMENT_MSB,
DEPLOYMENT_BUNDLE,
};
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_ANYPREVOUT; }
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_BUNDLE; }

enum DeploymentPos : uint16_t
{
Expand Down Expand Up @@ -87,6 +89,10 @@ struct Params {
/** Block height for ANYPREVOUT (BIP118/pr943) */
int AnyprevoutHeight = std::numeric_limits<int>::max();

/** Block height at which MSB (BIPXXX) becomes active */
int MSBHeight = std::numeric_limits<int>::max();
/** Block height at which bundle (BIPYYY) becomes active */
int BundleHeight = std::numeric_limits<int>::max();
/** Don't warn about unknown BIP 9 activations below this height.
* This prevents us from warning about the CSV and segwit activations. */
int MinBIP9WarningHeight;
Expand Down Expand Up @@ -132,6 +138,10 @@ struct Params {
return SegwitHeight;
case DEPLOYMENT_ANYPREVOUT:
return AnyprevoutHeight;
case DEPLOYMENT_MSB:
return MSBHeight;
case DEPLOYMENT_BUNDLE:
return BundleHeight;
} // no default case, so the compiler can warn about missing cases
return std::numeric_limits<int>::max();
}
Expand Down
4 changes: 4 additions & 0 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ std::string DeploymentName(Consensus::BuriedDeployment dep)
return "segwit";
case Consensus::DEPLOYMENT_ANYPREVOUT:
return "anyprevout";
case Consensus::DEPLOYMENT_MSB:
return "msb";
case Consensus::DEPLOYMENT_BUNDLE:
return "bundle";
} // no default case, so the compiler can warn about missing cases
return "";
}
2 changes: 1 addition & 1 deletion src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
if (!secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, &keypair)) return false;
unsigned char pubkey_bytes[32];
if (!secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)) return false;
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root, nullptr);
if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
}
bool ret = secp256k1_schnorrsig_sign(secp256k1_context_sign, sig.data(), hash.data(), &keypair, secp256k1_nonce_function_bip340, aux ? (void*)aux->data() : nullptr);
Expand Down
4 changes: 2 additions & 2 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// Taproot spend (non-P2SH-wrapped, version 1, witness program size 32; see BIP 341)
auto stack = MakeSpan(tx.vin[i].scriptWitness.stack);
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Annexes are nonstandard as long as no semantics are defined for them.
return false;
// Make annex standard ; ignore for now don't protect fields.
SpanPopBack(stack); // Ignore annex
}
if (stack.size() >= 2) {
// Script path spend (2 or more stack elements after removing optional annex)
Expand Down
4 changes: 3 additions & 1 deletion src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef BITCOIN_POLICY_POLICY_H
#define BITCOIN_POLICY_POLICY_H

#include <logging.h>
#include <consensus/consensus.h>
#include <policy/feerate.h>
#include <script/interpreter.h>
Expand Down Expand Up @@ -77,7 +78,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
SCRIPT_VERIFY_ANYPREVOUT;
SCRIPT_VERIFY_ANYPREVOUT |
SCRIPT_VERIFY_MERKLESUB;

/** 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
28 changes: 23 additions & 5 deletions src/pubkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,31 +196,34 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si

static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");

uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root, const int *parity_bit) const
{
if (merkle_root == nullptr) {
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
// allow for reproducible tweaking.
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
} else if (parity_bit != nullptr) {
// We have scripts and the parity bit has been committed.
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root << ((uint8_t)*parity_bit)).GetSHA256();
} else {
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
}
}

bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool q_parity, int* p_parity) const
{
secp256k1_xonly_pubkey internal_key;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false;
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root);
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin());
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root, p_parity);
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), q_parity, &internal_key, tweak.begin());
}

std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const
{
secp256k1_xonly_pubkey base_point;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
secp256k1_pubkey out;
uint256 tweak = ComputeTapTweakHash(merkle_root);
uint256 tweak = ComputeTapTweakHash(merkle_root, nullptr);
if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt;
int parity = -1;
std::pair<XOnlyPubKey, bool> ret;
Expand All @@ -232,6 +235,21 @@ std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const ui
return ret;
}

std::optional<XOnlyPubKey> XOnlyPubKey::UpdateInternalKey(Span<const unsigned char> raw_sub_point, int parity_bit, int *new_parity_bit) const
{
secp256k1_xonly_pubkey base_point;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;

secp256k1_xonly_pubkey sub_point;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &sub_point, raw_sub_point.begin())) return std::nullopt;

XOnlyPubKey new_point;
if (!secp256k1_xonly_pubkey_negate(secp256k1_context_verify, &sub_point)) return std::nullopt;
if (!secp256k1_xonly_pubkey_add(secp256k1_context_verify, &base_point, &sub_point, parity_bit, new_parity_bit)) return std::nullopt;

secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, new_point.begin(), &base_point);
return new_point;
}

bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
Expand Down
12 changes: 10 additions & 2 deletions src/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef BITCOIN_PUBKEY_H
#define BITCOIN_PUBKEY_H

#include <logging.h>
#include <hash.h>
#include <serialize.h>
#include <span.h>
Expand Down Expand Up @@ -238,6 +239,9 @@ class XOnlyPubKey
* !IsFullyValid(). */
bool IsNull() const { return m_keydata.IsNull(); }

/** Determine if this pubkey has an even */
bool IsEven() const;

/** Construct an x-only pubkey from exactly 32 bytes. */
explicit XOnlyPubKey(Span<const unsigned char> bytes);

Expand All @@ -258,15 +262,19 @@ class XOnlyPubKey
* Note that the behavior of this function with merkle_root != nullptr is
* consensus critical.
*/
uint256 ComputeTapTweakHash(const uint256* merkle_root) const;
uint256 ComputeTapTweakHash(const uint256* merkle_root, const int* parity) const;

/** Verify that this is a Taproot tweaked output point, against a specified internal key,
* Merkle root, and parity. */
bool CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const;
bool CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity, int *p_parity) const;

/** Construct a Taproot tweaked output point with this point as internal key. */
std::optional<std::pair<XOnlyPubKey, bool>> CreateTapTweak(const uint256* merkle_root) const;

/** Construct an updated internal key from this point by adding another one. */
std::optional<XOnlyPubKey>UpdateInternalKey(Span<const unsigned char> point, int parity_bit, int *new_parity_bit) const;

std::string ToString() const { return m_keydata.ToString(); }
const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
const unsigned char* data() const { return m_keydata.begin(); }
static constexpr size_t size() { return decltype(m_keydata)::size(); }
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,6 +1514,8 @@ RPCHelpMan getblockchaininfo()
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_ANYPREVOUT);
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_MSB);
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_BUNDLE);
obj.pushKV("softforks", softforks);

obj.pushKV("warnings", GetWarnings(false).original);
Expand Down
2 changes: 1 addition & 1 deletion src/script/bitcoinconsensus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
set_error(err, bitcoinconsensus_ERR_OK);

PrecomputedTransactionData txdata(tx);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr, nullptr);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
Expand Down
Loading

0 comments on commit d063925

Please sign in to comment.