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

fuzz testing #43

Merged
merged 12 commits into from
Aug 8, 2023
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
libmusig2.o
musig2test
musig2test.dSYM/
example_run/
test_run/
6 changes: 4 additions & 2 deletions examples/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ const char* const MUSIG2_STR[] = {
" (check commitments) ....................................[FAIL] \n",
" (combine partial signatures) ...........................[FAIL] \n",
" (compare R) ............................................[FAIL] \n",
" (serialize pubkey) .....................................[FAIL] \n",
" (serialize commitments) ................................[FAIL] \n",
" (ser/deser pubkey) .....................................[FAIL] \n",
" (ser/deser commitments) ................................[FAIL] \n",
" (operation) ............................................[FAIL] \n",

};
const char* musig2_error_str(MUSIG2_ERROR result)
{
Expand Down
6 changes: 3 additions & 3 deletions src/libmusig2.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,13 @@ MUSIG2_ERROR musig2_signer_precomputation(musig2_context *mc, unsigned char *ser
/* Parse the batch commitments of the signers */
for (i = 0; i < nr_signers; i++) {
if (!secp256k1_ec_pubkey_parse(mc->ctx, &pubkey_list[i], &serialized_pubkey_list[i * MUSIG2_PUBKEY_BYTES_COMPRESSED], MUSIG2_PUBKEY_BYTES_COMPRESSED)){
return MUSIG2_ERR_PARSE_PK_COMM;
return MUSIG2_ERR_PARSE_PK;
}
for (k = 0; k < mc->nr_messages; k++) {
for (j = 0; j < V; j++) {
ind = (k * nr_signers * V + i * V + j) * MUSIG2_PUBKEY_BYTES_COMPRESSED;
if(!secp256k1_ec_pubkey_parse(mc->ctx, &batch_list[k][i][j], &serialized_batch_list[ind], MUSIG2_PUBKEY_BYTES_COMPRESSED)){
return MUSIG2_ERR_PARSE_PK_COMM;
return MUSIG2_ERR_PARSE_COMM;
}
}
}
Expand Down Expand Up @@ -389,7 +389,7 @@ MUSIG2_ERROR musig2_prepare_verifier(musig2_aggr_pubkey *aggr_pubkey, unsigned c
for (i = 0; i < nr_signers; i++) {
if (!secp256k1_ec_pubkey_parse(verifier_context.ctx, &pubkey_list[i], &serialized_pubkey_list[i * MUSIG2_PUBKEY_BYTES_COMPRESSED],
MUSIG2_PUBKEY_BYTES_COMPRESSED)){
return MUSIG2_ERR_PARSE_PK_COMM;
return MUSIG2_ERR_PARSE_PK;
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/libmusig2.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ typedef enum musig2_error {
MUSIG2_ERR_CHECK_COMM, // 8
MUSIG2_ERR_ADD_PARSIG, // 9
MUSIG2_ERR_CMP_R, // 10
MUSIG2_ERR_PARSE_PK_COMM, // 11
MUSIG2_INVALID, // 12
MUSIG2_ERR_PARSE_PK, // 11
MUSIG2_ERR_PARSE_COMM, // 12
MUSIG2_INVALID, // 13
} MUSIG2_ERROR;


Expand Down
8 changes: 4 additions & 4 deletions tests/functiontest.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ TEST (musig2, future_state) {
err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_ERR_CMP_R);

// Verification should fail since one of the signers; signature used a future state.
// Verification should fail since one of the signers' signature used a future state.
err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_INVALID);

Expand Down Expand Up @@ -244,7 +244,7 @@ TEST (musig2, invalid_signer_key) {
err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

// Verification should fail since one of the signers; key is incorrect.
// Verification should fail since one of the signers' key is incorrect.
err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_INVALID);

Expand Down Expand Up @@ -305,7 +305,7 @@ TEST (musig2, aggregate_invalid_public_key) {
err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

// Verification should fail since one of the signers; public key is incorrect.
// Verification should fail since one of the signers' public key is incorrect.
err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_INVALID);

Expand All @@ -332,7 +332,7 @@ TEST (musig2, fail_excessive_num_of_participants) {
}
// Precomputation for a signer that fails
err = musig2_signer_precomputation(&mcs_list[0].mc, serialized_pubkey_list, serialized_batch_list, more_signers);
ASSERT_EQ(err, MUSIG2_ERR_PARSE_PK_COMM);
ASSERT_EQ(err, MUSIG2_ERR_PARSE_COMM);

// Generate partial signatures for `mcs_list[1], ..., mcs_list[NR_SIGNERS]`.
// Failing participant cannot sign.
Expand Down
180 changes: 180 additions & 0 deletions tests/serdetest.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extern "C" {
#include "../src/libmusig2.h"

TEST (musig2, pk_list_serialize_deserialize) {

Expand Down Expand Up @@ -48,4 +49,183 @@ TEST (musig2, commitments_serialize_deserialize) {
ASSERT_EQ(serde_batch_list[i], serialized_batch_list[i]);
}

/* Fuzz a public key then try to generate the aggregate public key */
TEST (musig2, fuzz_pubkey_precomputation) {
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
musig2_context_signer mcs_list[NR_SIGNERS]; // Array that holds NR_SIGNERS musig2_context_signer
musig2_context_signature mps[NR_SIGNERS];
unsigned char serialized_batch_list[NR_MESSAGES * NR_SIGNERS * V * MUSIG2_PUBKEY_BYTES_COMPRESSED];
unsigned char serialized_pubkey_list[NR_SIGNERS * MUSIG2_PUBKEY_BYTES_COMPRESSED]; // Signers' public key list
unsigned char signature[MUSIG2_BYTES];
secp256k1_pubkey pubkey;
MUSIG2_ERROR res;
int err;

res = musig2_helper_setup(mcs_list, serialized_pubkey_list, serialized_batch_list, NR_SIGNERS);
ASSERT_EQ(res, MUSIG2_OK);

int fuzz_index = (rand() % NR_SIGNERS) * MUSIG2_PUBKEY_BYTES_COMPRESSED;
musig2_helper_fuzz_data(&serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);

res = musig2_helper_precomputation(serialized_pubkey_list, serialized_batch_list, mcs_list, NR_SIGNERS);

switch(res){
case MUSIG2_ERR_PARSE_PK:
err = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(err, 0);
break;
default:
err = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(err, 1);
}
}

/* Fuzz a public key of a signer after the aggregate public key is generated.
* Try to verify the aggregate signature that includes a single signature created with an invalid public key. */
TEST (musig2, fuzz_pubkey_single_signature) {
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
musig2_context_signer mcs_list[NR_SIGNERS]; // Array that holds NR_SIGNERS musig2_context_signer
musig2_context_signature mps[NR_SIGNERS];
unsigned char serialized_batch_list[NR_MESSAGES * NR_SIGNERS * V * MUSIG2_PUBKEY_BYTES_COMPRESSED];
unsigned char serialized_pubkey_list[NR_SIGNERS * MUSIG2_PUBKEY_BYTES_COMPRESSED]; // Signers' public key list
unsigned char signature[MUSIG2_BYTES];
MUSIG2_ERROR err;

err = musig2_helper_setup(mcs_list, serialized_pubkey_list, serialized_batch_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_helper_precomputation(serialized_pubkey_list, serialized_batch_list, mcs_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

// Fuzz a public key of a randomly selected signer.
int fuzz_index = rand() % NR_SIGNERS;
musig2_helper_fuzz_data(&mcs_list[fuzz_index].keypair.data[MUSIG2_SCALAR_BYTES], MUSIG2_PUBKEY_BYTES_FULL);

err = musig2_helper_sign(mcs_list, mps, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

// Verification should fail since one of the signers' signature is generated with an incorrect public key.
err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_INVALID);
}

/* Set up the verifier given a list of public keys including a fuzzed public key in it.
* Try to verify the aggregate signature. */
TEST (musig2, fuzz_pubkey_verify_aggregate) {

secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
musig2_context_signer mcs_list[NR_SIGNERS]; // Array that holds NR_SIGNERS musig2_context_signer
musig2_context_signature mps[NR_SIGNERS];
unsigned char serialized_batch_list[NR_MESSAGES * NR_SIGNERS * V * MUSIG2_PUBKEY_BYTES_COMPRESSED];
unsigned char serialized_pubkey_list[NR_SIGNERS * MUSIG2_PUBKEY_BYTES_COMPRESSED]; // Signers' public key list
unsigned char signature[MUSIG2_BYTES];
MUSIG2_ERROR err;

err = musig2_helper_setup(mcs_list, serialized_pubkey_list, serialized_batch_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_helper_precomputation(serialized_pubkey_list, serialized_batch_list, mcs_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_helper_sign(mcs_list, mps, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

int fuzz_index = (rand() % NR_SIGNERS) * MUSIG2_PUBKEY_BYTES_COMPRESSED;
musig2_helper_fuzz_data(&serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);

err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);

secp256k1_pubkey pubkey;
int res;
switch(err){
case MUSIG2_ERR_PARSE_PK:
res = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(res, 0);
break;
default:
int cmp_res;
musig2_aggr_pubkey aggr_pubkey, fuzz_aggr_pubkey;
res = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_pubkey_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(res, 1);
assert(musig2_prepare_verifier(&aggr_pubkey, serialized_pubkey_list, NR_SIGNERS));
assert(secp256k1_xonly_pubkey_from_pubkey(ctx, &fuzz_aggr_pubkey, NULL, &mcs_list[0].mc.aggr_pubkey));
cmp_res = secp256k1_xonly_pubkey_cmp(ctx, &fuzz_aggr_pubkey, &aggr_pubkey);
ASSERT_NE(cmp_res, 0);

}
}

/* Fuzz a commitment then try to generate the aggregate R */
TEST (musig2, fuzz_commitment_precomputation) {

secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
musig2_context_signer mcs_list[NR_SIGNERS]; // Array that holds NR_SIGNERS musig2_context_signer
musig2_context_signature mps[NR_SIGNERS];
unsigned char serialized_batch_list[NR_MESSAGES * NR_SIGNERS * V * MUSIG2_PUBKEY_BYTES_COMPRESSED];
unsigned char serialized_pubkey_list[NR_SIGNERS * MUSIG2_PUBKEY_BYTES_COMPRESSED]; // Signers' public key list
unsigned char signature[MUSIG2_BYTES];
secp256k1_pubkey pubkey;
MUSIG2_ERROR res;
int err;

res = musig2_helper_setup(mcs_list, serialized_pubkey_list, serialized_batch_list, NR_SIGNERS);
ASSERT_EQ(res, MUSIG2_OK);

int fuzz_index = (rand() % (NR_SIGNERS * V));
musig2_helper_fuzz_data(&serialized_batch_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);

res = musig2_helper_precomputation(serialized_pubkey_list, serialized_batch_list, mcs_list, NR_SIGNERS);

switch(res){
case MUSIG2_ERR_PARSE_COMM:
err = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_batch_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(err, 0);
break;
default:
err = secp256k1_ec_pubkey_parse(ctx, &pubkey, &serialized_batch_list[fuzz_index], MUSIG2_PUBKEY_BYTES_COMPRESSED);
ASSERT_EQ(err, 1);

err = musig2_helper_sign(mcs_list, mps, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_ERR_CMP_R);
}
}

/* Set up the verifier given a signature with fuzzed aggregate R.
* Try to verify the aggregate signature. */
TEST (musig2, fuzz_commitment_verify_aggregate) {

musig2_context_signer mcs_list[NR_SIGNERS]; // Array that holds NR_SIGNERS musig2_context_signer
musig2_context_signature mps[NR_SIGNERS];
unsigned char serialized_batch_list[NR_MESSAGES * NR_SIGNERS * V * MUSIG2_PUBKEY_BYTES_COMPRESSED];
unsigned char serialized_pubkey_list[NR_SIGNERS * MUSIG2_PUBKEY_BYTES_COMPRESSED]; // Signers' public key list
unsigned char signature[MUSIG2_BYTES];
MUSIG2_ERROR err;

err = musig2_helper_setup(mcs_list, serialized_pubkey_list, serialized_batch_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_helper_precomputation(serialized_pubkey_list, serialized_batch_list, mcs_list, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_helper_sign(mcs_list, mps, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

err = musig2_aggregate_partial_sig(mps, signature, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_OK);

musig2_helper_fuzz_data(&signature[0], MUSIG2_AGGR_PUBKEY_BYTES);

err = musig2_helper_verify(serialized_pubkey_list, signature, MSG_1, MSG_1_LEN, NR_SIGNERS);
ASSERT_EQ(err, MUSIG2_INVALID);
}

}
8 changes: 8 additions & 0 deletions tests/testmusig2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
extern "C" {
#include "../src/libmusig2.h"
#include "config.h"
#include <time.h>

MUSIG2_ERROR musig2_helper_setup(musig2_context_signer *mcs_list, unsigned char *serialized_pubkey_list, unsigned char *serialized_batch_list, int nr_participants) {
int i, j, k, l;
Expand Down Expand Up @@ -71,11 +72,18 @@ MUSIG2_ERROR musig2_helper_verify(unsigned char *serialized_pubkey_list, unsigne
return MUSIG2_OK;
}

void musig2_helper_fuzz_data(unsigned char *serialized_pubkey, int size){
int i;
for (i = 0; i < size; i++)
serialized_pubkey[i] = rand();
}

#include "functiontest.c"
#include "serdetest.c"
}

int main(int argc, char* argv[]){
srand ((unsigned int) time (NULL));
iquerejeta marked this conversation as resolved.
Show resolved Hide resolved
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Loading