|
@@ -25,6 +25,7 @@ private:
|
|
|
pb_variable_array<FieldT> kbits, rbits;
|
|
|
pb_variable<FieldT> elgx, elgy;
|
|
|
pb_linear_combination<FieldT> x;
|
|
|
+ pb_variable<FieldT> s, y;
|
|
|
vector<packing_gadget<FieldT> > packers;
|
|
|
vector<ec_constant_scalarmul_vec_gadget<FieldT> > constmuls;
|
|
|
vector<ec_scalarmul_vec_gadget<FieldT> > muls;
|
|
@@ -35,7 +36,7 @@ public:
|
|
|
const pb_variable<FieldT> C1x, C1y, C2x, C2y, Kx, Ky;
|
|
|
const pb_variable<FieldT> Px, Py;
|
|
|
const pb_variable_array<FieldT> Ptable;
|
|
|
- const pb_variable<FieldT> k, s, y;
|
|
|
+ const pb_variable<FieldT> k;
|
|
|
|
|
|
verified_encryption_gadget(protoboard<FieldT> &pb,
|
|
|
Mode mode,
|
|
@@ -48,9 +49,7 @@ public:
|
|
|
const pb_variable<FieldT> &Px,
|
|
|
const pb_variable<FieldT> &Py,
|
|
|
const pb_variable_array<FieldT> &Ptable,
|
|
|
- const pb_variable<FieldT> &k,
|
|
|
- const pb_variable<FieldT> &s,
|
|
|
- const pb_variable<FieldT> &y) :
|
|
|
+ const pb_variable<FieldT> &k) :
|
|
|
gadget<FieldT>(pb, "verified_encryption_gadget"),
|
|
|
// Curve parameters and generators
|
|
|
numbits(FieldT::num_bits),
|
|
@@ -58,9 +57,10 @@ public:
|
|
|
Gx(0), Gy("11977228949870389393715360594190192321220966033310912010610740966317727761886"),
|
|
|
Hx(1), Hy("21803877843449984883423225223478944275188924769286999517937427649571474907279"),
|
|
|
mode(mode), C1x(C1x), C1y(C1y), C2x(C2x), C2y(C2y),
|
|
|
- Kx(Kx), Ky(Ky), Px(Px), Py(Py), Ptable(Ptable),
|
|
|
- k(k), s(s), y(y)
|
|
|
+ Kx(Kx), Ky(Ky), Px(Px), Py(Py), Ptable(Ptable), k(k)
|
|
|
{
|
|
|
+ s.allocate(pb, "s");
|
|
|
+ y.allocate(pb, "y");
|
|
|
r.allocate(pb, "r");
|
|
|
xsquared.allocate(pb, "xsquared");
|
|
|
ysquared.allocate(pb, "ysquared");
|
|
@@ -115,8 +115,73 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ void find_s_y(const FieldT &kval, FieldT &sval, FieldT &yval)
|
|
|
+ {
|
|
|
+ // A modification of the Tonelli-Shanks implementation from libff
|
|
|
+ // to catch the case when you encounter a nonresidue
|
|
|
+
|
|
|
+ const FieldT one = FieldT::one();
|
|
|
+
|
|
|
+ size_t v = FieldT::s;
|
|
|
+ FieldT z = FieldT::nqr_to_t;
|
|
|
+
|
|
|
+ FieldT s_candidate = 0;
|
|
|
+ bool found = false;
|
|
|
+ while (!found) {
|
|
|
+ FieldT x_candidate = kval*256+s_candidate;
|
|
|
+ FieldT ysq_candidate = (x_candidate.squared() - 3)*x_candidate + curve_b;
|
|
|
+
|
|
|
+ FieldT w = ysq_candidate^FieldT::t_minus_1_over_2;
|
|
|
+ FieldT x = ysq_candidate * w;
|
|
|
+ FieldT b = x * w; // b = ysq_candidate^t
|
|
|
+
|
|
|
+ bool nonresidue = false;
|
|
|
+ while (b != one && !nonresidue)
|
|
|
+ {
|
|
|
+ size_t m = 0;
|
|
|
+ FieldT b2m = b;
|
|
|
+ while (b2m != one)
|
|
|
+ {
|
|
|
+ /* invariant: b2m = b^(2^m) after entering this loop */
|
|
|
+ b2m = b2m.squared();
|
|
|
+ m += 1;
|
|
|
+ }
|
|
|
+ if (m == v) {
|
|
|
+ // Not a quadratic residue
|
|
|
+ s_candidate += 1;
|
|
|
+ nonresidue = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ int j = v-m-1;
|
|
|
+ w = z;
|
|
|
+ while (j > 0)
|
|
|
+ {
|
|
|
+ w = w.squared();
|
|
|
+ --j;
|
|
|
+ } // w = z^2^(v-m-1)
|
|
|
+
|
|
|
+ z = w.squared();
|
|
|
+ b = b * z;
|
|
|
+ x = x * w;
|
|
|
+ v = m;
|
|
|
+ }
|
|
|
+ if (!nonresidue) {
|
|
|
+ found = true;
|
|
|
+ yval = x;
|
|
|
+ sval = s_candidate;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
+ // Find an s and y such that x^3 - 3*x + b = y^2, where x = 256*k + s
|
|
|
+ FieldT sval, yval;
|
|
|
+ find_s_y(this->pb.val(k), sval, yval);
|
|
|
+ this->pb.val(s) = sval;
|
|
|
+ this->pb.val(y) = yval;
|
|
|
+
|
|
|
this->pb.val(r) = FieldT::random_element();
|
|
|
this->pb.val(xsquared) = (this->pb.val(k) * 256 + this->pb.val(s)).squared();
|
|
|
this->pb.val(ysquared) = this->pb.val(y).squared();
|
|
@@ -184,7 +249,7 @@ int main(int argc, char **argv)
|
|
|
pb_variable<FieldT> Kx[numverifencs], Ky[numverifencs];
|
|
|
pb_variable<FieldT> Px[numverifencs], Py[numverifencs];
|
|
|
pb_variable_array<FieldT> Ptable[numverifencs];
|
|
|
- pb_variable<FieldT> k[numverifencs], s[numverifencs], y[numverifencs];
|
|
|
+ pb_variable<FieldT> k[numverifencs];
|
|
|
|
|
|
const size_t numbits = FieldT::num_bits;
|
|
|
|
|
@@ -225,9 +290,6 @@ int main(int argc, char **argv)
|
|
|
// Private inputs:
|
|
|
// k is a 246-bit random number
|
|
|
k[i].allocate(pb, "k");
|
|
|
- // s and y are such that M = (256*k+s,y) is a point on the curve
|
|
|
- s[i].allocate(pb, "s");
|
|
|
- y[i].allocate(pb, "y");
|
|
|
}
|
|
|
|
|
|
// This sets up the protoboard variables so that the first n of them
|
|
@@ -245,7 +307,7 @@ int main(int argc, char **argv)
|
|
|
vector<verified_encryption_gadget<FieldT> > vencs;
|
|
|
|
|
|
for (size_t i = 0; i < numverifencs; ++i) {
|
|
|
- vencs.emplace_back(pb, mode, C1x[i], C1y[i], C2x[i], C2y[i], Kx[i], Ky[i], Px[i], Py[i], Ptable[i], k[i], s[i], y[i]);
|
|
|
+ vencs.emplace_back(pb, mode, C1x[i], C1y[i], C2x[i], C2y[i], Kx[i], Ky[i], Px[i], Py[i], Ptable[i], k[i]);
|
|
|
}
|
|
|
for (auto&& gadget : vencs) {
|
|
|
gadget.generate_r1cs_constraints();
|
|
@@ -266,22 +328,40 @@ int main(int argc, char **argv)
|
|
|
pb.val(Py[i]) = FieldT("9185463202887631101218413269806857706246311016297504828581985913021301344974");
|
|
|
}
|
|
|
}
|
|
|
+ gmp_randstate_t randstate;
|
|
|
+ gmp_randinit_default(randstate);
|
|
|
+ FieldT seed = FieldT::random_element();
|
|
|
+ mpz_t seed_mpz;
|
|
|
+ mpz_init(seed_mpz);
|
|
|
+ seed.mont_repr.to_mpz(seed_mpz);
|
|
|
+ gmp_randseed(randstate, seed_mpz);
|
|
|
+ mpz_clear(seed_mpz);
|
|
|
for (size_t i = 0; i < numverifencs; ++i) {
|
|
|
- pb.val(k[i]) = FieldT("31329510635628557928212225120518124937732397714111203844965919301557399521");
|
|
|
- pb.val(s[i]) = FieldT(1);
|
|
|
- pb.val(y[i]) = FieldT("4364798287654239504994818950156019747851405522689486598132350453516910863367");
|
|
|
+ mpz_t kval;
|
|
|
+ mpz_init(kval);
|
|
|
+ mpz_urandomb(kval, randstate, 246);
|
|
|
+ pb.val(k[i]) = FieldT(kval);
|
|
|
+ mpz_clear(kval);
|
|
|
}
|
|
|
|
|
|
+ libff::enter_block("PROVER TIME");
|
|
|
+
|
|
|
for (auto&& gadget : vencs) {
|
|
|
gadget.generate_r1cs_witness();
|
|
|
}
|
|
|
|
|
|
const r1cs_gg_ppzksnark_proof<default_r1cs_gg_ppzksnark_pp> proof = r1cs_gg_ppzksnark_prover<default_r1cs_gg_ppzksnark_pp>(keypair.pk, pb.primary_input(), pb.auxiliary_input());
|
|
|
|
|
|
+ libff::leave_block("PROVER TIME");
|
|
|
+
|
|
|
cout << "Verifier" << endl;
|
|
|
|
|
|
+ libff::enter_block("VERIFIER TIME");
|
|
|
+
|
|
|
bool verified = r1cs_gg_ppzksnark_verifier_strong_IC<default_r1cs_gg_ppzksnark_pp>(keypair.vk, pb.primary_input(), proof);
|
|
|
|
|
|
+ libff::leave_block("VERIFIER TIME");
|
|
|
+
|
|
|
cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl;
|
|
|
cout << "Primary (public) input length: " << pb.primary_input().size() << endl;
|
|
|
// cout << "Primary (public) input: " << pb.primary_input() << endl;
|