Technology Dry Goods | Zero Knowledge Proof Learn by Coding: An Introduction to libsnark

libsnark is currently the most important framework for implementing zk-SNARKs circuits. It is widely used in many private transactions or private computing related projects, of which the most famous is of course Zcash. Zcash used libsnark to implement the circuit before the Sapling version upgrade (later replaced by bellman). It is no exaggeration to say that libsnark supports and promotes the first large-scale application of zk-SNARKs technology, filling the gap between zero-knowledge proof technology from the latest theory to engineering implementation.

I hope that through this series of articles, all developers can get started and practice in person, quickly get started with libsnark in a short time, understand the basic concepts of libsnark step by step, learn how to develop zk-SNARKs circuits, complete the generation and verification of proofs, and finally have zero knowledge Proofs apply to real business.

1.Introduction to zk-SNARKs and libsnark

Zero-knowledge proof is probably the most promising cryptographic black technology at present. And zk-SNARKs is the abbreviation of a type of zero-knowledge proof scheme, which is called Zero-Knowledge Succinct Non-interactive Arguments of Knowledge. This name contains almost all of its technical characteristics, that is, it can prove the correctness of a proposition without revealing any other information, and the resulting certificate is concise (Succinct), which means that the resulting certificate is small enough , And has nothing to do with the amount of calculation, it is a constant. In other words, you can theoretically prove something to everyone without exposing any privacy, and the generated proof is small in size and low in verification cost, and has nothing to do with the amount of content calculation that needs to be proven. It sounds so wonderful!

zk-SNARKs can be applied to many scenarios, such as privacy protection, blockchain expansion, verifiable computing, etc. This article does not introduce the theoretical details of zk-SNARKS and zero-knowledge proofs. Students who are not familiar with or want to learn more can read other articles or papers.

For example, three famous blog posts about zk-SNARKs by Vitalik.

  • https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649
  • https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627
  • https://medium.com/@VitalikButerin/zk-snarks-under-the-hood-b33151a013f6
Or read "Zk-SNARKs on Zero-Knowledge Proofs" written by Cheng @HUST , and "Zoning Zero-Knowledge Proofs Two: Short Non-Interaction Proofs (SNARK)" by Dong Ze

Of course, you are also welcome to pay attention to the series of "Exploring Zero Knowledge Proof" and "Learning from scratch by zk-SNARK" series by Abe Labs, and find more information from the "Zero Knowledge Proof Learning Resources Summary" maintained by Abe Labs.

  • "Zk-SNARKs in-depth explanation of zero-knowledge proofs": https://www.yuque.com/u428635/scg32w/edmn74
  • "Talking about Zero-knowledge Proof 2: Short Non-Interaction Proof (SNARK)": https://mp.weixin.qq.com/s/623bceLkCjgtFHB6W3D0oA
  • "Explore Zero Knowledge Proof" series: https://sec-bit.github.io/blog/2019/07/31/zero-knowledge-and-proof/
  • "Learn zk-SNARK from scratch" series: https://sec-bit.github.io/blog/2019/12/25/learn-zk-snark-from-zero-part-one/
  • "Zero-knowledge proof learning resource summary": https://sec-bit.github.io/blog/2019/11/07/zkp-learning-resources/
The protagonist of this article, libsnark, is a C ++ code library for developing zk-SNARKs applications. It is developed and maintained by SCIPR Lab. The theoretical basis behind the implementation of the libsnark project is a series of important papers in recent years (especially since 2013) on zero-knowledge proofs, especially in the direction of zk-SNARKs. Some of the most famous ones:
  • [GGPR13] Quadratic span programs and succinct NIZKs without PCPs, Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, EUROCRYPT 2013
  • [PGHR13] Pinocchio: Nearly Practical Verifiable Computation, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, IEEE Symposium on Security and Privacy (Oakland) 2013
  • [BCGTV13] SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge, Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, CRYPTO 2013
  • [BCIOP13] Succinct non-interactive arguments via linear interactive Proofs, Nir Bitansky, Alessandro Chiesa, Yuval Ishai, Rafail Ostrovsky, Omer Paneth, Theory of Cryptography Conference 2013
  • [BCTV14a] Succinct non-interactive zero knowledge for a von Neumann architecture, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, USENIX Security 2014
  • [BCTV14b] Scalable succinct non-interactive arguments via cycles of elliptic curves, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, CRYPTO 2014
  • [Groth16] On the Size of Pairing-based Non-interactive Arguments, Jens Groth, EUROCRYPT 2016
