-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
musig: add key aggregation spec draft
- Loading branch information
Showing
1 changed file
with
103 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<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 MuSig coefficient is computed by hashing the key instead of key index because. 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 MuSig coefficient 1 which saves an exponentiation. | ||
|
||
=== 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 ≥ 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 = ±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 ≠ 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 ''sort(pk)'' | ||
** where ''pk<sub>i</sub> < pk<sub>j</sub>'' if for the smallest ''k'' such that ''pk<sub>i</sub>[k] &ne pk<sub>j</sub>[k]'' it holds that ''pk<sub>i</sub>[k] < pk<sub>j</sub>[k]''. | ||
==== 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> = ComputeCoefficient(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(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> ≠ pk<sub>1</sub>'': | ||
*** Return ''true'' if ''pk<sub>j</sub> = pk<sub>i</sub>'', otherwise return ''false''. | ||
* Return ''false'' | ||
The algorithm ''ComputeCoefficient(pk<sub>1..u</sub>, i)'' is defined as: | ||
* Let ''L = HashKeys(pk<sub>1..u</sub>)''. | ||
* Return ''int(hash<sub>MuSig coefficient</sub>(L || pk) mod n'' if ''IsSecond(pk<sub>1..u</sub>, i)'' ≠ 2, otherwise return 1. | ||
== Applications == | ||
|
||
== Test Vectors and Reference Code == | ||
|
||
== Footnotes == | ||
|
||
<references /> | ||
|
||
== Acknowledgements == |