Skip to content

Commit 4d59ef5

Browse files
committed
BP++ verifier
1 parent 20a7385 commit 4d59ef5

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed

src/modules/bulletproofs/bulletproofs_pp_rangeproof_impl.h

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,5 +692,267 @@ static int secp256k1_bulletproofs_pp_rangeproof_prove_impl(
692692
return res;
693693
}
694694

695+
typedef struct secp256k1_bulletproofs_pp_verify_cb_data {
696+
const unsigned char *proof;
697+
const secp256k1_scalar *g_vec_pub_deltas;
698+
const secp256k1_scalar *t_pows;
699+
const secp256k1_scalar *v;
700+
const secp256k1_ge *asset_genp;
701+
const secp256k1_ge *commit;
702+
const secp256k1_ge *g_gens;
703+
} secp256k1_bulletproofs_pp_verify_cb_data;
704+
705+
static int secp256k1_bulletproofs_pp_verify_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
706+
secp256k1_bulletproofs_pp_verify_cb_data *data = (secp256k1_bulletproofs_pp_verify_cb_data*) cbdata;
707+
switch(idx) {
708+
case 0: /* v * asset_genp */
709+
*pt = *data->asset_genp;
710+
*sc = *data->v;
711+
break;
712+
case 1: /* t * M */
713+
if (!secp256k1_eckey_pubkey_parse(pt, data->proof, 33)) {
714+
return 0;
715+
}
716+
*sc = data->t_pows[0];
717+
break;
718+
case 2: /* t^2 D */
719+
if (!secp256k1_eckey_pubkey_parse(pt, &data->proof[33], 33)) {
720+
return 0;
721+
}
722+
*sc = data->t_pows[1];
723+
break;
724+
case 3: /* t^3 R */
725+
if (!secp256k1_eckey_pubkey_parse(pt, &data->proof[33 * 2], 33)) {
726+
return 0;
727+
}
728+
*sc = data->t_pows[2];
729+
break;
730+
case 4: /* 1. S */
731+
if (!secp256k1_eckey_pubkey_parse(pt, &data->proof[33 * 3], 33)) {
732+
return 0;
733+
}
734+
secp256k1_scalar_set_int(sc, 1);
735+
break;
736+
case 5: /* 2t^5 V(commit) */
737+
*pt = *data->commit;
738+
*sc = data->t_pows[4];
739+
secp256k1_scalar_add(sc, sc, sc);
740+
break;
741+
default:
742+
idx -= 6;
743+
*pt = data->g_gens[idx];
744+
*sc = data->g_vec_pub_deltas[idx];
745+
break;
746+
}
747+
return 1;
748+
}
749+
750+
static int secp256k1_bulletproofs_pp_rangeproof_verify_impl(
751+
const secp256k1_context* ctx,
752+
secp256k1_scratch_space* scratch,
753+
const secp256k1_bulletproofs_generators* gens,
754+
const secp256k1_ge* asset_genp,
755+
const unsigned char* proof,
756+
const size_t proof_len,
757+
const size_t n_bits,
758+
const size_t digit_base,
759+
const uint64_t min_value,
760+
const secp256k1_ge* commitp,
761+
const unsigned char* extra_commit,
762+
size_t extra_commit_len
763+
) {
764+
size_t scratch_checkpoint;
765+
secp256k1_sha256 transcript;
766+
size_t num_digits = n_bits / secp256k1_bulletproofs_pp_log2(digit_base);
767+
size_t h_len = 8, i;
768+
size_t g_offset = num_digits > digit_base ? num_digits : digit_base;
769+
size_t log_n = secp256k1_bulletproofs_pp_log2(g_offset), log_m = secp256k1_bulletproofs_pp_log2(h_len);
770+
size_t n_rounds = log_n > log_m ? log_n : log_m;
771+
secp256k1_scalar v_g;
772+
secp256k1_scalar *q_pows, *q_inv_pows, *g_vec_pub_deltas;
773+
secp256k1_scalar e, q_sqrt, q, q_inv, x, y, t;
774+
/* To be re-used as c_vec later */
775+
secp256k1_scalar t_pows[8];
776+
777+
/* Check proof sizes*/
778+
if (proof_len != 33 * 4 + (65 * n_rounds) + 64) {
779+
return 0;
780+
}
781+
if (gens->n != (g_offset + h_len)) {
782+
return 0;
783+
}
784+
if (!secp256k1_check_power_of_two(digit_base) || !secp256k1_check_power_of_two(num_digits) || !secp256k1_check_power_of_two(n_bits)) {
785+
return 0;
786+
}
787+
if (n_bits > 64) {
788+
return 0;
789+
}
790+
if (extra_commit_len > 0 && extra_commit == NULL) {
791+
return 0;
792+
}
793+
794+
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
795+
q_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_offset * sizeof(secp256k1_scalar));
796+
q_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_offset * sizeof(secp256k1_scalar));
797+
g_vec_pub_deltas = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_offset * sizeof(secp256k1_scalar));
798+
799+
if ( q_pows == NULL || q_inv_pows == NULL ) {
800+
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
801+
return 0;
802+
}
803+
804+
/* Obtain the challenges */
805+
secp256k1_bulletproofs_pp_commit_initial_data(
806+
&transcript,
807+
num_digits,
808+
digit_base,
809+
min_value,
810+
commitp,
811+
asset_genp,
812+
extra_commit,
813+
extra_commit_len
814+
);
815+
816+
/* Verify round 1 */
817+
secp256k1_sha256_write(&transcript, proof, 66);
818+
secp256k1_bulletproofs_challenge_scalar(&e, &transcript, 0);
819+
820+
/* Verify round 2 */
821+
secp256k1_sha256_write(&transcript, &proof[33*2], 33);
822+
secp256k1_bulletproofs_challenge_scalar(&q_sqrt, &transcript, 0);
823+
secp256k1_bulletproofs_challenge_scalar(&x, &transcript, 1);
824+
secp256k1_bulletproofs_challenge_scalar(&y, &transcript, 2);
825+
secp256k1_scalar_sqr(&q, &q_sqrt);
826+
secp256k1_scalar_inverse_var(&q_inv, &q);
827+
828+
/* Verify round 3 */
829+
secp256k1_sha256_write(&transcript, &proof[33*3], 33);
830+
secp256k1_bulletproofs_challenge_scalar(&t, &transcript, 0);
831+
832+
secp256k1_bulletproofs_pp_rangeproof_powers_of_q(q_pows, &q, g_offset);
833+
secp256k1_bulletproofs_pp_rangeproof_powers_of_q(q_inv_pows, &q_inv, g_offset);
834+
835+
/* Computes from t^1 to t^7, Others unneeded, will be set to 0 later */
836+
secp256k1_bulletproofs_pp_rangeproof_powers_of_q(&t_pows[0], &t, 7);
837+
{
838+
/* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + (x/e+i)*t^4)*q_inv^i + e*t^2 */
839+
secp256k1_scalar b_pow_i_t3, neg_x_t2, x_t4, e_t2, base;
840+
b_pow_i_t3 = t_pows[2];
841+
secp256k1_scalar_negate(&neg_x_t2, &x);
842+
secp256k1_scalar_mul(&neg_x_t2, &neg_x_t2, &t_pows[1]);
843+
x_t4 = t_pows[3];
844+
secp256k1_scalar_mul(&x_t4, &x_t4, &x);
845+
e_t2 = t_pows[1];
846+
secp256k1_scalar_mul(&e_t2, &e_t2, &e);
847+
secp256k1_scalar_set_int(&base, digit_base);
848+
849+
for (i = 0; i < g_offset; i++) {
850+
secp256k1_scalar_clear(&g_vec_pub_deltas[i]);
851+
if (i < num_digits) {
852+
secp256k1_scalar_add(&g_vec_pub_deltas[i], &b_pow_i_t3, &neg_x_t2); /* g_vec_pub_delta[i] = b^i*t^3 + (-x)*t^2 */
853+
secp256k1_scalar_mul(&b_pow_i_t3, &b_pow_i_t3, &base);
854+
}
855+
856+
if (i < digit_base) {
857+
secp256k1_scalar e_plus_i_inv;
858+
secp256k1_scalar_set_int(&e_plus_i_inv, i); /* digit base is less than 2^32, can directly set*/
859+
secp256k1_scalar_add(&e_plus_i_inv, &e_plus_i_inv, &e); /* (e + i)*/
860+
secp256k1_scalar_inverse_var(&e_plus_i_inv, &e_plus_i_inv); /* 1/(e +i)*/
861+
secp256k1_scalar_mul(&e_plus_i_inv, &e_plus_i_inv, &x_t4); /* xt^4/(e+i) */
862+
863+
secp256k1_scalar_add(&g_vec_pub_deltas[i], &g_vec_pub_deltas[i], &e_plus_i_inv); /*g_vec_pub_delta[i] = b^i*t^3 + (-x)*t^2 + xt^4/(e+i)*/
864+
}
865+
866+
secp256k1_scalar_mul(&g_vec_pub_deltas[i], &g_vec_pub_deltas[i], &q_inv_pows[i]); /* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + xt^4/(e+i))*q_inv^i */
867+
if (i < num_digits) {
868+
secp256k1_scalar_add(&g_vec_pub_deltas[i], &g_vec_pub_deltas[i], &e_t2); /* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + xt^4/(e+i))*q_inv^i + e*t^2 */
869+
}
870+
}
871+
}
872+
873+
{
874+
/* v = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)>) + x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
875+
secp256k1_scalar two_t5, x2_t8, b_pow_i, neg_x_q_inv_pow_plus_e, e_plus_i_inv, base, v_g1, v_g2, sc_min_v;
876+
secp256k1_scalar_set_int(&two_t5, 2);
877+
secp256k1_scalar_mul(&two_t5, &two_t5, &t_pows[4]);
878+
secp256k1_scalar_mul(&x2_t8, &t_pows[3], &x);
879+
secp256k1_scalar_sqr(&x2_t8, &x2_t8);
880+
secp256k1_scalar_set_int(&b_pow_i, 1);
881+
secp256k1_scalar_clear(&v_g1);
882+
secp256k1_scalar_clear(&v_g2);
883+
secp256k1_scalar_set_int(&base, digit_base);
884+
885+
/* Compute v_g1 = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)>) */
886+
for (i = 0; i < num_digits; i++) {
887+
secp256k1_scalar_add(&v_g1, &v_g1, &q_pows[i]); /* v_g1 = <q^(i+1), 1> */
888+
secp256k1_scalar_negate(&neg_x_q_inv_pow_plus_e, &x); /* -x */
889+
secp256k1_scalar_mul(&neg_x_q_inv_pow_plus_e, &q_inv_pows[i], &neg_x_q_inv_pow_plus_e); /* -x*q^-(i+1) */
890+
secp256k1_scalar_add(&neg_x_q_inv_pow_plus_e, &neg_x_q_inv_pow_plus_e, &e); /* -x*q^-(i+1) + e */
891+
secp256k1_scalar_mul(&neg_x_q_inv_pow_plus_e, &neg_x_q_inv_pow_plus_e, &b_pow_i); /* <b^i, -x*q^-(i+1) + e> */
892+
secp256k1_scalar_add(&v_g1, &v_g1, &neg_x_q_inv_pow_plus_e); /* v_g1 = <q^(i+1), 1> + <b^i, -x*q^-(i+1) + e> */
893+
secp256k1_scalar_mul(&b_pow_i, &b_pow_i, &base);
894+
}
895+
secp256k1_scalar_set_int(&sc_min_v, min_value);
896+
secp256k1_scalar_negate(&sc_min_v, &sc_min_v);
897+
secp256k1_scalar_add(&v_g1, &v_g1, &sc_min_v); /* v_g1 = <q^(i+1), 1> + <b^i, -x*q^-(i+1) + e> - min_value */
898+
secp256k1_scalar_mul(&v_g1, &v_g1, &two_t5); /* v_g1 = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)> - min_value) */
899+
900+
/* Compute v_g2 = x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
901+
for (i = 0; i < digit_base; i++) {
902+
secp256k1_scalar_set_int(&e_plus_i_inv, i); /* digit base is less than 2^32, can directly set*/
903+
secp256k1_scalar_add(&e_plus_i_inv, &e_plus_i_inv, &e); /* (e + i)*/
904+
secp256k1_scalar_inverse_var(&e_plus_i_inv, &e_plus_i_inv); /* 1/(e +i)*/
905+
secp256k1_scalar_sqr(&e_plus_i_inv, &e_plus_i_inv); /* 1/(e +i)^2 */
906+
secp256k1_scalar_mul(&e_plus_i_inv, &e_plus_i_inv, &q_inv_pows[i]); /* q^-(i+1)/(e+i)^2 */
907+
secp256k1_scalar_add(&v_g2, &v_g2, &e_plus_i_inv); /* v_g2 = <q^-(i+1)/(e+i), 1/(e+i)> */
908+
}
909+
secp256k1_scalar_mul(&v_g2, &v_g2, &x2_t8); /* v_g2 = x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
910+
secp256k1_scalar_add(&v_g, &v_g1, &v_g2); /* v_g = v_g1 + v_g2 */
911+
}
912+
/* Ecmult to compute C = S + tM + t^2D + t^3R + 2t^5V + <g_vec_pub_deltas, G_vec> + v_g*A(asset_genP) */
913+
{
914+
secp256k1_bulletproofs_pp_verify_cb_data cb_data;
915+
secp256k1_gej c_commj;
916+
secp256k1_ge c_comm;
917+
size_t num_points;
918+
cb_data.g_vec_pub_deltas = g_vec_pub_deltas;
919+
cb_data.v = &v_g;
920+
cb_data.asset_genp = asset_genp;
921+
cb_data.commit = commitp;
922+
cb_data.g_gens = gens->gens;
923+
cb_data.proof = proof;
924+
cb_data.t_pows = t_pows;
925+
num_points = 6 + g_offset;
926+
927+
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &c_commj, NULL, secp256k1_bulletproofs_pp_verify_cb, (void*) &cb_data, num_points)) {
928+
return 0;
929+
}
930+
931+
secp256k1_ge_set_gej_var(&c_comm, &c_commj);
932+
/* Make c = y*(T, T^2, T^3, T^4, T^6, T^7, 0, 0) */
933+
t_pows[4] = t_pows[5];
934+
t_pows[5] = t_pows[6];
935+
for (i = 0; i < 6; i++) {
936+
secp256k1_scalar_mul(&t_pows[i], &t_pows[i], &y);
937+
}
938+
secp256k1_scalar_clear(&t_pows[6]);
939+
secp256k1_scalar_clear(&t_pows[7]);
940+
941+
return secp256k1_bulletproofs_pp_rangeproof_norm_product_verify(
942+
ctx,
943+
scratch,
944+
&proof[33*4],
945+
proof_len - 33*4,
946+
&transcript,
947+
&q_sqrt,
948+
gens,
949+
asset_genp,
950+
g_offset,
951+
t_pows,
952+
8,
953+
&c_comm
954+
);
955+
}
956+
}
695957

696958
#endif

0 commit comments

Comments
 (0)