diff --git a/README.md b/README.md index 092cfa6..d894590 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ zkSNARK library implementation in Go - `Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf ## Caution -Implementation from scratch in Go to understand the concepts. Do not use in production. +Implementation of the zkSNARK [Pinocchio protocol](https://eprint.iacr.org/2013/279.pdf) 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. @@ -15,17 +15,18 @@ Current implementation status: - [x] Finite Fields (1, 2, 6, 12) operations - [x] G1 and G2 curve operations - [x] BN128 Pairing -- [x] circuit code compiler +- [ ] circuit code compiler - [ ] code to flat code (improve circuit compiler) - [x] flat code compiler + - [ ] private & public inputs. fix circuit compiler - [x] circuit to R1CS - [x] polynomial operations - [x] R1CS to QAP - [x] generate trusted setup - [x] generate proofs - [x] verify proofs with BN128 pairing - - [ ] fix 4th pairing proofs generation & verification: ê(Vkx+piA, piB) == ê(piH, Vkz) * ê(piC, g2) -- [ ] WASM implementation to run on browsers + - [ ] fix 4th pairing proofs generation & verification: ê(Vkx+piA, piB) == ê(piH, Vkz) * ê(piC, G2) +- [ ] move witness calculation outside the setup phase ## Usage diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go index a811b98..7429b74 100644 --- a/r1csqap/r1csqap.go +++ b/r1csqap/r1csqap.go @@ -189,24 +189,24 @@ func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*bi // CombinePolynomials combine the given polynomials arrays into one, also returns the P(x) func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) { - var alpha []*big.Int + var ax []*big.Int for i := 0; i < len(r); i++ { m := pf.Mul([]*big.Int{r[i]}, ap[i]) - alpha = pf.Add(alpha, m) + ax = pf.Add(ax, m) } - var beta []*big.Int + var bx []*big.Int for i := 0; i < len(r); i++ { m := pf.Mul([]*big.Int{r[i]}, bp[i]) - beta = pf.Add(beta, m) + bx = pf.Add(bx, m) } - var gamma []*big.Int + var cx []*big.Int for i := 0; i < len(r); i++ { m := pf.Mul([]*big.Int{r[i]}, cp[i]) - gamma = pf.Add(gamma, m) + cx = pf.Add(cx, m) } - px := pf.Sub(pf.Mul(alpha, beta), gamma) - return alpha, beta, gamma, px + px := pf.Sub(pf.Mul(ax, bx), cx) + return ax, bx, cx, px } // DivisorPolynomial returns the divisor polynomial given two polynomials diff --git a/snark.go b/snark.go index cc6fe1c..581fc6c 100644 --- a/snark.go +++ b/snark.go @@ -99,13 +99,15 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al for i := 0; i < len(alphas); i++ { for j := 0; j < len(alphas[i]); j++ { if j <= circuit.NPublic { - if bytes.Equal(alphas[i][j].Bytes(), Utils.Bn.Fq1.Zero().Bytes()) { - alphas[i][j] = Utils.Bn.Fq1.One() + if bytes.Equal(alphas[i][j].Bytes(), Utils.FqR.Zero().Bytes()) { + alphas[i][j] = Utils.FqR.One() } } } } + fmt.Println("alphas[1]", alphas[1]) + // generate random t value setup.Toxic.T, err = Utils.FqR.Rand() if err != nil { @@ -176,7 +178,8 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al // for i := 0; i < circuit.NVars; i++ { for i := 0; i < len(circuit.Signals); i++ { at := Utils.PF.Eval(alphas[i], setup.Toxic.T) - rhoAat := Utils.Bn.Fq1.Mul(setup.Toxic.RhoA, at) + // rhoAat := Utils.Bn.Fq1.Mul(setup.Toxic.RhoA, at) + rhoAat := Utils.FqR.Mul(setup.Toxic.RhoA, at) a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoAat) setup.Pk.A = append(setup.Pk.A, a) if i <= circuit.NPublic { @@ -184,13 +187,15 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al } bt := Utils.PF.Eval(betas[i], setup.Toxic.T) - rhoBbt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoB, bt) + // rhoBbt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoB, bt) + rhoBbt := Utils.FqR.Mul(setup.Toxic.RhoB, bt) bg1 := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoBbt) bg2 := Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, rhoBbt) setup.Pk.B = append(setup.Pk.B, bg2) ct := Utils.PF.Eval(gammas[i], setup.Toxic.T) - rhoCct := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, ct) + // rhoCct := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, ct) + rhoCct := Utils.FqR.Mul(setup.Toxic.RhoC, ct) c := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoCct) setup.Pk.C = append(setup.Pk.C, c) @@ -212,8 +217,7 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al // z pol zpol := []*big.Int{big.NewInt(int64(1))} - // for i := 1; i < len(circuit.Constraints); i++ { - for i := 1; i <= circuit.NPublic; i++ { // circuit.NPublic == d + for i := 1; i < len(circuit.Constraints); i++ { zpol = Utils.PF.Mul( zpol, []*big.Int{ @@ -222,10 +226,12 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al big.NewInt(int64(1)), }) } + fmt.Println("zpol", zpol) setup.Pk.Z = zpol zt := Utils.PF.Eval(zpol, setup.Toxic.T) - rhoCzt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, zt) + // rhoCzt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, zt) + rhoCzt := Utils.FqR.Mul(setup.Toxic.RhoC, zt) setup.Vk.Vkz = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, rhoCzt) // encrypt t values with curve generators @@ -234,7 +240,8 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al tEncr := setup.Toxic.T for i := 1; i < len(zpol); i++ { //should be G1T = pkH = (tau**i * G1) from i=0 to d, where d is degree of pol Z(x) gt1 = append(gt1, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tEncr)) - tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T) + // tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T) + tEncr = Utils.FqR.Mul(tEncr, setup.Toxic.T) } fmt.Println("len(G1T)", len(gt1)) setup.G1T = gt1 @@ -272,8 +279,8 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) // maybe move this calculation to a previous step // piH = pkH,0 + sum ( hi * pk H,i ), where pkH = G1T, hi=hx - proof.PiH = Utils.Bn.G1.Add(proof.PiH, setup.G1T[0]) - for i := 1; i < len(setup.Pk.Z); i++ { + // proof.PiH = Utils.Bn.G1.Add(proof.PiH, setup.G1T[0]) + for i := 0; i < len(hx); i++ { proof.PiH = Utils.Bn.G1.Add(proof.PiH, Utils.Bn.G1.MulScalar(setup.G1T[i], hx[i])) } diff --git a/snark_test.go b/snark_test.go index bcf7827..0fe0de6 100644 --- a/snark_test.go +++ b/snark_test.go @@ -50,10 +50,11 @@ func TestZkFromFlatCircuitCode(t *testing.T) { fmt.Println("c:", c) // R1CS to QAP + // TODO zxQAP is not used and is an old impl, bad calculated. TODO remove alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c) fmt.Println("qap") fmt.Println("alphas", len(alphas)) - fmt.Println("alphas", alphas[0]) + fmt.Println("alphas[1]", alphas[1]) fmt.Println("betas", len(betas)) fmt.Println("gammas", len(gammas)) fmt.Println("zx length", len(zxQAP)) @@ -63,6 +64,10 @@ func TestZkFromFlatCircuitCode(t *testing.T) { fmt.Println("bx length", len(bx)) fmt.Println("cx length", len(cx)) fmt.Println("px length", len(px)) + fmt.Println("px[last]", px[0]) + px0 := Utils.PF.F.Add(px[0], big.NewInt(int64(88))) + fmt.Println(px0) + assert.Equal(t, px0.Bytes(), Utils.PF.F.Zero().Bytes()) hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP) fmt.Println("hx length", len(hxQAP)) @@ -92,15 +97,18 @@ func TestZkFromFlatCircuitCode(t *testing.T) { hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) fmt.Println("hx pk.z", hx) // assert.Equal(t, hxQAP, hx) + assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP)) + // hx==px/zx so px==hx*zx assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z)) + // check length of polynomials H(x) and Z(x) assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1) assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1) + // fmt.Println("pk.Z", len(setup.Pk.Z)) // fmt.Println("zxQAP", len(zxQAP)) - // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) proof, err := GenerateProofs(*circuit, setup, w, px) assert.Nil(t, err)