diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index 17ddf7d20..c4ddffbb8 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -223,6 +223,24 @@ SECP256K1_API int secp256k1_musig_pubkey_agg( size_t n_pubkeys ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5); +/** 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); + /** Tweak an x-only public key in a given keyagg_cache by adding * the generator multiplied with `tweak32` to it. * diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index 5299edca8..b8cb5d101 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -244,6 +244,20 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s return 1; } +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; +} + int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { secp256k1_keyagg_cache_internal cache_i; int overflow = 0; diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 69a91c160..01d1a9c8a 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -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,6 +244,15 @@ 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); + /* 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 **/ ecount = 0; {