snark

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2019 License: GPL-3.0 Imports: 7 Imported by: 4

README

go-snark Go Report Card Build Status Gitter

zkSNARK library implementation in Go

Caution & Warning

Implementation of the zkSNARK Pinocchio protocol and Groth16 protocol from scratch in Go to understand the concepts. Do not use in production.

Not finished, implementing this in my free time to understand it better, so I don't have much time.

Currently allows to do the complete path with Pinocchio protocol and Groth16 protocol :

  1. write circuit
  2. compile circuit
  3. generate trusted setup
  4. calculate witness
  5. generate proofs
  6. verify proofs

Minimal complete flow implementation:

  • Finite Fields (1, 2, 6, 12) operations
  • G1 and G2 curve operations
  • BN128 Pairing
  • circuit flat code compiler
  • circuit to R1CS
  • polynomial operations
  • R1CS to QAP
  • generate trusted setup
  • generate proofs
  • verify proofs with BN128 pairing

Improvements from the minimal implementation:

  • allow to call functions in circuits language
  • allow import in circuits language
  • allow for in circuits language
  • move witness values calculation outside the setup phase
  • Groth16
  • multiple optimizations
  • wasm proof generation
  • wasm proof verification

WASM usage

Ongoing experimentation with go-snark compiled to wasm: https://github.com/arnaucube/go-snark/tree/master/wasm

Usage

CLI usage

The cli still needs some improvements, such as seting input files, etc.

In this example we will follow the equation example from Vitalik's article: y = x^3 + x + 5, where y==35 and x==3. So we want to prove that we know a secret x such as the result of the equation is 35.

Compile circuit

Having a circuit file test.circuit:

func exp3(private a):
	b = a * a
	c = a * b
	return c

func main(private s0, public s1):
	s3 = exp3(s0)
	s4 = s3 + s0
	s5 = s4 + 5
	equals(s1, s5)
	out = 1 * 1

And a private inputs file privateInputs.json

[
	3
]

And a public inputs file publicInputs.json

[
	35
]

In the command line, execute:

> ./go-snark-cli compile test.circuit

If you want to have the wasm input ready also, add the flag wasm

> ./go-snark-cli compile test.circuit wasm

This will output the compiledcircuit.json file.

Trusted Setup

Having the compiledcircuit.json, now we can generate the TrustedSetup:

> ./go-snark-cli trustedsetup

This will create the file trustedsetup.json with the TrustedSetup data, and also a toxic.json file, with the parameters to delete from the Trusted Setup.

If you want to have the wasm input ready also, add the flag wasm

> ./go-snark-cli trustedsetup wasm
Generate Proofs

Assumming that we have the compiledcircuit.json, trustedsetup.json, privateInputs.json and the publicInputs.json we can now generate the Proofs with the following command:

> ./go-snark-cli genproofs

This will store the file proofs.json, that contains all the SNARK proofs.

Verify Proofs

Having the proofs.json, compiledcircuit.json, trustedsetup.json publicInputs.json files, we can now verify the Pairings of the proofs, in order to verify the proofs.

> ./go-snark-cli verify

This will return a true if the proofs are verified, or a false if the proofs are not verified.

Cli using Groth16

All this process can be done using Groth16 protocol protocol:

> ./go-snark-cli compile test.circuit
> ./go-snark-cli groth16 trustedsetup
> ./go-snark-cli groth16 genproofs
> ./go-snark-cli verify
Library usage

Example:

// compile circuit and get the R1CS
flatCode := `
func exp3(private a):
	b = a * a
	c = a * b
	return c

func main(private s0, public s1):
	s3 = exp3(s0)
	s4 = s3 + s0
	s5 = s4 + 5
	equals(s1, s5)
	out = 1 * 1
`

// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
circuit, err := parser.Parse()
assert.Nil(t, err)
fmt.Println(circuit)


b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b35 := big.NewInt(int64(35))
publicSignals := []*big.Int{b35}

// witness
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
fmt.Println("witness", w)

// now we have the witness:
// w = [1 35 3 9 27 30 35 1]

// flat code to R1CS
fmt.Println("generating R1CS from flat code")
a, b, c := circuit.GenerateR1CS()

/*
now we have the R1CS from the circuit:
a: [[0 0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 1 0 1 0 0 0] [5 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
b: [[0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
c: [[0 0 0 1 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1]]
*/


alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(a, b, c)


ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)

// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)

hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)

proof, err := GenerateProofs(*circuit, setup, w, px)

b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
Verify Proof generated from snarkjs

Is possible with go-snark to verify proofs generated by snarkjs

Example:

verified, err := VerifyFromCircom("circom-test/verification_key.json", "circom-test/proof.json", "circom-test/public.json")
assert.Nil(t, err)
assert.True(t, verified)

Versions

History of versions & tags of this project:

  • v0.0.1: zkSnark complete flow working with Pinocchio protocol
  • v0.0.2: circuit language improved (allow function calls and file imports)
  • v0.0.3: Groth16 zkSnark protocol added

Test

go test ./... -v

vim/nvim circuit syntax highlighter

For more details and installation instructions see https://github.com/arnaucube/go-snark/tree/master/vim-syntax


Thanks to @jbaylina, @bellesmarta, @adriamb for their explanations that helped to understand this a little bit. Also thanks to @vbuterin for all the published articles explaining the zkSNARKs.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Utils = prepareUtils()

Utils is the data structure holding the BN128, FqR Finite Field over R, PolynomialField, that will be used inside the snarks operations

Functions

func VerifyProof

func VerifyProof(vk Vk, proof Proof, publicSignals []*big.Int, debug bool) bool

VerifyProof verifies over the BN128 the Pairings of the Proof

Types

type Pk

type Pk struct {
	G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H
	A   [][3]*big.Int
	B   [][3][2]*big.Int
	C   [][3]*big.Int
	Kp  [][3]*big.Int
	Ap  [][3]*big.Int
	Bp  [][3]*big.Int
	Cp  [][3]*big.Int
	Z   []*big.Int
}

type Proof

type Proof struct {
	PiA  [3]*big.Int
	PiAp [3]*big.Int
	PiB  [3][2]*big.Int
	PiBp [3]*big.Int
	PiC  [3]*big.Int
	PiCp [3]*big.Int
	PiH  [3]*big.Int
	PiKp [3]*big.Int
}

Proof contains the parameters to proof the zkSNARK

func GenerateProofs

func GenerateProofs(circuit circuitcompiler.Circuit, pk Pk, w []*big.Int, px []*big.Int) (Proof, error)

GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness

type Setup

type Setup struct {
	Toxic struct {
		T      *big.Int // trusted setup secret
		Ka     *big.Int // prover
		Kb     *big.Int // prover
		Kc     *big.Int // prover
		Kbeta  *big.Int
		Kgamma *big.Int
		RhoA   *big.Int
		RhoB   *big.Int
		RhoC   *big.Int
	}

	// public
	Pk Pk
	Vk Vk
}

Setup is the data structure holding the Trusted Setup data. The Setup.Toxic sub struct must be destroyed after the GenerateTrustedSetup function is completed

func GenerateTrustedSetup

func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error)

GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed

type Vk

type Vk struct {
	Vka   [3][2]*big.Int
	Vkb   [3]*big.Int
	Vkc   [3][2]*big.Int
	IC    [][3]*big.Int
	G1Kbg [3]*big.Int    // g1 * Kbeta * Kgamma
	G2Kbg [3][2]*big.Int // g2 * Kbeta * Kgamma
	G2Kg  [3][2]*big.Int // g2 * Kgamma
	Vkz   [3][2]*big.Int
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL