From 46c7391154a7325133f97f9ec816ccf98ba76ede Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 26 Oct 2022 00:18:14 -0700 Subject: [PATCH] Add norm argument verify API --- .../bulletproofs_pp_norm_product_impl.h | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h index 1f7b16f1..c380bba1 100644 --- a/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h +++ b/src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h @@ -359,4 +359,190 @@ static int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove( *proof_len = proof_idx; return 1; } + +typedef struct ec_mult_verify_cb_data1 { + const unsigned char *proof; + const secp256k1_ge *commit; + const secp256k1_scalar *challenges; +} ec_mult_verify_cb_data1; + +static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata; + if (idx == 0) { + *pt = *data->commit; + secp256k1_scalar_set_int(sc, 1); + return 1; + } + idx -= 1; + if (idx % 2 == 0) { + unsigned char pk_buf[33]; + idx /= 2; + *sc = data->challenges[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))) { + return 0; + } + } else { + unsigned char pk_buf[33]; + secp256k1_scalar neg_one; + idx /= 2; + secp256k1_scalar_set_int(&neg_one, 1); + secp256k1_scalar_negate(&neg_one, &neg_one); + *sc = data->challenges[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))) { + return 0; + } + } + return 1; +} + +typedef struct ec_mult_verify_cb_data2 { + const secp256k1_scalar *s_g; + const secp256k1_scalar *s_h; + const secp256k1_ge *g_vec; + size_t g_vec_len; +} ec_mult_verify_cb_data2; + +static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata; + if (idx < data->g_vec_len) { + *sc = data->s_g[idx]; + } else { + *sc = data->s_h[idx - data->g_vec_len]; + } + *pt = data->g_vec[idx]; + return 1; +} + +/* Verify the proof. This function modifies the generators, c_vec and the challenge r. The + caller should make sure to back them up if they need to be reused. +*/ +static int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify( + const secp256k1_context* ctx, + secp256k1_scratch_space* scratch, + const unsigned char* proof, + size_t proof_len, + secp256k1_sha256* transcript, + const secp256k1_scalar* r, + const secp256k1_bulletproofs_generators* g_vec, + size_t g_len, + const secp256k1_scalar* c_vec, + size_t c_vec_len, + const secp256k1_ge* commit +) { + secp256k1_scalar r_f, q_f, v, n, l, r_inv, h_c; + secp256k1_scalar *es, *s_g, *s_h, *r_inv_pows; + secp256k1_gej res1, res2; + size_t i = 0, scratch_checkpoint; + int overflow; + size_t log_g_len = secp256k1_bulletproofs_pp_log2(g_len), log_h_len = secp256k1_bulletproofs_pp_log2(c_vec_len); + size_t n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; + size_t h_len = c_vec_len; + + if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) { + return 0; + } + + if (!secp256k1_is_power_of_two(g_len) || !secp256k1_is_power_of_two(h_len)) { + return 0; + } + + secp256k1_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */ + if (overflow) return 0; + secp256k1_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */ + if (overflow) return 0; + if (secp256k1_scalar_is_zero(r)) return 0; + + /* Collect the challenges in a new vector */ + scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + es = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(secp256k1_scalar)); + s_g = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar)); + s_h = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar)); + r_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, log_g_len * sizeof(secp256k1_scalar)); + if (es == NULL || s_g == NULL || s_h == NULL || r_inv_pows == NULL) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + + /* Compute powers of r_inv. Later used in g_factor computations*/ + secp256k1_scalar_inverse_var(&r_inv, r); + secp256k1_bulletproofs_powers_of_r(r_inv_pows, &r_inv, log_g_len); + + /* Compute r_f = r^(2^log_g_len) */ + r_f = *r; + for (i = 0; i < log_g_len; i++) { + secp256k1_scalar_sqr(&r_f, &r_f); + } + + for (i = 0; i < n_rounds; i++) { + secp256k1_scalar e; + secp256k1_sha256_write(transcript, &proof[i * 65], 65); + secp256k1_bulletproofs_challenge_scalar(&e, transcript, 0); + es[i] = e; + } + /* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} r^(2^j) + * = n * r^(2^log_g_len - 1) + * = n * r_f * r_inv */ + secp256k1_scalar_mul(&s_g[0], &n, &r_f); + secp256k1_scalar_mul(&s_g[0], &s_g[0], &r_inv); + for (i = 1; i < g_len; i++) { + size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t nearest_pow_of_two = (size_t)1 << log_i; + /* This combines the two multiplications of challenges and r_invs in a + * single loop. + * s_g[i] = s_g[i - nearest_pow_of_two] + * * e[log_i] * r_inv^(2^log_i) */ + secp256k1_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &es[log_i]); + secp256k1_scalar_mul(&s_g[i], &s_g[i], &r_inv_pows[log_i]); + } + s_h[0] = l; + secp256k1_scalar_set_int(&h_c, 0); + for (i = 1; i < h_len; i++) { + size_t log_i = secp256k1_bulletproofs_pp_log2(i); + size_t nearest_pow_of_two = (size_t)1 << log_i; + secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]); + } + secp256k1_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len); + /* Compute v = n*n*q_f + l*h_c where q_f = r_f^2 */ + secp256k1_scalar_sqr(&q_f, &r_f); + secp256k1_scalar_mul(&v, &n, &n); + secp256k1_scalar_mul(&v, &v, &q_f); + secp256k1_scalar_add(&v, &v, &h_c); + + { + ec_mult_verify_cb_data1 data; + data.proof = proof; + data.commit = commit; + data.challenges = es; + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + } + { + ec_mult_verify_cb_data2 data; + data.g_vec = g_vec->gens; + data.g_vec_len = g_len; + data.s_g = s_g; + data.s_h = s_h; + + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) { + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + return 0; + } + } + + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); + + /* res1 and res2 should be equal. Could not find a simpler way to compare them */ + secp256k1_gej_neg(&res1, &res1); + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); + return secp256k1_gej_is_infinity(&res1); +} #endif