Skip to content
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

FROST #138

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open

FROST #138

wants to merge 23 commits into from

Conversation

jesseposner
Copy link
Contributor

@jesseposner jesseposner commented Jul 21, 2021

This PR implements a BIP-340 compatible threshold signature system based on FROST (Flexible Round-Optimized Schnorr Threshold Signatures).

TODO

  • Key generation APIs
  • Nonce generation APIs
  • Signing APIs
  • Basic tests
  • Refactor APIs
  • Resolve merge conflicts
  • Get CI working
  • Sign list of VSS proofs from all participants to simulate broadcast channel
  • Verify shares with VSS
  • Update keygen protocol based on feedback from @LLFourn
  • refactor nonce and index handling
  • key tweaking (e.g. taproot and bip32)
  • adaptor support
  • Partial sig verification API
  • change indexes to x-only pubkeys
  • revert change to indexes
  • Public VSS Verify
  • Verification checks
  • Serialization APIs
  • Example file
  • API for generating public verification shares
  • Full tests
  • more detailed code comments, including references to RFC
  • Documentation file
  • Update API diagram [in-progress]
  • Update Python implementation [in-progress]
  • FROST BIP [in-progress]
  • Benchmarks and Stress Testing [in-progress]

FROST Paper

This PR is based upon the FROST paper by Chelsea Komlo and Ian Goldberg and the draft RFC.

Python Implementation [WIP]

https://github.com/jesseposner/FROST-BIP340

Prior Work

@apoelstra worked on a threshold implementation in #46 and this PR builds on the techniques introduced there.

This PR is patterned on the APIs, and in many instances duplicates code, from the MuSig implementation due to their similarities in nonce generation and signing.

@devos50
Copy link

devos50 commented Aug 20, 2021

@jesseposner Interesting work! I am currently thinking of a system where a large group of people would maintain ownership over a pool of funds, for example, within a single Bitcoin wallet. The FROST scheme looks like it could be a primitive in this scheme, especially if combined with an accountability protocol to detect/exclude malicious signers. Would this PR be ready for some preliminary experiments in a P2P setting?

@jesseposner
Copy link
Contributor Author

@devos50 The PR is currently in a very early state and isn't that useful yet, in particular, it doesn't yet have support for signing or generating nonces. However, I've made significant progress in my local branch and I will be pushing substantial changes to the PR by the end of the month that will have nonce generation and signing and should be sufficient for experimentation.

@devos50
Copy link

devos50 commented Aug 20, 2021

