Merge ElementsProject/secp256k1-zkp#151: MuSig: Add Minimal Compatibility with BIP32 Tweaking

8088eddc534cbbb89dd5f892828c4013416c4f2b musig: add test vector for ordinary (non xonly) tweaking (Elliott Jin)
57a17929fc0056efb5436a6001597d656591e1ad musig: add ordinary and xonly tweaking to the example (Jonas Nick)
37107361a0ff3b8764903e3b384cfc12ed484e7a musig: allow ordinary, non-xonly tweaking (Jonas Nick)
c519b468791670654f8b66368a675655cd337ae8 musig: add pubkey_get to obtain a full pubkey from a keyagg_cache (Jonas Nick)

Pull request description:

  In short, `musig_pubkey_tweak_add` now allows for xonly _and_ "ordinary" tweaking. Also, in order to allow using `ec_pubkey_tweak_add` on the non-xonly aggregate public key, there's a new function `musig_pubkey_get` that allows obtaining it from the `keyagg_cache`.

  One alternative would be that instead of adding `musig_pubkey_get`, we could change `pubkey_agg` to output an ordinary (non-xonly) pubkey. Then users of the API who do not need ordinary (BIP32) tweaking would be forced to call `xonly_pubkey_from_pubkey`. And we'd probably want to change the spec. And it would be a bit weird to output a pubkey that can't be directly schnorrsig_verify'd.

  Based on #131

ACKs for top commit:
  robot-dreams:
    ACK 8088eddc534cbbb89dd5f892828c4013416c4f2b based on https://github.com/ElementsProject/secp256k1-zkp/pull/151#issuecomment-1005198409 and the following `range-diff`:

Tree-SHA512: a4a0100f0470c870f88a8da27dbcc4684fcc2caabb368d4340e962e08d5ee04634e6289bafa3448dbfd0b5793a3e70de5bd6ddca7a619cc3220ff762d518a8fe
This commit is contained in:
Tim Ruffing 2022-01-25 10:17:17 +01:00
commit 772df3694e
No known key found for this signature in database
GPG Key ID: 8C461CCD293F6011
5 changed files with 298 additions and 110 deletions

View File

@ -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;
}

View File

