musig: add user documentation
This commit is contained in:
parent
d5e22a59f6
commit
6b0b22bc89
189
src/modules/musig/musig.md
Normal file
189
src/modules/musig/musig.md
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
MuSig - Rogue-Key-Resistant Multisignatures Module
|
||||||
|
===========================
|
||||||
|
|
||||||
|
This module implements the MuSig [1] multisignature scheme. The majority of
|
||||||
|
the module is an API designed to be used by signing or auditing participants
|
||||||
|
in a multisignature scheme. This involves a somewhat complex state machine
|
||||||
|
and significant effort has been taken to prevent accidental misuse of the
|
||||||
|
API in ways that could lead to accidental signatures or loss of key material.
|
||||||
|
|
||||||
|
# Theory
|
||||||
|
|
||||||
|
In MuSig all participants contribute key material to a single signing key,
|
||||||
|
using the equation
|
||||||
|
|
||||||
|
P = sum_i µ_i * P_i
|
||||||
|
|
||||||
|
where `P_i` is the public key of the `i`th participant and `µ_i` is a so-called
|
||||||
|
_MuSig coefficient_ computed according to the following equation
|
||||||
|
|
||||||
|
C = H(P_1 || P_2 || ... || P_n)
|
||||||
|
µ_i = H(C || i)
|
||||||
|
|
||||||
|
where H is a hash function modelled as a random oracle.
|
||||||
|
|
||||||
|
To produce a multisignature `(s, R)` on a message `m` using verification key
|
||||||
|
`P`, signers act as follows:
|
||||||
|
|
||||||
|
1. Each computes a nonce, or ephemeral keypair, `(k_i, R_i)`. Every participant
|
||||||
|
communinicates `H(R_i)` to every other participant.
|
||||||
|
2. Upon receipt of every `H(R_i)`, each participant communicates `R_i` to every
|
||||||
|
other participant. The recipients check that each `R_i` is consistent with
|
||||||
|
the previously-communicated hash.
|
||||||
|
3. Each participant computes a combined nonce
|
||||||
|
R = sum_i R_i
|
||||||
|
and shared challenge
|
||||||
|
e = H(R || P || m)
|
||||||
|
and partial signature
|
||||||
|
s_i = k_i + µ_i*x_i*e
|
||||||
|
where `x_i` is the secret key corresponding to `P_i`.
|
||||||
|
|
||||||
|
The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`.
|
||||||
|
|
||||||
|
# API Usage
|
||||||
|
|
||||||
|
It is essential to security that signers use a unique uniformly random none for all
|
||||||
|
signing sessions, and that they do not reuse these nonces even in the case that a
|
||||||
|
signing session fails to complete. To that end, all signing state is encapsulated
|
||||||
|
in the data structure `secp256k1_musig_session`. The API does not expose any
|
||||||
|
functionality to serialize or deserialize this structure; it is designed to exist
|
||||||
|
only in memory.
|
||||||
|
|
||||||
|
Users who need to persist this structure must take additional security measures
|
||||||
|
which cannot be enforced by a C API. Some guidance is provided in the documentation
|
||||||
|
for this data structure in `include/secp256k1_musig.h`.
|
||||||
|
|
||||||
|
## Key Generation
|
||||||
|
|
||||||
|
To use MuSig, users must first compute their combined public key `P`, which is
|
||||||
|
suitable for use on a blockchain or other public key repository. They do this
|
||||||
|
by calling `secp256k1_musig_pubkey_combine`.
|
||||||
|
|
||||||
|
This function takes as input a list of public keys `P_i` in the argument
|
||||||
|
`pubkeys`. It outputs the combined public key `P` in the out-pointer `combined_pk`
|
||||||
|
and hash `C` in the out-pointer `pk_hash32`, if this pointer is non-NULL.
|
||||||
|
|
||||||
|
## Signing
|
||||||
|
|
||||||
|
A participant who wishes to sign a message (as opposed to observing/auditing the
|
||||||
|
signature process, which is also a supported mode) acts as follows.
|
||||||
|
|
||||||
|
### Signing Participant
|
||||||
|
|
||||||
|
1. Starts the session by calling `secp256k1_musig_session_initialize`. This
|
||||||
|
function outputs
|
||||||
|
* an initialized session state in the out-pointer `session`
|
||||||
|
* an array of initialized signer data in the out-pointer `signers`
|
||||||
|
* a commitment `H(R_i)` to a nonce in the out-pointer `nonce_commitment32`
|
||||||
|
It takes as input
|
||||||
|
* a unique session ID `session_id32`
|
||||||
|
* (optionally) a message to be signed `msg32`
|
||||||
|
* the combined public key output from `secp256k1_musig_pubkey_combine`
|
||||||
|
* the public key hash output from `secp256k1_musig_pubkey_combine`
|
||||||
|
* the signer's index `i` `my_index`
|
||||||
|
* the signer's secret key `seckey`
|
||||||
|
2. The signer then communicates `H(R_i)` to all other signers, and receives
|
||||||
|
commitments `H(R_j)` from all other signers `j`. These hashes are simply
|
||||||
|
length-32 byte arrays which can be communicated however is communicated.
|
||||||
|
3. Once all signers nonce commitments have been received, the signer records
|
||||||
|
these commitments with the function `secp256k1_musig_session_get_public_nonce`.
|
||||||
|
This function updates in place
|
||||||
|
* the session state `session`
|
||||||
|
* the array of signer data `signers`
|
||||||
|
taking in as input the list of commitments `commitments` and outputting the
|
||||||
|
signer's public nonce `R_i` in the out-pointer `nonce`.
|
||||||
|
4. The signer then communicates `R_i` to all other signers, and receives `R_j`
|
||||||
|
from each signer `j`. On receipt of a nonce `R_j` he calls the function
|
||||||
|
`secp256k1_musig_set_nonce` to record this fact. This function checks that
|
||||||
|
the received nonce is consistent with the previously-received nonce and will
|
||||||
|
return 0 in this case.
|
||||||
|
These nonces `R_i` are secp256k1 public keys; they should be serialized using
|
||||||
|
`secp256k1_ec_pubkey_serialize` and parsed with `secp256k1_ec_pubkey_parse`.
|
||||||
|
5. Once all nonces have been exchanged in this way, signers are able to compute
|
||||||
|
their partial signatures. They do so by calling `secp256k1_musig_session_combine_nonces`
|
||||||
|
which updates in place
|
||||||
|
* the session state `session`
|
||||||
|
* the array of signer data `signers`
|
||||||
|
It outputs an auxillary integer `nonce_is_negated` and has an auxillary input
|
||||||
|
`adaptor`. Both of these may be set to NULL for ordinary signing purposes.
|
||||||
|
If the signer did not provide a message to `secp256k1_musig_session_initialize`,
|
||||||
|
a message must be provided now by calling `secp256k1_musig_session_set_msg` which
|
||||||
|
updates the session state in place.
|
||||||
|
6. The signer computes a partial signature `s_i` using the function
|
||||||
|
`secp256k1_musig_partial_sign` which takes the session state as input and
|
||||||
|
partial signature as output.
|
||||||
|
7. The signer then communicates the partial signature `s_i` to all other signers, or
|
||||||
|
to a central coordinator. These partial signatures should be serialized using
|
||||||
|
`musig_partial_signature_serialize` and parsed using `musig_partial_signature_parse`.
|
||||||
|
8. Each signer calls `secp256k1_musig_partial_sig_verify` on the other signers' partial
|
||||||
|
signatures to verify their correctness. If only the validity of the final signature
|
||||||
|
is important, not assigning blame, this step can be skipped.
|
||||||
|
9. Any signer, or central coordinator, may combine the partial signatures to obtain
|
||||||
|
a complete signature using `secp256k1_musig_partial_sig_combine`. This function takes
|
||||||
|
a signing session and array of MuSig partial signatures, and outputs a single
|
||||||
|
Schnorr signature.
|
||||||
|
|
||||||
|
### Non-signing Participant
|
||||||
|
|
||||||
|
A participant who wants to verify the signing process but not actually contribute a
|
||||||
|
partial signature, may do so using the above instructions except for the following
|
||||||
|
changes:
|
||||||
|
|
||||||
|
1. A signing session should be produced using `musig_session_initialize_verifier`
|
||||||
|
rather than `musig_session_initialize`; this function takes no secret data or
|
||||||
|
signer index.
|
||||||
|
2. The participant receives nonce commitments, public nonces and partial signatures,
|
||||||
|
but does not produce these values. Therefore `secp256k1_musig_session_get_public_nonce`
|
||||||
|
and `secp256k1_musig_partial_sign` are not called.
|
||||||
|
|
||||||
|
### Verifier
|
||||||
|
|
||||||
|
The final signature is simply a valid Schnorr signature using the combined public key. It
|
||||||
|
can be verified using the `secp256k1_schnorrsig_verify` with the correct message and
|
||||||
|
public key output from `secp256k1_musig_pubkey_combine`.
|
||||||
|
|
||||||
|
## Atomic Swaps
|
||||||
|
|
||||||
|
The signing API supports the production of "adaptor signatures", modified partial signatures
|
||||||
|
which have an auxiliary secret encrypted to them. A partial signature is revealed to a party
|
||||||
|
who learns the secret; conversely, a party with the corresponding secret will learn the
|
||||||
|
secret.
|
||||||
|
|
||||||
|
Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in
|
||||||
|
parallel such that one party's partial signatures are made atomic. That is, when the other
|
||||||
|
party learns one partial signature, she automatically learns the other. This has applications
|
||||||
|
in cross-chain atomic swaps.
|
||||||
|
|
||||||
|
Such a protocol can be executed as follows. Consider two participants, Alice and Bob, who
|
||||||
|
are simultaneously producing 2-of-2 multisignatures for two blockchains A and B. They act
|
||||||
|
as follows.
|
||||||
|
|
||||||
|
1. Before the protocol begins, Bob chooses a 32-byte auxiliary secret `t` at random and
|
||||||
|
computes a corresponding public point `T` by calling `secp256k1_ec_pubkey_create`.
|
||||||
|
He communicates `T` to Alice.
|
||||||
|
2. Together, the parties execute steps 1-4 of the signing protocol above.
|
||||||
|
3. At step 5, when combining the two parties' public nonces, both parties call
|
||||||
|
`secp256k1_musig_session_combine_nonces` with `adaptor` set to `T` and `nonce_is_negated`
|
||||||
|
set to a non-NULL pointer to int.
|
||||||
|
4. Steps 6 and 7 proceed as before. Step 8, verifying the partial signatures, is now
|
||||||
|
essential to the security of the protocol and must not be omitted!
|
||||||
|
|
||||||
|
The above steps are executed identically for both signing sessions. However, step 9 will
|
||||||
|
not work as before, since the partial signatures will not add up to a valid total signature.
|
||||||
|
Additonal steps must be taken, and it is at this point that the two signing sessions
|
||||||
|
diverge. From here on we consider "Session A" which benefits Alice (e.g. which sends her
|
||||||
|
coins) and "Session B" which benefits Bob (e.g. which sends him coins).
|
||||||
|
|
||||||
|
5. In Session B, Bob calls `secp256k1_musig_partial_sig_adapt` with his partial signature
|
||||||
|
and `t`, to produce an adaptor signature. He can then call `secp256k1_musig_partial_sig_combine`
|
||||||
|
with this adaptor signature and Alice's partial signature, to produce a complete
|
||||||
|
signature for blockchain B.
|
||||||
|
6. Alice reads this signature from blockchain B. She calls `secp256k1_musig_extract_secret_adaptor`,
|
||||||
|
passing the complete signature along with her and Bob's partial signatures. This function
|
||||||
|
outputs `t`, which until this point was only known to Bob.
|
||||||
|
7. In Session A, Alice is now able to replicate Bob's action, calling
|
||||||
|
`secp256k1_musig_partial_sig_adapt` with her own partial signature and `t`, ultimately
|
||||||
|
producing a complete signature on blockchain A.
|
||||||
|
|
||||||
|
[1] https://eprint.iacr.org/2018/068
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user