Skip to content

Commit 3860876

Browse files
committed
Add 3-of-3 MuSig example
1 parent 69d344d commit 3860876

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

src/modules/musig/Makefile.am.include

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
11
include_HEADERS += include/secp256k1_musig.h
22
noinst_HEADERS += src/modules/musig/main_impl.h
33
noinst_HEADERS += src/modules/musig/tests_impl.h
4+
5+
noinst_PROGRAMS += example_musig
6+
example_musig_SOURCES = src/modules/musig/example.c
7+
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES)
8+
if !ENABLE_COVERAGE
9+
example_musig_CPPFLAGS += -DVERIFY
10+
endif
11+
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS)
12+
example_musig_LDFLAGS = -static
13+
14+
if USE_TESTS
15+
TESTS += example_musig
16+
endif

src/modules/musig/example.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**********************************************************************
2+
* Copyright (c) 2018 Jonas Nick *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
/**
8+
* This file demonstrates how to use the MuSig module to create a multisignature.
9+
* Additionally, see the documentation in include/secp256k1_musig.h.
10+
*/
11+
12+
#include <stdio.h>
13+
#include <assert.h>
14+
#include <secp256k1.h>
15+
#include <secp256k1_schnorrsig.h>
16+
#include <secp256k1_musig.h>
17+
18+
/* Number of public keys involved in creating the aggregate signature */
19+
#define N_SIGNERS 3
20+
/* Create a key pair and store it in seckey and pubkey */
21+
int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pubkey* pubkey) {
22+
int ret;
23+
FILE *frand = fopen("/dev/urandom", "r");
24+
do {
25+
if (frand == NULL || !fread(seckey, 32, 1, frand)) {
26+
return 0;
27+
}
28+
/* The probability that this not a valid secret key is approximately 2^-128 */
29+
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
30+
fclose(frand);
31+
ret = secp256k1_ec_pubkey_create(ctx, pubkey, seckey);
32+
return ret;
33+
}
34+
35+
/* Sign a message hash with the given key pairs and store the result in sig */
36+
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_pubkey* pubkeys, const unsigned char* msg32, secp256k1_schnorrsig *sig) {
37+
secp256k1_musig_session musig_session[3];
38+
unsigned char nonce_commitment[N_SIGNERS][32];
39+
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
40+
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS];
41+
secp256k1_pubkey nonce[N_SIGNERS];
42+
int i, j;
43+
secp256k1_musig_partial_signature partial_sig[N_SIGNERS];
44+
45+
for (i = 0; i < N_SIGNERS; i++) {
46+
FILE *frand;
47+
unsigned char session_id32[32];
48+
unsigned char pk_hash[32];
49+
secp256k1_pubkey combined_pk;
50+
51+
/* Create combined pubkey and initialize signer data */
52+
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) {
53+
return 0;
54+
}
55+
/* Create random session ID. It is absolutely necessary that the session ID
56+
* is unique for every call of secp256k1_musig_session_initialize. */
57+
frand = fopen("/dev/urandom", "r");
58+
if (frand == NULL || !fread(session_id32, 32, 1, frand)) {
59+
return 0;
60+
}
61+
fclose(frand);
62+
/* Initialize session */
63+
if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, pubkeys, N_SIGNERS, i, seckeys[i])) {
64+
return 0;
65+
}
66+
nonce_commitment_ptr[i] = nonce_commitment[i];
67+
}
68+
/* Communication round 1: Exchange nonce commitments */
69+
for (i = 0; i < N_SIGNERS; i++) {
70+
/* Set nonce commitments in the signer data and get the own public nonce */
71+
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) {
72+
return 0;
73+
}
74+
}
75+
/* Communication round 2: Exchange nonces */
76+
for (i = 0; i < N_SIGNERS; i++) {
77+
for (j = 0; j < N_SIGNERS; j++) {
78+
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) {
79+
/* Signer j's nonce does not match the nonce commitment. Wait
80+
* until the correct nonce is received or restart the protocol
81+
* (with a different session ID of course). */
82+
return 0;
83+
}
84+
}
85+
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) {
86+
return 0;
87+
}
88+
}
89+
for (i = 0; i < N_SIGNERS; i++) {
90+
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) {
91+
return 0;
92+
}
93+
}
94+
/* Communication round 3: Exchange partial signatures */
95+
for (i = 0; i < N_SIGNERS; i++) {
96+
for (j = 0; j < N_SIGNERS; j++) {
97+
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j])) {
98+
return 0;
99+
}
100+
}
101+
}
102+
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS);
103+
}
104+
105+
int main(void) {
106+
secp256k1_context* ctx;
107+
int i;
108+
unsigned char seckeys[N_SIGNERS][32];
109+
secp256k1_pubkey pubkeys[N_SIGNERS];
110+
secp256k1_pubkey combined_pk;
111+
unsigned char msg[32] = "this_should_actually_be_msg_hash";
112+
secp256k1_schnorrsig sig;
113+
114+
/* Create a context for signing and verification */
115+
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
116+
printf("Creating key pairs......");
117+
for (i = 0; i < N_SIGNERS; i++) {
118+
if (!create_key(ctx, seckeys[i], &pubkeys[i])) {
119+
printf("FAILED\n");
120+
return 1;
121+
}
122+
}
123+
printf("ok\n");
124+
printf("Combining public keys...");
125+
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) {
126+
printf("FAILED\n");
127+
return 0;
128+
}
129+
printf("ok\n");
130+
printf("Signing message.........");
131+
if (!sign(ctx, seckeys, pubkeys, msg, &sig)) {
132+
printf("FAILED\n");
133+
return 1;
134+
}
135+
printf("ok\n");
136+
printf("Verifying signature.....");
137+
if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) {
138+
printf("FAILED\n");
139+
return 1;
140+
}
141+
printf("ok\n");
142+
secp256k1_context_destroy(ctx);
143+
return 0;
144+
}
145+

0 commit comments

Comments
 (0)