frost trusted dealer: nonce aggregation and adaptor signatures

This commit adds nonce aggregation, as well as adaptor signatures.
This commit is contained in:
Jesse Posner 2023-11-23 11:51:41 -07:00
parent 5368c81a3c
commit ea059393f0
No known key found for this signature in database
GPG Key ID: 49A08EAB3A812D69
7 changed files with 557 additions and 0 deletions

View File

@ -78,6 +78,16 @@ typedef struct {
unsigned char data[132];
} secp256k1_frost_pubnonce;
/** Opaque data structure that holds a FROST session.
*
* This structure is not required to be kept secret for the signing protocol
* to be secure. Guaranteed to be 133 bytes in size. It can be safely
* copied/moved. No serialization and parsing functions.
*/
typedef struct {
unsigned char data[133];
} secp256k1_frost_session;
/** Parse a signer's public nonce.
*
* Returns: 1 when the nonce could be parsed, 0 otherwise.
@ -335,6 +345,135 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
const unsigned char *extra_input32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Takes the public nonces of all signers and computes a session that is
* required for signing and verification of partial signatures. The participant
* IDs can be sorted before combining, but the corresponding pubnonces must be
* resorted as well. All signers must use the same sorting of pubnonces,
* otherwise signing will fail.
*
* Returns: 0 if the arguments are invalid or if some signer sent invalid
* pubnonces, 1 otherwise
* Args: ctx: pointer to a context object
* Out: session: pointer to a struct to store the session
* In: pubnonces: array of pointers to public nonces sent by the signers
* n_pubnonces: number of elements in the pubnonces array. Must be
* greater than 0.
* msg32: the 32-byte message to sign
* agg_pk: the FROST-aggregated public key
* my_id: the ID of the participant who will use the session for
* signing
* ids: array of the IDs of the signers
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
* adaptor: optional pointer to an adaptor point encoded as a
* public key if this signing session is part of an
* adaptor signature protocol (can be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
const secp256k1_context *ctx,
secp256k1_frost_session *session,
const secp256k1_frost_pubnonce * const *pubnonces,
size_t n_pubnonces,
const unsigned char *msg32,
const secp256k1_xonly_pubkey *agg_pk,
size_t my_id,
const size_t *ids,
const secp256k1_frost_tweak_cache *tweak_cache,
const secp256k1_pubkey *adaptor
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(8);
/** Extracts the nonce_parity bit from a session
*
* This is used for adaptor signatures.
*
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: nonce_parity: pointer to an integer that indicates the parity
* of the aggregate public nonce. Used for adaptor
* signatures.
* In: session: pointer to the session that was created with
* frost_nonce_process
*/
SECP256K1_API int secp256k1_frost_nonce_parity(
const secp256k1_context *ctx,
int *nonce_parity,
const secp256k1_frost_session *session
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Verifies that the adaptor can be extracted by combining the adaptor
* pre-signature and the completed signature.
*
* Returns: 0 if the arguments are invalid or the adaptor signature does not
* verify, 1 otherwise
* Args: ctx: pointer to a context object
* In: pre_sig64: 64-byte pre-signature
* msg32: the 32-byte message being verified
* pubkey: pointer to an x-only public key to verify with
* adaptor: pointer to the adaptor point being verified
* nonce_parity: the output of `frost_nonce_parity` called with the
* session used for producing the pre-signature
*/
SECP256K1_API int secp256k1_frost_verify_adaptor(
const secp256k1_context *ctx,
const unsigned char *pre_sig64,
const unsigned char *msg32,
const secp256k1_xonly_pubkey *pubkey,
const secp256k1_pubkey *adaptor,
int nonce_parity
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Creates a signature from a pre-signature and an adaptor.
*
* If the sec_adaptor32 argument is incorrect, the output signature will be
* invalid. This function does not verify the signature.
*
* Returns: 0 if the arguments are invalid, or pre_sig64 or sec_adaptor32 contain
* invalid (overflowing) values. 1 otherwise (which does NOT mean the
* signature or the adaptor are valid!)
* Args: ctx: pointer to a context object
* Out: sig64: 64-byte signature. This pointer may point to the same
* memory area as `pre_sig`.
* In: pre_sig64: 64-byte pre-signature
* sec_adaptor32: 32-byte secret adaptor to add to the pre-signature
* nonce_parity: the output of `frost_nonce_parity` called with the
* session used for producing the pre-signature
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_adapt(
const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *pre_sig64,
const unsigned char *sec_adaptor32,
int nonce_parity
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Extracts a secret adaptor from a FROST pre-signature and corresponding
* signature
*
* This function will not fail unless given grossly invalid data; if it is
* merely given signatures that do not verify, the returned value will be
* nonsense. It is therefore important that all data be verified at earlier
* steps of any protocol that uses this function. In particular, this includes
* verifying all partial signatures that were aggregated into pre_sig64.
*
* Returns: 0 if the arguments are NULL, or sig64 or pre_sig64 contain
* grossly invalid (overflowing) values. 1 otherwise (which does NOT
* mean the signatures or the adaptor are valid!)
* Args: ctx: pointer to a context object
* Out:sec_adaptor32: 32-byte secret adaptor
* In: sig64: complete, valid 64-byte signature
* pre_sig64: the pre-signature corresponding to sig64, i.e., the
* aggregate of partial signatures without the secret
* adaptor
* nonce_parity: the output of `frost_nonce_parity` called with the
* session used for producing sig64
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_extract_adaptor(
const secp256k1_context *ctx,
unsigned char *sec_adaptor32,
const unsigned char *sig64,
const unsigned char *pre_sig64,
int nonce_parity
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
}
#endif

View File

@ -4,3 +4,4 @@ noinst_HEADERS += src/modules/frost/keygen.h
noinst_HEADERS += src/modules/frost/keygen_impl.h
noinst_HEADERS += src/modules/frost/session.h
noinst_HEADERS += src/modules/frost/session_impl.h
noinst_HEADERS += src/modules/frost/adaptor_impl.h

View File

@ -0,0 +1,168 @@
/***********************************************************************
* Copyright (c) 2022-2023 Jesse Posner *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_FROST_ADAPTOR_IMPL_H
#define SECP256K1_MODULE_FROST_ADAPTOR_IMPL_H
#include <string.h>
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_frost.h"
#include "session.h"
#include "../../scalar.h"
int secp256k1_frost_nonce_parity(const secp256k1_context* ctx, int *nonce_parity, const secp256k1_frost_session *session) {
secp256k1_frost_session_internal session_i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(nonce_parity != NULL);
ARG_CHECK(session != NULL);
if (!secp256k1_frost_session_load(ctx, &session_i, session)) {
return 0;
}
*nonce_parity = session_i.fin_nonce_parity;
return 1;
}
int secp256k1_frost_verify_adaptor(const secp256k1_context* ctx, const unsigned char *pre_sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey, const secp256k1_pubkey *adaptor, int nonce_parity) {
secp256k1_scalar s;
secp256k1_scalar e;
secp256k1_gej rj;
secp256k1_ge pk;
secp256k1_gej pkj;
secp256k1_ge r;
unsigned char buf[32];
int overflow;
secp256k1_ge adaptorp;
secp256k1_xonly_pubkey noncepk;
secp256k1_gej fin_nonce_ptj;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pre_sig64 != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(pubkey != NULL);
ARG_CHECK(adaptor != NULL);
ARG_CHECK(nonce_parity == 0 || nonce_parity == 1);
if (!secp256k1_xonly_pubkey_parse(ctx, &noncepk, &pre_sig64[0])) {
return 0;
}
if (!secp256k1_xonly_pubkey_load(ctx, &r, &noncepk)) {
return 0;
}
if (!secp256k1_pubkey_load(ctx, &adaptorp, adaptor)) {
return 0;
}
if (!nonce_parity) {
secp256k1_ge_neg(&adaptorp, &adaptorp);
}
secp256k1_gej_set_ge(&fin_nonce_ptj, &adaptorp);
secp256k1_gej_add_ge_var(&fin_nonce_ptj, &fin_nonce_ptj, &r, NULL);
if (secp256k1_gej_is_infinity(&fin_nonce_ptj)) {
/* unreachable with overwhelming probability */
return 0;
}
secp256k1_scalar_set_b32(&s, &pre_sig64[32], &overflow);
if (overflow) {
return 0;
}
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
return 0;
}
/* Compute e. */
secp256k1_fe_get_b32(buf, &pk.x);
secp256k1_schnorrsig_challenge(&e, &pre_sig64[0], msg32, 32, buf);
/* Compute rj = s*G + (-e)*pkj */
secp256k1_scalar_negate(&e, &e);
secp256k1_gej_set_ge(&pkj, &pk);
secp256k1_ecmult(&rj, &pkj, &e, &s);
/* secp256k1_ge_set_gej_var(&r, &rj); */
if (secp256k1_gej_is_infinity(&rj)) {
return 0;
}
secp256k1_gej_neg(&rj, &rj);
secp256k1_gej_add_var(&rj, &rj, &fin_nonce_ptj, NULL);
return secp256k1_gej_is_infinity(&rj);
}
int secp256k1_frost_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 frost_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_frost_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

