libsnark is a C++ library for zkSNARK proofs. The library was originally developed by SCIPR Lab and contributors (see AUTHORS file) and is released under the MIT License (see LICENSE file).
This library implements zkSNARK schemes, which are a cryptographic method for proving/verifying, in zero knowledge, the integrity of computations.
A computation can be expressed as an NP statement, in forms such as the following:
A prover who knows the witness for the NP statement (i.e., a satisfying input/assignment) can produce a short proof attesting to the truth of the NP statement. This proof can be verified by anyone, and offers the following properties.
These properties are summarized by the zkSNARK acronym, which stands for Zero-Knowledge Succinct Non-interactive ARgument of Knowledge (though zkSNARKs are also knows as succinct non-interactive computationally-sound zero-knowledge proofs of knowledge). For formal definitions and theoretical discussions about these, see [BCCT12], [BCIOP13], and the references therein.
The libsnark library currently provides a C++ implementation of:
General-purpose proof systems:
A preprocessing zkSNARK for the NP-complete language "R1CS" (Rank-1 Constraint Systems), which is a language that is similar to arithmetic circuit satisfiability.
This zkSNARK construction follows, extends, and optimizes the approach described in [BCTV14a], itself an extension of [BCGTV13], following the approach of [GGPR13] and [BCIOP13]. (An alternative implementation of this approach is the Pinocchio system of [PGHR13].)
See the above references for discussions of efficiency aspects that arise in practical use of such constructions, as well as security and trust considerations.
This scheme is a preprocessing zkSNARK (ppzkSNARK): before proofs can be created and verified, one needs to first decide on a size/circuit/system representing the NP statements to be proved, and run a generator algorithm to create corresponding public parameters (a long proving key and a short verification key).
Using the library involves the following high-level steps:
The ppzkSNARK supports proving/verifying membership in a specific NP-complete language: R1CS (rank-1 constraint systems). An instance of the language is specified by a set of equations over a prime field F, and each equation looks like: < A, (1,X) > * < B , (1,X) > = < C, (1,X) > where A,B,C are vectors over F, and X is a vector of variables.
In particular, arithmetic (as well as boolean) circuits are easily reducible to this language by converting each gate into a rank-1 constraint. See [BCGTV13] Appendix E (and "System of Rank 1 Quadratic Equations") for more details about this.
The ppzkSNARK can be instantiated with different parameter choices, depending on which elliptic curve is used (see curves supported in libff)
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.
The theoretical security of the underlying mathematical constructions, and the requisite assumptions, are analyzed in detailed in the aforementioned research papers.
This code is a research-quality proof of concept, and has not yet undergone extensive review or testing. It is thus not suitable, as is, for use in critical or production systems.
Known issues include the following:
The ppzkSNARK's generator and prover exhibit data-dependent running times and memory usage. These form timing and cache-contention side channels, which may be an issue in some applications.
Randomness is retrieved from /dev/urandom, but this should be changed to a carefully considered (depending on system and threat model) external, high-quality randomness source when creating long-term proving/verification keys.
The libsnark library relies on the following:
Furthermore, Doxygen is used to generate the documentation.
So far we have tested these only on Linux, though we have been able to make the libsnark work, with some features disabled (such as memory profiling or GTest tests), on Windows via Cygwin and on Mac OS X. See also the notes on portability below. (If you port libsnark to additional platforms, please let us know!)
Concretely, here are the requisite packages in some Linux distributions:
sudo apt install \
build-essential \
git \
libboost-all-dev \
cmake \
libgmp3-dev \
libssl-dev \
libprocps-dev \
pkg-config
sudo apt-get install \
build-essential \
cmake \
git \
libgmp3-dev \
libprocps4-dev \
libboost-all-dev \
libssl-dev
sudo apt-get install \
build-essential \
cmake \
git \
libgmp3-dev \
libprocps3-dev \
libboost-all-dev \
libssl-dev
sudo yum install \
gcc-c++ \
cmake \
make \
git \
gmp-devel \
procps-ng-devel
Fetch dependencies from their GitHub repos:
git submodule update --init --recursive
Create the Makefile:
mkdir build && cd build && cmake ..
Then, to compile the library, tests, and profiling harness, run this within the build
directory:
make
To create the Doxygen documentation, run:
# Make sure to install doxygen if not already
# e.g. on Ubuntu run: apt-get install doxygen graphviz
cd build && cmake .. -DGEN_DOC=ON && make docs
To compile and run the tests for this library, run:
make check
To develop an application that uses libsnark, it's recommended to use your own build system that incorporates libsnark and dependencies. If you're using CMake, add libsnark as a git submodule, and then add it as a subdirectory. Then, add snark
as a library dependency to the appropriate rules.
To build and install the libsnark library:
DESTDIR=/install/path make install
This will install libsnark.a
into /install/path/lib
; so your application should be linked using -L/install/path/lib -lsnark
. It also installs the requisite headers into /install/path/include
; so your application should be compiled using -I/install/path/include
.
In addition, unless you use WITH_SUPERCOP=OFF
, libsnark_adsnark.a
will be installed and should be linked in using -lsnark_adsnark
.
When you use compile your application against libsnark
, you must have the same conditional defines (#define FOO
or g++ -DFOO
) as when you compiled libsnark
, due to the use of templates. One way to figure out the correct conditional defines is to look at build/libsnark/CMakeFiles/snark.dir/flags.make
after running cmake
. (Issue #21)
Install Cygwin using the graphical installer, including the g++
, libgmp
, cmake
, and git
packages. Then disable the dependencies not easily supported under CygWin, using:
cmake -DWITH_PROCPS=OFF ..
On Mac OS X, install GMP from MacPorts (port install gmp
). Then disable the
dependencies not easily supported under OS X, using:
cmake -DWITH_PROCPS=OFF ..
MacPorts does not write its libraries into standard system folders, so you
might need to explicitly provide the paths to the header files and libraries by
appending CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib
to the line
above.
Check CMakelists.txt for the whole list of build options. Some details are provided below.
cmake -DCURVE=choice
(where choice
is one of: ALT_BN128, BN128, EDWARDS, MNT4, MNT6): Set the default curve to one of the above (see elliptic curve choices).
cmake -DLOWMEM=ON
: Limit the size of multi-exponentiation tables, for low-memory platforms.
cmake -DWITH_PROCPS=OFF
: Do not link against libprocps. This disables memory profiling.
cmake -DWITH_SUPERCOP=OFF
: Do not link against SUPERCOP for optimized crypto. The ADSNARK executables will not be built.
cmake -DMULTICORE=ON
: Enable parallelized execution of the ppzkSNARK generator and prover, using OpenMP. This will utilize all cores on the CPU for heavyweight parallelizable operations such as FFT and multiexponentiation. The default is single-core. To override the maximum number of cores used, set the environment variable OMP_NUM_THREADS
at runtime (not compile time), e.g., OMP_NUM_THREADS=8 test_r1cs_sp_ppzkpc
. It defaults to the autodetected number of cores, but on some devices, dynamic core management confused OpenMP's autodetection, so setting OMP_NUM_THREADS
is necessary for full utilization.
cmake -DUSE_PT_COMPRESSION=OFF
: Do not use point compression. This gives much faster serialization times, at the expense of ~2x larger sizes for serialized keys and proofs.
cmake -DMONTGOMERY_OUTPUT=ON
: Serialize Fp elements as their Montgomery representations. If this option is disabled then Fp elements are serialized as their equivalence classes, which is slower but produces human-readable output.
cmake -DBINARY_OUTPUT=ON
: In serialization, output raw binary data (instead of decimal), which is smaller and faster.
cmake -DPROFILE_OP_COUNTS=ON
: Collect counts for field and curve operations inside static variables of the corresponding algebraic objects. This option works for all curves except bn128.
cmake -DUSE_ASM=ON
: Use architecture-specific assembly routines for F[p] arithmetic and heap in multi-exponentiation. (If disabled, use GMP's mpn_*
routines instead.)
cmake -DPERFORMANCE=ON
: Enables compiler optimizations such as link-time optimization, and disables debugging aids. (On some distributions this causes a plugin needed to handle lto object
link error and undefined reference
s, which can be remedied by AR=gcc-ar make ...
.)
cmake -DOPT_FLAGS=...
: Set the C++ compiler optimization flags, overriding the default (e.g., -DOPT_FLAGS="-Os -march=i386"
).
cmake -DDEPENDS_DIR=...
: Sets the dependency installation directory to the provided absolute path (default: installs dependencies in the respective submodule directories)
cmake -DUSE_LINKED_LIBRARIES=ON
: Setting this flag enables CMake to include installed libfqfft
and libff
libraries. This will tell the compiler to ignore the libfqfft
and libff
dependencies provided in the depends
folder.
Note: Not all combinations are tested together or supported by every part of the codebase.
libsnark includes a tutorial, and some usage examples, for the high-level API.
libsnark/gadgetlib1/examples1
contains a simple example for constructing a constraint system using gadgetlib1.
libsnark/gadgetlib2/examples
contains a tutorial for using gadgetlib2 to express NP statements as constraint systems. It introduces basic terminology, design overview, and recommended programming style. It also shows how to invoke ppzkSNARKs on such constraint systems. The main file, tutorial.cpp
, builds into a standalone executable.
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp
constructs a simple constraint system and runs the ppzksnark. See below for how to run it.
The command
libsnark/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.)
The command
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes
does the same but now the input consists of 10 bytes.
libsnark is written in fairly standard C++11.
However, having been developed on Linux on x86-64 CPUs, libsnark has some limitations with respect to portability. Specifically:
libsnark's algebraic data structures assume little-endian byte order.
Profiling routines use clock_gettime
and readproc
calls, which are Linux-specific.
Random-number generation is done by reading from /dev/urandom
, which is
specific to Unix-like systems.
libsnark binary serialization routines (see BINARY_OUTPUT
above) assume
a fixed machine word size (i.e. sizeof(mp_limb_t) for GMP's limb data type).
Objects serialized in binary on a 64-bit system cannot be de-serialized on
a 32-bit system, and vice versa.
(The decimal serialization routines have no such limitation.)
libsnark requires a C++ compiler with good C++11 support. It has been tested with g++ 4.7 and newer, and clang 3.4 and newer.
On x86-64, we by default use highly optimized assembly implementations for some
operations (see USE_ASM
above). On other architectures we fall back to a
portable C++ implementation, which is slower.
The ate-pairing library, require by the BN128 curve, can be compiled only on i686 and x86-64. (On other platforms, use other -DCURVE=...
choices.)
The SUPERCOP library, required by ADSNARK, can be compiled only on i686 and x86-64. (On other platforms, use -DWITH_SUPERCOP=OFF
.)
Tested configurations include:
-DWITH_SUPERCOP=OFF
)-DWITH_SUPERCOP=OFF
)-DWITH_PROCPS=OFF
and GTestdisabled)-DWITH_PROCPS=OFF
and GTest disabled)The directory structure of the libsnark library is as follows:
cmake -DDEPENDS_DIR=...
)Some of these module directories have the following subdirectories:
In particular, the top-level API examples are at libsnark/r1cs_ppzksnark/examples/
and libsnark/gadgetlib2/examples/
.
The ppzkSNARK's generator has to solve a fixed-base multi-exponentiation problem. We use a window-based method in which the optimal window size depends on the size of the multiexponentiation instance and the platform.
On our benchmarking platform (a 3.40 GHz Intel Core i7-4770 CPU), we have
computed for each curve optimal windows, provided as
fixed_base_exp_window_table
initialization sequences, for each curve; see
X_init.cpp
for X=edwards,bn128,alt_bn128.
Performance on other platforms may not be optimal (but probably not be far off). Future releases of the libsnark library will include a tool that generates optimal window sizes.
[BBFR15] ADSNARK: nearly practical and privacy-preserving proofs on authenticated data , Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, IEEE Symposium on Security and Privacy (Oakland) 2015
[BCCT12] From extractable collision resistance to succinct non-Interactive arguments of knowledge, and back again , Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, Innovations in Computer Science (ITCS) 2012
[BCCT13] Recursive composition and bootstrapping for SNARKs and proof-carrying data Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, Symposium on Theory of Computing (STOC) 13
[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
[CTV15] Cluster computing in zero knowledge , Alessandro Chiesa, Eran Tromer, Madars Virza, Eurocrypt 2015
[DFGK14] Square span programs with applications to succinct NIZK arguments , George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, ASIACCS 2014
[GM17] Snarky Signatures: Minimal Signatures of Knowledge from Simulation-Extractable SNARKs , Jens Groth and Mary Maller, IACR-CRYPTO-2017
[GGPR13] Quadratic span programs and succinct NIZKs without PCPs , Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, EUROCRYPT 2013
[ate-pairing] High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves , MITSUNARI Shigeo, TERUYA Tadanori
[PGHR13] Pinocchio: Nearly Practical Verifiable Computation , Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, IEEE Symposium on Security and Privacy (Oakland) 2013