The gnark library is a popular zk-SNARK library that offers a high-level API for designing circuits. zk-SNARK is a modern cryptographic tool that enables efficient proving of statements while maintaining privacy. However, a critical vulnerability was discovered in gnark prior to version .9., which enabled dual decomposition for some in-circuit values. This post will discuss the details of this vulnerability, provide sample code snippets that demonstrate the issue, and suggest upgrading to version .9. to fix the problem without needing to change the value comparison methods.

Exploit Details

Before we dive into the details of this vulnerability, let's first understand the concept of zk-SNARK. In the realm of cryptography, zk-SNARK stands for Zero-Knowledge Succinct Non-interactive Argument of Knowledge. It allows a prover to demonstrate they possess certain knowledge without revealing the actual details. Gnark is one such library that simplifies the implementation of zk-SNARK.

The vulnerability, identified as CVE-2023-44378, is caused by an error in the decomposition of values to bits while constructing the circuits. For some specific in-circuit values, it was observed that two valid decomposition to bits were possible. This means that instead of the intended, canonical decomposition of a, an adversary could craft an alternative decomposition for a+r, where r represents the modulus by which the values are being reduced.

The root cause of this vulnerability is an overflow in the field where the values are defined. This overflow enables the construction of a second decomposition that would leak critical information, thereby defeating the purpose of using zk-SNARK to preserve privacy in the first place.

Here's a simple code snippet to demonstrate the issue in gnark prior to version .9.

// Vulnerable code snippet in gnark <.9.
package main

import (
	"fmt"
	"github.com/consensys/gnark"
	"github.com/consensys/gnark/frontend"
)

type myCircuit struct {
	a frontend.Variable // public input
	b frontend.Variable // private input
}

func (circuit *myCircuit) Define(curveID gnark.CurveID, cs *frontend.ConstraintSystem) error {
	decomposed := cs.Decompose(circuit.a, 128)
	cs.IsTrue(circuit.b)                // intended use-case
	cs.IsTrue(circuit.b + 42 * circuit.a) // the alternative crafted value

	return nil
}

func main() {
	if err := TestOverflownValues(); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("Test passed")
	}
}

Patch Details and Upgrade

The gnark maintainers have released version .9. to address this vulnerability. Upgrading to this version should fix the issue without the need for changes to the methods used for comparing values. You can find the source code and release notes for version .9. on GitHub:

- Gnark v.9. on GitHub

To upgrade your gnark dependency in your Go project, simply update the version in your go.mod file. Alternatively, you can run go get github.com/consensys/gnark@v.9. to fetch the latest version of the library.

Conclusion

The dual decomposition vulnerability in the gnark zk-SNARK library (CVE-2023-44378) highlights the importance of not only understanding the intricacies of cryptographic primitives but also rigorously testing and verifying the implementation of these protocols. By updating to version .9. of gnark, users can easily fix this issue and continue leveraging the powerful capabilities of zk-SNARKs for secure and efficient proofs.

Timeline

Published on: 10/09/2023 14:15:10 UTC
Last modified on: 10/13/2023 18:43:14 UTC