Skip to content

BIP445: FROST Signing Protocol for BIP340 Signatures - #2070

Open
siv2r wants to merge 15 commits into
bitcoin:masterfrom
siv2r:bip-frost-signing
Open

BIP445: FROST Signing Protocol for BIP340 Signatures#2070
siv2r wants to merge 15 commits into
bitcoin:masterfrom
siv2r:bip-frost-signing

Conversation

@siv2r

@siv2r siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor

This PR adds a BIP for the FROST (Flexible Round-Optimized Schnorr Threshold) signing protocol. The development repository is at https://github.com/siv2r/bip-frost-signing.

There already exists RFC 9591, which standardizes the two-round FROST signing protocol, but it is incompatible with Bitcoin's BIP340 X-only public keys. This BIP bridges that gap by providing a BIP340-compatible variant of FROST.

This BIP standardizes the FROST3 variant (Section 2.3 of the ROAST paper). This variant shares significant similarities with the MuSig2 signing protocol (BIP327). Accordingly, this BIP follows the core design principles of BIP327, and many sections have been directly adapted from it.

FROST key generation is out of scope for this BIP. There are sister BIPs such as ChillDKG and Trusted Dealer Generation that specify key generation mechanisms. This BIP must be used in conjunction with either of those for the full workflow from key generation to signature creation. Careful consideration has been taken to ensure the terminology in this BIP matches that of ChillDKG.

There are multiple (experimental) implementations of this specification:

  • The reference Python implementation included in this PR
  • secp256k1-zkp FROST module (yet to implement the test vectors)
  • FROST-BIP340 TODO: verify if this impl is compatible with our test vectors
  • secp256kfun (implements ChillDKG with FROST signing) TODO: verify if this impl is compatible with our test vectors

Disclosure: AI has been used to rephrase paragraphs for clarity, refactor certain sections of the reference code, and review pull requests made to the development repository.

Feedback is appreciated! Please comment on this pull request or open an issue at https://github.com/siv2r/bip-frost-signing for any feedback. Thank you!

cc @jonasnick @real-or-random @jesseposner

@siv2r

siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

I'll fix the typos check soon

@siv2r

siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

I can see that GitHub's file changes view shows only one file at a time due to the large number of changes. This is because the reference implementation includes dependencies and auxiliary materials:

  • The reference code uses secp256k1lab python library (vendored as a git subtree, ~20 files) for scalar and group arithmetic. I can remove this from the PR when the library is integrated into this repository (RFC: Integrate secp256k1lab v1.0.0 as subtree, use it for BIP-374 #1855).
  • Auxiliary files include docs/partialsig_forgery.md (which I can move to a gist if preferred) and a test vector generation script (~1400 lines). I can exclude these if necessary.

@murchandamus murchandamus changed the title Add BIP: FROST Signing for BIP340-compatible Threshold Signatures BIP Draft: FROST Signing Protocol for BIP340 Schnorr Signatures Jan 6, 2026

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is just a first glance, but I noticed a few issues:

Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
@murchandamus murchandamus changed the title BIP Draft: FROST Signing Protocol for BIP340 Schnorr Signatures BIP Draft: FROST Signing Protocol for BIP340 Signatures Jan 8, 2026

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the quick turn-around. It’s on my todo list to give this a more thorough look, but it might take a bit. If you can motivate some other reviewers meanwhile, that would also be welcome.

Comment thread bip-frost-signing.md Outdated
@siv2r

siv2r commented Jan 9, 2026

Copy link
Copy Markdown
Contributor Author

If you can motivate some other reviewers meanwhile, that would also be welcome.

I've shared it with most of the Bitcoin cryptographers I know and will post it on Twitter and the Bitcoin dev groups I'm part of. Hopefully that will bring in more reviewers!

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hi! Quite a remarkable job! We found a few minor issues, and correcting them would improve the overall specification of the BIP.

Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md
Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated

@Christewart Christewart left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
@siv2r

siv2r commented Jan 21, 2026

Copy link
Copy Markdown
Contributor Author

Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Yes, it's a .md issue, this bip initially had a manually written table of contents but was removed after #2070 (comment)

@murchandamus

Copy link
Copy Markdown
Member

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Click there. ;)

