-
-
Notifications
You must be signed in to change notification settings - Fork 672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Taproot multisig #4159
base: main
Are you sure you want to change the base?
Taproot multisig #4159
Conversation
675c45c
to
7adcabd
Compare
7adcabd
to
20ad7e0
Compare
20ad7e0
to
14e9116
Compare
@prusnak @andrewkozlik @onvej-sl @matejcik Any feedback on this PR? |
sure! in the future, please open an issue first where you outline your proposed solution. that way you can avoid doing all the work in case we say it's not something we are interested in 🤷♀️ |
The change is not so big and honestly it is worth merging in. Of course, we really need to have the new code properly tested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add some tests that test the construction of a Taproot multisig transaction?
Thank you for the feedback @matejcik and @prusnak
There is in fact an open issue, #1946, which I linked. The consensus in that issue is to implement the approach in this PR. Also, this approach will be compatible with BIP387 descriptors
Yes, I'd be happy to add tests and make any changes needed to have this feature merged and released. But first, I would like some assurance that this will in fact be merged. Would we be able to approve the workflows here so I can make sure I didn't miss anything else? |
14e9116
to
c89ace9
Compare
Why is this preferred to using a static dummy key from previously used code? |
This makes it compatible with BIP388 wallet policies. I cannot make a multisig wallet using a Trezor as one key and another hardware wallet that uses wallet policies as another key with just a static dummy key. |
Amazing! |
I fixed smaller issues detected by the CI in commit e8cc7c4, but there is still bigger fish to fry:
|
For me
returns
I couldn't find much docs on setting up pyright. Any hints? |
Hm. Not sure - maybe Or you can use pyright from brew, if you are no macOS. |
Thanks! After my last commit I get:
|
I get an error that I need to add a changelog as well. Should I do that or will you? |
I added it in my commit already |
Ah I see legacy tests are failing. I only tested this on Model T with |
385baa6
to
a9ff3de
Compare
We can disable the tests with @pytest.mark.models(skip=["legacy"]) |
For the device tests, it appears I need to add hashes for each device and each language. Could that be done in an automated step by CI? |
eebf5ad
to
69e4e74
Compare
69e4e74
to
549d592
Compare
@prusnak I'm unsure how to proceed here. I don't have any context about what the Is there anything else I need to do here? |
Let's leave that to @matejcik or someone else from the firmware team. I am sure the fix is trivial, but for me or you it would take hours to figure out. Also legacy needs a changelog entry because we touched the code in the Again, thank you for this massive contribution and we'll take it from here. |
core/src/apps/bitcoin/multisig.py
Outdated
depth=0, | ||
fingerprint=2084970077, | ||
child_num=0, | ||
chain_code=b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we also want to allow passing in the chain code to create a randomized xpub that still uses the NUMS point public key. That way the derived public key is provably unspendable, but cannot be fingerprinted on chain.
We will need to define a new parameter for this in the MultisigRedeemScriptType.
for i in multisig.address_n: | ||
node.derive(i, True) | ||
return node.public_key() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something I don't understand: The dummy pubkey is derived using multisig.address_n
. Suppose we have two wallets. The first one uses a node HD1
and the other a node HD2
. Suppose we have a multisig address created from public keys HD1/0/0
and HD1/0/1
. Since the wallets use different paths to derive the dummy pubkey, they will generate different addresses. Consequently, if the first wallet creates a transaction with the multisig address as an output, the second wallet will create a valid witness with a probability of 1/2, because the parity of the tweaked dummy key is used in the witness. Is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But address_n
must be the same for the entire MultisigRedeemScriptType
, so how can the address be created by HD1/0/0
and HD1/0/1
? That would imply an address_n
of [0,0]
for the first key and [0,1]
for the second. Am I misunderstanding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under the impression that you could specify address_n
for each pubkey separately in multisig.pubkeys[*].address_n
.
return [multisig_get_pubkey(hd.node, hd.address_n) for hd in multisig.pubkeys] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see you can have pubkeys or nodes, and pubkeys have their own address_n individually. I haven't tested this with that. I suppose we can disable using pubkeys list for taproot multisig?
Is pubkeys list legacy or is it still widely used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I'm going to do a quick research to see what internal keys other wallets that support Taproot multisig use. If we want other wallets to be interoperable with trezor, we should follow the same approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it makes a difference in terms of security and privacy for the first 3 options.
Only the chain code and public key are used to derive the actual public key that will be used in the script though, so the last option would introduce malleability. For example, two xpubs where one lies about the depth would produce the same redeem script but would result in a different chaincode for the dummy xpub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I didn't realize but if using just the 33 bytes compressed public key like I have here it does make it compatible with Liana, if Liana has their xpubs sorted, no duplicates, and max depth of 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can proceed with a BIP and mailing list post if this is acceptable.
Thanks. Unless @onvej-sl has any objection to the proposed method, I encourage you to go ahead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no objections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience. I have created a BIP draft specifying this behavior. Once it gets assigned a number I can rebase this and hopefully we can see it merged 🤞
Compute a dummy xpub to use as the internal pubkey for taproot multisig. Sort and remove duplicates of all xpub pubkeys, concatenate and compute sha256 hash. The result is the chaincode, and the pubkey is the NUMS point.
11982dc
to
f6cb74d
Compare
Adds basic taproot multisig support.
Uses a single
OP_CHECKSIGADD
-based script at the root level. Uses the secp256k1 generator as the basis for an xpub that derives an unspendable internal pubkey.Resolves #1946