Unlocking the Power of Zero Knowledge Proofs with Gnark and Go
gnark is a high-performance, open-source library that enables effective zkSNARK applications.
This article is part of a four series introduction to Zero-Knowledge Proofs:
Introduction (The Magic of Proving Without Revealing: An Introduction to Zero-Knowledge Proofs)
Example of ZK Proofs in Go (Unlocking the Power of Zero Knowledge Proofs with Gnark and Go)
Introduction
In the previous article, I’ve explained what Zero knowledge proofs (ZKPs) are a and it’s many potential applications, from enhancing privacy in blockchain transactions to improving security in cloud computing. As a programmer, you’d like to get hands on with code for understanding a complex topic. This article provides examples in Go for playing around and understanding ZK Proofs with the help of GNARK.
Gnark is a popular open-source library for building ZKPs in Go. We'll use Gnark to create a simple zero knowledge proof that demonstrates the basic concepts of ZKPs.
https://github.com/ConsenSys/gnark
What is Gnark?
Gnark is a high-performance, open-source library for creating zero-knowledge proofs, specifically zkSNARK applications. We will go into details of SNARKs vs STARKs in the next article as I wanted to explain with code how ZK Proofs work.
Gnark provides a high-level language for specifying the proof's logic, and its API allows developers to easily create, verify, and deploy zero-knowledge proofs. It also includes a built-in compiler that transforms the high-level language into a low-level representation that can be run on a variety of platforms.
Gnark is Go-based. It uses a DSL (domain-specific language) to specify circuits, which are then compiled down to an R1CS (Rank-1 Constraint System) that can be used to generate a proof. Gnark also provides a set of pre-built circuit components, such as SHA-256 and elliptic curve arithmetic, that can be used to build more complex circuits.
Features of Gnark
Gnark comes with a host of features that make it a popular choice among developers. Here are some of its key features:
User-Friendly: Gnark has been designed with user-friendliness in mind. Its high-level language, based on the Golang programming language, makes it easy for developers to write and deploy zero-knowledge proofs.
Extensible: Gnark is designed to be highly extensible, with support for a variety of cryptographic primitives, including elliptic curve cryptography, pairing-based cryptography, and more.
High-Performance: Gnark is highly optimized for performance, with a compiler that generates efficient code that can be run on a variety of platforms.
Security: Gnark uses state-of-the-art cryptographic techniques to ensure the security and privacy of its users.
Interoperability: Gnark is designed to work seamlessly with other blockchain frameworks, such as Ethereum, and is also compatible with other cryptographic libraries.
Key components of GNARK
Circuit Definition Language (Circom): It is a DSL for defining arithmetic circuits. It allows the user to define a circuit that takes in input variables, performs some computations on those variables, and produces an output.
Constraint System: It is a collection of constraints that the circuit must satisfy. The constraints are usually defined in terms of arithmetic relations between variables. Gnark provides a variety of constraint systems such as R1CS (Rank-1 Constraint System), PLONK (Permutation-based, Linear-complexity, Overlogarithmic, Non-interactive, Knowledge-proofs), and Aurora.
Proving Key and Verification Key: The proving key is used by the prover to generate a proof, while the verification key is used by the verifier to verify the proof. Both keys are generated from the circuit and constraint system.
Proof: It is a cryptographic proof generated by the prover, which can be verified by anyone using the verification key.
Verifier: It is a component that verifies the proof using the verification key.
Witness: It is a set of input variables that satisfy the constraints defined in the circuit.
Prover: It is a component that generates a proof using the circuit, constraint system, and witness.
Example
Here's an example in Go that demonstrates how to use some of the components of Gnark.
The Circuit
Our example will use a simple arithmetic circuit that takes a secret input, squares it, and outputs the result. Here's what the circuit looks like in code:
package main
import (
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
)
// CubicCircuit defines a simple circuit
// x**3 + x + 5 == y
type CubicCircuit struct {
// struct tags on a variable is optional
// default uses variable name and secret visibility.
X frontend.Variable `gnark:"x"`
Y frontend.Variable `gnark:",public"`
}
// Define declares the circuit constraints
// x**3 + x + 5 == y
func (circuit *CubicCircuit) Define(api frontend.API) error {
x3 := api.Mul(circuit.X, circuit.X, circuit.X)
api.AssertIsEqual(circuit.Y, api.Add(x3, circuit.X, 5))
return nil
}
Generating the Proof
Now that we have our circuit defined, we can use Gnark to generate a zero knowledge proof. Here's what the code looks like:
func main() {
// compiles our circuit into a R1CS
var circuit CubicCircuit
ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
// groth16 zkSNARK: Setup
pk, vk, _ := groth16.Setup(ccs)
// witness definition
assignment := CubicCircuit{X: 3, Y: 35}
witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
// groth16: Prove & Verify
proof, _ := groth16.Prove(ccs, pk, witness)
groth16.Verify(proof, vk, publicWitness)
}
In the main
function, we create a new Circuit
with a secret input of 42
. We then define the curve and the proving scheme, and use the ToWitness
method to generate a witness for the circuit. Next, we use the Setup
method to generate a proving key, and the Prove
method to generate a proof.
Verifying the Proof
Finally, we can verify the proof using Gnark. Here's the code:
// Verify the proof
verificationKey := provingKey.VerificationKey()
err = scheme.Verify(proof, verificationKey, witness)
if err != nil {
panic(err)
}
fmt.Println("Zero knowledge proof generated and verified successfully!")
To verify the proof, we need the verification key that corresponds to the proving key. We generate this key using the VerificationKey
method on the proving key. Then, we use the Verify
method to verify the proof using the verification key and the witness.
Real World Application
Now let’s dive into multiple examples for gnark. We will look into the following examples:
Zero-Knowledge authentication scheme
Secure Messaging Protocol
1) Zero-Knowledge authentication scheme
Suppose you want to prove to a service that you know the password to your account without actually revealing the password. Normally, you would simply enter the password and the service would check it against its database. But with zero-knowledge proofs, you can prove that you know the password without actually revealing it.
Here's how it would work:
First, you would convert your password into a circuit using a tool like
libsnark
. The circuit would be a set of mathematical equations that represent your password.Next, you would generate a random string of bits, called a "witness", that satisfies the equations of the circuit.
You would then send the circuit and the witness to the service you want to authenticate with, without revealing your password.
The service would then run the circuit with the provided witness and verify that the equations hold true. If they do, the service knows that you must know the password that generated the circuit.
Finally, the service would grant you access to your account.
In this way, you have proven to the service that you know your password without actually revealing it. This is a powerful application of zero-knowledge proofs that can improve the security and privacy of authentication systems.
Conclusion
Gnark is a powerful library for building zero-knowledge proof circuits in Go. With its intuitive syntax and extensive features, it allows developers to easily create and verify complex proofs with minimal effort.
Although Gnark is still a relatively new library, its active development and growing community suggest that it will continue to evolve and improve over time. As more developers discover the benefits of zero-knowledge proofs and their applications, we can expect Gnark to play a vital role in securing our digital world.
You can visit Consensys website for more.