From 19f7216d0e3d3c9677e78ba9df201dc475824fa3 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Fri, 7 Dec 2018 22:00:27 +0100 Subject: [PATCH] e(Vb, piB) == e(piB', g2) proof --- README.md | 133 ++++++++++++++++------------------------------ bn128/README.md | 1 + r1csqap/README.md | 54 +++++++++++++++++++ zk/zk.go | 109 ++++++++++++++++++++++++------------- zk/zk_test.go | 10 +++- 5 files changed, 181 insertions(+), 126 deletions(-) create mode 100644 r1csqap/README.md diff --git a/README.md b/README.md index f12d369..b2882d2 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,70 @@ # go-snark [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/go-snark)](https://goreportcard.com/report/github.com/arnaucube/go-snark) -zk-SNARK library implementation in Go +zkSNARK library implementation in Go -#### Test -``` -go test ./... -v -``` +### Usage +- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/zk?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/zk) zk (TrustedSetup, GenerateProof, VerifyProof) +- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128) +- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields +- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap) +Example: +```go +bn, err := bn128.NewBn128() +assert.Nil(t, err) -## R1CS to Quadratic Arithmetic Program -- `Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf -- Vitalik Buterin blog post about QAP https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 -- Ariel Gabizon in Zcash blog https://z.cash/blog/snark-explain5 -- Lagrange polynomial Wikipedia article https://en.wikipedia.org/wiki/Lagrange_polynomial +// new Finite Field +f := fields.NewFq(bn.R) -#### Usage -- R1CS to QAP -```go -pf := NewPolynomialField(f) - -b0 := big.NewInt(int64(0)) -b1 := big.NewInt(int64(1)) -b3 := big.NewInt(int64(3)) -b5 := big.NewInt(int64(5)) -b9 := big.NewInt(int64(9)) -b27 := big.NewInt(int64(27)) -b30 := big.NewInt(int64(30)) -b35 := big.NewInt(int64(35)) -a := [][]*big.Int{ - []*big.Int{b0, b1, b0, b0, b0, b0}, - []*big.Int{b0, b0, b0, b1, b0, b0}, - []*big.Int{b0, b1, b0, b0, b1, b0}, - []*big.Int{b5, b0, b0, b0, b0, b1}, -} -b := [][]*big.Int{ - []*big.Int{b0, b1, b0, b0, b0, b0}, - []*big.Int{b0, b1, b0, b0, b0, b0}, - []*big.Int{b1, b0, b0, b0, b0, b0}, - []*big.Int{b1, b0, b0, b0, b0, b0}, -} -c := [][]*big.Int{ - []*big.Int{b0, b0, b0, b1, b0, b0}, - []*big.Int{b0, b0, b0, b0, b1, b0}, - []*big.Int{b0, b0, b0, b0, b0, b1}, - []*big.Int{b0, b0, b1, b0, b0, b0}, -} -alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) -fmt.Println(alphas) -fmt.Println(betas) -fmt.Println(gammas) -fmt.Println(z) +// new Polynomial Field +pf := r1csqap.NewPolynomialField(f) -w := []*big.Int{b1, b3, b35, b9, b27, b30} -ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) -fmt.Println(ax) -fmt.Println(bx) -fmt.Println(cx) -fmt.Println(px) +/* +suppose that we have the following variables with *big.Int elements: +a = [[0 1 0 0 0 0] [0 0 0 1 0 0] [0 1 0 0 1 0] [5 0 0 0 0 1]] +b = [[0 1 0 0 0 0] [0 1 0 0 0 0] [1 0 0 0 0 0] [1 0 0 0 0 0]] +c = [[0 0 0 1 0 0] [0 0 0 0 1 0] [0 0 0 0 0 1] [0 0 1 0 0 0]] -hx := pf.DivisorPolinomial(px, zx) -fmt.Println(hx) -``` +w = [1, 3, 35, 9, 27, 30] +*/ -## Bn128 -Implementation of the bn128 pairing in Go. +alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) +ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) -Implementation followng the information and the implementations from: -- `Multiplication and Squaring on Pairing-Friendly -Fields`, Augusto Jun Devegili, Colm Ó hÉigeartaigh, Michael Scott, and Ricardo Dahab https://pdfs.semanticscholar.org/3e01/de88d7428076b2547b60072088507d881bf1.pdf -- `Optimal Pairings`, Frederik Vercauteren https://www.cosic.esat.kuleuven.be/bcrypt/optimal.pdf , https://eprint.iacr.org/2008/096.pdf -- `Double-and-Add with Relative Jacobian -Coordinates`, Björn Fay https://eprint.iacr.org/2014/1014.pdf -- `Fast and Regular Algorithms for Scalar Multiplication -over Elliptic Curves`, Matthieu Rivain https://eprint.iacr.org/2011/338.pdf -- `High-Speed Software Implementation of the Optimal Ate Pairing over Barreto–Naehrig Curves`, Jean-Luc Beuchat, Jorge E. González-Díaz, Shigeo Mitsunari, Eiji Okamoto, Francisco Rodríguez-Henríquez, and Tadanori Teruya https://eprint.iacr.org/2010/354.pdf -- `New software speed records for cryptographic pairings`, Michael Naehrig, Ruben Niederhagen, Peter Schwabe https://cryptojedi.org/papers/dclxvi-20100714.pdf -- `Implementing Cryptographic Pairings over Barreto-Naehrig Curves`, Augusto Jun Devegili, Michael Scott, Ricardo Dahab https://eprint.iacr.org/2007/390.pdf -- https://github.com/zcash/zcash/tree/master/src/snark -- https://github.com/iden3/snarkjs -- https://github.com/ethereum/py_ecc/tree/master/py_ecc/bn128 +hx := pf.DivisorPolinomial(px, zx) +// hx==px/zx so px==hx*zx +assert.Equal(t, px, pf.Mul(hx, zx)) -#### Usage +// p(x) = a(x) * b(x) - c(x) == h(x) * z(x) +abc := pf.Sub(pf.Mul(ax, bx), cx) +assert.Equal(t, abc, px) +hz := pf.Mul(hx, zx) +assert.Equal(t, abc, hz) -- Pairing -```go -bn128, err := NewBn128() +// calculate trusted setup +setup, err := GenerateTrustedSetup(bn, len(ax)) assert.Nil(t, err) +fmt.Println("trusted setup:") +fmt.Println(setup.G1T) +fmt.Println(setup.G2T) -big25 := big.NewInt(int64(25)) -big30 := big.NewInt(int64(30)) - -g1a := bn128.G1.MulScalar(bn128.G1.G, big25) -g2a := bn128.G2.MulScalar(bn128.G2.G, big30) +// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) +proof, err := GenerateProofs(bn, f, setup, ax, bx, cx, hx, zx) +assert.Nil(t, err) -g1b := bn128.G1.MulScalar(bn128.G1.G, big30) -g2b := bn128.G2.MulScalar(bn128.G2.G, big25) -pA, err := bn128.Pairing(g1a, g2a) -assert.Nil(t, err) -pB, err := bn128.Pairing(g1b, g2b) -assert.Nil(t, err) -assert.True(t, bn128.Fq12.Equal(pA, pB)) +// verify the proofs with the bn128 pairing +verified := VerifyProof(bn, publicSetup, proof) +assert.True(t, verified) ``` +### Test +``` +go test ./... -v +``` --- diff --git a/bn128/README.md b/bn128/README.md index 5652ffc..0cedf3d 100644 --- a/bn128/README.md +++ b/bn128/README.md @@ -1,4 +1,5 @@ ## Bn128 +[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 Implementation of the bn128 pairing in Go. diff --git a/r1csqap/README.md b/r1csqap/README.md new file mode 100644 index 0000000..21c6054 --- /dev/null +++ b/r1csqap/README.md @@ -0,0 +1,54 @@ +## R1CS to Quadratic Arithmetic Program +[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP +- `Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf +- Vitalik Buterin blog post about QAP https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 +- Ariel Gabizon in Zcash blog https://z.cash/blog/snark-explain5 +- Lagrange polynomial Wikipedia article https://en.wikipedia.org/wiki/Lagrange_polynomial + +#### Usage +- R1CS to QAP +```go +pf := NewPolynomialField(f) + +b0 := big.NewInt(int64(0)) +b1 := big.NewInt(int64(1)) +b3 := big.NewInt(int64(3)) +b5 := big.NewInt(int64(5)) +b9 := big.NewInt(int64(9)) +b27 := big.NewInt(int64(27)) +b30 := big.NewInt(int64(30)) +b35 := big.NewInt(int64(35)) +a := [][]*big.Int{ + []*big.Int{b0, b1, b0, b0, b0, b0}, + []*big.Int{b0, b0, b0, b1, b0, b0}, + []*big.Int{b0, b1, b0, b0, b1, b0}, + []*big.Int{b5, b0, b0, b0, b0, b1}, +} +b := [][]*big.Int{ + []*big.Int{b0, b1, b0, b0, b0, b0}, + []*big.Int{b0, b1, b0, b0, b0, b0}, + []*big.Int{b1, b0, b0, b0, b0, b0}, + []*big.Int{b1, b0, b0, b0, b0, b0}, +} +c := [][]*big.Int{ + []*big.Int{b0, b0, b0, b1, b0, b0}, + []*big.Int{b0, b0, b0, b0, b1, b0}, + []*big.Int{b0, b0, b0, b0, b0, b1}, + []*big.Int{b0, b0, b1, b0, b0, b0}, +} +alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) +fmt.Println(alphas) +fmt.Println(betas) +fmt.Println(gammas) +fmt.Println(z) + +w := []*big.Int{b1, b3, b35, b9, b27, b30} +ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) +fmt.Println(ax) +fmt.Println(bx) +fmt.Println(cx) +fmt.Println(px) + +hx := pf.DivisorPolinomial(px, zx) +fmt.Println(hx) +``` diff --git a/zk/zk.go b/zk/zk.go index 28cbe38..3aa70d5 100644 --- a/zk/zk.go +++ b/zk/zk.go @@ -6,13 +6,16 @@ import ( "math/big" "github.com/arnaucube/go-snark/bn128" + "github.com/arnaucube/go-snark/fields" ) type Setup struct { - T *big.Int // trusted setup secret - Ka *big.Int // trusted setup - Kb *big.Int // trusted setup - Kc *big.Int // trusted setup + Toxic struct { + T *big.Int // trusted setup secret + Ka *big.Int // prover + Kb *big.Int // prover + Kc *big.Int // prover + } // public G1T [][3]*big.Int // t encrypted in G1 curve @@ -22,12 +25,12 @@ type Proof struct { PiA [3]*big.Int PiAp [3]*big.Int PiB [3][2]*big.Int - PiBp [3][2]*big.Int + PiBp [3]*big.Int PiC [3]*big.Int PiCp [3]*big.Int PiH [3]*big.Int Va [3][2]*big.Int - Vb [3][2]*big.Int + Vb [3]*big.Int Vc [3][2]*big.Int Vz [3][2]*big.Int } @@ -38,18 +41,18 @@ func GenerateTrustedSetup(bn bn128.Bn128, pollength int) (Setup, error) { var setup Setup var err error // generate random t value - setup.T, err = rand.Prime(rand.Reader, bits) + setup.Toxic.T, err = rand.Prime(rand.Reader, bits) if err != nil { return Setup{}, err } fmt.Print("trusted t: ") - fmt.Println(setup.T) + fmt.Println(setup.Toxic.T) // encrypt t values with curve generators var gt1 [][3]*big.Int var gt2 [][3][2]*big.Int for i := 0; i < pollength; i++ { - tPow := bn.Fq1.Exp(setup.T, big.NewInt(int64(i))) + tPow := bn.Fq1.Exp(setup.Toxic.T, big.NewInt(int64(i))) tEncr1 := bn.G1.MulScalar(bn.G1.G, tPow) gt1 = append(gt1, tEncr1) tEncr2 := bn.G2.MulScalar(bn.G2.G, tPow) @@ -60,67 +63,73 @@ func GenerateTrustedSetup(bn bn128.Bn128, pollength int) (Setup, error) { setup.G1T = gt1 setup.G2T = gt2 - // k for pi' - setup.Ka, err = rand.Prime(rand.Reader, bits) + return setup, nil +} + +func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, ax, bx, cx, hx, zx []*big.Int) (Proof, error) { + var proof Proof + var err error + + // k for calculating pi' and Vk + setup.Toxic.Ka, err = rand.Prime(rand.Reader, bits) if err != nil { - return Setup{}, err + return Proof{}, err } - setup.Kb, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kb, err = rand.Prime(rand.Reader, bits) if err != nil { - return Setup{}, err + return Proof{}, err } - setup.Kc, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kc, err = rand.Prime(rand.Reader, bits) if err != nil { - return Setup{}, err + return Proof{}, err } - return setup, nil -} - -func GenerateProofs(bn bn128.Bn128, setup Setup, ax, bx, cx, hx, zx []*big.Int) Proof { - var proof Proof - - // g1*A(x) + // g1*A(t) proof.PiA = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} for i := 0; i < len(ax); i++ { m := bn.G1.MulScalar(setup.G1T[i], ax[i]) proof.PiA = bn.G1.Add(proof.PiA, m) } - proof.PiAp = bn.G1.MulScalar(proof.PiA, setup.Ka) + proof.PiAp = bn.G1.MulScalar(proof.PiA, setup.Toxic.Ka) - // g1*B(x) + // g2*B(t) proof.PiB = bn.Fq6.Zero() + // g1*B(t) + pib1 := [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} for i := 0; i < len(bx); i++ { m := bn.G2.MulScalar(setup.G2T[i], bx[i]) proof.PiB = bn.G2.Add(proof.PiB, m) + m1 := bn.G1.MulScalar(setup.G1T[i], bx[i]) + pib1 = bn.G1.Add(pib1, m1) } - proof.PiBp = bn.G2.MulScalar(proof.PiB, setup.Kb) + proof.PiBp = bn.G1.MulScalar(pib1, setup.Toxic.Kb) - // g1*C(x) + // g1*C(t) proof.PiC = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} for i := 0; i < len(cx); i++ { m := bn.G1.MulScalar(setup.G1T[i], cx[i]) proof.PiC = bn.G1.Add(proof.PiC, m) } - proof.PiCp = bn.G1.MulScalar(proof.PiC, setup.Kc) + proof.PiCp = bn.G1.MulScalar(proof.PiC, setup.Toxic.Kc) - g1Ht := [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} + // g1*H(t) + proof.PiH = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} for i := 0; i < len(hx); i++ { m := bn.G1.MulScalar(setup.G1T[i], hx[i]) - g1Ht = bn.G1.Add(g1Ht, m) + proof.PiH = bn.G1.Add(proof.PiH, m) } + g2Zt := bn.Fq6.Zero() for i := 0; i < len(bx); i++ { m := bn.G2.MulScalar(setup.G2T[i], zx[i]) g2Zt = bn.G2.Add(g2Zt, m) } - proof.PiH = g1Ht proof.Vz = g2Zt - proof.Va = bn.G2.MulScalar(bn.G2.G, setup.Ka) - proof.Vb = bn.G2.MulScalar(bn.G2.G, setup.Kb) - proof.Vc = bn.G2.MulScalar(bn.G2.G, setup.Kc) + proof.Va = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Ka) + proof.Vb = bn.G1.MulScalar(bn.G1.G, setup.Toxic.Kb) + proof.Vc = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kc) - return proof + return proof, nil } func VerifyProof(bn bn128.Bn128, setup Setup, proof Proof) bool { @@ -138,7 +147,18 @@ func VerifyProof(bn bn128.Bn128, setup Setup, proof Proof) bool { return false } - // e(piB, Vb) == e(piB', g2) + // e(Vb, piB) == e(piB', g2) + pairingVbPib, err := bn.Pairing(proof.Vb, proof.PiB) + if err != nil { + return false + } + pairingPibpG2, err := bn.Pairing(proof.PiBp, bn.G2.G) + if err != nil { + return false + } + if !bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { + return false + } // e(piC, Vc) == e(piC', g2) pairingPicVc, err := bn.Pairing(proof.PiC, proof.Vc) @@ -153,7 +173,22 @@ func VerifyProof(bn bn128.Bn128, setup Setup, proof Proof) bool { return false } - // + // e(piA, piB) == e(piH, Vz) * e(piC, g2) + // pairingPiaPib, err := bn.Pairing(proof.PiA, proof.PiB) + // if err != nil { + // return false + // } + // pairingPihVz, err := bn.Pairing(proof.PiH, proof.Vz) + // if err != nil { + // return false + // } + // pairingPicG2, err := bn.Pairing(proof.PiC, bn.G2.G) + // if err != nil { + // return false + // } + // if !bn.Fq12.Equal(pairingPiaPib, bn.Fq12.Mul(pairingPihVz, pairingPicG2)) { + // return false + // } return true } diff --git a/zk/zk_test.go b/zk/zk_test.go index 8063f4f..4d9c9b4 100644 --- a/zk/zk_test.go +++ b/zk/zk_test.go @@ -71,7 +71,8 @@ func TestZk(t *testing.T) { fmt.Println(setup.G2T) // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) - proof := GenerateProofs(bn, setup, ax, bx, cx, hx, zx) + proof, err := GenerateProofs(bn, f, setup, ax, bx, cx, hx, zx) + assert.Nil(t, err) fmt.Println("proofs:") fmt.Println(proof.PiA) fmt.Println(proof.PiB) @@ -79,5 +80,10 @@ func TestZk(t *testing.T) { fmt.Println(proof.PiH) fmt.Println(proof.Vz) - assert.True(t, VerifyProof(bn, setup, proof)) + publicSetup := Setup{ + G1T: setup.G1T, + G2T: setup.G2T, + } + + assert.True(t, VerifyProof(bn, publicSetup, proof)) }