Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1/*************************************************************************2* To the extent possible under law, the author(s) have dedicated all *3* copyright and related and neighboring rights to the software in this *4* file to the public domain worldwide. This software is distributed *5* without any warranty. For the CC0 Public Domain Dedication, see *6* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *7*************************************************************************/9/** This file demonstrates how to use the MuSig module to create a10* 3-of-3 multisignature. Additionally, see the documentation in11* include/secp256k1_musig.h and doc/musig.md.12*/14#include <stdio.h>15#include <stdlib.h>16#include <assert.h>17#include <string.h>19#include <secp256k1.h>20#include <secp256k1_extrakeys.h>21#include <secp256k1_musig.h>22#include <secp256k1_schnorrsig.h>24#include "examples_util.h"26struct signer_secrets {27secp256k1_keypair keypair;28secp256k1_musig_secnonce secnonce;29};31struct signer {32secp256k1_pubkey pubkey;33secp256k1_musig_pubnonce pubnonce;34secp256k1_musig_partial_sig partial_sig;35};37/* Number of public keys involved in creating the aggregate signature */38#define N_SIGNERS 339/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */40static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {41unsigned char seckey[32];43if (!fill_random(seckey, sizeof(seckey))) {44printf("Failed to generate randomness\n");45return 0;46}47/* Try to create a keypair with a valid context. This only fails if the48* secret key is zero or out of range (greater than secp256k1's order). Note49* that the probability of this occurring is negligible with a properly50* functioning random number generator. */51if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {52return 0;53}54if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {55return 0;56}58secure_erase(seckey, sizeof(seckey));59return 1;60}62/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache63* and return the tweaked aggregate pk. */64static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {65secp256k1_pubkey output_pk;66/* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP67* 32. */68unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";69/* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as70* defined in BIP 341 */71unsigned char xonly_tweak[32] = "this could be a Taproot tweak..";74/* Plain tweaking which, for example, allows deriving multiple child75* public keys from a single aggregate key using BIP32 */76if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {77return 0;78}79/* Note that we did not provide an output_pk argument, because the80* resulting pk is also saved in the cache and so if one is just interested81* in signing, the output_pk argument is unnecessary. On the other hand, if82* one is not interested in signing, the same output_pk can be obtained by83* calling `secp256k1_musig_pubkey_get` right after key aggregation to get84* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */86/* Xonly tweaking which, for example, allows creating Taproot commitments */87if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {88return 0;89}90/* Note that if we wouldn't care about signing, we can arrive at the same91* output_pk by providing the untweaked public key to92* `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey93* if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */95/* Now we convert the output_pk to an xonly pubkey to allow to later verify96* the Schnorr signature against it. For this purpose we can ignore the97* `pk_parity` output argument; we would need it if we would have to open98* the Taproot commitment. */99if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {100return 0;101}102return 1;103}105/* Sign a message hash with the given key pairs and store the result in sig */106static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {107int i;108const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];109const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];110/* The same for all signers */111secp256k1_musig_session session;112secp256k1_musig_aggnonce agg_pubnonce;114for (i = 0; i < N_SIGNERS; i++) {115unsigned char seckey[32];116unsigned char session_secrand[32];117/* Create random session ID. It is absolutely necessary that the session ID118* is unique for every call of secp256k1_musig_nonce_gen. Otherwise119* it's trivial for an attacker to extract the secret key! */120if (!fill_random(session_secrand, sizeof(session_secrand))) {121return 0;122}123if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {124return 0;125}126/* Initialize session and create secret nonce for signing and public127* nonce to send to the other signers. */128if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {129return 0;130}131pubnonces[i] = &signer[i].pubnonce;133secure_erase(seckey, sizeof(seckey));134}136/* Communication round 1: Every signer sends their pubnonce to the137* coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends138* agg_pubnonce to each signer */139if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {140return 0;141}143/* Every signer creates a partial signature */144for (i = 0; i < N_SIGNERS; i++) {145/* Initialize the signing session by processing the aggregate nonce */146if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) {147return 0;148}149/* partial_sign will clear the secnonce by setting it to 0. That's because150* you must _never_ reuse the secnonce (or use the same session_secrand to151* create a secnonce). If you do, you effectively reuse the nonce and152* leak the secret key. */153if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {154return 0;155}156partial_sigs[i] = &signer[i].partial_sig;157}158/* Communication round 2: Every signer sends their partial signature to the159* coordinator, who verifies the partial signatures and aggregates them. */160for (i = 0; i < N_SIGNERS; i++) {161/* To check whether signing was successful, it suffices to either verify162* the aggregate signature with the aggregate public key using163* secp256k1_schnorrsig_verify, or verify all partial signatures of all164* signers individually. Verifying the aggregate signature is cheaper but165* verifying the individual partial signatures has the advantage that it166* can be used to determine which of the partial signatures are invalid167* (if any), i.e., which of the partial signatures cause the aggregate168* signature to be invalid and thus the protocol run to fail. It's also169* fine to first verify the aggregate sig, and only verify the individual170* sigs if it does not work.171*/172if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) {173return 0;174}175}176return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);177}179int main(void) {180secp256k1_context* ctx;181int i;182struct signer_secrets signer_secrets[N_SIGNERS];183struct signer signers[N_SIGNERS];184const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];185secp256k1_xonly_pubkey agg_pk;186secp256k1_musig_keyagg_cache cache;187unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";188unsigned char sig[64];190/* Create a secp256k1 context */191ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);192printf("Creating key pairs......");193fflush(stdout);194for (i = 0; i < N_SIGNERS; i++) {195if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {196printf("FAILED\n");197return EXIT_FAILURE;198}199pubkeys_ptr[i] = &signers[i].pubkey;200}201printf("ok\n");203/* The aggregate public key produced by secp256k1_musig_pubkey_agg depends204* on the order of the provided public keys. If there is no canonical order205* of the signers, the individual public keys can optionally be sorted with206* secp256k1_ec_pubkey_sort to ensure that the aggregate public key is207* independent of the order of signers. */208printf("Sorting public keys.....");209fflush(stdout);210if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) {211printf("FAILED\n");212return EXIT_FAILURE;213}214printf("ok\n");216printf("Combining public keys...");217fflush(stdout);218/* If you just want to aggregate and not sign, you can call219* secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL220* while providing a non-NULL agg_pk argument. */221if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) {222printf("FAILED\n");223return EXIT_FAILURE;224}225printf("ok\n");226printf("Tweaking................");227fflush(stdout);228/* Optionally tweak the aggregate key */229if (!tweak(ctx, &agg_pk, &cache)) {230printf("FAILED\n");231return EXIT_FAILURE;232}233printf("ok\n");234printf("Signing message.........");235fflush(stdout);236if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {237printf("FAILED\n");238return EXIT_FAILURE;239}240printf("ok\n");241printf("Verifying signature.....");242fflush(stdout);243if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) {244printf("FAILED\n");245return EXIT_FAILURE;246}247printf("ok\n");249/* It's best practice to try to clear secrets from memory after using them.250* This is done because some bugs can allow an attacker to leak memory, for
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.