image

@Christewart

Copy link
Copy Markdown
Contributor

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Click there. ;)

Thank you! TIL :-)

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A few additional minor issues and questions.

Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md
Comment thread bip-0445.md Outdated
@siv2r

siv2r commented Jan 25, 2026

Copy link
Copy Markdown
Contributor Author

@DarkWindman thanks a lot for the review! I've addressed most of your review comments in a88f033.

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

From an editorial standpoint, it looks pretty good and like all the required sections are present. I have read the proposal only partially, and do not have the expertise to fully understand all aspects, so I cannot comment on the technical soundness and whether the Specification is complete and sufficient.

Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jan 27, 2026
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445/python/vectors/sign_verify_vectors.json Outdated
@murchandamus

murchandamus commented Jan 30, 2026

Copy link
Copy Markdown
Member

Let’s call this BIP 445. Please add an entry for your proposal in the README table, in the preamble update the BIP header to 445 and Assigned header to 2026-01-30, and update your documents file name as well as the auxiliary file directory.

@murchandamus murchandamus changed the title BIP Draft: FROST Signing Protocol for BIP340 Signatures BIP445: FROST Signing Protocol for BIP340 Signatures Jan 30, 2026
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445/python/vectors/det_sign_vectors.json Outdated
@siv2r

siv2r commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

I've added multiple (t, n) configs to the test vectors. They now run across 4 configs, (2,3), (1,3), (3,3), and (3,5), instead of the single (2,3) setup we had before. That takes the total from 68 to 250 cases. Here's the per-API breakdown:

API Before Now
nonce_gen 5 5
nonce_agg 5 5
sign_verify 25 93
tweak 9 44
det_sign 19 81
sig_agg 5 22
Total 68 250

nonce_gen and nonce_agg don't depend on (t, n), so they stay the same. The rest grew because they now cover all 4 configs.

I also re-read the BIP text and the reference spec and fixed a few inconsistencies.

As far as I can tell, this addresses all the open review comments. I think the BIP is good to merge once the other reviewers are happy with it.

@murchandamus

Copy link
Copy Markdown
Member

@siv2r: Okay cool, I resubscribed to the PR and have added it to my review queue.

@mllwchrry mllwchrry left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed the BIP once again. Everything looks great! Found only two inconsistencies.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
@siv2r

siv2r commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

The changelog is at 0.6.0, using the same semver-style scheme as BIP327.

BIP327 bumped to 1.0.0 when its number was assigned. I didn't follow that for 445 because it was still under active review with suggestions coming in, so tagging it 1.0.0 felt premature back then. It's now had a good stretch of review without any drastic changes suggested.

@murchandamus should this be bumped to 1.0.0 just before merge? And what's the usual convention for bips changelog versioning?

@murchandamus

murchandamus commented Jun 26, 2026

Copy link
Copy Markdown
Member

@siv2r: Version 1.0.0 is usually reserved for the stage of the BIP that is advanced to Complete. You can find more guidance on Changelog Section and Version Header in BIP3.

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I gave this another fast read. From an editorial perspective, this looks properly formatted and complete (when considering the footnotes and "Remarks on Security and Correctness" the stand-in for the Rationale section). I did not spend the time to fully understand the scheme and only skimmed the algorithm sections. I saw that there was a reference implementation included and that it had some tests. Given the many review comments, and extensive Changelog, it seems to have been read much more carefully by multiple other more qualified reviewers.

From an editorial perspective, I’d be happy to publish this whenever the author and reviewers indicate that the proposal is clear, comprehensive, and mature enough to do so.

Comment thread bip-0445.md Outdated
@murchandamus murchandamus removed the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jun 26, 2026
@murchandamus

Copy link
Copy Markdown
Member

@siv2r: It sounds like you think it’s ready for publication, some reviewers have indicated the same. Let’s merge this in a week (on or after July 6th) unless more things crop up. Or if you want it published before then, please let me know.

@siv2r

siv2r commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Let’s merge this in a week (on or after July 6th) unless more things crop up

Sounds good! I'll do one final review this week, and will update here if anything comes up. Else we can merge on July 6th.

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor nit; everything else looks good to me!

