musig-spec: various cleanups

- add BIP header & abstract
- rename MuSig to MuSig2 because some people may want to use the 3-round version
- remove applications because we don't need to motivate an informational BIP
- x-only -> X-only
- remove overly repetetitive "The algorithm [...] is defined as"
- move "Remarks" and "Design" out of "Description" section and move "Test
  vectors and ..." into "Description" section. The idea is that the Description
  contains everything that is absolutely required to implement the BIP (safely).
This commit is contained in:
Jonas Nick 2022-03-22 21:25:01 +00:00
parent ef537b2065
commit 686d96222d

View File

@ -1,25 +1,27 @@
<pre> <pre>
Title: MuSig BIP: ?
Title: MuSig2
Author: Author:
Status: Draft Status: Draft
License: BSD-2-Clause License: BSD-3-Clause
Created: 2020-01-19 Type: Informational
Created: 2022-03-22
</pre> </pre>
== Introduction == == Introduction ==
=== Abstract === === Abstract ===
This document proposes a standard for the MuSig2 protocol that supports ''tweaking'' and outputs [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] public keys and signatures. This document proposes a standard for the [https://eprint.iacr.org/2020/1261.pdf MuSig2] protocol.
The standard is compatible with [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] public keys and signatures.
It also supports ''tweaking'', which allows creating [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] Taproot outputs with key and script paths.
=== Copyright === === Copyright ===
This document is licensed under the 2-clause BSD license. This document is licensed under the 3-clause BSD license.
=== Motivation === === Motivation ===
== Description ==
=== Design === === Design ===
* The output of the ''KeyAgg'' algorithm depends on the order of the input public keys. * The output of the ''KeyAgg'' algorithm depends on the order of the input public keys.
@ -30,9 +32,13 @@ This document is licensed under the 2-clause BSD license.
* The public nonces are serialized in compressed format (33 bytes). We accept the small overhead compared to x-only serialization to avoid complicating the specification. * The public nonces are serialized in compressed format (33 bytes). We accept the small overhead compared to x-only serialization to avoid complicating the specification.
* This specification supports signing for ''tweaked'' aggregate public keys. There are two modes of tweaking. ''Ordinary'' tweaking allows deriving child aggregate public keys per [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]. ''X-only'' tweaking allows creating a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] Taproot tweak. See section [[#tweaking|Tweaking]] below for details. * This specification supports signing for ''tweaked'' aggregate public keys. There are two modes of tweaking. ''Ordinary'' tweaking allows deriving child aggregate public keys per [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]. ''X-only'' tweaking allows creating a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] Taproot tweak. See section [[#tweaking|Tweaking]] below for details.
== Description ==
When implementing the specification, make sure to understand this section thoroughly, particularly the [[#signing-flow|Signing Flow]], to avoid subtle mistakes that lead to catastrophic failure.
=== Notation === === Notation ===
The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this specification to other elliptic curves is not straightforward and can result in an insecure scheme<ref>Among other pitfalls, using the specification with a curve whose order is not close to the size of the range of the nonce derivation function is insecure.</ref>. The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this specification to other elliptic curves is not straightforward and can result in an insecure scheme.
* Lowercase variables represent integers or byte arrays. * Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''. ** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''. ** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
@ -59,7 +65,7 @@ The following conventions are used, with constants as defined for [https://www.s
*** Fail if ''c &ne; y'<sup>2</sup> mod p''. *** Fail if ''c &ne; y'<sup>2</sup> mod p''.
*** Let ''y = y' '' if ''y' mod 2 = 0'', otherwise let ''y = p - y' ''. *** Let ''y = y' '' if ''y' mod 2 = 0'', otherwise let ''y = p - y' ''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y''. *** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y''.
** The function ''point(x)'', where ''x'' is a 32-byte array ("x-only" serialization), returns ''lift_x(int(x))''. Fail if ''lift_x'' fails. ** The function ''point(x)'', where ''x'' is a 32-byte array ("X-only" serialization), returns ''lift_x(int(x))''. Fail if ''lift_x'' fails.
** The function ''pointc(x)'', where ''x'' is a 33-byte array (compressed serialization), sets ''P = lift_x(int(x[1:33]))'' and fails if that fails. If ''x[0] = 2'' it returns ''P'' and if ''x[0] = 3'' it returns ''-P''. Otherwise, it fails. ** The function ''pointc(x)'', where ''x'' is a 33-byte array (compressed serialization), sets ''P = lift_x(int(x[1:33]))'' and fails if that fails. If ''x[0] = 2'' it returns ''P'' and if ''x[0] = 3'' it returns ''-P''. Otherwise, it fails.
** The function ''hash<sub>tag</sub>(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''. ** The function ''hash<sub>tag</sub>(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''.
* Other: * Other:
@ -73,7 +79,7 @@ Input:
* The number ''u'' of public keys with ''0 < u < 2^32'' * The number ''u'' of public keys with ''0 < u < 2^32''
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays * The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
The algorithm '''''KeySort(pk<sub>1..u</sub>)''''' is defined as: '''''KeySort(pk<sub>1..u</sub>)''''':
* Return ''pk<sub>1..u</sub>'' sorted in lexicographical order. * Return ''pk<sub>1..u</sub>'' sorted in lexicographical order.
==== Key Aggregation ==== ==== Key Aggregation ====
@ -85,11 +91,11 @@ Input:
* The tweaks ''tweak<sub>1..v</sub>'': ''v'' 32-byte arrays * The tweaks ''tweak<sub>1..v</sub>'': ''v'' 32-byte arrays
* The tweak methods ''is_xonly_t<sub>1..v</sub>'' : ''v'' booleans * The tweak methods ''is_xonly_t<sub>1..v</sub>'' : ''v'' booleans
The algorithm '''''KeyAgg(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''''' is defined as: '''''KeyAgg(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''''':
* Let ''(Q,_,_) = KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''; fail if that fails. * Let ''(Q,_,_) = KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''; fail if that fails.
* Return ''bytes(Q)''. * Return ''bytes(Q)''.
The algorithm '''''KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''''' is defined as: '''''KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''''':
* Let ''pk2 = GetSecondKey(pk<sub>1..u</sub>)'' * Let ''pk2 = GetSecondKey(pk<sub>1..u</sub>)''
* For ''i = 1 .. u'': * For ''i = 1 .. u'':
** Let ''P<sub>i</sub> = point(pk<sub>i</sub>)''; fail if that fails. ** Let ''P<sub>i</sub> = point(pk<sub>i</sub>)''; fail if that fails.
@ -102,26 +108,26 @@ The algorithm '''''KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xo
** Let ''(Q<sub>i</sub>, gacc<sub>i</sub>, tacc<sub>i</sub>) = Tweak(Q<sub>i-1</sub>, gacc<sub>i-1</sub>, tweak<sub>i</sub>, tacc<sub>i-1</sub>, is_xonly_t<sub>i</sub>)''; fail if that fails ** Let ''(Q<sub>i</sub>, gacc<sub>i</sub>, tacc<sub>i</sub>) = Tweak(Q<sub>i-1</sub>, gacc<sub>i-1</sub>, tweak<sub>i</sub>, tacc<sub>i-1</sub>, is_xonly_t<sub>i</sub>)''; fail if that fails
* Return ''(Q<sub>v</sub>, gacc<sub>v</sub>, tacc<sub>v</sub>)''. * Return ''(Q<sub>v</sub>, gacc<sub>v</sub>, tacc<sub>v</sub>)''.
The algorithm '''''HashKeys(pk<sub>1..u</sub>)''''' is defined as: '''''HashKeys(pk<sub>1..u</sub>)''''':
* Return ''hash<sub>KeyAgg list</sub>(pk<sub>1</sub> || pk<sub>2</sub> || ... || pk<sub>u</sub>)'' * Return ''hash<sub>KeyAgg list</sub>(pk<sub>1</sub> || pk<sub>2</sub> || ... || pk<sub>u</sub>)''
The algorithm '''''GetSecondKey(pk<sub>1..u</sub>)''''' is defined as: '''''GetSecondKey(pk<sub>1..u</sub>)''''':
* For ''j = 1 .. u'': * For ''j = 1 .. u'':
** If ''pk<sub>j</sub> &ne; pk<sub>1</sub>'': ** If ''pk<sub>j</sub> &ne; pk<sub>1</sub>'':
*** Return ''pk<sub>j</sub>'' *** Return ''pk<sub>j</sub>''
* Return ''bytes(0)'' * Return ''bytes(0)''
The algorithm '''''KeyAggCoeff(pk<sub>1..u</sub>, pk')''''' is defined as: '''''KeyAggCoeff(pk<sub>1..u</sub>, pk')''''':
* Let ''pk2 = GetSecondKey(pk<sub>1..u</sub>)'': * Let ''pk2 = GetSecondKey(pk<sub>1..u</sub>)'':
* Return ''KeyAggCoeff'(pk<sub>1..u</sub>, pk', pk2)'' * Return ''KeyAggCoeff'(pk<sub>1..u</sub>, pk', pk2)''
The algorithm '''''KeyAggCoeff'(pk<sub>1..u</sub>, pk', pk2)''''' is defined as: '''''KeyAggCoeff'(pk<sub>1..u</sub>, pk', pk2)''''':
* Let ''L = HashKeys(pk<sub>1..u</sub>)'' * Let ''L = HashKeys(pk<sub>1..u</sub>)''
* If ''pk' = pk2'': * If ''pk' = pk2'':
** Return 1 ** Return 1
* Return ''int(hash<sub>KeyAgg coefficient</sub>(L || pk')) mod n'' * Return ''int(hash<sub>KeyAgg coefficient</sub>(L || pk')) mod n''
The algorithm '''''Tweak(Q<sub>i-1</sub>, gacc<sub>i-1</sub>, tweak<sub>i</sub>, tacc<sub>i-1</sub>, is_xonly_t<sub>i</sub>)''''' is defined as: '''''Tweak(Q<sub>i-1</sub>, gacc<sub>i-1</sub>, tweak<sub>i</sub>, tacc<sub>i-1</sub>, is_xonly_t<sub>i</sub>)''''':
* If ''is_xonly_t<sub>i</sub>'' and ''not has_even_y(Q<sub>i-1</sub>)'': * If ''is_xonly_t<sub>i</sub>'' and ''not has_even_y(Q<sub>i-1</sub>)'':
** Let ''g<sub>i-1</sub> = -1 mod n'' ** Let ''g<sub>i-1</sub> = -1 mod n''
* Else: let ''g<sub>i-1</sub> = 1'' * Else: let ''g<sub>i-1</sub> = 1''
@ -134,7 +140,7 @@ The algorithm '''''Tweak(Q<sub>i-1</sub>, gacc<sub>i-1</sub>, tweak<sub>i</sub>,
==== Nonce Generation ==== ==== Nonce Generation ====
The algorithm '''''NonceGen()''''' is defined as: '''''NonceGen()''''':
* Generate two random integers ''k<sub>1</sub>, k<sub>2</sub>'' in the range ''1...n-1'' * Generate two random integers ''k<sub>1</sub>, k<sub>2</sub>'' in the range ''1...n-1''
* Let ''R<sup>*</sup><sub>1</sub> = k<sub>1</sub>⋅G, R<sup>*</sup><sub>2</sub> = k<sub>2</sub>⋅G'' * Let ''R<sup>*</sup><sub>1</sub> = k<sub>1</sub>⋅G, R<sup>*</sup><sub>2</sub> = k<sub>2</sub>⋅G''
* Let ''pubnonce = cbytes(R<sup>*</sup><sub>1</sub>) || cbytes(R<sup>*</sup><sub>2</sub>)'' * Let ''pubnonce = cbytes(R<sup>*</sup><sub>1</sub>) || cbytes(R<sup>*</sup><sub>2</sub>)''
@ -146,7 +152,7 @@ The algorithm '''''NonceGen()''''' is defined as:
* The number ''u'' of ''pubnonces'' with ''0 < u < 2^32'' * The number ''u'' of ''pubnonces'' with ''0 < u < 2^32''
* The public nonces ''pubnonce<sub>1..u</sub>'': ''u'' 66-byte arrays * The public nonces ''pubnonce<sub>1..u</sub>'': ''u'' 66-byte arrays
The algorithm '''''NonceAgg(pubnonce<sub>1..u</sub>)''''' is defined as: '''''NonceAgg(pubnonce<sub>1..u</sub>)''''':
* For ''i = 1 .. 2'': * For ''i = 1 .. 2'':
** For ''j = 1 .. u'': ** For ''j = 1 .. u'':
*** Let ''R<sub>i,j</sub> = pointc(pubnonce<sub>j</sub>[(i-1)*33:i*33])''; fail if that fails *** Let ''R<sub>i,j</sub> = pointc(pubnonce<sub>j</sub>[(i-1)*33:i*33])''; fail if that fails
@ -167,7 +173,7 @@ The Session Context is a data structure consisting of the following elements:
We write "Let ''(aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m) = session_ctx''" to assign names to the elements of a Session Context. We write "Let ''(aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m) = session_ctx''" to assign names to the elements of a Session Context.
The algorithm '''''GetSessionValues(session_ctx)''''' is defined as: '''''GetSessionValues(session_ctx)''''':
* Let ''(aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m) = session_ctx'' * Let ''(aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m) = session_ctx''
* Let ''(Q, gacc<sub>v</sub>, tacc<sub>v</sub>) = KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''; fail if that fails * Let ''(Q, gacc<sub>v</sub>, tacc<sub>v</sub>) = KeyAggInternal(pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>)''; fail if that fails
* Let ''b = int(hash<sub>MuSig/noncecoef</sub>(aggnonce || bytes(Q) || m)) mod n'' * Let ''b = int(hash<sub>MuSig/noncecoef</sub>(aggnonce || bytes(Q) || m)) mod n''
@ -177,7 +183,7 @@ The algorithm '''''GetSessionValues(session_ctx)''''' is defined as:
* Let ''e = int(hash<sub>BIP0340/challenge</sub>(bytes(R) || bytes(Q) || m)) mod n'' * Let ''e = int(hash<sub>BIP0340/challenge</sub>(bytes(R) || bytes(Q) || m)) mod n''
* Return ''(Q, gacc<sub>v</sub>, tacc<sub>v</sub>, b, R, e)'' * Return ''(Q, gacc<sub>v</sub>, tacc<sub>v</sub>, b, R, e)''
The algorithm '''''GetSessionKeyAggCoeff(session_ctx, P)''''' is defined as: '''''GetSessionKeyAggCoeff(session_ctx, P)''''':
* Let ''(_, u, pk<sub>1..u</sub>, _, _, _, _) = session_ctx'' * Let ''(_, u, pk<sub>1..u</sub>, _, _, _, _) = session_ctx''
* Return ''KeyAggCoeff(pk<sub>1..u</sub>, bytes(P))'' * Return ''KeyAggCoeff(pk<sub>1..u</sub>, bytes(P))''
@ -188,7 +194,7 @@ Input:
* The secret key ''sk'': a 32-byte array * The secret key ''sk'': a 32-byte array
* The ''session_ctx'': a [[#session-context|Session Context]] data structure * The ''session_ctx'': a [[#session-context|Session Context]] data structure
The algorithm '''''Sign(secnonce, sk, session_ctx)''''' is defined as: '''''Sign(secnonce, sk, session_ctx)''''':
* Let ''(Q, gacc<sub>v</sub>, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails * Let ''(Q, gacc<sub>v</sub>, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* Let ''k'<sub>1</sub> = int(secnonce[0:32]), k'<sub>2</sub> = int(secnonce[32:64])'' * Let ''k'<sub>1</sub> = int(secnonce[0:32]), k'<sub>2</sub> = int(secnonce[32:64])''
* Fail if ''k'<sub>i</sub> = 0'' or ''k'<sub>i</sub> &ge; n'' for ''i = 1..2'' * Fail if ''k'<sub>i</sub> = 0'' or ''k'<sub>i</sub> &ge; n'' for ''i = 1..2''
@ -219,21 +225,19 @@ Input:
* The message ''m'': a 32-byte array * The message ''m'': a 32-byte array
* The index of the signer ''i'' in the public nonces and public keys with ''0 < i &le; u'' * The index of the signer ''i'' in the public nonces and public keys with ''0 < i &le; u''
The algorithm '''''PartialSigVerify(psig, pubnonce<sub>1..u</sub>, pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m, i)''''' is defined as: '''''PartialSigVerify(psig, pubnonce<sub>1..u</sub>, pk<sub>1..u</sub>, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m, i)''''':
* Let ''aggnonce = NonceAgg(pubnonce<sub>1..u</sub>)''; fail if that fails * Let ''aggnonce = NonceAgg(pubnonce<sub>1..u</sub>)''; fail if that fails
* Let ''session_ctx = (aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m)'' * Let ''session_ctx = (aggnonce, u, pk<sub>1..u</sub>, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m)''
* Run ''PartialSigVerifyInternal(psig, pubnonce<sub>i</sub>, pk<sub>i</sub>, session_ctx)'' * Run ''PartialSigVerifyInternal(psig, pubnonce<sub>i</sub>, pk<sub>i</sub>, session_ctx)''
* Return success iff no failure occurred before reaching this point. * Return success iff no failure occurred before reaching this point.
===== PartialSigVerifyInternal =====
Input: Input:
* The partial signature ''psig'': a 32-byte array * The partial signature ''psig'': a 32-byte array
* The public nonce of the signer ''pubnonce'': a 66-byte array * The public nonce of the signer ''pubnonce'': a 66-byte array
* The public key of the signer ''pk<sup>*</sup>'' (in ''pk<sub>1..u</sub>'' of the session_ctx''): a 32-byte array * The public key of the signer ''pk<sup>*</sup>'' (in ''pk<sub>1..u</sub>'' of the session_ctx''): a 32-byte array
* The ''session_ctx'': a [[#session-context|Session Context]] data structure * The ''session_ctx'': a [[#session-context|Session Context]] data structure
The algorithm '''''PartialSigVerifyInternal(psig, pubnonce, pk<sup>*</sup>, session_ctx)''''' is defined as: '''''PartialSigVerifyInternal(psig, pubnonce, pk<sup>*</sup>, session_ctx)''''':
* Let ''(Q, gacc<sub>v</sub>, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails * Let ''(Q, gacc<sub>v</sub>, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* Let ''s = int(psig)''; fail if ''s &ge; n'' * Let ''s = int(psig)''; fail if ''s &ge; n''
* Let ''R<sup>*</sup><sub>1</sub> = pointc(pubnonce[0:33]), R<sup>*</sup><sub>2</sub> = pointc(pubnonce[33:66])'' * Let ''R<sup>*</sup><sub>1</sub> = pointc(pubnonce[0:33]), R<sup>*</sup><sub>2</sub> = pointc(pubnonce[33:66])''
@ -253,7 +257,7 @@ Input:
* The partial signatures ''psig<sub>1..u</sub>'': ''u'' 32-byte arrays * The partial signatures ''psig<sub>1..u</sub>'': ''u'' 32-byte arrays
* The ''session_ctx'': a [[#session-context|Session Context]] data structure * The ''session_ctx'': a [[#session-context|Session Context]] data structure
The algorithm '''''PartialSigAgg(psig<sub>1..u</sub>, session_ctx)''''' is defined as: '''''PartialSigAgg(psig<sub>1..u</sub>, session_ctx)''''':
* Let ''(Q, _, tacc<sub>v</sub>, _, _, R, e) = GetSessionValues(session_ctx)''; fail if that fails * Let ''(Q, _, tacc<sub>v</sub>, _, _, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* For ''i = 1 .. u'': * For ''i = 1 .. u'':
** Let ''s<sub>i</sub> = int(psig<sub>i</sub>)''; fail if ''s<sub>i</sub> &ge; n''. ** Let ''s<sub>i</sub> = int(psig<sub>i</sub>)''; fail if ''s<sub>i</sub> &ge; n''.
@ -277,29 +281,34 @@ Otherwise, it is possible to extract the secret signing key from the partial sig
An implementation may invalidate the secnonce argument after ''Sign'' to avoid any reuse. An implementation may invalidate the secnonce argument after ''Sign'' to avoid any reuse.
Avoiding reuse also implies that the ''NonceGen'' algorithm must compute unbiased, uniformly random values ''k<sub>1</sub>'' and ''k<sub>2</sub>''. Avoiding reuse also implies that the ''NonceGen'' algorithm must compute unbiased, uniformly random values ''k<sub>1</sub>'' and ''k<sub>2</sub>''.
=== Remarks on Security and Correctness === === Test Vectors and Reference Code ===
==== Tweaking ==== There are some vectors in libsecp256k1's [https://github.com/ElementsProject/secp256k1-zkp/blob/master/src/modules/musig/tests_impl.h MuSig test file].
Search for the ''musig_test_vectors_keyagg'' and ''musig_test_vectors_sign'' functions.
This MuSig specification supports two modes of tweaking that correspond to the following algorithms: == Remarks on Security and Correctness ==
=== Tweaking ===
This MuSig2 specification supports two modes of tweaking that correspond to the following algorithms:
Input: Input:
* ''P'': a point * ''P'': a point
* The tweak ''t'': an integer with ''0 &le; t < n '' * The tweak ''t'': an integer with ''0 &le; t < n ''
The algorithm '''''OrdinaryTweak(P, t)''''' is defined as: '''''OrdinaryTweak(P, t)''''':
* Return ''P + t⋅G'' * Return ''P + t⋅G''
The algorithm '''''XonlyTweak(P, t)''''' is defined as: '''''XonlyTweak(P, t)''''':
* Return ''with_even_y(P) + t⋅G'' * Return ''with_even_y(P) + t⋅G''
==== Negation Of The Secret Key When Signing ==== === Negation Of The Secret Key When Signing ===
In order to produce a partial signature for an x-only public key that is an aggregate of ''u'' x-only keys and tweaked ''v'' times (x-only or ordinarily), the ''[[#Sign negation|Sign]]'' algorithm may need to negate the secret key during the signing process. In order to produce a partial signature for an X-only public key that is an aggregate of ''u'' X-only keys and tweaked ''v'' times (X-only or ordinarily), the ''[[#Sign negation|Sign]]'' algorithm may need to negate the secret key during the signing process.
<poem> <poem>
The following public keys arise as intermediate steps in the MuSig protocol: The following public keys arise as intermediate steps in the MuSig2 protocol:
• ''P<sub>i</sub>'' as computed in ''KeyAggInternal'' is the point corresponding to the ''i''-th signer's x-only public key. Defining ''d'<sub>i</sub>'' to be the ''d' '' value as computed in the ''Sign'' algorithm of the ''i''-th signer, we have • ''P<sub>i</sub>'' as computed in ''KeyAggInternal'' is the point corresponding to the ''i''-th signer's X-only public key. Defining ''d'<sub>i</sub>'' to be the ''d' '' value as computed in the ''Sign'' algorithm of the ''i''-th signer, we have
''P<sub>i</sub> = with_even_y(d'<sub>i</sub>⋅G) ''. ''P<sub>i</sub> = with_even_y(d'<sub>i</sub>⋅G) ''.
• ''Q<sub>0</sub>'' is an aggregate of the signer's public keys and defined in ''KeyAggInternal'' as • ''Q<sub>0</sub>'' is an aggregate of the signer's public keys and defined in ''KeyAggInternal'' as
''Q<sub>0</sub> = a<sub>1</sub>⋅P<sub>1</sub> + a<sub>2</sub>⋅P<sub>1</sub> + ... + a<sub>u</sub>⋅P<sub>u</sub>''. ''Q<sub>0</sub> = a<sub>1</sub>⋅P<sub>1</sub> + a<sub>2</sub>⋅P<sub>1</sub> + ... + a<sub>u</sub>⋅P<sub>u</sub>''.
@ -309,7 +318,7 @@ The following public keys arise as intermediate steps in the MuSig protocol:
''f(i) := Q<sub>i</sub>'' otherwise. ''f(i) := Q<sub>i</sub>'' otherwise.
</poem> </poem>
The goal is to produce a partial signature corresponding to the output of ''KeyAgg'', i.e., the final (x-only) public key point after ''v'' tweaking operations ''with_even_y(Q<sub>v</sub>)''. The goal is to produce a partial signature corresponding to the output of ''KeyAgg'', i.e., the final (X-only) public key point after ''v'' tweaking operations ''with_even_y(Q<sub>v</sub>)''.
<poem> <poem>
We define ''gp<sub>i</sub>'' for ''1 &le; i &le; u'' to be ''gp '' as computed in the ''Sign'' algorithm of the ''i''-th signer. It holds that We define ''gp<sub>i</sub>'' for ''1 &le; i &le; u'' to be ''gp '' as computed in the ''Sign'' algorithm of the ''i''-th signer. It holds that
@ -323,7 +332,7 @@ Furthermore, the ''Sign'' and ''PartialSigVerify'' algorithms set ''g<sub>v</sub
</poem> </poem>
<poem> <poem>
So, the (x-only) final public key is So, the (X-only) final public key is
''with_even_y(Q<sub>v</sub>) ''with_even_y(Q<sub>v</sub>)
= g<sub>v</sub>⋅Q<sub>v</sub> = g<sub>v</sub>⋅Q<sub>v</sub>
= g<sub>v</sub>⋅(f(v-1) + t<sub>v</sub>⋅G) = g<sub>v</sub>⋅(f(v-1) + t<sub>v</sub>⋅G)
@ -377,7 +386,7 @@ The verifier doesn't have access to ''d⋅G'', but can construct it using the xo
= g<sub>v</sub>⋅gacc<sub>v</sub>⋅point(pk<sup>*</sup>)'' = g<sub>v</sub>⋅gacc<sub>v</sub>⋅point(pk<sup>*</sup>)''
</poem> </poem>
==== Dealing with Infinity in Nonce Aggregation ==== === Dealing with Infinity in Nonce Aggregation ===
If it happens that ''is_infinite(R'<sub>i</sub>)'' inside ''[[#NonceAgg infinity|NonceAgg]]'' there is at least one dishonest signer (except with negligible probability). If it happens that ''is_infinite(R'<sub>i</sub>)'' inside ''[[#NonceAgg infinity|NonceAgg]]'' there is at least one dishonest signer (except with negligible probability).
If we fail here, we will never be able to determine who it is. If we fail here, we will never be able to determine who it is.
@ -397,13 +406,6 @@ Given a successful adversary against the security game (EUF-CMA) for the modifie
We conclude that these two modifications preserve the security of the MuSig2* scheme. We conclude that these two modifications preserve the security of the MuSig2* scheme.
== Applications ==
== Test Vectors and Reference Code ==
There are some vectors in libsecp256k1's [https://github.com/ElementsProject/secp256k1-zkp/blob/master/src/modules/musig/tests_impl.h MuSig test file].
Search for the ''musig_test_vectors_keyagg'' and ''musig_test_vectors_sign'' functions.
== Footnotes == == Footnotes ==
<references /> <references />