diff --git a/src/modules/bppp/bppp_norm_product_impl.h b/src/modules/bppp/bppp_norm_product_impl.h index 6b7521a1..dd1a0d3b 100644 --- a/src/modules/bppp/bppp_norm_product_impl.h +++ b/src/modules/bppp/bppp_norm_product_impl.h @@ -300,17 +300,8 @@ static int secp256k1_bppp_rangeproof_norm_product_prove( 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_fe_normalize_var(&x_ge.x); - secp256k1_fe_normalize_var(&x_ge.y); 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); proof_idx += 65; @@ -379,16 +370,12 @@ static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx } idx -= 1; if (idx % 2 == 0) { - unsigned char pk_buf[33]; idx /= 2; *sc = data->gammas[idx]; - pk_buf[0] = 2 | (data->proof[65*idx] >> 1); - memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32); - if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { + if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 0)) { return 0; } } else { - unsigned char pk_buf[33]; secp256k1_scalar neg_one; idx /= 2; 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]; secp256k1_scalar_sqr(sc, sc); secp256k1_scalar_add(sc, sc, &neg_one); - pk_buf[0] = 2 | data->proof[65*idx]; - memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32); - if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) { + if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 1)) { return 0; } } diff --git a/src/modules/bppp/bppp_util.h b/src/modules/bppp/bppp_util.h index fd04ae69..12f3da5a 100644 --- a/src/modules/bppp/bppp_util.h +++ b/src/modules/bppp/bppp_util.h @@ -15,10 +15,33 @@ /* Outputs a pair of points, amortizing the parity byte between them * Assumes both points' coordinates have been normalized. */ -static void secp256k1_bppp_serialize_points(unsigned char *output, const secp256k1_ge *lpt, const secp256k1_ge *rpt) { - output[0] = (secp256k1_fe_is_odd(&lpt->y) << 1) + secp256k1_fe_is_odd(&rpt->y); - secp256k1_fe_get_b32(&output[1], &lpt->x); - secp256k1_fe_get_b32(&output[33], &rpt->x); +static void secp256k1_bppp_serialize_points(unsigned char *output, secp256k1_ge *lpt, secp256k1_ge *rpt) { + unsigned char tmp[33]; + secp256k1_ge_serialize_ext(tmp, lpt); + 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. diff --git a/src/modules/bppp/test_vectors/verify.h b/src/modules/bppp/test_vectors/verify.h index cc07850e..7b4bc634 100644 --- a/src/modules/bppp/test_vectors/verify.h +++ b/src/modules/bppp/test_vectors/verify.h @@ -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_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 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; diff --git a/src/modules/bppp/tests_impl.h b/src/modules/bppp/tests_impl.h index bbbc2b1f..4792519a 100644 --- a/src/modules/bppp/tests_impl.h +++ b/src/modules/bppp/tests_impl.h @@ -212,6 +212,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, @@ -416,7 +490,9 @@ void norm_arg_zero(void) { 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)); + 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); } @@ -558,6 +634,7 @@ void norm_arg_verify_vectors(void) { CHECK(IDX_TO_TEST(7)); CHECK(IDX_TO_TEST(8)); CHECK(IDX_TO_TEST(9)); + CHECK(IDX_TO_TEST(10)); CHECK(alloc == scratch->alloc_size); secp256k1_scratch_space_destroy(ctx, scratch); @@ -567,6 +644,7 @@ void norm_arg_verify_vectors(void) { 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();