Bitcoinjs-lib: TODO: Add Tapscript / Taproot feature

Created on 9 Dec 2019  路  19Comments  路  Source: bitcoinjs/bitcoinjs-lib

This will be a place to brainstorm ideas...

Needs:

  1. Tagged Hashes (maybe make a smaller separate package)
  2. Taproot builder (can we wedge this into the existing Payments API??? it seems to act similar to p2sh and p2wsh, and the lazy-loading should help greatly with performance due to the crypto operations to calculate the tweaked pubkey)
  3. Segwit v1 Address generation via the Payments(Taproot) API
  4. Schnorr signing module. (Modify tiny-secp256k1... not sure what to do with native JS though.)

Questions:

  1. When should this be implemented? I'm guessing we should wait for at least a testnet release of Taproot before spending time on it... But at the same time, it would help the development of taproot if we can look at taproot with fresh eyes / a new perspective and make suggestions based on problems while implementing.
  2. This is going to be a pretty big change... so maybe it should be a major version bump and that way we can reconsider existing API structure when adding Taproot.

Thoughts and comments welcome.

Most helpful comment

Working on it now.

Starting with tiny-secp256k1.

I am thinking of implementing TaggedHash and schnorr signing in tiny-secp256k1 itself since it is very bitcoin-specific. There is a PR currently up against secp256k1lib and I'll use that for the C++ addon for now.

WASM was considered to begin with for browsers but we'll put that off for now.

All 19 comments

Working on it now.

Starting with tiny-secp256k1.

I am thinking of implementing TaggedHash and schnorr signing in tiny-secp256k1 itself since it is very bitcoin-specific. There is a PR currently up against secp256k1lib and I'll use that for the C++ addon for now.

WASM was considered to begin with for browsers but we'll put that off for now.

Is there any update on this? I would like to help out if possible.

Hi @andrewtoth, thanks a lot.

There are quite a few large things I need to work on in order to get this out.

You helped a ton with # 3, thanks.

In order of difficulty, the next step would be to create a TaggedHash module. You can take care of that if you'd like. If you want you can just write a single js file and post a gist or create your own repo and I can take it into the BitcoinJS org. If you don't want to maintain it, it should be simple enough so we won't mind maintaining it.

After that... 2 is code-wise next difficult... but concept-wise it's one of the most difficult. I have been debating whether to just scrap the Payment API for a similar API that is more aligned with Output Descriptors. I envision an API where the methods would be able to calculate and output ranges of addresses, and there would be a toOutputDescriptor() method that would output the checksummed output descriptor.

As far as tiny-secp256k1 is concerned... I just need to sit down and do the work... I am thinking of borrowing code from node-secp256k1 so we can update to using N-API for native bindings.

Also I think bitcoinjs-lib should remove tiny-secp256k1 as a direct dependency but rather have it be passed as an optional dependency, that way anyone who doesn't need key operations can use bitcoinjs-lib without installing native addons. Also, you could plug in your own tiny-secp256k1 (I am making a WASM version in rust).

I also want to try and get the WASM version usable for the browser...

It's a daunting task. Though the recent discussions of a deployment schedule have pushed things forward.

Ok, I will get started on a TaggedHash module. Leave that with me.

I have some general thoughts on how we should approach this. I think making big changes before releasing some basic taproot features is a bit too ambitious. It could make taproot adoption for single sig wallets harder than it needs to be.

I started with # 3 because I think getting the ecosystem upgraded to allow sending to taproot is the best way to encourage adoption. Many projects need to have assurance that a good percentage of users will be able to send to a taproot address before integrating receiving and spending. I appreciate your point that backporting BIP350 could break some assumptions so it likely isn't safe to do so. I think we should cut a release with just the address and output generation right now as v6, to give many slow moving projects the ability to upgrade easily.

Next we should add a payments.p2tr that can receive and spend from a single key. That should then be released as a minor v6.1. I think for the vast majority of single sig wallets this will allow them to integrate taproot without burdening them with having to also move away from using the payments API. Adding unnecessary friction to simply switch to a different payment type is the wrong approach IMO.

