-
Notifications
You must be signed in to change notification settings - Fork 66
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
Add frost-secp256k1-tr crate (BIP340/BIP341) [moved] #730
Conversation
|
This PR clearly needs to be resynced with |
As noted by @jesseposner during the round table, the raw DKG output is not safe to use in a BIP341 context. I'm going to update this PR to reflect that, which might entail some API changes. |
I had the impression that this PR would adjust the sign of the X coordinate during signing? That would solve the issue. (I ask this because I remember the first thing I wanted to do in this PR was to make that during key generation only, but that's not possible by @jesseposner's point) |
There's a negation algorithm in the FROST signing BIP: https://github.com/siv2r/bip-frost-signing It gets a little tricky to account for both BIP32 tweaks and taproot script tweaks (TapTweaks), which is why the algorithm is a bit complex. The algorithm is implemented here: BlockstreamResearch/secp256k1-zkp#278 It's also the same algorithm used in the MuSig2 BIP and implementation. |
@conradoplg Yes, this PR does handle key negation properly at signing time (i haven't read Jesse's linked negation algorithm yet), but how would key negation at signing time prevent a cosigner from injecting a malicious tweak into the group key at DKG time? Maybe it'd help to actually write out the steps the attacker will do, so we're sure we're all talking about the same thing. Let's say we run a DKG to construct a simple 2-of-2 FROST group key. Honest participant A malicious participant
The resulting group pubkey accepted by the group will be: The DKG will succeed because the malicious participant does actually know the coefficients of their secret contribution polynomial and can produce a valid proof of possession. The only drawback of this attack is that it depends on the attacker waiting to hear everyone else's DKG commitments first, in order to compute the rogue tweak. And naturally it doesn't work if the group intends to use BIP32 or BIP341 tweaks after DKG, but if the group uses the raw DKG output pubkey |
@conduition Perhaps a simple solution is to tweak the DKG output in a way similar to BIP32? It could be as simple as tweaking by the group public key hash? Then the private shares, public shares and group key provided by the library can include this tweak with no API changes needed. |
@MatthewLM Great idea. It's simple and elegantly prevents the footgun, without limiting how participants use their group key. The group can still add further tweaks (e.g. BIP341, BIP32, etc) at signing time too. I spent last night trying to break it, but couldn't see anything wrong. @jesseposner @conradoplg What do you guys think? |
I'm starting the process of resyncing this PR with the upstream v2.0.0 changes on |
This sounds like what @real-or-random suggested here: BlockstreamResearch/bip-frost-dkg#41 (comment)
|
BIP341 suggests this tweak specifically: |
Isn't the key already tweaked at sign-time anyway? Looking at my own code, I've used an earlier version of this branch and I see that a TapTweak is already done. I was previously able to create successful Taproot signatures with key-spend tweaks. I'm not sure any changes are needed. I guess the fear is that the public key might be used outside the library without BIP341 compliance? In that case, pre-tweaking the DKG output might increase safety. |
Resyncing is done but not yet pushed to this branch. You can preview the changes here: main...conduition:frost:add-secp256k1-tr-reloaded @conradoplg Do you have any preference for how i merge the updates into this branch? If it's not important, i'll just force-push the new commit history over this PR. I tagged @mimoo and zebra-lucky as co-contributors in the commit messages but i'm not sure how else to properly attribute.
@MatthewLM Not always. The current code will, by default, sign without any tweak. The untweaked group pubkey which those signatures would verify under is susceptible to rogue tweak attacks at DKG-time. I think a static unspendable tweak of the group key at DKG time is the ideal scenario here, as this ensures that no sane caller will ever accidentally pay money to a group pubkey which could contain a rogue tweak. I'll see about adding this soon after merging the re-synced branch into this one. I'll try to follow the suggestion of BIP341 (using |
Just to formalize this 'tweak the DKG output' idea a little... Every FROST participant receives three things from the DKG:
To prevent malicious tweaks (inserted into some
The participants can do this implicitly after DKG, without any extra communication rounds. The shares are still valid and the resulting group key |
It doesn't matter, PRs are squashed in this repo anyway. GitHub will include the contributors in the commit message when it merges. Let me know if you need help solving conflicts. |
This commit contains changes to the frost-core crate which allow ciphersuites to better customize how signatures are computed. This will enable taproot support without requiring major changes to existing frost ciphersuites. Co-authored by @zebra-lucky and @mimoo This work sponsored by dlcbtc.com and lightspark.com
Co-authored by @zebra-lucky and @mimoo This work sponsored by dlcbtc.com and lightspark.com
Co-authored by @zebra-lucky and @mimoo This work sponsored by dlcbtc.com and lightspark.com
5807cb4
to
11f43eb
Compare
I've resynchronized this branch with upstream |
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.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #730 +/- ##
==========================================
+ Coverage 82.18% 83.44% +1.26%
==========================================
Files 31 37 +6
Lines 3188 4071 +883
==========================================
+ Hits 2620 3397 +777
- Misses 568 674 +106 ☔ View full report in Codecov by Sentry. |
Just FYI I'm actively reviewing this. It looks good, but I think it might be possible to simplify some of the code so I'm working on that. |
I pushed a cleanup of the code. My main motivation was to minimize changes to I change the approach of the additional One aspect which I'm not sure about is tweak handling. In my commit I reverted the This means that, with my changes, tweak handling is not longer "transparent". You will need to call e.g. There is also some stuff missing:
I apologize for changing everything so much, but I feel like this approach has some advantages and makes everything a bit easier to reason about. I really appreciate all the effort that went into this. You can look at the individual commit to see the changes from the original approach, and the overall PR diff to see differences with Looking forward to your feedback. |
Thanks @conradoplg, I'll try to take a look at these changes soon. |
Thinking about it I don't think we can get away with not using even-Y for DKG proof-of-knowledge since the signature serialization only encodes X and the PoK is represented as a |
Ah nevermind. I am using even-Y for the R component of the signature. It's just the DKG |
Uses r = e99ae2676eab512a3572c7b7655d633642a717250af57a7e0ccd5f9618b69f3f
@conradoplg Tests are passing for me on this branch 🎉 Now that we've got that sorted out, i'm going to do the pruning i suggested here to hopefully reduce code surface area. Fingers crossed it works. Might take a few days but i'll check in again soon 🙂 |
@conradoplg yes happy to run the testsuite again. I added a test to cover the taptweak case. In this test, we spend using the FROST key through the default key spend path, while also including optional tapleaf script paths. All tests are passing against the latest commit (f9237f5) |
With a couple of small adjustments to the code, we can remove the need for this extra associated type on the Ciphersuite crate. Accepting signature with odd-parity nonce values is OK, because BIP340 discard the nonce parity bit anyway.
Thanks, it looks great. I'll sort out the conflicts next. |
…add-secp256k1-tr
…tation Thanks to @conradoplg for spotting this. The internal key is supposed to be represented as an even-parity point when adding the TapTweak point t*G. I added a regression test to ensure the tweaked verifying key and its parity match the BIP341 spec.
Everything looks great, thank you all for the contributions. I'll merge this soon unless someone wants to add anything? |
Thank you very much @conradoplg ❤️ |
Hi, sorry for being late to the party. I'm just curious: Is there any specific reason why someone in the Zcash ecosystem would need this (e.g., swaps with Bitcoin)? Or are you "just" making this available to the world because you feel it's useful that there is a Rust implementation for experimentation and given that Bitcoin is widespread? In either case, it's nice to see a second independent implementation! :) |
@real-or-random Hi Tim! I chose this repo because the ZF FROST implementation is well-audited, reputable and well-documented already. Better to build on solid foundations battle-tested by others, than attempt to reimplement it from scratch myself. Instead I only had to implement a taproot compatibility layer here, which is much lower surface area than FROST itself. My hope is that with further auditing/review/improvement, this implementation could become the go-to FROST implementation in pure Rust that downstream Bitcoin multisig wallets can pull in. Someday, FROST will land in libsecp256k1-zkp and will then be pulled into the As for zcash uses, I'm not a zcash user myself, so I can't speak to utility in that domain. However, this is certainly useful for Nostr, Cashu, and any other spec where secp256k1 signatures must comply with BIP340. I'm curious what people will build there... |
Our original rationale is that BIP-340 is probably the biggest application of FROST and it made sense to support that; this repo was never meant to be Zcash-specific (the Zcash ciphersuites are not even here, but in https://github.com/ZcashFoundation/reddsa/ , though I'm thinking of moving them here too...). But now it does have an application for Zcash; the upcoming Zcash Shielded Assets will use BIP-340 signatures for issuance, and that's also a great use case for FROST. |
This PR is a re-opening of #584 to resolve PR ownership problems. I'm opening this so zebra-lucky (who is short on time) doesn't need to be the middle-man merging my commits into their PR anymore.
This PR adds a new ciphersuite crate
frost-secp256k1-tr
, which complies with BIP340 Schnorr Signatures on Bitcoin and is compatible with BIP341 tweaks. This crate can be used to produce valid signatures on Bitcoin transactions.We handle the complex x-only negation conditions of BIP340 by introducing new methods on the
Ciphersuite
trait, which are generally identity functions in the case of other ciphersuites, but which in the taproot suite will conditionally negate certain values at critical times to maintain compatibility with BIP340's x-only public keys. These methods are usually denotedC::effective_xyz(...)
.To support BIP341 taptree tweaking, we add two new types,
SigningTarget
andSigningParameters
, and modify the signature package to accept any type that transformsInto
SigningTarget
. For backwards compatibility, this includes any type which implementsAsRef<[u8]>
. These convert intoSigningTarget
paired withSigningParameters::default()
. TheSigningParameters
can be modified to commit signatures to a specific tapscript merkle root tweak, allowing FROST groups to modify (tweak) their group keys with taproot script-spending paths, while retaining the use of the key-spending path.Some additional features we can consider adding:
i have a separate feature branch,
taproot-bip32
, based off of this branch which adds BIP32 support to thefrost-secp256k1-tr
crate. See this discussion for more background. It would be nice to be able to PR that branch into this repo as well, so that FROST keys can be used in hierarchical and descriptor wallets. For now I am leaving that separate to reduce conflation of features, but they can be merged together if desired.