@ -223,16 +223,77 @@ SECP256K1_API int secp256k1_musig_pubkey_agg(
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
/** Tweak an x-only public key in a given keyagg_cache by adding
* the generator multiplied with `tweak32` to it.
/** Obtain the aggregate public key from a keyagg_cache.
*
* This is only useful if you need the non-xonly public key, in particular for
* ordinary (non-xonly) tweaking or batch-verifying multiple key aggregations
* (not implemented).
*
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: agg_pk: the MuSig-aggregated public key.
* In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
* `musig_pubkey_agg`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
const secp256k1_context* ctx,
secp256k1_pubkey *agg_pk,
secp256k1_musig_keyagg_cache *keyagg_cache
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Apply ordinary "EC" tweaking to a public key in a given keyagg_cache by
* adding the generator multiplied with `tweak32` to it. This is useful for
* deriving child keys from an aggregate public key via BIP32.
*
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
* the following pseudocode buf and buf2 have identical contents (absent
* earlier failures).
*
* secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...)
* secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache)
* secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache)
* secp256k1_ec_pubkey_serialize(..., buf, output_pk)
* secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32)
* secp256k1_ec_pubkey_serialize(..., buf2, agg_pk)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
* On the other hand, if you are only computing a public key, but not intending
* to create a signature for it, you can just use
* `secp256k1_ec_pubkey_tweak_add`.
*
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
* Args: ctx: pointer to a context object initialized for verification
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0. If you
* do not need it, this arg can be NULL.
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
* `musig_pubkey_agg`
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid
* according to `secp256k1_ec_seckey_verify`, this function
* returns 0. For uniformly random 32-byte arrays the
* chance of being invalid is negligible (around 1 in
* 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(
const secp256k1_context* ctx,
secp256k1_pubkey *output_pubkey,
secp256k1_musig_keyagg_cache *keyagg_cache,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the
* generator multiplied with `tweak32` to it. This is useful for creating
* Taproot outputs.
*
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
* failures) returns 1.
*
* secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...)
* secp256k1_musig_pubkey_tweak_add(..., output_pubkey, tweak32, keyagg_cache)
* secp256k1_xonly_pubkey_serialize(..., buf, output_pubkey)
* secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, tweak32, keyagg_cache)
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
@ -255,7 +316,7 @@ SECP256K1_API int secp256k1_musig_pubkey_agg(
* chance of being invalid is negligible (around 1 in
* 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(
const secp256k1_context* ctx,
secp256k1_pubkey *output_pubkey,
secp256k1_musig_keyagg_cache *keyagg_cache,

View File

@ -244,7 +244,21 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s
return 1;
}
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache) {
secp256k1_keyagg_cache_internal cache_i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(agg_pk != NULL);
memset(agg_pk, 0, sizeof(*agg_pk));
ARG_CHECK(keyagg_cache != NULL);
if(!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
return 0;
}
secp256k1_pubkey_save(agg_pk, &cache_i.pk);
return 1;
}
static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) {
secp256k1_keyagg_cache_internal cache_i;
int overflow = 0;
secp256k1_scalar tweak;
@ -263,7 +277,7 @@ int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pub
if (overflow) {
return 0;
}
if (secp256k1_extrakeys_ge_even_y(&cache_i.pk)) {
if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) {
cache_i.internal_key_parity ^= 1;
secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak);
}
@ -280,4 +294,12 @@ int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pub
return 1;
}
int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0);
}
int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1);
}
#endif

View File

@ -538,56 +538,65 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
* The following public keys arise as intermediate steps:
* - P[i] is the i-th public key with corresponding secret key x[i]
* P[i] := x[i]*G
* - P_agg is the aggregate public key
* P_agg := mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|
* - P_tweak[i] is the tweaked public key after the i-th tweaking operation
* P_tweak[0] := P_agg
* P_tweak[i] := |P_tweak[i-1]| + t[i]*G for i = 1, ..., m
* - P_agg[0] is the aggregate public key
* P_agg[0] := mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|
* - P_agg[i] for 1 <= i <= m is the tweaked public key after the i-th
* tweaking operation. There are two types of tweaking: x-only and ordinary
* "EC" tweaking. We define a boolean predicate xonly(i) that is true if
* the i-th tweaking operation is x-only tweaking and false otherwise
* (ordinary tweaking).
* Let
* P_agg[i] := f(i, P_agg[i-1]) + t[i]*G for i = 1, ..., m
* where f(i, X) := |X| if xonly(i)
* f(i, X) := X otherwise
*
* Note that our goal is to produce a partial signature corresponding to
* the final public key after m tweaking operations P_final = |P_tweak[m]|.
* the final public key after m tweaking operations P_final = |P_agg[m]|.
*
* Define d[i], d_agg, and d_tweak[i] so that:
* Define d[i] for 0 <= i <= n-1 and d_agg[i] for 0 <= i <= m so that:
* - |P[i]| = d[i]*P[i]
* - |P_agg| = d_agg*P_agg
* - |P_tweak[i]| = d_tweak[i]*P_tweak[i]
* - f(i+1, P_agg[i]) = d_agg[i]*P_agg[i] for 0 <= i <= m - 1
* - |P_agg[m]| = d_agg[m]*P_agg[m]
*
* In other words, d[i] = 1 if P[i] has even y coordinate, -1 otherwise;
* similarly for d_agg and d_tweak[i].
* In other words, d[i] = 1 if P[i] has even y coordinate, -1 otherwise.
* For 0 <= i <= m-1, d_agg[i] is -1 if and only if xonly(i+1) is true and
* P_agg[i] has an odd Y coordinate.
*
* The (xonly) final public key is P_final = |P_tweak[m]|
* = d_tweak[m]*P_tweak[m]
* = d_tweak[m]*(|P_tweak[m-1]| + t[m]*G)
* = d_tweak[m]*(d_tweak[m-1]*(|P_tweak[m-2]| + t[m-1]*G) + t[m]*G)
* = d_tweak[m]*...*d_tweak[1]*|P_agg| + (d_tweak[m]*t[m]+...+*d_tweak[1]*t[1])*G.
* The (x-only) final public key is P_final = |P_agg[m]|
* = d_agg[m]*P_agg[m]
* = d_agg[m]*(f(m, P_agg[m-1]) + t[m]*G)
* = d_agg[m]*(d_agg[m-1]*(f(m-1, P_agg[m-2]) + t[m-1]*G) + t[m]*G)
* = d_agg[m]*...*d_agg[0]*P_agg[0] + (d_agg[m]*t[m]+...+*d_agg[1]*t[1])*G.
* To simplify the equation let us define
* t := d_tweak[m]*t[m]+...+*d_tweak[1]*t[1]
* d_tweak := d_tweak[m]*...*d_tweak[1].
* d_agg := d_agg[m]*...*d_agg[0].
* t := d_agg[m]*t[m]+...+*d_agg[1]*t[1] if m > 0, otherwise t := 0
* Then we have
* P_final - t*G
* = d_tweak*|P_agg|
* = d_tweak*d_agg*P_agg
* = d_tweak*d_agg*(mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|)
* = d_tweak*d_agg*(d[0]*mu[0]*P[0] + ... + d[n-1]*mu[n-1]*P[n-1])
* = sum((d_tweak*d_agg*d[i])*mu[i]*x[i])*G.
* = d_agg*P_agg[0]
* = d_agg*(mu[0]*|P[0]| + ... + mu[n-1]*|P[n-1]|)
* = d_agg*(d[0]*mu[0]*P[0] + ... + d[n-1]*mu[n-1]*P[n-1])
* = sum((d_agg*d[i])*mu[i]*x[i])*G.
*
* Thus whether signer i should use the negated x[i] depends on the product
* d_tweak[m]*...*d_tweak[1]*d_agg*d[i]. In other words, negate if and only
* d_agg[m]*...*d_agg[1]*d_agg[0]*d[i]. In other words, negate if and only
* if the following holds:
* (P[i] has odd y) XOR (P_agg has odd y)
* XOR (P_tweak[1] has odd y) XOR ... XOR (P_tweak[m] has odd y)
* (P[i] has odd y) XOR (xonly(1) and P_agg[0] has odd y)
* XOR (xonly(2) and P_agg[1] has odd y)
* XOR ... XOR (xonly(m) and P_agg[m-1] has odd y)
* XOR (P_agg[m] has odd y)
*
* Let us now look at how the terms in the equation correspond to the if
* condition below for some values of m:
* m = 0: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
* P_agg has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* m = 0: P[i] has odd y = secp256k1_fe_is_odd(&pk.y)
* P_agg[0] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* cache_i.internal_key_parity = 0
* m = 1: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
* P_agg has odd y = cache_i.internal_key_parity
* P_tweak[1] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* m = 2: P_i has odd y = secp256k1_fe_is_odd(&pk.y)
* P_agg has odd y XOR P_tweak[1] has odd y = cache_i.internal_key_parity
* P_tweak[2] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* m = 1: P[i] has odd y = secp256k1_fe_is_odd(&pk.y)
* xonly(1) and P_agg[0] has odd y = cache_i.internal_key_parity
* P_agg[1] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* m = 2: P[i] has odd y = secp256k1_fe_is_odd(&pk.y)
* (xonly(1) and P_agg[0] has odd y)
XOR (xonly(2) and P_agg[1] has odd y) = cache_i.internal_key_parity
* P_agg[2] has odd y = secp256k1_fe_is_odd(&cache_i.pk.y)
* etc.
*/
if ((secp256k1_fe_is_odd(&pk.y)
@ -674,7 +683,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
/* When producing a partial signature, signer i uses a possibly
* negated secret key:
*
* sk[i] = (d_tweak*d_agg*d[i])*x[i]
* sk[i] = (d_agg*d[i])*x[i]
*
* to ensure that the aggregate signature will correspond to
* an aggregate public key with even Y coordinate (see the
@ -698,14 +707,14 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
* The verifier doesn't have access to sk[i]*G, but can construct
* it using the xonly public key |P[i]| as follows:
*
* sk[i]*G = d_tweak*d_agg*d[i]*x[i]*G
* = d_tweak*d_agg*d[i]*P[i]
* = d_tweak*d_agg*|P[i]|
* sk[i]*G = d_agg*d[i]*x[i]*G
* = d_agg*d[i]*P[i]
* = d_agg*|P[i]|
*
* The if condition below is true whenever d_tweak*d_agg is
* negative (again, see the explanation in musig_partial_sign). In
* this case, the verifier negates e which will have the same end
* result as negating |P[i]|, since they are multiplied later anyway.
* The if condition below is true whenever d_agg is negative (again, see the
* explanation in musig_partial_sign). In this case, the verifier negates e
* which will have the same end result as negating |P[i]|, since they are
* multiplied later anyway.
*/
if (secp256k1_fe_is_odd(&cache_i.pk.y)
!= cache_i.internal_key_parity) {

View File

@ -140,6 +140,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
unsigned char aggnonce_ser[66];
unsigned char msg[32];
secp256k1_xonly_pubkey agg_pk;
secp256k1_pubkey full_agg_pk;
secp256k1_musig_keyagg_cache keyagg_cache;
secp256k1_musig_keyagg_cache invalid_keyagg_cache;
secp256k1_musig_session session;
@ -243,39 +244,53 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
/** Tweaking **/
/* pubkey_get */
ecount = 0;
CHECK(secp256k1_musig_pubkey_get(none, &full_agg_pk, &keyagg_cache) == 1);
CHECK(secp256k1_musig_pubkey_get(none, NULL, &keyagg_cache) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_get(none, &full_agg_pk, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros68, sizeof(full_agg_pk)) == 0);
/** Tweaking **/
{
int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32);
tweak_func[0] = secp256k1_musig_pubkey_ec_tweak_add;
tweak_func[1] = secp256k1_musig_pubkey_xonly_tweak_add;
for (i = 0; i < 2; i++) {
secp256k1_pubkey tmp_output_pk;
secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
ecount = 0;
CHECK((*tweak_func[i])(ctx, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
/* Reset keyagg_cache */
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(none, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
CHECK((*tweak_func[i])(none, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
CHECK((*tweak_func[i])(sign, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_keyagg_cache, tweak) == 1);
CHECK((*tweak_func[i])(vrfy, NULL, &tmp_keyagg_cache, tweak) == 1);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, NULL, tweak) == 0);
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, NULL, tweak) == 0);
CHECK(ecount == 1);
CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0);
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0);
CHECK(ecount == 2);
CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0);
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0);
CHECK(ecount == 2);
CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
/* Uninitialized keyagg_cache */
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0);
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0);
CHECK(ecount == 3);
CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
}
}
/** Session creation **/
ecount = 0;
@ -841,7 +856,8 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), agg_pk) == 1);
}
/* Create aggregate public key P[0], tweak multiple times and test signing. */
/* Create aggregate public key P[0], tweak multiple times (using xonly and
* ordinary tweaking) and test signing. */
void musig_tweak_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
secp256k1_xonly_pubkey pk[2];
@ -861,22 +877,35 @@ void musig_tweak_test(secp256k1_scratch_space *scratch) {
/* Compute P0 = keyagg(pk0, pk1) and test signing for it */
CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1);
musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache);
CHECK(secp256k1_musig_pubkey_get(ctx, &P[0], &keyagg_cache));
/* Compute Pi = |Pj| + tweaki*G where where j = i-1 and try signing for
* that key. The function |.| normalizes the point to have an even
* X-coordinate. This results in ordinary "xonly-tweaking". */
/* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for
* that key. If xonly is set to true, the function f is normalizes the input
* point to have an even X-coordinate ("xonly-tweaking").
* Otherwise, the function f is the identity function. */
for (i = 1; i < N_TWEAKS; i++) {
unsigned char tweak[32];
int P_parity;
unsigned char P_serialized[32];
int xonly = secp256k1_testrand_bits(1);
secp256k1_testrand256(tweak);
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1);
if (xonly) {
CHECK(secp256k1_musig_pubkey_xonly_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1);
} else {
CHECK(secp256k1_musig_pubkey_ec_tweak_add(ctx, &P[i], &keyagg_cache, tweak) == 1);
}
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &P_xonly[i], &P_parity, &P[i]));
CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P_xonly[i]));
/* Check that musig_pubkey_tweak_add produces same result as
* xonly_pubkey_tweak_add. */
* xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */
if (xonly) {
unsigned char P_serialized[32];
CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P_xonly[i]));
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1);
} else {
secp256k1_pubkey tmp_key = P[i-1];
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &tmp_key, tweak));
CHECK(memcmp(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
}
/* Test signing for P[i] */
musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache);
}
@ -1114,7 +1143,7 @@ void musig_test_vectors_noncegen(void) {
}
}
void musig_test_vectors_sign_helper(secp256k1_musig_keyagg_cache *keyagg_cache, int *fin_nonce_parity, unsigned char *sig, const unsigned char *secnonce_bytes, const unsigned char *agg_pubnonce_ser, const unsigned char *sk, const unsigned char *msg, const unsigned char *tweak, const secp256k1_pubkey *adaptor, const unsigned char **pk_ser, int signer_pos) {
void musig_test_vectors_sign_helper(secp256k1_musig_keyagg_cache *keyagg_cache, int *fin_nonce_parity, unsigned char *sig, const unsigned char *secnonce_bytes, const unsigned char *agg_pubnonce_ser, const unsigned char *sk, const unsigned char *msg, const unsigned char *tweak, int xonly_tweak, const secp256k1_pubkey *adaptor, const unsigned char **pk_ser, int signer_pos) {
secp256k1_keypair signer_keypair;
secp256k1_musig_secnonce secnonce;
secp256k1_xonly_pubkey pk[3];
@ -1135,7 +1164,11 @@ void musig_test_vectors_sign_helper(secp256k1_musig_keyagg_cache *keyagg_cache,
}
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, keyagg_cache, pk_ptr, 3) == 1);
if (tweak != NULL) {
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, NULL, keyagg_cache, tweak) == 1);
if (xonly_tweak) {
CHECK(secp256k1_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweak) == 1);
} else {
CHECK(secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweak) == 1);
}
}
memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4);
memcpy(&secnonce.data[4], secnonce_bytes, sizeof(secnonce.data) - 4);
@ -1214,7 +1247,7 @@ void musig_test_vectors_sign(void) {
0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7,
0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B,
};
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 0);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, 0, NULL, pk, 0);
/* TODO: remove when test vectors are not expected to change anymore */
/* int k, l; */
/* printf("const unsigned char sig_expected[32] = {\n"); */
@ -1243,7 +1276,7 @@ void musig_test_vectors_sign(void) {
0x81, 0x38, 0xDA, 0xEC, 0x5C, 0xB2, 0x0A, 0x35,
0x7C, 0xEC, 0xA7, 0xC8, 0x42, 0x42, 0x95, 0xEA,
};
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 1);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, 0, NULL, pk, 1);
/* Check that the description of the test vector is correct */
CHECK(musig_test_pk_parity(&keyagg_cache) == 0);
CHECK(musig_test_is_second_pk(&keyagg_cache, sk));
@ -1259,7 +1292,7 @@ void musig_test_vectors_sign(void) {
0xE6, 0xA7, 0xF7, 0xFB, 0xE1, 0x5C, 0xDC, 0xAF,
0xA4, 0xA3, 0xD1, 0xBC, 0xAA, 0xBC, 0x75, 0x17,
};
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, pk, 2);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, 0, NULL, pk, 2);
/* Check that the description of the test vector is correct */
CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
CHECK(fin_nonce_parity == 0);
@ -1267,7 +1300,7 @@ void musig_test_vectors_sign(void) {
CHECK(memcmp(sig, sig_expected, 32) == 0);
}
{
/* This is a test that includes a public key tweak. */
/* This is a test that includes an xonly public key tweak. */
const unsigned char sig_expected[32] = {
0x5E, 0x24, 0xC7, 0x49, 0x6B, 0x56, 0x5D, 0xEB,
0xC3, 0xB9, 0x63, 0x9E, 0x6F, 0x13, 0x04, 0xA2,
@ -1280,13 +1313,34 @@ void musig_test_vectors_sign(void) {
0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
};
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, NULL, pk, 2);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, 1, NULL, pk, 2);
CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
CHECK(fin_nonce_parity == 1);
CHECK(memcmp(sig, sig_expected, 32) == 0);
}
{
/* This is a test that includes an ordinary public key tweak. */
const unsigned char sig_expected[32] = {
0x78, 0x40, 0x8D, 0xDC, 0xAB, 0x48, 0x13, 0xD1,
0x39, 0x4C, 0x97, 0xD4, 0x93, 0xEF, 0x10, 0x84,
0x19, 0x5C, 0x1D, 0x4B, 0x52, 0xE6, 0x3E, 0xCD,
0x7B, 0xC5, 0x99, 0x16, 0x44, 0xE4, 0x4D, 0xDD,
};
const unsigned char tweak[32] = {
0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF,
0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D,
0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
};
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, 0, NULL, pk, 2);
CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
CHECK(fin_nonce_parity == 0);
CHECK(memcmp(sig, sig_expected, 32) == 0);
}
{
/* This is a test that includes an adaptor. */
const unsigned char sig_expected[32] = {
@ -1303,7 +1357,7 @@ void musig_test_vectors_sign(void) {
};
secp256k1_pubkey pub_adaptor;
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor) == 1);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, &pub_adaptor, pk, 2);
musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, 0, &pub_adaptor, pk, 2);
CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));