Comment thread bip-0445.md Outdated
@real-or-random

Copy link
Copy Markdown
Contributor

Sorry for being late with a comment of this kind, but I think this should somehow take into account the "plausible attack on adaptive security of threshold Schnorr signatures" by Elizabeth Crites and Alistair Stewart (paper, talk).

tl;dr of the paper:

  • The result of the attack (if possible, see caveats below) is that the attacker can forge a signature after compromising (and learning the secret shares of) fewer than t participants.
  • It is not clear if there is an attack. It's only plausible in the sense that the attacker needs to solve a new computational problem from which nobody currently knows whether it's hard or not. This is unlike, e.g., the discrete logarithm problem on elliptic curves which has been studied for a long time, so that there's reasonable belief that it's hard.
  • The attack requires the attacker to be adaptive, i.e., the attacker chooses whom to corrupt after seeing the results of key generation including the public shares. This is realistic; and I think users expect that the scheme remains secure if the attacker can do this.
  • The attack requires t and n to be large. For example, a 131-of-196 setup is supposed to be easier to break than simply computing the discrete logarithm of the threshold public key but a 86-of-128 setup won't be affected (see Table 1 in the paper). Concretely, the authors suggest that the attack would be beneficial if effort(n, t) < 128 whereas effort is defined as in this Python code for secp256k1.
    from math import comb, log2
    def effort(n: int, t: int) -> float:
        c = comb(n, t-1)
        return -log2(c / ((2**256) + c))

The big question, of course, is what to do. I think there are two reasonable options:

  1. Forbid affected parameters (n, t) entirely, and explain the rationale.
  2. Only add a warning.

I tend to think that option 1 is better. Of course, that's a restriction in practice, but we can't just move on and pretend that everything will be fine. If someone wants to ignore the restriction, they can still do this, but then they're on their own.

@murchandamus

Copy link
Copy Markdown
Member

Given these new review comments, I expect that we will not publish today. I’ll wait for your input, @siv2r.

@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jul 6, 2026
@real-or-random

Copy link
Copy Markdown
Contributor

After consulting with @elizabeth-crites, I have a clearer understanding now, and I should have mentioned also a second paper of her with Jonathan Katz, Chelsea Komlo, Stefano Tessaro, and Chenzhi Zhu (talk; immediately after the other talk in the same video).

In fact, the situation is better than I mentioned. It's not just that we don't know whether an attack exist.

The new paper defines a computational problem LDVR and proves that FROST is adaptively secure when LDVR is hard in addition to the discrete logarithm problem DL (or strictly speaking, its variant AOMDL). Then the paper proves that LDVR is – at least for parameters we're interested in (i.e., small enough n) – so hard that it's better for the attacker to attack DL instead.

Here's improved script that estimates the bit security (function effort) of an attack against LDVR. Here, t_c is the number of actually corrupted parties, i.e., the worst case is t_c = t.)

from math import log2, perm

BITS_GROUP_ORDER = 256

def myperm(n: int, k: int):
    if k >= 1:
        return perm(n, k)
    else:
        return 1

def table1(n: int, t: int, t_c: int | None = None):
    if t_c is None:
        t_c = t  # worst case
    return log2(myperm(n, 2 * t_c - t)/myperm(t_c, 2 * t_c - t))

# Check some numbers from Table 1 in https://eprint.iacr.org/2025/1061
assert table1(128,  96,  round(0.9 *  96)) -  79.24 <= 0.01
assert table1(256,  64,               64 ) - 203.57 <= 0.01
assert table1(1024, 512, round(0.6 * 512)) - 197.18 <= 0.01

def effort(n: int, t: int | None = None, t_c: int | None = None):
    if t is None:
        t = n // 2  # worst case
    return -(table1(n, t, t_c) - BITS_GROUP_ORDER)

DL has an (assumed) bit security of ~128, and to be on the safe side, we want that breaking LDVR is at least as hard, i.e., effort should return at least 128. So to determine safe parameters, the BIP could use rely on the effort function.

There's a cruder but much simpler restriction: As long as n <= 131, we'll always have effort >= 128. So a simple restriction (or recommendation) for the BIP could be simply to require n <= 131 (or maybe n <= 128 to be on the safe side and have a nicer looking number).

