libsnark源码中提供了两个Gadget库。
The libsnark library currently provides two libraries for conveniently constructing
R1CS instances out of reusable “gadgets”. Both libraries provide a way to construct
gadgets on other gadgets as well as additional explicit equations. In this way,
complex R1CS instances can be built bottom up.
This is a low-level library which expose all features of the preprocessing
zkSNARK for R1CS. Its design is based on templates (as does the ppzkSNARK code)
to efficiently support working on multiple elliptic curves simultaneously. This
library is used for most of the constraint-building in libsnark, both internal
(reductions and Proof-Carrying Data) and examples applications.
This is an alternative library for constructing systems of polynomial equations
and, in particular, also R1CS instances. It is better documented and easier to
use than gadgetlib1, and its interface does not use templates. However, fewer
useful gadgets are provided.
使用Gadget,可只需关注circuit的public inputs和private inputs,其它的intermediate inputs可由Gadget的generate_r1cs_witness()
函数内根据constraints
自动计算。Gadget中还包括class类的继承构造函数
及generate_r1cs_constraints()
函数实现。
以下为 https://github.com/christianlundkvist/libsnark-tutorial 中的gadget实现源码:
#include "libsnark/gadgetlib1/gadget.hpp"
using namespace libsnark;
template
class test_gadget : public gadget {
private:
pb_variable sym_1;
pb_variable y;
pb_variable sym_2;
public:
const pb_variable out;
const pb_variable x;
test_gadget(protoboard &pb,
const pb_variable &out,
const pb_variable &x) :
gadget(pb, "poly_gadget"), out(out), x(x)
{
// Allocate variables to protoboard
// The strings (like "x") are only for debugging purposes
sym_1.allocate(this->pb, "sym_1");
y.allocate(this->pb, "y");
sym_2.allocate(this->pb, "sym_2");
}
void generate_r1cs_constraints()
{
// x*x = sym_1
this->pb.add_r1cs_constraint(r1cs_constraint(x, x, sym_1));
// sym_1 * x = y
this->pb.add_r1cs_constraint(r1cs_constraint(sym_1, x, y));
// y + x = sym_2
this->pb.add_r1cs_constraint(r1cs_constraint(y + x, 1, sym_2));
// sym_2 + 5 = ~out
this->pb.add_r1cs_constraint(r1cs_constraint(sym_2 + 5, 1, out));
}
void generate_r1cs_witness()
{
this->pb.val(sym_1) = this->pb.val(x) * this->pb.val(x);
this->pb.val(y) = this->pb.val(sym_1) * this->pb.val(x);
this->pb.val(sym_2) = this->pb.val(y) + this->pb.val(x);
}
};
gadgetlib2的应用示例,可查看libsnark/gadgetlib2/examples/tutorial.cpp
中。以及在jsnark中使用的jsnark_interface中也是基于gadgetlib2构建的。在其中的CircuitReader.cpp中注明了jsnark生成的*.arith circuit文件中的one-input
与基于Pinocchio生成的约定不同。
if (wireValues[0] != FieldT::one()) {
printf(">> Warning: when using jsnark circuit generator, the first input wire (#0) must have the value of 1.\n");
printf("\t If the circuit was generated using Pinocchio *without modification*, you can ignore this warning. Pinocchio uses a different indexing for the one-wire input. \n");
}
以下为基于jsnark生成的*.arith circuit文件:(Sudoku9x9.arith)
total 3785
input 0 # The one-input wire.
const-mul-0 in 1 <0> out 1 <1>
input 2
input 3
input 4
input 5
input 6
input 7
input 8
input 9
input 10
input 11
input 12
input 13
input 14
。。。。。。
以下为基于Pinocchio生成的*.arith circuit文件:(eqtest-p0-b32.arith)
total 11
input 0 # input
input 1 # input
input 2 # one-input
const-mul-0 in 1 <2> out 1 <3> # zero
const-mul-neg-1 in 1 <1> out 1 <4> # zerop subtract negative
add in 2 <0 4> out 1 <5> # zerop diff
zerop in 1 <5> out 2 <7 6> # zerop
const-mul-neg-1 in 1 <6> out 1 <8> # zerop inverse
add in 2 <2 8> out 1 <9> # zerop result
mul in 2 <2 9> out 1 <10> # output-cast
output 10 #