Skip to content

Commit

Permalink
separate Lagrange poly evaluation and linear combination
Browse files Browse the repository at this point in the history
  • Loading branch information
dtebbs committed Aug 20, 2019
1 parent 984536c commit 55c20fb
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 106 deletions.
113 changes: 16 additions & 97 deletions src/snarks/groth16/mpc_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,6 @@ using G2 = libff::G2<ppT>;
// static functions
// -----------------------------------------------------------------------------

template<typename Fr, typename Gr>
void basic_radix2_iFFT(
std::vector<Gr> &as,
const Fr &omega_inv)
{
libfqfft::_basic_radix2_FFT<Fr, Gr>(as, omega_inv);
const Fr n_inv = Fr(as.size()).inverse();
for (auto &a : as)
{
a = n_inv * a;
}
}

template<typename T>
void fill_vector_from_map(
std::vector<T> &out_vector,
Expand Down Expand Up @@ -75,23 +62,27 @@ mpc_layer1::mpc_layer1(
mpc_layer1
mpc_compute_linearcombination(
const powersoftau &pot,
const powersoftau_lagrange_evaluations &lagrange,
const qap_instance<Fr> &qap)
{
using Fr = libff::Fr<ppT>;
using G1 = libff::G1<ppT>;

libff::enter_block("Call to mpc_compute_linearcombination");

libfqfft::evaluation_domain<Fr> &domain = *qap.domain;
const size_t n = qap.degree();
libff::print_indent(); printf("n=%zu\n", n);
const size_t num_variables = qap.num_variables();

if (n != 1 << libff::log2(n))
{
throw std::invalid_argument("non-pow-2 domain");
}
if (n != lagrange.degree)
{
throw std::invalid_argument("domain size differs from Lagrange evaluation");
}

const size_t num_variables = qap.num_variables();
libff::enter_block("Call to mpc_compute_linearcombination");
libff::print_indent(); printf("n=%zu\n", n);

// Langrange polynomials, and therefore A, B, C will have order
// (n-1). T has order n. H.t() has order 2n-2, => H(.) has
Expand All @@ -105,87 +96,15 @@ mpc_compute_linearcombination(

assert(pot.tau_powers_g1.size() >= 2*n - 1);

// Number of coefficients to be applied to each power:
// num A's + num B's + num C's + (end_t - begin_T)
// ~=~ 3 * num A's + (end_t - begin_T)

const size_t scalar_size = libff::Fr<ppT>::size_in_bits();

// n+1 coefficients of t(.)

libff::enter_block("computing coefficients of t()");
std::vector<Fr> t_coefficients(n + 1, Fr::zero());
qap.domain->add_poly_Z(Fr::one(), t_coefficients);
domain.add_poly_Z(Fr::one(), t_coefficients);
libff::leave_block("computing coefficients of t()");

const Fr omega = domain.get_domain_element(1);
const Fr omega_inv = omega.inverse();

// Compute [ L_j(t) ]_1 from { [x^i] } i=0..n-1

libff::enter_block("computing [Lagrange_i(x)]_1");
std::vector<G1> Lagrange_g1(
crs1.tau_powers_g1.begin(),
crs1.tau_powers_g1.begin() + n);
assert(Lagrange_g1[0] == G1::one());
assert(Lagrange_g1.size() == n);
basic_radix2_iFFT(Lagrange_g1, omega_inv);
libff::leave_block("computing [Lagrange_i(x)]_1");

libff::enter_block("computing [Lagrange_i(x)]_2");
std::vector<G2> Lagrange_g2(
crs1.tau_powers_g2.begin(),
crs1.tau_powers_g2.begin() + n);
assert(Lagrange_g2[0] == G2::one());
assert(Lagrange_g2.size() == n);
basic_radix2_iFFT(Lagrange_g2, omega_inv);
libff::leave_block("computing [Lagrange_i(x)]_2");

libff::enter_block("computing [alpha . Lagrange_i(x)]_1");
std::vector<G1> alpha_lagrange_g1(
crs1.alpha_tau_powers_g1.begin(),
crs1.alpha_tau_powers_g1.begin() + n);
assert(alpha_lagrange_g1.size() == n);
basic_radix2_iFFT(alpha_lagrange_g1, omega_inv);
libff::leave_block("computing [alpha . Lagrange_i(x)]_1");

libff::enter_block("computing [beta . Lagrange_i(x)]_1");
std::vector<G1> beta_lagrange_g1(
crs1.beta_tau_powers_g1.begin(),
crs1.beta_tau_powers_g1.begin() + n);
assert(beta_lagrange_g1.size() == n);
basic_radix2_iFFT(beta_lagrange_g1, omega_inv);
libff::leave_block("computing [beta . Lagrange_i(x)]_1");

#if 1 // def DEBUG
evaluation_from_lagrange<ppT, G1> eval_g1(crs1.tau_powers_g1, domain);
evaluation_from_lagrange<ppT, G1> eval_alpha_g1(crs1.alpha_tau_powers_g1, domain);
evaluation_from_lagrange<ppT, G1> eval_beta_g1(crs1.beta_tau_powers_g1, domain);
for (size_t j = 0 ; j < n ; ++j)
{
printf("j=%zu\n", j);
std::map<size_t, Fr> l_factors;
l_factors[j] = Fr::one();
G1 L_j_g1 = eval_g1.evaluate_from_langrange_factors(l_factors);
if (L_j_g1 != Lagrange_g1[j])
{
throw std::invalid_argument("tau");
}

G1 alpha_L_j_g1 = eval_alpha_g1.evaluate_from_langrange_factors(l_factors);
if (alpha_L_j_g1 != alpha_lagrange_g1[j])
{
throw std::invalid_argument("alpha");
}

G1 beta_L_j_g1 = eval_beta_g1.evaluate_from_langrange_factors(l_factors);
if (beta_L_j_g1 != beta_lagrange_g1[j])
{
throw std::invalid_argument("beta");
}
}
#endif

// TODO: Optimize:
// for i = 0 ... n-1:
// for j = 0 ... num_variables:
Expand All @@ -211,9 +130,9 @@ mpc_compute_linearcombination(
for (const auto &entry : A_j_lagrange)
{
A_j_at_x = A_j_at_x +
(entry.second * Lagrange_g1[entry.first]);
(entry.second * lagrange.lagrange_g1[entry.first]);
ABC_j_at_x = ABC_j_at_x +
(entry.second * beta_lagrange_g1[entry.first]);
(entry.second * lagrange.beta_lagrange_g1[entry.first]);
}

As_g1[j] = A_j_at_x;
Expand All @@ -227,11 +146,11 @@ mpc_compute_linearcombination(
for (const auto &entry : B_j_lagrange)
{
B_j_at_x_g1 = B_j_at_x_g1 +
(entry.second * Lagrange_g1[entry.first]);
(entry.second * lagrange.lagrange_g1[entry.first]);
B_j_at_x_g2 = B_j_at_x_g2 +
(entry.second * Lagrange_g2[entry.first]);
(entry.second * lagrange.lagrange_g2[entry.first]);
ABC_j_at_x = ABC_j_at_x +
(entry.second * alpha_lagrange_g1[entry.first]);
(entry.second * lagrange.alpha_lagrange_g1[entry.first]);
}

Bs_g1[j] = B_j_at_x_g1;
Expand All @@ -244,7 +163,7 @@ mpc_compute_linearcombination(
for (const auto &entry : C_j_lagrange)
{
C_j_at_x = C_j_at_x +
entry.second * Lagrange_g1[entry.first];
entry.second * lagrange.lagrange_g1[entry.first];
}

Cs_g1[j] = C_j_at_x;
Expand Down Expand Up @@ -289,7 +208,7 @@ mpc_compute_linearcombination(
libff::get_window_table(
scalar_size,
window_size,
crs1.tau_powers_g1[i]);
pot.tau_powers_g1[i]);

for (size_t j = begin_T ; j < end_T ; ++j)
{
Expand Down
1 change: 1 addition & 0 deletions src/snarks/groth16/mpc_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class mpc_layer1
mpc_layer1
mpc_compute_linearcombination(
const powersoftau &pot,
const powersoftau_lagrange_evaluations &lagrange,
const libsnark::qap_instance<libff::Fr<ppT>> &qap);

/// Given the output from the first layer of the MPC, perform the 2nd
Expand Down
106 changes: 106 additions & 0 deletions src/snarks/groth16/powersoftau_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ namespace

// Utility functions

template<typename Fr, typename Gr>
static void basic_radix2_iFFT(
std::vector<Gr> &as,
const Fr &omega_inv)
{
libfqfft::_basic_radix2_FFT<Fr, Gr>(as, omega_inv);
const Fr n_inv = Fr(as.size()).inverse();
for (auto &a : as)
{
a = n_inv * a;
}
}

struct membuf : std::streambuf
{
membuf(char *begin, char *end)
Expand Down Expand Up @@ -72,6 +85,7 @@ using Fr = libff::Fr<ppT>;
using G1 = libff::G1<ppT>;
using G2 = libff::G2<ppT>;


template <typename ppT>
bool same_ratio(
const libff::G1<ppT> &a1,
Expand Down Expand Up @@ -380,6 +394,7 @@ powersoftau powersoftau_load(
beta_g2);
}


bool powersoftau_validate(
const powersoftau &pot,
const size_t n)
Expand Down Expand Up @@ -461,4 +476,95 @@ bool powersoftau_validate(
return true;
}


// -----------------------------------------------------------------------------
// powersoftau_lagrange_evaluations
// -----------------------------------------------------------------------------

powersoftau_lagrange_evaluations::powersoftau_lagrange_evaluations(
size_t degree,
std::vector<G1> &&lagrange_g1,
std::vector<G2> &&lagrange_g2,
std::vector<G1> &&alpha_lagrange_g1,
std::vector<G1> &&beta_lagrange_g1)
: degree(degree)
, lagrange_g1(std::move(lagrange_g1))
, lagrange_g2(std::move(lagrange_g2))
, alpha_lagrange_g1(std::move(alpha_lagrange_g1))
, beta_lagrange_g1(std::move(beta_lagrange_g1))
{
}


powersoftau_lagrange_evaluations
powersoftau_compute_lagrange_evaluations(
const powersoftau &pot,
const size_t n)
{
using Fr = libff::Fr<ppT>;
using G1 = libff::G1<ppT>;
using G2 = libff::G2<ppT>;

if (n != 1 << libff::log2(n))
{
throw std::invalid_argument("non-pow-2 domain");
}
if (pot.tau_powers_g1.size() < n)
{
throw std::invalid_argument("insufficient powers of tau");
}

libff::enter_block("r1cs_gg_ppzksnark_compute_lagrange_evaluations");
libff::print_indent(); printf("n=%zu\n", n);

libfqfft::basic_radix2_domain<Fr> domain(n);
const Fr omega = domain.get_domain_element(1);
const Fr omega_inv = omega.inverse();

// Compute [ L_j(t) ]_1 from { [x^i] } i=0..n-1

libff::enter_block("computing [Lagrange_i(x)]_1");
std::vector<G1> lagrange_g1(
pot.tau_powers_g1.begin(),
pot.tau_powers_g1.begin() + n);
assert(lagrange_g1[0] == G1::one());
assert(lagrange_g1.size() == n);
basic_radix2_iFFT(lagrange_g1, omega_inv);
libff::leave_block("computing [Lagrange_i(x)]_1");

libff::enter_block("computing [Lagrange_i(x)]_2");
std::vector<G2> lagrange_g2(
pot.tau_powers_g2.begin(),
pot.tau_powers_g2.begin() + n);
assert(lagrange_g2[0] == G2::one());
assert(lagrange_g2.size() == n);
basic_radix2_iFFT(lagrange_g2, omega_inv);
libff::leave_block("computing [Lagrange_i(x)]_2");

libff::enter_block("computing [alpha . Lagrange_i(x)]_1");
std::vector<G1> alpha_lagrange_g1(
pot.alpha_tau_powers_g1.begin(),
pot.alpha_tau_powers_g1.begin() + n);
assert(alpha_lagrange_g1.size() == n);
basic_radix2_iFFT(alpha_lagrange_g1, omega_inv);
libff::leave_block("computing [alpha . Lagrange_i(x)]_1");

libff::enter_block("computing [beta . Lagrange_i(x)]_1");
std::vector<G1> beta_lagrange_g1(
pot.beta_tau_powers_g1.begin(),
pot.beta_tau_powers_g1.begin() + n);
assert(beta_lagrange_g1.size() == n);
basic_radix2_iFFT(beta_lagrange_g1, omega_inv);
libff::leave_block("computing [beta . Lagrange_i(x)]_1");

libff::leave_block("r1cs_gg_ppzksnark_compute_lagrange_evaluations");

return powersoftau_lagrange_evaluations(
n,
std::move(lagrange_g1),
std::move(lagrange_g2),
std::move(alpha_lagrange_g1),
std::move(beta_lagrange_g1));
}

} // namespace libzeth
39 changes: 39 additions & 0 deletions src/snarks/groth16/powersoftau_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,36 @@ class powersoftau
const libff::G2<ppT> &beta_g2);
};


/// Encodings of lagrange polynomials at tau, computed from
/// powersoftau, on some domain of degree n.
class powersoftau_lagrange_evaluations
{
public:

const size_t degree;

/// ${ [ L_i(x) ]_1 }_i$
std::vector<libff::G1<ppT>> lagrange_g1;

/// ${ [ L_i(x) ]_2 }_i$
std::vector<libff::G2<ppT>> lagrange_g2;

/// ${ [ alpha . L_i(x) ]_1 }"$
std::vector<libff::G1<ppT>> alpha_lagrange_g1;

/// ${ [ beta . L_i(x) ]_1 }"$
std::vector<libff::G1<ppT>> beta_lagrange_g1;

powersoftau_lagrange_evaluations(
size_t degree,
std::vector<libff::G1<ppT>> &&lagrange_g1,
std::vector<libff::G2<ppT>> &&lagrange_g2,
std::vector<libff::G1<ppT>> &&alpha_lagrange_g1,
std::vector<libff::G1<ppT>> &&beta_lagrange_g1);
};


/// Given some secrets, compute a dummy set of powersoftau, for
/// circuits with polynomials A, B, C order-bound by `n` .
powersoftau dummy_powersoftau_from_secrets(
Expand Down Expand Up @@ -82,6 +112,15 @@ bool powersoftau_validate(
const powersoftau &pot,
const size_t n);


/// Compute the evaluation of the lagrange polynomials in G1 and G2,
/// along with some useful factors. The results can be cached and
/// used against any QAP, provided its domain size matched.
powersoftau_lagrange_evaluations
powersoftau_compute_lagrange_evaluations(
const powersoftau &pot,
const size_t n);

} // namespace libzeth

#endif // __ZETH_SNARKS_GROTH_POWERSOFTAU_UTILS_HPP__
Loading

0 comments on commit 55c20fb

Please sign in to comment.