I'm pretty sure that 128 parties will be enough for all envisioned currently envisioned use cases of FROST.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
@murchandamus

Copy link
Copy Markdown
Member

@siv2r: Please let me know whether you want to go forward with the publication or are still making further updates. The recent review comments could also be addressed in a follow-up authored by another contributor.

@siv2r

siv2r commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

I'm working on fixing the recent review comments. Let's not publish until they're fixed.

Comment thread bip-0445/python/tests.py
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md
This signing protocol is compatible with any key generation protocol that produces valid FROST keys.
Valid keys satisfy: (1) each *secret share* is a Shamir share of the *threshold secret key*, and (2) each *public share* equals the scalar multiplication *secshare \* G*.
Before signing, the signers context must pass *ValidateSignersCtx*, which rejects duplicate identifiers and confirms the key material reproduces the threshold public key. The signing algorithms (*Sign*, *PartialSigVerify*, and *PartialSigAgg*) include this check for clarity, so an implementation can instead validate a context once and skip the repeated checks in later calls.
For comprehensive validation of the entire key material, *ValidateSignersCtx* can be run on all possible *u* signing participants.

@real-or-random real-or-random Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: Do you mean "on the full set of n participants (u = n)" here? Could be clarified.

edit: On a further look, this is much more sublte. Moved the discussion to the dev repo at siv2r/bip-frost-signing#43 (comment).

Comment thread bip-0445.md Outdated
- Let *tweak_ctx<sub>i</sub> = ApplyTweak(tweak_ctx<sub>i-1</sub>, tweak<sub>i</sub>, is_xonly_t<sub>i</sub>)*; fail if that fails
- Let *(Q, gacc, tacc) = tweak_ctx<sub>v</sub>*
- Let *ser_ids* = *SerializeIds(id<sub>1..u</sub>)*[^canonical-ids-det-sign]
- Let *b* = *scalar_from_bytes_wrapping(hash<sub>BIP0445/noncecoef</sub>(ser_ids || aggnonce || xbytes(Q) || m))*

@jonasnick jonasnick Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ser_ids and m are of arbitrary length and not length prefixed when input to the noncecoef hash function. Hence, it seems easy to find tuples (ids, m) != (ids', m') that result in the same hash b.

@real-or-random real-or-random Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, "nice" find. A simple fix is to let SerializeIds prefix its output with a serialization of u.

edit: Or, for consistency, make it similar to how the inputs to hashBIP0445/deterministic/nonce are serialized.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Found by ChatGPT 5.6 when trying to prove security of the scheme specified in the BIP.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
@real-or-random

real-or-random commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

I completed a full pass on the text. Nothing substantial and sorry again that my comments arrive that late in the process.

edit: Forgot to mention a "global" nit: The text uses "signer" and "participant" interchangeable. Sticking to one term would make things a tiny bit clearer (but this may be an annoying change to make at this stage).

@siv2r

siv2r commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Tysm for the detailed review.

edit: Forgot to mention a "global" nit: The text uses "signer" and "participant" interchangeable. Sticking to one term would make things a tiny bit clearer (but this may be an annoying change to make at this stage).

This was fixed in the development repo recently. "Participants" refers to anyone involved in key generation, and "signers" to those participating in the current signing session. Will pull in the latest changes once the other review comments are resolved.

Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445.md Outdated
- Inputs:
- The participant secret signing share *secshare*: a 32-byte array, serialized scalar (optional argument)
- The participant public share *pubshare*: a 33-byte array, compressed serialized point (optional argument)
- The x-only threshold public key *thresh_pk*: a 32-byte array, X-only serialized point (optional argument). When tweaks have been applied, this is ideally the tweaked threshold public key from *GetXonlyPubkey(tweak_ctx)*.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is in the list of inputs to NonceGen.

It was a bit confusing to me that here the algorithms expect an xonly threshold pubkey as input whereas the signers_ctx requires a plain pubkey. (In particular because they use the same identifier thresh_pk.)

As far as I understand, the goal is to take account the tweaks for defense-in-depth reason (which is a good idea and an improvement over BIP327!).

