norm arg: allow X and R to be the point at infinity

Add test vector
This commit is contained in:
Jonas Nick 2023-03-01 12:51:15 +00:00
parent f22834f202
commit c0de361fc5
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
4 changed files with 115 additions and 22 deletions

View File

@ -300,17 +300,8 @@ static int secp256k1_bppp_rangeproof_norm_product_prove(
return 0; return 0;
} }
/* We only fail here because we cannot serialize points at infinity. */
if (secp256k1_gej_is_infinity(&xj) || secp256k1_gej_is_infinity(&rj)) {
return 0;
}
secp256k1_ge_set_gej_var(&x_ge, &xj); secp256k1_ge_set_gej_var(&x_ge, &xj);
secp256k1_fe_normalize_var(&x_ge.x);
secp256k1_fe_normalize_var(&x_ge.y);
secp256k1_ge_set_gej_var(&r_ge, &rj); secp256k1_ge_set_gej_var(&r_ge, &rj);
secp256k1_fe_normalize_var(&r_ge.x);
secp256k1_fe_normalize_var(&r_ge.y);
secp256k1_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge); secp256k1_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge);
proof_idx += 65; proof_idx += 65;
@ -379,16 +370,12 @@ static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx
} }
idx -= 1; idx -= 1;
if (idx % 2 == 0) { if (idx % 2 == 0) {
unsigned char pk_buf[33];
idx /= 2; idx /= 2;
*sc = data->gammas[idx]; *sc = data->gammas[idx];
pk_buf[0] = 2 | (data->proof[65*idx] >> 1); if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 0)) {
memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32);
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
return 0; return 0;
} }
} else { } else {
unsigned char pk_buf[33];
secp256k1_scalar neg_one; secp256k1_scalar neg_one;
idx /= 2; idx /= 2;
secp256k1_scalar_set_int(&neg_one, 1); secp256k1_scalar_set_int(&neg_one, 1);
@ -396,9 +383,7 @@ static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx
*sc = data->gammas[idx]; *sc = data->gammas[idx];
secp256k1_scalar_sqr(sc, sc); secp256k1_scalar_sqr(sc, sc);
secp256k1_scalar_add(sc, sc, &neg_one); secp256k1_scalar_add(sc, sc, &neg_one);
pk_buf[0] = 2 | data->proof[65*idx]; if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 1)) {
memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32);
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
return 0; return 0;
} }
} }

View File

@ -15,10 +15,33 @@
/* Outputs a pair of points, amortizing the parity byte between them /* Outputs a pair of points, amortizing the parity byte between them
* Assumes both points' coordinates have been normalized. * Assumes both points' coordinates have been normalized.
*/ */
static void secp256k1_bppp_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) { static void secp256k1_bppp_serialize_points(unsigned char *output, secp256k1_ge *lpt, secp256k1_ge *rpt) {
output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y); unsigned char tmp[33];
secp256k1_fe_get_b32(&output[1], &lpt->x); secp256k1_ge_serialize_ext(tmp, lpt);
secp256k1_fe_get_b32(&output[33], &rpt->x); output[0] = (tmp[0] & 1) << 1;
memcpy(&output[1], &tmp[1], 32);
secp256k1_ge_serialize_ext(tmp, rpt);
output[0] |= (tmp[0] & 1);
memcpy(&output[33], &tmp[1], 32);
}
static int secp256k1_bppp_parse_one_of_points(secp256k1_ge *pt, const unsigned char *in65, int idx) {
unsigned char tmp[33] = { 0 };
if (in65[0] > 3) {
return 0;
}
/* Check if the input array encodes the point at infinity */
if ((secp256k1_memcmp_var(tmp, &in65[1 + 32*idx], 32)) != 0) {
tmp[0] = 2 | ((in65[0] & (2 - idx)) >> (1 - idx));
memcpy(&tmp[1], &in65[1 + 32*idx], 32);
} else {
/* If we're parsing the point at infinity, enforce that the sign bit is
* 0. */
if ((in65[0] & (2 - idx)) != 0) {
return 0;
}
}
return secp256k1_ge_parse_ext(pt, tmp);
} }
/* Outputs a serialized point in compressed form. Returns 0 at point at infinity. /* Outputs a serialized point in compressed form. Returns 0 at point at infinity.

View File

@ -69,4 +69,11 @@ static secp256k1_scalar verify_vector_9_c_vec[1];
static const unsigned char verify_vector_9_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }; static const unsigned char verify_vector_9_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
static const unsigned char verify_vector_9_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const unsigned char verify_vector_9_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const int verify_vector_9_result = 1; static const int verify_vector_9_result = 1;
static const unsigned char verify_vector_10_commit33[33] = { 0x03, 0x62, 0x8A, 0xC2, 0xF1, 0xF2, 0x00, 0xE0, 0x81, 0xBD, 0xA0, 0xA9, 0x6D, 0x25, 0x53, 0xB4, 0x17, 0xC1, 0x02, 0x93, 0x50, 0x3E, 0x91, 0xD4, 0xD1, 0x3A, 0x82, 0x89, 0x02, 0x24, 0x78, 0x49, 0xA5 };
static const size_t verify_vector_10_n_vec_len = 2;
static const unsigned char verify_vector_10_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
static secp256k1_scalar verify_vector_10_c_vec[1];
static const unsigned char verify_vector_10_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
static const unsigned char verify_vector_10_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
static const int verify_vector_10_result = 1;

View File

@ -212,6 +212,80 @@ void test_norm_util_helpers(void) {
secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &rho_pows[3])); 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( static void secp256k1_norm_arg_commit_initial_data(
secp256k1_sha256* transcript, secp256k1_sha256* transcript,
const secp256k1_scalar* rho, const secp256k1_scalar* rho,
@ -416,7 +490,9 @@ void norm_arg_zero(void) {
random_scalar_order(&c_vec[i]); 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_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_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
secp256k1_sha256_initialize(&transcript);
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(ctx, gs); secp256k1_bppp_generators_destroy(ctx, gs);
} }
@ -558,6 +634,7 @@ void norm_arg_verify_vectors(void) {
CHECK(IDX_TO_TEST(7)); CHECK(IDX_TO_TEST(7));
CHECK(IDX_TO_TEST(8)); CHECK(IDX_TO_TEST(8));
CHECK(IDX_TO_TEST(9)); CHECK(IDX_TO_TEST(9));
CHECK(IDX_TO_TEST(10));
CHECK(alloc == scratch->alloc_size); CHECK(alloc == scratch->alloc_size);
secp256k1_scratch_space_destroy(ctx, scratch); secp256k1_scratch_space_destroy(ctx, scratch);
@ -567,6 +644,7 @@ void norm_arg_verify_vectors(void) {
void run_bppp_tests(void) { void run_bppp_tests(void) {
test_log_exp(); test_log_exp();
test_norm_util_helpers(); test_norm_util_helpers();
test_serialize_two_points();
test_bppp_generators_api(); test_bppp_generators_api();
test_bppp_generators_fixed(); test_bppp_generators_fixed();
test_bppp_tagged_hash(); test_bppp_tagged_hash();