Merge elementsproject/secp256k1-zkp#230: norm arg: add prove test vectors

f3126fdfec norm arg: remove prove edge tests which are now covered by vectors (Jonas Nick)
847ed9ecb2 norm arg: add verification to prove vectors (Jonas Nick)
cf797ed2a4 norm arg: add prove test vectors (Jonas Nick)
095c1e749c norm arg: add prove_const to tests (Jonas Nick)
bf7bf8a64f norm arg: split norm_arg_zero into prove_edge and verify_zero_len (Jonas Nick)
a70c4d4a8a norm arg: add test vector for |n| = 0 (Jonas Nick)
f5e4b16f0f norm arg: add test vector for sign bit malleability (Jonas Nick)
c0de361fc5 norm arg: allow X and R to be the point at infinity (Jonas Nick)
f22834f202 norm arg: add verify vector for n = [0], l = [0] (Jonas Nick)
d8e7f3763b musig: move ge_{serialize,parse}_ext to module-independent file (Jonas Nick)

Pull request description:

ACKs for top commit:
  Liam-Eagen:
    ACK f3126fd

Tree-SHA512: 1aad86521fce74435beabe7690c7fcc38ad9ae7a884ddcab69ef825b573433f700723a7672d29df1b4465bc33d5957b6a46f657f988cfd2cc73fa94a3472357d
This commit is contained in:
Jonas Nick
2023-05-09 10:41:47 +00:00
7 changed files with 338 additions and 144 deletions

View File

