1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_MPC_GROTH16_POWERSOFTAU_UTILS_TCC__
6 #define __ZETH_MPC_GROTH16_POWERSOFTAU_UTILS_TCC__
8 #include "libzeth/core/utils.hpp"
9 #include "libzeth/mpc/groth16/powersoftau_utils.hpp"
11 #include <libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp>
12 #include <libff/algebra/fields/fp.hpp>
21 template<mp_size_t n, const libff::bigint<n> &modulus>
22 void to_montgomery_repr(libff::Fp_model<n, modulus> &m)
24 m.mul_reduce(libff::Fp_model<n, modulus>::Rsquared);
27 template<mp_size_t n, const libff::bigint<n> &modulus>
28 libff::Fp_model<n, modulus> from_montgomery_repr(libff::Fp_model<n, modulus> m)
30 libff::Fp_model<n, modulus> tmp;
31 tmp.mont_repr.data[0] = 1;
32 tmp.mul_reduce(m.mont_repr);
36 template<mp_size_t n, const libff::bigint<n> &modulus>
37 std::istream &read_powersoftau_fp(
38 std::istream &in, libff::Fp_model<n, modulus> &out)
40 const size_t data_size = sizeof(libff::bigint<n>);
41 char *bytes = (char *)&out;
42 in.read(bytes, data_size);
44 std::reverse(&bytes[0], &bytes[data_size]);
45 to_montgomery_repr(out);
50 template<mp_size_t n, const libff::bigint<n> &modulus>
51 void write_powersoftau_fp(
52 std::ostream &out, const libff::Fp_model<n, modulus> &fp)
54 libff::Fp_model<n, modulus> copy = from_montgomery_repr(fp);
55 std::reverse((char *)©, (char *)(© + 1));
56 out.write((const char *)©, sizeof(mp_limb_t) * n);
59 template<mp_size_t n, const libff::bigint<n> &modulus>
60 std::istream &read_powersoftau_fp2(
61 std::istream &in, libff::Fp2_model<n, modulus> &el)
63 // Fq2 data is packed into a single 512 bit integer as:
66 libff::bigint<2 * n> packed;
68 std::reverse((uint8_t *)&packed, (uint8_t *)((&packed) + 1));
70 libff::bigint<n + 1> c1;
74 el.coeffs[0].mont_repr.data, // remainder
81 for (size_t i = 0; i < n; ++i) {
82 el.coeffs[1].mont_repr.data[i] = c1.data[i];
85 to_montgomery_repr(el.coeffs[0]);
86 to_montgomery_repr(el.coeffs[1]);
91 template<mp_size_t n, const libff::bigint<n> &modulus>
92 void write_powersoftau_fp2(
93 std::ostream &out, const libff::Fp2_model<n, modulus> &fp2)
95 // Fq2 data is packed into a single 512 bit integer as:
98 libff::Fp_model<n, modulus> c0 = from_montgomery_repr(fp2.coeffs[0]);
99 libff::Fp_model<n, modulus> c1 = from_montgomery_repr(fp2.coeffs[1]);
101 libff::bigint<2 * n> packed;
103 for (size_t i = 0; i < n; ++i) {
104 packed.data[i] = c0.mont_repr.data[i];
107 for (size_t i = 0; i < n; ++i) {
108 mp_limb_t carryout = mpn_addmul_1(
109 &packed.data[i], modulus.data, n, c1.mont_repr.data[i]);
110 assert(packed.data[n + i] == 0);
111 carryout = mpn_add_1(
112 &packed.data[n + i], &packed.data[n + i], n - i, carryout);
113 assert(carryout == 0);
116 std::reverse((uint8_t *)&packed, (uint8_t *)((&packed) + 1));
117 out.write((const char *)&packed, sizeof(packed));
120 // Use the technique described in Section 3 of "A multi-party protocol
121 // for constructing the public parameters of the Pinocchio zk-SNARK"
122 // (https://eprint.iacr.org/2017/602.pdf)
123 // to efficiently evaluate Lagrange polynomials ${L_i(x)}_i$ for the
124 // $d=2^n$-roots of unity, given powers ${x^i}_i$ for $i=0..d-1$.
125 template<typename Fr, typename Gr>
126 static void compute_lagrange_from_powers(
127 std::vector<Gr> &powers, const Fr &omega_inv)
129 libfqfft::_basic_radix2_FFT<Fr, Gr>(powers, omega_inv);
130 const Fr n_inv = Fr(powers.size()).inverse();
131 for (auto &a : powers) {
136 // Given two sequences `as` and `bs` of group elements, compute
137 // a_accum = as[0] * r_0 + ... + as[n] * r_n
138 // b_accum = bs[0] * r_0 + ... + bs[n] * r_n
139 // for random scalars r_0 ... r_n.
140 template<typename ppT, typename G>
141 void random_linear_combination(
142 const std::vector<G> &as, const std::vector<G> &bs, G &a_accum, G &b_accum)
144 if (as.size() != bs.size()) {
145 throw std::invalid_argument(
146 "vector size mismatch (random_linear_comb)");
152 // Split across threads, each one accumulating into its own thread-local
153 // variable, and then (atomically) adding that to the global a1_accum and
154 // b1_accum values. These final sums are then used in the final pairing
157 #pragma omp parallel shared(a_accum, b_accum)
160 G a_thread_accum = G::zero();
161 G b_thread_accum = G::zero();
163 const size_t scalar_bits = libff::Fr<ppT>::num_bits;
164 const size_t window_size = libff::wnaf_opt_window_size<G>(scalar_bits);
165 std::vector<long> wnaf;
170 for (size_t i = 0; i < as.size(); ++i) {
171 const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
172 update_wnaf(wnaf, window_size, r.as_bigint());
173 G r_ai = fixed_window_wnaf_exp(window_size, as[i], wnaf);
174 G r_bi = fixed_window_wnaf_exp(window_size, bs[i], wnaf);
176 a_thread_accum = a_thread_accum + r_ai;
177 b_thread_accum = b_thread_accum + r_bi;
184 a_accum = a_accum + a_thread_accum;
185 b_accum = b_accum + b_thread_accum;
190 // Similar to random_linear_combination, but compute:
191 // a_accum = as[0] * r_0 + ... + as[n-1] * r_{n-1}
192 // b_accum = bs[1] * r_0 + ... + bs[n ] * r_{n-1}
193 // for checking consistent ratio of consecutive entries.
194 template<typename ppT, typename G>
195 void random_linear_combination_consecutive(
196 const std::vector<G> &as, G &a_accum, G &b_accum)
201 const size_t num_entries = as.size() - 1;
204 #pragma omp parallel shared(a_accum, b_accum)
207 G a_thread_accum = G::zero();
208 G b_thread_accum = G::zero();
210 const size_t scalar_bits = libff::Fr<ppT>::num_bits;
211 const size_t window_size = libff::wnaf_opt_window_size<G>(scalar_bits);
212 std::vector<long> wnaf;
217 for (size_t i = 0; i < num_entries; ++i) {
218 const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
219 update_wnaf(wnaf, window_size, r.as_bigint());
220 G r_ai = fixed_window_wnaf_exp(window_size, as[i], wnaf);
221 G r_bi = fixed_window_wnaf_exp(window_size, as[i + 1], wnaf);
223 a_thread_accum = a_thread_accum + r_ai;
224 b_thread_accum = b_thread_accum + r_bi;
231 a_accum = a_accum + a_thread_accum;
232 b_accum = b_accum + b_thread_accum;
239 // -----------------------------------------------------------------------------
241 // -----------------------------------------------------------------------------
243 template<typename ppT>
244 srs_powersoftau<ppT>::srs_powersoftau(
245 libff::G1_vector<ppT> &&tau_powers_g1,
246 libff::G2_vector<ppT> &&tau_powers_g2,
247 libff::G1_vector<ppT> &&alpha_tau_powers_g1,
248 libff::G1_vector<ppT> &&beta_tau_powers_g1,
249 const libff::G2<ppT> &beta_g2)
250 : tau_powers_g1(std::move(tau_powers_g1))
251 , tau_powers_g2(std::move(tau_powers_g2))
252 , alpha_tau_powers_g1(std::move(alpha_tau_powers_g1))
253 , beta_tau_powers_g1(std::move(beta_tau_powers_g1))
258 template<typename ppT> bool srs_powersoftau<ppT>::is_well_formed() const
260 return libzeth::container_is_well_formed(tau_powers_g1) &&
261 libzeth::container_is_well_formed(tau_powers_g2) &&
262 libzeth::container_is_well_formed(alpha_tau_powers_g1) &&
263 libzeth::container_is_well_formed(beta_tau_powers_g1) &&
264 beta_g2.is_well_formed();
267 // -----------------------------------------------------------------------------
268 // powersoftau_lagrange_evaluations
269 // -----------------------------------------------------------------------------
271 template<typename ppT>
272 srs_lagrange_evaluations<ppT>::srs_lagrange_evaluations(
274 std::vector<libff::G1<ppT>> &&lagrange_g1,
275 std::vector<libff::G2<ppT>> &&lagrange_g2,
276 std::vector<libff::G1<ppT>> &&alpha_lagrange_g1,
277 std::vector<libff::G1<ppT>> &&beta_lagrange_g1)
279 , lagrange_g1(std::move(lagrange_g1))
280 , lagrange_g2(std::move(lagrange_g2))
281 , alpha_lagrange_g1(std::move(alpha_lagrange_g1))
282 , beta_lagrange_g1(std::move(beta_lagrange_g1))
286 template<typename ppT>
287 bool srs_lagrange_evaluations<ppT>::is_well_formed() const
289 return container_is_well_formed(lagrange_g1) &&
290 container_is_well_formed(lagrange_g2) &&
291 container_is_well_formed(alpha_lagrange_g1) &&
292 container_is_well_formed(beta_lagrange_g1);
295 template<typename ppT>
296 void srs_lagrange_evaluations<ppT>::write(std::ostream &out) const
298 check_well_formed(*this, "powersoftau (write)");
300 out.write((const char *)°ree, sizeof(degree));
301 for (const libff::G1<ppT> &l_g1 : lagrange_g1) {
304 for (const libff::G2<ppT> &l_g2 : lagrange_g2) {
307 for (const libff::G1<ppT> &alpha_l_g1 : alpha_lagrange_g1) {
310 for (const libff::G1<ppT> &beta_l_g1 : beta_lagrange_g1) {
315 template<typename ppT>
316 srs_lagrange_evaluations<ppT> srs_lagrange_evaluations<ppT>::read(
320 in.read((char *)°ree, sizeof(degree));
322 std::vector<libff::G1<ppT>> lagrange_g1(degree);
323 std::vector<libff::G2<ppT>> lagrange_g2(degree);
324 std::vector<libff::G1<ppT>> alpha_lagrange_g1(degree);
325 std::vector<libff::G1<ppT>> beta_lagrange_g1(degree);
327 for (libff::G1<ppT> &l_g1 : lagrange_g1) {
330 for (libff::G2<ppT> &l_g2 : lagrange_g2) {
333 for (libff::G1<ppT> &alpha_l_g1 : alpha_lagrange_g1) {
336 for (libff::G1<ppT> &beta_l_g1 : beta_lagrange_g1) {
340 srs_lagrange_evaluations<ppT> lagrange(
342 std::move(lagrange_g1),
343 std::move(lagrange_g2),
344 std::move(alpha_lagrange_g1),
345 std::move(beta_lagrange_g1));
346 check_well_formed(lagrange, "lagrange (read)");
350 template<typename ppT>
351 srs_powersoftau<ppT> dummy_powersoftau_from_secrets(
352 const libff::Fr<ppT> &tau,
353 const libff::Fr<ppT> &alpha,
354 const libff::Fr<ppT> &beta,
357 libff::enter_block("dummy_phase1_from_secrets");
359 // Compute powers. Note zero-th power is included (alpha_g1 etc
360 // are provided in this way), so to support order N polynomials,
361 // N+1 entries are required.
362 const size_t num_tau_powers_g1 = 2 * n - 2 + 1;
363 libff::G1_vector<ppT> tau_powers_g1;
364 libff::G2_vector<ppT> tau_powers_g2;
365 libff::G1_vector<ppT> alpha_tau_powers_g1;
366 libff::G1_vector<ppT> beta_tau_powers_g1;
368 libff::enter_block("tau powers");
369 std::vector<libff::Fr<ppT>> tau_powers(num_tau_powers_g1);
370 tau_powers[0] = libff::Fr<ppT>::one();
371 for (size_t i = 1; i < num_tau_powers_g1; ++i) {
372 tau_powers[i] = tau * tau_powers[i - 1];
374 libff::leave_block("tau powers");
376 libff::enter_block("window tables");
377 const size_t window_size = libff::get_exp_window_size<libff::G1<ppT>>(n);
378 const size_t window_size_tau_g1 =
379 libff::get_exp_window_size<libff::G1<ppT>>(2 * n - 1);
381 libff::window_table<libff::G1<ppT>> tau_g1_table;
382 libff::window_table<libff::G2<ppT>> tau_g2_table;
383 libff::window_table<libff::G1<ppT>> alpha_tau_g1_table;
384 libff::window_table<libff::G1<ppT>> beta_tau_g1_table;
386 std::thread tau_g1_table_thread([&tau_g1_table, window_size_tau_g1]() {
387 tau_g1_table = libff::get_window_table(
388 libff::G1<ppT>::size_in_bits(),
390 libff::G1<ppT>::one());
393 std::thread tau_g2_table_thread([&tau_g2_table, window_size]() {
394 tau_g2_table = libff::get_window_table(
395 libff::G2<ppT>::size_in_bits(),
397 libff::G2<ppT>::one());
400 std::thread alpha_tau_g1_table_thread(
401 [&alpha_tau_g1_table, window_size, alpha]() {
402 alpha_tau_g1_table = libff::get_window_table(
403 libff::G1<ppT>::size_in_bits(),
405 alpha * libff::G1<ppT>::one());
408 std::thread beta_tau_g1_table_thread(
409 [&beta_tau_g1_table, window_size, beta]() {
410 beta_tau_g1_table = libff::get_window_table(
411 libff::G1<ppT>::size_in_bits(),
413 beta * libff::G1<ppT>::one());
416 tau_g1_table_thread.join();
417 tau_g2_table_thread.join();
418 alpha_tau_g1_table_thread.join();
419 beta_tau_g1_table_thread.join();
421 libff::leave_block("window tables");
423 libff::enter_block("tau_g1 powers");
424 tau_powers_g1 = libff::batch_exp(
425 libff::G1<ppT>::size_in_bits(),
429 libff::leave_block("tau_g1 powers");
431 libff::enter_block("tau_g2 powers");
432 tau_powers_g2 = libff::batch_exp(
433 libff::G2<ppT>::size_in_bits(),
438 libff::leave_block("tau_g2 powers");
440 libff::enter_block("alpha_tau_g1 powers");
441 alpha_tau_powers_g1 = libff::batch_exp(
442 libff::G1<ppT>::size_in_bits(),
447 libff::leave_block("alpha_tau_g1 powers");
449 libff::enter_block("beta_tau_g1 powers");
450 beta_tau_powers_g1 = libff::batch_exp(
451 libff::G1<ppT>::size_in_bits(),
456 libff::leave_block("beta_tau_g1 powers");
458 libff::leave_block("dummy_phase1_from_secrets");
459 return srs_powersoftau<ppT>(
460 std::move(tau_powers_g1),
461 std::move(tau_powers_g2),
462 std::move(alpha_tau_powers_g1),
463 std::move(beta_tau_powers_g1),
464 beta * libff::G2<ppT>::one());
467 template<typename ppT> srs_powersoftau<ppT> dummy_powersoftau(size_t n)
469 libff::Fr<ppT> tau = libff::Fr<ppT>::random_element();
470 libff::Fr<ppT> alpha = libff::Fr<ppT>::random_element();
471 libff::Fr<ppT> beta = libff::Fr<ppT>::random_element();
473 return dummy_powersoftau_from_secrets<ppT>(tau, alpha, beta, n);
476 template<typename ppT>
477 void read_powersoftau_fr(std::istream &in, libff::Fr<ppT> &out)
479 read_powersoftau_fp(in, out);
482 template<typename ppT>
483 void read_powersoftau_g1(std::istream &in, libff::G1<ppT> &out)
486 in.read((char *)&marker, 1);
491 out = libff::G1<ppT>::zero();
497 read_powersoftau_fp(in, x);
498 read_powersoftau_fp(in, y);
499 out = libff::G1<ppT>(x, y, libff::Fq<ppT>::one());
508 /// Structure of G2 varies between pairings, so difficult to implement
509 /// generically. A specialized version for alt_bn128_pp is provided for
510 /// compatibility with https://github.com/clearmatics/powersoftau.
512 void read_powersoftau_g2<libff::alt_bn128_pp>(
513 std::istream &, libff::alt_bn128_G2 &);
515 template<typename ppT>
516 void read_powersoftau_g2(std::istream &in, libff::G2<ppT> &out)
521 template<typename ppT>
522 void write_powersoftau_fr(std::ostream &out, const libff::Fr<ppT> &fr)
524 write_powersoftau_fp(out, fr);
527 template<typename ppT>
528 void write_powersoftau_g1(std::ostream &out, const libff::G1<ppT> &g1)
531 const uint8_t zero = 0;
532 out.write((const char *)&zero, 1);
536 libff::G1<ppT> copy(g1);
537 copy.to_affine_coordinates();
539 const uint8_t marker = 0x04;
540 out.write((const char *)&marker, 1);
541 write_powersoftau_fp(out, copy.X);
542 write_powersoftau_fp(out, copy.Y);
545 /// Structure of G2 varies between pairings, so difficult to implement
546 /// generically. A specialized version for alt_bn128_pp is provided for
547 /// compatibility with https://github.com/clearmatics/powersoftau.
549 void write_powersoftau_g2<libff::alt_bn128_pp>(
550 std::ostream &, const libff::alt_bn128_G2 &);
552 template<typename ppT>
553 void write_powersoftau_g2(std::ostream &out, const libff::G2<ppT> &g2)
558 template<typename ppT>
559 srs_powersoftau<ppT> powersoftau_load(std::istream &in, size_t n)
561 using G1 = libff::G1<ppT>;
562 using G2 = libff::G2<ppT>;
566 // https://github.com/clearmatics/powersoftau
568 // Assume the stream is the final challenge file from the
569 // powersoftau protocol. Load the Accumulator object.
571 // File is structured:
573 // [prev_resp_hash : uint8_t[64]]
574 // [accumulator : Accumulator]
578 // pub struct Accumulator {
579 // /// tau^0, tau^1, tau^2, ..., tau^{TAU_POWERS_G1_LENGTH - 1}
580 // pub tau_powers_g1: Vec<G1>,
581 // /// tau^0, tau^1, tau^2, ..., tau^{TAU_POWERS_LENGTH - 1}
582 // pub tau_powers_g2: Vec<G2>,
583 // /// alpha * tau^0, alpha * tau^1, alpha * tau^2, ..., alpha *
584 // tau^{TAU_POWERS_LENGTH - 1} pub alpha_tau_powers_g1: Vec<G1>,
585 // /// beta * tau^0, beta * tau^1, beta * tau^2, ..., beta *
586 // tau^{TAU_POWERS_LENGTH - 1} pub beta_tau_powers_g1: Vec<G1>,
591 in.read((char *)(&hash[0]), sizeof(hash));
593 const size_t num_powers_of_tau = 2 * n - 1;
595 std::vector<G1> tau_powers_g1(num_powers_of_tau);
596 for (size_t i = 0; i < num_powers_of_tau; ++i) {
597 read_powersoftau_g1<ppT>(in, tau_powers_g1[i]);
599 if (tau_powers_g1[0] != G1::one()) {
600 throw std::invalid_argument("invalid powersoftau file?");
603 std::vector<G2> tau_powers_g2(n);
604 for (size_t i = 0; i < n; ++i) {
605 read_powersoftau_g2<ppT>(in, tau_powers_g2[i]);
607 if (tau_powers_g2[0] != G2::one()) {
608 throw std::invalid_argument("invalid powersoftau file?");
611 std::vector<G1> alpha_tau_powers_g1(n);
612 for (size_t i = 0; i < n; ++i) {
613 read_powersoftau_g1<ppT>(in, alpha_tau_powers_g1[i]);
616 std::vector<G1> beta_tau_powers_g1(n);
617 for (size_t i = 0; i < n; ++i) {
618 read_powersoftau_g1<ppT>(in, beta_tau_powers_g1[i]);
622 read_powersoftau_g2<ppT>(in, beta_g2);
624 srs_powersoftau<ppT> pot(
625 std::move(tau_powers_g1),
626 std::move(tau_powers_g2),
627 std::move(alpha_tau_powers_g1),
628 std::move(beta_tau_powers_g1),
630 check_well_formed(pot, "powersoftau (load)");
634 template<typename ppT>
635 void powersoftau_write(std::ostream &out, const srs_powersoftau<ppT> &pot)
637 check_well_formed(pot, "powersoftau (write)");
641 memset(hash, 0, sizeof(hash));
642 out.write((char *)(&hash[0]), sizeof(hash));
644 const size_t n = pot.tau_powers_g2.size();
645 const size_t num_powers_of_tau = 2 * n - 1;
646 for (size_t i = 0; i < num_powers_of_tau; ++i) {
647 write_powersoftau_g1<ppT>(out, pot.tau_powers_g1[i]);
649 for (size_t i = 0; i < n; ++i) {
650 write_powersoftau_g2<ppT>(out, pot.tau_powers_g2[i]);
652 for (size_t i = 0; i < n; ++i) {
653 write_powersoftau_g1<ppT>(out, pot.alpha_tau_powers_g1[i]);
655 for (size_t i = 0; i < n; ++i) {
656 write_powersoftau_g1<ppT>(out, pot.beta_tau_powers_g1[i]);
658 write_powersoftau_g2<ppT>(out, pot.beta_g2);
661 template<typename ppT>
663 const libff::G1<ppT> &a1,
664 const libff::G1<ppT> &b1,
665 const libff::G2<ppT> &a2,
666 const libff::G2<ppT> &b2)
668 const libff::G1_precomp<ppT> &a1_precomp = ppT::precompute_G1(a1);
669 const libff::G1_precomp<ppT> &b1_precomp = ppT::precompute_G1(b1);
670 const libff::G2_precomp<ppT> &a2_precomp = ppT::precompute_G2(a2);
671 const libff::G2_precomp<ppT> &b2_precomp = ppT::precompute_G2(b2);
673 const libff::Fqk<ppT> a1b2 = ppT::miller_loop(a1_precomp, b2_precomp);
674 const libff::Fqk<ppT> b1a2 = ppT::miller_loop(b1_precomp, a2_precomp);
676 const libff::GT<ppT> a1b2_gt = ppT::final_exponentiation(a1b2);
677 const libff::GT<ppT> b1a2_gt = ppT::final_exponentiation(b1a2);
679 // Decide whether ratio a1:b1 in G1 equals a2:b2 in G2 by checking:
680 // e(a1, b2) =?= e(b1, a2)
681 return a1b2_gt == b1a2_gt;
684 template<typename ppT>
685 bool same_ratio_vectors(
686 const std::vector<libff::G1<ppT>> &a1s,
687 const std::vector<libff::G1<ppT>> &b1s,
688 const libff::G2<ppT> &a2,
689 const libff::G2<ppT> &b2)
691 using G1 = libff::G1<ppT>;
693 libff::enter_block("call to same_ratio_vectors (G1)");
694 if (a1s.size() != b1s.size()) {
695 throw std::invalid_argument("vector size mismatch in same_ratio_batch");
698 libff::enter_block("accumulating random combination");
701 random_linear_combination<ppT>(a1s, b1s, a1_accum, b1_accum);
702 libff::leave_block("accumulating random combination");
704 const bool same = same_ratio<ppT>(a1_accum, b1_accum, a2, b2);
705 libff::leave_block("call to same_ratio_vectors (G1)");
709 template<typename ppT>
710 bool same_ratio_vectors(
711 const libff::G1<ppT> &a1,
712 const libff::G1<ppT> &b1,
713 const std::vector<libff::G2<ppT>> &a2s,
714 const std::vector<libff::G2<ppT>> &b2s)
716 using G2 = libff::G2<ppT>;
718 libff::enter_block("call to same_ratio_vectors (G2)");
719 if (a2s.size() != b2s.size()) {
720 throw std::invalid_argument("vector size mismatch in same_ratio_batch");
723 libff::enter_block("accumulating random combination");
726 random_linear_combination<ppT>(a2s, b2s, a2_accum, b2_accum);
727 libff::leave_block("accumulating random combination");
729 const bool same = same_ratio<ppT>(a1, b1, a2_accum, b2_accum);
730 libff::leave_block("call to same_ratio_vectors (G2)");
734 template<typename ppT>
735 bool same_ratio_consecutive(
736 const std::vector<libff::G1<ppT>> &a1s,
737 const libff::G2<ppT> &a2,
738 const libff::G2<ppT> &b2)
740 using G1 = libff::G1<ppT>;
742 libff::enter_block("call to same_ratio_consecutive (G1)");
744 libff::enter_block("accumulating random combination");
747 random_linear_combination_consecutive<ppT>(a1s, a1_accum, b1_accum);
748 libff::leave_block("accumulating random combination");
750 const bool same = same_ratio<ppT>(a1_accum, b1_accum, a2, b2);
751 libff::leave_block("call to same_ratio_consecutive (G1)");
755 template<typename ppT>
756 bool same_ratio_consecutive(
757 const libff::G1<ppT> &a1,
758 const libff::G1<ppT> &b1,
759 const std::vector<libff::G2<ppT>> &a2s)
761 using G2 = libff::G2<ppT>;
763 libff::enter_block("call to same_ratio_consecutive (G2)");
765 libff::enter_block("accumulating random combination");
768 random_linear_combination_consecutive<ppT>(a2s, a2_accum, b2_accum);
769 libff::leave_block("accumulating random combination");
771 const bool same = same_ratio<ppT>(a1, b1, a2_accum, b2_accum);
772 libff::leave_block("call to same_ratio_consecutive (G2)");
776 template<typename ppT>
777 bool powersoftau_is_well_formed(const srs_powersoftau<ppT> &pot)
779 // TODO: Cache precomputed g1, tau_g1, g2, tau_g2
782 // Check sizes are valid. tau_powers_g1 should have 2n-1 elements, and
783 // other vectors should have n entries.
784 const size_t n = (pot.tau_powers_g1.size() + 1) / 2;
785 if (n != 1ull << libff::log2(n) || n != pot.tau_powers_g2.size() ||
786 n != pot.alpha_tau_powers_g1.size() ||
787 n != pot.beta_tau_powers_g1.size()) {
791 // Make sure that the identity of each group is at index 0
792 if (pot.tau_powers_g1[0] != libff::G1<ppT>::one() ||
793 pot.tau_powers_g2[0] != libff::G2<ppT>::one()) {
797 const libff::G1<ppT> g1 = libff::G1<ppT>::one();
798 const libff::G2<ppT> g2 = libff::G2<ppT>::one();
799 const libff::G1<ppT> tau_g1 = pot.tau_powers_g1[1];
800 const libff::G2<ppT> tau_g2 = pot.tau_powers_g2[1];
802 // SameRatio((g1, tau_g1), (g2, tau_g2))
803 const bool tau_g1_g2_consistent =
804 same_ratio<ppT>(g1, pot.tau_powers_g1[1], g2, pot.tau_powers_g2[1]);
805 if (!tau_g1_g2_consistent) {
809 // SameRatio((tau_powers_g1[i-1], tau_powers_g1[i]), (g2, tau_g2))
810 // SameRatio((tau_powers_g2[i-1], tau_powers_g2[i]), (g1, tau_g1))
812 // (alpha_tau_powers_g1[i-1], alpha_tau_powers_g1[i]), (g2, tau_g2))
814 // (beta_tau_powers_g1[i-1], beta_tau_powers_g1[i]), (g2, tau_g2))
815 if (!same_ratio_consecutive<ppT>(pot.tau_powers_g1, g2, tau_g2) ||
816 !same_ratio_consecutive<ppT>(g1, tau_g1, pot.tau_powers_g2) ||
817 !same_ratio_consecutive<ppT>(pot.alpha_tau_powers_g1, g2, tau_g2) ||
818 !same_ratio_consecutive<ppT>(pot.beta_tau_powers_g1, g2, tau_g2)) {
822 // SameRatio((g1, beta_tau_powers_g1), (g2, beta_g2))
823 if (!same_ratio<ppT>(g1, pot.beta_tau_powers_g1[0], g2, pot.beta_g2)) {
830 template<typename ppT>
831 srs_lagrange_evaluations<ppT> powersoftau_compute_lagrange_evaluations(
832 const srs_powersoftau<ppT> &pot, const size_t n)
834 using Fr = libff::Fr<ppT>;
835 using G1 = libff::G1<ppT>;
836 using G2 = libff::G2<ppT>;
838 if (n != 1ull << libff::log2(n)) {
839 throw std::invalid_argument("non-pow-2 domain");
841 if (pot.tau_powers_g1.size() < n) {
842 throw std::invalid_argument("insufficient powers of tau");
845 libff::enter_block("r1cs_gg_ppzksnark_compute_lagrange_evaluations");
846 libff::print_indent();
847 printf("n=%zu\n", n);
849 libfqfft::basic_radix2_domain<Fr> domain(n);
850 const Fr omega = domain.get_domain_element(1);
851 const Fr omega_inv = omega.inverse();
853 // Compute [ L_j(t) ]_1 from { [x^i] } i=0..n-1
854 libff::enter_block("computing [Lagrange_i(x)]_1");
855 std::vector<G1> lagrange_g1(
856 pot.tau_powers_g1.begin(), pot.tau_powers_g1.begin() + n);
857 if (lagrange_g1[0] != G1::one() || lagrange_g1.size() != n) {
858 throw std::invalid_argument("unexpected powersoftau data (g1). Invalid "
859 "file or degree mismatch");
861 compute_lagrange_from_powers(lagrange_g1, omega_inv);
862 libff::leave_block("computing [Lagrange_i(x)]_1");
864 libff::enter_block("computing [Lagrange_i(x)]_2");
865 std::vector<G2> lagrange_g2(
866 pot.tau_powers_g2.begin(), pot.tau_powers_g2.begin() + n);
867 if (lagrange_g2[0] != G2::one() || lagrange_g2.size() != n) {
868 throw std::invalid_argument("unexpected powersoftau data (g2). invalid "
869 "file or degree mismatch");
871 compute_lagrange_from_powers(lagrange_g2, omega_inv);
872 libff::leave_block("computing [Lagrange_i(x)]_2");
874 libff::enter_block("computing [alpha . Lagrange_i(x)]_1");
875 std::vector<G1> alpha_lagrange_g1(
876 pot.alpha_tau_powers_g1.begin(), pot.alpha_tau_powers_g1.begin() + n);
877 if (alpha_lagrange_g1.size() != n) {
878 throw std::invalid_argument("unexpected powersoftau data (alpha). "
879 "invalid file or degree mismatch");
881 compute_lagrange_from_powers(alpha_lagrange_g1, omega_inv);
882 libff::leave_block("computing [alpha . Lagrange_i(x)]_1");
884 libff::enter_block("computing [beta . Lagrange_i(x)]_1");
885 std::vector<G1> beta_lagrange_g1(
886 pot.beta_tau_powers_g1.begin(), pot.beta_tau_powers_g1.begin() + n);
887 if (beta_lagrange_g1.size() != n) {
888 throw std::invalid_argument("unexpected powersoftau data (alpha). "
889 "invalid file or degree mismatch");
891 compute_lagrange_from_powers(beta_lagrange_g1, omega_inv);
892 libff::leave_block("computing [beta . Lagrange_i(x)]_1");
894 libff::leave_block("r1cs_gg_ppzksnark_compute_lagrange_evaluations");
896 return srs_lagrange_evaluations<ppT>(
898 std::move(lagrange_g1),
899 std::move(lagrange_g2),
900 std::move(alpha_lagrange_g1),
901 std::move(beta_lagrange_g1));
904 } // namespace libzeth
906 #endif // __ZETH_MPC_GROTH16_POWERSOFTAU_UTILS_TCC__