Merge ElementsProject/secp256k1-zkp#157: Add description of MuSig signing to musig-spec.md

69b392f3cb musig: move explanation for aggnonce=inf to spec (Jonas Nick)
4824220bb7 musig-spec: describe NonceGen, NonceAgg, Sign,PartialSig{Verify,Agg} (Jonas Nick)
3c122d0780 musig-spec: improve definition of lift_x (Jonas Nick)
e0bb2d7009 musig-spec: improve KeyAgg description (Jonas Nick)
b8f4e75d89 musig-spec: move to doc directory (Jonas Nick)

Pull request description:

  Will wait before adding tweaking until #151 is merged.

ACKs for top commit:
  robot-dreams:
    ACK 69b392f3cb based on:
  real-or-random:
    ACK 69b392f3cb I haven't looked at every detail but it's certainly ready to be merged as draft spec

Tree-SHA512: e3aa0265a9d7a7648e03ca42575397100edd5af43f0224937af51aa5c77efc451d7938149bdc711f69e24fb9291438453b8cd762affaa1a2e7bcc89f121485df
This commit is contained in:
Tim Ruffing
2022-01-25 10:55:01 +01:00
3 changed files with 256 additions and 117 deletions

View File

@@ -1,102 +0,0 @@
<pre>
Title: MuSig Key Aggregation
Author:
Status: Draft
License: BSD-2-Clause
Created: 2020-01-19
</pre>
== Introduction ==
=== Abstract ===
This document describes MuSig Key Aggregation in libsecp256k1-zkp.
=== Copyright ===
This document is licensed under the 2-clause BSD license.
=== Motivation ===
== Description ==
=== Design ===
* A function for sorting public keys allows to aggregate keys independent of the (initial) order.
* The KeyAgg coefficient is computed by hashing the key instead of key index. Otherwise, if the pubkey list gets sorted, the signer needs to translate between key indices pre- and post-sorting.
* The second unique key in the pubkey list gets the constant KeyAgg coefficient 1 which saves an exponentiation (see the MuSig2* appendix in the [https://eprint.iacr.org/2020/1261 MuSig2 paper]).
=== Specification ===
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>.
* Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
* Uppercase variables refer to points on the curve with equation ''y<sup>2</sup> = x<sup>3</sup> + 7'' over the integers modulo ''p''.
** ''is_infinite(P)'' returns whether or not ''P'' is the point at infinity.
** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity).
** The constant ''G'' refers to the base point, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''.
** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation].
** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation.
* Functions and operations:
** ''||'' refers to byte array concatenation.
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j &ge; 0'', returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''.
** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first.
** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref>
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x<sup>3</sup> + 7 mod p'' and they can be computed as ''y = &plusmn;c<sup>(p+1)/4</sup> mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''.</ref> and ''has_even_y(P)'', or fails if no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Let ''c = x<sup>3</sup> + 7 mod p''.
*** Let ''y = c<sup>(p+1)/4</sup> mod p''.
*** Fail if ''c &ne; y<sup>2</sup> mod p''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y'' if ''y mod 2 = 0'' or ''y(P) = p-y'' otherwise.
** 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)''.
==== Key Sorting ====
Input:
* The number ''u'' of signatures with ''0 < u < 2^32''
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
The algorithm ''KeySort(pk<sub>1..u</sub>)'' is defined as:
* Return ''pk<sub>1..u</sub>'' sorted in lexicographical order.
==== Key Aggregation ====
Input:
* The number ''u'' of signatures with ''0 < u < 2^32''
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
The algorithm ''KeyAgg(pk<sub>1..u</sub>)'' is defined as:
* For ''i = 1 .. u'':
** Let ''a<sub>i</sub> = KeyAggCoeff(pk<sub>1..u</sub>, i)''.
** Let ''P<sub>i</sub> = lift_x(int(pk<sub>i</sub>))''; fail if it fails.
* Let ''S = a<sub>1</sub>⋅P<sub>1</sub> + a<sub>2</sub>⋅P<sub>1</sub> + ... + a<sub>u</sub>⋅P<sub>u</sub>''
* Fail if ''is_infinite(S)''.
* Return ''bytes(S)''.
The algorithm ''HashKeys(pk<sub>1..u</sub>)'' is defined as:
* Return ''hash<sub>KeyAgg list</sub>(pk<sub>1</sub> || pk<sub>2</sub> || ... || pk<sub>u</sub>)''
The algorithm ''IsSecond(pk<sub>1..u</sub>, i)'' is defined as:
* For ''j = 1 .. u'':
** If ''pk<sub>j</sub> &ne; pk<sub>1</sub>'':
*** Return ''true'' if ''pk<sub>j</sub> = pk<sub>i</sub>'', otherwise return ''false''.
* Return ''false''
The algorithm ''KeyAggCoeff(pk<sub>1..u</sub>, i)'' is defined as:
* Let ''L = HashKeys(pk<sub>1..u</sub>)''.
* Return 1 if ''IsSecond(pk<sub>1..u</sub>, i)'', otherwise return ''int(hash<sub>KeyAgg coefficient</sub>(L || pk<sub>i</sub>) mod n''.
== Applications ==
== Test Vectors and Reference Code ==
== Footnotes ==
<references />
== Acknowledgements ==

View File

@@ -362,21 +362,7 @@ int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggn
}
for (i = 0; i < 2; i++) {
if (secp256k1_gej_is_infinity(&aggnonce_ptj[i])) {
/* There must be at least one dishonest signer. If we would return 0
here, we will never be able to determine who it is. Therefore, we
should continue such that the culprit is revealed when collecting
and verifying partial signatures.
However, dealing with the point at infinity (loading,
de-/serializing) would require a lot of extra code complexity.
Instead, we set the aggregate nonce to some arbitrary point (the
generator). This is secure, because it only restricts the
abilities of the attacker: an attacker that forces the sum of
nonces to be infinity by sending some maliciously generated nonce
pairs can be turned into an attacker that forces the sum to be
the generator (by simply adding the generator to one of the
malicious nonces), and this does not change the winning condition
of the EUF-CMA game. */
/* Set to G according to the specification */
aggnonce_pt[i] = secp256k1_ge_const_g;
} else {
secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]);