From f555ae4b18988b7a00fe44135252c6b387c6d1bd Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 23 Dec 2018 16:19:33 +0100 Subject: [PATCH] snark trusted setup + generate proof + verify proof working. Added test to bn128 pairing --- README.md | 27 +++--- bn128/bn128.go | 21 +++-- bn128/bn128_test.go | 31 +++++-- compiler/circuit.go | 7 ++ fields/fq.go | 21 +++++ go.mod | 3 + go.sum | 6 ++ r1csqap/r1csqap.go | 1 - snark.go | 200 ++++++++++++++++++-------------------------- snark_test.go | 31 +++---- 10 files changed, 187 insertions(+), 161 deletions(-) create mode 100644 compiler/circuit.go diff --git a/README.md b/README.md index 374cc2b..6222d3c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ zkSNARK library implementation in Go `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 +`Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf ### Usage - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark @@ -18,7 +19,7 @@ bn, err := bn128.NewBn128() assert.Nil(t, err) // new Finite Field -f := fields.NewFq(bn.R) +fqR := fields.NewFq(bn.R) // new Polynomial Field pf := r1csqap.NewPolynomialField(f) @@ -34,6 +35,13 @@ w = [1, 3, 35, 9, 27, 30] alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) +// wittness = 1, 3, 35, 9, 27, 30 +w := []*big.Int{b1, b3, b35, b9, b27, b30} +circuit := compiler.Circuit{ + NVars: 6, + NPublic: 0, + NSignals: len(w), +} ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) hx := pf.DivisorPolinomial(px, zx) @@ -46,22 +54,21 @@ abc := pf.Sub(pf.Mul(ax, bx), cx) assert.Equal(t, abc, px) hz := pf.Mul(hx, zx) assert.Equal(t, abc, hz) + +div, rem := pf.Div(px, zx) +assert.Equal(t, hx, div) +assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) // calculate trusted setup -setup, err := GenerateTrustedSetup(bn, len(ax)) +setup, err := GenerateTrustedSetup(bn, fqR, pf, len(w), circuit, alphas, betas, gammas, zx) assert.Nil(t, err) -fmt.Println("trusted setup:") -fmt.Println(setup.G1T) -fmt.Println(setup.G2T) +fmt.Println("t", setup.Toxic.T) // 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) +proof, err := GenerateProofs(bn, fqR, circuit, setup, hx, w) assert.Nil(t, err) - -// verify the proofs with the bn128 pairing -verified := VerifyProof(bn, publicSetup, proof) -assert.True(t, verified) +assert.True(t, VerifyProof(bn, circuit, setup, proof)) ``` ### Test diff --git a/bn128/bn128.go b/bn128/bn128.go index 921bde8..8af445b 100644 --- a/bn128/bn128.go +++ b/bn128/bn128.go @@ -105,7 +105,7 @@ func NewBn128() (Bn128, error) { return b, nil } -func NewFqR() (fields.Fq, error){ +func NewFqR() (fields.Fq, error) { r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) if !ok { return fields.Fq{}, errors.New("err parsing R") @@ -172,16 +172,13 @@ func (bn128 *Bn128) preparePairing() error { } -func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) ([2][3][2]*big.Int, error) { +func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) [2][3][2]*big.Int { pre1 := bn128.PreComputeG1(p1) - pre2, err := bn128.PreComputeG2(p2) - if err != nil { - return [2][3][2]*big.Int{}, err - } + pre2 := bn128.PreComputeG2(p2) r1 := bn128.MillerLoop(pre1, pre2) res := bn128.FinalExponentiation(r1) - return res, nil + return res } type AteG1Precomp struct { @@ -209,7 +206,7 @@ type AteG2Precomp struct { Coeffs []EllCoeffs } -func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) { +func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) AteG2Precomp { qCopy := bn128.G2.Affine(p) res := AteG2Precomp{ qCopy[0], @@ -235,11 +232,13 @@ func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) { q1 := bn128.G2.Affine(bn128.G2MulByQ(qCopy)) if !bn128.Fq2.Equal(q1[2], bn128.Fq2.One()) { - return res, errors.New("q1[2] != Fq2.One") + // return res, errors.New("q1[2] != Fq2.One") + panic(errors.New("q1[2] != Fq2.One()")) } q2 := bn128.G2.Affine(bn128.G2MulByQ(q1)) if !bn128.Fq2.Equal(q2[2], bn128.Fq2.One()) { - return res, errors.New("q2[2] != Fq2.One") + // return res, errors.New("q2[2] != Fq2.One") + panic(errors.New("q2[2] != Fq2.One()")) } if bn128.LoopCountNeg { @@ -253,7 +252,7 @@ func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) { c, r = bn128.MixedAdditionStep(q2, r) res.Coeffs = append(res.Coeffs, c) - return res, nil + return res } func (bn128 Bn128) DoublingStep(current [3][2]*big.Int) (EllCoeffs, [3][2]*big.Int) { diff --git a/bn128/bn128_test.go b/bn128/bn128_test.go index 72c286d..ecfa585 100644 --- a/bn128/bn128_test.go +++ b/bn128/bn128_test.go @@ -22,10 +22,10 @@ func TestBN128(t *testing.T) { g2b := bn128.G2.MulScalar(bn128.G2.G, bn128.Fq1.Copy(big40)) pre1a := bn128.PreComputeG1(g1a) - pre2a, err := bn128.PreComputeG2(g2a) + pre2a := bn128.PreComputeG2(g2a) assert.Nil(t, err) pre1b := bn128.PreComputeG1(g1b) - pre2b, err := bn128.PreComputeG2(g2b) + pre2b := bn128.PreComputeG2(g2b) assert.Nil(t, err) r1 := bn128.MillerLoop(pre1a, pre2a) @@ -55,10 +55,8 @@ func TestBN128Pairing(t *testing.T) { 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) + pA := bn128.Pairing(g1a, g2a) + pB := bn128.Pairing(g1b, g2b) assert.True(t, bn128.Fq12.Equal(pA, pB)) @@ -67,3 +65,24 @@ func TestBN128Pairing(t *testing.T) { // assert.Equal(t, pA[0][0][0].String(), "73680848340331011700282047627232219336104151861349893575958589557226556635706") // assert.Equal(t, bn128.Fq12.Affine(pA)[0][0][0].String(), "8016119724813186033542830391460394070015218389456422587891475873290878009957") } + +func TestBN128Pairing2(t *testing.T) { + // test idea from https://bplib.readthedocs.io/en/latest/ by George Danezis + bn, err := NewBn128() + assert.Nil(t, err) + + gt := bn.Pairing(bn.G1.G, bn.G2.G) + + gt6 := bn.Fq12.Exp(gt, big.NewInt(int64(6))) + + // e(g1, g2)^6 == e(g1, 6*g2) + assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.G, bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(6)))))) + + // e(g1, g2)^6 == e(6* g1, g2) + assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(6))), bn.G2.G))) + // e(g1, g2)^6 == e(3*g1, 2*g2) + assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(3))), bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(2)))))) + // e(g1, g2)^6 == e(2*g1, 3*g2) + assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(2))), bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(3)))))) + +} diff --git a/compiler/circuit.go b/compiler/circuit.go new file mode 100644 index 0000000..e6987f1 --- /dev/null +++ b/compiler/circuit.go @@ -0,0 +1,7 @@ +package compiler + +type Circuit struct { + NVars int + NPublic int + NSignals int +} diff --git a/fields/fq.go b/fields/fq.go index 3a8ad10..fc85f0a 100644 --- a/fields/fq.go +++ b/fields/fq.go @@ -2,6 +2,7 @@ package fields import ( "bytes" + "crypto/rand" "math/big" ) @@ -117,6 +118,26 @@ func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int { return res } +func (fq Fq) Rand() (*big.Int, error) { + + // twoexp := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(maxbits)), nil) + // max := new(big.Int).Sub(twoexp, big.NewInt(1)) + + maxbits := fq.Q.BitLen() + b := make([]byte, (maxbits/8)-1) + // b := make([]byte, 3) + // b := make([]byte, 3) + _, err := rand.Read(b) + if err != nil { + return nil, err + } + r := new(big.Int).SetBytes(b) + rq := new(big.Int).Mod(r, fq.Q) + + // return r over q, nil + return rq, nil +} + func (fq Fq) IsZero(a *big.Int) bool { return bytes.Equal(a.Bytes(), fq.Zero().Bytes()) } diff --git a/go.mod b/go.mod index 001be98..dbc095e 100644 --- a/go.mod +++ b/go.mod @@ -2,5 +2,8 @@ module github.com/arnaucube/go-snark require ( github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd + github.com/fatih/color v1.7.0 + github.com/mattn/go-colorable v0.0.9 // indirect + github.com/mattn/go-isatty v0.0.4 // indirect github.com/stretchr/testify v1.2.2 ) diff --git a/go.sum b/go.sum index 9fa27b1..460a134 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,12 @@ github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd h1:NDpNBTFeHNE github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd/go.mod h1:PZE8kKpHPD1UMrS3mTfAMmEEinGtijSwjxLRqRcD64A= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go index cd7cb46..9cf69c5 100644 --- a/r1csqap/r1csqap.go +++ b/r1csqap/r1csqap.go @@ -95,7 +95,6 @@ func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int { func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int { r := big.NewInt(int64(0)) for i := 0; i < len(v); i++ { - // xi := FloatPow(x, i) xi := pf.F.Exp(x, big.NewInt(int64(i))) elem := pf.F.Mul(v[i], xi) r = pf.F.Add(r, elem) diff --git a/snark.go b/snark.go index 7c9a1b2..aa35b92 100644 --- a/snark.go +++ b/snark.go @@ -1,11 +1,12 @@ package snark import ( - "crypto/rand" "fmt" "math/big" + "os" "github.com/arnaucube/go-snark/bn128" + "github.com/arnaucube/go-snark/compiler" "github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/r1csqap" ) @@ -36,9 +37,10 @@ type Setup struct { Cp [][3]*big.Int } Vk struct { - A [3][2]*big.Int - B [3]*big.Int - C [3][2]*big.Int + Vka [3][2]*big.Int + Vkb [3]*big.Int + Vkc [3][2]*big.Int + A [][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 @@ -47,67 +49,66 @@ type Setup struct { } 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 + 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 + PublicSignals []*big.Int } -const bits = 512 - -func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLength int, alphas, betas, gammas [][]*big.Int, ax, bx, cx, hx, zx []*big.Int) (Setup, error) { +func GenerateTrustedSetup(bn bn128.Bn128, fqR fields.Fq, pf r1csqap.PolynomialField, witnessLength int, circuit compiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) { var setup Setup var err error // generate random t value - setup.Toxic.T, err = rand.Prime(rand.Reader, bits) + setup.Toxic.T, err = fqR.Rand() if err != nil { return Setup{}, err } // k for calculating pi' and Vk - setup.Toxic.Ka, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Ka, err = fqR.Rand() if err != nil { return Setup{}, err } - setup.Toxic.Kb, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kb, err = fqR.Rand() if err != nil { return Setup{}, err } - setup.Toxic.Kc, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kc, err = fqR.Rand() if err != nil { return Setup{}, err } // generate Kβ (Kbeta) and Kγ (Kgamma) - setup.Toxic.Kbeta, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kbeta, err = fqR.Rand() if err != nil { return Setup{}, err } - setup.Toxic.Kgamma, err = rand.Prime(rand.Reader, bits) + setup.Toxic.Kgamma, err = fqR.Rand() if err != nil { return Setup{}, err } // generate ρ (Rho): ρA, ρB, ρC - setup.Toxic.RhoA, err = rand.Prime(rand.Reader, bits) + setup.Toxic.RhoA, err = fqR.Rand() if err != nil { return Setup{}, err } - setup.Toxic.RhoB, err = rand.Prime(rand.Reader, bits) + setup.Toxic.RhoB, err = fqR.Rand() if err != nil { return Setup{}, err } - setup.Toxic.RhoC = bn.Fq1.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB) + setup.Toxic.RhoC = fqR.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB) // encrypt t values with curve generators var gt1 [][3]*big.Int var gt2 [][3][2]*big.Int for i := 0; i < witnessLength; i++ { - tPow := bn.Fq1.Exp(setup.Toxic.T, big.NewInt(int64(i))) + tPow := fqR.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) @@ -118,9 +119,9 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen setup.G1T = gt1 setup.G2T = gt2 - setup.Vk.A = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Ka) - setup.Vk.B = bn.G1.MulScalar(bn.G1.G, setup.Toxic.Kb) - setup.Vk.C = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kc) + setup.Vk.Vka = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Ka) + setup.Vk.Vkb = bn.G1.MulScalar(bn.G1.G, setup.Toxic.Kb) + setup.Vk.Vkc = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kc) /* Verification keys: @@ -128,16 +129,19 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen - Vk_betagamma2: setup.G2Kbg = g2 * Kbeta*Kgamma - Vk_gamma: setup.G2Kg = g2 * Kgamma */ - kbg := bn.Fq1.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma) + kbg := fqR.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma) setup.Vk.G1Kbg = bn.G1.MulScalar(bn.G1.G, kbg) setup.Vk.G2Kbg = bn.G2.MulScalar(bn.G2.G, kbg) setup.Vk.G2Kg = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kgamma) - for i := 0; i < witnessLength; i++ { - // A[i] = g1 * ax[t] + // for i := 0; i < circuit.NSignals; i++ { + for i := 0; i < circuit.NVars; i++ { at := pf.Eval(alphas[i], setup.Toxic.T) a := bn.G1.MulScalar(bn.G1.G, at) setup.Pk.A = append(setup.Pk.A, a) + if i <= circuit.NPublic { + setup.Vk.A = append(setup.Vk.A, a) + } bt := pf.Eval(betas[i], setup.Toxic.T) bg1 := bn.G1.MulScalar(bn.G1.G, bt) @@ -148,20 +152,27 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen c := bn.G1.MulScalar(bn.G1.G, ct) setup.Pk.C = append(setup.Pk.C, c) - kt := bn.Fq1.Add(bn.Fq1.Add(at, bt), ct) - k := bn.G1.MulScalar(bn.G1.G, kt) + kt := fqR.Add(fqR.Add(at, bt), ct) + k := bn.G1.Affine(bn.G1.MulScalar(bn.G1.G, kt)) + + ktest := bn.G1.Affine(bn.G1.Add(bn.G1.Add(a, bg1), c)) + if !bn.Fq2.Equal(k, ktest) { + os.Exit(1) + return setup, err + } setup.Pk.Ap = append(setup.Pk.Ap, bn.G1.MulScalar(a, setup.Toxic.Ka)) setup.Pk.Bp = append(setup.Pk.Bp, bn.G1.MulScalar(bg1, setup.Toxic.Kb)) setup.Pk.Cp = append(setup.Pk.Cp, bn.G1.MulScalar(c, setup.Toxic.Kc)) - setup.Pk.Kp = append(setup.Pk.Kp, bn.G1.MulScalar(k, setup.Toxic.Kbeta)) + k_ := bn.G1.MulScalar(bn.G1.G, kt) + setup.Pk.Kp = append(setup.Pk.Kp, bn.G1.MulScalar(k_, setup.Toxic.Kbeta)) } setup.Vk.Vkz = bn.G2.MulScalar(bn.G2.G, pf.Eval(zx, setup.Toxic.T)) return setup, nil } -func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) { +func GenerateProofs(bn bn128.Bn128, f fields.Fq, circuit compiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) { var proof Proof proof.PiA = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiAp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} @@ -172,12 +183,12 @@ func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w [ proof.PiH = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiKp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} - for i := 0; i < len(w); i++ { + for i := circuit.NPublic + 1; i < circuit.NVars; i++ { proof.PiA = bn.G1.Add(proof.PiA, bn.G1.MulScalar(setup.Pk.A[i], w[i])) proof.PiAp = bn.G1.Add(proof.PiAp, bn.G1.MulScalar(setup.Pk.Ap[i], w[i])) } - for i := 0; i < len(w); i++ { + for i := 0; i < circuit.NVars; i++ { proof.PiB = bn.G2.Add(proof.PiB, bn.G2.MulScalar(setup.Pk.B[i], w[i])) proof.PiBp = bn.G1.Add(proof.PiBp, bn.G1.MulScalar(setup.Pk.Bp[i], w[i])) @@ -186,122 +197,73 @@ func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w [ proof.PiKp = bn.G1.Add(proof.PiKp, bn.G1.MulScalar(setup.Pk.Kp[i], w[i])) } + for i := 0; i < len(hx); i++ { proof.PiH = bn.G1.Add(proof.PiH, bn.G1.MulScalar(setup.G1T[i], hx[i])) } + proof.PublicSignals = w[1 : circuit.NPublic+1] return proof, nil } -func VerifyProof(bn bn128.Bn128, setup Setup, proof Proof) bool { +func VerifyProof(bn bn128.Bn128, circuit compiler.Circuit, setup Setup, proof Proof) bool { // e(piA, Va) == e(piA', g2) - pairingPiaVa, err := bn.Pairing(proof.PiA, setup.Vk.A) - if err != nil { - return false - } - pairingPiapG2, err := bn.Pairing(proof.PiAp, bn.G2.G) - if err != nil { - return false - } + pairingPiaVa := bn.Pairing(proof.PiA, setup.Vk.Vka) + pairingPiapG2 := bn.Pairing(proof.PiAp, bn.G2.G) if !bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) { return false } else { - fmt.Println("valid knowledge commitment for A") + fmt.Println("✓ e(piA, Va) == e(piA', g2), valid knowledge commitment for A") } // e(Vb, piB) == e(piB', g2) - pairingVbPib, err := bn.Pairing(setup.Vk.B, proof.PiB) - if err != nil { - return false - } - pairingPibpG2, err := bn.Pairing(proof.PiBp, bn.G2.G) - if err != nil { - return false - } + pairingVbPib := bn.Pairing(setup.Vk.Vkb, proof.PiB) + pairingPibpG2 := bn.Pairing(proof.PiBp, bn.G2.G) if !bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { return false } else { - fmt.Println("valid knowledge commitment for B") + fmt.Println("✓ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B") } // e(piC, Vc) == e(piC', g2) - pairingPicVc, err := bn.Pairing(proof.PiC, setup.Vk.C) - if err != nil { - return false - } - pairingPicpG2, err := bn.Pairing(proof.PiCp, bn.G2.G) - if err != nil { - return false - } + pairingPicVc := bn.Pairing(proof.PiC, setup.Vk.Vkc) + pairingPicpG2 := bn.Pairing(proof.PiCp, bn.G2.G) if !bn.Fq12.Equal(pairingPicVc, pairingPicpG2) { return false } else { - fmt.Println("valid knowledge commitment for C") + fmt.Println("✓ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C") } // Vkx, to then calculate Vkx+piA + vkxpia := setup.Vk.A[0] + for i := 0; i < circuit.NPublic; i++ { + vkxpia = bn.G1.Add(vkxpia, bn.G1.MulScalar(setup.Vk.A[i+1], proof.PublicSignals[i])) + } // e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2) - pairingPiaPib, err := bn.Pairing(proof.PiA, proof.PiB) - if err != nil { - return false - } - pairingPihVkz, err := bn.Pairing(proof.PiH, setup.Vk.Vkz) - if err != nil { - return false - } - pairingPicG2, err := bn.Pairing(proof.PiC, bn.G2.G) - if err != nil { - return false - } - pairingR := bn.Fq12.Mul(pairingPihVkz, pairingPicG2) - if !bn.Fq12.Equal(pairingPiaPib, pairingR) { - fmt.Println("p4") + if !bn.Fq12.Equal( + bn.Pairing(bn.G1.Add(vkxpia, proof.PiA), proof.PiB), + bn.Fq12.Mul( + bn.Pairing(proof.PiH, setup.Vk.Vkz), + bn.Pairing(proof.PiC, bn.G2.G))) { return false } else { - fmt.Println("QAP disibility checked") + fmt.Println("✓ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked") } - // e(piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) + // e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) // == e(piK, g2Kgamma) - // piApiC := bn.G1.Add(proof.PiA, proof.PiC) - // pairingPiACG2Kbg, err := bn.Pairing(piApiC, setup.Vk.G2Kbg) - // if err != nil { - // return false - // } - // pairingG1KbgPiB, err := bn.Pairing(setup.Vk.G1Kbg, proof.PiB) - // if err != nil { - // return false - // } - // pairingL := bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB) - // pairingR, err := bn.Pairing(proof.PiKp, setup.Vk.G2Kg) - // if err != nil { - // return false - // } - // if !bn.Fq12.Equal(pairingL, pairingR) { - // fmt.Println("p5") - // 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, setup.Vk.Vkz) - // 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 - // } + piApiC := bn.G1.Add(bn.G1.Add(vkxpia, proof.PiA), proof.PiC) + pairingPiACG2Kbg := bn.Pairing(piApiC, setup.Vk.G2Kbg) + pairingG1KbgPiB := bn.Pairing(setup.Vk.G1Kbg, proof.PiB) + pairingL := bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB) + pairingR := bn.Pairing(proof.PiKp, setup.Vk.G2Kg) + if !bn.Fq12.Equal(pairingL, pairingR) { + return false + } else { + fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") + } return true } diff --git a/snark_test.go b/snark_test.go index 3f7a3fb..b3e3f7e 100644 --- a/snark_test.go +++ b/snark_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/arnaucube/go-snark/bn128" + "github.com/arnaucube/go-snark/compiler" "github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/r1csqap" "github.com/stretchr/testify/assert" @@ -16,10 +17,10 @@ func TestZk(t *testing.T) { assert.Nil(t, err) // new Finite Field - f := fields.NewFq(bn.R) + fqR := fields.NewFq(bn.R) // new Polynomial Field - pf := r1csqap.NewPolynomialField(f) + pf := r1csqap.NewPolynomialField(fqR) b0 := big.NewInt(int64(0)) b1 := big.NewInt(int64(1)) @@ -49,7 +50,13 @@ func TestZk(t *testing.T) { } alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) + // wittness = 1, 3, 35, 9, 27, 30 w := []*big.Int{b1, b3, b35, b9, b27, b30} + circuit := compiler.Circuit{ + NVars: 6, + NPublic: 0, + NSignals: len(w), + } ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) hx := pf.DivisorPolinomial(px, zx) @@ -62,23 +69,19 @@ func TestZk(t *testing.T) { assert.Equal(t, abc, px) hz := pf.Mul(hx, zx) assert.Equal(t, abc, hz) + + div, rem := pf.Div(px, zx) + assert.Equal(t, hx, div) + assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) // calculate trusted setup - setup, err := GenerateTrustedSetup(bn, pf, len(w), alphas, betas, gammas, ax, bx, cx, hx, zx) + setup, err := GenerateTrustedSetup(bn, fqR, pf, len(w), circuit, alphas, betas, gammas, zx) assert.Nil(t, err) - fmt.Println("trusted setup:") - fmt.Println(setup.G1T) - fmt.Println(setup.G2T) + fmt.Println("t", setup.Toxic.T) // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) - proof, err := GenerateProofs(bn, f, setup, hx, w) + proof, err := GenerateProofs(bn, fqR, circuit, setup, hx, w) assert.Nil(t, err) - fmt.Println("proofs:") - fmt.Println(proof.PiA) - fmt.Println(proof.PiB) - fmt.Println(proof.PiC) - fmt.Println(proof.PiH) - // fmt.Println(proof.Vz) - assert.True(t, VerifyProof(bn, setup, proof)) + assert.True(t, VerifyProof(bn, circuit, setup, proof)) }