diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index ead762d2..657bacab 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -7,6 +7,10 @@ * (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the * module's directory (src/modules/musig/example.c) that demonstrates how it can be * used. + * + * The documentation in this include file is for reference and may not be sufficient + * for users to begin using the library. A full description of API usage can be found + * in src/modules/musig/musig.md */ /** Data structure containing data related to a signing session resulting in a single @@ -15,22 +19,9 @@ * This structure is not opaque, but it MUST NOT be copied or read or written to it * directly. A signer who is online throughout the whole process and can keep this * structure in memory can use the provided API functions for a safe standard - * workflow. - * - * A signer who goes offline and needs to import/export or save/load this structure - * **must** take measures prevent replay attacks wherein an old state is loaded and - * the signing protocol forked from that point. One straightforward way to accomplish - * this is to attach the output of a monotonic non-resettable counter (hardware - * support is needed for this). Increment the counter before each output and - * encrypt+sign the entire package. If a package is deserialized with an old counter - * state or bad signature it should be rejected. - * - * Observe that an independent counter is needed for each concurrent signing session - * such a device is involved in. To avoid fragility, it is therefore recommended that - * any offline signer be usable for only a single session at once. - * - * Given access to such a counter, its output should be used as (or mixed into) the - * session ID to ensure uniqueness. + * workflow. See https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ + * for more details about the risks associated with serializing or deserializing this + * structure. * * Fields: * combined_pk: MuSig-computed combined public key diff --git a/src/modules/musig/musig.md b/src/modules/musig/musig.md new file mode 100644 index 00000000..015ce91b --- /dev/null +++ b/src/modules/musig/musig.md @@ -0,0 +1,199 @@ +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. + +The resulting signatures are valid Schnorr signatures as described in [2]. + +# Theory + +In MuSig all signers 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 signer and `µ_i` is a so-called +_MuSig coefficient_ computed according to the following equation + + L = H(P_1 || P_2 || ... || P_n) + µ_i = H(L || 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 signer + communicates `H(R_i)` to every participant (both signers and auditors). +2. Upon receipt of every `H(R_i)`, each signer communicates `R_i` to every + participant. The recipients check that each `R_i` is consistent with the + previously-communicated hash. +3. Each signer 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 + +The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`. + +It is essential to security that signers use a unique uniformly random nonce 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 `L` 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. The signer 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. The signer must also call this function with his own + nonce and his own index `i`. + 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 auxiliary integer `nonce_is_negated` and has an auxiliary 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, i.e. check that nonce commitments +are consistent and partial signatures are correct without contributing 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 are offset by an auxiliary secret known to one party. That is, +1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`. +2. When combining nonces, each party adds `T` to the total nonce used in the signature. +3. The party who knows `t` must "adapt" their partial signature with `t` to complete the + signature. +4. Any party who sees both the final signature and the original partial signatures + can compute `t`. + +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. +Additional 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 from Session B. + 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 +[2] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki +