Skip to content

Conversation

@jachiang
Copy link

@jachiang jachiang commented Aug 26, 2019

This is the Schnorr & Taproot library extension of the Bitcoin Core Python TestFramework I have been working on during my residency. Although the TestFramework is intended to provide functional test coverage for the Bitcoin Core project, it can also serve as a convenient Schnorr/Taproot prototyping tool for developers.

The goal of this project was to provide a toolkit for users to quickly prototype new Bitcoin contracting proposals with Schnorr & Taproot, so that the community can quickly get familiar and provide constructive feedback.

Schnorr extensions

  • Musig signature aggregation
  • Adaptor Signature generation (Removed from this PR, out of scope for Optech)
  • Discrete Log Contract key generation (Removed, out of scope for Optech)

Taproot output classes (Segwit V1)

  • Taptree & constructor methods (huffman construtor with weighted tapleafs)
  • Tapscript descriptors (see below)

Minscript classes (can be composed to (correctly) express tapscript descriptors)
For example:

  • pkolder(key, time) = and_v(v:pk(key),older(time))
  • csahash(n, keys, hash) = and_v(v:thresh_csa,ripemd160)
  • csahasholder(n,keys,hash,time) = and_v(v:thresh_csa ,and_v(v:ripemd160(hash), older(time)))

Utility Classes/Methods

  • TestWrapper class wraps functionality of BitcoinTestFramework for external usage.
  • Refactor BitcoinTestFramework to encapsulate code in main into setup and shutdown, in order to prevent current code duplication in TestWrapper. I will also create a PR in master for this once completed.

Future work

  • Complete miniscript language support.
  • Policy to Miniscript compiler for Taproot outputs (Policy language can provide flexible composition of spending conditions for taproot outputs. The compiler will separate policy sub-expressions in different tapleafs for user-defined privacy.)

Your feedback and review is greatly appreciated.

I am currently documenting the library in form of interactive jupyter notebook files in bitcoinops/taproot.

@jachiang jachiang requested review from jnewbery and maflcko August 26, 2019 16:02
@jachiang jachiang closed this Aug 26, 2019
@jachiang jachiang force-pushed the optech-taproot-master branch from d84583b to 0423cd2 Compare August 26, 2019 16:17
@jachiang jachiang reopened this Aug 26, 2019
@jachiang jachiang force-pushed the optech-taproot-master branch from f01a3df to d55b495 Compare August 28, 2019 18:54
@jnewbery
Copy link

jnewbery commented Sep 2, 2019

Hi James. Thanks for removing the adaptor signature/DLC stuff. There are still a couple of things more to do before this is ready for review:

  • squash the 'fixup' commits. (eg remove the Removed Whitespaces. Edited var name & comments. and Min nVersion corrected to 1 in tests. commits)
  • make the framework changes in the same (or consecutive) commits to the tests in which they're first used.

Could you also open a PR just for the Add TestFramework reset required by TestWrapper. and Reorganization of BitcoinTestFramework main method. commits please (since we'd want to get those merged into bitcoin/bitcoin).

@jachiang jachiang force-pushed the optech-taproot-master branch from d55b495 to a5e7fb6 Compare September 3, 2019 00:33
@jachiang
Copy link
Author

jachiang commented Sep 3, 2019

  • squash the 'fixup' commits. (eg remove the Removed Whitespaces. Edited var name & comments. and Min nVersion corrected to 1 in tests. commits)
  • make the framework changes in the same (or consecutive) commits to the tests in which they're first used.

Could you also open a PR just for the Add TestFramework reset required by TestWrapper. and Reorganization of BitcoinTestFramework main method. commits please (since we'd want to get those merged into bitcoin/bitcoin).

Hi @jnewbery - Many thanks for the preliminary review. I have addressed your comments as suggested.

@jnewbery jnewbery force-pushed the optech-taproot-master branch from a5e7fb6 to 34f3874 Compare September 6, 2019 17:40
@jnewbery
Copy link

jnewbery commented Sep 6, 2019

I've force pushed a change to fix some general best practices:

  • wrapped commit logs at 120 chars
  • removed unused python imports and sorted imports according to PEP 8.

original branch is here: https://github.com/jnewbery/bitcoin/tree/2019-09-optech-taproot-master-original

@jnewbery jnewbery force-pushed the optech-taproot-master branch from 34f3874 to e6b0948 Compare September 6, 2019 18:05
@jnewbery
Copy link

jnewbery commented Sep 6, 2019

force-pushed some more updates:

  • changed file permissions so test files are runnable (chmod 755)
  • renamed test files to be feature_ instead of framework_
  • added boilerplate licence text and doc strings
  • fixed all flake8 warnings

Copy link

@jnewbery jnewbery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed all the changes in key.py. I haven't reviewed script.py or the individual test scripts.

return ret

def mul(self, data):
assert(self.valid)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I know this already occurs throughout this module, but in Python, assert is a statement, not a function, so this should be assert self.valid. No need to change it here, but this would be better without the parens.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a docstring commenting this function (ie that this multiplies a public key by a scalar).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a docstring commenting this function (ie that this adds two pubkeys)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider using the __add__ method so users can use the more natural notation:

a = ECPubKey()
b = ECPubKey()
c = a + b

than:

a = ECPubKey()
b = ECPubKey()
c = a.add(b)

(same comment for other add() and mul() functions in this commit)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I kept add/mul for key operations for scalar bytes (e.g. tweaking a key with hash digest), but these are just wrappers for +/- to minimise code duplication.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the variable name secret is appropriate here. Perhaps summand?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider using a map-reduce here:

from functools import reduce
R_agg = reduce(lambda x, y: SECP256K1.add(x, y), map(lambda x: x.p, Rv))

actually, since you've already defined a way to add ECPubKeys, you don't even need the map:

R_agg = reduce(lambda x, y: x.add(y), Rv).p

If you define __add__ for ECPubKey, then this just becomes:

R_agg = sum(Rv).p

edit: since you're returning a ECPubKey object, just set R_agg as a ECPubKey:

R_agg = reduce(lambda x, y: x.add(y), Rv)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I suggest using a reduce pattern here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment could be improved by documenting what is being returned.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len(s) is guaranteed to be 32 by construction. It would be better to assert that len(sig) == 64 at the top.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use sum or reduce here (and for the r aggregation below)

@jachiang jachiang force-pushed the optech-taproot-master branch from 2495575 to 16e581b Compare September 15, 2019 16:05
@jachiang
Copy link
Author

@jnewbery - Many thanks for your detailed review. I have incorporated all of your feedback in the latest push.

In order to wrap the BitcoinTestFramework class in a user-defined class,
which can be started and shutdown, the code in BitcoinTestFramework main
has been encapsulated in respective functions. Additionally, test-run
specific state in temp-directory and NetworkThread is now reset after
shutdown.
These methods are required for the multiplication/tweaking of
private/public key pairs. Keypairs are multiplied by a challenge factor
in musig signatures. Keypairs are tweaked in both discrete log contracts
and adaptor signatures.
@jnewbery jnewbery force-pushed the optech-taproot-master branch from 16e581b to 2cb0009 Compare September 15, 2019 19:47
@jnewbery
Copy link

I've force-pushed a branch that squashes the latest changes into the appropriate commits, and also adds the tests to test_runner.py

Copy link

@jnewbery jnewbery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed three commits containing nits for the add/mul commit, the schnorr commit and the musig commit.

@jachiang - can you review those commits and squash them into the preceding commits if you're happy with them?

I've also left a couple of small comments on musig.py

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicating code from sign_schnorr in key.py. Can you just call through to that method to avoid the duplication?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you document what the arguments are in this docstring?

jachiang and others added 3 commits September 16, 2019 17:20
MuSig scheme is based on the interactive MuSig proposal, which is not
formalized into a BIP proposal at the time of this writing.
Added miniscript class and expressions.

Added subset of miniscript, which can be used to construct/satisfy
scripts in a composable manner.

Add miniscript to TapLeaf descriptors.

TapLeaf class now deserializes/serializes descriptors with miniscript
nodes. This facilitates construction of new tapleaf descriptors due to
composability. New TapLeaf descriptors added containing time/hash
expressions.

Added TapLeaf test for pk descriptor types.

Test constructs and spends scriptpaths of taptree which is constructed
from various pk tapscript descriptor types containing pk, hash and time
expressions.

Added TapLeaf test for csa descriptor types.

Test constructs and spends scriptpaths of taptree which is constructed
from various csa (checksigadd) tapscript descriptor types containing pk,
hash and time expressions.
@jnewbery jnewbery force-pushed the optech-taproot-master branch from a4dd190 to 18a2613 Compare September 16, 2019 21:24
@jnewbery
Copy link

@jachiang - this code is still undergoing active development in the https://github.com/bitcoinops/taproot-workshop repo. I suggest we close this PR until that's settled down, and then perhaps you can re-open against https://github.com/bitcoin/bitcoin when there's a schnorr/taproot PR?

@jachiang
Copy link
Author

@jachiang - this code is still undergoing active development in the https://github.com/bitcoinops/taproot-workshop repo. I suggest we close this PR until that's settled down, and then perhaps you can re-open against https://github.com/bitcoin/bitcoin when there's a schnorr/taproot PR?

Sounds good @jnewbery! Many thanks again for your extensive review on this PR.

@jnewbery jnewbery closed this Oct 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants