Skip to content

Commit d063925

Browse files
committed
OP_MERKLESUB + SIGHASH_GROUP implementations
1 parent 57cb124 commit d063925

File tree

24 files changed

+846
-56
lines changed

24 files changed

+846
-56
lines changed

src/chainparams.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ class SigNetParams : public CChainParams {
329329
consensus.CSVHeight = 1;
330330
consensus.SegwitHeight = 1;
331331
consensus.AnyprevoutHeight = 1;
332+
consensus.MSBHeight = 1;
333+
consensus.BundleHeight = 1;
332334
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
333335
consensus.nPowTargetSpacing = 10 * 60;
334336
consensus.fPowAllowMinDifficultyBlocks = false;
@@ -398,6 +400,8 @@ class CRegTestParams : public CChainParams {
398400
consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
399401
consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
400402
consensus.AnyprevoutHeight = 0; // ANYPREVOUT is always activated on regtest
403+
consensus.MSBHeight = 0; // MSB is always activated on regtest unless overriden
404+
consensus.BundleHeight = 0; // Bundle is always activated on regtest unless overriden
401405
consensus.MinBIP9WarningHeight = 0;
402406
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
403407
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks

src/consensus/params.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ enum BuriedDeployment : int16_t
2020
DEPLOYMENT_CSV,
2121
DEPLOYMENT_SEGWIT,
2222
DEPLOYMENT_ANYPREVOUT,
23+
DEPLOYMENT_MSB,
24+
DEPLOYMENT_BUNDLE,
2325
};
24-
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_ANYPREVOUT; }
26+
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_BUNDLE; }
2527

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

92+
/** Block height at which MSB (BIPXXX) becomes active */
93+
int MSBHeight = std::numeric_limits<int>::max();
94+
/** Block height at which bundle (BIPYYY) becomes active */
95+
int BundleHeight = std::numeric_limits<int>::max();
9096
/** Don't warn about unknown BIP 9 activations below this height.
9197
* This prevents us from warning about the CSV and segwit activations. */
9298
int MinBIP9WarningHeight;
@@ -132,6 +138,10 @@ struct Params {
132138
return SegwitHeight;
133139
case DEPLOYMENT_ANYPREVOUT:
134140
return AnyprevoutHeight;
141+
case DEPLOYMENT_MSB:
142+
return MSBHeight;
143+
case DEPLOYMENT_BUNDLE:
144+
return BundleHeight;
135145
} // no default case, so the compiler can warn about missing cases
136146
return std::numeric_limits<int>::max();
137147
}

src/deploymentinfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ std::string DeploymentName(Consensus::BuriedDeployment dep)
3333
return "segwit";
3434
case Consensus::DEPLOYMENT_ANYPREVOUT:
3535
return "anyprevout";
36+
case Consensus::DEPLOYMENT_MSB:
37+
return "msb";
38+
case Consensus::DEPLOYMENT_BUNDLE:
39+
return "bundle";
3640
} // no default case, so the compiler can warn about missing cases
3741
return "";
3842
}

src/key.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
271271
if (!secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, &keypair)) return false;
272272
unsigned char pubkey_bytes[32];
273273
if (!secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)) return false;
274-
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
274+
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root, nullptr);
275275
if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
276276
}
277277
bool ret = secp256k1_schnorrsig_sign(secp256k1_context_sign, sig.data(), hash.data(), &keypair, secp256k1_nonce_function_bip340, aux ? (void*)aux->data() : nullptr);

