examples/musig.c
int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const unsigned char* msg32, unsigned char *sig64) {
    int i;
    const secp256k1_xonly_pubkey *pubkeys[N_SIGNERS];
    const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
    const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
    /* The same for all signers */
    secp256k1_musig_keyagg_cache cache;
    secp256k1_musig_session session;

    for (i = 0; i < N_SIGNERS; i++) {
        FILE *frand;
        unsigned char seckey[32];
        unsigned char session_id[32];
        /* Create random session ID. It is absolutely necessary that the session ID
         * is unique for every call of secp256k1_musig_nonce_gen. 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_id, 32, 1, frand)) {
            fclose(frand);
            return 0;
        }
        fclose(frand);
        if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
            return 0;
        }
        /* Initialize session and create secret nonce for signing and public
         * nonce to send to the other signers. */
        if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, msg32, NULL, NULL)) {
            return 0;
        }
        pubkeys[i] = &signer[i].pubkey;
        pubnonces[i] = &signer[i].pubnonce;
    }
    /* Communication round 1: A production system would exchange public nonces
     * here before moving on. */
    for (i = 0; i < N_SIGNERS; i++) {
        secp256k1_musig_aggnonce agg_pubnonce;

        /* Create aggregate pubkey, aggregate nonce and initialize signer data */
        if (!secp256k1_musig_pubkey_agg(ctx, NULL, NULL, &cache, pubkeys, N_SIGNERS)) {
            return 0;
        }
        if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
            return 0;
        }
        if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, &cache, NULL)) {
            return 0;
        }
        /* partial_sign will clear the secnonce by setting it to 0. That's because
         * you must _never_ reuse the secnonce (or use the same session_id to
         * create a secnonce). If you do, you effectively reuse the nonce and
         * leak the secret key. */
        if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, &cache, &session)) {
            return 0;
        }
        partial_sigs[i] = &signer[i].partial_sig;
    }
    /* Communication round 2: A production system would exchange
     * partial signatures here before moving on. */
    for (i = 0; i < N_SIGNERS; i++) {
        /* To check whether signing was successful, it suffices to either verify
         * the aggregate signature with the aggregate public key using
         * secp256k1_schnorrsig_verify, or verify all partial signatures of all
         * signers individually. Verifying the aggregate 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 aggregate
         * signature to be invalid and thus the protocol run to fail. It's also
         * fine to first verify the aggregate sig, and only verify the individual
         * sigs if it does not work.
         */
        if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, &cache, &session)) {
            return 0;
        }
    }
    return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
}
/* Sign a message hash with the given key pairs and store the result in sig */
Sign a message hash with the given key pairs and store the result in sig
Sign a message hash with the given key pairs and store the result in sig
int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const unsigned char* msg32, unsigned char *sig64) {
    int i;
    const secp256k1_xonly_pubkey *pubkeys[N_SIGNERS];
    const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
    const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
    secp256k1_musig_keyagg_cache cache;
    secp256k1_musig_session session;
    for (i = 0; i < N_SIGNERS; i++) {
        FILE *frand;
        unsigned char seckey[32];
        unsigned char session_id[32];
        frand = fopen("/dev/urandom", "r");
        if(frand == NULL) {
            return 0;
        }
        if (!fread(session_id, 32, 1, frand)) {
            fclose(frand);
            return 0;
        }
        fclose(frand);
        if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
            return 0;
        }
        if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, msg32, NULL, NULL)) {
            return 0;
        }
        pubkeys[i] = &signer[i].pubkey;
        pubnonces[i] = &signer[i].pubnonce;
    }
    for (i = 0; i < N_SIGNERS; i++) {
        secp256k1_musig_aggnonce agg_pubnonce;
        if (!secp256k1_musig_pubkey_agg(ctx, NULL, NULL, &cache, pubkeys, N_SIGNERS)) {
            return 0;
        }
        if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
            return 0;
        }
        if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, &cache, NULL)) {
            return 0;
        }
        if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, &cache, &session)) {
            return 0;
        }
        partial_sigs[i] = &signer[i].partial_sig;
    }
    for (i = 0; i < N_SIGNERS; i++) {
        if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, &cache, &session)) {
            return 0;
        }
    }
    return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
}
int sign ( const secp256k1_context * ctx , struct signer_secrets * signer_secrets , struct signer * signer , const unsigned char * msg32 , unsigned char * sig64 ) { int i ; const secp256k1_xonly_pubkey * pubkeys [ N_SIGNERS ] ; const secp256k1_musig_pubnonce * pubnonces [ N_SIGNERS ] ; const secp256k1_musig_partial_sig * partial_sigs [ N_SIGNERS ] ; secp256k1_musig_keyagg_cache cache ; secp256k1_musig_session session ; for ( i = 0 ; i < N_SIGNERS ; i ++ ) { FILE * frand ; unsigned char seckey [ 32 ] ; unsigned char session_id [ 32 ] ; frand = fopen ( " " , " " ) ; if ( frand == NULL ) { return 0 ; } if ( ! fread ( session_id , 32 , 1 , frand ) ) { fclose ( frand ) ; return 0 ; } fclose ( frand ) ; if ( ! secp256k1_keypair_sec ( ctx , seckey , & signer_secrets [ i ] . keypair ) ) { return 0 ; } if ( ! secp256k1_musig_nonce_gen ( ctx , & signer_secrets [ i ] . secnonce , & signer [ i ] . pubnonce , session_id , seckey , msg32 , NULL , NULL ) ) { return 0 ; } pubkeys [ i ] = & signer [ i ] . pubkey ; pubnonces [ i ] = & signer [ i ] . pubnonce ; } for ( i = 0 ; i < N_SIGNERS ; i ++ ) { secp256k1_musig_aggnonce agg_pubnonce ; if ( ! secp256k1_musig_pubkey_agg ( ctx , NULL , NULL , & cache , pubkeys , N_SIGNERS ) ) { return 0 ; } if ( ! secp256k1_musig_nonce_agg ( ctx , & agg_pubnonce , pubnonces , N_SIGNERS ) ) { return 0 ; } if ( ! secp256k1_musig_nonce_process ( ctx , & session , & agg_pubnonce , msg32 , & cache , NULL ) ) { return 0 ; } if ( ! secp256k1_musig_partial_sign ( ctx , & signer [ i ] . partial_sig , & signer_secrets [ i ] . secnonce , & signer_secrets [ i ] . keypair , & cache , & session ) ) { return 0 ; } partial_sigs [ i ] = & signer [ i ] . partial_sig ; } for ( i = 0 ; i < N_SIGNERS ; i ++ ) { if ( ! secp256k1_musig_partial_sig_verify ( ctx , & signer [ i ] . partial_sig , & signer [ i ] . pubnonce , & signer [ i ] . pubkey , & cache , & session ) ) { return 0 ; } } return secp256k1_musig_partial_sig_agg ( ctx , sig64 , & session , partial_sigs , N_SIGNERS ) ; }
Sign a message hash with the given key pairs and store the result in sig
Sign a message hash with the given key pairs and store the result in sig
/* The same for all signers */ /* Create random session ID. It is absolutely necessary that the session ID
         * is unique for every call of secp256k1_musig_nonce_gen. Otherwise
         * it's trivial for an attacker to extract the secret key! */ /* Initialize session and create secret nonce for signing and public
         * nonce to send to the other signers. */ /* Communication round 1: A production system would exchange public nonces
     * here before moving on. */ /* Create aggregate pubkey, aggregate nonce and initialize signer data */ /* partial_sign will clear the secnonce by setting it to 0. That's because
         * you must _never_ reuse the secnonce (or use the same session_id to
         * create a secnonce). If you do, you effectively reuse the nonce and
         * leak the secret key. */ /* Communication round 2: A production system would exchange
     * partial signatures here before moving on. */ /* To check whether signing was successful, it suffices to either verify
         * the aggregate signature with the aggregate public key using
         * secp256k1_schnorrsig_verify, or verify all partial signatures of all
         * signers individually. Verifying the aggregate 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 aggregate
         * signature to be invalid and thus the protocol run to fail. It's also
         * fine to first verify the aggregate sig, and only verify the individual
         * sigs if it does not work.
         */