Merge ElementsProject/secp256k1-zkp#131: Replace MuSig(1) module with MuSig2
ac1e36769dmusig: turn off multiexponentiation for now (Jonas Nick)3c79d97bd9ci: increase timeout for macOS tasks (Jonas Nick)22c88815c7musig: replace MuSig(1) with MuSig2 (Jonas Nick) Pull request description: The main commit comprises `905 insertions(+), 1253 deletions(-)`. The diff isn't as small as I had hoped, but that's mostly because it was possible to simplify the API quite substantially which required rewriting large parts. Sorry, almost all of the changes are in one big commit which makes the diff very hard to read. Perhaps best to re-review most parts from scratch. A few key changes: - Obviously no commitment round. No big session struct and no `verifier` sessions. No `signer` struct. - There's a new `secnonce` struct that is the output of musig_nonce_gen and derived from a uniformly random session_id32. The derivation can be strengthened by adding whatever session parameters (combined_pk, msg) are available. The nonce function is my ad-hoc construction that allows for these optional inputs. Please have a look at that. - The secnonce is made invalid after being used in partial_sign. - Adaptor signatures basically work as before, according to https://github.com/ElementsProject/scriptless-scripts/pull/24 (with the exception that they operate on aggregate instead of partial sigs) - To avoid making this PR overly complex I did not consider how this implementation interacts with nested-MuSig, sign-to-contract, and antiklepto. - Testing should be close to complete. There's no reachable line or branch that isn't exercised by the tests. - [x] ~In the current implementation when a signer sends an invalid nonce (i.e. some garbage that can't be mapped to a group element), it is ignored when combining nonces. Only after receiving the signers partial signature and running `partial_sig_verify` will we notice that the signer misbehaved. The reason for this is that 1) this makes the API simpler and 2) malicious peers don't gain any additional powers because they can always interrupt the protocol by refusing to sign. However, this is up for discussion.~ EDIT: this is not the case anymore since invalid nonces are rejected when they're parsed. - [x] ~For every partial signature we verify we have to parse the pubnonce (two compressed points), despite having parsed it in `process_nonces` already. This is not great. `process_nonces` could optionally output the array of parsed pubnonces.~ EDIT: fixed by having a dedicated type for nonces. - [x] ~I left `src/modules/musig/musig.md` unchanged for now. Perhaps we should merge it with the `musig-spec`~ EDIT: musig.md is updated - [x] partial verification should use multiexp to compute `R1 + b*R2 + c*P`, but this can be done in a separate PR - [x] renaming wishlist - pre_session -> keyagg_cache (because there is no session anymore) - pubkey_combine, nonce_combine, partial_sig_combine -> pubkey_agg, nonce_agg, partial_sig_agg (shorter, matches terminology in musig2) - musig_session_init -> musig_start (shorter, simpler) or [musig_generate_nonce](https://github.com/ElementsProject/secp256k1-zkp/pull/131#discussion_r654190890) or musig_prepare - musig_partial_signature to musig_partial_sig (shorter) - [x] perhaps remove pubnonces and n_pubnonces argument from process_nonces (and then also add a opaque type for the combined nonce?) - [x] write the `combined_pubkey` into the `pre_session` struct (as suggested [below](https://github.com/ElementsProject/secp256k1-zkp/pull/131#issuecomment-866904975): then 1) session_init and process_nonces don't need a combined_pk argument (and there can't be mix up between tweaked and untweaked keys) and 2) pubkey_tweak doesn't need an input_pubkey and the output_pubkey can be written directly into the pre_session (reducing frustration such as Replace MuSig(1) module with MuSig2 #131 (comment)) - [x] perhaps allow adapting both partial sigs (`partial_sig` struct) and aggregate partial sigs (64 raw bytes) as suggested [below](https://github.com/ElementsProject/secp256k1-zkp/pull/131#issuecomment-867281531). Based on #120. ACKs for top commit: robot-dreams: ACKac1e36769dreal-or-random: ACKac1e36769dTree-SHA512: 916b42811aa5c00649cfb923d2002422c338106a6936a01253ba693015a242f21f7f7b4cce60d5ab5764a129926c6fd6676977c69c9e6e0aedc51b308ac6578d
This commit is contained in:
@@ -1,16 +1,8 @@
|
||||
include_HEADERS += include/secp256k1_musig.h
|
||||
noinst_HEADERS += src/modules/musig/main_impl.h
|
||||
noinst_HEADERS += src/modules/musig/keyagg.h
|
||||
noinst_HEADERS += src/modules/musig/keyagg_impl.h
|
||||
noinst_HEADERS += src/modules/musig/session.h
|
||||
noinst_HEADERS += src/modules/musig/session_impl.h
|
||||
noinst_HEADERS += src/modules/musig/adaptor_impl.h
|
||||
noinst_HEADERS += src/modules/musig/tests_impl.h
|
||||
|
||||
noinst_PROGRAMS += example_musig
|
||||
example_musig_SOURCES = src/modules/musig/example.c
|
||||
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES)
|
||||
if !ENABLE_COVERAGE
|
||||
example_musig_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
example_musig_LDFLAGS = -static
|
||||
|
||||
if USE_TESTS
|
||||
TESTS += example_musig
|
||||
endif
|
||||
|
||||
101
src/modules/musig/adaptor_impl.h
Normal file
101
src/modules/musig/adaptor_impl.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H
|
||||
#define SECP256K1_MODULE_MUSIG_ADAPTOR_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "session.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
int secp256k1_musig_nonce_parity(const secp256k1_context* ctx, int *nonce_parity, const secp256k1_musig_session *session) {
|
||||
secp256k1_musig_session_internal session_i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(nonce_parity != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
return 0;
|
||||
}
|
||||
*nonce_parity = session_i.fin_nonce_parity;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_adapt(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *pre_sig64, const unsigned char *sec_adaptor32, int nonce_parity) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar t;
|
||||
int overflow;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pre_sig64 != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
ARG_CHECK(nonce_parity == 0 || nonce_parity == 1);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, &pre_sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow);
|
||||
ret &= !overflow;
|
||||
|
||||
/* Determine if the secret adaptor should be negated.
|
||||
*
|
||||
* The musig_session stores the X-coordinate and the parity of the "final nonce"
|
||||
* (r + t)*G, where r*G is the aggregate public nonce and t is the secret adaptor.
|
||||
*
|
||||
* Since a BIP340 signature requires an x-only public nonce, in the case where
|
||||
* (r + t)*G has odd Y-coordinate (i.e. nonce_parity == 1), the x-only public nonce
|
||||
* corresponding to the signature is actually (-r - t)*G. Thus adapting a
|
||||
* pre-signature requires negating t in this case.
|
||||
*/
|
||||
if (nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
|
||||
secp256k1_scalar_add(&s, &s, &t);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &s);
|
||||
memmove(sig64, pre_sig64, 32);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_musig_extract_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const unsigned char *pre_sig64, int nonce_parity) {
|
||||
secp256k1_scalar t;
|
||||
secp256k1_scalar s;
|
||||
int overflow;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(pre_sig64 != NULL);
|
||||
ARG_CHECK(nonce_parity == 0 || nonce_parity == 1);
|
||||
|
||||
secp256k1_scalar_set_b32(&t, &sig64[32], &overflow);
|
||||
ret &= !overflow;
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, &pre_sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&t, &t, &s);
|
||||
|
||||
if (!nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
secp256k1_scalar_get_b32(sec_adaptor32, &t);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
/**
|
||||
* This file demonstrates how to use the MuSig module to create a multisignature.
|
||||
* Additionally, see the documentation in include/secp256k1_musig.h.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
#include <secp256k1_musig.h>
|
||||
|
||||
/* Number of public keys involved in creating the aggregate signature */
|
||||
#define N_SIGNERS 3
|
||||
/* Create a key pair and store it in seckey and pubkey */
|
||||
int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) {
|
||||
int ret;
|
||||
secp256k1_keypair keypair;
|
||||
FILE *frand = fopen("/dev/urandom", "r");
|
||||
if (frand == NULL) {
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
if(!fread(seckey, 32, 1, frand)) {
|
||||
fclose(frand);
|
||||
return 0;
|
||||
}
|
||||
/* The probability that this not a valid secret key is approximately 2^-128 */
|
||||
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
|
||||
fclose(frand);
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
|
||||
ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey** pubkeys, const unsigned char* msg32, unsigned char *sig64) {
|
||||
secp256k1_musig_session musig_session[N_SIGNERS];
|
||||
unsigned char nonce_commitment[N_SIGNERS][32];
|
||||
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
|
||||
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS];
|
||||
unsigned char nonce[N_SIGNERS][32];
|
||||
int i, j;
|
||||
secp256k1_musig_partial_signature partial_sig[N_SIGNERS];
|
||||
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
FILE *frand;
|
||||
unsigned char session_id32[32];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
|
||||
/* Create combined pubkey and initialize signer data */
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) {
|
||||
return 0;
|
||||
}
|
||||
/* Create random session ID. It is absolutely necessary that the session ID
|
||||
* is unique for every call of secp256k1_musig_session_init. Otherwise
|
||||
* it's trivial for an attacker to extract the secret key! */
|
||||
frand = fopen("/dev/urandom", "r");
|
||||
if(frand == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (!fread(session_id32, 32, 1, frand)) {
|
||||
fclose(frand);
|
||||
return 0;
|
||||
}
|
||||
fclose(frand);
|
||||
/* Initialize session */
|
||||
if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, seckeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
|
||||
}
|
||||
/* Communication round 1: Exchange nonce commitments */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* Set nonce commitments in the signer data and get the own public nonce */
|
||||
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Communication round 2: Exchange nonces */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
for (j = 0; j < N_SIGNERS; j++) {
|
||||
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], nonce[j])) {
|
||||
/* Signer j's nonce does not match the nonce commitment. In this case
|
||||
* abort the protocol. If you make another attempt at finishing the
|
||||
* protocol, create a new session (with a fresh session ID!). */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Communication round 3: Exchange partial signatures */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
for (j = 0; j < N_SIGNERS; j++) {
|
||||
/* To check whether signing was successful, it suffices to either verify
|
||||
* the combined signature with the combined public key using
|
||||
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
|
||||
* signers individually. Verifying the combined signature is cheaper but
|
||||
* verifying the individual partial signatures has the advantage that it
|
||||
* can be used to determine which of the partial signatures are invalid
|
||||
* (if any), i.e., which of the partial signatures cause the combined
|
||||
* signature to be invalid and thus the protocol run to fail. It's also
|
||||
* fine to first verify the combined sig, and only verify the individual
|
||||
* sigs if it does not work.
|
||||
*/
|
||||
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], pubkeys[j])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
int i;
|
||||
unsigned char seckeys[N_SIGNERS][32];
|
||||
secp256k1_xonly_pubkey pubkeys[N_SIGNERS];
|
||||
const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create a context for signing and verification */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
printf("Creating key pairs......");
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
pubkeys_ptr[i] = &pubkeys[i];
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Combining public keys...");
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
if (!sign(ctx, seckeys, pubkeys_ptr, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Verifying signature.....");
|
||||
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &combined_pk)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
34
src/modules/musig/keyagg.h
Normal file
34
src/modules/musig/keyagg.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||
#define SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "../../field.h"
|
||||
#include "../../group.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_fe second_pk_x;
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_scalar tweak;
|
||||
int internal_key_parity;
|
||||
} secp256k1_keyagg_cache_internal;
|
||||
|
||||
/* Requires that the saved point is not infinity */
|
||||
static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge);
|
||||
|
||||
static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data);
|
||||
|
||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
||||
|
||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x);
|
||||
|
||||
#endif
|
||||
283
src/modules/musig/keyagg_impl.h
Normal file
283
src/modules/musig/keyagg_impl.h
Normal file
@@ -0,0 +1,283 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||
#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "keyagg.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../ecmult.h"
|
||||
#include "../../field.h"
|
||||
#include "../../group.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../util.h"
|
||||
|
||||
static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge) {
|
||||
if (sizeof(secp256k1_ge_storage) == 64) {
|
||||
secp256k1_ge_storage s;
|
||||
secp256k1_ge_to_storage(&s, ge);
|
||||
memcpy(data, &s, sizeof(s));
|
||||
} else {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
|
||||
secp256k1_fe_normalize_var(&ge->x);
|
||||
secp256k1_fe_normalize_var(&ge->y);
|
||||
secp256k1_fe_get_b32(data, &ge->x);
|
||||
secp256k1_fe_get_b32(data + 32, &ge->y);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) {
|
||||
if (sizeof(secp256k1_ge_storage) == 64) {
|
||||
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
|
||||
* representation as conversion is very fast. */
|
||||
secp256k1_ge_storage s;
|
||||
memcpy(&s, data, sizeof(s));
|
||||
secp256k1_ge_from_storage(ge, &s);
|
||||
} else {
|
||||
/* Otherwise, fall back to 32-byte big endian for X and Y. */
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_fe_set_b32(&x, data);
|
||||
secp256k1_fe_set_b32(&y, data + 32);
|
||||
secp256k1_ge_set_xy(ge, &x, &y);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
||||
|
||||
/* A keyagg cache consists of
|
||||
* - 4 byte magic set during initialization to allow detecting an uninitialized
|
||||
* object.
|
||||
* - 64 byte aggregate (and potentially tweaked) public key
|
||||
* - 32 byte X-coordinate of "second" public key (0 if not present)
|
||||
* - 32 byte hash of all public keys
|
||||
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
|
||||
* - 32 byte tweak
|
||||
*/
|
||||
/* Requires that cache_i->pk is not infinity and cache_i->second_pk_x to be normalized. */
|
||||
static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, secp256k1_keyagg_cache_internal *cache_i) {
|
||||
unsigned char *ptr = cache->data;
|
||||
memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4);
|
||||
ptr += 4;
|
||||
secp256k1_point_save(ptr, &cache_i->pk);
|
||||
ptr += 64;
|
||||
secp256k1_fe_get_b32(ptr, &cache_i->second_pk_x);
|
||||
ptr += 32;
|
||||
memcpy(ptr, cache_i->pk_hash, 32);
|
||||
ptr += 32;
|
||||
*ptr = cache_i->internal_key_parity;
|
||||
ptr += 1;
|
||||
secp256k1_scalar_get_b32(ptr, &cache_i->tweak);
|
||||
}
|
||||
|
||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) {
|
||||
const unsigned char *ptr = cache->data;
|
||||
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0);
|
||||
ptr += 4;
|
||||
secp256k1_point_load(&cache_i->pk, ptr);
|
||||
ptr += 64;
|
||||
secp256k1_fe_set_b32(&cache_i->second_pk_x, ptr);
|
||||
ptr += 32;
|
||||
memcpy(cache_i->pk_hash, ptr, 32);
|
||||
ptr += 32;
|
||||
cache_i->internal_key_parity = *ptr & 1;
|
||||
ptr += 1;
|
||||
secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */
|
||||
static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
|
||||
sha->s[0] = 0xb399d5e0ul;
|
||||
sha->s[1] = 0xc8fff302ul;
|
||||
sha->s[2] = 0x6badac71ul;
|
||||
sha->s[3] = 0x07c5b7f1ul;
|
||||
sha->s[4] = 0x9701e2eful;
|
||||
sha->s[5] = 0x2a72ecf8ul;
|
||||
sha->s[6] = 0x201a4c7bul;
|
||||
sha->s[7] = 0xab148a38ul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */
|
||||
static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_xonly_pubkey * const* pk, size_t np) {
|
||||
secp256k1_sha256 sha;
|
||||
size_t i;
|
||||
|
||||
secp256k1_musig_keyagglist_sha256(&sha);
|
||||
for (i = 0; i < np; i++) {
|
||||
unsigned char ser[32];
|
||||
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, ser, 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, pk_hash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */
|
||||
static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
|
||||
sha->s[0] = 0x6ef02c5aul;
|
||||
sha->s[1] = 0x06a480deul;
|
||||
sha->s[2] = 0x1f298665ul;
|
||||
sha->s[3] = 0x1d1134f2ul;
|
||||
sha->s[4] = 0x56a0b063ul;
|
||||
sha->s[5] = 0x52da4147ul;
|
||||
sha->s[6] = 0xf280d9d4ul;
|
||||
sha->s[7] = 0x4484be15ul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
||||
* tagged_hash(pk_hash, x) where pk_hash is the hash of public keys otherwise.
|
||||
* second_pk_x can be 0 in case there is no second_pk. Assumes both field
|
||||
* elements x and second_pk_x are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, const secp256k1_fe *x, const secp256k1_fe *second_pk_x) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[32];
|
||||
|
||||
if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) {
|
||||
secp256k1_scalar_set_int(r, 1);
|
||||
} else {
|
||||
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||
secp256k1_sha256_write(&sha, pk_hash, 32);
|
||||
secp256k1_fe_get_b32(buf, x);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Assumes both field elements x and second_pk_x are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x) {
|
||||
secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, x, &cache_i->second_pk_x);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
/* pk_hash is the hash of the public keys */
|
||||
unsigned char pk_hash[32];
|
||||
const secp256k1_xonly_pubkey * const* pks;
|
||||
secp256k1_fe second_pk_x;
|
||||
} secp256k1_musig_pubkey_agg_ecmult_data;
|
||||
|
||||
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
|
||||
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
|
||||
int ret;
|
||||
ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
||||
/* pubkey_load can't fail because the same pks have already been loaded in
|
||||
* `musig_compute_pk_hash` (and we test this). */
|
||||
VERIFY_CHECK(ret);
|
||||
secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, &pt->x, &ctx->second_pk_x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge pkp;
|
||||
size_t i;
|
||||
(void) scratch;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
if (agg_pk != NULL) {
|
||||
memset(agg_pk, 0, sizeof(*agg_pk));
|
||||
}
|
||||
ARG_CHECK(pubkeys != NULL);
|
||||
ARG_CHECK(n_pubkeys > 0);
|
||||
|
||||
ecmult_data.ctx = ctx;
|
||||
ecmult_data.pks = pubkeys;
|
||||
/* No point on the curve has an X coordinate equal to 0 */
|
||||
secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0);
|
||||
for (i = 1; i < n_pubkeys; i++) {
|
||||
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
||||
secp256k1_ge pt;
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
ecmult_data.second_pk_x = pt.x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_compute_pk_hash(ctx, ecmult_data.pk_hash, pubkeys, n_pubkeys)) {
|
||||
return 0;
|
||||
}
|
||||
/* TODO: actually use optimized ecmult_multi algorithms by providing a
|
||||
* scratch space */
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) {
|
||||
/* In order to reach this line with the current implementation of
|
||||
* ecmult_multi_var one would need to provide a callback that can
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||
secp256k1_fe_normalize_var(&pkp.y);
|
||||
/* The resulting public key is infinity with negligible probability */
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp));
|
||||
if (keyagg_cache != NULL) {
|
||||
secp256k1_keyagg_cache_internal cache_i = { 0 };
|
||||
cache_i.pk = pkp;
|
||||
cache_i.second_pk_x = ecmult_data.second_pk_x;
|
||||
memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash));
|
||||
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||
}
|
||||
|
||||
secp256k1_extrakeys_ge_even_y(&pkp);
|
||||
if (agg_pk != NULL) {
|
||||
secp256k1_xonly_pubkey_save(agg_pk, &pkp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
int overflow = 0;
|
||||
secp256k1_scalar tweak;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
if (output_pubkey != NULL) {
|
||||
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||
}
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&tweak, tweak32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (secp256k1_extrakeys_ge_even_y(&cache_i.pk)) {
|
||||
cache_i.internal_key_parity ^= 1;
|
||||
secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak);
|
||||
}
|
||||
secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak);
|
||||
if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk));
|
||||
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||
if (output_pubkey != NULL) {
|
||||
secp256k1_pubkey_save(output_pubkey, &cache_i.pk);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,735 +4,11 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
#define _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
#ifndef SECP256K1_MODULE_MUSIG_MAIN
|
||||
#define SECP256K1_MODULE_MUSIG_MAIN
|
||||
|
||||
#include <stdint.h>
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_musig.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */
|
||||
static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
|
||||
sha->s[0] = 0xb399d5e0ul;
|
||||
sha->s[1] = 0xc8fff302ul;
|
||||
sha->s[2] = 0x6badac71ul;
|
||||
sha->s[3] = 0x07c5b7f1ul;
|
||||
sha->s[4] = 0x9701e2eful;
|
||||
sha->s[5] = 0x2a72ecf8ul;
|
||||
sha->s[6] = 0x201a4c7bul;
|
||||
sha->s[7] = 0xab148a38ul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
|
||||
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey * const* pk, size_t np) {
|
||||
secp256k1_sha256 sha;
|
||||
size_t i;
|
||||
|
||||
secp256k1_musig_keyagglist_sha256(&sha);
|
||||
for (i = 0; i < np; i++) {
|
||||
unsigned char ser[32];
|
||||
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, ser, 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, ell);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */
|
||||
static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
|
||||
sha->s[0] = 0x6ef02c5aul;
|
||||
sha->s[1] = 0x06a480deul;
|
||||
sha->s[2] = 0x1f298665ul;
|
||||
sha->s[3] = 0x1d1134f2ul;
|
||||
sha->s[4] = 0x56a0b063ul;
|
||||
sha->s[5] = 0x52da4147ul;
|
||||
sha->s[6] = 0xf280d9d4ul;
|
||||
sha->s[7] = 0x4484be15ul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
||||
* SHA256(ell, x) otherwise. second_pk_x can be NULL in case there is no
|
||||
* second_pk. Assumes both field elements x and second_pk_x are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *ell, secp256k1_fe *x, const secp256k1_fe *second_pk_x) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[32];
|
||||
|
||||
if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) {
|
||||
secp256k1_scalar_set_int(r, 1);
|
||||
} else {
|
||||
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||
secp256k1_sha256_write(&sha, ell, 32);
|
||||
secp256k1_fe_get_b32(buf, x);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes both field elements x and second_pk_x are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_musig_pre_session *pre_session, secp256k1_fe *x) {
|
||||
secp256k1_fe second_pk_x;
|
||||
secp256k1_fe_set_b32(&second_pk_x, pre_session->second_pk);
|
||||
secp256k1_musig_keyaggcoef_internal(r, pre_session->pk_hash, x, &second_pk_x);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
unsigned char ell[32];
|
||||
const secp256k1_xonly_pubkey * const* pks;
|
||||
secp256k1_fe second_pk_x;
|
||||
} secp256k1_musig_pubkey_combine_ecmult_data;
|
||||
|
||||
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
|
||||
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
|
||||
int ret;
|
||||
ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
||||
/* pubkey_load can't fail because the same pks have already been loaded (and
|
||||
* we test this) */
|
||||
VERIFY_CHECK(ret);
|
||||
secp256k1_musig_keyaggcoef_internal(sc, ctx->ell, &pt->x, &ctx->second_pk_x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
memset(&signers[i], 0, sizeof(signers[i]));
|
||||
signers[i].present = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL;
|
||||
|
||||
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge pkp;
|
||||
int pk_parity;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pubkeys != NULL);
|
||||
ARG_CHECK(n_pubkeys > 0);
|
||||
|
||||
ecmult_data.ctx = ctx;
|
||||
ecmult_data.pks = pubkeys;
|
||||
/* No point on the curve has an X coordinate equal to 0 */
|
||||
secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0);
|
||||
for (i = 1; i < n_pubkeys; i++) {
|
||||
secp256k1_ge pt;
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
||||
ecmult_data.second_pk_x = pt.x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
|
||||
/* The current implementation of ecmult_multi_var makes this code unreachable with tests. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||
secp256k1_fe_normalize_var(&pkp.y);
|
||||
pk_parity = secp256k1_extrakeys_ge_even_y(&pkp);
|
||||
secp256k1_xonly_pubkey_save(combined_pk, &pkp);
|
||||
|
||||
if (pre_session != NULL) {
|
||||
pre_session->magic = pre_session_magic;
|
||||
memcpy(pre_session->pk_hash, ecmult_data.ell, 32);
|
||||
pre_session->pk_parity = pk_parity;
|
||||
pre_session->is_tweaked = 0;
|
||||
secp256k1_fe_get_b32(pre_session->second_pk, &ecmult_data.second_pk_x);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_musig_pre_session *pre_session, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
/* This function can only be called once because otherwise signing would not
|
||||
* succeed */
|
||||
ARG_CHECK(pre_session->is_tweaked == 0);
|
||||
|
||||
pre_session->internal_key_parity = pre_session->pk_parity;
|
||||
if(!secp256k1_xonly_pubkey_tweak_add(ctx, output_pubkey, internal_pubkey, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pre_session->tweak, tweak32, 32);
|
||||
pre_session->is_tweaked = 1;
|
||||
|
||||
ret = secp256k1_pubkey_load(ctx, &pk, output_pubkey);
|
||||
/* Successful xonly_pubkey_tweak_add always returns valid output_pubkey */
|
||||
VERIFY_CHECK(ret);
|
||||
|
||||
pre_session->pk_parity = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const uint64_t session_magic = 0xd92e6fc1ee41b4cbUL;
|
||||
|
||||
int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, const unsigned char *seckey) {
|
||||
unsigned char combined_ser[32];
|
||||
int overflow;
|
||||
secp256k1_scalar secret;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_gej pj;
|
||||
secp256k1_ge p;
|
||||
unsigned char nonce_ser[32];
|
||||
size_t nonce_ser_size = sizeof(nonce_ser);
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(nonce_commitment32 != NULL);
|
||||
ARG_CHECK(session_id32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ARG_CHECK(n_signers > 0);
|
||||
ARG_CHECK(n_signers <= UINT32_MAX);
|
||||
|
||||
memset(session, 0, sizeof(*session));
|
||||
|
||||
session->magic = session_magic;
|
||||
if (msg32 != NULL) {
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->is_msg_set = 1;
|
||||
} else {
|
||||
session->is_msg_set = 0;
|
||||
}
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
session->pre_session = *pre_session;
|
||||
session->has_secret_data = 1;
|
||||
session->n_signers = (uint32_t) n_signers;
|
||||
secp256k1_musig_signers_init(signers, session->n_signers);
|
||||
|
||||
/* Compute secret key */
|
||||
secp256k1_scalar_set_b32(&secret, seckey, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_fe_normalize_var(&p.x);
|
||||
secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &p.x);
|
||||
/* Compute the signer's public key point and determine if the secret is
|
||||
* negated before signing. That happens if if the signer's pubkey has an odd
|
||||
* Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR
|
||||
* (if tweaked) the internal key has an odd Y coordinate.
|
||||
*
|
||||
* This can be seen by looking at the secret key belonging to `combined_pk`.
|
||||
* Let's define
|
||||
* P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
|
||||
* point x_i*G, mu_i is the i-th KeyAgg coefficient and |.| is a function
|
||||
* that normalizes a point to an even Y by negating if necessary similar to
|
||||
* secp256k1_extrakeys_ge_even_y. Then we have
|
||||
* P := |P'| + t*G where t is the tweak.
|
||||
* And the combined xonly public key is
|
||||
* |P| = x*G
|
||||
* where x = sum_i(b_i*mu_i*x_i) + b'*t
|
||||
* b' = -1 if P != |P|, 1 otherwise
|
||||
* b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) and 1
|
||||
* otherwise.
|
||||
*/
|
||||
secp256k1_fe_normalize_var(&p.y);
|
||||
if((secp256k1_fe_is_odd(&p.y)
|
||||
+ session->pre_session.pk_parity
|
||||
+ (session->pre_session.is_tweaked
|
||||
&& session->pre_session.internal_key_parity))
|
||||
% 2 == 1) {
|
||||
secp256k1_scalar_negate(&secret, &secret);
|
||||
}
|
||||
secp256k1_scalar_mul(&secret, &secret, &mu);
|
||||
secp256k1_scalar_get_b32(session->seckey, &secret);
|
||||
|
||||
/* Compute secret nonce */
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, session_id32, 32);
|
||||
if (session->is_msg_set) {
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
}
|
||||
secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk);
|
||||
secp256k1_sha256_write(&sha, combined_ser, 32);
|
||||
secp256k1_sha256_write(&sha, seckey, 32);
|
||||
secp256k1_sha256_finalize(&sha, session->secnonce);
|
||||
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute public nonce and commitment */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_fe_normalize_var(&p.y);
|
||||
session->partial_nonce_parity = secp256k1_extrakeys_ge_even_y(&p);
|
||||
secp256k1_xonly_pubkey_save(&session->nonce, &p);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
|
||||
secp256k1_sha256_write(&sha, nonce_ser, nonce_ser_size);
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitment32);
|
||||
|
||||
session->round = 0;
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char nonce_commitments_hash[32];
|
||||
size_t i;
|
||||
unsigned char nonce_ser[32];
|
||||
size_t nonce_ser_size = sizeof(nonce_ser);
|
||||
(void) ctx;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(commitments != NULL);
|
||||
|
||||
ARG_CHECK(session->round == 0);
|
||||
/* If the message was not set during initialization it must be set now. */
|
||||
ARG_CHECK(!(!session->is_msg_set && msg32 == NULL));
|
||||
/* The message can only be set once. */
|
||||
ARG_CHECK(!(session->is_msg_set && msg32 != NULL));
|
||||
ARG_CHECK(session->has_secret_data);
|
||||
ARG_CHECK(n_commitments == session->n_signers);
|
||||
for (i = 0; i < n_commitments; i++) {
|
||||
ARG_CHECK(commitments[i] != NULL);
|
||||
}
|
||||
|
||||
if (msg32 != NULL) {
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->is_msg_set = 1;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
for (i = 0; i < n_commitments; i++) {
|
||||
memcpy(signers[i].nonce_commitment, commitments[i], 32);
|
||||
secp256k1_sha256_write(&sha, commitments[i], 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
|
||||
memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32);
|
||||
|
||||
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
|
||||
memcpy(nonce, &nonce_ser, nonce_ser_size);
|
||||
session->round = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_init_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) {
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(commitments != NULL);
|
||||
/* Check n_signers before checking commitments to allow testing the case where
|
||||
* n_signers is big without allocating the space. */
|
||||
ARG_CHECK(n_signers > 0);
|
||||
ARG_CHECK(n_signers <= UINT32_MAX);
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
ARG_CHECK(commitments[i] != NULL);
|
||||
}
|
||||
(void) ctx;
|
||||
|
||||
memset(session, 0, sizeof(*session));
|
||||
|
||||
session->magic = session_magic;
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
session->pre_session = *pre_session;
|
||||
session->n_signers = (uint32_t) n_signers;
|
||||
secp256k1_musig_signers_init(signers, session->n_signers);
|
||||
|
||||
session->pre_session = *pre_session;
|
||||
session->is_msg_set = 1;
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->has_secret_data = 0;
|
||||
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
memcpy(signers[i].nonce_commitment, commitments[i], 32);
|
||||
}
|
||||
session->round = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const unsigned char *nonce) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char commit[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(signer != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, nonce, 32);
|
||||
secp256k1_sha256_finalize(&sha, commit);
|
||||
|
||||
if (memcmp(commit, signer->nonce_commitment, 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&signer->nonce, nonce, sizeof(*nonce));
|
||||
if (!secp256k1_xonly_pubkey_parse(ctx, &signer->nonce, nonce)) {
|
||||
return 0;
|
||||
}
|
||||
signer->present = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_parity, const secp256k1_pubkey *adaptor) {
|
||||
secp256k1_gej combined_noncej;
|
||||
secp256k1_ge combined_noncep;
|
||||
secp256k1_ge noncep;
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char nonce_commitments_hash[32];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 1);
|
||||
ARG_CHECK(n_signers == session->n_signers);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_gej_set_infinity(&combined_noncej);
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
if (!signers[i].present) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32);
|
||||
secp256k1_xonly_pubkey_load(ctx, &noncep, &signers[i].nonce);
|
||||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
|
||||
/* If the signers' commitments changed between get_public_nonce and now we
|
||||
* have to abort because in that case they may have seen our nonce before
|
||||
* creating their commitment. That can happen if the signer_data given to
|
||||
* this function is different to the signer_data given to get_public_nonce.
|
||||
* */
|
||||
if (session->has_secret_data
|
||||
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add public adaptor to nonce */
|
||||
if (adaptor != NULL) {
|
||||
secp256k1_pubkey_load(ctx, &noncep, adaptor);
|
||||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
|
||||
}
|
||||
|
||||
/* Negate nonce if Y coordinate is not square */
|
||||
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
|
||||
secp256k1_fe_normalize_var(&combined_noncep.y);
|
||||
session->combined_nonce_parity = secp256k1_extrakeys_ge_even_y(&combined_noncep);
|
||||
if (nonce_parity != NULL) {
|
||||
*nonce_parity = session->combined_nonce_parity;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(&session->combined_nonce, &combined_noncep);
|
||||
session->round = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
memcpy(out32, sig->data, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(in32 != NULL);
|
||||
memcpy(sig->data, in32, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */
|
||||
static void secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_ge rp;
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
VERIFY_CHECK(session->round >= 2);
|
||||
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_xonly_pubkey_load(ctx, &rp, &session->combined_nonce);
|
||||
secp256k1_fe_get_b32(buf, &rp.x);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
|
||||
secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_write(&sha, session->msg, 32);
|
||||
secp256k1_sha256_finalize(&sha, msghash);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) {
|
||||
unsigned char msghash[32];
|
||||
int overflow;
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar e, k;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
ARG_CHECK(session->has_secret_data);
|
||||
|
||||
/* build message hash */
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&sk, session->seckey, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&k, session->secnonce, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&k)) {
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_scalar_clear(&k);
|
||||
return 0;
|
||||
}
|
||||
if (session->partial_nonce_parity != session->combined_nonce_parity) {
|
||||
secp256k1_scalar_negate(&k, &k);
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
secp256k1_scalar_mul(&e, &e, &sk);
|
||||
secp256k1_scalar_add(&e, &e, &k);
|
||||
secp256k1_scalar_get_b32(&partial_sig->data[0], &e);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_scalar_clear(&k);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
|
||||
size_t i;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_ge noncep;
|
||||
(void) ctx;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
|
||||
if (n_sigs != session->n_signers) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_clear(&s);
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
int overflow;
|
||||
secp256k1_scalar term;
|
||||
|
||||
secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &term);
|
||||
}
|
||||
|
||||
/* If there is a tweak then add (or subtract) `msghash` times `tweak` to `s`.*/
|
||||
if (session->pre_session.is_tweaked) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar e, scalar_tweak;
|
||||
int overflow = 0;
|
||||
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, session->pre_session.tweak, &overflow);
|
||||
if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) {
|
||||
/* This mimics the behavior of secp256k1_ec_seckey_tweak_mul regarding
|
||||
* overflow and tweak being 0. */
|
||||
return 0;
|
||||
}
|
||||
if (session->pre_session.pk_parity) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &e);
|
||||
}
|
||||
|
||||
secp256k1_xonly_pubkey_load(ctx, &noncep, &session->combined_nonce);
|
||||
VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y));
|
||||
secp256k1_fe_normalize(&noncep.x);
|
||||
secp256k1_fe_get_b32(&sig64[0], &noncep.x);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pkp;
|
||||
secp256k1_ge rp;
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signer != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
ARG_CHECK(signer->present);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
/* Multiplying the messagehash by the KeyAgg coefficient is equivalent
|
||||
* to multiplying the signer's public key by the coefficient, except
|
||||
* much easier to do. */
|
||||
secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &pkp.x);
|
||||
secp256k1_scalar_mul(&e, &e, &mu);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &rp, &signer->nonce)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the MuSig-combined point has an odd Y coordinate, the signers will
|
||||
* sign for the negation of their individual xonly public key such that the
|
||||
* combined signature is valid for the MuSig aggregated xonly key. If the
|
||||
* MuSig-combined point was tweaked then `e` is negated if the combined key
|
||||
* has an odd Y coordinate XOR the internal key has an odd Y coordinate.*/
|
||||
if (session->pre_session.pk_parity
|
||||
!= (session->pre_session.is_tweaked
|
||||
&& session->pre_session.internal_key_parity)) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
secp256k1_ecmult(&rj, &pkj, &e, &s);
|
||||
|
||||
if (!session->combined_nonce_parity) {
|
||||
secp256k1_ge_neg(&rp, &rp);
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL);
|
||||
|
||||
return secp256k1_gej_is_infinity(&rj);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_parity) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar t;
|
||||
int overflow;
|
||||
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(adaptor_sig != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
|
||||
secp256k1_scalar_add(&s, &s, &t);
|
||||
secp256k1_scalar_get_b32(adaptor_sig->data, &s);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_parity) {
|
||||
secp256k1_scalar t;
|
||||
secp256k1_scalar s;
|
||||
int overflow;
|
||||
size_t i;
|
||||
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&t, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
|
||||
for (i = 0; i < n_partial_sigs; i++) {
|
||||
secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&t, &t, &s);
|
||||
}
|
||||
|
||||
if (!nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
secp256k1_scalar_get_b32(sec_adaptor32, &t);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 1;
|
||||
}
|
||||
#include "keyagg_impl.h"
|
||||
#include "session_impl.h"
|
||||
#include "adaptor_impl.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,198 +1,63 @@
|
||||
MuSig - Rogue-Key-Resistant Multisignatures Module
|
||||
Notes on the musig module API
|
||||
===========================
|
||||
|
||||
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 following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`).
|
||||
A usage example can be found in `examples/musig.c`.
|
||||
|
||||
The resulting signatures are valid Schnorr signatures as described in [2].
|
||||
# API misuse
|
||||
|
||||
# Theory
|
||||
The musig API is designed to be as misuse resistant as possible.
|
||||
However, the MuSig protocol has some additional failure modes (mainly due to interactivity) that do not appear in single-signing.
|
||||
While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to rule out all such failure modes.
|
||||
|
||||
In MuSig all signers contribute key material to a single signing key,
|
||||
using the equation
|
||||
Therefore, users of the musig module must take great care to make sure of the following:
|
||||
|
||||
P = sum_i µ_i * P_i
|
||||
1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`.
|
||||
See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that.
|
||||
2. The `secp256k1_musig_secnonce` structure is never copied or serialized.
|
||||
See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`.
|
||||
3. Opaque data structures are never written to or read from directly.
|
||||
Instead, only the provided accessor functions are used.
|
||||
4. If adaptor signatures are used, all partial signatures are verified.
|
||||
|
||||
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
|
||||
# Key Aggregation and (Taproot) Tweaking
|
||||
|
||||
L = H(P_1 || P_2 || ... || P_n)
|
||||
µ_i = H(L || i)
|
||||
Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`.
|
||||
A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly_pubkey_tweak_add`.
|
||||
|
||||
where H is a hash function modelled as a random oracle.
|
||||
# Signing
|
||||
|
||||
To produce a multisignature `(s, R)` on a message `m` using verification key
|
||||
`P`, signers act as follows:
|
||||
This is covered by `examples/musig.c`.
|
||||
Essentially, the protocol proceeds in the following steps:
|
||||
|
||||
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`.
|
||||
1. Generate a keypair with `secp256k1_keypair_create` and obtain the xonly public key with `secp256k1_keypair_xonly_pub`.
|
||||
2. Call `secp256k1_musig_pubkey_agg` with the xonly pubkeys of all participants.
|
||||
3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_tweak_add`.
|
||||
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
|
||||
5. Someone (not necessarily the signer) aggregates the public nonce with `secp256k1_musig_nonce_agg` and sends it to the signers.
|
||||
6. Process the aggregate nonce with `secp256k1_musig_nonce_process`.
|
||||
7. Create a partial signature with `secp256k1_musig_partial_sign`.
|
||||
8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`.
|
||||
9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`.
|
||||
|
||||
The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`.
|
||||
The aggregate signature can be verified with `secp256k1_schnorrsig_verify`.
|
||||
|
||||
# API Usage
|
||||
Note that steps 1 to 6 can happen before the message to be signed is known to the signers.
|
||||
Therefore, the communication round to exchange nonces can be viewed as a pre-processing step that is run whenever convenient to the signers.
|
||||
This disables some of the defense-in-depth measures that may protect against API misuse in some cases.
|
||||
Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 6).
|
||||
|
||||
The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`.
|
||||
# Verification
|
||||
|
||||
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.
|
||||
A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7.
|
||||
|
||||
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_init`.
|
||||
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`.
|
||||
If the signer did not provide a message to `secp256k1_musig_session_init`,
|
||||
a message must be provided now.
|
||||
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.
|
||||
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_init_verifier`
|
||||
rather than `musig_session_init`; 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
|
||||
# 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
|
||||
|
||||
2. When calling `secp256k1_musig_nonce_process`, the public adaptor `T` is provided as the `adaptor` argument.
|
||||
3. The party who is going to extract the secret adaptor `t` later must verify all partial signatures.
|
||||
4. Due to step 2, the signature output of `secp256k1_musig_partial_sig_agg` is a pre-signature and not a valid Schnorr signature. All parties involved extract this session's `nonce_parity` with `secp256k1_musig_nonce_parity`.
|
||||
5. The party who knows `t` must "adapt" the pre-signature with `t` (and the `nonce_parity` using `secp256k1_musig_adapt` to complete the signature.
|
||||
6. Any party who sees both the final signature and the pre-signature (and has the `nonce_parity`) can extract `t` with `secp256k1_musig_extract_adaptor`.
|
||||
|
||||
25
src/modules/musig/session.h
Normal file
25
src/modules/musig/session.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_SESSION_H
|
||||
#define SECP256K1_MODULE_MUSIG_SESSION_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "../../scalar.h"
|
||||
|
||||
typedef struct {
|
||||
int fin_nonce_parity;
|
||||
unsigned char fin_nonce[32];
|
||||
secp256k1_scalar noncecoef;
|
||||
secp256k1_scalar challenge;
|
||||
secp256k1_scalar s_part;
|
||||
} secp256k1_musig_session_internal;
|
||||
|
||||
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session);
|
||||
|
||||
#endif
|
||||
755
src/modules/musig/session_impl.h
Normal file
755
src/modules/musig/session_impl.h
Normal file
@@ -0,0 +1,755 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||
#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "keyagg.h"
|
||||
#include "session.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
#include "../../util.h"
|
||||
|
||||
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
|
||||
|
||||
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) {
|
||||
memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4);
|
||||
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
|
||||
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_musig_secnonce *secnonce) {
|
||||
int is_zero;
|
||||
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0);
|
||||
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
|
||||
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
|
||||
/* We make very sure that the nonce isn't invalidated by checking the values
|
||||
* in addition to the magic. */
|
||||
is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]);
|
||||
secp256k1_declassify(ctx, &is_zero, sizeof(is_zero));
|
||||
ARG_CHECK(!is_zero);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */
|
||||
static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) {
|
||||
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
|
||||
/* The flag argument is usually classified. So, above code makes the magic
|
||||
* classified. However, we need the magic to be declassified to be able to
|
||||
* compare it during secnonce_load. */
|
||||
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
|
||||
|
||||
/* Requires that none of the provided group elements is infinity. Works for both
|
||||
* musig_pubnonce and musig_aggnonce. */
|
||||
static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp256k1_ge* ge) {
|
||||
int i;
|
||||
memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_point_save(nonce->data + 4+64*i, &ge[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Works for both musig_pubnonce and musig_aggnonce. Returns 1 unless the nonce
|
||||
* wasn't properly initialized */
|
||||
static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_pubnonce* nonce) {
|
||||
int i;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_point_load(&ge[i], nonce->data + 4 + 64*i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, secp256k1_ge* ge) {
|
||||
secp256k1_musig_pubnonce_save((secp256k1_musig_pubnonce *) nonce, ge);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_aggnonce* nonce) {
|
||||
return secp256k1_musig_pubnonce_load(ctx, ge, (secp256k1_musig_pubnonce *) nonce);
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 };
|
||||
|
||||
/* A session consists of
|
||||
* - 4 byte session cache magic
|
||||
* - 1 byte the parity of the final nonce
|
||||
* - 32 byte serialized x-only final nonce
|
||||
* - 32 byte nonce coefficient b
|
||||
* - 32 byte signature challenge hash e
|
||||
* - 32 byte scalar s that is added to the partial signatures of the signers
|
||||
*/
|
||||
static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) {
|
||||
unsigned char *ptr = session->data;
|
||||
|
||||
memcpy(ptr, secp256k1_musig_session_cache_magic, 4);
|
||||
ptr += 4;
|
||||
*ptr = session_i->fin_nonce_parity;
|
||||
ptr += 1;
|
||||
memcpy(ptr, session_i->fin_nonce, 32);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->noncecoef);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->challenge);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->s_part);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) {
|
||||
const unsigned char *ptr = session->data;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0);
|
||||
ptr += 4;
|
||||
session_i->fin_nonce_parity = *ptr;
|
||||
ptr += 1;
|
||||
memcpy(session_i->fin_nonce, ptr, 32);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 };
|
||||
|
||||
static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) {
|
||||
memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4);
|
||||
secp256k1_scalar_get_b32(&sig->data[4], s);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) {
|
||||
int overflow;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0);
|
||||
secp256k1_scalar_set_b32(s, &sig->data[4], &overflow);
|
||||
/* Parsed signatures can not overflow */
|
||||
VERIFY_CHECK(!overflow);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) {
|
||||
secp256k1_ge ge[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out66 != NULL);
|
||||
memset(out66, 0, 66);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, ge, nonce)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
int ret;
|
||||
size_t size = 33;
|
||||
ret = secp256k1_eckey_pubkey_serialize(&ge[i], &out66[33*i], &size, 1);
|
||||
/* serialize must succeed because the point was just loaded */
|
||||
VERIFY_CHECK(ret && size == 33);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) {
|
||||
secp256k1_ge ge[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(in66 != NULL);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!secp256k1_eckey_pubkey_parse(&ge[i], &in66[33*i], 33)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_is_in_correct_subgroup(&ge[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* The group elements can not be infinity because they were just parsed */
|
||||
secp256k1_musig_pubnonce_save(nonce, ge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) {
|
||||
return secp256k1_musig_pubnonce_serialize(ctx, out66, (secp256k1_musig_pubnonce*) nonce);
|
||||
}
|
||||
|
||||
int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) {
|
||||
return secp256k1_musig_pubnonce_parse(ctx, (secp256k1_musig_pubnonce*) nonce, in66);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
memcpy(out32, &sig->data[4], 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) {
|
||||
secp256k1_scalar tmp;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(in32 != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, in32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_partial_sig_save(sig, &tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Normalizes the x-coordinate of the given group element. */
|
||||
static int secp256k1_xonly_ge_serialize(unsigned char *output32, secp256k1_ge *ge) {
|
||||
if (secp256k1_ge_is_infinity(ge)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&ge->x);
|
||||
secp256k1_fe_get_b32(output32, &ge->x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *key32, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char seed[32];
|
||||
unsigned char i;
|
||||
enum { n_extra_in = 4 };
|
||||
const unsigned char *extra_in[n_extra_in];
|
||||
|
||||
/* TODO: this doesn't have the same sidechannel resistance as the BIP340
|
||||
* nonce function because the seckey feeds directly into SHA. */
|
||||
|
||||
/* Subtract one from `sizeof` to avoid hashing the implicit null byte */
|
||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/nonce", sizeof("MuSig/nonce") - 1);
|
||||
secp256k1_sha256_write(&sha, session_id, 32);
|
||||
extra_in[0] = msg32;
|
||||
extra_in[1] = key32;
|
||||
extra_in[2] = agg_pk32;
|
||||
extra_in[3] = extra_input32;
|
||||
for (i = 0; i < n_extra_in; i++) {
|
||||
unsigned char len;
|
||||
if (extra_in[i] != NULL) {
|
||||
len = 32;
|
||||
secp256k1_sha256_write(&sha, &len, 1);
|
||||
secp256k1_sha256_write(&sha, extra_in[i], 32);
|
||||
} else {
|
||||
len = 0;
|
||||
secp256k1_sha256_write(&sha, &len, 1);
|
||||
}
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, seed);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, seed, 32);
|
||||
secp256k1_sha256_write(&sha, &i, sizeof(i));
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_scalar k[2];
|
||||
secp256k1_ge nonce_pt[2];
|
||||
int i;
|
||||
unsigned char pk_ser[32];
|
||||
unsigned char *pk_ser_ptr = NULL;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secnonce != NULL);
|
||||
memset(secnonce, 0, sizeof(*secnonce));
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||
ARG_CHECK(session_id32 != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
if (seckey == NULL) {
|
||||
/* Check in constant time that the session_id is not 0 as a
|
||||
* defense-in-depth measure that may protect against a faulty RNG. */
|
||||
unsigned char acc = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
acc |= session_id32[i];
|
||||
}
|
||||
ret &= !!acc;
|
||||
memset(&acc, 0, sizeof(acc));
|
||||
}
|
||||
|
||||
/* Check that the seckey is valid to be able to sign for it later. */
|
||||
if (seckey != NULL) {
|
||||
secp256k1_scalar sk;
|
||||
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
}
|
||||
|
||||
if (keyagg_cache != NULL) {
|
||||
int ret_tmp;
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
ret_tmp = secp256k1_xonly_ge_serialize(pk_ser, &cache_i.pk);
|
||||
/* Serialization can not fail because the loaded point can not be infinity. */
|
||||
VERIFY_CHECK(ret_tmp);
|
||||
pk_ser_ptr = pk_ser;
|
||||
}
|
||||
secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser_ptr, extra_input32);
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
|
||||
VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1]));
|
||||
secp256k1_musig_secnonce_save(secnonce, k);
|
||||
secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_gej nonce_ptj;
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]);
|
||||
secp256k1_ge_set_gej(&nonce_pt[i], &nonce_ptj);
|
||||
secp256k1_declassify(ctx, &nonce_pt[i], sizeof(nonce_pt));
|
||||
secp256k1_scalar_clear(&k[i]);
|
||||
}
|
||||
/* nonce_pt won't be infinity because k != 0 with overwhelming probability */
|
||||
secp256k1_musig_pubnonce_save(pubnonce, nonce_pt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_musig_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
secp256k1_gej_set_infinity(&summed_nonces[0]);
|
||||
secp256k1_gej_set_infinity(&summed_nonces[1]);
|
||||
|
||||
for (i = 0; i < n_pubnonces; i++) {
|
||||
secp256k1_ge nonce_pt[2];
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pt, pubnonces[i])) {
|
||||
return 0;
|
||||
}
|
||||
for (j = 0; j < 2; j++) {
|
||||
secp256k1_gej_add_ge_var(&summed_nonces[j], &summed_nonces[j], &nonce_pt[j], NULL);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||
secp256k1_gej aggnonce_ptj[2];
|
||||
secp256k1_ge aggnonce_pt[2];
|
||||
int i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(aggnonce != NULL);
|
||||
ARG_CHECK(pubnonces != NULL);
|
||||
ARG_CHECK(n_pubnonces > 0);
|
||||
|
||||
if (!secp256k1_musig_sum_nonces(ctx, aggnonce_ptj, pubnonces, n_pubnonces)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (secp256k1_gej_is_infinity(&aggnonce_ptj[i])) {
|
||||
/* There must be at least one dishonest signer. If we would return 0
|
||||
here, we will never be able to determine who it is. Therefore, we
|
||||
should continue such that the culprit is revealed when collecting
|
||||
and verifying partial signatures.
|
||||
|
||||
However, dealing with the point at infinity (loading,
|
||||
de-/serializing) would require a lot of extra code complexity.
|
||||
Instead, we set the aggregate nonce to some arbitrary point (the
|
||||
generator). This is secure, because it only restricts the
|
||||
abilities of the attacker: an attacker that forces the sum of
|
||||
nonces to be infinity by sending some maliciously generated nonce
|
||||
pairs can be turned into an attacker that forces the sum to be
|
||||
the generator (by simply adding the generator to one of the
|
||||
malicious nonces), and this does not change the winning condition
|
||||
of the EUF-CMA game. */
|
||||
aggnonce_pt[i] = secp256k1_ge_const_g;
|
||||
} else {
|
||||
secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]);
|
||||
}
|
||||
}
|
||||
secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */
|
||||
static int secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||
unsigned char buf[33];
|
||||
secp256k1_sha256 sha;
|
||||
int i;
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/noncecoef", sizeof("MuSig/noncecoef") - 1);
|
||||
for (i = 0; i < 2; i++) {
|
||||
size_t size;
|
||||
if (!secp256k1_eckey_pubkey_serialize(&aggnonce[i], buf, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
VERIFY_CHECK(size == sizeof(buf));
|
||||
secp256k1_sha256_write(&sha, buf, sizeof(buf));
|
||||
}
|
||||
secp256k1_sha256_write(&sha, agg_pk32, 32);
|
||||
secp256k1_sha256_write(&sha, msg, 32);
|
||||
secp256k1_sha256_finalize(&sha, noncehash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_gej *aggnoncej, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||
unsigned char noncehash[32];
|
||||
secp256k1_ge fin_nonce_pt;
|
||||
secp256k1_gej fin_nonce_ptj;
|
||||
secp256k1_ge aggnonce[2];
|
||||
|
||||
secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]);
|
||||
secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]);
|
||||
if (!secp256k1_musig_compute_noncehash(noncehash, aggnonce, agg_pk32, msg)) {
|
||||
return 0;
|
||||
}
|
||||
/* fin_nonce = aggnonce[0] + b*aggnonce[1] */
|
||||
secp256k1_scalar_set_b32(b, noncehash, NULL);
|
||||
secp256k1_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL);
|
||||
secp256k1_gej_add_ge(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0]);
|
||||
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
|
||||
if (!secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt)) {
|
||||
/* unreachable with overwhelming probability */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&fin_nonce_pt.y);
|
||||
*fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey *adaptor) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_ge aggnonce_pt[2];
|
||||
secp256k1_gej aggnonce_ptj[2];
|
||||
unsigned char fin_nonce[32];
|
||||
secp256k1_musig_session_internal session_i;
|
||||
unsigned char agg_pk32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(aggnonce != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x);
|
||||
|
||||
if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pt, aggnonce)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&aggnonce_ptj[0], &aggnonce_pt[0]);
|
||||
secp256k1_gej_set_ge(&aggnonce_ptj[1], &aggnonce_pt[1]);
|
||||
/* Add public adaptor to nonce */
|
||||
if (adaptor != NULL) {
|
||||
secp256k1_ge adaptorp;
|
||||
if (!secp256k1_pubkey_load(ctx, &adaptorp, adaptor)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&aggnonce_ptj[0], &aggnonce_ptj[0], &adaptorp, NULL);
|
||||
}
|
||||
if (!secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, agg_pk32, msg32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32);
|
||||
|
||||
/* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/
|
||||
secp256k1_scalar_set_int(&session_i.s_part, 0);
|
||||
if (!secp256k1_scalar_is_zero(&cache_i.tweak)) {
|
||||
secp256k1_scalar e_tmp;
|
||||
secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak);
|
||||
if (secp256k1_fe_is_odd(&cache_i.pk.y)) {
|
||||
secp256k1_scalar_negate(&e_tmp, &e_tmp);
|
||||
}
|
||||
secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &e_tmp);
|
||||
}
|
||||
memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce));
|
||||
secp256k1_musig_session_save(session, &session_i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
|
||||
secp256k1_scalar_clear(sk);
|
||||
secp256k1_scalar_clear(&k[0]);
|
||||
secp256k1_scalar_clear(&k[1]);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_scalar k[2];
|
||||
secp256k1_scalar mu, s;
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
ARG_CHECK(secnonce != NULL);
|
||||
/* Fails if the magic doesn't match */
|
||||
ret = secp256k1_musig_secnonce_load(ctx, k, secnonce);
|
||||
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
|
||||
* of this function to fail */
|
||||
memset(secnonce, 0, sizeof(*secnonce));
|
||||
if (!ret) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
if (!secp256k1_keypair_load(ctx, &sk, &pk, keypair)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&pk.y);
|
||||
/* Determine if the secret key sk should be negated before signing.
|
||||
*
|
||||
* We use the following notation:
|
||||
* - |.| is a function that normalizes a point to an even Y by negating
|
||||
* if necessary, similar to secp256k1_extrakeys_ge_even_y
|
||||
* - mu[i] is the i-th KeyAgg coefficient
|
||||
* - t[i] is the i-th tweak
|
||||
*
|
||||
* The following public keys arise as intermediate steps:
|
||||
* - P[i] is the i-th public key with corresponding secret key x[i]
|
||||
* P[i] := x[i]*G
|
||||
* - P_agg is the aggregate public key
|
||||
* P_agg := mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|
|
||||
* - P_tweak[i] is the tweaked public key after the i-th tweaking operation
|
||||
* P_tweak[0] := P_agg
|
||||
* P_tweak[i] := |P_tweak[i-1]| + t[i]*G for i = 1, ..., m
|
||||
*
|
||||
* Note that our goal is to produce a partial signature corresponding to
|
||||
* the final public key after m tweaking operations P_final = |P_tweak[m]|.
|
||||
*
|
||||
* Define d[i], d_agg, and d_tweak[i] so that:
|
||||
* - |P[i]| = d[i]*P[i]
|
||||
* - |P_agg| = d_agg*P_agg
|
||||
* - |P_tweak[i]| = d_tweak[i]*P_tweak[i]
|
||||
*
|
||||
* In other words, d[i] = 1 if P[i] has even y coordinate, -1 otherwise;
|
||||
* similarly for d_agg and d_tweak[i].
|
||||
*
|
||||
* The (xonly) final public key is P_final = |P_tweak[m]|
|
||||
* = d_tweak[m]*P_tweak[m]
|
||||
* = d_tweak[m]*(|P_tweak[m-1]| + t[m]*G)
|
||||
* = d_tweak[m]*(d_tweak[m-1]*(|P_tweak[m-2]| + t[m-1]*G) + t[m]*G)
|
||||
* = d_tweak[m]*...*d_tweak[1]*|P_agg| + (d_tweak[m]*t[m]+...+*d_tweak[1]*t[1])*G.
|
||||
* To simplify the equation let us define
|
||||
* t := d_tweak[m]*t[m]+...+*d_tweak[1]*t[1]
|
||||
* d_tweak := d_tweak[m]*...*d_tweak[1].
|
||||
* Then we have
|
||||
* P_final - t*G
|
||||
* = d_tweak*|P_agg|
|
||||
* = d_tweak*d_agg*P_agg
|
||||
* = d_tweak*d_agg*(mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|)
|
||||
* = d_tweak*d_agg*(d[0]*mu[0]*P[0] + ... + d[n-1]*mu[n-1]*P[n-1])
|
||||
* = sum((d_tweak*d_agg*d[i])*mu[i]*x[i])*G.
|
||||
*
|
||||
* Thus whether signer i should use the negated x[i] depends on the product
|
||||
* d_tweak[m]*...*d_tweak[1]*d_agg*d[i]. In other words, negate if and only
|
||||
* if the following holds:
|
||||
* (P[i] has odd y) XOR (P_agg has odd y)
|
||||
* XOR (P_tweak[1] has odd y) XOR ... XOR (P_tweak[m] has odd y)
|
||||
*
|
||||
* Let us now look at how the terms in the equation correspond to the if
|
||||
* condition below for some values of m:
|
||||
* m = 0: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
|
||||
* P_agg has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
* cache_i.internal_key_parity = 0
|
||||
* m = 1: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
|
||||
* P_agg has odd y = cache_i.internal_key_parity
|
||||
* P_tweak[1] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
* m = 2: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
|
||||
* P_agg has odd y XOR P_tweak[1] has odd y = cache_i.internal_key_parity
|
||||
* P_tweak[2] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
* etc.
|
||||
*/
|
||||
if ((secp256k1_fe_is_odd(&pk.y)
|
||||
!= secp256k1_fe_is_odd(&cache_i.pk.y))
|
||||
!= cache_i.internal_key_parity) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
/* Multiply KeyAgg coefficient */
|
||||
secp256k1_fe_normalize_var(&pk.x);
|
||||
/* TODO Cache mu */
|
||||
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk.x);
|
||||
secp256k1_scalar_mul(&sk, &sk, &mu);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session_i.fin_nonce_parity) {
|
||||
secp256k1_scalar_negate(&k[0], &k[0]);
|
||||
secp256k1_scalar_negate(&k[1], &k[1]);
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
secp256k1_scalar_mul(&s, &session_i.challenge, &sk);
|
||||
secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]);
|
||||
secp256k1_scalar_add(&k[0], &k[0], &k[1]);
|
||||
secp256k1_scalar_add(&s, &s, &k[0]);
|
||||
secp256k1_musig_partial_sig_save(partial_sig, &s);
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_xonly_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
secp256k1_scalar mu, e, s;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge nonce_pt[2];
|
||||
secp256k1_gej rj;
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_ge pkp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute "effective" nonce rj = aggnonce[0] + b*aggnonce[1] */
|
||||
/* TODO: use multiexp to compute -s*G + e*mu*pubkey + aggnonce[0] + b*aggnonce[1] */
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pt, pubnonce)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&rj, &nonce_pt[1]);
|
||||
secp256k1_ecmult(&rj, &rj, &session_i.noncecoef, NULL);
|
||||
secp256k1_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
|
||||
* to multiplying the signer's public key by the coefficient, except
|
||||
* much easier to do. */
|
||||
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp.x);
|
||||
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
||||
|
||||
/* If the MuSig-aggregate point has an odd Y coordinate, the signers will
|
||||
* sign for the negation of their individual xonly public key. If the
|
||||
* aggregate key is untweaked, then internal_key_parity is 0, so `e` is
|
||||
* negated exactly when the aggregate key parity is odd. If the aggregate
|
||||
* key is tweaked, then negation happens when the aggregate key has an odd Y
|
||||
* coordinate XOR the internal key has an odd Y coordinate.*/
|
||||
|
||||
/* When producing a partial signature, signer i uses a possibly
|
||||
* negated secret key:
|
||||
*
|
||||
* sk[i] = (d_tweak*d_agg*d[i])*x[i]
|
||||
*
|
||||
* to ensure that the aggregate signature will correspond to
|
||||
* an aggregate public key with even Y coordinate (see the
|
||||
* notation and explanation in musig_partial_sign).
|
||||
*
|
||||
* We use the following additional notation:
|
||||
* - e is the (Schnorr signature) challenge
|
||||
* - r[i] is the i-th signer's secret nonce
|
||||
* - R[i] = r[i]*G is the i-th signer's public nonce
|
||||
* - R is the aggregated public nonce
|
||||
* - d_nonce is chosen so that |R| = d_nonce*R
|
||||
*
|
||||
* The i-th partial signature is:
|
||||
*
|
||||
* s[i] = d_nonce*r[i] + mu[i]*e*sk[i]
|
||||
*
|
||||
* In order to verify this partial signature, we need to check:
|
||||
*
|
||||
* s[i]*G = d_nonce*R[i] + mu[i]*e*sk[i]*G
|
||||
*
|
||||
* The verifier doesn't have access to sk[i]*G, but can construct
|
||||
* it using the xonly public key |P[i]| as follows:
|
||||
*
|
||||
* sk[i]*G = d_tweak*d_agg*d[i]*x[i]*G
|
||||
* = d_tweak*d_agg*d[i]*P[i]
|
||||
* = d_tweak*d_agg*|P[i]|
|
||||
*
|
||||
* The if condition below is true whenever d_tweak*d_agg is
|
||||
* negative (again, see the explanation in musig_partial_sign). In
|
||||
* this case, the verifier negates e which will have the same end
|
||||
* result as negating |P[i]|, since they are multiplied later anyway.
|
||||
*/
|
||||
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
!= cache_i.internal_key_parity) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) {
|
||||
return 0;
|
||||
}
|
||||
/* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
secp256k1_ecmult(&tmp, &pkj, &e, &s);
|
||||
if (session_i.fin_nonce_parity) {
|
||||
secp256k1_gej_neg(&rj, &rj);
|
||||
}
|
||||
secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL);
|
||||
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) {
|
||||
size_t i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
ARG_CHECK(n_sigs > 0);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
secp256k1_scalar term;
|
||||
if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term);
|
||||
}
|
||||
secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part);
|
||||
memcpy(&sig64[0], session_i.fin_nonce, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <valgrind/memcheck.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
#include "assumptions.h"
|
||||
@@ -35,6 +36,10 @@
|
||||
#include "include/secp256k1_ecdsa_adaptor.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
#include "include/secp256k1_musig.h"
|
||||
#endif
|
||||
|
||||
void run_tests(secp256k1_context *ctx, unsigned char *key);
|
||||
|
||||
int main(void) {
|
||||
@@ -241,4 +246,70 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
CHECK(ret == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
{
|
||||
secp256k1_xonly_pubkey pk;
|
||||
const secp256k1_xonly_pubkey *pk_ptr[1];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
unsigned char session_id[32];
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
|
||||
secp256k1_musig_aggnonce aggnonce;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
const secp256k1_musig_partial_sig *partial_sig_ptr[1];
|
||||
unsigned char extra_input[32];
|
||||
unsigned char sec_adaptor[32];
|
||||
secp256k1_pubkey adaptor;
|
||||
unsigned char pre_sig[64];
|
||||
int nonce_parity;
|
||||
|
||||
pk_ptr[0] = &pk;
|
||||
pubnonce_ptr[0] = &pubnonce;
|
||||
VALGRIND_MAKE_MEM_DEFINED(key, 32);
|
||||
memcpy(session_id, key, sizeof(session_id));
|
||||
session_id[0] = session_id[0] + 1;
|
||||
memcpy(extra_input, key, sizeof(extra_input));
|
||||
extra_input[0] = extra_input[0] + 2;
|
||||
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
|
||||
sec_adaptor[0] = extra_input[0] + 3;
|
||||
partial_sig_ptr[0] = &partial_sig;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
||||
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(session_id, sizeof(session_id));
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(extra_input, sizeof(extra_input));
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(sec_adaptor, sizeof(sec_adaptor));
|
||||
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, msg, &cache, extra_input);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1);
|
||||
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
VALGRIND_MAKE_MEM_DEFINED(&partial_sig, sizeof(partial_sig));
|
||||
CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1));
|
||||
VALGRIND_MAKE_MEM_DEFINED(pre_sig, sizeof(pre_sig));
|
||||
|
||||
CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session));
|
||||
ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user