Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

musig2 wrappers over libsecp #31

Merged
merged 12 commits into from
Nov 16, 2022
Merged

musig2 wrappers over libsecp #31

merged 12 commits into from
Nov 16, 2022

Conversation

curiecrypt
Copy link
Collaborator

@curiecrypt curiecrypt commented Nov 12, 2022

This PR aims to update the library so that the end users do not need to make calls from secp256k1 as mentioned in #30. The following list provides the changes:

  1. Library functions are updated not to take any secp256k1 parameters, including secp256k1_context. Context creation is now handled in library functions.

  2. Defined constants renamed, i.e., SCALAR_BYTES is changed to MUSIG2_SCALAR_BYTES.

  3. A new type (musig2_pubkey) representing the x_only public key of secp256k1 is defined. MuSig2 library does not require full-size public keys; thus, instead of calling secp256k1_xonly_pubkey, users will call musig2_pubkey.

  4. The function musig2_prepare_signer_to_register is created. This function

    • serializes signers' public key and batch commitments in compressed format,
    • called by musig2_prepare_signer_to_register,
    • returns serialized_pk (33-byte) and serialized_comm_list, which is a list of 33-byte commitments with V * NR_MESSAGES elements. So, after initialization, these return values can be directly used to register the signer (Collecting public keys and batch commitments.
  5. Verification of the final signature with secp256k1_schnorrsig_verify is implemented in the library function musig2_verify_musig2.

Note that the documentation and comments are not completed yet.


This closes #30.

src/libmusig2.c Outdated
@@ -193,46 +196,79 @@ void musig2_context_sig_free(musig2_context_sig *mcs) {
musig2_context_free(&mcs->mc);
}

int musig2_prepare_signer_to_register(musig2_context_sig *mcs, unsigned char *serialized_pubkey, unsigned char serialized_batch_list[][MUSIG2_PUBKEY_BYTES_COMPRESSED]){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is only used internally. It could be static.

src/libmusig2.c Outdated
if (secp256k1_keypair_pub(mcs->mc.ctx, &temp_pk, &mcs->keypair))
secp256k1_ec_pubkey_serialize(mcs->mc.ctx, serialized_pubkey, &ser_size, &temp_pk, SECP256K1_EC_COMPRESSED );
else {
musig2_context_sig_free(mcs);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freeing the context within the function might result in a double free, or in using a freed pointer. This should be handled externally, as we might want to continue with the same context if the serialisation failed

src/libmusig2.c Outdated
if (secp256k1_keypair_pub(mcs->mc.ctx, &temp_pk, mcs->comm_list[i]))
secp256k1_ec_pubkey_serialize(mcs->mc.ctx, serialized_batch_list[i], &ser_size, &temp_pk, SECP256K1_EC_COMPRESSED );
else {
musig2_context_sig_free(mcs);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

src/libmusig2.c Outdated
Comment on lines 242 to 244
if (!musig2_prepare_signer_to_register(mcs, serialized_pubkey, serialized_comm_list)){
musig2_context_sig_free(mcs);
return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that what prepare_signer_to_register really does is serialise the pubkey and batched commitments. What do you think of having a function serialise_shareable_context, that takes as input mcs and the two pointers for the serialised data? In this way we explicitly distinguish both calls

src/libmusig2.h Outdated
Comment on lines 15 to 17
#define MUSIG2_PUBKEY_BYTES 32 // XONLY PUBLIC KEY BYTES
#define MUSIG2_PUBKEY_BYTES_COMPRESSED 33 // COMPRESSED PUBLIC KEY BYTES
#define MUSIG2_PUBKEY_BYTES_FULL 64 // FULL SIZE PUBLIC KEY BYTES
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's counterintuitive that BYTES_COMPRESSED is larger than BYTES. I would find a different name to the former (maybe something to do with omit sign bit or something of the sort)

Copy link
Collaborator

@iquerejeta iquerejeta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that the serialisation is separated from the initialisation function.

@curiecrypt curiecrypt self-assigned this Nov 15, 2022
Copy link
Collaborator

@iquerejeta iquerejeta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes look good. Have a look at my comments, and change what you consider, but other than that, happy to see this merged.

src/libmusig2.c Outdated
Comment on lines 223 to 232
if (!musig2_key_gen(mcs)) {
musig2_context_sig_free(mcs);
return 0;
}

/* Generate the batch commitments for given signer */
if (!musig2_batch_commitment(mcs))
if (!musig2_batch_commitment(mcs)) {
return 0;
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be consistent with freeing the context. Both errors are the same (=0), so the function caller will always react the same way for failures. This means that the outcome of both failures needs to be the same wrt freeing the context. Either we free the context in or out of the function, but we cannot do both.


int musig2_verify_musig2(unsigned char *signature, const unsigned char *msg, int msg_len, musig2_aggr_pubkey *aggr_pk){
int result;
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be confusing for someone reading the code in the future to see these two functions: musig2_prepare_verifier and musig2_verify_musig2, and see that in both we create a new context and destroy it. For sake of clarity, I would comment why we do this, and the design decision for not doing it in a single function.

src/libmusig2.c Outdated

musig2_context_free(&verifier_context);
}

int musig2_verify_musig2(unsigned char *signature, const unsigned char *msg, int msg_len, musig2_aggr_pubkey *aggr_pk){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int musig2_verify_musig2(unsigned char *signature, const unsigned char *msg, int msg_len, musig2_aggr_pubkey *aggr_pk){
int musig2_verify(unsigned char *signature, const unsigned char *msg, int msg_len, musig2_aggr_pubkey *aggr_pk){

Comment on lines +13 to 19
#define MUSIG2_SCALAR_BYTES 32 // SCALAR BYTES
#define MUSIG2_PARSIG_BYTES 32 // PARTIAL SIGNATURE BYTES
#define MUSIG2_AGGR_PUBKEY_BYTES 32 // XONLY PUBLIC KEY BYTES
#define MUSIG2_PUBKEY_BYTES_COMPRESSED 33 // COMPRESSED PUBLIC KEY BYTES
#define MUSIG2_PUBKEY_BYTES_FULL 64 // FULL SIZE PUBLIC KEY BYTES
#define MUSIG2_BYTES 64 // SCHNORR SIGNATURE BYTES

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced by this naming. But this is just a suggestion. You'll be the main maintainer of the lib, so you can make the final call. The following is my reasoning:

  • MUSIG2_PARSIG_BYTES is a bit confusing, because we define musig2_partial_signature to be two values with a total of 64 bytes. This variable is really used to determine the size of the 'scalar part' of the partial signature.
  • I think I would remove the parsig bytes, and simply useSCALAR_BYTES and MUSIG2_BYTES for referring to the size of the signatures.

@iquerejeta
Copy link
Collaborator

Sorry, for the double comments. I'm using the code editor to review the PR and something clearly went wrong 😅

@curiecrypt curiecrypt merged commit b1d14f6 into main Nov 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Abstract library users completely from bitcoin-core/secp256k1
2 participants