Fix libsnark dependency build.
This changes libsnark to build in-place, instead of copying first to a build directory. Previously, modifications made to the original sources wouldn't get rebuilt without a 'make clean' because users would be pointing to the copies. This closes #2689.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of functionality that runs the R1CS ppzkSNARK for
|
||||
a given R1CS example.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef RUN_R1CS_PPZKSNARK_HPP_
|
||||
#define RUN_R1CS_PPZKSNARK_HPP_
|
||||
|
||||
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/**
|
||||
* Runs the ppzkSNARK (generator, prover, and verifier) for a given
|
||||
* R1CS example (specified by a constraint system, input, and witness).
|
||||
*
|
||||
* Optionally, also test the serialization routines for keys and proofs.
|
||||
* (This takes additional time.)
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool run_r1cs_ppzksnark(const r1cs_example<Fr<ppT> > &example,
|
||||
const bool test_serialization);
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc"
|
||||
|
||||
#endif // RUN_R1CS_PPZKSNARK_HPP_
|
||||
@@ -0,0 +1,114 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of functionality that runs the R1CS ppzkSNARK for
|
||||
a given R1CS example.
|
||||
|
||||
See run_r1cs_ppzksnark.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef RUN_R1CS_PPZKSNARK_TCC_
|
||||
#define RUN_R1CS_PPZKSNARK_TCC_
|
||||
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/profiling.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename ppT>
|
||||
typename std::enable_if<ppT::has_affine_pairing, void>::type
|
||||
test_affine_verifier(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof,
|
||||
const bool expected_answer)
|
||||
{
|
||||
print_header("R1CS ppzkSNARK Affine Verifier");
|
||||
const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC<ppT>(vk, primary_input, proof);
|
||||
assert(answer == expected_answer);
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
typename std::enable_if<!ppT::has_affine_pairing, void>::type
|
||||
test_affine_verifier(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof,
|
||||
const bool expected_answer)
|
||||
{
|
||||
UNUSED(vk, primary_input, proof, expected_answer);
|
||||
print_header("R1CS ppzkSNARK Affine Verifier");
|
||||
printf("Affine verifier is not supported; not testing anything.\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* The code below provides an example of all stages of running a R1CS ppzkSNARK.
|
||||
*
|
||||
* Of course, in a real-life scenario, we would have three distinct entities,
|
||||
* mangled into one in the demonstration below. The three entities are as follows.
|
||||
* (1) The "generator", which runs the ppzkSNARK generator on input a given
|
||||
* constraint system CS to create a proving and a verification key for CS.
|
||||
* (2) The "prover", which runs the ppzkSNARK prover on input the proving key,
|
||||
* a primary input for CS, and an auxiliary input for CS.
|
||||
* (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key,
|
||||
* a primary input for CS, and a proof.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool run_r1cs_ppzksnark(const r1cs_example<Fr<ppT> > &example,
|
||||
const bool test_serialization)
|
||||
{
|
||||
enter_block("Call to run_r1cs_ppzksnark");
|
||||
|
||||
print_header("R1CS ppzkSNARK Generator");
|
||||
r1cs_ppzksnark_keypair<ppT> keypair = r1cs_ppzksnark_generator<ppT>(example.constraint_system);
|
||||
printf("\n"); print_indent(); print_mem("after generator");
|
||||
|
||||
print_header("Preprocess verification key");
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(keypair.vk);
|
||||
|
||||
if (test_serialization)
|
||||
{
|
||||
enter_block("Test serialization of keys");
|
||||
keypair.pk = reserialize<r1cs_ppzksnark_proving_key<ppT> >(keypair.pk);
|
||||
keypair.vk = reserialize<r1cs_ppzksnark_verification_key<ppT> >(keypair.vk);
|
||||
pvk = reserialize<r1cs_ppzksnark_processed_verification_key<ppT> >(pvk);
|
||||
leave_block("Test serialization of keys");
|
||||
}
|
||||
|
||||
print_header("R1CS ppzkSNARK Prover");
|
||||
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_prover<ppT>(keypair.pk, example.primary_input, example.auxiliary_input, example.constraint_system);
|
||||
printf("\n"); print_indent(); print_mem("after prover");
|
||||
|
||||
if (test_serialization)
|
||||
{
|
||||
enter_block("Test serialization of proof");
|
||||
proof = reserialize<r1cs_ppzksnark_proof<ppT> >(proof);
|
||||
leave_block("Test serialization of proof");
|
||||
}
|
||||
|
||||
print_header("R1CS ppzkSNARK Verifier");
|
||||
const bool ans = r1cs_ppzksnark_verifier_strong_IC<ppT>(keypair.vk, example.primary_input, proof);
|
||||
printf("\n"); print_indent(); print_mem("after verifier");
|
||||
printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL"));
|
||||
|
||||
print_header("R1CS ppzkSNARK Online Verifier");
|
||||
const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC<ppT>(pvk, example.primary_input, proof);
|
||||
assert(ans == ans2);
|
||||
|
||||
test_affine_verifier<ppT>(keypair.vk, example.primary_input, proof, ans);
|
||||
|
||||
leave_block("Call to run_r1cs_ppzksnark");
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // RUN_R1CS_PPZKSNARK_TCC_
|
||||
@@ -0,0 +1,71 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
Profiling program that exercises the ppzkSNARK (first generator, then prover,
|
||||
then verifier) on a synthetic R1CS instance.
|
||||
|
||||
The command
|
||||
|
||||
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr
|
||||
|
||||
exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements.
|
||||
|
||||
(If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).)
|
||||
|
||||
The command
|
||||
|
||||
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes
|
||||
|
||||
does the same but now the input consists of 10 bytes.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "common/default_types/r1cs_ppzksnark_pp.hpp"
|
||||
#include "common/profiling.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp"
|
||||
|
||||
using namespace libsnark;
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
default_r1cs_ppzksnark_pp::init_public_params();
|
||||
start_profiling();
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "-v") == 0)
|
||||
{
|
||||
print_compilation_info();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc != 3 && argc != 4)
|
||||
{
|
||||
printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
const int num_constraints = atoi(argv[1]);
|
||||
int input_size = atoi(argv[2]);
|
||||
if (argc == 4)
|
||||
{
|
||||
assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0);
|
||||
if (strcmp(argv[3], "bytes") == 0)
|
||||
{
|
||||
input_size = div_ceil(8 * input_size, Fr<default_ec_pp>::capacity());
|
||||
}
|
||||
}
|
||||
|
||||
enter_block("Generate R1CS example");
|
||||
r1cs_example<Fr<default_r1cs_ppzksnark_pp> > example = generate_r1cs_example_with_field_input<Fr<default_r1cs_ppzksnark_pp> >(num_constraints, input_size);
|
||||
leave_block("Generate R1CS example");
|
||||
|
||||
print_header("(enter) Profile R1CS ppzkSNARK");
|
||||
const bool test_serialization = true;
|
||||
run_r1cs_ppzksnark<default_r1cs_ppzksnark_pp>(example, test_serialization);
|
||||
print_header("(leave) Profile R1CS ppzkSNARK");
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of interfaces for a ppzkSNARK for R1CS.
|
||||
|
||||
This includes:
|
||||
- class for proving key
|
||||
- class for verification key
|
||||
- class for processed verification key
|
||||
- class for key pair (proving key & verification key)
|
||||
- class for proof
|
||||
- generator algorithm
|
||||
- prover algorithm
|
||||
- verifier algorithm (with strong or weak input consistency)
|
||||
- online verifier algorithm (with strong or weak input consistency)
|
||||
|
||||
The implementation instantiates (a modification of) the protocol of \[PGHR13],
|
||||
by following extending, and optimizing the approach described in \[BCTV14].
|
||||
|
||||
|
||||
Acronyms:
|
||||
|
||||
- R1CS = "Rank-1 Constraint Systems"
|
||||
- ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge"
|
||||
|
||||
References:
|
||||
|
||||
\[BCTV14]:
|
||||
"Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture",
|
||||
Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza,
|
||||
USENIX Security 2014,
|
||||
<http://eprint.iacr.org/2013/879>
|
||||
|
||||
\[PGHR13]:
|
||||
"Pinocchio: Nearly practical verifiable computation",
|
||||
Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova,
|
||||
IEEE S&P 2013,
|
||||
<https://eprint.iacr.org/2013/279>
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef R1CS_PPZKSNARK_HPP_
|
||||
#define R1CS_PPZKSNARK_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "algebra/curves/public_params.hpp"
|
||||
#include "common/data_structures/accumulation_vector.hpp"
|
||||
#include "algebra/knowledge_commitment/knowledge_commitment.hpp"
|
||||
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/******************************** Proving key ********************************/
|
||||
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_proving_key;
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk);
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk);
|
||||
|
||||
/**
|
||||
* A proving key for the R1CS ppzkSNARK.
|
||||
*/
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_proving_key {
|
||||
public:
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query;
|
||||
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query;
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query;
|
||||
G1_vector<ppT> H_query;
|
||||
G1_vector<ppT> K_query;
|
||||
|
||||
r1cs_ppzksnark_proving_key() {};
|
||||
r1cs_ppzksnark_proving_key<ppT>& operator=(const r1cs_ppzksnark_proving_key<ppT> &other) = default;
|
||||
r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key<ppT> &other) = default;
|
||||
r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key<ppT> &&other) = default;
|
||||
r1cs_ppzksnark_proving_key(knowledge_commitment_vector<G1<ppT>, G1<ppT> > &&A_query,
|
||||
knowledge_commitment_vector<G2<ppT>, G1<ppT> > &&B_query,
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > &&C_query,
|
||||
G1_vector<ppT> &&H_query,
|
||||
G1_vector<ppT> &&K_query) :
|
||||
A_query(std::move(A_query)),
|
||||
B_query(std::move(B_query)),
|
||||
C_query(std::move(C_query)),
|
||||
H_query(std::move(H_query)),
|
||||
K_query(std::move(K_query))
|
||||
{};
|
||||
|
||||
size_t G1_size() const
|
||||
{
|
||||
return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size();
|
||||
}
|
||||
|
||||
size_t G2_size() const
|
||||
{
|
||||
return B_query.domain_size();
|
||||
}
|
||||
|
||||
size_t G1_sparse_size() const
|
||||
{
|
||||
return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size();
|
||||
}
|
||||
|
||||
size_t G2_sparse_size() const
|
||||
{
|
||||
return B_query.size();
|
||||
}
|
||||
|
||||
size_t size_in_bits() const
|
||||
{
|
||||
return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query);
|
||||
}
|
||||
|
||||
void print_size() const
|
||||
{
|
||||
print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size());
|
||||
print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size());
|
||||
print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size());
|
||||
print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size());
|
||||
print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits());
|
||||
}
|
||||
|
||||
bool operator==(const r1cs_ppzksnark_proving_key<ppT> &other) const;
|
||||
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk);
|
||||
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk);
|
||||
};
|
||||
|
||||
|
||||
/******************************* Verification key ****************************/
|
||||
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_verification_key;
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk);
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk);
|
||||
|
||||
/**
|
||||
* A verification key for the R1CS ppzkSNARK.
|
||||
*/
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_verification_key {
|
||||
public:
|
||||
G2<ppT> alphaA_g2;
|
||||
G1<ppT> alphaB_g1;
|
||||
G2<ppT> alphaC_g2;
|
||||
G2<ppT> gamma_g2;
|
||||
G1<ppT> gamma_beta_g1;
|
||||
G2<ppT> gamma_beta_g2;
|
||||
G2<ppT> rC_Z_g2;
|
||||
|
||||
accumulation_vector<G1<ppT> > encoded_IC_query;
|
||||
|
||||
r1cs_ppzksnark_verification_key() = default;
|
||||
r1cs_ppzksnark_verification_key(const G2<ppT> &alphaA_g2,
|
||||
const G1<ppT> &alphaB_g1,
|
||||
const G2<ppT> &alphaC_g2,
|
||||
const G2<ppT> &gamma_g2,
|
||||
const G1<ppT> &gamma_beta_g1,
|
||||
const G2<ppT> &gamma_beta_g2,
|
||||
const G2<ppT> &rC_Z_g2,
|
||||
const accumulation_vector<G1<ppT> > &eIC) :
|
||||
alphaA_g2(alphaA_g2),
|
||||
alphaB_g1(alphaB_g1),
|
||||
alphaC_g2(alphaC_g2),
|
||||
gamma_g2(gamma_g2),
|
||||
gamma_beta_g1(gamma_beta_g1),
|
||||
gamma_beta_g2(gamma_beta_g2),
|
||||
rC_Z_g2(rC_Z_g2),
|
||||
encoded_IC_query(eIC)
|
||||
{};
|
||||
|
||||
size_t G1_size() const
|
||||
{
|
||||
return 2 + encoded_IC_query.size();
|
||||
}
|
||||
|
||||
size_t G2_size() const
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
size_t size_in_bits() const
|
||||
{
|
||||
return (2 * G1<ppT>::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2<ppT>::size_in_bits());
|
||||
}
|
||||
|
||||
void print_size() const
|
||||
{
|
||||
print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size());
|
||||
print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size());
|
||||
print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits());
|
||||
}
|
||||
|
||||
bool operator==(const r1cs_ppzksnark_verification_key<ppT> &other) const;
|
||||
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk);
|
||||
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk);
|
||||
|
||||
static r1cs_ppzksnark_verification_key<ppT> dummy_verification_key(const size_t input_size);
|
||||
};
|
||||
|
||||
|
||||
/************************ Processed verification key *************************/
|
||||
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_processed_verification_key;
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
|
||||
|
||||
/**
|
||||
* A processed verification key for the R1CS ppzkSNARK.
|
||||
*
|
||||
* Compared to a (non-processed) verification key, a processed verification key
|
||||
* contains a small constant amount of additional pre-computed information that
|
||||
* enables a faster verification time.
|
||||
*/
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_processed_verification_key {
|
||||
public:
|
||||
G2_precomp<ppT> pp_G2_one_precomp;
|
||||
G2_precomp<ppT> vk_alphaA_g2_precomp;
|
||||
G1_precomp<ppT> vk_alphaB_g1_precomp;
|
||||
G2_precomp<ppT> vk_alphaC_g2_precomp;
|
||||
G2_precomp<ppT> vk_rC_Z_g2_precomp;
|
||||
G2_precomp<ppT> vk_gamma_g2_precomp;
|
||||
G1_precomp<ppT> vk_gamma_beta_g1_precomp;
|
||||
G2_precomp<ppT> vk_gamma_beta_g2_precomp;
|
||||
|
||||
accumulation_vector<G1<ppT> > encoded_IC_query;
|
||||
|
||||
bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const;
|
||||
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
|
||||
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
|
||||
};
|
||||
|
||||
|
||||
/********************************** Key pair *********************************/
|
||||
|
||||
/**
|
||||
* A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key.
|
||||
*/
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_keypair {
|
||||
public:
|
||||
r1cs_ppzksnark_proving_key<ppT> pk;
|
||||
r1cs_ppzksnark_verification_key<ppT> vk;
|
||||
|
||||
r1cs_ppzksnark_keypair() = default;
|
||||
r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair<ppT> &other) = default;
|
||||
r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key<ppT> &&pk,
|
||||
r1cs_ppzksnark_verification_key<ppT> &&vk) :
|
||||
pk(std::move(pk)),
|
||||
vk(std::move(vk))
|
||||
{}
|
||||
|
||||
r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair<ppT> &&other) = default;
|
||||
};
|
||||
|
||||
|
||||
/*********************************** Proof ***********************************/
|
||||
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_proof;
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
/**
|
||||
* A proof for the R1CS ppzkSNARK.
|
||||
*
|
||||
* While the proof has a structure, externally one merely opaquely produces,
|
||||
* seralizes/deserializes, and verifies proofs. We only expose some information
|
||||
* about the structure for statistics purposes.
|
||||
*/
|
||||
template<typename ppT>
|
||||
class r1cs_ppzksnark_proof {
|
||||
public:
|
||||
knowledge_commitment<G1<ppT>, G1<ppT> > g_A;
|
||||
knowledge_commitment<G2<ppT>, G1<ppT> > g_B;
|
||||
knowledge_commitment<G1<ppT>, G1<ppT> > g_C;
|
||||
G1<ppT> g_H;
|
||||
G1<ppT> g_K;
|
||||
|
||||
r1cs_ppzksnark_proof()
|
||||
{
|
||||
// invalid proof with valid curve points
|
||||
this->g_A.g = G1<ppT> ::one();
|
||||
this->g_A.h = G1<ppT>::one();
|
||||
this->g_B.g = G2<ppT> ::one();
|
||||
this->g_B.h = G1<ppT>::one();
|
||||
this->g_C.g = G1<ppT> ::one();
|
||||
this->g_C.h = G1<ppT>::one();
|
||||
this->g_H = G1<ppT>::one();
|
||||
this->g_K = G1<ppT>::one();
|
||||
}
|
||||
r1cs_ppzksnark_proof(knowledge_commitment<G1<ppT>, G1<ppT> > &&g_A,
|
||||
knowledge_commitment<G2<ppT>, G1<ppT> > &&g_B,
|
||||
knowledge_commitment<G1<ppT>, G1<ppT> > &&g_C,
|
||||
G1<ppT> &&g_H,
|
||||
G1<ppT> &&g_K) :
|
||||
g_A(std::move(g_A)),
|
||||
g_B(std::move(g_B)),
|
||||
g_C(std::move(g_C)),
|
||||
g_H(std::move(g_H)),
|
||||
g_K(std::move(g_K))
|
||||
{};
|
||||
|
||||
size_t G1_size() const
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
size_t G2_size() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t size_in_bits() const
|
||||
{
|
||||
return G1_size() * G1<ppT>::size_in_bits() + G2_size() * G2<ppT>::size_in_bits();
|
||||
}
|
||||
|
||||
void print_size() const
|
||||
{
|
||||
print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size());
|
||||
print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size());
|
||||
print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits());
|
||||
}
|
||||
|
||||
bool is_well_formed() const
|
||||
{
|
||||
return (g_A.g.is_well_formed() && g_A.h.is_well_formed() &&
|
||||
g_B.g.is_well_formed() && g_B.h.is_well_formed() &&
|
||||
g_C.g.is_well_formed() && g_C.h.is_well_formed() &&
|
||||
g_H.is_well_formed() &&
|
||||
g_K.is_well_formed());
|
||||
}
|
||||
|
||||
bool operator==(const r1cs_ppzksnark_proof<ppT> &other) const;
|
||||
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof);
|
||||
};
|
||||
|
||||
|
||||
/***************************** Main algorithms *******************************/
|
||||
|
||||
/**
|
||||
* A generator algorithm for the R1CS ppzkSNARK.
|
||||
*
|
||||
* Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS.
|
||||
*/
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system<ppT> &cs);
|
||||
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &cs,
|
||||
const Fr<ppT>& t,
|
||||
const Fr<ppT>& alphaA,
|
||||
const Fr<ppT>& alphaB,
|
||||
const Fr<ppT>& alphaC,
|
||||
const Fr<ppT>& rA,
|
||||
const Fr<ppT>& rB,
|
||||
const Fr<ppT>& beta,
|
||||
const Fr<ppT>& gamma
|
||||
);
|
||||
|
||||
/**
|
||||
* A prover algorithm for the R1CS ppzkSNARK.
|
||||
*
|
||||
* Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm
|
||||
* produces a proof (of knowledge) that attests to the following statement:
|
||||
* ``there exists Y such that CS(X,Y)=0''.
|
||||
* Above, CS is the R1CS constraint system that was given as input to the generator algorithm.
|
||||
*/
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key<ppT> &pk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system);
|
||||
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system);
|
||||
|
||||
/*
|
||||
Below are four variants of verifier algorithm for the R1CS ppzkSNARK.
|
||||
|
||||
These are the four cases that arise from the following two choices:
|
||||
|
||||
(1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key.
|
||||
In the latter case, we call the algorithm an "online verifier".
|
||||
|
||||
(2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency.
|
||||
Strong input consistency requires that |primary_input| = CS.num_inputs, whereas
|
||||
weak input consistency requires that |primary_input| <= CS.num_inputs (and
|
||||
the primary input is implicitly padded with zeros up to length CS.num_inputs).
|
||||
*/
|
||||
|
||||
/**
|
||||
* A verifier algorithm for the R1CS ppzkSNARK that:
|
||||
* (1) accepts a non-processed verification key, and
|
||||
* (2) has weak input consistency.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
/**
|
||||
* A verifier algorithm for the R1CS ppzkSNARK that:
|
||||
* (1) accepts a non-processed verification key, and
|
||||
* (2) has strong input consistency.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
/**
|
||||
* Convert a (non-processed) verification key into a processed verification key.
|
||||
*/
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key<ppT> &vk);
|
||||
|
||||
/**
|
||||
* A verifier algorithm for the R1CS ppzkSNARK that:
|
||||
* (1) accepts a processed verification key, and
|
||||
* (2) has weak input consistency.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
/**
|
||||
* A verifier algorithm for the R1CS ppzkSNARK that:
|
||||
* (1) accepts a processed verification key, and
|
||||
* (2) has strong input consistency.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
/****************************** Miscellaneous ********************************/
|
||||
|
||||
/**
|
||||
* For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget):
|
||||
*
|
||||
* A verifier algorithm for the R1CS ppzkSNARK that:
|
||||
* (1) accepts a non-processed verification key,
|
||||
* (2) has weak input consistency, and
|
||||
* (3) uses affine coordinates for elliptic-curve computations.
|
||||
*/
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof);
|
||||
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc"
|
||||
|
||||
#endif // R1CS_PPZKSNARK_HPP_
|
||||
@@ -0,0 +1,886 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of interfaces for a ppzkSNARK for R1CS.
|
||||
|
||||
See r1cs_ppzksnark.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef R1CS_PPZKSNARK_TCC_
|
||||
#define R1CS_PPZKSNARK_TCC_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "common/profiling.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "algebra/scalar_multiplication/multiexp.hpp"
|
||||
#include "algebra/scalar_multiplication/kc_multiexp.hpp"
|
||||
#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_proving_key<ppT>::operator==(const r1cs_ppzksnark_proving_key<ppT> &other) const
|
||||
{
|
||||
return (this->A_query == other.A_query &&
|
||||
this->B_query == other.B_query &&
|
||||
this->C_query == other.C_query &&
|
||||
this->H_query == other.H_query &&
|
||||
this->K_query == other.K_query);
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk)
|
||||
{
|
||||
out << pk.A_query;
|
||||
out << pk.B_query;
|
||||
out << pk.C_query;
|
||||
out << pk.H_query;
|
||||
out << pk.K_query;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk)
|
||||
{
|
||||
in >> pk.A_query;
|
||||
in >> pk.B_query;
|
||||
in >> pk.C_query;
|
||||
in >> pk.H_query;
|
||||
in >> pk.K_query;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_verification_key<ppT>::operator==(const r1cs_ppzksnark_verification_key<ppT> &other) const
|
||||
{
|
||||
return (this->alphaA_g2 == other.alphaA_g2 &&
|
||||
this->alphaB_g1 == other.alphaB_g1 &&
|
||||
this->alphaC_g2 == other.alphaC_g2 &&
|
||||
this->gamma_g2 == other.gamma_g2 &&
|
||||
this->gamma_beta_g1 == other.gamma_beta_g1 &&
|
||||
this->gamma_beta_g2 == other.gamma_beta_g2 &&
|
||||
this->rC_Z_g2 == other.rC_Z_g2 &&
|
||||
this->encoded_IC_query == other.encoded_IC_query);
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk)
|
||||
{
|
||||
out << vk.alphaA_g2 << OUTPUT_NEWLINE;
|
||||
out << vk.alphaB_g1 << OUTPUT_NEWLINE;
|
||||
out << vk.alphaC_g2 << OUTPUT_NEWLINE;
|
||||
out << vk.gamma_g2 << OUTPUT_NEWLINE;
|
||||
out << vk.gamma_beta_g1 << OUTPUT_NEWLINE;
|
||||
out << vk.gamma_beta_g2 << OUTPUT_NEWLINE;
|
||||
out << vk.rC_Z_g2 << OUTPUT_NEWLINE;
|
||||
out << vk.encoded_IC_query << OUTPUT_NEWLINE;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk)
|
||||
{
|
||||
in >> vk.alphaA_g2;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.alphaB_g1;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.alphaC_g2;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.gamma_g2;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.gamma_beta_g1;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.gamma_beta_g2;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.rC_Z_g2;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> vk.encoded_IC_query;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_processed_verification_key<ppT>::operator==(const r1cs_ppzksnark_processed_verification_key<ppT> &other) const
|
||||
{
|
||||
return (this->pp_G2_one_precomp == other.pp_G2_one_precomp &&
|
||||
this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp &&
|
||||
this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp &&
|
||||
this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp &&
|
||||
this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp &&
|
||||
this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp &&
|
||||
this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp &&
|
||||
this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp &&
|
||||
this->encoded_IC_query == other.encoded_IC_query);
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
|
||||
{
|
||||
out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE;
|
||||
out << pvk.encoded_IC_query << OUTPUT_NEWLINE;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
|
||||
{
|
||||
in >> pvk.pp_G2_one_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_alphaA_g2_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_alphaB_g1_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_alphaC_g2_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_rC_Z_g2_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_gamma_g2_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_gamma_beta_g1_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.vk_gamma_beta_g2_precomp;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> pvk.encoded_IC_query;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_proof<ppT>::operator==(const r1cs_ppzksnark_proof<ppT> &other) const
|
||||
{
|
||||
return (this->g_A == other.g_A &&
|
||||
this->g_B == other.g_B &&
|
||||
this->g_C == other.g_C &&
|
||||
this->g_H == other.g_H &&
|
||||
this->g_K == other.g_K);
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
out << proof.g_A << OUTPUT_NEWLINE;
|
||||
out << proof.g_B << OUTPUT_NEWLINE;
|
||||
out << proof.g_C << OUTPUT_NEWLINE;
|
||||
out << proof.g_H << OUTPUT_NEWLINE;
|
||||
out << proof.g_K << OUTPUT_NEWLINE;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
in >> proof.g_A;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> proof.g_B;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> proof.g_C;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> proof.g_H;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> proof.g_K;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
r1cs_ppzksnark_verification_key<ppT> r1cs_ppzksnark_verification_key<ppT>::dummy_verification_key(const size_t input_size)
|
||||
{
|
||||
r1cs_ppzksnark_verification_key<ppT> result;
|
||||
result.alphaA_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
|
||||
result.alphaB_g1 = Fr<ppT>::random_element() * G1<ppT>::one();
|
||||
result.alphaC_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
|
||||
result.gamma_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
|
||||
result.gamma_beta_g1 = Fr<ppT>::random_element() * G1<ppT>::one();
|
||||
result.gamma_beta_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
|
||||
result.rC_Z_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
|
||||
|
||||
G1<ppT> base = Fr<ppT>::random_element() * G1<ppT>::one();
|
||||
G1_vector<ppT> v;
|
||||
for (size_t i = 0; i < input_size; ++i)
|
||||
{
|
||||
v.emplace_back(Fr<ppT>::random_element() * G1<ppT>::one());
|
||||
}
|
||||
|
||||
result.encoded_IC_query = accumulation_vector<G1<ppT> >(std::move(base), std::move(v));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system<ppT> &cs)
|
||||
{
|
||||
/* draw random element at which the QAP is evaluated */
|
||||
const Fr<ppT> t = Fr<ppT>::random_element();
|
||||
|
||||
const Fr<ppT> alphaA = Fr<ppT>::random_element(),
|
||||
alphaB = Fr<ppT>::random_element(),
|
||||
alphaC = Fr<ppT>::random_element(),
|
||||
rA = Fr<ppT>::random_element(),
|
||||
rB = Fr<ppT>::random_element(),
|
||||
beta = Fr<ppT>::random_element(),
|
||||
gamma = Fr<ppT>::random_element();
|
||||
|
||||
return r1cs_ppzksnark_generator<ppT>(cs, t, alphaA, alphaB, alphaC, rA, rB, beta, gamma);
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &cs,
|
||||
const Fr<ppT>& t,
|
||||
const Fr<ppT>& alphaA,
|
||||
const Fr<ppT>& alphaB,
|
||||
const Fr<ppT>& alphaC,
|
||||
const Fr<ppT>& rA,
|
||||
const Fr<ppT>& rB,
|
||||
const Fr<ppT>& beta,
|
||||
const Fr<ppT>& gamma
|
||||
)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_generator");
|
||||
|
||||
/* make the B_query "lighter" if possible */
|
||||
r1cs_ppzksnark_constraint_system<ppT> cs_copy(cs);
|
||||
cs_copy.swap_AB_if_beneficial();
|
||||
|
||||
qap_instance_evaluation<Fr<ppT> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t);
|
||||
|
||||
print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables());
|
||||
print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size());
|
||||
print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree());
|
||||
print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs());
|
||||
|
||||
enter_block("Compute query densities");
|
||||
size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0;
|
||||
for (size_t i = 0; i < qap_inst.num_variables()+1; ++i)
|
||||
{
|
||||
if (!qap_inst.At[i].is_zero())
|
||||
{
|
||||
++non_zero_At;
|
||||
}
|
||||
if (!qap_inst.Bt[i].is_zero())
|
||||
{
|
||||
++non_zero_Bt;
|
||||
}
|
||||
if (!qap_inst.Ct[i].is_zero())
|
||||
{
|
||||
++non_zero_Ct;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < qap_inst.degree()+1; ++i)
|
||||
{
|
||||
if (!qap_inst.Ht[i].is_zero())
|
||||
{
|
||||
++non_zero_Ht;
|
||||
}
|
||||
}
|
||||
leave_block("Compute query densities");
|
||||
|
||||
Fr_vector<ppT> At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later
|
||||
Fr_vector<ppT> Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later
|
||||
Fr_vector<ppT> Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later
|
||||
Fr_vector<ppT> Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later
|
||||
|
||||
/* append Zt to At,Bt,Ct with */
|
||||
At.emplace_back(qap_inst.Zt);
|
||||
Bt.emplace_back(qap_inst.Zt);
|
||||
Ct.emplace_back(qap_inst.Zt);
|
||||
|
||||
const Fr<ppT> rC = rA * rB;
|
||||
|
||||
// consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At)
|
||||
Fr_vector<ppT> Kt;
|
||||
Kt.reserve(qap_inst.num_variables()+4);
|
||||
for (size_t i = 0; i < qap_inst.num_variables()+1; ++i)
|
||||
{
|
||||
Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) );
|
||||
}
|
||||
Kt.emplace_back(beta * rA * qap_inst.Zt);
|
||||
Kt.emplace_back(beta * rB * qap_inst.Zt);
|
||||
Kt.emplace_back(beta * rC * qap_inst.Zt);
|
||||
|
||||
/* zero out prefix of At and stick it into IC coefficients */
|
||||
Fr_vector<ppT> IC_coefficients;
|
||||
IC_coefficients.reserve(qap_inst.num_inputs() + 1);
|
||||
for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i)
|
||||
{
|
||||
IC_coefficients.emplace_back(At[i]);
|
||||
assert(!IC_coefficients[i].is_zero());
|
||||
At[i] = Fr<ppT>::zero();
|
||||
}
|
||||
|
||||
const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size();
|
||||
const size_t g2_exp_count = non_zero_Bt;
|
||||
|
||||
size_t g1_window = get_exp_window_size<G1<ppT> >(g1_exp_count);
|
||||
size_t g2_window = get_exp_window_size<G2<ppT> >(g2_exp_count);
|
||||
print_indent(); printf("* G1 window: %zu\n", g1_window);
|
||||
print_indent(); printf("* G2 window: %zu\n", g2_window);
|
||||
|
||||
#ifdef MULTICORE
|
||||
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
|
||||
#else
|
||||
const size_t chunks = 1;
|
||||
#endif
|
||||
|
||||
enter_block("Generating G1 multiexp table");
|
||||
window_table<G1<ppT> > g1_table = get_window_table(Fr<ppT>::size_in_bits(), g1_window, G1<ppT>::one());
|
||||
leave_block("Generating G1 multiexp table");
|
||||
|
||||
enter_block("Generating G2 multiexp table");
|
||||
window_table<G2<ppT> > g2_table = get_window_table(Fr<ppT>::size_in_bits(), g2_window, G2<ppT>::one());
|
||||
leave_block("Generating G2 multiexp table");
|
||||
|
||||
enter_block("Generate R1CS proving key");
|
||||
|
||||
enter_block("Generate knowledge commitments");
|
||||
enter_block("Compute the A-query", false);
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks);
|
||||
leave_block("Compute the A-query", false);
|
||||
|
||||
enter_block("Compute the B-query", false);
|
||||
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks);
|
||||
leave_block("Compute the B-query", false);
|
||||
|
||||
enter_block("Compute the C-query", false);
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks);
|
||||
leave_block("Compute the C-query", false);
|
||||
|
||||
enter_block("Compute the H-query", false);
|
||||
G1_vector<ppT> H_query = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, Ht);
|
||||
leave_block("Compute the H-query", false);
|
||||
|
||||
enter_block("Compute the K-query", false);
|
||||
G1_vector<ppT> K_query = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, Kt);
|
||||
#ifdef USE_MIXED_ADDITION
|
||||
batch_to_special<G1<ppT> >(K_query);
|
||||
#endif
|
||||
leave_block("Compute the K-query", false);
|
||||
|
||||
leave_block("Generate knowledge commitments");
|
||||
|
||||
leave_block("Generate R1CS proving key");
|
||||
|
||||
enter_block("Generate R1CS verification key");
|
||||
G2<ppT> alphaA_g2 = alphaA * G2<ppT>::one();
|
||||
G1<ppT> alphaB_g1 = alphaB * G1<ppT>::one();
|
||||
G2<ppT> alphaC_g2 = alphaC * G2<ppT>::one();
|
||||
G2<ppT> gamma_g2 = gamma * G2<ppT>::one();
|
||||
G1<ppT> gamma_beta_g1 = (gamma * beta) * G1<ppT>::one();
|
||||
G2<ppT> gamma_beta_g2 = (gamma * beta) * G2<ppT>::one();
|
||||
G2<ppT> rC_Z_g2 = (rC * qap_inst.Zt) * G2<ppT>::one();
|
||||
|
||||
enter_block("Encode IC query for R1CS verification key");
|
||||
G1<ppT> encoded_IC_base = (rA * IC_coefficients[0]) * G1<ppT>::one();
|
||||
Fr_vector<ppT> multiplied_IC_coefficients;
|
||||
multiplied_IC_coefficients.reserve(qap_inst.num_inputs());
|
||||
for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i)
|
||||
{
|
||||
multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]);
|
||||
}
|
||||
G1_vector<ppT> encoded_IC_values = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients);
|
||||
|
||||
leave_block("Encode IC query for R1CS verification key");
|
||||
leave_block("Generate R1CS verification key");
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_generator");
|
||||
|
||||
accumulation_vector<G1<ppT> > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values));
|
||||
|
||||
r1cs_ppzksnark_verification_key<ppT> vk = r1cs_ppzksnark_verification_key<ppT>(alphaA_g2,
|
||||
alphaB_g1,
|
||||
alphaC_g2,
|
||||
gamma_g2,
|
||||
gamma_beta_g1,
|
||||
gamma_beta_g2,
|
||||
rC_Z_g2,
|
||||
encoded_IC_query);
|
||||
r1cs_ppzksnark_proving_key<ppT> pk = r1cs_ppzksnark_proving_key<ppT>(std::move(A_query),
|
||||
std::move(B_query),
|
||||
std::move(C_query),
|
||||
std::move(H_query),
|
||||
std::move(K_query));
|
||||
|
||||
pk.print_size();
|
||||
vk.print_size();
|
||||
|
||||
return r1cs_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
|
||||
}
|
||||
|
||||
template <typename ppT, typename T1, typename T2>
|
||||
knowledge_commitment<T1, T2> r1cs_compute_proof_kc(const qap_witness<Fr<ppT> > &qap_wit,
|
||||
const knowledge_commitment_vector<T1, T2> &kcv,
|
||||
const Fr<ppT> &zk_shift)
|
||||
{
|
||||
knowledge_commitment<T1, T2> returnval = kcv[0] + (zk_shift * kcv[qap_wit.num_variables()+1]);
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(kcv.domain_size() == qap_wit.num_variables()+2);
|
||||
#endif
|
||||
|
||||
#ifdef MULTICORE
|
||||
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
|
||||
#else
|
||||
const size_t chunks = 1;
|
||||
#endif
|
||||
|
||||
returnval = returnval + kc_multi_exp_with_mixed_addition<T1, T2, Fr<ppT> >(
|
||||
kcv,
|
||||
1,
|
||||
1 + qap_wit.num_variables(),
|
||||
qap_wit.coefficients_for_ABCs.begin(),
|
||||
qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(),
|
||||
chunks,
|
||||
true
|
||||
);
|
||||
|
||||
return returnval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename ppT>
|
||||
G1<ppT> r1cs_compute_proof_K(const qap_witness<Fr<ppT>> &qap_wit, const G1_vector<ppT> &K_query, const G1<ppT> &zk_shift)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
assert(K_query.size() == qap_wit.num_variables()+4);
|
||||
#endif
|
||||
|
||||
#ifdef MULTICORE
|
||||
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
|
||||
#else
|
||||
const size_t chunks = 1;
|
||||
#endif
|
||||
|
||||
G1<ppT> g_K = K_query[0] + zk_shift;
|
||||
g_K = g_K + multi_exp_with_mixed_addition<G1<ppT>, Fr<ppT> >(
|
||||
K_query.begin()+1,
|
||||
K_query.begin()+1+qap_wit.num_variables(),
|
||||
qap_wit.coefficients_for_ABCs.begin(),
|
||||
qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(),
|
||||
chunks,
|
||||
true
|
||||
);
|
||||
|
||||
return g_K;
|
||||
}
|
||||
|
||||
|
||||
template <typename ppT>
|
||||
G1<ppT> r1cs_compute_proof_H(const qap_witness<Fr<ppT> > &qap_wit, const G1_vector<ppT> &H_query)
|
||||
{
|
||||
G1<ppT> g_H = G1<ppT>::zero();
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(H_query.size() == qap_wit.degree()+1);
|
||||
#endif
|
||||
|
||||
#ifdef MULTICORE
|
||||
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
|
||||
#else
|
||||
const size_t chunks = 1;
|
||||
#endif
|
||||
|
||||
g_H = g_H + multi_exp<G1<ppT>, Fr<ppT> >(
|
||||
H_query.begin(),
|
||||
H_query.begin()+qap_wit.degree()+1,
|
||||
qap_wit.coefficients_for_H.begin(),
|
||||
qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1,
|
||||
chunks,
|
||||
true
|
||||
);
|
||||
|
||||
return g_H;
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key<ppT> &pk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_prover");
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(constraint_system.is_satisfied(primary_input, auxiliary_input));
|
||||
#endif
|
||||
|
||||
const Fr<ppT> d1 = Fr<ppT>::random_element(),
|
||||
d2 = Fr<ppT>::random_element(),
|
||||
d3 = Fr<ppT>::random_element();
|
||||
|
||||
enter_block("Compute the polynomial H");
|
||||
const qap_witness<Fr<ppT> > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3);
|
||||
leave_block("Compute the polynomial H");
|
||||
|
||||
#ifdef DEBUG
|
||||
const Fr<ppT> t = Fr<ppT>::random_element();
|
||||
qap_instance_evaluation<Fr<ppT> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(constraint_system, t);
|
||||
assert(qap_inst.is_satisfied(qap_wit));
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i)
|
||||
{
|
||||
assert(pk.A_query[i].g == G1<ppT>::zero());
|
||||
}
|
||||
#endif
|
||||
|
||||
enter_block("Compute the proof");
|
||||
|
||||
enter_block("Compute answer to A-query", false);
|
||||
auto g_A = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, pk.A_query, qap_wit.d1);
|
||||
leave_block("Compute answer to A-query", false);
|
||||
|
||||
enter_block("Compute answer to B-query", false);
|
||||
auto g_B = r1cs_compute_proof_kc<ppT, G2<ppT>, G1<ppT> >(qap_wit, pk.B_query, qap_wit.d2);
|
||||
leave_block("Compute answer to B-query", false);
|
||||
|
||||
enter_block("Compute answer to C-query", false);
|
||||
auto g_C = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, pk.C_query, qap_wit.d3);
|
||||
leave_block("Compute answer to C-query", false);
|
||||
|
||||
enter_block("Compute answer to H-query", false);
|
||||
auto g_H = r1cs_compute_proof_H<ppT>(qap_wit, pk.H_query);
|
||||
leave_block("Compute answer to H-query", false);
|
||||
|
||||
enter_block("Compute answer to K-query", false);
|
||||
G1<ppT> zk_shift = qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] +
|
||||
qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] +
|
||||
qap_wit.d3*pk.K_query[qap_wit.num_variables()+3];
|
||||
G1<ppT> g_K = r1cs_compute_proof_K<ppT>(qap_wit, pk.K_query, zk_shift);
|
||||
leave_block("Compute answer to K-query", false);
|
||||
|
||||
leave_block("Compute the proof");
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_prover");
|
||||
|
||||
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_proof<ppT>(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K));
|
||||
|
||||
return proof;
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
|
||||
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_prover_streaming");
|
||||
|
||||
const Fr<ppT> d1 = Fr<ppT>::random_element(),
|
||||
d2 = Fr<ppT>::random_element(),
|
||||
d3 = Fr<ppT>::random_element();
|
||||
|
||||
enter_block("Compute the polynomial H");
|
||||
const qap_witness<Fr<ppT> > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3);
|
||||
leave_block("Compute the polynomial H");
|
||||
|
||||
enter_block("Compute the proof");
|
||||
|
||||
r1cs_ppzksnark_proof<ppT> proof;
|
||||
|
||||
enter_block("Compute answer to A-query", false);
|
||||
{
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query;
|
||||
proving_key_file >> A_query;
|
||||
proof.g_A = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, A_query, qap_wit.d1);
|
||||
}
|
||||
leave_block("Compute answer to A-query", false);
|
||||
|
||||
enter_block("Compute answer to B-query", false);
|
||||
{
|
||||
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query;
|
||||
proving_key_file >> B_query;
|
||||
proof.g_B = r1cs_compute_proof_kc<ppT, G2<ppT>, G1<ppT> >(qap_wit, B_query, qap_wit.d2);
|
||||
}
|
||||
leave_block("Compute answer to B-query", false);
|
||||
|
||||
enter_block("Compute answer to C-query", false);
|
||||
{
|
||||
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query;
|
||||
proving_key_file >> C_query;
|
||||
proof.g_C = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, C_query, qap_wit.d3);
|
||||
}
|
||||
leave_block("Compute answer to C-query", false);
|
||||
|
||||
enter_block("Compute answer to H-query", false);
|
||||
{
|
||||
G1_vector<ppT> H_query;
|
||||
proving_key_file >> H_query;
|
||||
proof.g_H = r1cs_compute_proof_H<ppT>(qap_wit, H_query);
|
||||
}
|
||||
leave_block("Compute answer to H-query", false);
|
||||
|
||||
enter_block("Compute answer to K-query", false);
|
||||
{
|
||||
G1_vector<ppT> K_query;
|
||||
proving_key_file >> K_query;
|
||||
G1<ppT> zk_shift = qap_wit.d1*K_query[qap_wit.num_variables()+1] +
|
||||
qap_wit.d2*K_query[qap_wit.num_variables()+2] +
|
||||
qap_wit.d3*K_query[qap_wit.num_variables()+3];
|
||||
proof.g_K = r1cs_compute_proof_K<ppT>(qap_wit, K_query, zk_shift);
|
||||
}
|
||||
leave_block("Compute answer to K-query", false);
|
||||
|
||||
leave_block("Compute the proof");
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_prover_streaming");
|
||||
|
||||
return proof;
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key<ppT> &vk)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_verifier_process_vk");
|
||||
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> pvk;
|
||||
pvk.pp_G2_one_precomp = ppT::precompute_G2(G2<ppT>::one());
|
||||
pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2);
|
||||
pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1);
|
||||
pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2);
|
||||
pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2);
|
||||
pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2);
|
||||
pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1);
|
||||
pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2);
|
||||
|
||||
pvk.encoded_IC_query = vk.encoded_IC_query;
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_verifier_process_vk");
|
||||
|
||||
return pvk;
|
||||
}
|
||||
|
||||
template <typename ppT>
|
||||
bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
assert(pvk.encoded_IC_query.domain_size() >= primary_input.size());
|
||||
|
||||
const accumulation_vector<G1<ppT> > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk<Fr<ppT> >(primary_input.begin(), primary_input.end(), 0);
|
||||
const G1<ppT> &acc = accumulated_IC.first;
|
||||
|
||||
if (!proof.is_well_formed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
G1_precomp<ppT> proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g);
|
||||
G1_precomp<ppT> proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h);
|
||||
Fqk<ppT> kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp);
|
||||
Fqk<ppT> kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp);
|
||||
GT<ppT> kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse());
|
||||
if (kc_A != GT<ppT>::one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
G2_precomp<ppT> proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g);
|
||||
G1_precomp<ppT> proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h);
|
||||
Fqk<ppT> kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp);
|
||||
Fqk<ppT> kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp);
|
||||
GT<ppT> kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse());
|
||||
if (kc_B != GT<ppT>::one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
G1_precomp<ppT> proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g);
|
||||
G1_precomp<ppT> proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h);
|
||||
Fqk<ppT> kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp);
|
||||
Fqk<ppT> kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp);
|
||||
GT<ppT> kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse());
|
||||
if (kc_C != GT<ppT>::one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C)
|
||||
// equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1)
|
||||
G1_precomp<ppT> proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc);
|
||||
G1_precomp<ppT> proof_g_H_precomp = ppT::precompute_G1(proof.g_H);
|
||||
Fqk<ppT> QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp);
|
||||
Fqk<ppT> QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp);
|
||||
GT<ppT> QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse());
|
||||
if (QAP != GT<ppT>::one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
G1_precomp<ppT> proof_g_K_precomp = ppT::precompute_G1(proof.g_K);
|
||||
G1_precomp<ppT> proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
|
||||
Fqk<ppT> K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp);
|
||||
Fqk<ppT> K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp);
|
||||
GT<ppT> K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse());
|
||||
if (K != GT<ppT>::one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_verifier_weak_IC");
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
|
||||
bool result = r1cs_ppzksnark_online_verifier_weak_IC<ppT>(pvk, primary_input, proof);
|
||||
leave_block("Call to r1cs_ppzksnark_verifier_weak_IC");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
bool result = true;
|
||||
enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
|
||||
|
||||
if (pvk.encoded_IC_query.domain_size() != primary_input.size())
|
||||
{
|
||||
print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size());
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof);
|
||||
}
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_verifier_strong_IC");
|
||||
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
|
||||
bool result = r1cs_ppzksnark_online_verifier_strong_IC<ppT>(pvk, primary_input, proof);
|
||||
leave_block("Call to r1cs_ppzksnark_verifier_strong_IC");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ppT>
|
||||
bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
|
||||
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
|
||||
const r1cs_ppzksnark_proof<ppT> &proof)
|
||||
{
|
||||
enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
|
||||
assert(vk.encoded_IC_query.domain_size() >= primary_input.size());
|
||||
|
||||
affine_ate_G2_precomp<ppT> pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2<ppT>::one());
|
||||
affine_ate_G2_precomp<ppT> pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2);
|
||||
affine_ate_G1_precomp<ppT> pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1);
|
||||
affine_ate_G2_precomp<ppT> pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2);
|
||||
affine_ate_G2_precomp<ppT> pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2);
|
||||
affine_ate_G2_precomp<ppT> pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2);
|
||||
affine_ate_G1_precomp<ppT> pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1);
|
||||
affine_ate_G2_precomp<ppT> pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2);
|
||||
|
||||
enter_block("Compute input-dependent part of A");
|
||||
const accumulation_vector<G1<ppT> > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk<Fr<ppT> >(primary_input.begin(), primary_input.end(), 0);
|
||||
assert(accumulated_IC.is_fully_accumulated());
|
||||
const G1<ppT> &acc = accumulated_IC.first;
|
||||
leave_block("Compute input-dependent part of A");
|
||||
|
||||
bool result = true;
|
||||
enter_block("Check knowledge commitment for A is valid");
|
||||
affine_ate_G1_precomp<ppT> proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g);
|
||||
affine_ate_G1_precomp<ppT> proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h);
|
||||
Fqk<ppT> kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp);
|
||||
GT<ppT> kc_A = ppT::final_exponentiation(kc_A_miller);
|
||||
|
||||
if (kc_A != GT<ppT>::one())
|
||||
{
|
||||
print_indent(); printf("Knowledge commitment for A query incorrect.\n");
|
||||
result = false;
|
||||
}
|
||||
leave_block("Check knowledge commitment for A is valid");
|
||||
|
||||
enter_block("Check knowledge commitment for B is valid");
|
||||
affine_ate_G2_precomp<ppT> proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g);
|
||||
affine_ate_G1_precomp<ppT> proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h);
|
||||
Fqk<ppT> kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp);
|
||||
GT<ppT> kc_B = ppT::final_exponentiation(kc_B_miller);
|
||||
if (kc_B != GT<ppT>::one())
|
||||
{
|
||||
print_indent(); printf("Knowledge commitment for B query incorrect.\n");
|
||||
result = false;
|
||||
}
|
||||
leave_block("Check knowledge commitment for B is valid");
|
||||
|
||||
enter_block("Check knowledge commitment for C is valid");
|
||||
affine_ate_G1_precomp<ppT> proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g);
|
||||
affine_ate_G1_precomp<ppT> proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h);
|
||||
Fqk<ppT> kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp);
|
||||
GT<ppT> kc_C = ppT::final_exponentiation(kc_C_miller);
|
||||
if (kc_C != GT<ppT>::one())
|
||||
{
|
||||
print_indent(); printf("Knowledge commitment for C query incorrect.\n");
|
||||
result = false;
|
||||
}
|
||||
leave_block("Check knowledge commitment for C is valid");
|
||||
|
||||
enter_block("Check QAP divisibility");
|
||||
affine_ate_G1_precomp<ppT> proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc);
|
||||
affine_ate_G1_precomp<ppT> proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H);
|
||||
Fqk<ppT> QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp);
|
||||
GT<ppT> QAP = ppT::final_exponentiation(QAP_miller);
|
||||
if (QAP != GT<ppT>::one())
|
||||
{
|
||||
print_indent(); printf("QAP divisibility check failed.\n");
|
||||
result = false;
|
||||
}
|
||||
leave_block("Check QAP divisibility");
|
||||
|
||||
enter_block("Check same coefficients were used");
|
||||
affine_ate_G1_precomp<ppT> proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K);
|
||||
affine_ate_G1_precomp<ppT> proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
|
||||
Fqk<ppT> K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp);
|
||||
GT<ppT> K = ppT::final_exponentiation(K_miller);
|
||||
if (K != GT<ppT>::one())
|
||||
{
|
||||
print_indent(); printf("Same-coefficient check failed.\n");
|
||||
result = false;
|
||||
}
|
||||
leave_block("Check same coefficients were used");
|
||||
|
||||
leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
#endif // R1CS_PPZKSNARK_TCC_
|
||||
@@ -0,0 +1,34 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of public-parameter selector for the R1CS ppzkSNARK.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef R1CS_PPZKSNARK_PARAMS_HPP_
|
||||
#define R1CS_PPZKSNARK_PARAMS_HPP_
|
||||
|
||||
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/**
|
||||
* Below are various template aliases (used for convenience).
|
||||
*/
|
||||
|
||||
template<typename ppT>
|
||||
using r1cs_ppzksnark_constraint_system = r1cs_constraint_system<Fr<ppT> >;
|
||||
|
||||
template<typename ppT>
|
||||
using r1cs_ppzksnark_primary_input = r1cs_primary_input<Fr<ppT> >;
|
||||
|
||||
template<typename ppT>
|
||||
using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input<Fr<ppT> >;
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // R1CS_PPZKSNARK_PARAMS_HPP_
|
||||
@@ -0,0 +1,44 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
Test program that exercises the ppzkSNARK (first generator, then
|
||||
prover, then verifier) on a synthetic R1CS instance.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
|
||||
#include "common/profiling.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
|
||||
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace libsnark;
|
||||
|
||||
template<typename ppT>
|
||||
void test_r1cs_ppzksnark(size_t num_constraints,
|
||||
size_t input_size)
|
||||
{
|
||||
print_header("(enter) Test R1CS ppzkSNARK");
|
||||
|
||||
const bool test_serialization = true;
|
||||
r1cs_example<Fr<ppT> > example = generate_r1cs_example_with_binary_input<Fr<ppT> >(num_constraints, input_size);
|
||||
example.constraint_system.swap_AB_if_beneficial();
|
||||
const bool bit = run_r1cs_ppzksnark<ppT>(example, test_serialization);
|
||||
EXPECT_TRUE(bit);
|
||||
|
||||
print_header("(leave) Test R1CS ppzkSNARK");
|
||||
}
|
||||
|
||||
TEST(zk_proof_systems, r1cs_ppzksnark)
|
||||
{
|
||||
start_profiling();
|
||||
|
||||
test_r1cs_ppzksnark<alt_bn128_pp>(1000, 20);
|
||||
}
|
||||
Reference in New Issue
Block a user