Skip to content

Commit

Permalink
simulated 2nd layer of MPC with full tests of resulting keys
Browse files Browse the repository at this point in the history
  • Loading branch information
dtebbs committed Aug 29, 2019
1 parent 70fd908 commit f900c92
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/snarks/groth16/mpc_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,83 @@ mpc_layer1 mpc_compute_linearcombination(
std::move(ABC_i_g1));
}

r1cs_gg_ppzksnark_keypair<ppT> mpc_dummy_layer2(
powersoftau &&pot,
mpc_layer1 &&layer1,
const Fr &delta,
r1cs_constraint_system<Fr> &&cs,
const qap_instance<Fr> &qap)
{
const Fr delta_inverse = delta.inverse();

// { H_i } = { [ t(x) . x^i / delta ]_i } i = 0 .. m-1

libff::G1_vector<ppT> T_tau_powers_over_delta_g1(
layer1.T_tau_powers_g1.size());
for (size_t i = 0; i < layer1.T_tau_powers_g1.size(); ++i) {
T_tau_powers_over_delta_g1[i] =
delta_inverse * layer1.T_tau_powers_g1[i];
}

// ABC in verification key includes 1 + num_inputs terms.
// ABC/delta in prover key includes the remaining (num_variables -
// num_inputs) terms.

const size_t num_orig_ABC = layer1.ABC_g1.size();
const size_t num_variables = qap.num_variables();
const size_t num_inputs = qap.num_inputs();
const size_t num_L_elements = num_variables - num_inputs;

assert(num_orig_ABC == num_variables + 1);

// { ([B_i]_2, [B_i]_1) } i = 0 .. num_orig_ABC

std::vector<knowledge_commitment<G2, G1>> B_i(num_orig_ABC);
for (size_t i = 0; i < num_orig_ABC; ++i) {
B_i[i] = knowledge_commitment<G2, G1>(layer1.B_g2[i], layer1.B_g1[i]);
}

assert(B_i.size() == qap.num_variables() + 1);

// { L_i } = [ { ABC_i / delta } ]_1, i = l+1 .. num_variables

libff::G1_vector<ppT> L_g1(num_L_elements);
for (size_t i = 0; i < num_L_elements; ++i) {
L_g1[i] = delta_inverse * layer1.ABC_g1[i + num_inputs + 1];
}
assert(L_g1.size() == qap.num_variables() - qap.num_inputs());

// [ ABC_0 ]_1, { [ABC_i]_1 }, i = 1 .. num_inputs

G1 ABC_0 = layer1.ABC_g1[0];
libff::G1_vector<ppT> ABC_i(num_inputs);
for (size_t i = 0; i < num_inputs; ++i) {
ABC_i[i] = layer1.ABC_g1[i + 1];
}

// Care has been taken above to ensure nothing is used after it's
// moved, but to be safe, create the vk first (whose constructor
// does not require a move).

r1cs_gg_ppzksnark_verification_key<ppT> vk(
pot.alpha_tau_powers_g1[0],
pot.beta_g2,
delta * G2::one(),
accumulation_vector<G1>(std::move(ABC_0), std::move(ABC_i)));

r1cs_gg_ppzksnark_proving_key<ppT> pk(
G1(pot.alpha_tau_powers_g1[0]),
G1(pot.beta_tau_powers_g1[0]),
G2(pot.beta_g2),
delta * G1::one(),
delta * G2::one(),
std::move(layer1.A_g1),
knowledge_commitment_vector<G2, G1>(std::move(B_i)),
std::move(T_tau_powers_over_delta_g1),
std::move(L_g1),
std::move(cs));

return r1cs_gg_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
}

} // namespace libzeth
11 changes: 11 additions & 0 deletions src/snarks/groth16/mpc_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ class mpc_layer1
mpc_layer1 mpc_compute_linearcombination(
const powersoftau &pot, const libsnark::qap_instance<libff::Fr<ppT>> &qap);

/// Given the output from the first layer of the MPC, perform the 2nd
/// layer computation using just local randomness. This is not a
/// substitute for the full MPC with an auditable log of
/// contributions, but is useful for testing.
libsnark::r1cs_gg_ppzksnark_keypair<ppT> mpc_dummy_layer2(
powersoftau &&pot,
mpc_layer1 &&layer1,
const libff::Fr<ppT> &delta,
libsnark::r1cs_constraint_system<libff::Fr<ppT>> &&cs,
const libsnark::qap_instance<libff::Fr<ppT>> &qap);

} // namespace libzeth

#endif // __ZETH_SNARKS_GROTH16_MPC_UTILS_HPP__
144 changes: 144 additions & 0 deletions src/test/mpc_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,150 @@ TEST(MPCTests, LinearCombination)
}
}

TEST(MPCTests, Layer2)
{
const size_t n = 16;
const Fr tau = Fr::random_element();
const Fr alpha = Fr::random_element();
const Fr beta = Fr::random_element();
const Fr delta = Fr::random_element();
const G1 g1_generator = G1::one();
const G2 g2_generator = G2::one();

// dummy CRS1
powersoftau pot = dummy_powersoftau_from_secrets(tau, alpha, beta, n);

// dummy circuit and Layer1
protoboard<Fr> pb;
libzeth::test::simple_circuit<Fr>(pb);
r1cs_constraint_system<Fr> constraint_system = pb.get_constraint_system();
qap_instance<Fr> qap = r1cs_to_qap_instance_map(constraint_system);

size_t num_variables = qap.num_variables();
size_t num_inputs = qap.num_inputs();

mpc_layer1 layer1 = mpc_compute_linearcombination(pot, qap);

// Final key pair
const r1cs_gg_ppzksnark_keypair<ppT> keypair = mpc_dummy_layer2(
std::move(pot),
std::move(layer1),
delta,
std::move(constraint_system),
qap);

// Compare against directly computed values
{
const qap_instance_evaluation<Fr> qap_evaluation = ([&tau] {
protoboard<Fr> pb;
libzeth::test::simple_circuit<Fr>(pb);
const r1cs_constraint_system<Fr> constraint_system =
pb.get_constraint_system();
return r1cs_to_qap_instance_map_with_evaluation(
constraint_system, tau);
})();

const Fr delta_inverse = delta.inverse();

// Test Proving Key

const r1cs_gg_ppzksnark_proving_key<ppT> &pk = keypair.pk;

ASSERT_EQ(alpha * G1::one(), pk.alpha_g1);
ASSERT_EQ(beta * G1::one(), pk.beta_g1);
ASSERT_EQ(beta * G2::one(), pk.beta_g2);
ASSERT_EQ(delta * G1::one(), pk.delta_g1);
ASSERT_EQ(delta * G2::one(), pk.delta_g2);

// H_query

ASSERT_EQ(qap_evaluation.degree() - 1, pk.H_query.size());
Fr t_x_i = qap_evaluation.domain->compute_vanishing_polynomial(tau) *
delta_inverse;
for (size_t i = 0; i < pk.H_query.size(); ++i) {
ASSERT_EQ(t_x_i * G1::one(), pk.H_query[i])
<< "i = " << std::to_string(i);
t_x_i = tau * t_x_i;
}

// L_query

ASSERT_EQ(num_variables - num_inputs, pk.L_query.size());
for (size_t i = 0; i < num_variables - num_inputs; ++i) {
const size_t j = i + num_inputs + 1; // index into qap_evaluation

// ABC / delta
const Fr ABC_j_over_delta =
(beta * qap_evaluation.At[j] + alpha * qap_evaluation.Bt[j] +
qap_evaluation.Ct[j]) *
delta_inverse;
ASSERT_EQ(ABC_j_over_delta * G1::one(), pk.L_query[i])
<< "i = " << std::to_string(i);
}

// Test Verification Key

const r1cs_gg_ppzksnark_verification_key<ppT> &vk = keypair.vk;
ASSERT_EQ(alpha * G1::one(), vk.alpha_g1);
ASSERT_EQ(beta * G2::one(), vk.beta_g2);
ASSERT_EQ(delta * G2::one(), vk.delta_g2);
ASSERT_EQ(num_inputs, vk.ABC_g1.domain_size());

const Fr ABC_0 = beta * qap_evaluation.At[0] +
alpha * qap_evaluation.Bt[0] + qap_evaluation.Ct[0];
ASSERT_EQ(ABC_0 * G1::one(), vk.ABC_g1.first);
for (size_t i = 1; i < vk.ABC_g1.size(); ++i) {
const Fr ABC_i = beta * qap_evaluation.At[i] +
alpha * qap_evaluation.Bt[i] +
qap_evaluation.Ct[i];
ASSERT_EQ(ABC_i * G1::one(), vk.ABC_g1.rest[i - 1]);
}
}

// Compare with key_pair generated directly from the same secrets.
{
const r1cs_constraint_system<Fr> constraint_system = ([&] {
protoboard<Fr> pb;
libzeth::test::simple_circuit<Fr>(pb);
r1cs_constraint_system<Fr> cs = pb.get_constraint_system();
cs.swap_AB_if_beneficial();
return cs;
})();

const r1cs_gg_ppzksnark_keypair<ppT> keypair2 =
r1cs_gg_ppzksnark_generator_from_secrets<ppT>(
constraint_system,
tau,
alpha,
beta,
delta,
g1_generator,
g2_generator);

ASSERT_EQ(keypair2.pk.alpha_g1, keypair.pk.alpha_g1);
ASSERT_EQ(keypair2.pk.beta_g1, keypair.pk.beta_g1);
ASSERT_EQ(keypair2.pk.beta_g2, keypair.pk.beta_g2);
ASSERT_EQ(keypair2.pk.delta_g1, keypair.pk.delta_g1);
ASSERT_EQ(keypair2.pk.delta_g2, keypair.pk.delta_g2);
ASSERT_EQ(keypair2.pk.A_query, keypair.pk.A_query);
ASSERT_EQ(keypair2.pk.B_query, keypair.pk.B_query);
ASSERT_EQ(keypair2.pk.H_query, keypair.pk.H_query);
ASSERT_EQ(keypair2.pk.L_query, keypair.pk.L_query);

ASSERT_EQ(keypair2.vk, keypair.vk);
}

// Check that the keypair works for proving / verification
{
const r1cs_primary_input<Fr> primary{12};
const r1cs_auxiliary_input<Fr> auxiliary{1, 1, 1};
const r1cs_gg_ppzksnark_proof<ppT> proof =
r1cs_gg_ppzksnark_prover(keypair.pk, primary, auxiliary);
ASSERT_TRUE(
r1cs_gg_ppzksnark_verifier_strong_IC(keypair.vk, primary, proof));
}
}

} // namespace

int main(int argc, char **argv)
Expand Down

0 comments on commit f900c92

Please sign in to comment.