From 37107361a0ff3b8764903e3b384cfc12ed484e7a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 25 Oct 2021 21:50:08 +0000 Subject: [PATCH] musig: allow ordinary, non-xonly tweaking --- include/secp256k1_musig.h | 53 +++++++++++++++-- src/modules/musig/keyagg_impl.h | 12 +++- src/modules/musig/session_impl.h | 95 ++++++++++++++++-------------- src/modules/musig/tests_impl.h | 99 +++++++++++++++++++------------- 4 files changed, 169 insertions(+), 90 deletions(-) diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index c4ddffbb..45f4d32e 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -241,16 +241,59 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( secp256k1_musig_keyagg_cache *keyagg_cache ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak an x-only public key in a given keyagg_cache by adding - * the generator multiplied with `tweak32` to it. +/** 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. @@ -273,7 +316,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( * 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, diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index b8cb5d10..c7f18b37 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -258,7 +258,7 @@ int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *a 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) { +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; @@ -277,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); } @@ -294,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 diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 7cdcebe3..b85881c4 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -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. - * 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]. + * 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 + * 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) { diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 01d1a9c8..ece8a96e 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -254,37 +254,42 @@ void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros68, sizeof(full_agg_pk)) == 0); /** Tweaking **/ - ecount = 0; { - 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); - /* Reset keyagg_cache */ - tmp_keyagg_cache = keyagg_cache; - CHECK(secp256k1_musig_pubkey_tweak_add(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); - tmp_keyagg_cache = keyagg_cache; - CHECK(secp256k1_musig_pubkey_tweak_add(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); - tmp_keyagg_cache = keyagg_cache; - CHECK(secp256k1_musig_pubkey_tweak_add(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(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(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(ecount == 3); - CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0); + 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; + ecount = 0; + CHECK((*tweak_func[i])(ctx, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + /* Reset keyagg_cache */ + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(none, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(sign, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(vrfy, NULL, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + 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((*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((*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((*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 **/ @@ -851,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]; @@ -871,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. */ - CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); + * 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); } @@ -1145,7 +1164,7 @@ 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); + CHECK(secp256k1_musig_pubkey_xonly_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);