-
Notifications
You must be signed in to change notification settings - Fork 226
musig: add user documentation #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
6b0b22b
0492592
8cab1c5
0512dd2
9125c16
792d504
89b7f5b
f6a6bca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. | ||
|
apoelstra marked this conversation as resolved.
|
||
|
|
||
| # Theory | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This paragraph uses "signers" and "participants" for the same thing. That's not necessarily bad it actually reminded me that there can be participants who are not signers (just listening -- and the code supports that). So maybe we should make that clearer.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah I see that distinction is made below, so yes, I think it should be made here too
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed this paragraph. |
||
| 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) | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| µ_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 | ||
|
apoelstra marked this conversation as resolved.
|
||
|
|
||
| It is essential to security that signers use a unique uniformly random none for all | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| `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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
jonasnick marked this conversation as resolved.
Outdated
|
||
| who learns the secret; conversely, a party with the corresponding secret will learn the | ||
| secret. | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
|
|
||
| Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in | ||
|
apoelstra marked this conversation as resolved.
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
apoelstra marked this conversation as resolved.
Outdated
|
||
| 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 | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.