@@ -14,6 +14,7 @@
#include "bppp_util.h"
#include "bppp_transcript_impl.h"
#include "test_vectors/verify.h"
#include "test_vectors/prove.h"
static void test_bppp_generators_api(void) {
/* The BP generator API requires no precomp */
@@ -212,6 +213,80 @@ void test_norm_util_helpers(void) {
secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &rho_pows[3]));
}
void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R) {
secp256k1_ge X_tmp, R_tmp;
unsigned char buf[65];
secp256k1_bppp_serialize_points(buf, X, R);
CHECK(secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0));
CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1));
ge_equals_ge(X, &X_tmp);
ge_equals_ge(R, &R_tmp);
}
void test_serialize_two_points(void) {
secp256k1_ge X, R;
int i;
for (i = 0; i < count; i++) {
random_group_element_test(&X);
random_group_element_test(&R);
test_serialize_two_points_roundtrip(&X, &R);
}
for (i = 0; i < count; i++) {
random_group_element_test(&X);
secp256k1_ge_set_infinity(&R);
test_serialize_two_points_roundtrip(&X, &R);
}
for (i = 0; i < count; i++) {
secp256k1_ge_set_infinity(&X);
random_group_element_test(&R);
test_serialize_two_points_roundtrip(&X, &R);
}
secp256k1_ge_set_infinity(&X);
secp256k1_ge_set_infinity(&R);
test_serialize_two_points_roundtrip(&X, &R);
/* Test invalid sign byte */
{
secp256k1_ge X_tmp, R_tmp;
unsigned char buf[65];
random_group_element_test(&X);
random_group_element_test(&R);
secp256k1_bppp_serialize_points(buf, &X, &R);
buf[0] |= 4 + (unsigned char)secp256k1_testrandi64(4, 255);
CHECK(!secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0));
CHECK(!secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 0));
}
/* Check that sign bit is 0 for point at infinity */
for (i = 0; i < count; i++) {
secp256k1_ge X_tmp, R_tmp;
unsigned char buf[65];
int expect;
random_group_element_test(&X);
random_group_element_test(&R);
secp256k1_bppp_serialize_points(buf, &X, &R);
memset(&buf[1], 0, 32);
if ((buf[0] & 2) == 0) {
expect = 1;
} else {
expect = 0;
}
CHECK(secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0) == expect);
CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1));
memset(&buf[33], 0, 32);
if ((buf[0] & 1) == 0) {
expect = 1;
} else {
expect = 0;
}
CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1) == expect);
}
}
static void secp256k1_norm_arg_commit_initial_data(
secp256k1_sha256* transcript,
const secp256k1_scalar* rho,
@@ -273,6 +348,50 @@ static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch,
memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(secp256k1_ge));
}
/* Same as secp256k1_bppp_rangeproof_norm_product_prove but does not modify the inputs */
static int secp256k1_bppp_rangeproof_norm_product_prove_const(
secp256k1_scratch_space* scratch,
unsigned char* proof,
size_t *proof_len,
secp256k1_sha256 *transcript,
const secp256k1_scalar* rho,
const secp256k1_ge* g_vec,
size_t g_vec_len,
const secp256k1_scalar* n_vec,
size_t n_vec_len,
const secp256k1_scalar* l_vec,
size_t l_vec_len,
const secp256k1_scalar* c_vec,
size_t c_vec_len
) {
secp256k1_scalar *ns, *ls, *cs;
secp256k1_ge *gs;
size_t scratch_checkpoint;
size_t g_len = n_vec_len, h_len = l_vec_len;
int res;
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, g_vec, g_len, h_len);
res = secp256k1_bppp_rangeproof_norm_product_prove(
ctx,
scratch,
proof,
proof_len,
transcript, /* Transcript hash of the parent protocol */
rho,
gs,
g_vec_len,
ns,
n_vec_len,
ls,
l_vec_len,
cs,
c_vec_len
);
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
return res;
}
/* A complete norm argument. In contrast to secp256k1_bppp_rangeproof_norm_product_prove, this is meant
to be used as a standalone norm argument.
This is a simple wrapper around secp256k1_bppp_rangeproof_norm_product_prove
@@ -293,38 +412,10 @@ static int secp256k1_norm_arg_prove(
size_t c_vec_len,
const secp256k1_ge* commit
) {
secp256k1_scalar *ns, *ls, *cs;
secp256k1_ge *gs, comm = *commit;
size_t scratch_checkpoint;
size_t g_len = n_vec_len, h_len = l_vec_len;
int res;
secp256k1_sha256 transcript;
secp256k1_norm_arg_commit_initial_data(&transcript, rho, gens_vec, n_vec_len, c_vec, c_vec_len, commit);
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens_vec->gens, g_len, h_len);
/* Commit to the initial public values */
secp256k1_norm_arg_commit_initial_data(&transcript, rho, gens_vec, g_len, c_vec, c_vec_len, &comm);
res = secp256k1_bppp_rangeproof_norm_product_prove(
ctx,
scratch,
proof,
proof_len,
&transcript, /* Transcript hash of the parent protocol */
rho,
gs,
gens_vec->n,
ns,
n_vec_len,
ls,
l_vec_len,
cs,
c_vec_len
);
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
return res;
return secp256k1_bppp_rangeproof_norm_product_prove_const(scratch, proof, proof_len, &transcript, rho, gens_vec->gens, gens_vec->n, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len);
}
/* Verify the proof */
@@ -362,81 +453,30 @@ static int secp256k1_norm_arg_verify(
return res;
}
void norm_arg_zero(void) {
/* Verify |c| = 0 */
void norm_arg_verify_zero_len(void) {
secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
secp256k1_scalar rho, mu;
secp256k1_ge commit;
size_t i;
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*10); /* shouldn't need much */
unsigned char proof[1000];
secp256k1_sha256 transcript;
unsigned int n_vec_len = 1;
unsigned int c_vec_len = 1;
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
size_t plen = sizeof(proof);
random_scalar_order(&rho);
secp256k1_scalar_sqr(&mu, &rho);
/* l is zero vector and n is zero vectors of length 1 each. */
{
size_t plen = sizeof(proof);
unsigned int n_vec_len = 1;
unsigned int c_vec_len = 1;
secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
random_scalar_order(&n_vec[0]);
random_scalar_order(&c_vec[0]);
random_scalar_order(&l_vec[0]);
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, 0, &commit));
secp256k1_scalar_set_int(&n_vec[0], 0);
secp256k1_scalar_set_int(&l_vec[0], 0);
random_scalar_order(&c_vec[0]);
secp256k1_sha256_initialize(&transcript); /* No challenges used in n = 1, l = 1, but we set transcript as a good practice*/
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
{
secp256k1_scalar *ns, *ls, *cs;
secp256k1_ge *gs;
size_t scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, gens->gens, n_vec_len, c_vec_len);
CHECK(secp256k1_bppp_rangeproof_norm_product_prove(ctx, scratch, proof, &plen, &transcript, &rho, gs, gens->n, ns, n_vec_len, ls, c_vec_len, cs, c_vec_len));
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
}
secp256k1_sha256_initialize(&transcript);
CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gens, c_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(ctx, gens);
}
/* l is the zero vector and longer than n. This results in one of the
* internal commitments X or R to be the point at infinity. */
{
unsigned int n_vec_len = 1;
unsigned int c_vec_len = 2;
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
size_t plen = sizeof(proof);
for (i = 0; i < n_vec_len; i++) {
random_scalar_order(&n_vec[i]);
}
for (i = 0; i < c_vec_len; i++) {
secp256k1_scalar_set_int(&l_vec[i], 0);
random_scalar_order(&c_vec[i]);
}
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(!secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(ctx, gs);
}
/* Verify vectors of length 0 */
{
unsigned int n_vec_len = 1;
unsigned int c_vec_len = 1;
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
size_t plen = sizeof(proof);
random_scalar_order(&n_vec[0]);
random_scalar_order(&c_vec[0]);
random_scalar_order(&l_vec[0]);
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, 0, c_vec, c_vec_len, &commit));
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, 0, &commit));
secp256k1_bppp_generators_destroy(ctx, gs);
}
secp256k1_bppp_generators_destroy(ctx, gs);
secp256k1_scratch_space_destroy(ctx, scratch);
}
@@ -535,7 +575,7 @@ int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned ch
secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow);
CHECK(!overflow);
}
CHECK(secp256k1_eckey_pubkey_parse(&commit, commit33, 33));
CHECK(secp256k1_ge_parse_ext(&commit, commit33));
ret = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit);
secp256k1_bppp_generators_destroy(ctx, gs);
@@ -557,20 +597,89 @@ void norm_arg_verify_vectors(void) {
CHECK(IDX_TO_TEST(6));
CHECK(IDX_TO_TEST(7));
CHECK(IDX_TO_TEST(8));
CHECK(IDX_TO_TEST(9));
CHECK(IDX_TO_TEST(10));
CHECK(IDX_TO_TEST(11));
CHECK(IDX_TO_TEST(12));
CHECK(alloc == scratch->alloc_size);
secp256k1_scratch_space_destroy(ctx, scratch);
}
#undef IDX_TO_TEST
void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, const unsigned char n_vec32[][32], secp256k1_scalar *n_vec, size_t n_vec_len, const unsigned char l_vec32[][32], secp256k1_scalar *l_vec, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, int result) {
secp256k1_sha256 transcript;
secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len));
secp256k1_scalar rho, mu;
secp256k1_ge commit;
unsigned char myproof[1024];
size_t myplen = sizeof(myproof);
int overflow;
int i;
CHECK(gs != NULL);
secp256k1_sha256_initialize(&transcript);
secp256k1_scalar_set_b32(&rho, r32, &overflow);
CHECK(!overflow);
secp256k1_scalar_sqr(&mu, &rho);
for (i = 0; i < (int)n_vec_len; i++) {
secp256k1_scalar_set_b32(&n_vec[i], n_vec32[i], &overflow);
CHECK(!overflow);
}
for (i = 0; i < (int)c_vec_len; i++) {
secp256k1_scalar_set_b32(&l_vec[i], l_vec32[i], &overflow);
CHECK(!overflow);
secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow);
CHECK(!overflow);
}
CHECK(secp256k1_bppp_rangeproof_norm_product_prove_const(scratch, myproof, &myplen, &transcript, &rho, gs->gens, gs->n, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len) == result);
if (!result) {
secp256k1_bppp_generators_destroy(ctx, gs);
return;
}
CHECK(plen == myplen);
CHECK(secp256k1_memcmp_var(proof, myproof, plen) == 0);
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
secp256k1_sha256_initialize(&transcript);
CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(ctx, gs);
}
#define IDX_TO_TEST(i) (norm_arg_prove_vectors_helper(scratch, prove_vector_gens, prove_vector_##i##_proof, sizeof(prove_vector_##i##_proof), prove_vector_##i##_r32,\
prove_vector_##i##_n_vec32, prove_vector_##i##_n_vec, sizeof(prove_vector_##i##_n_vec)/sizeof(secp256k1_scalar),\
prove_vector_##i##_l_vec32, prove_vector_##i##_l_vec,\
prove_vector_##i##_c_vec32, prove_vector_##i##_c_vec, sizeof(prove_vector_##i##_c_vec)/sizeof(secp256k1_scalar), \
prove_vector_##i##_result))
void norm_arg_prove_vectors(void) {
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
size_t alloc = scratch->alloc_size;
IDX_TO_TEST(0);
IDX_TO_TEST(1);
IDX_TO_TEST(2);
IDX_TO_TEST(3);
IDX_TO_TEST(4);
CHECK(alloc == scratch->alloc_size);
secp256k1_scratch_space_destroy(ctx, scratch);
}
#undef IDX_TO_TEST
void run_bppp_tests(void) {
test_log_exp();
test_norm_util_helpers();
test_serialize_two_points();
test_bppp_generators_api();
test_bppp_generators_fixed();
test_bppp_tagged_hash();
norm_arg_zero();
norm_arg_verify_zero_len();
norm_arg_test(1, 1);
norm_arg_test(1, 64);
norm_arg_test(64, 1);
@@ -578,7 +687,9 @@ void run_bppp_tests(void) {
norm_arg_test(32, 64);
norm_arg_test(64, 32);
norm_arg_test(64, 64);
norm_arg_verify_vectors();
norm_arg_prove_vectors();
}
#endif