Skip to content

Commit 3ffb9aa

Browse files
committed
Merge c7dd9ff into merged_master (Bitcoin PR bitcoin/bitcoin#22051)
Does the bare minimum to introduce Taproot wallet support with CT; just adds a CPubKey blinding_pubkey to the taproot destination variant and updates some visitors. In future when we define blech32 we will need to make sure we are using that encoding and using the pubkey.
2 parents 97ea1da + c7dd9ff commit 3ffb9aa

17 files changed

Lines changed: 876 additions & 55 deletions

doc/descriptors.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Output descriptors currently support:
3030
- Pay-to-witness-pubkey-hash scripts (P2WPKH), through the `wpkh` function.
3131
- Pay-to-script-hash scripts (P2SH), through the `sh` function.
3232
- Pay-to-witness-script-hash scripts (P2WSH), through the `wsh` function.
33+
- Pay-to-taproot outputs (P2TR), through the `tr` function.
3334
- Multisig scripts, through the `multi` function.
3435
- Multisig scripts where the public keys are sorted lexicographically, through the `sortedmulti` function.
3536
- Any type of supported address through the `addr` function.
@@ -54,20 +55,22 @@ Output descriptors currently support:
5455
- `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)` describes a set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint `d34db33f`, and derived using path `44'/0'/0'`.
5556
- `wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default).
5657
- `wsh(sortedmulti(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where one multisig key is the *1/0/`i`* child of the first specified xpub and the other multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). The order of public keys in the resulting witnessScripts is determined by the lexicographic order of the public keys at that index.
58+
- `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,{pk(fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),pk(e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)})` describes a P2TR output with the `c6...` x-only pubkey as internal key, and two script paths.
5759

5860
## Reference
5961

6062
Descriptors consist of several types of expressions. The top level expression is either a `SCRIPT`, or `SCRIPT#CHECKSUM` where `CHECKSUM` is an 8-character alphanumeric descriptor checksum.
6163

6264
`SCRIPT` expressions:
6365
- `sh(SCRIPT)` (top level only): P2SH embed the argument.
64-
- `wsh(SCRIPT)` (not inside another 'wsh'): P2WSH embed the argument.
66+
- `wsh(SCRIPT)` (top level or inside `sh` only): P2WSH embed the argument.
6567
- `pk(KEY)` (anywhere): P2PK output for the given public key.
66-
- `pkh(KEY)` (anywhere): P2PKH output for the given public key (use `addr` if you only know the pubkey hash).
67-
- `wpkh(KEY)` (not inside `wsh`): P2WPKH output for the given compressed pubkey.
68+
- `pkh(KEY)` (not inside `tr`): P2PKH output for the given public key (use `addr` if you only know the pubkey hash).
69+
- `wpkh(KEY)` (top level or inside `sh` only): P2WPKH output for the given compressed pubkey.
6870
- `combo(KEY)` (top level only): an alias for the collection of `pk(KEY)` and `pkh(KEY)`. If the key is compressed, it also includes `wpkh(KEY)` and `sh(wpkh(KEY))`.
69-
- `multi(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script.
70-
- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script with keys sorted lexicographically in the resulting script.
71+
- `multi(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script.
72+
- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script with keys sorted lexicographically in the resulting script.
73+
- `tr(KEY)` or `tr(KEY,TREE)` (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths.
7174
- `addr(ADDR)` (top level only): the script which ADDR expands to.
7275
- `raw(HEX)` (top level only): the script whose hex encoding is HEX.
7376

@@ -80,12 +83,17 @@ Descriptors consist of several types of expressions. The top level expression is
8083
- Followed by the actual key, which is either:
8184
- Hex encoded public keys (either 66 characters starting with `02` or `03` for a compressed pubkey, or 130 characters starting with `04` for an uncompressed pubkey).
8285
- Inside `wpkh` and `wsh`, only compressed public keys are permitted.
86+
- Inside `tr`, x-only pubkeys are also permitted (64 hex characters).
8387
- [WIF](https://en.bitcoin.it/wiki/Wallet_import_format) encoded private keys may be specified instead of the corresponding public key, with the same meaning.
8488
- `xpub` encoded extended public key or `xprv` encoded extended private key (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)).
8589
- Followed by zero or more `/NUM` unhardened and `/NUM'` hardened BIP32 derivation steps.
8690
- Optionally followed by a single `/*` or `/*'` final step to denote all (direct) unhardened or hardened children.
8791
- The usage of hardened derivation steps requires providing the private key.
8892

93+
`TREE` expressions:
94+
- any `SCRIPT` expression
95+
- An open brace `{`, a `TREE` expression, a comma `,`, a `TREE` expression, and a closing brace `}`
96+
8997
(Anywhere a `'` suffix is permitted to denote hardened derivation, the suffix `h` can be used instead.)
9098

9199
`ADDR` expressions are any type of supported address:

src/key_io.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ class DestinationEncoder
9898
return bech32::Encode(bech32::Encoding::BECH32, hrp, data);
9999
}
100100

101+
std::string operator()(const WitnessV1Taproot& tap) const
102+
{
103+
std::vector<unsigned char> data = {1};
104+
data.reserve(53);
105+
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, tap.begin(), tap.end());
106+
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
107+
}
108+
101109
std::string operator()(const WitnessUnknown& id) const
102110
{
103111
if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
@@ -215,6 +223,13 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
215223
return CNoDestination();
216224
}
217225

226+
if (version == 1 && data.size() == WITNESS_V1_TAPROOT_SIZE) {
227+
static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size());
228+
WitnessV1Taproot tap;
229+
std::copy(data.begin(), data.end(), tap.begin());
230+
return tap;
231+
}
232+
218233
if (version > 16) {
219234
error_str = "Invalid Bech32 address witness version";
220235
return CNoDestination();

src/pubkey.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes)
180180
std::copy(bytes.begin(), bytes.end(), m_keydata.begin());
181181
}
182182

