Skip to content

Commit 8d6bb0b

Browse files
committed
Add norm argument verify API
1 parent a726d5e commit 8d6bb0b

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed

src/modules/bulletproofs/bulletproofs_pp_norm_product_impl.h

+198
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,202 @@ int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove(
386386
*proof_len = start_idx + 64;
387387
return 1;
388388
}
389+
390+
typedef struct ec_mult_verify_cb_data1 {
391+
const unsigned char *proof;
392+
const secp256k1_ge *commit;
393+
const secp256k1_scalar *challenges;
394+
} ec_mult_verify_cb_data1;
395+
396+
static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
397+
ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata;
398+
if (idx == 0) {
399+
*pt = *data->commit;
400+
secp256k1_scalar_set_int(sc, 1);
401+
return 1;
402+
}
403+
idx -= 1;
404+
if (idx % 2 == 0) {
405+
unsigned char pk_buf[33];
406+
idx /= 2;
407+
*sc = data->challenges[idx];
408+
pk_buf[0] = 2 | (data->proof[65*idx] >> 1);
409+
memcpy(&pk_buf[1], &data->proof[65*idx + 1], 32);
410+
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
411+
return 0;
412+
}
413+
} else {
414+
unsigned char pk_buf[33];
415+
secp256k1_scalar neg_one;
416+
idx /= 2;
417+
secp256k1_scalar_set_int(&neg_one, 1);
418+
secp256k1_scalar_negate(&neg_one, &neg_one);
419+
*sc = data->challenges[idx];
420+
secp256k1_scalar_sqr(sc, sc);
421+
secp256k1_scalar_add(sc, sc, &neg_one); /* Ignore overflow */
422+
pk_buf[0] = 2 | data->proof[65*idx];
423+
memcpy(&pk_buf[1], &data->proof[65*idx + 33], 32);
424+
if (!secp256k1_eckey_pubkey_parse(pt, pk_buf, sizeof(pk_buf))) {
425+
return 0;
426+
}
427+
}
428+
return 1;
429+
}
430+
431+
typedef struct ec_mult_verify_cb_data2 {
432+
const secp256k1_scalar *s_g;
433+
const secp256k1_scalar *s_h;
434+
const secp256k1_ge *g_vec;
435+
size_t g_vec_len;
436+
} ec_mult_verify_cb_data2;
437+
438+
static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
439+
ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata;
440+
if (idx < data->g_vec_len) {
441+
*sc = data->s_g[idx];
442+
} else {
443+
*sc = data->s_h[idx - data->g_vec_len];
444+
}
445+
*pt = data->g_vec[idx];
446+
return 1;
447+
}
448+
449+
/* Verify the proof */
450+
int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(
451+
const secp256k1_context* ctx,
452+
secp256k1_scratch_space* scratch,
453+
unsigned char* proof,
454+
size_t proof_len,
455+
unsigned char *transcript_hash32,
456+
const secp256k1_scalar* r_ch,
457+
secp256k1_bulletproofs_generators* g_vec,
458+
size_t g_len,
459+
secp256k1_scalar* c_vec,
460+
size_t c_vec_len,
461+
const secp256k1_ge* commit
462+
) {
463+
secp256k1_scalar q, r, v, n, l, r_inv, h_c;
464+
secp256k1_scalar *es, *s_g, *s_h, *r_inv_pows;
465+
secp256k1_gej res1, res2;
466+
size_t i = 0, scratch_checkpoint;
467+
int overflow;
468+
secp256k1_sha256 sha256;
469+
unsigned char ser_commit[33];
470+
size_t log_n = secp256k1_bulletproofs_pp_log2(g_len), log_m = secp256k1_bulletproofs_pp_log2(c_vec_len);
471+
size_t n_rounds = log_n > log_m ? log_n : log_m;
472+
size_t h_len = c_vec_len;
473+
secp256k1_ge comm = *commit;
474+
475+
if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) {
476+
return 0;
477+
}
478+
479+
if (!secp256k1_check_power_of_two(g_len) || !secp256k1_check_power_of_two(h_len)) {
480+
return 0;
481+
}
482+
483+
secp256k1_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */
484+
if (overflow) return 0;
485+
secp256k1_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */
486+
if (overflow) return 0;
487+
if (secp256k1_scalar_is_zero(r_ch)) return 0;
488+
489+
/* Compute powers of q_inv. Later used in g_factor computations*/
490+
r = *r_ch;
491+
secp256k1_scalar_inverse_var(&r_inv, &r);
492+
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
493+
494+
r_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, log_n * sizeof(secp256k1_scalar));
495+
secp256k1_bulletproofs_powers_of_r(r_inv_pows, &r_inv, log_n);
496+
497+
secp256k1_sha256_initialize(&sha256);
498+
secp256k1_sha256_write(&sha256, transcript_hash32, 32);
499+
secp256k1_fe_normalize_var(&comm.x);
500+
secp256k1_fe_normalize_var(&comm.y);
501+
ser_commit[0] = 0x02 | secp256k1_fe_is_odd(&comm.y);
502+
secp256k1_fe_get_b32(&ser_commit[1], &comm.x);
503+
secp256k1_sha256_write(&sha256, ser_commit, 33);
504+
secp256k1_sha256_finalize(&sha256, transcript_hash32);
505+
506+
for (i = 0; i < log_n; i++) {
507+
secp256k1_scalar_sqr(&r, &r);
508+
}
509+
510+
/* Collect the challenges in a new vector */
511+
es = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(secp256k1_scalar));
512+
s_g = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
513+
s_h = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
514+
if (es == NULL || s_g == NULL || s_h == NULL) {
515+
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
516+
return 0;
517+
}
518+
519+
for (i = 0; i < n_rounds; i++) {
520+
secp256k1_scalar e;
521+
secp256k1_sha256_initialize(&sha256);
522+
secp256k1_sha256_write(&sha256, transcript_hash32, 32);
523+
secp256k1_sha256_write(&sha256, &proof[i * 65], 65);
524+
secp256k1_sha256_finalize(&sha256, transcript_hash32);
525+
/* Ignore overflow, output of an hash function will fall in curve order with high probability*/
526+
secp256k1_scalar_set_b32(&e, transcript_hash32, &overflow);
527+
es[i] = e;
528+
}
529+
/* s_g[0] = n * r^(n - 1) = n * (r)^n * r_inv = n * q * r_inv */
530+
secp256k1_scalar_mul(&s_g[0], &n, &r);
531+
secp256k1_scalar_mul(&s_g[0], &s_g[0], &r_inv);
532+
for (i = 1; i < g_len; i++) {
533+
size_t log_i = secp256k1_bulletproofs_pp_log2(i);
534+
size_t nearest_pow_of_two = (size_t)1 << log_i;
535+
secp256k1_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &es[log_i]);
536+
secp256k1_scalar_mul(&s_g[i], &s_g[i], &r_inv_pows[log_i]);
537+
}
538+
s_h[0] = l;
539+
secp256k1_scalar_set_int(&h_c, 0);
540+
for (i = 1; i < h_len; i++) {
541+
size_t log_i = secp256k1_bulletproofs_pp_log2(i);
542+
size_t nearest_pow_of_two = (size_t)1 << log_i;
543+
secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &es[log_i]);
544+
}
545+
secp256k1_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len);
546+
/* Compute v = n*n*q + l*h_c*/
547+
secp256k1_scalar_sqr(&q, &r);
548+
secp256k1_scalar_mul(&v, &n, &n);
549+
secp256k1_scalar_mul(&v, &v, &q);
550+
secp256k1_scalar_add(&v, &v, &h_c);
551+
552+
{
553+
ec_mult_verify_cb_data1 data;
554+
secp256k1_gej temp1, temp2;
555+
secp256k1_scalar one;
556+
data.proof = proof;
557+
data.commit = commit;
558+
data.challenges = es;
559+
560+
secp256k1_gej_set_ge(&temp2, commit);
561+
secp256k1_scalar_set_int(&one, 1);
562+
secp256k1_ecmult(&temp1, &temp2, &one, NULL);
563+
564+
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) {
565+
return 0;
566+
}
567+
}
568+
{
569+
ec_mult_verify_cb_data2 data;
570+
data.g_vec = g_vec->gens;
571+
data.g_vec_len = g_len;
572+
data.s_g = s_g;
573+
data.s_h = s_h;
574+
575+
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) {
576+
return 0;
577+
}
578+
}
579+
580+
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
581+
582+
/* res1 and res2 should be equal. Could not find a simpler way to compare them */
583+
secp256k1_gej_neg(&res1, &res1);
584+
secp256k1_gej_add_var(&res1, &res1, &res2, NULL);
585+
return secp256k1_gej_is_infinity(&res1);
586+
}
389587
#endif

0 commit comments

Comments
 (0)