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
Musig2: add new MuSig2 RPC methods to signrpc
#6361
Conversation
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.
The final component!
Completed an early initial pass focusing mainly on the protocol and client flow, which matches up pretty closely with what I had in mind.
lnrpc/signrpc/signer.proto
Outdated
Indicates whether all nonces required to start the signing process are known | ||
now. | ||
*/ | ||
bool have_all_nonces = 4; |
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.
Won't this always be false the first time a session is created?
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.
We can send a set of already known nonces. So for the last signer, we might already have all other nonces and therefore it can be true.
lnrpc/signrpc/signer.proto
Outdated
of 66 bytes. Can be split into the two 33-byte points to get the individual | ||
nonces. | ||
*/ | ||
bytes local_public_nonces = 3; |
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.
FWIW this is only actually needed for incremental verification, but maybe it's also useful on the caller side of things?
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.
We need to communicate the nonce to the other party, so we need to know it at some point, don't we? Or how would the nonce exchange work?
lnrpc/signrpc/signer_server.go
Outdated
// MuSig2SessionIDSize is the size of a MuSig2 session ID. It is the | ||
// length of the combined public key and the two public nonces, all of | ||
// them being compressed points. | ||
MuSig2SessionIDSize = 99 |
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.
Ah I see this sort of combines the notions of the session+context into one. If we wanted to get away with a smaller value there, then we can just hash these items and use a single 32 byte value here.
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.
Good idea with the hashing, added that.
49d2ebb
to
096feff
Compare
What needs to be done to take this out of the draft stage? Merging of the upstream btcd PR? |
Mostly adding the MuSig2 methods to the signer interface so they can also be forwarded to the remote signer. And cleaning up some user input validation TODOs. So not a big diff, working on it today. |
9ba253e
to
892d343
Compare
Took the PR out of draft state. Everything works now, including remote signing! While working on remote signing support for MuSig2 I noticed that the standalone Taproot functionality does not work in remote mode. Turns out we need #6268 to enable that. |
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.
The only thing remaining is to make the linter happy and fix the mobile build.
Other than those it's a super clean PR, really enjoyed reviewing! Awesome addition to LND 🚀 Great work @guggero 🥇
@Roasbeef: review reminder |
I added a convenience RPC called I also went ahead and added a short doc explaining the current MuSig2 implementation and examples. |
e42fc02
to
d254573
Compare
I updated to the latest version of btcsuite/btcd#1820 and added an itest for using a MuSig2 combined key in a tap leaf with a simple I also found a small bug in the helper function |
The btcd PR has been merged, so this can be rebased! |
Yes in this case, the verifier just takes the leaf, computes one level of tapLeaf hashing and uses that directly. You can see this interaction here if you pretend the loop below doesn't actually exist: https://github.com/btcsuite/btcd/blob/master/txscript/taproot.go#L155-L177 |
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.
LGTM 🌂
require ( | ||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect | ||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect | ||
github.com/aead/siphash v1.0.1 // indirect |
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.
None of this goes away with a go mod tidy
run w/ Go 1.18?
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.
No, unfortunately not. Go 1.17/1.18 just puts all the indirect dependencies in their own block.
input/musig2.go
Outdated
|
||
// MuSig2SessionID is a type for a session ID that is just a hash of the MuSig2 | ||
// combined key and the local public nonces. | ||
type MuSig2SessionID = [sha256.Size]byte |
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.
FWIW this is actually a type alias (the =
) sign, but not sure it actually needs to be?
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.
Re the derivation of this: doesn't need to be accounted for yet, but w/ the new mode that lets you generate the nonce before the rest of the keys are known, we may just need to have this be derived using just our local key and the nonce info.
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.
Ah, good point. I thought the alias would make it easier to convert between the type and the hash returned by the sha256
package. But I don't think that's really required.
About your second comment: I'll address that in a follow-up PR. Would like to get this PR in as is to unblock some work down the dependency tree.
// already known, they can be submitted as well to reduce the number of | ||
// method calls necessary later on. | ||
MuSig2CreateSession(keychain.KeyLocator, []*btcec.PublicKey, | ||
*MuSig2Tweaks, [][musig2.PubNonceSize]byte) (*MuSig2SessionInfo, |
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.
Hmm so we don't make the distinction between the context vs the session here? Is the param of the set of nonce optional? Looking at just this function signature, I would think no...
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.
Looking at it again, maybe unifying things just makes the API simpler: users call into this once they have all the pubkey and nonce info.
Or is the passed nonce here actually our local nonce? Need to get further in the diff.
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.
No, we don't make the distinction because with the previous design of the API we needed the session to get our local nonce so we could give it to the other parties.
The list of other party public nonces is not optional as in dynamic argument list. But you can pass in nil
if you're the first to create a session and don't know any nonces of other participants yet.
I'll see how this looks once I've incorporated the recent API changes in the context/session. I hope I can add that functionality with minimal changes to the RPC API surface.
The new |
With this commit we add the high-level MuSig2 signing methods to the btcwallet which will later be exposed through an RPC interface.
The inclusion proof field in the TapscriptPartialReveal function was incorrect. An inclusion proof can be zero or more elements of 32-byte slices. So an empty inclusion proof can be valid too for a tree that only consists of a single leaf.
Depends on btcsuite/btcd#1820.
Adds a new MuSig2 API for cooperatively producing Schnorr signatures that can be used either for Taproot internal keys or for
OP_CHECKSIG
signatures within a tap script tree.