mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Merge 5bf65ec66e into merged_master (Bitcoin PR bitcoin/bitcoin#22558)
This commit is contained in:
commit
2d07ef8fc1
17 changed files with 710 additions and 31 deletions
|
|
@ -882,7 +882,7 @@ protected:
|
|||
if (!xpk.IsFullyValid()) return {};
|
||||
builder.Finalize(xpk);
|
||||
WitnessV1Taproot output = builder.GetOutput();
|
||||
out.tr_spenddata[output].Merge(builder.GetSpendData());
|
||||
out.tr_trees[output] = builder;
|
||||
out.pubkeys.emplace(keys[0].GetID(), keys[0]);
|
||||
return Vector(GetScriptForDestination(output));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, Signatur
|
|||
auto it = sigdata.taproot_script_sigs.find(lookup_key);
|
||||
if (it != sigdata.taproot_script_sigs.end()) {
|
||||
sig_out = it->second;
|
||||
return true;
|
||||
}
|
||||
if (creator.CreateSchnorrSig(provider, sig_out, pubkey, &leaf_hash, nullptr, sigversion)) {
|
||||
sigdata.taproot_script_sigs[lookup_key] = sig_out;
|
||||
|
|
@ -173,6 +174,17 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
|
|||
// <xonly pubkey> OP_CHECKSIG
|
||||
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
|
||||
XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
|
||||
|
||||
KeyOriginInfo info;
|
||||
if (provider.GetKeyOriginByXOnly(pubkey, info)) {
|
||||
auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
|
||||
if (it == sigdata.taproot_misc_pubkeys.end()) {
|
||||
sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
|
||||
} else {
|
||||
it->second.first.insert(leaf_hash);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> sig;
|
||||
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
|
||||
result = Vector(std::move(sig));
|
||||
|
|
@ -209,17 +221,29 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
|
|||
static bool SignTaproot(const SigningProvider& provider, const BaseSignatureCreator& creator, const WitnessV1Taproot& output, SignatureData& sigdata, std::vector<valtype>& result)
|
||||
{
|
||||
TaprootSpendData spenddata;
|
||||
TaprootBuilder builder;
|
||||
|
||||
// Gather information about this output.
|
||||
if (provider.GetTaprootSpendData(output, spenddata)) {
|
||||
sigdata.tr_spenddata.Merge(spenddata);
|
||||
}
|
||||
if (provider.GetTaprootBuilder(output, builder)) {
|
||||
sigdata.tr_builder = builder;
|
||||
}
|
||||
|
||||
// Try key path spending.
|
||||
{
|
||||
KeyOriginInfo info;
|
||||
if (provider.GetKeyOriginByXOnly(sigdata.tr_spenddata.internal_key, info)) {
|
||||
auto it = sigdata.taproot_misc_pubkeys.find(sigdata.tr_spenddata.internal_key);
|
||||
if (it == sigdata.taproot_misc_pubkeys.end()) {
|
||||
sigdata.taproot_misc_pubkeys.emplace(sigdata.tr_spenddata.internal_key, std::make_pair(std::set<uint256>(), info));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> sig;
|
||||
if (sigdata.taproot_key_path_sig.size() == 0) {
|
||||
if (creator.CreateSchnorrSig(provider, sig, spenddata.internal_key, nullptr, &spenddata.merkle_root, SigVersion::TAPROOT)) {
|
||||
if (creator.CreateSchnorrSig(provider, sig, sigdata.tr_spenddata.internal_key, nullptr, &sigdata.tr_spenddata.merkle_root, SigVersion::TAPROOT)) {
|
||||
sigdata.taproot_key_path_sig = sig;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,10 +70,12 @@ struct SignatureData {
|
|||
CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
|
||||
CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
|
||||
TaprootSpendData tr_spenddata; ///< Taproot spending data.
|
||||
std::optional<TaprootBuilder> tr_builder; ///< Taproot tree used to build tr_spenddata.
|
||||
std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
|
||||
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
|
||||
std::vector<unsigned char> taproot_key_path_sig; /// Schnorr signature for key path spending
|
||||
std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> taproot_script_sigs; ///< (Partial) schnorr signatures, indexed by XOnlyPubKey and leaf_hash.
|
||||
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> taproot_misc_pubkeys; ///< Miscellaneous Taproot pubkeys involved in this input along with their leaf script hashes and key origin data. Also includes the Taproot internal key (may have no leaf script hashes).
|
||||
std::vector<CKeyID> missing_pubkeys; ///< KeyIDs of pubkeys which could not be found
|
||||
std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found
|
||||
uint160 missing_redeem_script; ///< ScriptID of the missing redeemScript (if any)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ bool HidingSigningProvider::GetTaprootSpendData(const XOnlyPubKey& output_key, T
|
|||
{
|
||||
return m_provider->GetTaprootSpendData(output_key, spenddata);
|
||||
}
|
||||
bool HidingSigningProvider::GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const
|
||||
{
|
||||
return m_provider->GetTaprootBuilder(output_key, builder);
|
||||
}
|
||||
|
||||
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
|
||||
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
|
||||
|
|
@ -61,7 +65,16 @@ bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info)
|
|||
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
|
||||
bool FlatSigningProvider::GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const
|
||||
{
|
||||
return LookupHelper(tr_spenddata, output_key, spenddata);
|
||||
TaprootBuilder builder;
|
||||
if (LookupHelper(tr_trees, output_key, builder)) {
|
||||
spenddata = builder.GetSpendData();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool FlatSigningProvider::GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const
|
||||
{
|
||||
return LookupHelper(tr_trees, output_key, builder);
|
||||
}
|
||||
|
||||
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
|
||||
|
|
@ -75,10 +88,8 @@ FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvide
|
|||
ret.keys.insert(b.keys.begin(), b.keys.end());
|
||||
ret.origins = a.origins;
|
||||
ret.origins.insert(b.origins.begin(), b.origins.end());
|
||||
ret.tr_spenddata = a.tr_spenddata;
|
||||
for (const auto& [output_key, spenddata] : b.tr_spenddata) {
|
||||
ret.tr_spenddata[output_key].Merge(spenddata);
|
||||
}
|
||||
ret.tr_trees = a.tr_trees;
|
||||
ret.tr_trees.insert(b.tr_trees.begin(), b.tr_trees.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
virtual bool HaveKey(const CKeyID &address) const { return false; }
|
||||
virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
|
||||
virtual bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const { return false; }
|
||||
virtual bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const { return false; }
|
||||
|
||||
bool GetKeyByXOnly(const XOnlyPubKey& pubkey, CKey& key) const
|
||||
{
|
||||
|
|
@ -67,6 +68,7 @@ public:
|
|||
bool GetKey(const CKeyID& keyid, CKey& key) const override;
|
||||
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
||||
bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override;
|
||||
bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const override;
|
||||
};
|
||||
|
||||
struct FlatSigningProvider final : public SigningProvider
|
||||
|
|
@ -75,13 +77,14 @@ struct FlatSigningProvider final : public SigningProvider
|
|||
std::map<CKeyID, CPubKey> pubkeys;
|
||||
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
|
||||
std::map<CKeyID, CKey> keys;
|
||||
std::map<XOnlyPubKey, TaprootSpendData> tr_spenddata; /** Map from output key to spend data. */
|
||||
std::map<XOnlyPubKey, TaprootBuilder> tr_trees; /** Map from output key to Taproot tree (which can then make the TaprootSpendData */
|
||||
|
||||
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
|
||||
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
|
||||
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
|
||||
bool GetKey(const CKeyID& keyid, CKey& key) const override;
|
||||
bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override;
|
||||
bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const override;
|
||||
};
|
||||
|
||||
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
|
||||
|
|
|
|||
|
|
@ -519,6 +519,7 @@ WitnessV1Taproot TaprootBuilder::GetOutput() { return WitnessV1Taproot{m_output_
|
|||
TaprootSpendData TaprootBuilder::GetSpendData() const
|
||||
{
|
||||
assert(IsComplete());
|
||||
assert(m_output_key.IsFullyValid());
|
||||
TaprootSpendData spd;
|
||||
spd.merkle_root = m_branch.size() == 0 ? uint256() : m_branch[0]->hash;
|
||||
spd.internal_key = m_internal_key;
|
||||
|
|
@ -676,3 +677,19 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::tuple<uint8_t, uint8_t, CScript>> TaprootBuilder::GetTreeTuples() const
|
||||
{
|
||||
assert(IsComplete());
|
||||
std::vector<std::tuple<uint8_t, uint8_t, CScript>> tuples;
|
||||
if (m_branch.size()) {
|
||||
const auto& leaves = m_branch[0]->leaves;
|
||||
for (const auto& leaf : leaves) {
|
||||
assert(leaf.merkle_branch.size() <= TAPROOT_CONTROL_MAX_NODE_COUNT);
|
||||
uint8_t depth = (uint8_t)leaf.merkle_branch.size();
|
||||
uint8_t leaf_ver = (uint8_t)leaf.leaf_version;
|
||||
tuples.push_back(std::make_tuple(depth, leaf_ver, leaf.script));
|
||||
}
|
||||
}
|
||||
return tuples;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,6 +385,8 @@ public:
|
|||
static bool ValidDepths(const std::vector<int>& depths);
|
||||
/** Compute spending data (after Finalize()). */
|
||||
TaprootSpendData GetSpendData() const;
|
||||
/** Returns a vector of tuples representing the depth, leaf version, and script */
|
||||
std::vector<std::tuple<uint8_t, uint8_t, CScript>> GetTreeTuples() const;
|
||||
};
|
||||
|
||||
/** Given a TaprootSpendData and the output key, reconstruct its script tree.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue