By using this site, you agree to our use of cookies, which we use to analyse our traffic in accordance with our Privacy Policy. We also share information about your use of our site with our analytics partners.

R&D

gnark: Your Guide to Write zkSNARKs in Go

gnark is a high-performance, open-source library that enables effective zkSNARK applications.
by Gautam BortrelNovember 22, 2022
gnark  Your Guide to Writ zkSNARKs in Go

zkSNARKs have important applications for blockchains, especially for scalability and privacy. It is an acronym  for zero-knowledge succinct non-interactive argument of knowledge and refers to a family of cryptographic protocols that allows a party to prove to another that it holds some information, without disclosing that information, in a very short amount of time. 

This recent write up by A16Z gives a sense of the current landscape of SNARKs. ConsenSys R&D develops gnark – a high-performance, open-source zkSNARK library. 

The zero-knowledge research space is booming with advancements in programmability (verifying execution trace of virtual machines inside a SNARK), and performance (new schemes, better composability, hardware-implementations).

Virtual machines in SNARKs, like the zkEVM our colleagues are working on, offer great advances towards programmability. We can see these zkVMs as a single zkSNARK circuit capable of verifying executions of many different programs.

Specialized circuits – one zkSNARK circuit per program – still make a lot of sense where performance is critical (for example; to verify the inner proof of a zkVM execution on the blockchain) or at the protocol level (bridges, light clients, privacy-preserving protocols). gnark’s goal is to enable efficient specialized circuits.

In this post, we will learn more about gnark and walk through some on-going work our research teams are doing.

A Tour of gnark

gnark circuits are written in plain Go and can be integrated in complex solutions like any other Go module. Serialization, web-services, logging, are all but a couple of lines of code away.

gnark’s philosophy is simple; no domain-specific language (DSL), one codebase without external dependencies which integrates and performs well on server, browser, and mobile. gnark ensures a smooth learning curve, a mature tool chain, and blazingly fast compile and proving times. Go enables all this and a battle-tested developer environment, which includes dependency management, unit tests, benchmarking, IDE integration. These features are stable, free, and used and maintained by hundreds of thousands of users. 

Source: gnark Playground

gnark supports several elliptic curves and multiple backends (Groth16, PlonK w/ KZG or FRI), with more to come. In particular, we are looking at recursion, emulated arithmetic, GKR (faster hash verification) and new field-agnostic proof systems.

zkSNARK workflow

Let’s walk through an example. We are going to prove that a BLS signature is valid, inside a SNARK. 

To do so, we use bls12-377/bw6-761 forming a 2-chain. The BLS signature is defined over bls12-377 base field, which happens to be bw6-761 scalar field; in other words, we are going to instantiate a SNARK over bw6-761 (the outer curve) and prove a statement defined on bls12-377 (the inner curve). This recursion technique can be used to verify SNARKs inside of a SNARK very efficiently. 

This leverages on our “in-circuit” pairing implementation in 11.5k constraints, which is, to the best of our knowledge, the most efficient to date.

First we define the circuit:

Screenshot 2022 11 23 at 3 32 52 PM

Then we define the constraints (using gnark/std/algebra).

Screenshot 2022 11 23 at 3 34 44 PM

And compile the constraint system:

Screenshot 2022 11 23 at 3 35 42 PM

gnark helps identify performance bottlenecks by outputting pprof compatible data. Here we can see the graph of the constraints generated by the example circuit. 

Finally we run the setup/prove/verify algorithms:

Screenshot 2022 11 23 at 3 38 04 PM

Alternatively, gnark exposes a test engine, which doesn’t build a constraint system but simply executes the circuit Define method. It makes it extremely convenient to debug, fuzz-test or cross-test against “out-of-circuit” implementation.

Screenshot 2022 11 23 at 3 38 42 PM

Checkout the documentation to learn more about features like compiler hints, and the online playground to explore more examples. 

gnark is Blazingly Fast

On low-level primitives like the pairing or the field multiplication, gnark-crypto outperforms most libraries out there. It translates well up-the-stack – gnark compiles gigantic circuits in seconds, and its solver (aka witness generation), prover and verifier are significantly faster than circom/rapidsnark or arkworks. For protocols like zk-Rollups, this translates directly in throughput on the network.

Groth16 prover time, 65k and 8M constraints (AWS hpc6a instance)

Groth16 verifier time (AWS hpc6a instance)

We recently participated in the ZPrize competition (accelerating primitives used in zkSNARKs); our gnark-crypto based submission to the Mobile track is ~78% faster than the baseline benchmark. 

gnark-crypto provides components of independent interest, ranging from field arithmetic to polynomial commitment schemes (e.g. KZG). The image below gives an overview of the packages.

All primitives in gnark-crypto can be used independently from gnark. 

If you are interested in our work or want to contribute, give us a shout