arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/groth16/groth16_test.go
groth16/groth16_test.goRaw
  1package groth16
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"math/big"
  7	"strings"
  8	"testing"
  9	"time"
 10
 11	"github.com/arnaucube/go-snark/circuitcompiler"
 12	"github.com/arnaucube/go-snark/r1csqap"
 13	"github.com/stretchr/testify/assert"
 14)
 15
 16func TestGroth16MinimalFlow(t *testing.T) {
 17	fmt.Println("testing Groth16 minimal flow")
 18	// circuit function
 19	// y = x^3 + x + 5
 20	code := `
 21	func main(private s0, public s1):
 22		s2 = s0 * s0
 23		s3 = s2 * s0
 24		s4 = s3 + s0
 25		s5 = s4 + 5
 26		equals(s1, s5)
 27		out = 1 * 1
 28	`
 29	fmt.Print("\ncode of the circuit:")
 30
 31	// parse the code
 32	parser := circuitcompiler.NewParser(strings.NewReader(code))
 33	circuit, err := parser.Parse()
 34	assert.Nil(t, err)
 35
 36	b3 := big.NewInt(int64(3))
 37	privateInputs := []*big.Int{b3}
 38	b35 := big.NewInt(int64(35))
 39	publicSignals := []*big.Int{b35}
 40
 41	// wittness
 42	w, err := circuit.CalculateWitness(privateInputs, publicSignals)
 43	assert.Nil(t, err)
 44
 45	// code to R1CS
 46	fmt.Println("\ngenerating R1CS from code")
 47	a, b, c := circuit.GenerateR1CS()
 48	fmt.Println("\nR1CS:")
 49	fmt.Println("a:", a)
 50	fmt.Println("b:", b)
 51	fmt.Println("c:", c)
 52
 53	// R1CS to QAP
 54	// TODO zxQAP is not used and is an old impl, TODO remove
 55	alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c)
 56	fmt.Println("qap")
 57	assert.Equal(t, 8, len(alphas))
 58	assert.Equal(t, 8, len(alphas))
 59	assert.Equal(t, 8, len(alphas))
 60	assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
 61
 62	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
 63	assert.Equal(t, 7, len(ax))
 64	assert.Equal(t, 7, len(bx))
 65	assert.Equal(t, 7, len(cx))
 66	assert.Equal(t, 13, len(px))
 67
 68	// ---
 69	// from here is the GROTH16
 70	// ---
 71	// calculate trusted setup
 72	fmt.Println("groth")
 73	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
 74	assert.Nil(t, err)
 75	fmt.Println("\nt:", setup.Toxic.T)
 76
 77	hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
 78	div, rem := Utils.PF.Div(px, setup.Pk.Z)
 79	assert.Equal(t, hx, div)
 80	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
 81
 82	// hx==px/zx so px==hx*zx
 83	assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
 84
 85	// check length of polynomials H(x) and Z(x)
 86	assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
 87
 88	proof, err := GenerateProofs(*circuit, setup, w, px)
 89	assert.Nil(t, err)
 90
 91	// fmt.Println("\n proofs:")
 92	// fmt.Println(proof)
 93
 94	// fmt.Println("public signals:", proof.PublicSignals)
 95	fmt.Println("\nsignals:", circuit.Signals)
 96	fmt.Println("witness:", w)
 97	b35Verif := big.NewInt(int64(35))
 98	publicSignalsVerif := []*big.Int{b35Verif}
 99	before := time.Now()
100	assert.True(t, VerifyProof(setup, proof, publicSignalsVerif, true))
101	fmt.Println("verify proof time elapsed:", time.Since(before))
102
103	// check that with another public input the verification returns false
104	bOtherWrongPublic := big.NewInt(int64(34))
105	wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
106	assert.True(t, !VerifyProof(setup, proof, wrongPublicSignalsVerif, false))
107}