musig: add ordinary and xonly tweaking to the example
This commit is contained in:
parent
37107361a0
commit
57a17929fc
@ -52,14 +52,51 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache
|
||||
* and return the tweaked aggregate pk. */
|
||||
int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
|
||||
secp256k1_pubkey output_pk;
|
||||
unsigned char ordinary_tweak[32] = "this could be a BIP32 tweak....";
|
||||
unsigned char xonly_tweak[32] = "this could be a taproot tweak..";
|
||||
|
||||
|
||||
/* Ordinary tweaking which, for example, allows deriving multiple child
|
||||
* public keys from a single aggregate key using BIP32 */
|
||||
if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, ordinary_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that we did not provided an output_pk argument, because the
|
||||
* resulting pk is also saved in the cache and so if one is just interested
|
||||
* in signing the output_pk argument is unnecessary. On the other hand, if
|
||||
* one is not interested in signing, the same output_pk can be obtained by
|
||||
* calling `secp256k1_musig_pubkey_get` right after key aggregation to get
|
||||
* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */
|
||||
|
||||
/* Xonly tweaking which, for example, allows creating taproot commitments */
|
||||
if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that if we wouldn't care about signing, we can arrive at the same
|
||||
* output_pk by providing the untweaked public key to
|
||||
* `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey
|
||||
* if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */
|
||||
|
||||
/* Now we convert the output_pk to an xonly pubkey to allow to later verify
|
||||
* the Schnorr signature against it. For this purpose we can ignore the
|
||||
* `pk_parity` output argument; we would need it if we would have to open
|
||||
* the taproot commitment. */
|
||||
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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 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) {
|
||||
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++) {
|
||||
@ -86,7 +123,6 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
||||
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
|
||||
@ -94,21 +130,18 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
||||
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;
|
||||
}
|
||||
/* Create aggregate nonce and initialize the session */
|
||||
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)) {
|
||||
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)) {
|
||||
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;
|
||||
@ -127,7 +160,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
||||
* 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)) {
|
||||
if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -141,6 +174,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
||||
struct signer signers[N_SIGNERS];
|
||||
const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
||||
unsigned char sig[64];
|
||||
|
||||
@ -156,13 +190,21 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Combining public keys...");
|
||||
if (!secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, NULL, pubkeys_ptr, N_SIGNERS)) {
|
||||
/* If you just want to aggregate and not sign the cache can be NULL */
|
||||
if (!secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Tweaking................");
|
||||
/* Optionally tweak the aggregate key */
|
||||
if (!tweak(ctx, &agg_pk, &cache)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
if (!sign(ctx, signer_secrets, signers, msg, sig)) {
|
||||
if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user