
/**********************************************************************
 * Copyright (c) 2018 Andrew Poelstra, 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_MAIN_
#define _SECP256K1_MODULE_MUSIG_MAIN_

#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_musig.h"
#include "hash.h"

/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_pubkey *pk, size_t np) {
    secp256k1_sha256 sha;
    size_t i;

    secp256k1_sha256_initialize(&sha);
    for (i = 0; i < np; i++) {
        unsigned char ser[33];
        size_t serlen = sizeof(ser);
        if (!secp256k1_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) {
            return 0;
        }
        secp256k1_sha256_write(&sha, ser, serlen);
    }
    secp256k1_sha256_finalize(&sha, ell);
    return 1;
}

/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
 * SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) {
    secp256k1_sha256_initialize(sha);

    sha->s[0] = 0x0fd0690cul;
    sha->s[1] = 0xfefeae97ul;
    sha->s[2] = 0x996eac7ful;
    sha->s[3] = 0x5c30d864ul;
    sha->s[4] = 0x8c4a0573ul;
    sha->s[5] = 0xaca1a22ful;
    sha->s[6] = 0x6f43b801ul;
    sha->s[7] = 0x85ce27cdul;
    sha->bytes = 64;
}

/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) {
    secp256k1_sha256 sha;
    unsigned char buf[32];
    size_t i;

    secp256k1_musig_sha256_init_tagged(&sha);
    secp256k1_sha256_write(&sha, ell, 32);
    /* We're hashing the index of the signer instead of its public key as specified
     * in the MuSig paper. This reduces the total amount of data that needs to be
     * hashed.
     * Additionally, it prevents creating identical musig_coefficients for identical
     * public keys. A participant Bob could choose his public key to be the same as
     * Alice's, then replay Alice's messages (nonce and partial signature) to create
     * a valid partial signature. This is not a problem for MuSig per se, but could
     * result in subtle issues with protocols building on threshold signatures.
     * With the assumption that public keys are unique, hashing the index is
     * equivalent to hashing the public key. Because the public key can be
     * identified by the index given the ordered list of public keys (included in
     * ell), the index is just a different encoding of the public key.*/
    for (i = 0; i < sizeof(uint32_t); i++) {
        unsigned char c = idx;
        secp256k1_sha256_write(&sha, &c, 1);
        idx >>= 8;
    }
    secp256k1_sha256_finalize(&sha, buf);
    secp256k1_scalar_set_b32(r, buf, NULL);
}

typedef struct {
    const secp256k1_context *ctx;
    unsigned char ell[32];
    const secp256k1_pubkey *pks;
} 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;
    secp256k1_musig_coefficient(sc, ctx->ell, idx);
    return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
}


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].index = i;
        signers[i].present = 0;
    }
}

int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys) {
    secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
    secp256k1_gej pkj;
    secp256k1_ge pkp;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(combined_pk != NULL);
    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
    ARG_CHECK(pubkeys != NULL);
    ARG_CHECK(n_pubkeys > 0);

    ecmult_data.ctx = ctx;
    ecmult_data.pks = pubkeys;
    if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
        return 0;
    }
    if (!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
        return 0;
    }
    secp256k1_ge_set_gej(&pkp, &pkj);
    secp256k1_pubkey_save(combined_pk, &pkp);

    if (pk_hash32 != NULL) {
        memcpy(pk_hash32, ecmult_data.ell, 32);
    }
    return 1;
}

