Skip to content

Commit 5d87f56

Browse files
committed
bip-frost-signing: add info about OP_CHECKSIGADD and minor edits
1 parent 6ea53f2 commit 5d87f56

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

bip-frost-signing.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ The accompanying source code is licensed under the [MIT license](https://opensou
2222

2323
## Motivation
2424

25-
<!-- REVIEW: Should we add a paragraph about `OP_CHECKSIGADD` like BIP327 does? -->
25+
The FROST signature scheme enables threshold Schnorr signatures. In a *t-of-n* threshold configuration, any *t*[^t-edge-cases] participants can cooperatively produce a Schnorr signature that is indistinguishable from a signature produced by a single signer. FROST signatures are unforgeable as long as fewer than *t* participants are corrupted. The signing protocol remains functional provided that at least *t* honest participants retain access to their secret key shares.
2626

27-
The FROST signature scheme enables threshold Schnorr signatures. In a *t*-of-*n* threshold configuration, any *t*[^t-edge-cases] participants can cooperatively produce a Schnorr signature that is indistinguishable from a signature produced by a single signer. FROST signatures are unforgeable as long as fewer than *t* participants are corrupted. The signing protocol remains functional provided that at least *t* honest participants retain access to their secret key shares.
28-
29-
[^t-edge-cases]: While *t = n* and *t = 1* are in principle supported, simpler alternatives are available in these cases. In the case *t = n*, using a dedicated *n*-of-*n* multi-signature scheme such as MuSig2 (see [BIP327][bip327]) instead of FROST avoids the need for an interactive DKG. The case *t = 1* can be realized by letting one signer generate an ordinary [BIP340][bip340] key pair and transmitting the key pair to every other signer, who can check its consistency and then simply use the ordinary [BIP340][bip340] signing algorithm. Signers still need to ensure that they agree on a key pair.
27+
[^t-edge-cases]: While *t = n* and *t = 1* are in principle supported, simpler alternatives are available in these cases. In the case *t = n*, using a dedicated *n-of-n* multi-signature scheme such as MuSig2 (see [BIP327][bip327]) instead of FROST avoids the need for an interactive DKG. The case *t = 1* can be realized by letting one signer generate an ordinary [BIP340][bip340] key pair and transmitting the key pair to every other signer, who can check its consistency and then simply use the ordinary [BIP340][bip340] signing algorithm. Signers still need to ensure that they agree on a key pair.
3028

3129
The IRTF has published [RFC 9591][rfc9591], which specifies the FROST signing protocol for several elliptic curve and hash function combinations, including secp256k1 with SHA-256, the cryptographic primitives used in Bitcoin. However, the signatures produced by RFC 9591 are incompatible with BIP340 Schnorr signatures due to the X-only public keys introduced in BIP340. Additionally, RFC 9591 does not specify key tweaking mechanisms, which are essential for Bitcoin applications such as [BIP32][bip32] key derivation and [BIP341][bip341] Taproot. This document addresses these limitations by specifying a BIP340-compatible variant of FROST signing protocol that supports key tweaking.
3230

@@ -36,6 +34,11 @@ This document specifies the FROST3 variant[^frost3-security]. The FROST3 signing
3634

3735
[^frost3-security]: The FROST3 signing scheme has been proven existentially unforgeable for both trusted dealer and distributed key generation setups. When using a trusted dealer for key generation, security reduces to the standard One-More Discrete Logarithm (OMDL) assumption. When instantiated with a distributed key generation protocol such as SimplPedPoP, security reduces to the Algebraic One-More Discrete Logarithm (AOMDL) assumption.
3836

37+
The on-chain footprint of a FROST Taproot output is essentially a single BIP340 public key, and a transaction spending the output only requires a single signature cooperatively produced by at least *t* signers. This is **more compact** and has **lower verification cost** than each signer providing an individual public key and signature, as would be required by an *t-of-n* policy implemented using `OP_CHECKSIGADD` as introduced in [BIP342][bip342].
38+
As a side effect, the number *n* of signers is not limited by any consensus rules when using FROST.
39+
40+
Moreover, FROST offers a **higher level of privacy** than `OP_CHECKSIGADD`: FROST Taproot outputs are indistinguishable for a blockchain observer from regular, single-signer Taproot outputs even though they are actually controlled by multiple signers. By tweaking the threshold public key, the shared Taproot output can have script spending paths that are hidden unless used.
41+
3942
## Overview
4043

4144
Implementers must make sure to understand this section thoroughly to avoid subtle mistakes that may lead to catastrophic failure.
@@ -56,7 +59,7 @@ Similarly, the test vectors that exercise the unimplemented features should be r
5659
### Key Material and Setup
5760

5861
<!-- REVIEW: should we use "identifiers `i`", secret share `secshare_i` style here? -->
59-
A FROST key generation protocol configures a group of *n* participants with a *threshold public key* (representing a *t*-of-*n* threshold policy).
62+
A FROST key generation protocol configures a group of *n* participants with a *threshold public key* (representing a *t-of-n* threshold policy).
6063
The corresponding *threshold secret key* is Shamir secret-shared among all *n* participants, where each participant holds a distinct long-term *secret share*.
6164
This ensures that any subset of at least *t* participants can jointly run the FROST signing protocol to produce a signature under the *threshold secret key*.
6265

@@ -66,7 +69,7 @@ This protocol distinguishes between two public key formats: *plain public keys*
6669
Key generation protocols produce *public shares* and *threshold public keys* in the plain format. During signing, we conditionally negate *secret shares* to ensure the resulting threshold-signature verifies under the corresponding *X-only threshold public key*.
6770

6871
> [!WARNING]
69-
> Key generation protocols must commit the *threshold public key* to an unspendable script path as recommended in [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-23). This prevents a malicious party from embedding a hidden script path during key generation that would allow them to bypass the *t*-of-*n* threshold policy.
72+
> Key generation protocols must commit the *threshold public key* to an unspendable script path as recommended in [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-23). This prevents a malicious party from embedding a hidden script path during key generation that would allow them to bypass the *t-of-n* threshold policy.
7073
7174
#### Protocol Parties and Network Setup
7275

@@ -107,8 +110,8 @@ Signers begin the signing session by running *NonceGen* to compute their *secnon
107110
Each signer sends their *pubnonce* to the coordinator, who aggregates them using *NonceAgg* to produce an aggregate nonce and sends it back to all signers.
108111

109112
[^nonce-serialization-detail]: We treat the *secnonce* and *pubnonce* as grammatically singular even though they include serializations of two scalars and two elliptic curve points, respectively.
110-
This treatment may be confusing for readers familiar with the MuSig2 paper.
111-
However, serialization is a technical detail that is irrelevant for users of MuSig2 interfaces.
113+
This treatment may be confusing for readers familiar with the [FROST paper][olaf].
114+
However, serialization is a technical detail that is irrelevant for users of FROST interfaces.
112115

113116
**Second broadcast round:**
114117
At this point, every signer has the required data to sign, which, in the algorithms specified below, is stored in a data structure called [Session Context](#session-context).
@@ -241,10 +244,10 @@ The reference code vendors the secp256k1lab library to handle underlying arithme
241244
| Notation | secp256k1lab | Description |
242245
| --- | --- | --- |
243246
| *p* | *FE.SIZE* | Field element size |
244-
| *ord* | *GE.ORDER* | Group order |
247+
| *ord* | *GE.ORDER*, *Scalar.SIZE* | Group order |
245248
| *G* | *G* | The secp256k1 generator point |
246249
| *inf_point* | *GE()* | The infinity point |
247-
| *is_infinity(P)* | *P.infinity()* | Returns whether *P* is the point at infinity |
250+
| *is_infinity(P)* | *P.infinity* | Returns whether *P* is the point at infinity |
248251
| *x(P)* | *P.x* | Returns the x-coordinate of a non-infinity point *P*, in the range *[0, p−1]* |
249252
| *y(P)* | *P.y* | Returns the y-coordinate of a non-infinity point *P*, in the range *[0, p-1]* |
250253
| *has_even_y(P)* | *P.has_even_y()* | Returns whether *P* has an even y-coordinate |
@@ -347,8 +350,8 @@ Internal Algorithm *DeriveInterpolatingValue(id<sub>1..u</sub>, my_id):*
347350
The Tweak Context is a data structure consisting of the following elements:
348351

349352
- The point *Q* representing the potentially tweaked threshold public key: a *GE*
350-
- The accumulated tweak *tacc*: a *Scalar*
351353
- The value *gacc*: *Scalar(1)* or *Scalar(-1)*
354+
- The accumulated tweak *tacc*: a *Scalar*
352355

353356
We write "Let *(Q, gacc, tacc) = tweak_ctx*" to assign names to the elements of a Tweak Context.
354357

@@ -426,12 +429,12 @@ Algorithm *NonceGen(secshare, pubshare, thresh_pk, m, extra_in)*:
426429
- Fail if *k<sub>1</sub> = Scalar(0)* or *k<sub>2</sub> = Scalar(0)*
427430
- Let *R<sub>\*,1</sub> = k<sub>1</sub> &middot; G*, *R<sub>\*,2</sub> = k<sub>2</sub> &middot; G*
428431
- Let *pubnonce = cbytes(R<sub>\*,1</sub>) || cbytes(R<sub>\*,2</sub>)*
429-
- Let *secnonce = bytes(32, k<sub>1</sub>) || bytes(32, k<sub>2</sub>)*[^secnonce-ser]
432+
- Let *secnonce = scalar_to_bytes(k<sub>1</sub>) || scalar_to_bytes(k<sub>2</sub>)*[^secnonce-ser]
430433
- Return *(secnonce, pubnonce)*
431434

432435
[^sk-xor-rand]: The random data is hashed (with a unique tag) as a precaution against situations where the randomness may be correlated with the secret signing share itself. It is xored with the secret share (rather than combined with it in a hash) to reduce the number of operations exposed to the actual secret share.
433436

434-
[^secnonce-ser]: The algorithms as specified here assume that the *secnonce* is stored as a 64-byte array using the serialization *secnonce = bytes(32, k<sub>1</sub>) || bytes(32, k<sub>2</sub>)*. The same format is used in the reference implementation and in the test vectors. However, since the *secnonce* is (obviously) not meant to be sent over the wire, compatibility between implementations is not a concern, and this method of storing the *secnonce* is merely a suggestion. The *secnonce* is effectively a local data structure of the signer which comprises the value pair *(k<sub>1</sub>, k<sub>2</sub>)*, and implementations may choose any suitable method to carry it from *NonceGen* (first communication round) to *Sign* (second communication round). In particular, implementations may choose to hide the *secnonce* in internal state without exposing it in an API explicitly, e.g., in an effort to prevent callers from reusing a *secnonce* accidentally.
437+
[^secnonce-ser]: The algorithms as specified here assume that the *secnonce* is stored as a 64-byte array using the serialization *secnonce = scalar_to_bytes(k<sub>1</sub>) || scalar_to_bytes(k<sub>2</sub>)*. The same format is used in the reference implementation and in the test vectors. However, since the *secnonce* is (obviously) not meant to be sent over the wire, compatibility between implementations is not a concern, and this method of storing the *secnonce* is merely a suggestion. The *secnonce* is effectively a local data structure of the signer which comprises the value pair *(k<sub>1</sub>, k<sub>2</sub>)*, and implementations may choose any suitable method to carry it from *NonceGen* (first communication round) to *Sign* (second communication round). In particular, implementations may choose to hide the *secnonce* in internal state without exposing it in an API explicitly, e.g., in an effort to prevent callers from reusing a *secnonce* accidentally.
435438

436439
[^max-msg-len]: In theory, the allowed message size is restricted because SHA256 accepts byte strings only up to size of 2^61-1 bytes (and because of the 8-byte length encoding).
437440

@@ -442,7 +445,7 @@ Algorithm *NonceAgg(pubnonce<sub>1..u</sub>, id<sub>1..u</sub>)*:
442445
- Inputs:
443446
- The number *u* of signing participants: an integer with *t ≤ u ≤ n*
444447
- The list of participant public nonces *pubnonce<sub>1..u</sub>**u* 66-byte array, each an output of *NonceGen*
445-
- The list of participant identifiers *id<sub>1..u</sub>*: *u* integers, each with 0 ≤ *id<sub>i</sub>* < *n*
448+
- The list of participant identifiers *id<sub>1..u</sub>*: *u* integers, each with *0 ≤ id<sub>i</sub> ≤ n-1*
446449
- For *j = 1 .. 2*:
447450
- For *i = 1 .. u*:
448451
- Let *R<sub>i,j</sub> = cpoint(pubnonce<sub>i</sub>[(j-1)\*33:j\*33])*; fail if that fails and blame signer *id<sub>i</sub>* for invalid *pubnonce*
@@ -525,7 +528,7 @@ Algorithm *PartialSigVerify(psig, pubnonce<sub>1..u</sub>, signers_ctx, tweak<su
525528

526529
- Inputs:
527530
- The partial signature *psig*: a 32-byte array, serialized scalar
528-
- The list public nonces *pubnonce<sub>1..u</sub>*: *u* 66-byte arrays, each an output of *NonceGen*
531+
- The list of public nonces *pubnonce<sub>1..u</sub>*: *u* 66-byte arrays, each an output of *NonceGen*
529532
- The *signers_ctx*: a [Signers Context](#signers-context) data structure
530533
- The number *v* of tweaks with *0 ≤ v < 2^32*
531534
- The list of tweaks *tweak<sub>1..v</sub>**v* 32-byte arrays, each a serialized scalar
@@ -811,7 +814,7 @@ We thank Jonas Nick, Tim Ruffing, Jesse Posner, and Sebastian Falbesoner for the
811814
[bip32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
812815
[bip340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
813816
[bip341]: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
814-
<!-- [bip342]: https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki -->
817+
[bip342]: https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki
815818
[bip327]: https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki
816819
[frost1]: https://eprint.iacr.org/2020/852
817820
[frost2]: https://eprint.iacr.org/2021/1375

0 commit comments

Comments
 (0)