Implement BIP 340-342 validation - Implement Taproot validation (BIP 341) (consensus, taproot)

Host: jnewbery  -  PR author: sipa

The PR branch HEAD was 84ec87085 at the time of this review club meeting.

This is the fifth in a series of review club meetings on the (work in progress) implementation of BIP 340-342.

This week, we’ll look at another commit from PR 17977 - Implement Taproot validation (BIP 341).


  • Remember that this PR uses an updated version of libsecp256k1 that requires the --enable-module-schnorrsig and --enable-experimental options. You may need to make clean && ./configure && make for the build to succeed.

  • This commit implements the script validation rules from BIP 341. It’ll help to refer back to that specification as you review the code.

  • There are several script verification flags defined in the software. These are passed to the script interpreter and specify which rules the interpreter should enforce. Each of these verification flags should be a tightening of the rules (adding a new script verification flag can make a previously succeeding script fail, but cannot make a previously failing script succeed).

  • This commit adds two new script verification flags: SCRIPT_VERIFY_TAPROOT and SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION.

  • Pay-to-contract is a method of hiding a commitment inside a public key, which can be selectively revealed later. The idea has been around for many years, with the original taproot post citing a paper by Ilja Gerhardt and Timo Hanke from 2012. Taproot uses pay-to-contract to commit to a script (or scripts) inside a public key.

  • This commit adds a CheckPayToContract() function, which calls through to the secp256k1_xonly_pubkey_tweak_add_check() function.

  • The main code changes in this commit are in src/script/interpreter.cpp. The VerifyWitnessProgram() is modified, and a new VerifyTaprootCommitment() is added.

  • Everything in the if (stack.size == 1) branch corresponds to the “If there is exactly one element left in the witness stack, key path spending is used” section of the BIP. Everything in the else branch corresponds to the “If there are at least two witness elements left, script path spending is used” part of the BIP.

  • This commit does not add any script verification for the taproot script path spending (that comes in a later commit). Once the taproot commitment has been verified, we either fail validation if the SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION is set, or succeed if it isn’t (code).


  1. Will the new SCRIPT_VERIFY_TAPROOT and SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION script verification flags be used for consensus checks or policy checks?

  2. What is the maximum permitted size of the control block?

  3. What happens if a segwit v1 output has a witness program that isn’t 32 bytes? What happens if there’s a P2SH-wrapped segwit v1 output?

  4. Explain this line: if (!(flags & SCRIPT_VERIFY_TAPROOT)) return set_success(serror);

  5. What error is given if VerifyTaprootCommitment() fails? Why?

Meeting Log

  117:00 <jnewbery> #startmeeting
  217:00 <jnewbery> Hi folks. Welcome to PR Review club. Feel free to say hi!
  317:00 <gzhao408> HI!!!!
  417:00 <pinheadmz> hi
  517:00 <emzy> hi
  617:00 <robot-dreams> Hi
  717:00 <Paul_R> hi everyone
  817:00 <nehan> hi
  917:00 <kimgnome> hi
 1017:00 <sosthene> hi!
 1117:00 <jnewbery> HI GZHAO!
 1217:00 <michaelfolkson> WHAT
 1317:00 <jnewbery> And let us know if it's your first time here. We love new participants.
 1417:00 <michaelfolkson> hi
 1517:00 <kimgnome> First time
 1617:00 <gzhao408> 😂
 1717:01 <jnewbery> welcome kimgnome!
 1817:01 <fjahr> hi
 1917:01 <jonatack> hi. i see some people are wide awake at this hour ;)
 2017:01 <kimgnome> Thanks
 2117:01 <unweave> hi
 2217:01 <jnewbery> Brief reminder of the format: I have some questions prepared that we'll go through, but feel free to jump in at any point. If you have a question, just ask at any time!
 2317:01 <sosthene> not really my first time, but it has been a while, a year I think :)
 2417:01 <dhruvm> hi
 2517:01 <Paul_R> also my first time
 2617:01 <jnewbery> welcome back sosthene :)
 2717:01 <jnewbery> welcome Paul_R
 2817:01 <Paul_R> thx
 2917:02 <jnewbery> other thing to remember: We're all here to learn, so there's no such thing as a stupid question.
 3017:02 <jonatack> great to see new people :D
 3117:02 <jnewbery> ok, let's get started!
 3217:02 <jnewbery> Notes and questions in the normal place:
 3317:02 <jnewbery> Who had a chance to review this week's commit? (y/n)
 3417:02 <pinheadmz> y
 3517:02 <gzhao408> y
 3617:02 <robot-dreams> y
 3717:02 <Paul_R> y
 3817:02 <emzy> n
 3917:02 <sosthene> n
 4017:02 <nehan> .5y
 4117:02 <jonatack> y
 4217:02 <fjahr> y
 4317:02 <jnewbery> wow that's a lot of review
 4417:02 <figs> y
 4517:02 <jnewbery> Any initial thoughts from those who reviewed it? Is it what you expected taproot to look like?
 4617:03 <robot-dreams> initial thoughts: I expected it'd be a really scary change about elliptic curves, but it turned out to be slightly more approachable and focused on soft forks :)
 4717:04 <jnewbery> robot-dreams: good! Yes, all the EC stuff is hidden away in libsecp
 4817:04 <gzhao408> It taught me about script upgradeability using witness versions 🤔was wondering, if there was another script upgrade we wanted to do using v2 for example, would it be incompatible with taproot?
 4917:04 <nehan> i am super confused and am looking forward to learning more about what's going on!
 5017:04 <pinheadmz> yeah its simpler than i expected -- checkTaprootCommitmenet in particualr, the way the control block is merkleized is a lot simpler than i imagined
 5117:05 <jnewbery> robot-dreams: probably good to review the last taproot PR review club to see how we use the new libsecp interface:
 5217:05 <pinheadmz> gzhao408 v2 wouldnt be inompatible with taproot kinda like how taproot (v1) isnt incompatible with segwit v0
 5317:05 <pinheadmz> i mean, they are incompatible but they dont interfere with each other
 5417:06 <michaelfolkson> We are swimming in possible upgrade paths
 5517:06 <gzhao408> right, but if they had distinct features that were both really nice, would we be able to have both in the same script? or would there be a better way?
 5617:06 <unweave> pinheadmz would it be accurate to say "wouldn't *need to be* incompatible" ?
 5717:06 <pinheadmz> i see - well there are some logic in the code where its like (if WITNESSV0 || TAPROOT)
 5817:06 <pinheadmz> so you could add another (...|| V2) in there to share logic from taproot with v2
 5917:06 <gzhao408> my guess is no but I can't think of any concrete examples where it'd be necessary so 😅
 6017:07 <jnewbery> gzhao408: it's difficult for me to imagine something that abstract
 6117:07 <sosthene> But do we still need V2 anyway? :p
 6217:07 <jnewbery> but if there were eventually some segwit v2 I imagine it might have a superset of taproot's functionality maybe(?)
 6317:08 <pinheadmz> true also with leaf versions you could have a new script language inside a v1 taproot
 6417:08 <jnewbery> pinheadmz: yep, I expect you can do almost everything you want with script versions inside taproot
 6517:09 <michaelfolkson> It gets messy when you start wanting to take an old version (say 1) when you have a new version (say 2) and add new features to that old version to make say 3
 6617:09 <jnewbery> ok, first question: Will the new SCRIPT_VERIFY_TAPROOT and SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION script verification flags be used for consensus checks or policy checks?
 6717:09 <gzhao408> thanks for answering my question <jnewbery> <pinheadmz>, I'll think on it more - just want to feel out what the boundaries of compatibility are
 6817:09 <robot-dreams> I think `SCRIPT_VERIFY_TAPROOT` is for consensus: it might cause some blocks to be rejected
 6917:09 <robot-dreams> On the other hand, I think `SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION` is for policy: it might prevent some transactions from being signed or added to the mempool, but it won't cause blocks to be rejected
 7017:09 <pinheadmz> robot-dreams i think youre right, and "DISCOURAGE..." anything is just policy
 7117:09 <gzhao408> +1 robot-dreams, and I wanna check my understanding of the DISCOURAGE flags, I think it’s: before, v1 would have been WITNESS_UNKNOWN, so no requirements… and now there are (stricter) defined taproot spending rules. So if we didn’t discourage, it’s possible for us to accept an old v1 to mempool, but then it wouldn’t pass consensus after the soft fork?
 7217:09 <gzhao408> yeah, discourage but not enforce
 7317:10 <gzhao408> er - enforce in block validation*
 7417:10 <pinheadmz> discourage means: reject from mempool, still valid in block
 7517:10 <jonatack> counterargument to sow doubt: the flags are in protocol.h
 7617:11 <gzhao408> pinheadmz 👍
 7717:11 <Paul_R> therefore it's a policy, not consensus rule
 7817:11 <Paul_R> @pin
 7917:11 <Paul_R> pinheadmz
 8017:11 <gzhao408> :jonatack: well, policy flags is a superset of consensus flags
 8117:11 <jonatack> gzhao408: stirring things up
 8217:11 <pinheadmz> and then you might see in the future say if ANNEX gets a function, that DISCOURAGE ANNEX will be removed and the new annex rules enforced by soft fork
 8317:11 <gzhao408> u jonatack i counteratack
 8417:12 <gzhao408> AND It’s not possible to add a script verification flag that makes spending rules less strict, right? i.e. they are all backwards compatible
 8517:12 <pinheadmz> less strict rules -> hard fork :-(
 8617:12 <jnewbery> jonatack: the flags are in script/interpreter.h
 8717:13 <jnewbery> gzhao408: yes, adding a new flag should only make things more strict
 8817:13 <gzhao408> I think jonatack is referring to the STANDARD_SCRIPT_VERIFY_FLAGS in policy.h
 8917:14 <jonatack> i wondered if the "answer" might be "both"
 9017:14 <robot-dreams> Yes, STANDARD_SCRIPT_VERIFY_FLAGS is in policy.h but I think it's also worth noting GetBlockScriptFlags
 9117:15 <jnewbery> my answer is: after the taproot softfork (however it gets activated), SCRIPT_VERIFY_TAPROOT will be a consensus rule
 9217:15 <jnewbery> SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION is intended to be a policy rule
 9317:15 <jnewbery> why do we discourage future taproot versions?
 9417:16 <michaelfolkson> Because they are unencumbered?
 9517:16 <sosthene> To discourage people using future versions while there are still not defined?
 9617:17 <robot-dreams> to communicate something like "this is a nonstandard transaction, don't do this"?
 9717:17 <pinheadmz> some of these policy rules are because they are anyone can spend, but a lot of policy rules are DDoS mitigation as well
 9817:17 <gzhao408> because... otherwise you might accept to mempool (if you didn't discourage in policy), and then there's a spending rule activated, and then it no longer passes consensus?
 9917:17 <gzhao408> (is that scenario possible?)
10017:18 <pinheadmz> gzhao408 youd have to get the timing just right :-)
10117:18 <gzhao408> <pinheadmz> couldn't it hang out in your mempool for a while if it was full?
10217:18 <pinheadmz> get a tx in the mempool right on activation
10317:18 <jnewbery> gzhao408: you certainly need to be careful around activation time with your mempool and propagating transactions
10417:19 <pinheadmz> i wonder actually if the mempool evicts invalid txs on the edge of activation
10517:19 <jnewbery> you're right that having a policy rule well in advance of activation prevents us from having this problem
10617:19 <pinheadmz> I actually sent btc to a v1 address, that is an anyonecanspend output and its in the utxo set right now
10717:19 <pinheadmz> someone could try to spend it on the block before taproot is enforced
10817:19 <Paul_R> recently?
10917:20 <pinheadmz> a few months ago, after bitcoin core eased the restriciton on DISCOURAGE UNKOWN WITNESS version
11017:20 <jnewbery> pinheadmz: I don't think the mempool would do anything at activation time, but policy should mean that there aren't any of those transaction in there
11117:21 <gzhao408> ! so at what point do we start applying SCRIPT_VERIFY_DISCOURAGE_UPGRADEABLE_TAPROOT_VERSION, would that theoretically be well before we start enforcing taproot in consensus?
11217:21 <jnewbery> right, sending _to_ a v1 address is policy-valid. Spending _from_ v1 is policy-invalid
11317:21 <pinheadmz> ah ok
11417:21 <pinheadmz> what if a node / miner had requireStandard: false ?
11517:21 <jnewbery> so someone could theoretically spend pinheadmz's output if they could get their transaction to a miner that isn't enforcing that policy
11617:22 <jnewbery> but that transaction probably won't propogate through the network otherwise because it's policy-invalid for most nodes
11717:22 <pinheadmz> but is there any chance that (lets say with standard: false) the spend enters a miner's mempool?
11817:22 <pinheadmz> then the next block, taproot is enforecd
11917:22 <pinheadmz> the mining code assumes the entire mempool is valid for the next block, i think ?
12017:23 <jnewbery> pinheadmz: i believe you're right. So the miner needs to ensure that they're enforcing the new consensus rules on their mempool well before activation
12117:23 <pinheadmz> interesting
12217:23 <pinheadmz> theres no check mempool and evict function outside of a reorg ?
12317:24 <Paul_R> jnewbery: are miner's generally this responsible?
12417:24 <robot-dreams> this is for the miner's benefit, right? (they don't want to put in the work to mine a block and then have it be rejected cause of upgraded VERIFY rules)
12517:24 <jnewbery> gzhao: SCRIPT_VERIFY_DISCOURAGED_UPGRADEABLE_TAPROOT_VERSION would be enforced in policy from when taproot is activated
12617:24 <gzhao408> <jnewbery> ohhh i see, thanks!
12717:25 <unweave> >that transaction probably won't propogate [...] because it's policy-invalid I've had transactions confirm that violated policy and I didn't put any extra effort into shepherding them to a miner FWIW
12817:25 <jnewbery> Paul_R: if they're running Bitcoin Core then any v1 spends are already policy-invalid and not in their mempool
12917:25 <jonatack> pinheadmz: i've wondered when/why someone would set -acceptnonstdtxn
13017:25 <pinheadmz> p.s.
13117:26 <pinheadmz> 5,431 free satoshis for someone
13217:26 <jonatack> it's testing only
13317:26 <jnewbery> unweave: interesting
13417:26 <jnewbery> Next question (although feel free to continue asking questions about flags/policy if there's anything unanswered): What is the maximum permitted size of the control block?
13517:27 <unweave> If I recall correctly, it was a txn which had sub 1 sat/byte fee rate
13617:27 <michaelfolkson> 33+32*128
13717:27 <jonatack> static_assert(TAPROOT_CONTROL_MAX_SIZE == 4129); // 33 + (32 * 128)
13817:28 <jnewbery> unweave: that is interesting. Most nodes won't propogate transactions with a feerate under 1 sat/byte
13917:28 <jnewbery> michaelfolkson jonatack: exactly
14017:28 <jnewbery> that was an easy one though :)
14117:28 <jnewbery> Next: What happens if a segwit v1 output has a witness program that isn’t 32 bytes? What happens if there’s a P2SH-wrapped segwit v1 output?
14217:29 <pinheadmz> jnewbery these are unencumbered
14317:29 <jnewbery> pinheadmz: yes!
14417:29 <pinheadmz> although - there was the bech32 issue which could be mitigated if program length was more strictly enforced
14517:29 <pinheadmz> lost track of that thread, i guess we are not doing anything about in taproot?
14617:29 <robot-dreams> but I believe if the `SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM` flag is set, we will fail validation for these cases
14717:30 <jnewbery> bech32 is an address format. It doesn't impact consensus or validity of transactions.
14817:30 <michaelfolkson> I had to look up what a control block is
14917:30 * michaelfolkson shrugs
15017:30 <pinheadmz> jnewbery yes but if we enforce v1 programs to be exactly 32 bytes then we can mitigate a user error where an address has extra qqqq's or whatever it was
15117:31 <jnewbery> robot-dreams: right, exactly. So these transactions would be consensus valid, but would fail policy
15217:31 <pinheadmz> robot-dreams good point
15317:31 <jnewbery> pinheadmz: when you say "we enforce" are you talking about in the wallet software?
15417:32 <pinheadmz> hm. i suppose yeah - but consensus doesn't allow witness v0 programs to be != 20 or 32
15517:32 <pinheadmz> so even broken wallet software cant lose money sent to a v0 program with 33 bytes
15617:33 <pinheadmz> a broken v1 wallet could, although tht point about policy i guess steps in there
15717:33 <jnewbery> pinheadmz: yes, an OP_0 then a push that isn't 20 or 32 bytes is always invalid.
15817:33 <Paul_R> Can a full-node be adversarial by not-listening to policy? could it then spread undesirable txs to miners & possibly blocks? will this nodes peers ban it?
15917:34 <jnewbery> does anyone have any questions about 'P2SH-wrapped'?
16017:34 <pinheadmz> Paul_R you cant force a peer to accept a tx. so *their* mempool polocy protects them, including miners
16117:34 <jnewbery> Like for example "what is P2SH-wrapped?"? Does anyone have that question?
16217:35 <robot-dreams> jnewbery: I do have a question, why don't we support that for Taproot?
16317:35 <jnewbery> good question robot-dreams!
16417:35 <robot-dreams> I'd imagine it'd be a convenient way to let legacy wallets pay to a new address
16517:35 <jnewbery> anyone got a good answer for that?
16617:35 <pinheadmz> i think its bc it turns into a complexity nightmare
16717:35 <pinheadmz> nested was essential for the transition to segwit
16817:36 <michaelfolkson> Because we were introducing bech32 right?
16917:36 <pinheadmz> this just means that wallets cant send to taproot address :-P
17017:37 <michaelfolkson> There is no new address format with Taproot
17117:37 <pinheadmz> michaelfolkson right I mean, if you only want to accept taproot ouputs there is no address you can give to a legacy-legacy wallet
17217:37 <pinheadmz> with segwit v0 you had the option of nested addresses
17317:37 <michaelfolkson> So a P2SH wrapped Taproot won't be able to be spent
17417:38 <jnewbery> Right exactly, bech32 has been around for several years, so there's nothing new for wallets to do to be able to send to a taproot output
17517:38 <pinheadmz> michaelfolkson there's just no such thing
17617:38 <pinheadmz> its anyone can spend
17717:38 <jnewbery>
17817:38 <jnewbery> pinheadmz: exactly - it's unencumbered
17917:38 <michaelfolkson> Ah ok
18017:39 <nehan> what exactly does unencumbered mean?
18117:39 <robot-dreams> Just confirming, "unencumbered" means it's a transaction output that anyone can figure out how to spend just by looking at it (no private keys / etc. neeeded)?
18217:39 <robot-dreams> nehan: thanks for asking :)
18317:39 <Paul_R> +1
18417:39 <jnewbery> yes that. It's anyone-can-spend
18517:40 <michaelfolkson> There's no reason for wanting P2SH wrapped Taproot as far as I know. Other than for avoiding mistakes with anyone can spend
18617:40 <jnewbery> Of course, you'd need the preimage, so maybe unencumbered is maybe the wrong word
18717:40 <jonatack> unencumbered by rules
18817:40 <jnewbery> but if you have the preimage, it's anyone can spend (eg a miner could steal it from you if you created a transaction spending it)
18917:41 <jnewbery> does that make sense nehan?
19017:41 <nehan> jnewbery: yes thanks
19117:41 <jonatack> unencumbered by s/rules/script validation rules/
19217:42 <jnewbery> good! Everyone else happy with that? It's a little bit subtle
19317:42 <michaelfolkson> encumber -to burden with obligations (dictionary)
19417:42 <jnewbery> ok, next question: Explain this line: if (!(flags & SCRIPT_VERIFY_TAPROOT)) return set_success(serror);
19517:43 <nehan> why are v1 outputs with lengths other than 32 bytes unencumbered instead of unspendable?
19617:43 <michaelfolkson> For future upgradability
19717:43 <sosthene> nehan: iirc, it is to allow them being used in the future
19817:43 <nehan> ah, ok thanks!
19917:43 <pinheadmz> yeah, an interesting design charactersitic of taproot is ALLL the upgradeablity
20017:43 <jonatack> The bitwise AND of (flags & SCRIPT_VERIFY_TAPROOT) equalling 1 (true) means we need to verify SCRIPT_VERIFY_TAPROOT?
20117:43 <jonatack> so if bitwise AND evaluates to 0 (false) then no need to verify and we can return with success
20217:43 <robot-dreams> jnewbery: Taproot validation is a soft fork: if the VERIFY flag is not set, it's unencumbered (similar to legacy client behavior for P2SH and Segwit)
20317:44 <pinheadmz> i think the authors might have felt like segwit v0 was too restricvitve perhaps, that theyd painted themself into a corner
20417:44 <fjahr> Checks that the SCRIPT_VERIFY_TAPROOT flag is set for this script check. If not it skips verification and returns with success immediately.
20517:44 <jnewbery> michaelfolkson sosthene: potentially, but it seems unlikely we'd ever use non-20/32-byte v1 outputs for anything
20617:44 <michaelfolkson> No loss though right? If there is even a chance we might use them, keep them upgradable?
20717:45 <michaelfolkson> Apart from anyone can spend mistakes by people playing around with this stuff
20817:45 <jnewbery> michaelfolkson: is that any worse than unspendable?
20917:45 <nehan> well, anyone can spend seems always better than unspendable
21017:45 <sosthene> jnewbery: why?
21117:46 <michaelfolkson> Fair point. If you put something with anyone can spend on the blockchain you aren't getting it back :)
21217:46 <sosthene> I mean, it seems that last year there was discussion about the benefits of leaving this door open, but maybe there are other arguiments since I'm not aware of
21317:46 <michaelfolkson> But you aren't getting it back if it is unspendable either so...
21417:46 * michaelfolkson shrugs
21517:46 <nehan> unspendable = money burnt forever
21617:47 <michaelfolkson> anyone-can-spend = enter into a race with the entire Bitcoin world
21717:47 <Paul_R> could someone create a 'chain-analysis' of sorts, to automatically detect unencumbered coins and sweep them?
21817:47 <jnewbery> robot-dreams: that's right, if the flag isn't set, then a v1 segwit output is unencumbered
21917:47 <jnewbery> Paul_R: I'm sure they already have
22017:47 <unweave> michaelfolkson and yet as pinheadmz 's txn shows, it's a very slow race, no?
22117:48 <Paul_R> because then it seems like there would be some parties competing to do so, which would be a weird industry... yeah pinheadmz shows it is a very slow race so far haha
22217:48 <unweave> Paul_R this already happens with low entropy keys
22317:48 <michaelfolkson> Oh no that actually is unspendable isn't it?
22417:48 <pinheadmz> that and as discussed, policy rejects spending from anyonecanspend
22517:48 <pinheadmz> so itd have to be a clever miner
22617:48 <michaelfolkson> Wasn't that a Taproot output?
22717:48 <michaelfolkson> Before Taproot is activated?
22817:48 <pinheadmz> and yes, the taproot address i used is just 32 0x01 bytes -- so this output is actually UNSPENDABLE once taproot activates!
22917:49 <pinheadmz> (bc there is no private key for that witness program)
23017:49 <Paul_R> pinheadmz all for 5000sats // .50 euros
23117:49 <unweave> ah I think I misunderstood
23217:49 <unweave> :)
23317:49 <jnewbery> Final question: What error is given if VerifyTaprootCommitment() fails? Why?
23417:49 <michaelfolkson> Oh there's that too pinheadmz but it is currently unspendable now too right?
23517:49 <pinheadmz> witness program mismatch
23617:50 <pinheadmz> this is the function that checks that the control block crap and witness data match the output, aka witness program aka the adress coin is sent to
23717:50 <pinheadmz> oops didnt mean to type crap
23817:50 <michaelfolkson> banned
23917:50 <jonatack> no more review club for you
24017:50 <jnewbery> :shocked:
24117:50 <pinheadmz> damn
24217:51 <pinheadmz> starting my own ##PR-club-with-cuss-words
24317:51 <robot-dreams> This means the witness program (Schnorr public key) didn't commit to the Merkle root demonstrated by the script
24417:51 <fjahr> michaelfolkson: it's not really a race between the entire bitcoin world though, only the question which miner mines the next block. If you send a miner a anyonecanspend why would they mine it for you? They will just replace it with their own tx.
24517:51 <robot-dreams> (though I don't yet know the mechanism by which a Schnorr public key commits to a hash)
24617:51 * michaelfolkson checks code of conduct
24717:52 <jnewbery> but yes, it's the function that checks that the witness program has commited to the witness, so if it fails, then it's a witness program mismatch
24817:53 <jnewbery> ok, we have a few minutes left. Did anyone have any other questions or observations they wanted to share?
24917:53 <unweave> [off topic] Paul_R see this presentation for examples of automated sweeping of low-entropy bitcoin funds "DEF CON 23 - Ryan Castellucci - Cracking CryptoCurrency Brainwallets"
25017:53 <Paul_R> unweave thx!
25117:54 <michaelfolkson> Yeah I guess its worse than I said. Race in which you can only win if miner is dumb
25217:54 <robot-dreams> to followup on P2SH wrapping:
25317:54 <robot-dreams> was the conclusion "we're not going to support this because the benefit (allowing very old wallets to send to a taproot output) isn't worth the multitude of added complexity, privacy implications, etc."?
25417:56 <jnewbery> robot-dreams: yes, those are good arguments against
25517:57 <jnewbery> I argued against it here: because I think the benefits of allowing P2SH-wrapped segwit v0 don't apply any more
25617:57 <jnewbery> ok, just about time to wrap up. Any final thoughts? How are y'all enjoying taproot review?
25717:57 <jonatack> we lost gzhao408
25817:58 <Paul_R> that was a great first experience, thanks everyone
25917:58 <Paul_R> i wish i had come sooner
26017:58 * gzhao408 was afk because of work meeting
26117:58 <robot-dreams> very exciting taproot review, this was a great entry point into "what is taproot"
26217:58 <michaelfolkson> I'd like to suggest added comments to Taproot PR but I guess it isn't a good time
26317:58 <jnewbery> ok, let's call it. Thanks everyone. See you all next week!
26417:58 <sosthene> thanks, that was very interesting
26517:59 <gzhao408> jnewbery i am loving taproot review, script is very exciting stuff
26617:59 <jonatack> Paul_R: great 🚀
26717:59 <jnewbery> #endmeeting