Skip to content

Commit b081471

Browse files
committed
BP++ verifier
1 parent eed6839 commit b081471

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed

src/modules/bppp/bppp_rangeproof_impl.h

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,5 +704,267 @@ static int secp256k1_bppp_rangeproof_prove_impl(
704704
return res;
705705
}
706706

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

708970
#endif

0 commit comments

Comments
 (0)