@jesseposner thanks for your response! I will wait for your changes then and try to build something around it later when the PR is more feature-complete 👍 (I'm going on holiday tomorrow so no need to rush).

@real-or-random
Copy link
Collaborator

Here's another BIP340 FROST implementation (in Go):
https://github.com/taurusgroup/multi-party-sig

I think it would be nice to have a chat with them.

@real-or-random
Copy link
Collaborator

By the way, there's a new paper about FROST that has a nice pseudocode in Figure 10: https://eprint.iacr.org/2021/1375.pdf

@real-or-random
Copy link
Collaborator

  • Describe modifications to the FROST protocol [in-progress]

Just curious, are there any significant changes to the protocol itself (ignoring implementation details -- of course the line is fuzzy)?

@jesseposner
Copy link
Contributor Author

jesseposner commented Jan 7, 2022

@real-or-random I'll have a full write-up ready very soon, but the general idea is that I'm using a method for combining MuSig and FROST that provides the following advantages: (1) MuSig keys can be converted to FROST keys without changing the aggregate public key, (2) a "broadcast channel" is implemented using MuSig to sign a hashed list of coefficient commitments, and (3) MuSig APIs are utilized (secp256k1_musig_pubkey_agg, secp256k1_musig_nonce_gen, secp256k1_musig_nonce_agg, secp256k1_musig_nonce_process, secp256k1_musig_partial_sig_agg) allowing for simpler code implementation and maintenance.

The FROST protocol is modified such that the first step is to generate a MuSig key. From there, the participants generate random polynomial coefficients, however, for their first coefficient the participants use their respective individual MuSig private key multiplied by the key aggregation coefficient. This results in the FROST and MuSig aggregate public key being the same, because the FROST aggregate public key is the sum of the commitments to each participant's first polynomial coefficient. This also means that the participants no longer need to distribute a proof of knowledge of their first coefficient, as specified by FROST, because the rogue key attack is prevented via MuSig and the key aggregation coefficients.

Then, when the participants distribute their shares and coefficient commitments, the FROST protocol is modified such that they also distribute a MuSig nonce commitment pair. When they have received coefficient commitments from all the other participants, they generate a hash of the list (i.e. the vss_hash), and sign it using MuSig. The partial MuSig signatures are aggregated, and a valid signature verifies that each participant has received the same commitments (thus simulating the broadcast channel, whose implementation is not specified in FROST). This completes key generation.

At that point, each participant has a FROST share that they can use for threshold signing, however, they use MuSig nonces (MuSig nonce generation and FROST nonce generation are nearly identical: in both cases the protocols use a pair of nonces and nonce commitments that are combined with a binding value).

The example file currently implements this method of key generation, nonce generation, and signing: https://github.com/ElementsProject/secp256k1-zkp/blob/36eba62b3b5450f0acde3459cf7600af2116bc32/examples/frost.c. If we want to use the more standard FROST protocol, the code changes required will be relatively modest (e.g. remove keyagg coefficient from share generation, add a proof of knowledge in share generation, create a secp256k1_frost_nonce_process function based on secp256k1_musig_nonce_process that uses a slightly different binding value and removes the keyagg coefficient when generating the challenge hash, derive aggregate public key in secp256k1_frost_share_agg.). It would also be possible to provide APIs for both protocols (standard FROST and hybrid FROST/MuSig).

@real-or-random
Copy link
Collaborator

I had a closer look at the modified KeyGen (the picture in the first comment) and here are few comments:

  • I'm not sure if it's actually an anti-feature that this is compatible to MuSig key aggregation. I think it's a good mind model to keep threshold and multisigs separate as much as possible because the setup is so different. Do we really want users to reuse their FROST pubkey shares as MuSig public keys? It's strictly less secure than having a separate key for MuSig because you gave others shares of the key. And I don't see where reuse will be helpful. I tend to believe that it is good to use a FROST key only for running FROST, with exactly the group of signers it was supposed to be used.
  • It's a very neat idea to use MuSig during KeyGen but isn't it dangerous right now without a security proof for the modified protocol? This is in particular true when we drop the proofs of knowledge. I'm not entirely sure that the MuSig2 signing can replace those. In any case it will require the AGM then to prove the protocol secure, whereas probably ROM+OMDL will be enough for a proof of the unmodified FROST.
  • I don't think that MuSig can replace a broadcast channel. To be more specific, it may be able to replace a reliable broadcast channel but not a terminating broadcast channel. That is, the current KeyGen protocol still needs broadcast: If you terminates with an aggregate pubkey, you don't know if the others terminated or not. So you can't go ahead and use the pubkey (e.g., send money to it). For example, if everyone else has aborted, it's impossible to sign for that pubkey. This can be mitigated by a third round in which everyone confirms that the first two rounds were correct. If you receive a third-round confirmation from everybody, then you know that signing is possible and you can return the aggregate pubkey to the caller. (This still does not mean that everyone else will have received valid third-round confirmations... So others may be in some uncertain state but that's okayish if they don't timeout and delete their secrets. Signing will be possible, it's just that not everyone knows that it will be possible. To be really sure, you need terminating reliable broadcast, which is almost as strong as consensus.)
  • Have you considered using hashes of the pubkey shares as identities for Lagrange coefficients (instead of 1, 2, 3, ...). This may be nicer in practice because then you don't need to bother with an ordering of the pubkeys. (I learned this trick from https://blog.trailofbits.com/2021/12/21/disclosing-shamirs-secret-sharing-vulnerabilities-and-announcing-zkdocs/ which explains how to use it properly. Hashing is certainly safe.)
  • nit: It shouldn't be necessary to verify the partial sigs and the final sig.

@jesseposner
Copy link
Contributor Author

@real-or-random Thank you for the comments!

I'm not sure if it's actually an anti-feature that this is compatible to MuSig key aggregation. I think it's a good mind model to keep threshold and multisigs separate as much as possible because the setup is so different. Do we really want users to reuse their FROST pubkey shares as MuSig public keys? It's strictly less secure than having a separate key for MuSig because you gave others shares of the key. And I don't see where reuse will be helpful. I tend to believe that it is good to use a FROST key only for running FROST, with exactly the group of signers it was supposed to be used.

Reuse is potentially helpful if you have funds secured with a MuSig setup and later decide you'd like to convert to a threshold setup without needing to move the funds. In practice I'm not sure how useful or desirable this actually is and I'm open to the idea that the security downsides outweigh the benefits. Even if that's the case, we can still use MuSig for the broadcast channel (assuming we want to do that), and change the API such that it doesn't allow for converting a pre-existing MuSig key.

It's a very neat idea to use MuSig during KeyGen but isn't it dangerous right now without a security proof for the modified protocol? This is in particular true when we drop the proofs of knowledge. I'm not entirely sure that the MuSig2 signing can replace those. In any case it will require the AGM then to prove the protocol secure, whereas probably ROM+OMDL will be enough for a proof of the unmodified FROST.

I agree that we need a security proof for the modified protocol if we think that's worth pursuing. However, the MuSig partial signatures are also proofs of knowledge, so I think the modified protocol still provides that.

I don't think that MuSig can replace a broadcast channel. To be more specific, it may be able to replace a reliable broadcast channel but not a terminating broadcast channel. That is, the current KeyGen protocol still needs broadcast: If you terminates with an aggregate pubkey, you don't know if the others terminated or not. So you can't go ahead and use the pubkey (e.g., send money to it). For example, if everyone else has aborted, it's impossible to sign for that pubkey. This can be mitigated by a third round in which everyone confirms that the first two rounds were correct. If you receive a third-round confirmation from everybody, then you know that signing is possible and you can return the aggregate pubkey to the caller. (This still does not mean that everyone else will have received valid third-round confirmations... So others may be in some uncertain state but that's okayish if they don't timeout and delete their secrets. Signing will be possible, it's just that not everyone knows that it will be possible. To be really sure, you need terminating reliable broadcast, which is almost as strong as consensus.)

The MuSig partial signatures are not generated until every participant has received their shares, verified their shares, and aggregated their shares. So when a participant receives partial signatures from every other participant, they know that each participant has the shares required to sign for the aggregate public key assuming that all participants verified their shares against the same commitments. This final assumption is validated when the partial signatures are aggregated and the aggregate is verified as a valid signature. So at that point, I believe the participants are left in that same final state you described at the end, where they are potentially uncertain (because they don't know if the other participants were able to verify the aggregate signature), however signing will be possible assuming they don't timeout and delete.

Have you considered using hashes of the pubkey shares as identities for Lagrange coefficients (instead of 1, 2, 3, ...). This may be nicer in practice because then you don't need to bother with an ordering of the pubkeys. (I learned this trick from https://blog.trailofbits.com/2021/12/21/disclosing-shamirs-secret-sharing-vulnerabilities-and-announcing-zkdocs/ which explains how to use it properly. Hashing is certainly safe.)

That looks very useful, thanks for the suggestion!

nit: It shouldn't be necessary to verify the partial sigs and the final sig.

Great point!

@real-or-random
Copy link
Collaborator

I'm not sure if it's actually an anti-feature that this is compatible to MuSig key aggregation. I think it's a good mind model to keep threshold and multisigs separate as much as possible because the setup is so different. Do we really want users to reuse their FROST pubkey shares as MuSig public keys? It's strictly less secure than having a separate key for MuSig because you gave others shares of the key. And I don't see where reuse will be helpful. I tend to believe that it is good to use a FROST key only for running FROST, with exactly the group of signers it was supposed to be used.

Reuse is potentially helpful if you have funds secured with a MuSig setup and later decide you'd like to convert to a threshold setup without needing to move the funds. In practice I'm not sure how useful or desirable this actually is and I'm open to the idea that the security downsides outweigh the benefits. Even if that's the case, we can still use MuSig for the broadcast channel (assuming we want to do that), and change the API such that it doesn't allow for converting a pre-existing MuSig key.

Hm yes, I tend to believe that converting from a MuSig pubkey to a FROST pubkey is rare enough that it doesn't matter to change the pubkey.

It's a very neat idea to use MuSig during KeyGen but isn't it dangerous right now without a security proof for the modified protocol? This is in particular true when we drop the proofs of knowledge. I'm not entirely sure that the MuSig2 signing can replace those. In any case it will require the AGM then to prove the protocol secure, whereas probably ROM+OMDL will be enough for a proof of the unmodified FROST.

I agree that we need a security proof for the modified protocol if we think that's worth pursuing. However, the MuSig partial signatures are also proofs of knowledge, so I think the modified protocol still provides that.

The partial sigs is one part where I'm not sure. A single partial sig is not a proof of knowledge because the hashed nonce is not the partial nonce of the participant. A maybe surprising property is that partial sigs during a MuSig2 run can be forged -- just not all partial signatures of one run because this would imply a real forgery. Now in this case we get all partial sigs (and a full sig) but one would need to see if this really means that all keys can be extracted. I never thought about this to be honest.

I don't think that MuSig can replace a broadcast channel. To be more specific, it may be able to replace a reliable broadcast channel but not a terminating broadcast channel. That is, the current KeyGen protocol still needs broadcast: If you terminates with an aggregate pubkey, you don't know if the others terminated or not. So you can't go ahead and use the pubkey (e.g., send money to it). For example, if everyone else has aborted, it's impossible to sign for that pubkey. This can be mitigated by a third round in which everyone confirms that the first two rounds were correct. If you receive a third-round confirmation from everybody, then you know that signing is possible and you can return the aggregate pubkey to the caller. (This still does not mean that everyone else will have received valid third-round confirmations... So others may be in some uncertain state but that's okayish if they don't timeout and delete their secrets. Signing will be possible, it's just that not everyone knows that it will be possible. To be really sure, you need terminating reliable broadcast, which is almost as strong as consensus.)

The MuSig partial signatures are not generated until every participant has received their shares, verified their shares, and aggregated their shares. So when a participant receives partial signatures from every other participant, they know that each participant has the shares required to sign for the aggregate public key assuming that all participants verified their shares against the same commitments. This final assumption is validated when the partial signatures are aggregated and the aggregate is verified as a valid signature. So at that point, I believe the participants are left in that same final state you described at the end, where they are potentially uncertain (because they don't know if the other participants were able to verify the aggregate signature), however signing will be possible assuming they don't timeout and delete.

Ok yes, I think you're right.

examples/frost.c Outdated
if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, THRESHOLD)) {
return 0;
}
if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, &cache, NULL)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The combination of using MuSig2-style nonce aggregation and reusing MuSig2's way of computing the coefficient for the nonce ("b" in the notation of MuSig2 paper) seems to make this vulnerable to Wagner/BLLOR-style attacks (see MuSig2 paper) if the attacker can choose the set of t participants after seeing an honest signer's nonce pair. Letting the attacker choose the set of participants will give the attacker some control over the Lagrange coefficient, which has a similar effect as giving the attacker control over the Fiat-Shamir challenge, because the two values are simply multiplied to each other.. I say "similar" because the Lagrange coefficient is structured and not random but I don't except that this makes an attack significantly harder or easier.

The fix is to include the set of participants in the derivation of b.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, that's a great point. This is fixed in changes I will be pushing shortly that make nonce generation conform to the latest FROST spec (https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/).

@synctext
Copy link

synctext commented May 13, 2022

Awsome work @jesseposner, thank you. Do you consider stress testing your code with 10M users?
btw Proof-of-concept of your FROST efforts now operational on Android. Delft University students took your code and used it towards building a fully decentralised Taproot-based DAO, based on joint ownership of Bitcoin funds which can be spent by participating in a k-out-of-n Schnorr signature. Specifically, its expanded for distributed usage with our "Trustchain ledger" for potentially numerous signatures from Android users. interesting?

@jesseposner
Copy link
Contributor Author

Thanks @synctext! I'm excited to see that your students were able to leverage this code for their project, I will check it out. Please be careful, the code is still early and has not yet been reviewed and should not be considered secure software.

Great suggestion regarding the stress testing, I will add it to the to-do list.

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

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

@jesseposner I had a shallow look at your PR. In particular, I like the implementation of the vss_hashes because it allows to see when key generation has worked. Ideally, we would also be able to assign blame if the vss_hashes are not identical and then resolve the issue through some other process.

As far as I can see, there are no proofs of knowledge involved in key aggregation and, instead, MuSig-aggregation is assumed make PoKs unnecessary. I think this would require a security proof/argument.

Agree with @real-or-random that we should try to get rid of signer indices entirely if possible.

I pushed a branch with a few fixup! commits and CI integration. Feel free to cherry-pick: https://github.com/jonasnick/secp256k1-zkp/commits/frost-jn.

include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
examples/frost.c Outdated Show resolved Hide resolved
@jesseposner
Copy link
Contributor Author

jesseposner commented May 17, 2022

Thanks for the comments @jonasnick!

As far as I can see, there are no proofs of knowledge involved in key aggregation and, instead, MuSig-aggregation is assumed make PoKs unnecessary. I think this would require a security proof/argument.

The vss_hash signatures are also PoKs. Instead of distributing PoKs in the first round, we distribute them in the second round, and instead of simply using the index and a context string as the message for the signature that serves as the PoK, we use the vss_hash as the message.

By moving the PoK to the second round and including the vss_hash in the PoK, we fulfill the broadcast channel requirement with the same set of signatures used for the PoK (otherwise we would need an additional set of signatures to fulfill the broadcast channel requirement). As you observed, we already have secure channels between the participants, so we could distribute the vss_hash separately. However, by using the PoKs, that step becomes unnecessary, so it's a little more efficient.

Agree with @real-or-random that we should try to get rid of signer indices entirely if possible.

Great point, I added this to the to-do list.

I pushed a branch with a few fixup! commits and CI integration. Feel free to cherry-pick: https://github.com/jonasnick/secp256k1-zkp/commits/frost-jn.

Thanks, will do!

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

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

Ah, clever idea to use this signature as the PoK. I pushed two more commits to my branch. Feel free to cherry-pick if you agree that they're useful.

I think one open todo that may be useful to keep in the OP is:

  • decide on whether to use MuSig key aggregation

Btw, I mentioned earlier that

Ideally, we would also be able to assign blame if the vss_hashes are not identical and then resolve the issue through some other process.

It seems like this API is already close (requires share_agg(...) to indicate which share failed to verify) to providing the possibility to do something like this.

  1. When distributing shares, signers sign vss_commitment and share, and send the signature to the along with the vss_commitment.
  2. The receiving signer does vss verification of the share. If it fails, the share, the vss_commitment and the signature can be used to complain. Perhaps it makes sense to make the vss_verify function in my branch public because it would allow a third party with minimal information about the key generation session to verify the complaint.
  3. If the vss_hash turns out to not be identical, every signer submits all received vss_commitments and their signatures to the complaint handler, which should be sufficient to identify disruptive signers.

One problem is that there's no agreed-upon session identifer that is covered by the signature, so signatures are transferrable between sessions. A malicious signer could send a received vss_commitment and signature from a different session to the complaint handler to blame an innocent signer that was present in two keygen sessions.

src/modules/frost/main_impl.h Outdated Show resolved Hide resolved
@jesseposner
Copy link
Contributor Author

@jonasnick

I think one open todo that may be useful to keep in the OP is:

  • decide on whether to use MuSig key aggregation

done

One problem is that there's no agreed-upon session identifer that is covered by the signature, so signatures are transferrable between sessions. A malicious signer could send a received vss_commitment and signature from a different session to the complaint handler to blame an innocent signer that was present in two keygen sessions.

Here's an idea for how we might incorporate a session ID by building on what you described:

  1. Each signer generates a random session ID for the DKG session. When distributing shares, signers sign the (1) VSS commitment, (2) share, (3) index, and (4) session ID. This signature could serve as the PoK. If it's not serving as the PoK, then it can just be a hash, and we presume that the hash is signed by the secure channel between the signers when it is sent.
  2. Upon share verification failure, the signer submits the signature and its inputs to the complaint handler. I agree, we should have a verification API that a third party handler can use for this purpose.
  3. Instead of signing the vss_hash by itself, the vss_hash is signed along with the session ID. Also, we might not need to double hash here: the signature inputs could just be the inputs to the vss_hash rather than the hash. If this signature isn't serving as the PoK, then we can use a hash instead of a signature and presume the hash is signed via the secure channel.
  4. If a signer receives an unexpected VSS set from another signer, all signers submit all the signatures they received from step 1 and from step 3 to the complaint handler, along with the inputs to those signatures. The session IDs prevent data from another session being used to blame an innocent signer.

@jonasnick
Copy link
Contributor

Regarding the issue of identifying dishonest signers in the key generation phase, @real-or-random rightfully points out that transcript + signatures only helps if the signers already agree on the individual public keys. If there's disagreement, the signature is worthless. Establishing agreement is difficult. I'm not sure how much sense it makes in practice to simply assume that there is already agreement on the public keys.

@jesseposner
Copy link
Contributor Author

@jonasnick Perhaps we can use the key pair provided to secp256k1_frost_share_gen when keygen is initialized as an authentication foundation. We require the participants to agree upon individual public keys before beginning the protocol, and they provide their respective key pairs to secp256k1_frost_share_gen. The participants can use this key for signing various commitments during keygen, and we require explicit signatures instead of implied secure channels in all cases, and the third party handler would also be familiar with these keys as part of the public key agreement phase.

@jesseposner jesseposner force-pushed the frost branch 2 times, most recently from 54120ad to 28fa632 Compare May 28, 2022 04:22
include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
include/secp256k1_frost.h Outdated Show resolved Hide resolved
Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

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

@jesseposner

The session IDs prevent data from another session being used to blame an innocent signer.

Let me try to expand on the argument: If malicious signer A complains that innocent signer B sent a bad vss_comm that resulted in A having the wrong vss_hash, A must provide sig_B(vss_comm, share, ID) as well as sig_B(vss_hash, ID). If these signatures are from a different session, then the vss_hash differs and therefore B can prove its innocence by showing that it computed the vss_hash correctly. As an aside, the vss_hash may be the same across sessions because they are derived deterministically from the inputs to keygen.

Cool idea. But it's really hard to convince yourself that it works in any case and risks inventing complicated machinery that turns out to be broken. I think this needs more formal treatment. In any case, blaming - even with your idea - does not seem to require API changes. Blaming seems to be something that we can focus on later.

This commits add BIP-341 ("Taproot") and BIP-32 ("ordinary") public key
tweaking.
This commit adds nonce aggregation, as well as adaptor signatures.
This commit adds signature generation and aggregation, as well as
partial signature serialization and parsing.
This commit adds an example file to demonstrate how to use the module.
Add api tests, nonce tests, tweak tests, sha256 tag tests, and constant
time tests.
This commit adds a documentation file with detailed instructions for how
to use the module properly.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_get(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_gen(
const secp256k1_context *ctx,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: frost_pubkey_gen -> frost_keygen_cache_init?
The BIP calls it KeygenCtxInit

Copy link
Contributor

Choose a reason for hiding this comment

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

I changed my mind. Libsecp APIs don't seem to use this init style. I'll have the BIP call it KeygenCtx instead.

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.

10 participants