int secp256k1_musig_session_initialize(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_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey) {
    unsigned char combined_ser[33];
    size_t combined_ser_size = sizeof(combined_ser);
    int overflow;
    secp256k1_scalar secret;
    secp256k1_scalar mu;
    secp256k1_sha256 sha;
    secp256k1_gej rj;
    secp256k1_ge rp;

    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(pk_hash32 != NULL);
    ARG_CHECK(seckey != NULL);

    memset(session, 0, sizeof(*session));

    if (msg32 != NULL) {
        memcpy(session->msg, msg32, 32);
        session->msg_is_set = 1;
    } else {
        session->msg_is_set = 0;
    }
    memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
    memcpy(session->pk_hash, pk_hash32, 32);
    session->nonce_is_set = 0;
    session->has_secret_data = 1;
    if (n_signers == 0 || my_index >= n_signers) {
        return 0;
    }
    if (n_signers > UINT32_MAX) {
        return 0;
    }
    session->n_signers = (uint32_t) n_signers;
    secp256k1_musig_signers_init(signers, session->n_signers);
    session->nonce_commitments_hash_is_set = 0;

    /* Compute secret key */
    secp256k1_scalar_set_b32(&secret, seckey, &overflow);
    if (overflow) {
        secp256k1_scalar_clear(&secret);
        return 0;
    }
    secp256k1_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index);
    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->msg_is_set) {
        secp256k1_sha256_write(&sha, msg32, 32);
    }
    secp256k1_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED);
    secp256k1_sha256_write(&sha, combined_ser, combined_ser_size);
    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, &rj, &secret);
    secp256k1_ge_set_gej(&rp, &rj);
    secp256k1_pubkey_save(&session->nonce, &rp);

    if (nonce_commitment32 != NULL) {
        unsigned char commit[33];
        size_t commit_size = sizeof(commit);
        secp256k1_sha256_initialize(&sha);
        secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, &session->nonce, SECP256K1_EC_COMPRESSED);
        secp256k1_sha256_write(&sha, commit, commit_size);
        secp256k1_sha256_finalize(&sha, nonce_commitment32);
    }

    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, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments) {
    secp256k1_sha256 sha;
    unsigned char nonce_commitments_hash[32];
    size_t i;
    (void) ctx;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(session != NULL);
    ARG_CHECK(signers != NULL);
    ARG_CHECK(nonce != NULL);
    ARG_CHECK(commitments != NULL);

    if (!session->has_secret_data || n_commitments != session->n_signers) {
        return 0;
    }
    for (i = 0; i < n_commitments; i++) {
        ARG_CHECK(commitments[i] != NULL);
    }

    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);
    if (session->nonce_commitments_hash_is_set
            && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
        /* Abort if get_public_nonce has been called before with a different array of
         * commitments. */
        return 0;
    }
    memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32);
    session->nonce_commitments_hash_is_set = 1;
    memcpy(nonce, &session->nonce, sizeof(*nonce));
    return 1;
}

int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, 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(combined_pk != NULL);
    ARG_CHECK(pk_hash32 != NULL);
    ARG_CHECK(commitments != NULL);
    /* Check n_signers before checking commitments to allow testing the case where
     * n_signers is big without allocating the space. */
    if (n_signers > UINT32_MAX) {
        return 0;
    }
    for (i = 0; i < n_signers; i++) {
        ARG_CHECK(commitments[i] != NULL);
    }
    (void) ctx;

    memset(session, 0, sizeof(*session));

    memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
    if (n_signers == 0) {
        return 0;
    }
    session->n_signers = (uint32_t) n_signers;
    secp256k1_musig_signers_init(signers, session->n_signers);

    memcpy(session->pk_hash, pk_hash32, 32);
    session->nonce_is_set = 0;
    session->msg_is_set = 0;
    if (msg32 != NULL) {
        memcpy(session->msg, msg32, 32);
        session->msg_is_set = 1;
    }
    session->has_secret_data = 0;
    session->nonce_commitments_hash_is_set = 0;

    for (i = 0; i < n_signers; i++) {
        memcpy(signers[i].nonce_commitment, commitments[i], 32);
    }
    return 1;
}

int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const secp256k1_pubkey *nonce) {
    unsigned char commit[33];
    size_t commit_size = sizeof(commit);
    secp256k1_sha256 sha;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(signer != NULL);
    ARG_CHECK(nonce != NULL);

    secp256k1_sha256_initialize(&sha);
    secp256k1_ec_pubkey_serialize(ctx, commit, &commit_size, nonce, SECP256K1_EC_COMPRESSED);
    secp256k1_sha256_write(&sha, commit, commit_size);
    secp256k1_sha256_finalize(&sha, commit);

    if (memcmp(commit, signer->nonce_commitment, 32) != 0) {
        return 0;
    }
    memcpy(&signer->nonce, nonce, sizeof(*nonce));
    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_is_negated, 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);

    if (n_signers != session->n_signers) {
        return 0;
    }
    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_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);
    /* Either the session is a verifier session or or the nonce_commitments_hash has
     * been set in `musig_session_get_public_nonce`. */
    VERIFY_CHECK(!session->has_secret_data || session->nonce_commitments_hash_is_set);
    if (session->has_secret_data
            && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
        /* 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.
         * */
        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);
    }
    secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
    if (secp256k1_fe_is_quad_var(&combined_noncep.y)) {
        session->nonce_is_negated = 0;
    } else {
        session->nonce_is_negated = 1;
        secp256k1_ge_neg(&combined_noncep, &combined_noncep);
    }
    if (nonce_is_negated != NULL) {
        *nonce_is_negated = session->nonce_is_negated;
    }
    secp256k1_pubkey_save(&session->combined_nonce, &combined_noncep);
    session->nonce_is_set = 1;
    return 1;
}

