musig-spec: improve KeyAgg description
It's easier to identify a signer with a public key instead of an index in KeyAggCoef because it doesn't force the signer to know its index.
This commit is contained in:
parent
b8f4e75d89
commit
e0bb2d7009
@ -22,10 +22,11 @@ This document is licensed under the 2-clause BSD license.
|
|||||||
|
|
||||||
=== Design ===
|
=== Design ===
|
||||||
|
|
||||||
* A function for sorting public keys allows to aggregate keys independent of the (initial) order.
|
* The output of the ''KeyAgg'' algorithm depends on the order of the input public keys.
|
||||||
|
* It is possible to sort the public keys with the ''KeySort'' algorithm before key aggregation to ensure the same output, 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 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]).
|
* The second unique key in the pubkey list given to ''KeyAgg'' (as well as any keys identical to this key) gets the constant KeyAgg coefficient 1 which saves an exponentiation (see the MuSig2* appendix in the [https://eprint.iacr.org/2020/1261 MuSig2 paper]).
|
||||||
|
* The public key inputs are serialized using x-only (32 byte) instead of compressed (33 byte) serialization. The reason for this is that as x-only keys are becoming more common, the full key may not be available.
|
||||||
|
|
||||||
=== Specification ===
|
=== Specification ===
|
||||||
|
|
||||||
@ -44,8 +45,9 @@ The following conventions are used, with constants as defined for [https://www.s
|
|||||||
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j ≥ 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 ''x[i:j]'', where ''x'' is a byte array and ''i, j ≥ 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(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 ''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 ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
|
||||||
|
** The function ''cbytes(P)'', where ''P'' is a point, returns ''a || bytes(P)'' where ''a'' is ''2'' if ''has_even_y(P)'' and ''3'' otherwise.
|
||||||
|
** 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 ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref>
|
** 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 = ±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:
|
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 = ±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 ''c = x<sup>3</sup> + 7 mod p''.
|
||||||
@ -67,34 +69,39 @@ The algorithm ''KeySort(pk<sub>1..u</sub>)'' is defined as:
|
|||||||
==== Key Aggregation ====
|
==== Key Aggregation ====
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
* The number ''u'' of signatures 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 ''KeyAgg(pk<sub>1..u</sub>)'' is defined as:
|
The algorithm ''KeyAgg(pk<sub>1..u</sub>)'' is defined as:
|
||||||
* For ''i = 1 .. u'':
|
* For ''i = 1 .. u'':
|
||||||
** Let ''a<sub>i</sub> = KeyAggCoeff(pk<sub>1..u</sub>, i)''.
|
** Let ''a<sub>i</sub> = KeyAggCoeff(pk<sub>1..u</sub>, pk<sub>i</sub>)''.
|
||||||
** Let ''P<sub>i</sub> = lift_x(int(pk<sub>i</sub>))''; fail if it fails.
|
** 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>''
|
* Let ''Q = 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)''.
|
* Fail if ''is_infinite(Q)''.
|
||||||
* Return ''bytes(S)''.
|
* Return ''bytes(Q)''.
|
||||||
|
|
||||||
The algorithm ''HashKeys(pk<sub>1..u</sub>)'' is defined as:
|
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>)''
|
* 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:
|
The algorithm ''IsSecond(pk<sub>1..u</sub>, pk')'' is defined as:
|
||||||
* For ''j = 1 .. u'':
|
* For ''j = 1 .. u'':
|
||||||
** If ''pk<sub>j</sub> ≠ pk<sub>1</sub>'':
|
** If ''pk<sub>j</sub> ≠ pk<sub>1</sub>'':
|
||||||
*** Return ''true'' if ''pk<sub>j</sub> = pk<sub>i</sub>'', otherwise return ''false''.
|
*** Return ''true'' if ''pk<sub>j</sub> = pk' '', otherwise return ''false''.
|
||||||
* Return ''false''
|
* Return ''false''
|
||||||
|
|
||||||
The algorithm ''KeyAggCoeff(pk<sub>1..u</sub>, i)'' is defined as:
|
The algorithm ''KeyAggCoeff(pk<sub>1..u</sub>, pk')'' is defined as:
|
||||||
* Let ''L = HashKeys(pk<sub>1..u</sub>)''.
|
* 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''.
|
* If ''IsSecond(pk<sub>1..u</sub>, pk')'':
|
||||||
|
** Return 1
|
||||||
|
* Return ''int(hash<sub>KeyAgg coefficient</sub>(L || pk')) mod n''
|
||||||
|
|
||||||
== Applications ==
|
== Applications ==
|
||||||
|
|
||||||
== Test Vectors and Reference Code ==
|
== 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'' function.
|
||||||
|
|
||||||
== Footnotes ==
|
== Footnotes ==
|
||||||
|
|
||||||
<references />
|
<references />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user