diff --git a/doc/musig-spec.mediawiki b/doc/musig-spec.mediawiki
index 09ebd6c9..f94e5a7a 100644
--- a/doc/musig-spec.mediawiki
+++ b/doc/musig-spec.mediawiki
@@ -22,10 +22,11 @@ This document is licensed under the 2-clause BSD license.
=== 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 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 ===
@@ -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 ''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 ''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''[
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 = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 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''.] 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 = x3 + 7 mod p''.
@@ -67,34 +69,39 @@ The algorithm ''KeySort(pk1..u)'' is defined as:
==== Key Aggregation ====
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 ''pk1..u'': ''u'' 32-byte arrays
The algorithm ''KeyAgg(pk1..u)'' is defined as:
* For ''i = 1 .. u'':
-** Let ''ai = KeyAggCoeff(pk1..u, i)''.
+** Let ''ai = KeyAggCoeff(pk1..u, pki)''.
** Let ''Pi = lift_x(int(pki))''; fail if it fails.
-* Let ''S = a1⋅P1 + a2⋅P1 + ... + au⋅Pu''
-* Fail if ''is_infinite(S)''.
-* Return ''bytes(S)''.
+* Let ''Q = a1⋅P1 + a2⋅P1 + ... + au⋅Pu''
+* Fail if ''is_infinite(Q)''.
+* Return ''bytes(Q)''.
The algorithm ''HashKeys(pk1..u)'' is defined as:
* Return ''hashKeyAgg list(pk1 || pk2 || ... || pku)''
-The algorithm ''IsSecond(pk1..u, i)'' is defined as:
+The algorithm ''IsSecond(pk1..u, pk')'' is defined as:
* For ''j = 1 .. u'':
** If ''pkj ≠ pk1'':
-*** Return ''true'' if ''pkj = pki'', otherwise return ''false''.
+*** Return ''true'' if ''pkj = pk' '', otherwise return ''false''.
* Return ''false''
-The algorithm ''KeyAggCoeff(pk1..u, i)'' is defined as:
+The algorithm ''KeyAggCoeff(pk1..u, pk')'' is defined as:
* Let ''L = HashKeys(pk1..u)''.
-* Return 1 if ''IsSecond(pk1..u, i)'', otherwise return ''int(hashKeyAgg coefficient(L || pki) mod n''.
+* If ''IsSecond(pk1..u, pk')'':
+** Return 1
+* Return ''int(hashKeyAgg coefficient(L || pk')) mod n''
== 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'' function.
+
== Footnotes ==