183+
bool XOnlyPubKey::IsFullyValid() const
184+
{
185+
secp256k1_xonly_pubkey pubkey;
186+
return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data());
187+
}
188+
183189
bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const
184190
{
185191
assert(sigbytes.size() == 64);
@@ -188,13 +194,45 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si
188194
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), &pubkey);
189195
}
190196

191-
bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const
197+
static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
198+
199+
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
200+
{
201+
if (merkle_root == nullptr) {
202+
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
203+
// allow for reproducible tweaking.
204+
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
205+
} else {
206+
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
207+
}
208+
}
209+
210+
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const
211+
{
212+
secp256k1_xonly_pubkey internal_key;
213+
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());
216+
}
217+
218+
std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const
192219
{
193220
secp256k1_xonly_pubkey base_point;
194-
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, base.data())) return false;
195-
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &base_point, hash.begin());
221+
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
222+
secp256k1_pubkey out;
223+
uint256 tweak = ComputeTapTweakHash(merkle_root);
224+
if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt;
225+
int parity = -1;
226+
std::pair<XOnlyPubKey, bool> ret;
227+
secp256k1_xonly_pubkey out_xonly;
228+
if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt;
229+
secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly);
230+
assert(parity == 0 || parity == 1);
231+
ret.second = parity;
232+
return ret;
196233
}
197234

235+
198236
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
199237
if (!IsValid())
200238
return false;

src/pubkey.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <uint256.h>
1414

1515
#include <cstring>
16+
#include <optional>
1617
#include <vector>
1718

1819
const unsigned int BIP32_EXTKEY_SIZE = 74;
@@ -222,19 +223,56 @@ class XOnlyPubKey
222223
uint256 m_keydata;
223224

224225
public:
226+
/** Construct an empty x-only pubkey. */
227+
XOnlyPubKey() = default;
228+
229+
XOnlyPubKey(const XOnlyPubKey&) = default;
230+
XOnlyPubKey& operator=(const XOnlyPubKey&) = default;
231+
232+
/** Determine if this pubkey is fully valid. This is true for approximately 50% of all
233+
* possible 32-byte arrays. If false, VerifySchnorr and CreatePayToContract will always
234+
* fail. */
235+
bool IsFullyValid() const;
236+
225237
/** Construct an x-only pubkey from exactly 32 bytes. */
226238
explicit XOnlyPubKey(Span<const unsigned char> bytes);
227239

240+
/** Construct an x-only pubkey from a normal pubkey. */
241+
explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(Span<const unsigned char>(pubkey.begin() + 1, pubkey.begin() + 33)) {}
242+
228243
/** Verify a Schnorr signature against this public key.
229244
*
230245
* sigbytes must be exactly 64 bytes.
231246
*/
232247
bool VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const;
233-
bool CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const;
248+
249+
/** Compute the Taproot tweak as specified in BIP341, with *this as internal
250+
* key:
251+
* - if merkle_root == nullptr: H_TapTweak(xonly_pubkey)
252+
* - otherwise: H_TapTweak(xonly_pubkey || *merkle_root)
253+
*
254+
* Note that the behavior of this function with merkle_root != nullptr is
255+
* consensus critical.
256+
*/
257+
uint256 ComputeTapTweakHash(const uint256* merkle_root) const;
258+
259+
/** Verify that this is a Taproot tweaked output point, against a specified internal key,
260+
* Merkle root, and parity. */
261+
bool CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const;
262+
263+
/** Construct a Taproot tweaked output point with this point as internal key. */
264+
std::optional<std::pair<XOnlyPubKey, bool>> CreateTapTweak(const uint256* merkle_root) const;
234265

235266
const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
236267
const unsigned char* data() const { return m_keydata.begin(); }
237-
size_t size() const { return m_keydata.size(); }
268+
static constexpr size_t size() { return decltype(m_keydata)::size(); }
269+
const unsigned char* begin() const { return m_keydata.begin(); }
270+
const unsigned char* end() const { return m_keydata.end(); }
271+
unsigned char* begin() { return m_keydata.begin(); }
272+
unsigned char* end() { return m_keydata.end(); }
273+
bool operator==(const XOnlyPubKey& other) const { return m_keydata == other.m_keydata; }
274+
bool operator!=(const XOnlyPubKey& other) const { return m_keydata != other.m_keydata; }
275+
bool operator<(const XOnlyPubKey& other) const { return m_keydata < other.m_keydata; }
238276
};
239277

240278
struct CExtPubKey {

src/rpc/misc.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,11 @@ class BlindingPubkeyAdderVisitor
966966
id.blinding_pubkey = blind_key;
967967
}
968968

969+
void operator()(WitnessV1Taproot& tap) const
970+
{
971+
tap.blinding_pubkey = blind_key;
972+
}
973+
969974
void operator()(WitnessUnknown& id) const
970975
{
971976
id.blinding_pubkey = blind_key;

src/rpc/util.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,16 @@ class DescribeAddressVisitor
306306
return obj;
307307
}
308308

309+
UniValue operator()(const WitnessV1Taproot& tap) const
310+
{
311+
UniValue obj(UniValue::VOBJ);
312+
obj.pushKV("isscript", true);
313+
obj.pushKV("iswitness", true);
314+
obj.pushKV("witness_version", 1);
315+
obj.pushKV("witness_program", HexStr(tap));
316+
return obj;
317+
}
318+
309319
UniValue operator()(const WitnessUnknown& id) const
310320
{
311321
UniValue obj(UniValue::VOBJ);
@@ -1075,6 +1085,11 @@ class BlindingPubkeyVisitor
10751085
return id.blinding_pubkey;
10761086
}
10771087

1088+
CPubKey operator()(const WitnessV1Taproot& tap) const
1089+
{
1090+
return tap.blinding_pubkey;
1091+
}
1092+
10781093
CPubKey operator()(const WitnessUnknown& id) const
10791094
{
10801095
return id.blinding_pubkey;
@@ -1168,6 +1183,22 @@ class DescribeBlindAddressVisitor
11681183
return obj;
11691184
}
11701185

1186+
UniValue operator()(const WitnessV1Taproot& tap) const
1187+
{
1188+
UniValue obj(UniValue::VOBJ);
1189+
const CPubKey& blind_pub = tap.blinding_pubkey;
1190+
if (IsBlindDestination(tap)) {
1191+
obj.pushKV("confidential_key", HexStr(blind_pub));
1192+
WitnessV1Taproot unblinded(tap);
1193+
unblinded.blinding_pubkey = CPubKey();
1194+
obj.pushKV("unconfidential", EncodeDestination(unblinded));
1195+
} else {
1196+
obj.pushKV("confidential_key", "");
1197+
obj.pushKV("unconfidential", EncodeDestination(tap));
1198+
}
1199+
return obj;
1200+
}
1201+
11711202
UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
11721203
UniValue operator()(const NullData& id) const { return NullUniValue; }
11731204
};

0 commit comments

Comments
 (0)