2021-05-05 15:45:31 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* 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 };
|
|
|
|
|
2023-02-04 17:38:42 +00:00
|
|
|
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, secp256k1_ge *pk) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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]);
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_point_save(&secnonce->data[68], pk);
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
2023-02-04 17:38:42 +00:00
|
|
|
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, secp256k1_musig_secnonce *secnonce) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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);
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_point_load(pk, &secnonce->data[68]);
|
2021-05-05 15:45:31 +00:00
|
|
|
/* 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);
|
2023-02-04 17:38:42 +00:00
|
|
|
/* The flag argument is usually classified. So, the line above makes the
|
|
|
|
* magic and public key classified. However, we need both to be
|
|
|
|
* declassified. Note that we don't declassify the entire object, because if
|
|
|
|
* flag is 0, then k[0] and k[1] have not been zeroed. */
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_declassify(ctx, &secnonce->data[68], 64);
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
|
|
|
|
|
2022-12-20 13:13:54 +00:00
|
|
|
/* Saves two group elements into a pubnonce. Requires that none of the provided
|
|
|
|
* group elements is infinity. */
|
2021-05-05 15:45:31 +00:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-20 13:13:54 +00:00
|
|
|
/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't
|
|
|
|
* properly initialized */
|
2021-05-05 15:45:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-12-20 13:13:54 +00:00
|
|
|
static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 };
|
|
|
|
|
2021-05-05 15:45:31 +00:00
|
|
|
static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, secp256k1_ge* ge) {
|
2022-12-20 13:13:54 +00:00
|
|
|
int i;
|
|
|
|
memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
secp256k1_point_save_ext(&nonce->data[4 + 64*i], &ge[i]);
|
|
|
|
}
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_aggnonce* nonce) {
|
2022-12-20 13:13:54 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
secp256k1_point_load_ext(&ge[i], &nonce->data[4 + 64*i]);
|
|
|
|
}
|
|
|
|
return 1;
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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) {
|
2022-12-20 13:13:54 +00:00
|
|
|
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_aggnonce_load(ctx, ge, nonce)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
secp256k1_ge_serialize_ext(&out66[33*i], &ge[i]);
|
|
|
|
}
|
|
|
|
return 1;
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) {
|
2022-12-20 13:13:54 +00:00
|
|
|
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_ge_parse_ext(&ge[i], &in66[33*i])) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
secp256k1_musig_aggnonce_save(nonce, ge);
|
|
|
|
return 1;
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-04-19 12:43:11 +00:00
|
|
|
/* Write optional inputs into the hash */
|
2022-12-20 19:11:35 +00:00
|
|
|
static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
|
2022-12-20 13:39:44 +00:00
|
|
|
unsigned char zero[7] = { 0 };
|
|
|
|
/* The spec requires length prefixes to be between 1 and 8 bytes
|
|
|
|
* (inclusive) */
|
|
|
|
VERIFY_CHECK(prefix_size <= 8);
|
2022-12-20 19:11:35 +00:00
|
|
|
/* Since the length of all input data fits in a byte, we can always pad the
|
|
|
|
* length prefix with prefix_size - 1 zero bytes. */
|
2022-12-20 13:39:44 +00:00
|
|
|
secp256k1_sha256_write(sha, zero, prefix_size - 1);
|
2022-12-20 19:11:35 +00:00
|
|
|
if (data != NULL) {
|
2022-04-19 12:43:11 +00:00
|
|
|
secp256k1_sha256_write(sha, &len, 1);
|
2022-12-20 19:11:35 +00:00
|
|
|
secp256k1_sha256_write(sha, data, len);
|
2022-04-19 12:43:11 +00:00
|
|
|
} else {
|
2022-12-20 19:11:35 +00:00
|
|
|
len = 0;
|
2022-04-19 12:43:11 +00:00
|
|
|
secp256k1_sha256_write(sha, &len, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-20 19:11:35 +00:00
|
|
|
static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_sha256 sha;
|
2022-04-19 12:43:11 +00:00
|
|
|
unsigned char rand[32];
|
2021-05-05 15:45:31 +00:00
|
|
|
unsigned char i;
|
2022-12-20 13:39:44 +00:00
|
|
|
unsigned char msg_present;
|
2021-05-05 15:45:31 +00:00
|
|
|
|
2022-12-20 19:11:35 +00:00
|
|
|
if (seckey32 != NULL) {
|
2022-04-19 12:43:11 +00:00
|
|
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/aux", sizeof("MuSig/aux") - 1);
|
|
|
|
secp256k1_sha256_write(&sha, session_id, 32);
|
|
|
|
secp256k1_sha256_finalize(&sha, rand);
|
|
|
|
for (i = 0; i < 32; i++) {
|
2022-12-20 19:11:35 +00:00
|
|
|
rand[i] ^= seckey32[i];
|
2022-04-19 12:43:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(rand, session_id, sizeof(rand));
|
|
|
|
}
|
2021-05-05 15:45:31 +00:00
|
|
|
|
|
|
|
/* Subtract one from `sizeof` to avoid hashing the implicit null byte */
|
|
|
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/nonce", sizeof("MuSig/nonce") - 1);
|
2022-04-19 12:43:11 +00:00
|
|
|
secp256k1_sha256_write(&sha, rand, sizeof(rand));
|
2022-12-20 19:11:35 +00:00
|
|
|
secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33);
|
|
|
|
secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32);
|
2022-12-20 13:39:44 +00:00
|
|
|
msg_present = msg32 != NULL;
|
|
|
|
secp256k1_sha256_write(&sha, &msg_present, 1);
|
|
|
|
if (msg_present) {
|
2022-12-20 19:11:35 +00:00
|
|
|
secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32);
|
2022-12-20 13:39:44 +00:00
|
|
|
}
|
2022-12-20 19:11:35 +00:00
|
|
|
secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32);
|
2021-05-05 15:45:31 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
unsigned char buf[32];
|
2022-04-19 12:43:11 +00:00
|
|
|
secp256k1_sha256 sha_tmp = sha;
|
|
|
|
secp256k1_sha256_write(&sha_tmp, &i, 1);
|
|
|
|
secp256k1_sha256_finalize(&sha_tmp, buf);
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-20 19:11:35 +00:00
|
|
|
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 secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_keyagg_cache_internal cache_i;
|
|
|
|
secp256k1_scalar k[2];
|
|
|
|
secp256k1_ge nonce_pt[2];
|
|
|
|
int i;
|
2022-12-20 19:11:35 +00:00
|
|
|
unsigned char pk_ser[33];
|
|
|
|
size_t pk_ser_len = sizeof(pk_ser);
|
|
|
|
unsigned char aggpk_ser[32];
|
|
|
|
unsigned char *aggpk_ser_ptr = NULL;
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_ge pk;
|
|
|
|
int pk_serialize_success;
|
2021-05-05 15:45:31 +00:00
|
|
|
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);
|
2022-12-20 19:11:35 +00:00
|
|
|
ARG_CHECK(pubkey != NULL);
|
2021-05-05 15:45:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-12-20 19:11:35 +00:00
|
|
|
ret_tmp = secp256k1_xonly_ge_serialize(aggpk_ser, &cache_i.pk);
|
2021-05-05 15:45:31 +00:00
|
|
|
/* Serialization can not fail because the loaded point can not be infinity. */
|
|
|
|
VERIFY_CHECK(ret_tmp);
|
2022-12-20 19:11:35 +00:00
|
|
|
aggpk_ser_ptr = aggpk_ser;
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
2023-02-04 17:38:42 +00:00
|
|
|
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
2022-12-20 19:11:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2023-02-04 17:38:42 +00:00
|
|
|
pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, SECP256K1_EC_COMPRESSED);
|
|
|
|
/* A pubkey cannot be the point at infinity */
|
|
|
|
VERIFY_CHECK(pk_serialize_success);
|
2022-12-20 19:11:35 +00:00
|
|
|
VERIFY_CHECK(pk_ser_len == sizeof(pk_ser));
|
|
|
|
|
|
|
|
secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
|
2021-05-05 15:45:31 +00:00
|
|
|
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]));
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_musig_secnonce_save(secnonce, k, &pk);
|
2021-05-05 15:45:31 +00:00
|
|
|
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++) {
|
2022-12-20 13:13:54 +00:00
|
|
|
secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]);
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
|
|
|
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++) {
|
2022-12-20 13:13:54 +00:00
|
|
|
secp256k1_ge_serialize_ext(buf, &aggnonce[i]);
|
2021-05-05 15:45:31 +00:00
|
|
|
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];
|
2022-12-20 13:13:54 +00:00
|
|
|
int ret;
|
2021-05-05 15:45:31 +00:00
|
|
|
|
|
|
|
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);
|
2022-12-20 13:13:54 +00:00
|
|
|
secp256k1_gej_set_infinity(&fin_nonce_ptj);
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL);
|
2022-12-20 13:13:54 +00:00
|
|
|
secp256k1_gej_add_ge_var(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0], NULL);
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
|
2022-12-20 13:13:54 +00:00
|
|
|
if (secp256k1_ge_is_infinity(&fin_nonce_pt)) {
|
|
|
|
fin_nonce_pt = secp256k1_ge_const_g;
|
2021-05-05 15:45:31 +00:00
|
|
|
}
|
2022-12-20 13:13:54 +00:00
|
|
|
ret = secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt);
|
|
|
|
/* Can't fail since fin_nonce_pt is not infinity */
|
|
|
|
VERIFY_CHECK(ret);
|
2021-05-05 15:45:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-12 16:41:43 +00:00
|
|
|
static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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;
|
2023-02-04 17:38:42 +00:00
|
|
|
secp256k1_ge pk, keypair_pk;
|
2021-05-05 15:45:31 +00:00
|
|
|
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 */
|
2023-02-04 17:38:42 +00:00
|
|
|
ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
|
2021-05-05 15:45:31 +00:00
|
|
|
/* 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);
|
|
|
|
|
2023-02-04 17:38:42 +00:00
|
|
|
if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) {
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_musig_partial_sign_clear(&sk, k);
|
|
|
|
return 0;
|
|
|
|
}
|
2023-02-04 17:38:42 +00:00
|
|
|
ARG_CHECK(secp256k1_fe_equal_var(&pk.x, &keypair_pk.x)
|
|
|
|
&& secp256k1_fe_equal_var(&pk.y, &keypair_pk.y));
|
2021-05-05 15:45:31 +00:00
|
|
|
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);
|
2022-03-15 22:26:55 +00:00
|
|
|
|
2022-12-20 16:59:12 +00:00
|
|
|
/* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
|
|
|
* This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the
|
|
|
|
* specification. */
|
2022-03-15 22:26:55 +00:00
|
|
|
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
|
2022-12-20 16:59:12 +00:00
|
|
|
!= cache_i.parity_acc)) {
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_scalar_negate(&sk, &sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Multiply KeyAgg coefficient */
|
|
|
|
secp256k1_fe_normalize_var(&pk.x);
|
|
|
|
/* TODO Cache mu */
|
2022-12-20 16:59:12 +00:00
|
|
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk);
|
2021-05-05 15:45:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-12-20 16:59:12 +00:00
|
|
|
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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);
|
|
|
|
|
2022-12-20 16:59:12 +00:00
|
|
|
if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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. */
|
2022-12-20 16:59:12 +00:00
|
|
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp);
|
2021-05-05 15:45:31 +00:00
|
|
|
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
|
|
|
|
2022-12-20 16:59:12 +00:00
|
|
|
/* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
|
|
|
* This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e"
|
|
|
|
* in the specification. */
|
2021-05-05 15:45:31 +00:00
|
|
|
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
2022-03-15 22:26:55 +00:00
|
|
|
!= cache_i.parity_acc) {
|
2021-05-05 15:45:31 +00:00
|
|
|
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
|