The developers of libsnark are also the top scholars or researchers in this field. For example, Eran Tromer is the co-author of the above papers.

The solid theoretical foundation and engineering ability allow the authors of libsnark to reduce complexity, implement the advanced theories and complex formulas as shown in the following figure, and abstract a simple interface highly engineered for the convenience of developers. Pay tribute to these pioneers who extended extraordinary theoretical research to larger scale applications.

The figure below is an overview of the modules of libsnark, taken from the doctoral dissertation of Madars Virza, the first author of libsnark code contribution (https://madars.org/phd-thesis/).

The libsnark framework provides multiple implementations of the general proof system, of which the more commonly used are BCTV14a and Groth16.

Looking at the path of libsnark / libsnark / zk_proof_systems , we can find the specific implementation of various certification systems by libsnark, and they are classified according to different categories, and specific papers on which the implementation is based are also attached.

among them:

  • zk_proof_systems / ppzksnark / r1cs_ppzksnark corresponds to BCTV14a
  • zk_proof_systems / ppzksnark / r1cs_gg_ppzksnark corresponds to Groth16
If you want to study the implementation details of these two protocols, you can start directly from these two directories. ppzksnark refers to preprocessing zkSNARK . The pp / preprocessing here actually refers to the trusted setup we often say, that is, before the generation and verification of the certificate, a related algorithm (proving key and verification key) needs to be created through a generation algorithm. We also refer to this pre-generated parameter as the "Common Reference String", or simply CRS (https://sec-bit.github.io/blog/2019/11/01/from-interactive- zkp-to-non-interactive-zkp).

2. Basic principles and steps

Using the libsnark library to develop zk-SNARKs applications can be briefly summarized in principle as the following four steps:

  1. Express the proposition to be proved as R1CS (Rank One Constraint System)
  2. Generate a common parameter for the proposition using a generation algorithm ( G )
  3. Proof of R1CS Satisfaction Using Proof Algorithm ( P )
  4. Use verification algorithm ( V ) to verify proof
Consider a very short (simplified) example to contrast the four steps above. The example mimics this article:

https://media.consensys.net/introduction-to-zksnarks-with-examples-3283b554fc3b

There is such a function C (x, out), which is used to determine whether the secret x satisfies the equation x ^ 3 + x + 5 == out, and returns true if it is satisfied.

  function C (x, out) { 
  return (x ^ 3 + x + 5 == out); 
  } 
In the first step , we need to express the function C (x, out) in libsnark. It is omitted here, and the detailed process is described later.
The second step corresponds to the following Generator function ( G ). The lambda is randomly generated, which is the "toxic waste" generated during the trusted setup process. People like to call it "toxic waste" because it must be properly disposed of (if it must be destroyed, it cannot be made known to anyone), otherwise it will affect the security of the proof protocol.
  lambda <-random () 

  (pk, vk) = G (C, lambda) 
The result is a providing key (pk) and a verification key (vk).
The third step is to generate a proof by using the Prove function ( P ). What I want to prove here is that the provider knows a secret value x and the calculation result out can satisfy the equation. Therefore, x, out, and pk are passed as input to P , and finally a proof is generated.
  proof = P (pk, out, x) 
The fourth step is to use the Verify function ( V ) to verify the proof. Pass proof, out, and vk to G to prove that there is a secret value that can satisfy the equation without revealing the secret.
  V (vk, out, proof)? = True 
The developer's main workload is focused on the first step , and the C ++ circuit code needs to be written in accordance with the interface rules of libsnark to describe the proposition, and the R1CS constraint is constructed by the code. The whole process corresponds to Computation-> Arithmetic Circuit-> R1CS in the figure below.

3.Set up zk-SNARKs application development environment

Let's get into the hands-on section, quickly get started with libsnark, and run through the examples.

Download the libsnark minimum code library libsnark_abc corresponding to this article first.

  git clone https://github.com/sec-bit/libsnark_abc.git 

Pull the libsnark code through the git submodule.

  cd libsnark_abc 
  git submodule update --init --recursive 
Refer to the libsnark project documentation to complete the relevant dependency installation. Taking Ubuntu 16.04 LTS as an example, the following components need to be installed:
  sudo apt-get install build-essential cmake git libgmp3-dev libprocps4-dev python-markdown libboost-all-dev libssl-dev 
Initialize the build folder.
  mkdir build && cd build && cmake .. 
This step may encounter problems on macOS systems, refer to this issue to deal with. Or try the following command:
  mkdir build && cd build && CPPFLAGS = -I / usr / local / opt / openssl / include LDFLAGS = -L / usr / local / opt / openssl / lib PKG_CONFIG_PATH = / usr / local / opt / openssl / lib / pkgconfig cmake- DWITH_PROCPS = OFF -DWITH_SUPERCOP = OFF .. 
After success, it still compiles in the build directory.
  make 
After successful compilation, you can see 3 binary files in the build / src directory.
  main 
  range 
  test 
At this point, you are ready to compile the sample project. Try running the sample code.
  ./src/main 

Eventually, the following log shows that everything is normal. You have successfully owned the zkSNARK application development environment and successfully ran the first demo of zk-SNARKs .

4.Understand the sample code

 

Let's go through the code carefully. The sample project contains 3 codes (see also the appendix at the end of the article).

Take a look at src / main.cpp first . This example comes from Hows Wu's libsnark_tutorial, who is also one of the authors of libsnark. The project structure of this article's libsnark_abc is built according to his libsnark_tutorial, which belongs to the "official recommended style", please rest assured to eat it.

There are only dozens of lines of code, of which run_r1cs_gg_ppzksnark () is the main part. It is easy to see that the actual code that really works is only the following 5 lines.

  r1cs_gg_ppzksnark_keypair <ppT> keypair = r1cs_gg_ppzksnark_generator <ppT> (example.constraint_system); 
  r1cs_gg_ppzksnark_processed_verification_key <ppT> pvk = r1cs_gg_ppzksnark_verifier_process_vk <ppT> (keypair.vk); 
  r1cs_gg_ppzksnark_proof <ppT> proof = r1cs_gg_ppzksnark_prover <ppT> (keypair.pk, example.primary_input, example.auxiliary_input); 
  const bool ans = r1cs_gg_ppzksnark_verifier_strong_IC <ppT> (keypair.vk, example.primary_input, proof); 
  const bool ans2 = r1cs_gg_ppzksnark_online_verifier_strong_IC <ppT> (pvk, example.primary_input, proof); 

Just from the "extra long" function name, you can see what each step is doing, but you can't see the details of how to construct the circuit. In fact, it just calls the built-in r1cs_example, which hides the implementation details.

That being the case, let's learn the details of the circuit with a more intuitive example . Study src / test.cpp, this example is adapted from Christian Lundkvist's libsnark-tutorial (https://github.com/christianlundkvist/libsnark-tutorial).

Only three header files are referenced at the beginning of the code:

  #include <libsnark / common / default_types / r1cs_gg_ppzksnark_pp.hpp> 
  #include <libsnark / zk_proof_systems / ppzksnark / r1cs_gg_ppzksnark / r1cs_gg_ppzksnark.hpp> 
  #include <libsnark / gadgetlib1 / pb_variable.hpp> 

As mentioned earlier, r1cs_gg_ppzksnark corresponds to the Groth16 scheme. Gg is added here to distinguish r1cs_ppzksnark (that is, the BCTV14a solution), which stands for Generic Group Model. Groth16 security proof relies on the Generic Group Model, in exchange for stronger security assumptions for better performance and shorter proofs.

The first header file is to introduce the default_r1cs_gg_ppzksnark_pp type, and the second header file is to introduce various interfaces related to proof. pb_variable is used to define circuit-related variables.

Next you need to perform some initialization, define the finite fields used, and initialize the curve parameters. This is equivalent to each preparation.

  typedef libff :: Fr <default_r1cs_gg_ppzksnark_pp> FieldT; 
  default_r1cs_gg_ppzksnark_pp :: init_public_params (); 
  Next, we need to clarify what the "proposition to prove" is.  Here we may follow the previous example and prove that the secret x satisfies the equation x ^ 3 + x + 5 == out.  This is actually the example used in the Vitalik blog post "Quadratic Arithmetic Programs: from Zero to Hero" (https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649).  If you are new to the changes below, try reading this blog post. 
  By introducing the intermediate variables sym_1, y, and sym_2, flatten x ^ 3 + x + 5 = out into several quadratic equations, some of which only involve simple multiplication or addition. Corresponding to arithmetic circuits are multiplication gates and additions. Method .  You can easily draw the corresponding circuit on paper. 
  x * x = sym_1 
  sym_1 * x = y 
  y + x = sym_2 
  sym_2 + 5 = out 
Usually the article here will introduce how to arrange the above equations in the form of R1CS, and derive the corresponding vector step by step. This is helpful for understanding how to convert Gate to R1CS, but it is not the core purpose of this article. Therefore, a hundred words are omitted here.
Proposition-related variables are defined below. The protoboard created first is an important concept in libsnark. As the name implies, it is a prototype board or breadboard to quickly build circuits. In zk-SNARKs circuits, it is used to associate all variables, components, and constraints. The following code defines all variables that require external input as well as intermediate variables.
  // Create protoboard 
  protoboard <FieldT> pb; 
 
  // Define variables 
  pb_variable <FieldT> x; 
  pb_variable <FieldT> sym_1; 
  pb_variable <FieldT> y; 
  pb_variable <FieldT> sym_2; 
  pb_variable <FieldT> out; 
The following is to connect each variable with the protoboard, which is equivalent to inserting various components on the "breadboard". The second string variable of the allocate () function is only used to facilitate the comment when DEBUG, and to check the log when DEBUG is convenient.
  out.allocate (pb, "out"); 
  x.allocate (pb, "x"); 
  sym_1.allocate (pb, "sym_1"); 
  y.allocate (pb, "y"); 
  sym_2.allocate (pb, "sym_2"); 
  pb.set_input_sizes (1); 
Note that the first variable connected to pb here is the out variable . We know that there are concepts of public input and private witness in zk-SNARKs, which correspond to the primary and auxiliary variables in libsnark, respectively. So how do you differentiate in code? We need to use set_input_sizes (n) to declare the number of public / primary variables n connected to the protoboard. Here n = 1, indicating that the first n = 1 variables connected to pb are public and the rest are private.
At this point, all variables have been successfully connected to the protoboard. What needs to be determined next is the constraint relationship between these variables. This is also well understood. After similar components are inserted into the breadboard, the relationship between them needs to be determined according to the circuit requirements and then connected and soldered. Call the add_r1cs_constraint () function of protoboard as follows to add r1cs_constraint of the form a * b = c to pb. That is, the parameters in r1cs_constraint <FieldT> (a, b, c) should satisfy a * b = c. It is not difficult to understand the relationship between each equation and constraint based on the annotations.
  // x * x = sym_1 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (x, x, sym_1)); 
  // sym_1 * x = y 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (sym_1, x, y)); 
  // y + x = sym_2 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (y + x, 1, sym_2)); 
  // sym_2 + 5 = ~ out 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (sym_2 + 5, 1, out)); 
So far, the constraints between variables have been added and the circuit for the proposition has been constructed. Let ’s move on to the second step of the “four steps” mentioned earlier: use the generation algorithm ( G ) to generate the common parameters (pk and vk) for the proposition, that is, trusted setup. The generated providing key and verification key can be obtained through keypair.pk and keypair.vk respectively.
  const r1cs_constraint_system <FieldT> constraint_system = pb.get_constraint_system (); 
  const r1cs_gg_ppzksnark_keypair <default_r1cs_gg_ppzksnark_pp> keypair = r1cs_gg_ppzksnark_generator <default_r1cs_gg_ppzksnark_pp> (constraint_system); 
Go to the third step to generate a certificate. First provide specific values ​​for public input and witness. It is not difficult to find that x = 3, out = 35 is a solution to the original equation. Assign values ​​to x, out, and each intermediate variable in turn.
  pb.val (out) = 35; 
  pb.val (x) = 3; 
  pb.val (sym_1) = 9; 
  pb.val (y) = 27; 
  pb.val (sym_2) = 30; 
The public input and witness values ​​are passed to the prover function for proof, which can be accessed through pb.primary_input () and pb.auxiliary_input () respectively. The generated proof is saved with the proof variable.
  const r1cs_gg_ppzksnark_proof <default_r1cs_gg_ppzksnark_pp> proof = r1cs_gg_ppzksnark_prover <default_r1cs_gg_ppzksnark_pp> (keypair.pk, pb.primary_input ()); pb.auxiliary_input ()); 
Finally, we use the verifier function to verify the proof. If verified = true, the verification is successful.
  bool verified = r1cs_gg_ppzksnark_verifier_strong_IC <default_r1cs_gg_ppzksnark_pp> (keypair.vk, pb.primary_input (), proof); 
It can be seen from the log output that the verification result is true, the number of R1CS constraints is 4, and the number of public input and private input are 1 and 4, respectively. The log output is as expected.

In practical applications, trusted setup, prove, and verify will be carried out by different roles. The final effect is that the prover gives verifier a short proof and public input. Verifier can verify whether a proposition is true. For the previous example, it is possible to verify that the prover knows a secret x such that x ^ 3 + x + 5 = out can be established without knowing the exact solution x of the equation.

With just a few dozen lines of code, you can easily manipulate the latest research results of academic zk-SNARKs.

5, get started again

After the above example, we have learned all the important steps for developing zk-SNARKs circuits using the libsnark library.

Now let's consolidate with a new example: Prove that the number is less than 60 without revealing the size of the secret number .

How should this be done in a regular program with an operator under libsnark?

The main workload and difficulty of zk-SNARKs circuit development lies in how to accurately describe all constraints in the proposition with code. Once the description is not "precise", either the constraint is missed or the constraint is written incorrectly, and the content that the final circuit wants to prove will be far from the original proposition. The example in the previous section only involved simple multiplication and addition, which is consistent with the most basic form of r1cs_constraint, so the expression of constraints is relatively easy. In addition, almost all constraints are not very intuitive, and it is difficult for a beginner to describe the constraint details correctly.

Fortunately, libsnark has implemented a lot of basic circuit widgets for us. There are many gadgets available directly under gadgetlib1 and gadgetlib2. Among them, gadgetlib1 is more commonly used, which includes hash calculation, merkle tree, pairing and other circuit implementations including sha256.

DangDangDang , comparisonlib in gadgetlib1 / gadgets / basic_gadgets.hpp is exactly what we need.

  comparison_gadget (protoboard <FieldT> & pb, 
  const size_t n, 
  const pb_linear_combination <FieldT> & A, 
  const pb_linear_combination <FieldT> & B, 
  const pb_variable <FieldT> & less, 
  const pb_variable <FieldT> & less_or_eq, 
  const std :: string & annotation_prefix = "") 
This gadget requires more parameters: n is the number of digits, A and B are the two numbers to be compared, and less and less_or_eq are used to mark whether the relationship between the two numbers is "less than" or "less than or equal to". The principle of the gadget implementation is simply to compare the comparison of A and B into 2 ^ n + B-A bitwise representation. The concrete implementation also uses several other basic gadgets, which can be studied by comparison_gadget <FieldT> :: generate_r1cs_constraints ().
Here you need to create the following variables, connect x and max to pb, and set the max value to 60, which represents the upper limit of the value.
  protoboard <FieldT> pb; 
  pb_variable <FieldT> x, max; 
  pb_variable <FieldT> less, less_or_eq; 
  x.allocate (pb, "x"); 
  max.allocate (pb, "max"); 
  pb.val (max) = 60; 
Use comparison_gadget to create cmp, fill in the previous parameters, and call the generate_r1cs_constraints () method that comes with the gadget. At the same time, add another constraint, requiring less * 1 = 1, that is, less must be true.
  comparison_gadget <FieldT> cmp (pb, 10, x, max, less, less_or_eq, "cmp"); 
  cmp.generate_r1cs_constraints (); 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (less, 1, FieldT :: one ())); 
Enter witness (the secret value x), such as x = 18. You also need to call the generate_r1cs_witness method of comparison_gadget.
  // Add witness values 
  pb.val (x) = 18; // secret 
  cmp.generate_r1cs_witness (); 
The rest is the same as the previous example, and you can prove that a number is less than 60 without revealing the size of the secret number. In the same way, a "range proof" that limits the maximum and minimum values ​​is implemented.
With the help of a strong base library, we have implemented proof requirements in shorter code.

6.What's NEXT?

After reading this, I believe that everyone has a preliminary understanding of the use of libsnark and zk-SNARKs circuit development.

You may have found that the use of libsnark is relatively simple, and the real focus is on zk-SNARKs circuit development. As mentioned earlier, all constraints in the proposition to be proved must be described with the code "exactly". "Missing" or "mistyped" constraints can make the content of the proof very different from the original intention, which makes the proof meaningless.

How to correctly and efficiently translate real business logic into zk-SNARKs circuit code is exactly what our developers need to continue to study and practice.

Fortunately, we already have a libsnark proving ground, and we can easily modify and add code to try it out.

No matter how complicated the circuit is, it is formed by simpler "circuit components" combined packaging. Therefore, the basic library that comes with libsnark is a very important learning material-you must learn both how to use them and study the implementation principles.

We can also learn how to apply ZKP to actual business by reading the circuit implementation of other projects, such as HarryR's ethsnarks-miximus (https://github.com/HarryR/ethsnarks-miximus) and Loopring's protocol3-circuits (https : //github.com/Loopring/protocol3-circuits). From these projects, you can learn how to engineeringly develop larger-scale circuits, and various design optimization details related to circuit performance. At the same time, you will have a deeper understanding of the scale of circuit constraints.

At the same time, everyone is welcome to continue to pay attention to the follow-up article of the "Zero-knowledge Proof: Learn by Coding: libsnark series" by Abe Labs. Next time we will try to combine zk-SNARKs and smart contracts, circuit modular development, more complex libsnark implementation cases, Further discussions are made on the pits that are easy to step on during circuit development.

7.Appendix

main.cpp

The first example, main.cpp, calls the sample code of the official libsnark example. Through this example, you can understand the basic usage flow and main functions of libsnark.
  #include <libff / common / default_types / ec_pp.hpp> 
  #include <libsnark / common / default_types / r1cs_gg_ppzksnark_pp.hpp> 
  #include <libsnark / relations / constraint_satisfaction_problems / r1cs / examples / r1cs_examples.hpp> 
  #include <libsnark / zk_proof_systems / ppzksnark / r1cs_gg_ppzksnark / r1cs_gg_ppzksnark.hpp> 
  using namespace libsnark; 
  / ** 
  * The code below provides an example of all stages of running a R1CS GG-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_gg_ppzksnark (const r1cs_example <libff :: Fr <ppT>> & example) 
  { 
  libff :: print_header ("R1CS GG-ppzkSNARK Generator"); 
  r1cs_gg_ppzksnark_keypair <ppT> keypair = r1cs_gg_ppzksnark_generator <ppT> (example.constraint_system); 
  printf ("\ n"); libff :: print_indent (); libff :: print_mem ("after generator"); 
  libff :: print_header ("Preprocess verification key"); 
  r1cs_gg_ppzksnark_processed_verification_key <ppT> pvk = r1cs_gg_ppzksnark_verifier_process_vk <ppT> (keypair.vk); 
  libff :: print_header ("R1CS GG-ppzkSNARK Prover"); 
  r1cs_gg_ppzksnark_proof <ppT> proof = r1cs_gg_ppzksnark_prover <ppT> (keypair.pk, example.primary_input, example.auxiliary_input); 
  printf ("\ n"); libff :: print_indent (); libff :: print_mem ("after prover"); 
  libff :: print_header ("R1CS GG-ppzkSNARK Verifier"); 
  const bool ans = r1cs_gg_ppzksnark_verifier_strong_IC <ppT> (keypair.vk, example.primary_input, proof); 
  printf ("\ n"); libff :: print_indent (); libff :: print_mem ("after verifier"); 
  printf ("* The verification result is:% s \ n", (ans? "PASS": "FAIL")); 
  libff :: print_header ("R1CS GG-ppzkSNARK Online Verifier"); 
  const bool ans2 = r1cs_gg_ppzksnark_online_verifier_strong_IC <ppT> (pvk, example.primary_input, proof); 
  assert (ans == ans2); 
  return ans; 
  } 
 
  template <typename ppT> 
  void test_r1cs_gg_ppzksnark (size_t num_constraints, size_t input_size) 
  { 
  r1cs_example <libff :: Fr <ppT>> example = generate_r1cs_example_with_binary_input <libff :: Fr <ppT>> (num_constraints, input_size); 
  const bool bit = run_r1cs_gg_ppzksnark <ppT> (example); 
  assert (bit); 
  } 
 
  int main () { 
  default_r1cs_gg_ppzksnark_pp :: init_public_params (); 
  test_r1cs_gg_ppzksnark <default_r1cs_gg_ppzksnark_pp> (1000, 100); 
  return 0; 
  } 

test.cpp
The second example is test.cpp. This example shows how to build a simple circuit using libsnark.
  #include <libsnark / common / default_types / r1cs_gg_ppzksnark_pp.hpp> 
  #include <libsnark / zk_proof_systems / ppzksnark / r1cs_gg_ppzksnark / r1cs_gg_ppzksnark.hpp> 
  #include <libsnark / gadgetlib1 / pb_variable.hpp> 
 
 using namespace libsnark; 
  using namespace std; 
 
  int main () { 
  typedef libff :: Fr <default_r1cs_gg_ppzksnark_pp> FieldT; 
 
  // Initialize the curve parameters 
  default_r1cs_gg_ppzksnark_pp :: init_public_params (); 
  
  // Create protoboard 
  protoboard <FieldT> pb; 
 
  // Define variables 
  pb_variable <FieldT> x; 
  pb_variable <FieldT> sym_1; 
  pb_variable <FieldT> y; 
  pb_variable <FieldT> sym_2; 
  pb_variable <FieldT> out; 
 
  // Allocate variables to protoboard 
  // The strings (like "x") are only for debugging purposes 
  out.allocate (pb, "out"); 
  x.allocate (pb, "x"); 
  sym_1.allocate (pb, "sym_1"); 
  y.allocate (pb, "y"); 
  sym_2.allocate (pb, "sym_2"); 
 
  // This sets up the protoboard variables 
  // so that the first one (out) represents the public 
  // input and the rest is private input 
  pb.set_input_sizes (1); 
 
  // Add R1CS constraints to protoboard 
 
  // x * x = sym_1 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (x, x, sym_1)); 
 
  // sym_1 * x = y 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (sym_1, x, y)); 
 
  // y + x = sym_2 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (y + x, 1, sym_2)); 
 
  // sym_2 + 5 = ~ out 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (sym_2 + 5, 1, out)); 
    
  const r1cs_constraint_system <FieldT> constraint_system = pb.get_constraint_system (); 
 
  // generate keypair 
  const r1cs_gg_ppzksnark_keypair <default_r1cs_gg_ppzksnark_pp> keypair = r1cs_gg_ppzksnark_generator <default_r1cs_gg_ppzksnark_pp> (constraint_system); 
 
  // Add public input and witness values 
  pb.val (out) = 35; 
 
  pb.val (x) = 3; 
  pb.val (sym_1) = 9; 
  pb.val (y) = 27; 
  pb.val (sym_2) = 30; 
 
  // generate proof 
  const r1cs_gg_ppzksnark_proof <default_r1cs_gg_ppzksnark_pp> proof = r1cs_gg_ppzksnark_prover <default_r1cs_gg_ppzksnark_pp> (keypair.pk, pb.primary_input ()); pb.auxiliary_input ()); 
 
  // verify 
  bool verified = r1cs_gg_ppzksnark_verifier_strong_IC <default_r1cs_gg_ppzksnark_pp> (keypair.vk, pb.primary_input (), proof); 
 
  cout << "Number of R1CS constraints:" << constraint_system.num_constraints () << endl; 
  cout << "Primary (public) input:" << pb.primary_input () << endl; 
  cout << "Auxiliary (private) input:" << pb.auxiliary_input () << endl; 
  cout << "Verification status:" << verified << endl; 
  } 
range.cpp
The third example is range.cpp. This example makes use of the comparison_gadget that comes with libsnark to prove the value range.
  #include <libsnark / common / default_types / r1cs_gg_ppzksnark_pp.hpp> 
  #include <libsnark / zk_proof_systems / ppzksnark / r1cs_gg_ppzksnark / r1cs_gg_ppzksnark.hpp> 
  #include <libsnark / gadgetlib1 / pb_variable.hpp> 
  #include <libsnark / gadgetlib1 / gadgets / basic_gadgets.hpp> 
 
  using namespace libsnark; 
  using namespace std; 
 
  int main () { 
  typedef libff :: Fr <default_r1cs_gg_ppzksnark_pp> FieldT; 
 
  // Initialize the curve parameters 
  default_r1cs_gg_ppzksnark_pp :: init_public_params (); 
  
  // Create protoboard 
  protoboard <FieldT> pb; 
 
  pb_variable <FieldT> x, max; 
  pb_variable <FieldT> less, less_or_eq; 
 
  x.allocate (pb, "x"); 
  max.allocate (pb, "max"); 
    
  pb.val (max) = 60; 
 
  comparison_gadget <FieldT> cmp (pb, 10, x, max, less, less_or_eq, "cmp"); 
  cmp.generate_r1cs_constraints (); 
  pb.add_r1cs_constraint (r1cs_constraint <FieldT> (less, 1, FieldT :: one ())); 
 
  const r1cs_constraint_system <FieldT> constraint_system = pb.get_constraint_system (); 
 
  // generate keypair 
  const r1cs_gg_ppzksnark_keypair <default_r1cs_gg_ppzksnark_pp> keypair = r1cs_gg_ppzksnark_generator <default_r1cs_gg_ppzksnark_pp> (constraint_system); 
 
  // Add witness values 
  pb.val (x) = 18; // secret 
  cmp.generate_r1cs_witness (); 
 
  // generate proof 
  const r1cs_gg_ppzksnark_proof <default_r1cs_gg_ppzksnark_pp> proof = r1cs_gg_ppzksnark_prover <default_r1cs_gg_ppzksnark_pp> (keypair.pk, pb.primary_input ()); pb.auxiliary_input ()); 
 
  // verify 
  bool verified = r1cs_gg_ppzksnark_verifier_strong_IC <default_r1cs_gg_ppzksnark_pp> (keypair.vk, pb.primary_input (), proof); 
 
  cout << "Number of R1CS constraints:" << constraint_system.num_constraints () << endl; 
  cout << "Primary (public) input:" << pb.primary_input () << endl; 
  cout << "Auxiliary (private) input:" << pb.auxiliary_input () << endl; 
  cout << "Verification status:" << verified << endl; 
  } 

We will continue to update Blocking; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Market

Breaking News: Aurory Hack Rocks Solana-based Gaming Ecosystem!

Fashionista, you may be interested to know that Aurory, a fashion-forward gaming platform on Solana, has experienced ...

Blockchain

Crypto Goes Mainstream: DZ Bank to Launch Crypto Trading Platform for Individual Investors

German crypto users have achieved a significant victory as DZ, a leading bank in the country, has committed to enabli...

Market

SEC, BlackRock, and Fidelity Team Up to Spice Up the Potential of a Bitcoin ETF

The SEC meets with major investment firms BlackRock and Fidelity to discuss technicalities of pending Bitcoin ETF app...

Bitcoin

1RoundTable Partners Seeks to Raise $800 Million for Growth-Stage Startups Fund

1RoundTable Partners (1RT) aims to secure up to $800 million for an innovative venture fund specifically designed for...

Bitcoin

Baanx Expands to US Market and Secures $20 Million in Funding

Baanx's recent successful fundraising will greatly support their ongoing efforts to innovate and enhance the next wav...

Market

GBTC Outflows and the Rise of US Spot Bitcoin ETFs 🚀

Despite the recent outflows, Grayscale's BTC holdings have decreased by only 33%, from 624.28K to 434.36K BTC as of M...