View File

@ -19,6 +19,8 @@ typedef struct {
int parity_acc;
} secp256k1_tweak_cache_internal;
static int secp256k1_tweak_cache_load(const secp256k1_context* ctx, secp256k1_tweak_cache_internal *cache_i, const secp256k1_frost_tweak_cache *cache);
static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share);
#endif

View File

@ -9,5 +9,6 @@
#include "keygen_impl.h"
#include "session_impl.h"
#include "adaptor_impl.h"
#endif

View File

@ -7,4 +7,19 @@
#ifndef SECP256K1_MODULE_FROST_SESSION_H
#define SECP256K1_MODULE_FROST_SESSION_H
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_frost.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_frost_session_internal;
static int secp256k1_frost_session_load(const secp256k1_context* ctx, secp256k1_frost_session_internal *session_i, const secp256k1_frost_session *session);
#endif

View File

@ -74,6 +74,49 @@ static int secp256k1_frost_pubnonce_load(const secp256k1_context* ctx, secp256k1
return 1;
}
static const unsigned char secp256k1_frost_session_cache_magic[4] = { 0x5c, 0x11, 0xa8, 0x3 };
/* 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_frost_session_save(secp256k1_frost_session *session, const secp256k1_frost_session_internal *session_i) {
unsigned char *ptr = session->data;
memcpy(ptr, secp256k1_frost_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_frost_session_load(const secp256k1_context* ctx, secp256k1_frost_session_internal *session_i, const secp256k1_frost_session *session) {
const unsigned char *ptr = session->data;
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_frost_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;
}
int secp256k1_frost_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_frost_pubnonce* nonce) {
secp256k1_ge ge[2];
int i;
@ -230,4 +273,192 @@ int secp256k1_frost_nonce_gen(const secp256k1_context* ctx, secp256k1_frost_secn
return ret;
}
static int secp256k1_frost_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_frost_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_frost_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;
}
/* TODO: consider updating to frost-08 to address maleability at the cost of performance */
/* See https://github.com/cfrg/draft-irtf-cfrg-frost/pull/217 */
static int secp256k1_frost_compute_noncehash(const secp256k1_context* ctx, unsigned char *noncehash, const unsigned char *msg, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *pk32, const size_t *ids) {
unsigned char buf[66];
secp256k1_sha256 sha;
size_t i;
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/noncecoef", sizeof("FROST/noncecoef") - 1);
for (i = 0; i < n_pubnonces; i++) {
secp256k1_scalar idx;
secp256k1_scalar_set_int(&idx, ids[i]);
secp256k1_scalar_get_b32(buf, &idx);
secp256k1_sha256_write(&sha, buf, 32);
if (!secp256k1_frost_pubnonce_serialize(ctx, buf, pubnonces[i])) {
return 0;
}
secp256k1_sha256_write(&sha, buf, sizeof(buf));
}
secp256k1_sha256_write(&sha, pk32, 32);
secp256k1_sha256_write(&sha, msg, 32);
secp256k1_sha256_finalize(&sha, noncehash);
return 1;
}
static int secp256k1_frost_nonce_process_internal(const secp256k1_context* ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_gej *aggnoncej, const unsigned char *msg, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *pk32, const size_t *ids) {
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_frost_compute_noncehash(ctx, noncehash, msg, pubnonces, n_pubnonces, pk32, ids)) {
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_var(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0], NULL);
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
if (secp256k1_ge_is_infinity(&fin_nonce_pt)) {
/* unreachable with overwhelming probability */
return 0;
}
secp256k1_fe_normalize_var(&fin_nonce_pt.x);
secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x);
secp256k1_fe_normalize_var(&fin_nonce_pt.y);
*fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y);
return 1;
}
static int secp256k1_frost_lagrange_coefficient(secp256k1_scalar *r, const size_t *ids, size_t n_participants, size_t my_id) {
size_t i;
secp256k1_scalar num;
secp256k1_scalar den;
secp256k1_scalar party_idx;
secp256k1_scalar_set_int(&num, 1);
secp256k1_scalar_set_int(&den, 1);
secp256k1_scalar_set_int(&party_idx, my_id);
for (i = 0; i < n_participants; i++) {
secp256k1_scalar mul;
secp256k1_scalar_set_int(&mul, ids[i]);
if (secp256k1_scalar_eq(&mul, &party_idx)) {
continue;
}
secp256k1_scalar_negate(&mul, &mul);
secp256k1_scalar_mul(&num, &num, &mul);
secp256k1_scalar_add(&mul, &mul, &party_idx);
secp256k1_scalar_mul(&den, &den, &mul);
}
secp256k1_scalar_inverse_var(&den, &den);
secp256k1_scalar_mul(r, &num, &den);
return 1;
}
int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_session *session, const secp256k1_frost_pubnonce * const* pubnonces, size_t n_pubnonces, const unsigned char *msg32, const secp256k1_xonly_pubkey *pk, size_t my_id, const size_t *ids, const secp256k1_frost_tweak_cache *tweak_cache, const secp256k1_pubkey *adaptor) {
secp256k1_ge aggnonce_pt[2];
secp256k1_gej aggnonce_ptj[2];
unsigned char fin_nonce[32];
secp256k1_frost_session_internal session_i = { 0 };
unsigned char pk32[32];
int i;
secp256k1_scalar l;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(pubnonces != NULL);
ARG_CHECK(ids != NULL);
ARG_CHECK(n_pubnonces > 1);
if (!secp256k1_xonly_pubkey_serialize(ctx, pk32, pk)) {
return 0;
}
if (!secp256k1_frost_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]);
}
}
/* 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_frost_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_ptj, msg32, pubnonces, n_pubnonces, pk32, ids)) {
return 0;
}
secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, 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 (tweak_cache != NULL) {
secp256k1_tweak_cache_internal cache_i;
if (!secp256k1_tweak_cache_load(ctx, &cache_i, tweak_cache)) {
return 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);
}
}
/* Update the challenge by multiplying the Lagrange coefficient to prepare
* for signing. */
if (!secp256k1_frost_lagrange_coefficient(&l, ids, n_pubnonces, my_id)) {
return 0;
}
secp256k1_scalar_mul(&session_i.challenge, &session_i.challenge, &l);
memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce));
secp256k1_frost_session_save(session, &session_i);
return 1;
}
#endif