src/policy/policy.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,8 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
251251
// Taproot spend (non-P2SH-wrapped, version 1, witness program size 32; see BIP 341)
252252
auto stack = MakeSpan(tx.vin[i].scriptWitness.stack);
253253
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
254-
// Annexes are nonstandard as long as no semantics are defined for them.
255-
return false;
254+
// Make annex standard ; ignore for now don't protect fields.
255+
SpanPopBack(stack); // Ignore annex
256256
}
257257
if (stack.size() >= 2) {
258258
// Script path spend (2 or more stack elements after removing optional annex)

src/policy/policy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_POLICY_POLICY_H
77
#define BITCOIN_POLICY_POLICY_H
88

9+
#include <logging.h>
910
#include <consensus/consensus.h>
1011
#include <policy/feerate.h>
1112
#include <script/interpreter.h>
@@ -77,7 +78,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
7778
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
7879
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
7980
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
80-
SCRIPT_VERIFY_ANYPREVOUT;
81+
SCRIPT_VERIFY_ANYPREVOUT |
82+
SCRIPT_VERIFY_MERKLESUB;
8183

8284
/** For convenience, standard but not mandatory verify flags. */
8385
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

src/pubkey.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,31 +196,34 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si
196196

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

199-
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
199+
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root, const int *parity_bit) const
200200
{
201201
if (merkle_root == nullptr) {
202202
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
203203
// allow for reproducible tweaking.
204204
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
205+
} else if (parity_bit != nullptr) {
206+
// We have scripts and the parity bit has been committed.
207+
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root << ((uint8_t)*parity_bit)).GetSHA256();
205208
} else {
206209
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
207210
}
208211
}
209212

210-
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const
213+
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool q_parity, int* p_parity) const
211214
{
212215
secp256k1_xonly_pubkey internal_key;
213216
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false;
214-
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root);
215-
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin());
217+
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root, p_parity);
218+
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), q_parity, &internal_key, tweak.begin());
216219
}
217220

218221
std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const
219222
{
220223
secp256k1_xonly_pubkey base_point;
221224
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
222225
secp256k1_pubkey out;
223-
uint256 tweak = ComputeTapTweakHash(merkle_root);
226+
uint256 tweak = ComputeTapTweakHash(merkle_root, nullptr);
224227
if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt;
225228
int parity = -1;
226229
std::pair<XOnlyPubKey, bool> ret;
@@ -232,6 +235,21 @@ std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const ui
232235
return ret;
233236
}
234237

238+
std::optional<XOnlyPubKey> XOnlyPubKey::UpdateInternalKey(Span<const unsigned char> raw_sub_point, int parity_bit, int *new_parity_bit) const
239+
{
240+
secp256k1_xonly_pubkey base_point;
241+
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
242+
243+
secp256k1_xonly_pubkey sub_point;
244+
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &sub_point, raw_sub_point.begin())) return std::nullopt;
245+
246+
XOnlyPubKey new_point;
247+
if (!secp256k1_xonly_pubkey_negate(secp256k1_context_verify, &sub_point)) return std::nullopt;
248+
if (!secp256k1_xonly_pubkey_add(secp256k1_context_verify, &base_point, &sub_point, parity_bit, new_parity_bit)) return std::nullopt;
249+
250+
secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, new_point.begin(), &base_point);
251+
return new_point;
252+
}
235253

236254
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
237255
if (!IsValid())

src/pubkey.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef BITCOIN_PUBKEY_H
88
#define BITCOIN_PUBKEY_H
99

10+
#include <logging.h>
1011
#include <hash.h>
1112
#include <serialize.h>
1213
#include <span.h>
@@ -238,6 +239,9 @@ class XOnlyPubKey
238239
* !IsFullyValid(). */
239240
bool IsNull() const { return m_keydata.IsNull(); }
240241

242+
/** Determine if this pubkey has an even */
243+
bool IsEven() const;
244+
241245
/** Construct an x-only pubkey from exactly 32 bytes. */
242246
explicit XOnlyPubKey(Span<const unsigned char> bytes);
243247

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

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

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

274+
/** Construct an updated internal key from this point by adding another one. */
275+
std::optional<XOnlyPubKey>UpdateInternalKey(Span<const unsigned char> point, int parity_bit, int *new_parity_bit) const;
276+
277+
std::string ToString() const { return m_keydata.ToString(); }
270278
const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
271279
const unsigned char* data() const { return m_keydata.begin(); }
272280
static constexpr size_t size() { return decltype(m_keydata)::size(); }

src/rpc/blockchain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,8 @@ RPCHelpMan getblockchaininfo()
15141514
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
15151515
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
15161516
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_ANYPREVOUT);
1517+
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_MSB);
1518+
SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_BUNDLE);
15171519
obj.pushKV("softforks", softforks);
15181520

15191521
obj.pushKV("warnings", GetWarnings(false).original);

src/script/bitcoinconsensus.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
9292
set_error(err, bitcoinconsensus_ERR_OK);
9393

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

0 commit comments

Comments
 (0)