diff --git a/.gitignore b/.gitignore index 26876d4..21807d4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ cli/proofs.json cli/test.circuit cli/trustedsetup.json tmp +tmpBackup diff --git a/README.md b/README.md index 2db9d3d..092cfa6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Current implementation status: - [x] generate trusted setup - [x] generate proofs - [x] verify proofs with BN128 pairing - - [ ] fix 4th pairing proofs generation & verification + - [ ] fix 4th pairing proofs generation & verification: ê(Vkx+piA, piB) == ê(piH, Vkz) * ê(piC, g2) - [ ] WASM implementation to run on browsers @@ -36,6 +36,8 @@ Current implementation status: - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler) Circuit Compiler ### Library usage +Warning: not finished. + Example: ```go // compile circuit and get the R1CS diff --git a/circuitcompiler/circuit.go b/circuitcompiler/circuit.go index 9cb0070..de3d147 100644 --- a/circuitcompiler/circuit.go +++ b/circuitcompiler/circuit.go @@ -153,6 +153,7 @@ type Inputs struct { } // CalculateWitness calculates the Witness of a Circuit based on the given inputs +// witness = [ one, output, publicInputs, privateInputs, ...] func (circ *Circuit) CalculateWitness(inputs []*big.Int) ([]*big.Int, error) { if len(inputs) != len(circ.Inputs) { return []*big.Int{}, errors.New("given inputs != circuit.Inputs") diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go index 88b532d..a811b98 100644 --- a/r1csqap/r1csqap.go +++ b/r1csqap/r1csqap.go @@ -175,10 +175,14 @@ func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*bi gammas = append(gammas, pf.LagrangeInterpolation(cT[i])) } z := []*big.Int{big.NewInt(int64(1))} - for i := 1; i < len(aT[0])+1; i++ { - ineg := big.NewInt(int64(-i)) - b1 := big.NewInt(int64(1)) - z = pf.Mul(z, []*big.Int{ineg, b1}) + for i := 1; i < len(alphas)-1; i++ { + z = pf.Mul( + z, + []*big.Int{ + pf.F.Neg( + big.NewInt(int64(i))), + big.NewInt(int64(1)), + }) } return alphas, betas, gammas, z } diff --git a/r1csqap/r1csqap_test.go b/r1csqap/r1csqap_test.go index 08c4597..54dba62 100644 --- a/r1csqap/r1csqap_test.go +++ b/r1csqap/r1csqap_test.go @@ -2,7 +2,6 @@ package r1csqap import ( "bytes" - "fmt" "math/big" "testing" @@ -31,9 +30,14 @@ func TestTranspose(t *testing.T) { }) } +func neg(a *big.Int) *big.Int { + return new(big.Int).Neg(a) +} + func TestPol(t *testing.T) { b0 := big.NewInt(int64(0)) b1 := big.NewInt(int64(1)) + b2 := big.NewInt(int64(2)) b3 := big.NewInt(int64(3)) b4 := big.NewInt(int64(4)) b5 := big.NewInt(int64(5)) @@ -55,6 +59,17 @@ func TestPol(t *testing.T) { o := pf.Mul(a, b) assert.Equal(t, o, []*big.Int{b3, b0, b16, b0, b5}) + // polynomial division + quo, rem := pf.Div(a, b) + assert.Equal(t, quo[0].Int64(), int64(5)) + assert.Equal(t, new(big.Int).Sub(rem[0], r).Int64(), int64(-14)) // check the rem result without modulo + + c := []*big.Int{neg(b4), b0, neg(b2), b1} + d := []*big.Int{neg(b3), b1} + quo2, rem2 := pf.Div(c, d) + assert.Equal(t, quo2, []*big.Int{b3, b1, b1}) + assert.Equal(t, rem2[0].Int64(), int64(5)) + // polynomial addition o = pf.Add(a, b) assert.Equal(t, o, []*big.Int{b4, b0, b6}) @@ -67,8 +82,8 @@ func TestPol(t *testing.T) { assert.True(t, bytes.Equal(b0.Bytes(), o[1].Bytes())) assert.True(t, bytes.Equal(b0.Bytes(), o[2].Bytes())) - c := []*big.Int{b5, b6, b1} - d := []*big.Int{b1, b3} + c = []*big.Int{b5, b6, b1} + d = []*big.Int{b1, b3} o = pf.Sub(c, d) assert.Equal(t, o, []*big.Int{b4, b3, b1}) @@ -133,21 +148,21 @@ func TestR1CSToQAP(t *testing.T) { []*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.Print("Z(x): ") - fmt.Println(zx) + // fmt.Println(alphas) + // fmt.Println(betas) + // fmt.Println(gammas) + // fmt.Print("Z(x): ") + // fmt.Println(zx) 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) + // fmt.Println(ax) + // fmt.Println(bx) + // fmt.Println(cx) + // fmt.Println(px) hx := pf.DivisorPolynomial(px, zx) - fmt.Println(hx) + // fmt.Println(hx) // hx==px/zx so px==hx*zx assert.Equal(t, px, pf.Mul(hx, zx)) diff --git a/snark.go b/snark.go index fe7dbe6..cc6fe1c 100644 --- a/snark.go +++ b/snark.go @@ -27,7 +27,7 @@ type Setup struct { } // public - G1T [][3]*big.Int // t encrypted in G1 curve + G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H G2T [][3][2]*big.Int // t encrypted in G2 curve Pk struct { // Proving Key pk:=(pkA, pkB, pkC, pkH) A [][3]*big.Int @@ -37,6 +37,7 @@ type Setup struct { Ap [][3]*big.Int Bp [][3]*big.Int Cp [][3]*big.Int + Z []*big.Int } Vk struct { Vka [3][2]*big.Int @@ -90,7 +91,7 @@ func prepareUtils() utils { } // GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed -func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) { +func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error) { var setup Setup var err error @@ -146,15 +147,7 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al } setup.Toxic.RhoC = Utils.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 - gt1 = append(gt1, Utils.Bn.G1.G) - tEncr := setup.Toxic.T - for i := 1; i < witnessLength; i++ { - gt1 = append(gt1, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tEncr)) - tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T) - } + // calculated more down // for i := 0; i < witnessLength; i++ { // tPow := Utils.FqR.Exp(setup.Toxic.T, big.NewInt(int64(i))) // tEncr1 := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tPow) @@ -164,8 +157,6 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al // } // gt1: g1, g1*t, g1*t^2, g1*t^3, ... // gt2: g2, g2*t, g2*t^2, ... - setup.G1T = gt1 - setup.G2T = gt2 setup.Vk.Vka = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Ka) setup.Vk.Vkb = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kb) @@ -182,7 +173,8 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al setup.Vk.G2Kbg = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, kbg) setup.Vk.G2Kg = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kgamma) - for i := 0; i < circuit.NVars; i++ { + // 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) a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoAat) @@ -217,15 +209,41 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al k_ := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, kt) setup.Pk.Kp = append(setup.Pk.Kp, Utils.Bn.G1.MulScalar(k_, setup.Toxic.Kbeta)) } - zt := Utils.PF.Eval(zx, setup.Toxic.T) + + // 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 + zpol = Utils.PF.Mul( + zpol, + []*big.Int{ + Utils.FqR.Neg( // neg over R + big.NewInt(int64(i))), + big.NewInt(int64(1)), + }) + } + setup.Pk.Z = zpol + + zt := Utils.PF.Eval(zpol, setup.Toxic.T) rhoCzt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, zt) setup.Vk.Vkz = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, rhoCzt) + // encrypt t values with curve generators + var gt1 [][3]*big.Int + gt1 = append(gt1, Utils.Bn.G1.G) // the first is t**0 * G1 = 1 * G1 = G1 + 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) + } + fmt.Println("len(G1T)", len(gt1)) + setup.G1T = gt1 + return setup, nil } // GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness -func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) { +func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, px []*big.Int) (Proof, error) { var proof Proof proof.PiA = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} proof.PiAp = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} @@ -251,7 +269,11 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int, proof.PiKp = Utils.Bn.G1.Add(proof.PiKp, Utils.Bn.G1.MulScalar(setup.Pk.Kp[i], w[i])) } - for i := 0; i < len(hx); i++ { + 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, Utils.Bn.G1.MulScalar(setup.G1T[i], hx[i])) } @@ -259,14 +281,14 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int, } // VerifyProof verifies over the BN128 the Pairings of the Proof -func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, printVer bool) bool { +func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, debug bool) bool { // e(piA, Va) == e(piA', g2) pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka) pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G) if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) { return false } - if printVer { + if debug { fmt.Println("✓ e(piA, Va) == e(piA', g2), valid knowledge commitment for A") } @@ -276,7 +298,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { return false } - if printVer { + if debug { fmt.Println("✓ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B") } @@ -286,13 +308,14 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) { return false } - if printVer { + if debug { fmt.Println("✓ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C") } // Vkx, to then calculate Vkx+piA vkxpia := setup.Vk.IC[0] for i := 0; i < len(publicSignals); i++ { + fmt.Println("pub sig", publicSignals[i]) vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i+1], publicSignals[i])) } @@ -304,7 +327,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) { return false } - if printVer { + if debug { fmt.Println("✓ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked") } @@ -318,7 +341,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ if !Utils.Bn.Fq12.Equal(pairingL, pairingR) { return false } - if printVer { + if debug { fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") } diff --git a/snark_test.go b/snark_test.go index 3f9ef7e..bcf7827 100644 --- a/snark_test.go +++ b/snark_test.go @@ -13,31 +13,36 @@ import ( "github.com/stretchr/testify/assert" ) -/* -func TestZkMultiplication(t *testing.T) { +func TestZkFromFlatCircuitCode(t *testing.T) { // compile circuit and get the R1CS flatCode := ` - func test(a, b): - out = a * b + func test(x): + aux = x*x + y = aux*x + z = x + y + out = z + 5 ` + fmt.Print("\nflat code of the circuit:") + fmt.Println(flatCode) // parse the code parser := circuitcompiler.NewParser(strings.NewReader(flatCode)) circuit, err := parser.Parse() assert.Nil(t, err) + fmt.Println("\ncircuit data:", circuit) + circuitJson, _ := json.Marshal(circuit) + fmt.Println("circuit:", string(circuitJson)) b3 := big.NewInt(int64(3)) - b4 := big.NewInt(int64(4)) - inputs := []*big.Int{b3, b4} + privateInputs := []*big.Int{b3} // wittness - w, err := circuit.CalculateWitness(inputs) + w, err := circuit.CalculateWitness(privateInputs) assert.Nil(t, err) - - fmt.Println("circuit") - fmt.Println(circuit.NPublic) + fmt.Println("\nwitness", w) // flat code to R1CS + fmt.Println("\ngenerating R1CS from flat code") a, b, c := circuit.GenerateR1CS() fmt.Println("\nR1CS:") fmt.Println("a:", a) @@ -45,74 +50,99 @@ func TestZkMultiplication(t *testing.T) { fmt.Println("c:", c) // R1CS to QAP - alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c) + alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c) fmt.Println("qap") - fmt.Println("alphas", alphas) - fmt.Println("betas", betas) - fmt.Println("gammas", gammas) + fmt.Println("alphas", len(alphas)) + fmt.Println("alphas", alphas[0]) + fmt.Println("betas", len(betas)) + fmt.Println("gammas", len(gammas)) + fmt.Println("zx length", len(zxQAP)) ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas) + fmt.Println("ax length", len(ax)) + fmt.Println("bx length", len(bx)) + fmt.Println("cx length", len(cx)) + fmt.Println("px length", len(px)) - hx := Utils.PF.DivisorPolynomial(px, zx) + hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP) + fmt.Println("hx length", len(hxQAP)) // hx==px/zx so px==hx*zx - assert.Equal(t, px, Utils.PF.Mul(hx, zx)) + assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP)) // p(x) = a(x) * b(x) - c(x) == h(x) * z(x) abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx) assert.Equal(t, abc, px) - hz := Utils.PF.Mul(hx, zx) - assert.Equal(t, abc, hz) + hzQAP := Utils.PF.Mul(hxQAP, zxQAP) + assert.Equal(t, abc, hzQAP) - div, rem := Utils.PF.Div(px, zx) - assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1)) + div, rem := Utils.PF.Div(px, zxQAP) + assert.Equal(t, hxQAP, div) + assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) // calculate trusted setup - setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx) + setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas) assert.Nil(t, err) + fmt.Println("\nt:", setup.Toxic.T) + + // zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation + // assert.Equal(t, zxQAP, setup.Pk.Z) + + fmt.Println("hx pk.z", hxQAP) + 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)) + assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z)) + + 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, hx, w) + proof, err := GenerateProofs(*circuit, setup, w, px) assert.Nil(t, err) - // assert.True(t, VerifyProof(*circuit, setup, proof, false)) + // fmt.Println("\n proofs:") + // fmt.Println(proof) + + // fmt.Println("public signals:", proof.PublicSignals) + fmt.Println("\nwitness", w) + // b1 := big.NewInt(int64(1)) b35 := big.NewInt(int64(35)) + // publicSignals := []*big.Int{b1, b35} publicSignals := []*big.Int{b35} + before := time.Now() assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true)) + fmt.Println("verify proof time elapsed:", time.Since(before)) } -*/ -func TestZkFromFlatCircuitCode(t *testing.T) { +/* +func TestZkMultiplication(t *testing.T) { // compile circuit and get the R1CS flatCode := ` - func test(x): - aux = x*x - y = aux*x - z = x + y - out = z + 5 + func test(a, b): + out = a * b ` - fmt.Print("\nflat code of the circuit:") - fmt.Println(flatCode) // parse the code parser := circuitcompiler.NewParser(strings.NewReader(flatCode)) circuit, err := parser.Parse() assert.Nil(t, err) - fmt.Println("\ncircuit data:", circuit) - circuitJson, _ := json.Marshal(circuit) - fmt.Println("circuit:", string(circuitJson)) b3 := big.NewInt(int64(3)) - privateInputs := []*big.Int{b3} + b4 := big.NewInt(int64(4)) + inputs := []*big.Int{b3, b4} // wittness - w, err := circuit.CalculateWitness(privateInputs) + w, err := circuit.CalculateWitness(inputs) assert.Nil(t, err) - fmt.Println("\nwitness", w) + + fmt.Println("circuit") + fmt.Println(circuit.NPublic) // flat code to R1CS - fmt.Println("\ngenerating R1CS from flat code") a, b, c := circuit.GenerateR1CS() fmt.Println("\nR1CS:") fmt.Println("a:", a) @@ -125,13 +155,8 @@ func TestZkFromFlatCircuitCode(t *testing.T) { fmt.Println("alphas", alphas) fmt.Println("betas", betas) fmt.Println("gammas", gammas) - fmt.Println("zx", zx) ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas) - fmt.Println("ax", ax) - // fmt.Println("bx", bx) - // fmt.Println("cx", cx) - // fmt.Println("px", px) hx := Utils.PF.DivisorPolynomial(px, zx) @@ -146,32 +171,22 @@ func TestZkFromFlatCircuitCode(t *testing.T) { div, rem := Utils.PF.Div(px, zx) assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) + assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1)) // calculate trusted setup setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx) - // setup, err := GenerateTrustedSetup(len(w), *circuit, ax, bx, cx, zx) assert.Nil(t, err) - fmt.Println("\nt:", setup.Toxic.T) // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) proof, err := GenerateProofs(*circuit, setup, hx, w) assert.Nil(t, err) - fmt.Println("IC", setup.Vk.IC) - - // fmt.Println("\n proofs:") - // fmt.Println(proof) - // fmt.Println("public signals:", proof.PublicSignals) - fmt.Println("\nwitness", w) + // assert.True(t, VerifyProof(*circuit, setup, proof, false)) b35 := big.NewInt(int64(35)) publicSignals := []*big.Int{b35} - fmt.Println("public signals:", publicSignals) - before := time.Now() assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true)) - fmt.Println("verify proof time elapsed:", time.Since(before)) } - +*/ /* func TestZkFromHardcodedR1CS(t *testing.T) { b0 := big.NewInt(int64(0))