int secp256k1_musig_session_set_msg(const secp256k1_context* ctx, secp256k1_musig_session *session, const unsigned char *msg32) {
    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(session != NULL);
    ARG_CHECK(msg32 != NULL);

    if (session->msg_is_set) {
        return 0;
    }
    memcpy(session->msg, msg32, 32);
    session->msg_is_set = 1;
    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 int secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
    unsigned char buf[33];
    size_t bufsize = 33;
    secp256k1_ge rp;
    secp256k1_sha256 sha;

    secp256k1_sha256_initialize(&sha);
    if (!session->nonce_is_set) {
        return 0;
    }
    secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce);
    secp256k1_fe_get_b32(buf, &rp.x);
    secp256k1_sha256_write(&sha, buf, 32);
    secp256k1_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED);
    VERIFY_CHECK(bufsize == 33);
    secp256k1_sha256_write(&sha, buf, bufsize);
    if (!session->msg_is_set) {
        return 0;
    }
    secp256k1_sha256_write(&sha, session->msg, 32);
    secp256k1_sha256_finalize(&sha, msghash);
    return 1;
}

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);

    if (!session->nonce_is_set || !session->has_secret_data) {
        return 0;
    }

    /* build message hash */
    if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
        return 0;
    }
    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->nonce_is_negated) {
        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, secp256k1_schnorrsig *sig, 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(sig != NULL);
    ARG_CHECK(partial_sigs != NULL);
    ARG_CHECK(session != NULL);

    if (!session->nonce_is_set) {
        return 0;
    }
    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);
    }

    secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce);
    VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y));
    secp256k1_fe_normalize(&noncep.x);
    secp256k1_fe_get_b32(&sig->data[0], &noncep.x);
    secp256k1_scalar_get_b32(&sig->data[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_pubkey *pubkey) {
    unsigned char msghash[32];
    secp256k1_scalar s;
    secp256k1_scalar e;
    secp256k1_scalar mu;
    secp256k1_gej rj;
    secp256k1_ge rp;
    int overflow;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
    ARG_CHECK(session != NULL);
    ARG_CHECK(signer != NULL);
    ARG_CHECK(partial_sig != NULL);
    ARG_CHECK(pubkey != NULL);

    if (!session->nonce_is_set || !signer->present) {
        return 0;
    }
    secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
    if (overflow) {
        return 0;
    }
    if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
        return 0;
    }
    secp256k1_scalar_set_b32(&e, msghash, NULL);

    /* Multiplying the messagehash by the musig coefficient is equivalent
     * to multiplying the signer's public key by the coefficient, except
     * much easier to do. */
    secp256k1_musig_coefficient(&mu, session->pk_hash, signer->index);
    secp256k1_scalar_mul(&e, &e, &mu);

    if (!secp256k1_pubkey_load(ctx, &rp, &signer->nonce)) {
        return 0;
    }

    if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) {
        return 0;
    }
    if (!session->nonce_is_negated) {
        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_is_negated) {
    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_is_negated) {
        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 secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) {
    secp256k1_scalar t;
    secp256k1_scalar s;
    int overflow;
    size_t i;

    (void) ctx;
    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(sec_adaptor32 != NULL);
    ARG_CHECK(sig != NULL);
    ARG_CHECK(partial_sigs != NULL);

    secp256k1_scalar_set_b32(&t, &sig->data[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_is_negated) {
        secp256k1_scalar_negate(&t, &t);
    }
    secp256k1_scalar_get_b32(sec_adaptor32, &t);
    secp256k1_scalar_clear(&t);
    return 1;
}

#endif

