2 *****************************************************************************
 
    4 Implementation of interfaces for a ppzkSNARK for R1CS.
 
    6 See r1cs_gg_ppzksnark.hpp .
 
    8 *****************************************************************************
 
    9 * @author     This file is part of libsnark, developed by SCIPR Lab
 
   10 *             and contributors (see AUTHORS).
 
   11 * @copyright  MIT license (see LICENSE file)
 
   12 *****************************************************************************/
 
   14 #ifndef R1CS_GG_PPZKSNARK_TCC_
 
   15 #define R1CS_GG_PPZKSNARK_TCC_
 
   21 #include <libff/algebra/scalar_multiplication/multiexp.hpp>
 
   22 #include <libff/common/profiling.hpp>
 
   23 #include <libff/common/utils.hpp>
 
   30 #include <libsnark/knowledge_commitment/kc_multiexp.hpp>
 
   31 #include <libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp>
 
   36 template<typename ppT>
 
   37 bool r1cs_gg_ppzksnark_proving_key<ppT>::operator==(
 
   38     const r1cs_gg_ppzksnark_proving_key<ppT> &other) const
 
   41         this->alpha_g1 == other.alpha_g1 && this->beta_g1 == other.beta_g1 &&
 
   42         this->beta_g2 == other.beta_g2 && this->delta_g1 == other.delta_g1 &&
 
   43         this->delta_g2 == other.delta_g2 && this->A_query == other.A_query &&
 
   44         this->B_query == other.B_query && this->H_query == other.H_query &&
 
   45         this->L_query == other.L_query &&
 
   46         this->constraint_system == other.constraint_system);
 
   49 template<typename ppT>
 
   50 std::ostream &operator<<(
 
   51     std::ostream &out, const r1cs_gg_ppzksnark_proving_key<ppT> &pk)
 
   53     out << pk.alpha_g1 << OUTPUT_NEWLINE;
 
   54     out << pk.beta_g1 << OUTPUT_NEWLINE;
 
   55     out << pk.beta_g2 << OUTPUT_NEWLINE;
 
   56     out << pk.delta_g1 << OUTPUT_NEWLINE;
 
   57     out << pk.delta_g2 << OUTPUT_NEWLINE;
 
   62     out << pk.constraint_system;
 
   67 template<typename ppT>
 
   68 std::istream &operator>>(
 
   69     std::istream &in, r1cs_gg_ppzksnark_proving_key<ppT> &pk)
 
   72     libff::consume_OUTPUT_NEWLINE(in);
 
   74     libff::consume_OUTPUT_NEWLINE(in);
 
   76     libff::consume_OUTPUT_NEWLINE(in);
 
   78     libff::consume_OUTPUT_NEWLINE(in);
 
   80     libff::consume_OUTPUT_NEWLINE(in);
 
   85     in >> pk.constraint_system;
 
   90 template<typename ppT>
 
   91 bool r1cs_gg_ppzksnark_verification_key<ppT>::operator==(
 
   92     const r1cs_gg_ppzksnark_verification_key<ppT> &other) const
 
   95         this->alpha_g1 == other.alpha_g1 && this->beta_g2 == other.beta_g2 &&
 
   96         this->delta_g2 == other.delta_g2 && this->ABC_g1 == other.ABC_g1);
 
   99 template<typename ppT>
 
  100 std::ostream &operator<<(
 
  101     std::ostream &out, const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
 
  103     out << vk.alpha_g1 << OUTPUT_NEWLINE;
 
  104     out << vk.beta_g2 << OUTPUT_NEWLINE;
 
  105     out << vk.delta_g2 << OUTPUT_NEWLINE;
 
  106     out << vk.ABC_g1 << OUTPUT_NEWLINE;
 
  111 template<typename ppT>
 
  112 std::istream &operator>>(
 
  113     std::istream &in, r1cs_gg_ppzksnark_verification_key<ppT> &vk)
 
  116     libff::consume_OUTPUT_NEWLINE(in);
 
  118     libff::consume_OUTPUT_NEWLINE(in);
 
  120     libff::consume_OUTPUT_NEWLINE(in);
 
  122     libff::consume_OUTPUT_NEWLINE(in);
 
  127 template<typename ppT>
 
  128 bool r1cs_gg_ppzksnark_processed_verification_key<ppT>::operator==(
 
  129     const r1cs_gg_ppzksnark_processed_verification_key<ppT> &other) const
 
  132         this->vk_alpha_g1_precomp == other.vk_alpha_g1_precomp &&
 
  133         this->vk_beta_g2_precomp == other.vk_beta_g2_precomp &&
 
  134         this->vk_generator_g2_precomp == other.vk_generator_g2_precomp &&
 
  135         this->vk_delta_g2_precomp == other.vk_delta_g2_precomp &&
 
  136         this->ABC_g1 == other.ABC_g1);
 
  139 template<typename ppT>
 
  140 std::ostream &operator<<(
 
  142     const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
 
  144     out << pvk.vk_alpha_g1_precomp << OUTPUT_NEWLINE;
 
  145     out << pvk.vk_beta_g2_precomp << OUTPUT_NEWLINE;
 
  146     out << pvk.vk_generator_g2_precomp << OUTPUT_NEWLINE;
 
  147     out << pvk.vk_delta_g2_precomp << OUTPUT_NEWLINE;
 
  148     out << pvk.ABC_g1 << OUTPUT_NEWLINE;
 
  153 template<typename ppT>
 
  154 std::istream &operator>>(
 
  155     std::istream &in, r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk)
 
  157     in >> pvk.vk_alpha_g1_precomp;
 
  158     libff::consume_OUTPUT_NEWLINE(in);
 
  159     in >> pvk.vk_beta_g2_precomp;
 
  160     libff::consume_OUTPUT_NEWLINE(in);
 
  161     in >> pvk.vk_generator_g2_precomp;
 
  162     libff::consume_OUTPUT_NEWLINE(in);
 
  163     in >> pvk.vk_delta_g2_precomp;
 
  164     libff::consume_OUTPUT_NEWLINE(in);
 
  166     libff::consume_OUTPUT_NEWLINE(in);
 
  171 template<typename ppT>
 
  172 bool r1cs_gg_ppzksnark_proof<ppT>::operator==(
 
  173     const r1cs_gg_ppzksnark_proof<ppT> &other) const
 
  176         this->g_A == other.g_A && this->g_B == other.g_B &&
 
  177         this->g_C == other.g_C);
 
  180 template<typename ppT>
 
  181 std::ostream &operator<<(
 
  182     std::ostream &out, const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  184     out << proof.g_A << OUTPUT_NEWLINE;
 
  185     out << proof.g_B << OUTPUT_NEWLINE;
 
  186     out << proof.g_C << OUTPUT_NEWLINE;
 
  191 template<typename ppT>
 
  192 std::istream &operator>>(std::istream &in, r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  195     libff::consume_OUTPUT_NEWLINE(in);
 
  197     libff::consume_OUTPUT_NEWLINE(in);
 
  199     libff::consume_OUTPUT_NEWLINE(in);
 
  204 template<typename ppT>
 
  205 r1cs_gg_ppzksnark_verification_key<ppT> r1cs_gg_ppzksnark_verification_key<
 
  206     ppT>::dummy_verification_key(const size_t input_size)
 
  208     r1cs_gg_ppzksnark_verification_key<ppT> result;
 
  209     result.alpha_g1 = libff::G1<ppT>::random_element();
 
  210     result.beta_g2 = libff::G2<ppT>::random_element();
 
  211     result.delta_g2 = libff::G2<ppT>::random_element();
 
  213     libff::G1<ppT> base = libff::G1<ppT>::random_element();
 
  214     libff::G1_vector<ppT> v;
 
  215     for (size_t i = 0; i < input_size; ++i) {
 
  216         v.emplace_back(libff::G1<ppT>::random_element());
 
  220         accumulation_vector<libff::G1<ppT>>(std::move(base), std::move(v));
 
  225 template<typename ppT, libff::multi_exp_base_form BaseForm>
 
  226 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator_from_secrets(
 
  227     const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
 
  228     const libff::Fr<ppT> &t,
 
  229     const libff::Fr<ppT> &alpha,
 
  230     const libff::Fr<ppT> &beta,
 
  231     const libff::Fr<ppT> &delta,
 
  232     const libff::G1<ppT> &g1_generator,
 
  233     const libff::G2<ppT> &g2_generator,
 
  234     bool force_pow_2_domain)
 
  236     libff::enter_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
 
  238     /* Make the B_query "lighter" if possible */
 
  239     r1cs_gg_ppzksnark_constraint_system<ppT> r1cs_copy(r1cs);
 
  240     r1cs_copy.swap_AB_if_beneficial();
 
  242     const libff::Fr<ppT> delta_inverse = delta.inverse();
 
  244     /* A quadratic arithmetic program evaluated at t. */
 
  245     qap_instance_evaluation<libff::Fr<ppT>> qap =
 
  246         r1cs_to_qap_instance_map_with_evaluation(
 
  247             r1cs_copy, t, force_pow_2_domain);
 
  249     libff::print_indent();
 
  250     printf("* QAP number of variables: %zu\n", qap.num_variables());
 
  251     libff::print_indent();
 
  252     printf("* QAP pre degree: %zu\n", r1cs_copy.constraints.size());
 
  253     libff::print_indent();
 
  254     printf("* QAP degree: %zu\n", qap.degree());
 
  255     libff::print_indent();
 
  256     printf("* QAP number of input variables: %zu\n", qap.num_inputs());
 
  258     libff::enter_block("Compute query densities");
 
  259     size_t non_zero_At = 0;
 
  260     size_t non_zero_Bt = 0;
 
  261     for (size_t i = 0; i < qap.num_variables() + 1; ++i) {
 
  262         if (!qap.At[i].is_zero()) {
 
  265         if (!qap.Bt[i].is_zero()) {
 
  269     libff::leave_block("Compute query densities");
 
  271     /* qap.{At,Bt,Ct,Ht} are now in unspecified state, but we do not use them
 
  273     libff::Fr_vector<ppT> At = std::move(qap.At);
 
  274     libff::Fr_vector<ppT> Bt = std::move(qap.Bt);
 
  275     libff::Fr_vector<ppT> Ct = std::move(qap.Ct);
 
  276     libff::Fr_vector<ppT> Ht = std::move(qap.Ht);
 
  278     /* The product component: (beta*A_i(t) + alpha*B_i(t) + C_i(t)). */
 
  279     libff::enter_block("Compute ABC for R1CS verification key");
 
  280     libff::Fr_vector<ppT> ABC;
 
  281     ABC.reserve(qap.num_inputs());
 
  283     const libff::Fr<ppT> ABC_0 = beta * At[0] + alpha * Bt[0] + Ct[0];
 
  284     for (size_t i = 1; i < qap.num_inputs() + 1; ++i) {
 
  285         ABC.emplace_back(beta * At[i] + alpha * Bt[i] + Ct[i]);
 
  287     libff::leave_block("Compute ABC for R1CS verification key");
 
  289     /* The delta inverse product component: (beta*A_i(t) + alpha*B_i(t) +
 
  290      * C_i(t)) * delta^{-1}. */
 
  291     libff::enter_block("Compute L query for R1CS proving key");
 
  292     libff::Fr_vector<ppT> Lt;
 
  293     Lt.reserve(qap.num_variables() - qap.num_inputs());
 
  295     const size_t Lt_offset = qap.num_inputs() + 1;
 
  296     for (size_t i = Lt_offset; i < qap.num_variables() + 1; ++i) {
 
  297         Lt.emplace_back((beta * At[i] + alpha * Bt[i] + Ct[i]) * delta_inverse);
 
  299     libff::leave_block("Compute L query for R1CS proving key");
 
  302      * Note that H for Groth's proof system is degree d-2, but the QAP
 
  303      * reduction returns coefficients for degree d polynomial H (in
 
  304      * style of PGHR-type proof systems)
 
  306     Ht.resize(Ht.size() - 2);
 
  309     const size_t chunks =
 
  310         omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
 
  311                                // call omp_set_num_threads()
 
  313     const size_t chunks = 1;
 
  316     libff::enter_block("Generating G1 MSM window table");
 
  317     const size_t g1_scalar_count =
 
  318         non_zero_At + non_zero_Bt + qap.num_variables();
 
  319     const size_t g1_scalar_size = libff::Fr<ppT>::size_in_bits();
 
  320     const size_t g1_window_size =
 
  321         libff::get_exp_window_size<libff::G1<ppT>>(g1_scalar_count);
 
  323     libff::print_indent();
 
  324     printf("* G1 window: %zu\n", g1_window_size);
 
  325     libff::window_table<libff::G1<ppT>> g1_table =
 
  326         libff::get_window_table(g1_scalar_size, g1_window_size, g1_generator);
 
  327     libff::leave_block("Generating G1 MSM window table");
 
  329     libff::enter_block("Generating G2 MSM window table");
 
  330     const size_t g2_scalar_count = non_zero_Bt;
 
  331     const size_t g2_scalar_size = libff::Fr<ppT>::size_in_bits();
 
  332     size_t g2_window_size =
 
  333         libff::get_exp_window_size<libff::G2<ppT>>(g2_scalar_count);
 
  335     libff::print_indent();
 
  336     printf("* G2 window: %zu\n", g2_window_size);
 
  337     libff::window_table<libff::G2<ppT>> g2_table =
 
  338         libff::get_window_table(g2_scalar_size, g2_window_size, g2_generator);
 
  339     libff::leave_block("Generating G2 MSM window table");
 
  341     libff::enter_block("Generate R1CS proving key");
 
  342     libff::G1<ppT> alpha_g1 = alpha * g1_generator;
 
  343     libff::G1<ppT> beta_g1 = beta * g1_generator;
 
  344     libff::G2<ppT> beta_g2 = beta * g2_generator;
 
  345     libff::G1<ppT> delta_g1 = delta * g1_generator;
 
  346     libff::G2<ppT> delta_g2 = delta * g2_generator;
 
  348     libff::enter_block("Generate queries");
 
  349     libff::enter_block("Compute the A-query", false);
 
  350     libff::G1_vector<ppT> A_query =
 
  351         batch_exp(g1_scalar_size, g1_window_size, g1_table, At);
 
  352     if (BaseForm == libff::multi_exp_base_form_special) {
 
  353         libff::batch_to_special<libff::G1<ppT>>(A_query);
 
  355     libff::leave_block("Compute the A-query", false);
 
  357     libff::enter_block("Compute the B-query", false);
 
  358     // Force kc_batch_exp to convert to special form, if BaseForm ==
 
  359     // libff::multi_exp_base_form_special.
 
  360     knowledge_commitment_vector<libff::G2<ppT>, libff::G1<ppT>> B_query =
 
  362             libff::Fr<ppT>::size_in_bits(),
 
  367             libff::Fr<ppT>::one(),
 
  368             libff::Fr<ppT>::one(),
 
  371             BaseForm == libff::multi_exp_base_form_special);
 
  372     libff::leave_block("Compute the B-query", false);
 
  374     libff::enter_block("Compute the H-query", false);
 
  375     libff::G1_vector<ppT> H_query = batch_exp_with_coeff(
 
  376         g1_scalar_size, g1_window_size, g1_table, qap.Zt * delta_inverse, Ht);
 
  377     if (BaseForm == libff::multi_exp_base_form_special) {
 
  378         libff::batch_to_special<libff::G1<ppT>>(H_query);
 
  380     libff::leave_block("Compute the H-query", false);
 
  382     libff::enter_block("Compute the L-query", false);
 
  383     libff::G1_vector<ppT> L_query =
 
  384         batch_exp(g1_scalar_size, g1_window_size, g1_table, Lt);
 
  385     if (BaseForm == libff::multi_exp_base_form_special) {
 
  386         libff::batch_to_special<libff::G1<ppT>>(L_query);
 
  388     libff::leave_block("Compute the L-query", false);
 
  389     libff::leave_block("Generate queries");
 
  391     libff::leave_block("Generate R1CS proving key");
 
  393     libff::enter_block("Generate R1CS verification key");
 
  395     libff::enter_block("Encode ABC for R1CS verification key");
 
  396     libff::G1<ppT> ABC_g1_0 = ABC_0 * g1_generator;
 
  397     libff::G1_vector<ppT> ABC_g1_values =
 
  398         batch_exp(g1_scalar_size, g1_window_size, g1_table, ABC);
 
  399     libff::leave_block("Encode ABC for R1CS verification key");
 
  400     libff::leave_block("Generate R1CS verification key");
 
  402     libff::leave_block("Call to r1cs_gg_ppzksnark_generator_from_secrets");
 
  404     accumulation_vector<libff::G1<ppT>> ABC_g1(
 
  405         std::move(ABC_g1_0), std::move(ABC_g1_values));
 
  407     r1cs_gg_ppzksnark_verification_key<ppT> vk =
 
  408         r1cs_gg_ppzksnark_verification_key<ppT>(
 
  409             alpha_g1, beta_g2, delta_g2, ABC_g1);
 
  411     r1cs_gg_ppzksnark_proving_key<ppT> pk = r1cs_gg_ppzksnark_proving_key<ppT>(
 
  421         std::move(r1cs_copy));
 
  426     return r1cs_gg_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
 
  429 template<typename ppT, libff::multi_exp_base_form BaseForm>
 
  430 r1cs_gg_ppzksnark_keypair<ppT> r1cs_gg_ppzksnark_generator(
 
  431     const r1cs_gg_ppzksnark_constraint_system<ppT> &r1cs,
 
  432     bool force_pow_2_domain)
 
  434     libff::enter_block("Call to r1cs_gg_ppzksnark_generator");
 
  436     /* Generate secret randomness */
 
  437     const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
 
  438     const libff::Fr<ppT> alpha = libff::Fr<ppT>::random_element();
 
  439     const libff::Fr<ppT> beta = libff::Fr<ppT>::random_element();
 
  440     const libff::Fr<ppT> delta = libff::Fr<ppT>::random_element();
 
  441     const libff::G1<ppT> g1_generator = libff::G1<ppT>::one();
 
  442     const libff::G2<ppT> g2_generator = libff::G2<ppT>::one();
 
  444     r1cs_gg_ppzksnark_keypair<ppT> key_pair =
 
  445         r1cs_gg_ppzksnark_generator_from_secrets<ppT, BaseForm>(
 
  455     libff::leave_block("Call to r1cs_gg_ppzksnark_generator");
 
  462     libff::multi_exp_method Method,
 
  463     libff::multi_exp_base_form BaseForm>
 
  464 r1cs_gg_ppzksnark_proof<ppT> r1cs_gg_ppzksnark_prover(
 
  465     const r1cs_gg_ppzksnark_proving_key<ppT> &pk,
 
  466     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  467     const r1cs_gg_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
 
  468     bool force_pow_2_domain)
 
  470     libff::enter_block("Call to r1cs_gg_ppzksnark_prover");
 
  473     assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input));
 
  476     libff::enter_block("Compute the polynomial H");
 
  477     const qap_witness<libff::Fr<ppT>> qap_wit = r1cs_to_qap_witness_map(
 
  478         pk.constraint_system,
 
  481         libff::Fr<ppT>::zero(),
 
  482         libff::Fr<ppT>::zero(),
 
  483         libff::Fr<ppT>::zero(),
 
  486     /* We are dividing degree 2(d-1) polynomial by degree d polynomial
 
  487        and not adding a PGHR-style ZK-patch, so our H is degree d-2 */
 
  488     assert(!qap_wit.coefficients_for_H[qap_wit.degree() - 2].is_zero());
 
  489     assert(qap_wit.coefficients_for_H[qap_wit.degree() - 1].is_zero());
 
  490     assert(qap_wit.coefficients_for_H[qap_wit.degree()].is_zero());
 
  491     libff::leave_block("Compute the polynomial H");
 
  494     const libff::Fr<ppT> t = libff::Fr<ppT>::random_element();
 
  495     qap_instance_evaluation<libff::Fr<ppT>> qap_inst =
 
  496         r1cs_to_qap_instance_map_with_evaluation(
 
  497             pk.constraint_system, t, force_pow_2_domain);
 
  498     assert(qap_inst.is_satisfied(qap_wit));
 
  501     /* Choose two random field elements for prover zero-knowledge. */
 
  502     const libff::Fr<ppT> r = libff::Fr<ppT>::random_element();
 
  503     const libff::Fr<ppT> s = libff::Fr<ppT>::random_element();
 
  506     assert(qap_wit.coefficients_for_ABCs.size() == qap_wit.num_variables());
 
  507     assert(pk.A_query.size() == qap_wit.num_variables() + 1);
 
  508     assert(pk.B_query.domain_size() == qap_wit.num_variables() + 1);
 
  509     assert(pk.H_query.size() == qap_wit.degree() - 1);
 
  510     assert(pk.L_query.size() == qap_wit.num_variables() - qap_wit.num_inputs());
 
  514     const size_t chunks =
 
  515         omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or
 
  516                                // call omp_set_num_threads()
 
  518     const size_t chunks = 1;
 
  521     libff::enter_block("Compute the proof");
 
  523     libff::enter_block("Compute evaluation to A-query", false);
 
  524     // TODO: sort out indexing
 
  525     libff::Fr_vector<ppT> const_padded_assignment(1, libff::Fr<ppT>::one());
 
  526     const_padded_assignment.insert(
 
  527         const_padded_assignment.end(),
 
  528         qap_wit.coefficients_for_ABCs.begin(),
 
  529         qap_wit.coefficients_for_ABCs.end());
 
  531     libff::G1<ppT> evaluation_At = libff::multi_exp_filter_one_zero<
 
  537         pk.A_query.begin() + qap_wit.num_variables() + 1,
 
  538         const_padded_assignment.begin(),
 
  539         const_padded_assignment.begin() + qap_wit.num_variables() + 1,
 
  541     libff::leave_block("Compute evaluation to A-query", false);
 
  543     libff::enter_block("Compute evaluation to B-query", false);
 
  544     knowledge_commitment<libff::G2<ppT>, libff::G1<ppT>> evaluation_Bt =
 
  545         kc_multi_exp_with_mixed_addition<
 
  553             qap_wit.num_variables() + 1,
 
  554             const_padded_assignment.begin(),
 
  555             const_padded_assignment.begin() + qap_wit.num_variables() + 1,
 
  557     libff::leave_block("Compute evaluation to B-query", false);
 
  559     libff::enter_block("Compute evaluation to H-query", false);
 
  560     libff::G1<ppT> evaluation_Ht =
 
  561         libff::multi_exp<libff::G1<ppT>, libff::Fr<ppT>, Method, BaseForm>(
 
  563             pk.H_query.begin() + (qap_wit.degree() - 1),
 
  564             qap_wit.coefficients_for_H.begin(),
 
  565             qap_wit.coefficients_for_H.begin() + (qap_wit.degree() - 1),
 
  567     libff::leave_block("Compute evaluation to H-query", false);
 
  569     libff::enter_block("Compute evaluation to L-query", false);
 
  570     libff::G1<ppT> evaluation_Lt = libff::multi_exp_filter_one_zero<
 
  577         const_padded_assignment.begin() + qap_wit.num_inputs() + 1,
 
  578         const_padded_assignment.begin() + qap_wit.num_variables() + 1,
 
  580     libff::leave_block("Compute evaluation to L-query", false);
 
  582     /* A = alpha + sum_i(a_i*A_i(t)) + r*delta */
 
  583     libff::G1<ppT> g1_A = pk.alpha_g1 + evaluation_At + r * pk.delta_g1;
 
  585     /* B = beta + sum_i(a_i*B_i(t)) + s*delta */
 
  586     libff::G1<ppT> g1_B = pk.beta_g1 + evaluation_Bt.h + s * pk.delta_g1;
 
  587     libff::G2<ppT> g2_B = pk.beta_g2 + evaluation_Bt.g + s * pk.delta_g2;
 
  589     /* C = sum_i(a_i*((beta*A_i(t) + alpha*B_i(t) + C_i(t)) + H(t)*Z(t))/delta)
 
  590      * + A*s + r*b - r*s*delta */
 
  591     libff::G1<ppT> g1_C = evaluation_Ht + evaluation_Lt + s * g1_A + r * g1_B -
 
  592                           (r * s) * pk.delta_g1;
 
  594     libff::leave_block("Compute the proof");
 
  596     libff::leave_block("Call to r1cs_gg_ppzksnark_prover");
 
  598     r1cs_gg_ppzksnark_proof<ppT> proof = r1cs_gg_ppzksnark_proof<ppT>(
 
  599         std::move(g1_A), std::move(g2_B), std::move(g1_C));
 
  605 template<typename ppT>
 
  606 r1cs_gg_ppzksnark_processed_verification_key<ppT>
 
  607 r1cs_gg_ppzksnark_verifier_process_vk(
 
  608     const r1cs_gg_ppzksnark_verification_key<ppT> &vk)
 
  610     libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
 
  612     r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk;
 
  613     pvk.vk_alpha_g1_precomp = ppT::precompute_G1(vk.alpha_g1);
 
  614     pvk.vk_beta_g2_precomp = ppT::precompute_G2(vk.beta_g2);
 
  615     pvk.vk_generator_g2_precomp = ppT::precompute_G2(libff::G2<ppT>::one());
 
  616     pvk.vk_delta_g2_precomp = ppT::precompute_G2(vk.delta_g2);
 
  617     pvk.ABC_g1 = vk.ABC_g1;
 
  619     libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_process_vk");
 
  624 template<typename ppT>
 
  625 bool r1cs_gg_ppzksnark_online_verifier_weak_IC(
 
  626     const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
 
  627     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  628     const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  630     libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
 
  631     assert(pvk.ABC_g1.domain_size() >= primary_input.size());
 
  633     libff::enter_block("Accumulate input");
 
  634     const accumulation_vector<libff::G1<ppT>> accumulated_IC =
 
  635         pvk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
 
  636             primary_input.begin(), primary_input.end(), 0);
 
  637     const libff::G1<ppT> &acc = accumulated_IC.first;
 
  638     libff::leave_block("Accumulate input");
 
  642     libff::enter_block("Check if the proof is well-formed");
 
  643     if (!proof.is_well_formed()) {
 
  644         if (!libff::inhibit_profiling_info) {
 
  645             libff::print_indent();
 
  646             printf("At least one of the proof elements does not lie on the "
 
  651     libff::leave_block("Check if the proof is well-formed");
 
  653     libff::enter_block("Online pairing computations");
 
  654     libff::enter_block("Check QAP divisibility");
 
  655     const libff::G1_precomp<ppT> proof_g_A_precomp =
 
  656         ppT::precompute_G1(proof.g_A);
 
  657     const libff::G2_precomp<ppT> proof_g_B_precomp =
 
  658         ppT::precompute_G2(proof.g_B);
 
  659     const libff::G1_precomp<ppT> proof_g_C_precomp =
 
  660         ppT::precompute_G1(proof.g_C);
 
  661     const libff::G1_precomp<ppT> acc_precomp = ppT::precompute_G1(acc);
 
  663     const libff::Fqk<ppT> f =
 
  664         ppT::miller_loop(pvk.vk_alpha_g1_precomp, pvk.vk_beta_g2_precomp);
 
  665     const libff::GT<ppT> vk_alpha_g1_beta_g2 = ppT::final_exponentiation(f);
 
  667     const libff::Fqk<ppT> QAP1 =
 
  668         ppT::miller_loop(proof_g_A_precomp, proof_g_B_precomp);
 
  669     const libff::Fqk<ppT> QAP2 = ppT::double_miller_loop(
 
  671         pvk.vk_generator_g2_precomp,
 
  673         pvk.vk_delta_g2_precomp);
 
  674     const libff::GT<ppT> QAP =
 
  675         ppT::final_exponentiation(QAP1 * QAP2.unitary_inverse());
 
  677     if (QAP != vk_alpha_g1_beta_g2) {
 
  678         if (!libff::inhibit_profiling_info) {
 
  679             libff::print_indent();
 
  680             printf("QAP divisibility check failed.\n");
 
  684     libff::leave_block("Check QAP divisibility");
 
  685     libff::leave_block("Online pairing computations");
 
  687     libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC");
 
  692 template<typename ppT>
 
  693 bool r1cs_gg_ppzksnark_verifier_weak_IC(
 
  694     const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
 
  695     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  696     const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  698     libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
 
  699     r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
 
  700         r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
 
  701     bool result = r1cs_gg_ppzksnark_online_verifier_weak_IC<ppT>(
 
  702         pvk, primary_input, proof);
 
  703     libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC");
 
  707 template<typename ppT>
 
  708 bool r1cs_gg_ppzksnark_online_verifier_strong_IC(
 
  709     const r1cs_gg_ppzksnark_processed_verification_key<ppT> &pvk,
 
  710     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  711     const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  714     libff::enter_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
 
  716     if (pvk.ABC_g1.domain_size() != primary_input.size()) {
 
  717         libff::print_indent();
 
  719             "Input length differs from expected (got %zu, expected %zu).\n",
 
  720             primary_input.size(),
 
  721             pvk.ABC_g1.domain_size());
 
  724         result = r1cs_gg_ppzksnark_online_verifier_weak_IC(
 
  725             pvk, primary_input, proof);
 
  728     libff::leave_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC");
 
  732 template<typename ppT>
 
  733 bool r1cs_gg_ppzksnark_verifier_strong_IC(
 
  734     const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
 
  735     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  736     const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  738     libff::enter_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
 
  739     r1cs_gg_ppzksnark_processed_verification_key<ppT> pvk =
 
  740         r1cs_gg_ppzksnark_verifier_process_vk<ppT>(vk);
 
  741     bool result = r1cs_gg_ppzksnark_online_verifier_strong_IC<ppT>(
 
  742         pvk, primary_input, proof);
 
  743     libff::leave_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC");
 
  747 template<typename ppT>
 
  748 bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(
 
  749     const r1cs_gg_ppzksnark_verification_key<ppT> &vk,
 
  750     const r1cs_gg_ppzksnark_primary_input<ppT> &primary_input,
 
  751     const r1cs_gg_ppzksnark_proof<ppT> &proof)
 
  753     libff::enter_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
 
  754     assert(vk.ABC_g1.domain_size() >= primary_input.size());
 
  756     libff::affine_ate_G2_precomp<ppT> pvk_vk_generator_g2_precomp =
 
  757         ppT::affine_ate_precompute_G2(libff::G2<ppT>::one());
 
  758     libff::affine_ate_G2_precomp<ppT> pvk_vk_delta_g2_precomp =
 
  759         ppT::affine_ate_precompute_G2(vk.delta_g2);
 
  761     libff::enter_block("Accumulate input");
 
  762     const accumulation_vector<libff::G1<ppT>> accumulated_IC =
 
  763         vk.ABC_g1.template accumulate_chunk<libff::Fr<ppT>>(
 
  764             primary_input.begin(), primary_input.end(), 0);
 
  765     const libff::G1<ppT> &acc = accumulated_IC.first;
 
  766     libff::leave_block("Accumulate input");
 
  770     libff::enter_block("Check if the proof is well-formed");
 
  771     if (!proof.is_well_formed()) {
 
  772         if (!libff::inhibit_profiling_info) {
 
  773             libff::print_indent();
 
  774             printf("At least one of the proof elements does not lie on the "
 
  779     libff::leave_block("Check if the proof is well-formed");
 
  781     libff::enter_block("Check QAP divisibility");
 
  782     const libff::affine_ate_G1_precomp<ppT> proof_g_A_precomp =
 
  783         ppT::affine_ate_precompute_G1(proof.g_A);
 
  784     const libff::affine_ate_G2_precomp<ppT> proof_g_B_precomp =
 
  785         ppT::affine_ate_precompute_G2(proof.g_B);
 
  786     const libff::affine_ate_G1_precomp<ppT> proof_g_C_precomp =
 
  787         ppT::affine_ate_precompute_G1(proof.g_C);
 
  788     const libff::affine_ate_G1_precomp<ppT> acc_precomp =
 
  789         ppT::affine_ate_precompute_G1(acc);
 
  791     const libff::Fqk<ppT> QAP_miller =
 
  792         ppT::affine_ate_e_times_e_over_e_miller_loop(
 
  794             pvk_vk_generator_g2_precomp,
 
  796             pvk_vk_delta_g2_precomp,
 
  799     const libff::GT<ppT> QAP =
 
  800         ppT::final_exponentiation(QAP_miller.unitary_inverse());
 
  801     const libff::GT<ppT> vk_alpha_g1_beta_g2 =
 
  802         ppT::reduced_pairing(vk.alpha_g1, vk.beta_g2);
 
  804     if (QAP != vk_alpha_g1_beta_g2) {
 
  805         if (!libff::inhibit_profiling_info) {
 
  806             libff::print_indent();
 
  807             printf("QAP divisibility check failed.\n");
 
  811     libff::leave_block("Check QAP divisibility");
 
  813     libff::leave_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC");
 
  818 } // namespace libsnark
 
  819 #endif // R1CS_GG_PPZKSNARK_TCC_