musig: update to BIP v0.8 "Switch from X-only to plain pk inputs."
This commit is contained in:
parent
304f1bc96d
commit
d717a4980b
@ -26,7 +26,7 @@ struct signer_secrets {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct signer {
|
struct signer {
|
||||||
secp256k1_xonly_pubkey pubkey;
|
secp256k1_pubkey pubkey;
|
||||||
secp256k1_musig_pubnonce pubnonce;
|
secp256k1_musig_pubnonce pubnonce;
|
||||||
secp256k1_musig_partial_sig partial_sig;
|
secp256k1_musig_partial_sig partial_sig;
|
||||||
};
|
};
|
||||||
@ -45,7 +45,7 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) {
|
if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -164,7 +164,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
|||||||
int i;
|
int i;
|
||||||
struct signer_secrets signer_secrets[N_SIGNERS];
|
struct signer_secrets signer_secrets[N_SIGNERS];
|
||||||
struct signer signers[N_SIGNERS];
|
struct signer signers[N_SIGNERS];
|
||||||
const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS];
|
const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||||
secp256k1_xonly_pubkey agg_pk;
|
secp256k1_xonly_pubkey agg_pk;
|
||||||
secp256k1_musig_keyagg_cache cache;
|
secp256k1_musig_keyagg_cache cache;
|
||||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
||||||
|
@ -40,11 +40,11 @@ extern "C" {
|
|||||||
|
|
||||||
/** Opaque data structure that caches information about public key aggregation.
|
/** Opaque data structure that caches information about public key aggregation.
|
||||||
*
|
*
|
||||||
* Guaranteed to be 165 bytes in size. It can be safely copied/moved. No
|
* Guaranteed to be 197 bytes in size. It can be safely copied/moved. No
|
||||||
* serialization and parsing functions (yet).
|
* serialization and parsing functions (yet).
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char data[165];
|
unsigned char data[197];
|
||||||
} secp256k1_musig_keyagg_cache;
|
} secp256k1_musig_keyagg_cache;
|
||||||
|
|
||||||
/** Opaque data structure that holds a signer's _secret_ nonce.
|
/** Opaque data structure that holds a signer's _secret_ nonce.
|
||||||
@ -190,8 +190,8 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse(
|
|||||||
*
|
*
|
||||||
* Different orders of `pubkeys` result in different `agg_pk`s.
|
* Different orders of `pubkeys` result in different `agg_pk`s.
|
||||||
*
|
*
|
||||||
* The pubkeys can be sorted before combining with `secp256k1_xonly_sort` which
|
* Before aggregating, the pubkeys can be sorted with `secp256k1_pubkey_sort`
|
||||||
* ensures the same `agg_pk` result for the same multiset of pubkeys.
|
* which ensures the same `agg_pk` result for the same multiset of pubkeys.
|
||||||
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
|
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
|
||||||
* does not affect the aggregate public key.
|
* does not affect the aggregate public key.
|
||||||
*
|
*
|
||||||
@ -219,7 +219,7 @@ SECP256K1_API int secp256k1_musig_pubkey_agg(
|
|||||||
secp256k1_scratch_space *scratch,
|
secp256k1_scratch_space *scratch,
|
||||||
secp256k1_xonly_pubkey *agg_pk,
|
secp256k1_xonly_pubkey *agg_pk,
|
||||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
const secp256k1_xonly_pubkey * const* pubkeys,
|
const secp256k1_pubkey * const* pubkeys,
|
||||||
size_t n_pubkeys
|
size_t n_pubkeys
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
@ -494,7 +494,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
|
|||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
const secp256k1_musig_partial_sig *partial_sig,
|
const secp256k1_musig_partial_sig *partial_sig,
|
||||||
const secp256k1_musig_pubnonce *pubnonce,
|
const secp256k1_musig_pubnonce *pubnonce,
|
||||||
const secp256k1_xonly_pubkey *pubkey,
|
const secp256k1_pubkey *pubkey,
|
||||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||||
const secp256k1_musig_session *session
|
const secp256k1_musig_session *session
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
secp256k1_ge pk;
|
secp256k1_ge pk;
|
||||||
secp256k1_fe second_pk_x;
|
/* If there is no "second" public key, second_pk is set to the point at
|
||||||
|
* infinity */
|
||||||
|
secp256k1_ge second_pk;
|
||||||
unsigned char pk_hash[32];
|
unsigned char pk_hash[32];
|
||||||
/* tweak is identical to value tacc[v] in the specification. */
|
/* tweak is identical to value tacc[v] in the specification. */
|
||||||
secp256k1_scalar tweak;
|
secp256k1_scalar tweak;
|
||||||
@ -25,13 +27,23 @@ typedef struct {
|
|||||||
int parity_acc;
|
int parity_acc;
|
||||||
} secp256k1_keyagg_cache_internal;
|
} secp256k1_keyagg_cache_internal;
|
||||||
|
|
||||||
/* Requires that the saved point is not infinity */
|
/* Save and load points to and from byte arrays, similar to
|
||||||
|
* secp256k1_pubkey_{save,load}. */
|
||||||
static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge);
|
static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge);
|
||||||
|
|
||||||
|
/* In contrast to pubkey_load, point_load does not attempt to check that data
|
||||||
|
* has been initialized, since it is assumed that this check already happened
|
||||||
|
* (e.g. by comparing magic bytes) */
|
||||||
static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data);
|
static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data);
|
||||||
|
|
||||||
|
/* point_save_ext and point_load_ext are identical to point_save and point_load
|
||||||
|
* except that they allow saving and loading the point at infinity */
|
||||||
|
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge);
|
||||||
|
|
||||||
|
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||||
|
|
||||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
||||||
|
|
||||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x);
|
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,13 +47,30 @@ static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) {
|
||||||
|
if (secp256k1_ge_is_infinity(ge)) {
|
||||||
|
memset(data, 0, 64);
|
||||||
|
} else {
|
||||||
|
secp256k1_point_save(data, ge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) {
|
||||||
|
unsigned char zeros[64] = { 0 };
|
||||||
|
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
||||||
|
secp256k1_ge_set_infinity(ge);
|
||||||
|
} else {
|
||||||
|
secp256k1_point_load(ge, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
||||||
|
|
||||||
/* A keyagg cache consists of
|
/* A keyagg cache consists of
|
||||||
* - 4 byte magic set during initialization to allow detecting an uninitialized
|
* - 4 byte magic set during initialization to allow detecting an uninitialized
|
||||||
* object.
|
* object.
|
||||||
* - 64 byte aggregate (and potentially tweaked) public key
|
* - 64 byte aggregate (and potentially tweaked) public key
|
||||||
* - 32 byte X-coordinate of "second" public key (0 if not present)
|
* - 64 byte "second" public key (set to the point at infinity if not present)
|
||||||
* - 32 byte hash of all public keys
|
* - 32 byte hash of all public keys
|
||||||
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
|
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
|
||||||
* - 32 byte tweak
|
* - 32 byte tweak
|
||||||
@ -65,8 +82,8 @@ static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, sec
|
|||||||
ptr += 4;
|
ptr += 4;
|
||||||
secp256k1_point_save(ptr, &cache_i->pk);
|
secp256k1_point_save(ptr, &cache_i->pk);
|
||||||
ptr += 64;
|
ptr += 64;
|
||||||
secp256k1_fe_get_b32(ptr, &cache_i->second_pk_x);
|
secp256k1_point_save_ext(ptr, &cache_i->second_pk);
|
||||||
ptr += 32;
|
ptr += 64;
|
||||||
memcpy(ptr, cache_i->pk_hash, 32);
|
memcpy(ptr, cache_i->pk_hash, 32);
|
||||||
ptr += 32;
|
ptr += 32;
|
||||||
*ptr = cache_i->parity_acc;
|
*ptr = cache_i->parity_acc;
|
||||||
@ -80,8 +97,8 @@ static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_k
|
|||||||
ptr += 4;
|
ptr += 4;
|
||||||
secp256k1_point_load(&cache_i->pk, ptr);
|
secp256k1_point_load(&cache_i->pk, ptr);
|
||||||
ptr += 64;
|
ptr += 64;
|
||||||
secp256k1_fe_set_b32(&cache_i->second_pk_x, ptr);
|
secp256k1_point_load_ext(&cache_i->second_pk, ptr);
|
||||||
ptr += 32;
|
ptr += 64;
|
||||||
memcpy(cache_i->pk_hash, ptr, 32);
|
memcpy(cache_i->pk_hash, ptr, 32);
|
||||||
ptr += 32;
|
ptr += 32;
|
||||||
cache_i->parity_acc = *ptr & 1;
|
cache_i->parity_acc = *ptr & 1;
|
||||||
@ -107,17 +124,19 @@ static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */
|
/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */
|
||||||
static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_xonly_pubkey * const* pk, size_t np) {
|
static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_pubkey * const* pk, size_t np) {
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
secp256k1_musig_keyagglist_sha256(&sha);
|
secp256k1_musig_keyagglist_sha256(&sha);
|
||||||
for (i = 0; i < np; i++) {
|
for (i = 0; i < np; i++) {
|
||||||
unsigned char ser[32];
|
unsigned char ser[33];
|
||||||
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) {
|
size_t ser_len = sizeof(ser);
|
||||||
|
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pk[i], SECP256K1_EC_COMPRESSED)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
secp256k1_sha256_write(&sha, ser, 32);
|
VERIFY_CHECK(ser_len == sizeof(ser));
|
||||||
|
secp256k1_sha256_write(&sha, ser, sizeof(ser));
|
||||||
}
|
}
|
||||||
secp256k1_sha256_finalize(&sha, pk_hash);
|
secp256k1_sha256_finalize(&sha, pk_hash);
|
||||||
return 1;
|
return 1;
|
||||||
@ -140,52 +159,59 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
||||||
* tagged_hash(pk_hash, x) where pk_hash is the hash of public keys otherwise.
|
* otherwise tagged_hash(pk_hash, x) where pk_hash is the hash of public keys.
|
||||||
* second_pk_x can be 0 in case there is no second_pk. Assumes both field
|
* second_pk is the point at infinity in case there is no second_pk. Assumes
|
||||||
* elements x and second_pk_x are normalized. */
|
* that pk is not the point at infinity and that the coordinates of pk and
|
||||||
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, const secp256k1_fe *x, const secp256k1_fe *second_pk_x) {
|
* second_pk are normalized. */
|
||||||
|
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) {
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
unsigned char buf[32];
|
|
||||||
|
|
||||||
if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) {
|
if (!secp256k1_ge_is_infinity(second_pk)
|
||||||
|
&& secp256k1_fe_equal(&pk->x, &second_pk->x)
|
||||||
|
&& secp256k1_fe_is_odd(&pk->y) == secp256k1_fe_is_odd(&second_pk->y)) {
|
||||||
secp256k1_scalar_set_int(r, 1);
|
secp256k1_scalar_set_int(r, 1);
|
||||||
} else {
|
} else {
|
||||||
|
unsigned char buf[33];
|
||||||
|
size_t buflen = sizeof(buf);
|
||||||
|
int ret;
|
||||||
secp256k1_musig_keyaggcoef_sha256(&sha);
|
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||||
secp256k1_sha256_write(&sha, pk_hash, 32);
|
secp256k1_sha256_write(&sha, pk_hash, 32);
|
||||||
secp256k1_fe_get_b32(buf, x);
|
ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1);
|
||||||
secp256k1_sha256_write(&sha, buf, 32);
|
/* Serialization does not fail since the pk is not the point at infinity
|
||||||
|
* (according to this function's precondition). */
|
||||||
|
VERIFY_CHECK(ret && buflen == sizeof(buf));
|
||||||
|
secp256k1_sha256_write(&sha, buf, sizeof(buf));
|
||||||
secp256k1_sha256_finalize(&sha, buf);
|
secp256k1_sha256_finalize(&sha, buf);
|
||||||
secp256k1_scalar_set_b32(r, buf, NULL);
|
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assumes both field elements x and second_pk_x are normalized. */
|
/* Assumes both field elements x and second_pk_x are normalized. */
|
||||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x) {
|
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) {
|
||||||
secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, x, &cache_i->second_pk_x);
|
secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, pk, &cache_i->second_pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const secp256k1_context *ctx;
|
const secp256k1_context *ctx;
|
||||||
/* pk_hash is the hash of the public keys */
|
/* pk_hash is the hash of the public keys */
|
||||||
unsigned char pk_hash[32];
|
unsigned char pk_hash[32];
|
||||||
const secp256k1_xonly_pubkey * const* pks;
|
const secp256k1_pubkey * const* pks;
|
||||||
secp256k1_fe second_pk_x;
|
secp256k1_ge second_pk;
|
||||||
} secp256k1_musig_pubkey_agg_ecmult_data;
|
} secp256k1_musig_pubkey_agg_ecmult_data;
|
||||||
|
|
||||||
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
|
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
|
||||||
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||||
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
|
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
|
||||||
int ret;
|
int ret;
|
||||||
ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
||||||
/* pubkey_load can't fail because the same pks have already been loaded in
|
/* pubkey_load can't fail because the same pks have already been loaded in
|
||||||
* `musig_compute_pk_hash` (and we test this). */
|
* `musig_compute_pk_hash` (and we test this). */
|
||||||
VERIFY_CHECK(ret);
|
VERIFY_CHECK(ret);
|
||||||
secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, &pt->x, &ctx->second_pk_x);
|
secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, pt, &ctx->second_pk);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) {
|
int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) {
|
||||||
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
|
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
|
||||||
secp256k1_gej pkj;
|
secp256k1_gej pkj;
|
||||||
secp256k1_ge pkp;
|
secp256k1_ge pkp;
|
||||||
@ -201,15 +227,15 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s
|
|||||||
|
|
||||||
ecmult_data.ctx = ctx;
|
ecmult_data.ctx = ctx;
|
||||||
ecmult_data.pks = pubkeys;
|
ecmult_data.pks = pubkeys;
|
||||||
/* No point on the curve has an X coordinate equal to 0 */
|
|
||||||
secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0);
|
secp256k1_ge_set_infinity(&ecmult_data.second_pk);
|
||||||
for (i = 1; i < n_pubkeys; i++) {
|
for (i = 1; i < n_pubkeys; i++) {
|
||||||
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
||||||
secp256k1_ge pt;
|
secp256k1_ge pk;
|
||||||
if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) {
|
if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ecmult_data.second_pk_x = pt.x;
|
ecmult_data.second_pk = pk;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,7 +258,7 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s
|
|||||||
if (keyagg_cache != NULL) {
|
if (keyagg_cache != NULL) {
|
||||||
secp256k1_keyagg_cache_internal cache_i = { 0 };
|
secp256k1_keyagg_cache_internal cache_i = { 0 };
|
||||||
cache_i.pk = pkp;
|
cache_i.pk = pkp;
|
||||||
cache_i.second_pk_x = ecmult_data.second_pk_x;
|
cache_i.second_pk = ecmult_data.second_pk;
|
||||||
memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash));
|
memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash));
|
||||||
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly
|
|||||||
This is covered by `examples/musig.c`.
|
This is covered by `examples/musig.c`.
|
||||||
Essentially, the protocol proceeds in the following steps:
|
Essentially, the protocol proceeds in the following steps:
|
||||||
|
|
||||||
1. Generate a keypair with `secp256k1_keypair_create` and obtain the xonly public key with `secp256k1_keypair_xonly_pub`.
|
1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`.
|
||||||
2. Call `secp256k1_musig_pubkey_agg` with the xonly pubkeys of all participants.
|
2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants.
|
||||||
3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`.
|
3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`.
|
||||||
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
|
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
|
||||||
5. Someone (not necessarily the signer) aggregates the public nonce with `secp256k1_musig_nonce_agg` and sends it to the signers.
|
5. Someone (not necessarily the signer) aggregates the public nonce with `secp256k1_musig_nonce_agg` and sends it to the signers.
|
||||||
|
@ -20,25 +20,6 @@
|
|||||||
#include "../../scalar.h"
|
#include "../../scalar.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
|
|
||||||
/* point_save_ext and point_load_ext are identical to point_save and point_load
|
|
||||||
* except that they allow saving and loading the point at infinity */
|
|
||||||
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) {
|
|
||||||
if (secp256k1_ge_is_infinity(ge)) {
|
|
||||||
memset(data, 0, 64);
|
|
||||||
} else {
|
|
||||||
secp256k1_point_save(data, ge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) {
|
|
||||||
unsigned char zeros[64] = { 0 };
|
|
||||||
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
|
||||||
secp256k1_ge_set_infinity(ge);
|
|
||||||
} else {
|
|
||||||
secp256k1_point_load(ge, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
|
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
|
||||||
|
|
||||||
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) {
|
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) {
|
||||||
@ -608,25 +589,18 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
|
|||||||
}
|
}
|
||||||
secp256k1_fe_normalize_var(&pk.y);
|
secp256k1_fe_normalize_var(&pk.y);
|
||||||
|
|
||||||
/* The specification requires that the secret key is multiplied by
|
/* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||||
* g[v]*g*gp. All factors are -1 or 1. The value g[v] is -1 iff
|
* This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the
|
||||||
* secp256k1_fe_is_odd(&cache_i.pk.y)), g is is -1 iff parity_acc is 1 and
|
* specification. */
|
||||||
* gp is -1 if secp256k1_fe_is_odd(&pk.y). Therefore, multiplying by
|
|
||||||
* g[v]*g*gp is equivalent to negating if
|
|
||||||
* secp256k1_fe_is_odd(&cache_i.pk.y))
|
|
||||||
* XOR cache_i.parity_acc
|
|
||||||
* XOR secp256k1_fe_is_odd(&pk.y).
|
|
||||||
*/
|
|
||||||
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
|
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||||
!= cache_i.parity_acc)
|
!= cache_i.parity_acc)) {
|
||||||
!= secp256k1_fe_is_odd(&pk.y)) {
|
|
||||||
secp256k1_scalar_negate(&sk, &sk);
|
secp256k1_scalar_negate(&sk, &sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Multiply KeyAgg coefficient */
|
/* Multiply KeyAgg coefficient */
|
||||||
secp256k1_fe_normalize_var(&pk.x);
|
secp256k1_fe_normalize_var(&pk.x);
|
||||||
/* TODO Cache mu */
|
/* TODO Cache mu */
|
||||||
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk.x);
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk);
|
||||||
secp256k1_scalar_mul(&sk, &sk, &mu);
|
secp256k1_scalar_mul(&sk, &sk, &mu);
|
||||||
|
|
||||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||||
@ -649,7 +623,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_xonly_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||||
secp256k1_keyagg_cache_internal cache_i;
|
secp256k1_keyagg_cache_internal cache_i;
|
||||||
secp256k1_musig_session_internal session_i;
|
secp256k1_musig_session_internal session_i;
|
||||||
secp256k1_scalar mu, e, s;
|
secp256k1_scalar mu, e, s;
|
||||||
@ -679,7 +653,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
|
|||||||
secp256k1_ecmult(&rj, &rj, &session_i.noncecoef, NULL);
|
secp256k1_ecmult(&rj, &rj, &session_i.noncecoef, NULL);
|
||||||
secp256k1_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL);
|
secp256k1_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL);
|
||||||
|
|
||||||
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
|
if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||||
@ -688,14 +662,12 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
|
|||||||
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
|
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
|
||||||
* to multiplying the signer's public key by the coefficient, except
|
* to multiplying the signer's public key by the coefficient, except
|
||||||
* much easier to do. */
|
* much easier to do. */
|
||||||
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp.x);
|
secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp);
|
||||||
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
||||||
|
|
||||||
/* The specification requires that the public key is multiplied by g[v]*g.
|
/* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||||
* All factors are -1 or 1. The value g[v] is -1 iff
|
* This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e"
|
||||||
* secp256k1_fe_is_odd(&cache_i.pk.y)) and g is is -1 iff parity_acc is 1.
|
* in the specification. */
|
||||||
* Therefore, multiplying by g[v]*g is equivalent to negating if
|
|
||||||
* fe_is_odd(&cache_i.pk.y) XOR parity_acc. */
|
|
||||||
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||||
!= cache_i.parity_acc) {
|
!= cache_i.parity_acc) {
|
||||||
secp256k1_scalar_negate(&e, &e);
|
secp256k1_scalar_negate(&e, &e);
|
||||||
|
@ -23,11 +23,11 @@
|
|||||||
#include "../../hash.h"
|
#include "../../hash.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
|
|
||||||
static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_xonly_pubkey *pk, const unsigned char *sk) {
|
static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) {
|
||||||
int ret;
|
int ret;
|
||||||
secp256k1_keypair keypair_tmp;
|
secp256k1_keypair keypair_tmp;
|
||||||
ret = secp256k1_keypair_create(ctx, &keypair_tmp, sk);
|
ret = secp256k1_keypair_create(ctx, &keypair_tmp, sk);
|
||||||
ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair_tmp);
|
ret &= secp256k1_keypair_pub(ctx, pk, &keypair_tmp);
|
||||||
if (keypair != NULL) {
|
if (keypair != NULL) {
|
||||||
*keypair = keypair_tmp;
|
*keypair = keypair_tmp;
|
||||||
}
|
}
|
||||||
@ -47,8 +47,8 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
|
|||||||
secp256k1_musig_keyagg_cache keyagg_cache;
|
secp256k1_musig_keyagg_cache keyagg_cache;
|
||||||
unsigned char session_id[2][32];
|
unsigned char session_id[2][32];
|
||||||
secp256k1_musig_secnonce secnonce[2];
|
secp256k1_musig_secnonce secnonce[2];
|
||||||
secp256k1_xonly_pubkey pk[2];
|
secp256k1_pubkey pk[2];
|
||||||
const secp256k1_xonly_pubkey *pk_ptr[2];
|
const secp256k1_pubkey *pk_ptr[2];
|
||||||
secp256k1_musig_partial_sig partial_sig[2];
|
secp256k1_musig_partial_sig partial_sig[2];
|
||||||
const secp256k1_musig_partial_sig *partial_sig_ptr[2];
|
const secp256k1_musig_partial_sig *partial_sig_ptr[2];
|
||||||
unsigned char final_sig[64];
|
unsigned char final_sig[64];
|
||||||
@ -145,11 +145,11 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
|||||||
secp256k1_musig_keyagg_cache invalid_keyagg_cache;
|
secp256k1_musig_keyagg_cache invalid_keyagg_cache;
|
||||||
secp256k1_musig_session session;
|
secp256k1_musig_session session;
|
||||||
secp256k1_musig_session invalid_session;
|
secp256k1_musig_session invalid_session;
|
||||||
secp256k1_xonly_pubkey pk[2];
|
secp256k1_pubkey pk[2];
|
||||||
const secp256k1_xonly_pubkey *pk_ptr[2];
|
const secp256k1_pubkey *pk_ptr[2];
|
||||||
secp256k1_xonly_pubkey invalid_pk;
|
secp256k1_pubkey invalid_pk;
|
||||||
const secp256k1_xonly_pubkey *invalid_pk_ptr2[2];
|
const secp256k1_pubkey *invalid_pk_ptr2[2];
|
||||||
const secp256k1_xonly_pubkey *invalid_pk_ptr3[3];
|
const secp256k1_pubkey *invalid_pk_ptr3[3];
|
||||||
unsigned char tweak[32];
|
unsigned char tweak[32];
|
||||||
int nonce_parity;
|
int nonce_parity;
|
||||||
unsigned char sec_adaptor[32];
|
unsigned char sec_adaptor[32];
|
||||||
@ -684,10 +684,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
|||||||
unsigned char sk_b[2][32];
|
unsigned char sk_b[2][32];
|
||||||
secp256k1_keypair keypair_a[2];
|
secp256k1_keypair keypair_a[2];
|
||||||
secp256k1_keypair keypair_b[2];
|
secp256k1_keypair keypair_b[2];
|
||||||
secp256k1_xonly_pubkey pk_a[2];
|
secp256k1_pubkey pk_a[2];
|
||||||
const secp256k1_xonly_pubkey *pk_a_ptr[2];
|
const secp256k1_pubkey *pk_a_ptr[2];
|
||||||
secp256k1_xonly_pubkey pk_b[2];
|
secp256k1_pubkey pk_b[2];
|
||||||
const secp256k1_xonly_pubkey *pk_b_ptr[2];
|
const secp256k1_pubkey *pk_b_ptr[2];
|
||||||
secp256k1_musig_keyagg_cache keyagg_cache_a;
|
secp256k1_musig_keyagg_cache keyagg_cache_a;
|
||||||
secp256k1_musig_keyagg_cache keyagg_cache_b;
|
secp256k1_musig_keyagg_cache keyagg_cache_b;
|
||||||
secp256k1_xonly_pubkey agg_pk_a;
|
secp256k1_xonly_pubkey agg_pk_a;
|
||||||
@ -816,7 +816,7 @@ void sha256_tag_test(void) {
|
|||||||
/* Attempts to create a signature for the aggregate public key using given secret
|
/* Attempts to create a signature for the aggregate public key using given secret
|
||||||
* keys and keyagg_cache. */
|
* keys and keyagg_cache. */
|
||||||
void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) {
|
void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) {
|
||||||
secp256k1_xonly_pubkey pk[2];
|
secp256k1_pubkey pk[2];
|
||||||
unsigned char session_id[2][32];
|
unsigned char session_id[2][32];
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
secp256k1_musig_secnonce secnonce[2];
|
secp256k1_musig_secnonce secnonce[2];
|
||||||
@ -860,8 +860,8 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne
|
|||||||
* plain tweaking) and test signing. */
|
* plain tweaking) and test signing. */
|
||||||
void musig_tweak_test(secp256k1_scratch_space *scratch) {
|
void musig_tweak_test(secp256k1_scratch_space *scratch) {
|
||||||
unsigned char sk[2][32];
|
unsigned char sk[2][32];
|
||||||
secp256k1_xonly_pubkey pk[2];
|
secp256k1_pubkey pk[2];
|
||||||
const secp256k1_xonly_pubkey *pk_ptr[2];
|
const secp256k1_pubkey *pk_ptr[2];
|
||||||
secp256k1_musig_keyagg_cache keyagg_cache;
|
secp256k1_musig_keyagg_cache keyagg_cache;
|
||||||
enum { N_TWEAKS = 8 };
|
enum { N_TWEAKS = 8 };
|
||||||
secp256k1_pubkey P[N_TWEAKS + 1];
|
secp256k1_pubkey P[N_TWEAKS + 1];
|
||||||
|
@ -249,8 +249,8 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
|
|
||||||
#ifdef ENABLE_MODULE_MUSIG
|
#ifdef ENABLE_MODULE_MUSIG
|
||||||
{
|
{
|
||||||
secp256k1_xonly_pubkey pk;
|
secp256k1_pubkey pk;
|
||||||
const secp256k1_xonly_pubkey *pk_ptr[1];
|
const secp256k1_pubkey *pk_ptr[1];
|
||||||
secp256k1_xonly_pubkey agg_pk;
|
secp256k1_xonly_pubkey agg_pk;
|
||||||
unsigned char session_id[32];
|
unsigned char session_id[32];
|
||||||
secp256k1_musig_secnonce secnonce;
|
secp256k1_musig_secnonce secnonce;
|
||||||
@ -279,7 +279,7 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
partial_sig_ptr[0] = &partial_sig;
|
partial_sig_ptr[0] = &partial_sig;
|
||||||
|
|
||||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
|
||||||
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
|
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
|
||||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user