I think the project should wait for a v7 before adding any complex tapscript functionality that breaks existing API. Let me know your thoughts.

I am against releasing a v6 with just the address changes.

If you are really set on releasing the address change ASAP, add some new methods and revert the changes to the old methods. Then we can release it as a minor version change to v5, and switch back to the currently merged method for v6.

fromBech32m,
toBech32m,
bech32mFromOutputScript,
bech32mToOutputScript

They should probably contain a deprecation warning with console.warn saying they will be removed in v6 for integration in fromBech32 etc.

I would be willing to release that immediately.

But that would make https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/transaction_builder.ts#L231 no longer just work with taproot, which is the key benefit in my view.

Ok it would be better than nothing if users of v5 can do txBuilder.addOutput(baddress.bech32mToOutputScript(taproot_address), value) instead of having no way to decode the new addresses.

I made a new branch https://github.com/bitcoinjs/bitcoinjs-lib/tree/v5 (I haven't actually published up to this point yet, but the changes are minor, so we can add the new methods to this and publish it.)

You can add the new methods to that.

Also, unrelated, TransactionBuilder is deprecated and will be removed in v6, so people coding in v5 should be moving to PSBT anyways.

@junderw here's the TaggedHash module if you want to pull it into BitcoinJs https://github.com/andrewtoth/tagged-hash.

It can be optimized by saving the mid state after hashing the prefix. I left an issue comment https://github.com/crypto-browserify/sha.js/issues/70. If it's worth it we can implement our own mid state savable implementation. I haven't found any.

Hi @junderw, I'm a software engineer at BitGo where we use a fork of bitcoinjs-lib for our utxo wallets. We're really interested in helping support taproot in bitcoinjs-lib, is there anything we can do to help with this? We would be willing to contribute our taproot code upstream

Hi!

Currently the plan is to use the tiny-secp256k1 WASM update, that way we can use the C library directly.

That said, this will shut out people who have older browsers.

One way I was thinking to solve this is to separate and make the tiny-secp256k1 module composable. So someone could implement a pure JS module with the same interface, and people could then plug in their own tiny-secp256k1-esque library.

Any thoughts on a WASM-only approach?

I think WASM support is wide spread enough that we wouldn't be too concerned with dropping support for older browsers.

However, my understanding is that this would require the unsafe-eval CSP rule enabled for pages which want to use WASM, which we don't currently allow (you can see a demo of this in action here). It looks like chromium is working on adding a wasm-unsafe-eval CSP rule which would allow this for WASM code only, but that is going to take a while to roll out.

I believe that means that these are our options:
1) enable unsafe-eval to run WASM-based tiny-secp256k1
2) use the upcoming modular tiny-secp256k1 and implement the interface in pure JS
3) do something fancy like run a tiny-secp256k1 worker with unsafe-eval enabled
4) wait for wasm-unsafe-eval to become implemented in mainline chrome

Is that right, or is there some other path forward that I'm missing here?

That sounds about right.
Thanks for sharing about the CSP rule behavior for WASM. I was not aware.

If you want to go with 2 you can definitely fork off of our pre-WASM version if that makes it easier, which would require adding some new schnorr based functions for both the native and pure JS module. I am not sure whether the pure JS schnorr parts should be included upstream elliptic library or not (that's what we used for the pure JS in the pre-WASM version)

3 might be better though short term, then 4 once it's widespread.

Hi @junderw,
I've been doing some outreach to get a sense whether projects and companies are going to be ready to send to Bech32m addresses when Taproot activates. The code changes in https://github.com/bitcoinjs/bitcoinjs-lib/pull/1676 seem to indicate that bitcoinjs could be ready, but I gather here that the sending support wasn't released yet. Do you think that bitcoinjs will have sending support before Taproot goes live in November?

That's the plan.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dakk picture dakk  路  3Comments

rbndg picture rbndg  路  3Comments

hoshsadiq picture hoshsadiq  路  3Comments

panpan2 picture panpan2  路  3Comments

namnv04 picture namnv04  路  3Comments