I see two possible improvements:

  • Make the wording and notation a bit clearer (see below for a possible wording).
  • Or, instead of taking the xonly key, take all tweaks (and is_xonly_t values) and hash them.
Suggested change
- The x-only threshold public key *thresh_pk*: a 32-byte array, X-only serialized point (optional argument). When tweaks have been applied, this is ideally the tweaked threshold public key from *GetXonlyPubkey(tweak_ctx)*.
- The x-only threshold public key *tweaked_xonly_thresh_pk*: a 32-byte array, X-only serialized point (optional argument). If tweaks are supposed to be applied during signing, this should ideally be the resulting xonly public key after applying all tweaks to the threshold public key, i.e., the output of *GetXonlyPubkey(tweak_ctx)*. If no tweaks are supposed to be applied, or if it is not yet determined at nonce generation stage whether or what tweaks will be applied, this may also be the last 32 bytes of the threshold public key.

@siv2r siv2r Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought about your second option, hashing all tweaks and is_xonly_t values. I believe it doesn't add any protection over hashing a single tweaked key, and the current x-only input is exactly as strong as both. So the choice is purely an API question. Here's my thinking:

All signing algorithms consume the tweak list only through the triple $(Q_v, gacc_v, tacc_v)$, which satisfies the invariant $Q_v = gacc_v \cdot Q_0 + tacc_v \cdot G$ with $gacc_v \in {1, -1}$. Concretely, $b$ and $e$ hash $xbytes(Q_v)$, Sign computes $d = g \cdot gacc \cdot d'$, PartialSigAgg adds $e \cdot g \cdot tacc$, and $g$ is determined by the parity of $Q_v$.

Let's consider two different tweak sequences applied to the same threshold key and analyze when they collide on the NonceGen hash. Assume $rand'$ is identical in both runs, since that's the failure mode the defense-in-depth targets. Note that since $gacc \in {1, -1}$, the two sequences either have the same $gacc$ or opposite ones, so there are only two cases per option.

Option 1: NonceGen hashes the plain tweaked key (PlainPk). A collision means the same $Q_v$.

  • Case 1 (same $gacc$): the invariant forces the same $tacc$, so both contexts produce byte-identical partial signatures. Deriving the same nonce for them is harmless.
  • Case 2 (opposite $gacc$): the invariant forces $tacc' = tacc + 2 \cdot gacc \cdot x_0$, where $x_0$ is the threshold secret key. Constructing such a pair requires knowing $x_0$, and honest BIP32/BIP341 hash-derived tweaks hit it with probability $\sim 2^{-256}$.

Option 2: NonceGen hashes the tweak and tweak mode lists (with count prefixing). Distinct sequences always get distinct nonces. The only pairs this separates beyond Option 1 are the benign ones from Case 1, so it adds no extra protection.

Option 3: NonceGen hashes the x-only tweaked key (XonlyPk, current spec). A collision means $Q_v' = \pm Q_v$, giving four cases.

  • Case 1 (same $gacc$, same $Q_v$): same as Option 1, Case 1.
  • Case 2 (same $gacc$, opposite $Q_v$): the invariant forces $tacc' = -tacc - 2 \cdot gacc \cdot x_0$, so it requires knowing $x_0$, same reasoning as Option 1, Case 2.
  • Case 3 (opposite $gacc$, same $Q_v$): the invariant forces $tacc' = tacc + 2 \cdot gacc \cdot x_0$, which is exactly Option 1, Case 2.
  • Case 4 (opposite $gacc$, opposite $Q_v$): the invariant forces $tacc' = -tacc$. Here $g$ flips together with the parity of $Q_v$, so $g \cdot gacc$ and $g \cdot tacc$ are unchanged, and both contexts produce byte-identical signatures for the same x-only key. Benign, like Case 1.

So all three options give equally good defense-in-depth. Given that, I'd prefer switching the argument from x-only to the plain, potentially tweaked key, i.e. the output of GetPlainPubkey(tweak_ctx). It matches the thresh_pk field in the Signers Context, matches what key generation outputs (ChillDKG returns a plain threshold pubkey), and lets the untweaked case pass thresh_pk through unchanged, which removes the confusion you pointed out. Plus the change is quite minimal compared to adding two new list params to NonceGen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New BIP PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants