From 54a265e73b0aae9e87211ca5d2810ec7e3713228 Mon Sep 17 00:00:00 2001 From: Ali Kefia Date: Tue, 18 Jun 2019 23:35:47 +0200 Subject: [PATCH] move pf to fields and qap conversion to proof module --- circuit/circuit.go | 10 +- circuit/circuit_test.go | 83 ++++---- cmd/go-snark/compile.go | 74 +------ cmd/go-snark/generate.go | 15 +- cmd/go-snark/main.go | 6 + cmd/go-snark/setup.go | 19 +- cmd/go-snark/test.go | 77 ++++++++ cmd/go-snark/verify.go | 18 +- r1csqap/r1csqap.go => fields/pf.go | 64 ++----- r1csqap/r1csqap_test.go => fields/pf_test.go | 73 +------ install | 6 + proof/groth16.go | 46 ++--- proof/groth16_test.go | 71 +++---- proof/pinocchio.go | 131 +++---------- proof/pinocchio_test.go | 192 ++++++++----------- proof/proof.go | 49 ++--- proof/qap.go | 37 ++++ proof/qap_test.go | 73 +++++++ r1csqap/README.md | 54 ------ 19 files changed, 452 insertions(+), 646 deletions(-) create mode 100644 cmd/go-snark/test.go rename r1csqap/r1csqap.go => fields/pf.go (65%) rename r1csqap/r1csqap_test.go => fields/pf_test.go (60%) create mode 100755 install create mode 100644 proof/qap.go create mode 100644 proof/qap_test.go delete mode 100644 r1csqap/README.md diff --git a/circuit/circuit.go b/circuit/circuit.go index de7d8a5..3655b0d 100644 --- a/circuit/circuit.go +++ b/circuit/circuit.go @@ -5,7 +5,7 @@ import ( "math/big" "strconv" - "github.com/arnaucube/go-snark/r1csqap" + "github.com/arnaucube/go-snark/fields" ) // Circuit is the data structure of the compiled circuit @@ -90,9 +90,9 @@ func (circ *Circuit) GenerateR1CS() ([][]*big.Int, [][]*big.Int, [][]*big.Int) { used := make(map[string]bool) for _, constraint := range circ.Constraints { - aConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals)) - bConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals)) - cConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals)) + aConstraint := fields.ArrayOfBigZeros(len(circ.Signals)) + bConstraint := fields.ArrayOfBigZeros(len(circ.Signals)) + cConstraint := fields.ArrayOfBigZeros(len(circ.Signals)) // if existInArray(constraint.Out) { // if used[constraint.Out] { @@ -162,7 +162,7 @@ func (circ *Circuit) CalculateWitness(privateInputs []*big.Int, publicInputs []* if len(publicInputs) != len(circ.PublicInputs) { return []*big.Int{}, errors.New("given publicInputs != circuit.PublicInputs") } - w := r1csqap.ArrayOfBigZeros(len(circ.Signals)) + w := fields.ArrayOfBigZeros(len(circ.Signals)) w[0] = big.NewInt(int64(1)) for i, input := range publicInputs { w[i+1] = input diff --git a/circuit/circuit_test.go b/circuit/circuit_test.go index ec68d4e..e53c566 100644 --- a/circuit/circuit_test.go +++ b/circuit/circuit_test.go @@ -22,15 +22,15 @@ func TestCircuitParser(t *testing.T) { out = 1 * 1 ` parser := NewParser(strings.NewReader(flat)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) // flat code to R1CS - a, b, c := circuit.GenerateR1CS() - assert.Equal(t, "s0", circuit.PrivateInputs[0]) - assert.Equal(t, "s1", circuit.PublicInputs[0]) + cir.GenerateR1CS() + assert.Equal(t, "s0", cir.PrivateInputs[0]) + assert.Equal(t, "s1", cir.PublicInputs[0]) - assert.Equal(t, []string{"one", "s1", "s0", "s2", "s3", "s4", "s5", "out"}, circuit.Signals) + assert.Equal(t, []string{"one", "s1", "s0", "s2", "s3", "s4", "s5", "out"}, cir.Signals) // expected result b0 := big.NewInt(int64(0)) @@ -64,16 +64,16 @@ func TestCircuitParser(t *testing.T) { []*big.Int{b0, b0, b0, b0, b0, b0, b0, b1}, } - assert.Equal(t, aExpected, a) - assert.Equal(t, bExpected, b) - assert.Equal(t, cExpected, c) + assert.Equal(t, aExpected, cir.R1CS.A) + assert.Equal(t, bExpected, cir.R1CS.B) + assert.Equal(t, cExpected, cir.R1CS.C) b3 := big.NewInt(int64(3)) privateInputs := []*big.Int{b3} b35 := big.NewInt(int64(35)) publicInputs := []*big.Int{b35} // Calculate Witness - w, err := circuit.CalculateWitness(privateInputs, publicInputs) + w, err := cir.CalculateWitness(privateInputs, publicInputs) assert.Nil(t, err) b9 := big.NewInt(int64(9)) b27 := big.NewInt(int64(27)) @@ -81,12 +81,9 @@ func TestCircuitParser(t *testing.T) { wExpected := []*big.Int{b1, b35, b3, b9, b27, b30, b35, b1} assert.Equal(t, wExpected, w) - // circuitJson, _ := json.Marshal(circuit) - // fmt.Println("circuit:", string(circuitJson)) - - assert.Equal(t, circuit.NPublic, 1) - assert.Equal(t, len(circuit.PublicInputs), 1) - assert.Equal(t, len(circuit.PrivateInputs), 1) + assert.Equal(t, cir.NPublic, 1) + assert.Equal(t, len(cir.PublicInputs), 1) + assert.Equal(t, len(cir.PrivateInputs), 1) } func TestCircuitWithFuncCallsParser(t *testing.T) { @@ -108,15 +105,15 @@ func TestCircuitWithFuncCallsParser(t *testing.T) { out = 1 * 1 ` parser := NewParser(strings.NewReader(code)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) // flat code to R1CS - a, b, c := circuit.GenerateR1CS() - assert.Equal(t, "s0", circuit.PrivateInputs[0]) - assert.Equal(t, "s1", circuit.PublicInputs[0]) + cir.GenerateR1CS() + assert.Equal(t, "s0", cir.PrivateInputs[0]) + assert.Equal(t, "s1", cir.PublicInputs[0]) - assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, circuit.Signals) + assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, cir.Signals) // expected result b0 := big.NewInt(int64(0)) @@ -150,16 +147,16 @@ func TestCircuitWithFuncCallsParser(t *testing.T) { []*big.Int{b0, b0, b0, b0, b0, b0, b0, b1}, } - assert.Equal(t, aExpected, a) - assert.Equal(t, bExpected, b) - assert.Equal(t, cExpected, c) + assert.Equal(t, aExpected, cir.R1CS.A) + assert.Equal(t, bExpected, cir.R1CS.B) + assert.Equal(t, cExpected, cir.R1CS.C) b3 := big.NewInt(int64(3)) privateInputs := []*big.Int{b3} b35 := big.NewInt(int64(35)) publicInputs := []*big.Int{b35} - // Calculate Witness - w, err := circuit.CalculateWitness(privateInputs, publicInputs) + + w, err := cir.CalculateWitness(privateInputs, publicInputs) assert.Nil(t, err) b9 := big.NewInt(int64(9)) b27 := big.NewInt(int64(27)) @@ -167,12 +164,9 @@ func TestCircuitWithFuncCallsParser(t *testing.T) { wExpected := []*big.Int{b1, b35, b3, b9, b27, b30, b35, b1} assert.Equal(t, wExpected, w) - // circuitJson, _ := json.Marshal(circuit) - // fmt.Println("circuit:", string(circuitJson)) - - assert.Equal(t, circuit.NPublic, 1) - assert.Equal(t, len(circuit.PublicInputs), 1) - assert.Equal(t, len(circuit.PrivateInputs), 1) + assert.Equal(t, cir.NPublic, 1) + assert.Equal(t, len(cir.PublicInputs), 1) + assert.Equal(t, len(cir.PrivateInputs), 1) } func TestCircuitFromFileWithImports(t *testing.T) { @@ -180,15 +174,15 @@ func TestCircuitFromFileWithImports(t *testing.T) { assert.Nil(t, err) parser := NewParser(bufio.NewReader(circuitFile)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) // flat code to R1CS - a, b, c := circuit.GenerateR1CS() - assert.Equal(t, "s0", circuit.PrivateInputs[0]) - assert.Equal(t, "s1", circuit.PublicInputs[0]) + cir.GenerateR1CS() + assert.Equal(t, "s0", cir.PrivateInputs[0]) + assert.Equal(t, "s1", cir.PublicInputs[0]) - assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, circuit.Signals) + assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, cir.Signals) // expected result b0 := big.NewInt(int64(0)) @@ -222,16 +216,16 @@ func TestCircuitFromFileWithImports(t *testing.T) { []*big.Int{b0, b0, b0, b0, b0, b0, b0, b1}, } - assert.Equal(t, aExpected, a) - assert.Equal(t, bExpected, b) - assert.Equal(t, cExpected, c) + assert.Equal(t, aExpected, cir.R1CS.A) + assert.Equal(t, bExpected, cir.R1CS.B) + assert.Equal(t, cExpected, cir.R1CS.C) b3 := big.NewInt(int64(3)) privateInputs := []*big.Int{b3} b35 := big.NewInt(int64(35)) publicInputs := []*big.Int{b35} // Calculate Witness - w, err := circuit.CalculateWitness(privateInputs, publicInputs) + w, err := cir.CalculateWitness(privateInputs, publicInputs) assert.Nil(t, err) b9 := big.NewInt(int64(9)) b27 := big.NewInt(int64(27)) @@ -239,10 +233,7 @@ func TestCircuitFromFileWithImports(t *testing.T) { wExpected := []*big.Int{b1, b35, b3, b9, b27, b30, b35, b1} assert.Equal(t, wExpected, w) - // circuitJson, _ := json.Marshal(circuit) - // fmt.Println("circuit:", string(circuitJson)) - - assert.Equal(t, circuit.NPublic, 1) - assert.Equal(t, len(circuit.PublicInputs), 1) - assert.Equal(t, len(circuit.PrivateInputs), 1) + assert.Equal(t, cir.NPublic, 1) + assert.Equal(t, len(cir.PublicInputs), 1) + assert.Equal(t, len(cir.PrivateInputs), 1) } diff --git a/cmd/go-snark/compile.go b/cmd/go-snark/compile.go index e33f260..839532f 100644 --- a/cmd/go-snark/compile.go +++ b/cmd/go-snark/compile.go @@ -1,97 +1,31 @@ package main import ( - "bytes" - "fmt" - "log" - "math/big" "os" "github.com/urfave/cli" "github.com/arnaucube/go-snark/circuit" - "github.com/arnaucube/go-snark/proof" - "github.com/arnaucube/go-snark/r1csqap" ) func compile(context *cli.Context) error { circuitPath := context.Args().Get(0) - // load compiled + // load circuit circuitFile, err := os.Open(circuitPath) if err != nil { return err } parser := circuit.NewParser(circuitFile) - cir, err := parser.Parse() - if err != nil { - return err - } - log.Printf("circuit: %v\n", cir) - // load inputs - var inputs circuit.Inputs - if err := loadFromFile(privateFileName, &inputs.Private); err != nil { - return err - } - if err := loadFromFile(publicFileName, &inputs.Public); err != nil { - return err - } - - // calculate witness - w, err := cir.CalculateWitness(inputs.Private, inputs.Public) + // parse circuit + cir, err := parser.Parse() if err != nil { return err } - log.Printf("w: %v\n", w) // flat code to R1CS - a, b, c := cir.GenerateR1CS() - log.Printf("a: %v\n", a) - log.Printf("b: %v\n", b) - log.Printf("c: %v\n", c) - - // R1CS to QAP - alphas, betas, gammas, zx := proof.Utils.PF.R1CSToQAP(a, b, c) - log.Printf("alphas: %v\n", alphas) - log.Printf("betas: %v\n", betas) - log.Printf("gammas: %v\n", gammas) - log.Printf("zx: %v\n", zx) - - ax, bx, cx, px := proof.Utils.PF.CombinePolynomials(w, alphas, betas, gammas) - - hx := proof.Utils.PF.DivisorPolynomial(px, zx) - - // hx==px/zx so px==hx*zx - // assert.Equal(t, px, snark.Utils.PF.Mul(hx, zx)) - if !r1csqap.BigArraysEqual(px, proof.Utils.PF.Mul(hx, zx)) { - return fmt.Errorf("px != hx*zx") - } - - // p(x) = a(x) * b(x) - c(x) == h(x) * z(x) - abc := proof.Utils.PF.Sub(proof.Utils.PF.Mul(ax, bx), cx) - // assert.Equal(t, abc, px) - if !r1csqap.BigArraysEqual(abc, px) { - return fmt.Errorf("abc != px") - } - - hz := proof.Utils.PF.Mul(hx, zx) - if !r1csqap.BigArraysEqual(abc, hz) { - return fmt.Errorf("abc != hz") - } - // assert.Equal(t, abc, hz) - - div, rem := proof.Utils.PF.Div(px, zx) - if !r1csqap.BigArraysEqual(hx, div) { - return fmt.Errorf("hx != div") - } - // assert.Equal(t, hx, div) - // assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) - for _, r := range rem { - if !bytes.Equal(r.Bytes(), big.NewInt(int64(0)).Bytes()) { - return fmt.Errorf("error:error: px/zx rem not equal to zeros") - } - } + cir.GenerateR1CS() // save circuit return saveToFile(compiledFileName, cir) diff --git a/cmd/go-snark/generate.go b/cmd/go-snark/generate.go index 2d92854..3f9b75a 100644 --- a/cmd/go-snark/generate.go +++ b/cmd/go-snark/generate.go @@ -1,8 +1,6 @@ package main import ( - "log" - "github.com/arnaucube/go-snark/circuit" "github.com/arnaucube/go-snark/proof" "github.com/urfave/cli" @@ -10,11 +8,10 @@ import ( func generate(context *cli.Context) error { // load circuit - var cir circuit.Circuit - if err := loadFromFile(compiledFileName, &cir); err != nil { + cir := &circuit.Circuit{} + if err := loadFromFile(compiledFileName, cir); err != nil { return err } - log.Printf("circuit: %v\n", cir) // load inputs var inputs circuit.Inputs @@ -30,7 +27,6 @@ func generate(context *cli.Context) error { if err != nil { return err } - log.Printf("w: %v\n", w) // load setup setup, err := newSetup() @@ -40,23 +36,20 @@ func generate(context *cli.Context) error { if err := loadFromFile(setupFileName, setup); err != nil { return err } - log.Printf("setup: %v\n", setup) // R1CS to QAP - alphas, betas, gammas, _ := proof.Utils.PF.R1CSToQAP( + alphas, betas, gammas, _ := proof.R1CSToQAP( cir.R1CS.A, cir.R1CS.B, cir.R1CS.C) + _, _, _, px := proof.Utils.PF.CombinePolynomials(w, alphas, betas, gammas) - hx := proof.Utils.PF.DivisorPolynomial(px, setup.Z()) - log.Printf("hx: %v\n", hx) // generate proof proof, err := setup.Generate(cir, w, px) if err != nil { return err } - log.Printf("proof: %v\n", proof) // save proof return saveToFile(proofFileName, proof) diff --git a/cmd/go-snark/main.go b/cmd/go-snark/main.go index 9a79018..967ac80 100644 --- a/cmd/go-snark/main.go +++ b/cmd/go-snark/main.go @@ -31,6 +31,12 @@ var commands = []cli.Command{ Usage: "compile a circuit", Action: compile, }, + { + Name: "test", + Aliases: []string{}, + Usage: "test a circuit", + Action: test, + }, { Name: "setup", Aliases: []string{}, diff --git a/cmd/go-snark/setup.go b/cmd/go-snark/setup.go index 1302106..24d9c52 100644 --- a/cmd/go-snark/setup.go +++ b/cmd/go-snark/setup.go @@ -1,8 +1,6 @@ package main import ( - "log" - "github.com/arnaucube/go-snark/circuit" "github.com/arnaucube/go-snark/proof" "github.com/urfave/cli" @@ -10,11 +8,10 @@ import ( func setup(context *cli.Context) error { // load circuit - var cir circuit.Circuit - if err := loadFromFile(compiledFileName, &cir); err != nil { + cir := &circuit.Circuit{} + if err := loadFromFile(compiledFileName, cir); err != nil { return err } - log.Printf("circuit: %v\n", cir) // load inputs var inputs circuit.Inputs @@ -25,15 +22,8 @@ func setup(context *cli.Context) error { return err } - // calculate witness - w, err := cir.CalculateWitness(inputs.Private, inputs.Public) - if err != nil { - return err - } - log.Printf("w: %v\n", w) - // R1CS to QAP - alphas, betas, gammas, _ := proof.Utils.PF.R1CSToQAP( + alphas, betas, gammas, _ := proof.R1CSToQAP( cir.R1CS.A, cir.R1CS.B, cir.R1CS.C) @@ -43,10 +33,9 @@ func setup(context *cli.Context) error { if err != nil { return err } - if err := setup.Init(len(w), cir, alphas, betas, gammas); err != nil { + if err := setup.Init(cir, alphas, betas, gammas); err != nil { return err } - log.Printf("setup: %v\n", setup) // save setup return saveToFile(setupFileName, setup) diff --git a/cmd/go-snark/test.go b/cmd/go-snark/test.go new file mode 100644 index 0000000..dfdfd94 --- /dev/null +++ b/cmd/go-snark/test.go @@ -0,0 +1,77 @@ +package main + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/urfave/cli" + + "github.com/arnaucube/go-snark/circuit" + "github.com/arnaucube/go-snark/fields" + "github.com/arnaucube/go-snark/proof" +) + +func test(context *cli.Context) error { + // load circuit + cir := &circuit.Circuit{} + if err := loadFromFile(compiledFileName, cir); err != nil { + return err + } + + // load inputs + var inputs circuit.Inputs + if err := loadFromFile(privateFileName, &inputs.Private); err != nil { + return err + } + if err := loadFromFile(publicFileName, &inputs.Public); err != nil { + return err + } + + // calculate witness + w, err := cir.CalculateWitness(inputs.Private, inputs.Public) + if err != nil { + return err + } + + // R1CS to QAP + alphas, betas, gammas, zx := proof.R1CSToQAP( + cir.R1CS.A, + cir.R1CS.B, + cir.R1CS.C, + ) + + // px == ax * bx - cx + ax, bx, cx, px := proof.Utils.PF.CombinePolynomials(w, alphas, betas, gammas) + + // hx == px / zx + hx := proof.Utils.PF.DivisorPolynomial(px, zx) + if !fields.BigArraysEqual(px, proof.Utils.PF.Mul(hx, zx)) { + return fmt.Errorf("px != hx * zx") + } + + // ax * bx - cx == px + abc := proof.Utils.PF.Sub(proof.Utils.PF.Mul(ax, bx), cx) + if !fields.BigArraysEqual(abc, px) { + return fmt.Errorf("ax * bx - cx != px") + } + + // hx * zx == ax * bx - cx + hz := proof.Utils.PF.Mul(hx, zx) + if !fields.BigArraysEqual(hz, abc) { + return fmt.Errorf("hx * zx != ax * bx - cx") + } + + // dx == px / zx + rx + dx, rx := proof.Utils.PF.Div(px, zx) + if !fields.BigArraysEqual(dx, hx) { + return fmt.Errorf("dx != hx") + } + for _, r := range rx { + if !bytes.Equal(r.Bytes(), big.NewInt(int64(0)).Bytes()) { + return fmt.Errorf("rx != 0") + } + } + + return nil +} diff --git a/cmd/go-snark/verify.go b/cmd/go-snark/verify.go index d93d708..67f8dbf 100644 --- a/cmd/go-snark/verify.go +++ b/cmd/go-snark/verify.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "log" "github.com/arnaucube/go-snark/circuit" "github.com/urfave/cli" @@ -10,11 +9,10 @@ import ( func verify(context *cli.Context) error { // load circuit - var cir circuit.Circuit - if err := loadFromFile(compiledFileName, &cir); err != nil { + cir := &circuit.Circuit{} + if err := loadFromFile(compiledFileName, cir); err != nil { return err } - log.Printf("circuit: %v\n", cir) // load inputs var inputs circuit.Inputs @@ -30,7 +28,6 @@ func verify(context *cli.Context) error { if err := loadFromFile(setupFileName, setup); err != nil { return err } - log.Printf("setup: %v\n", setup) // load proof proof, err := newProof() @@ -42,9 +39,14 @@ func verify(context *cli.Context) error { } // verify proof - if ok := setup.Verify(cir, proof, inputs.Public, true); !ok { - return fmt.Errorf("verif KO") + ok, err := setup.Verify(proof, inputs.Public) + if err != nil { + return err + } + if ok { + fmt.Println("OK") + } else { + fmt.Println("KO") } - log.Printf("verif OK\n") return nil } diff --git a/r1csqap/r1csqap.go b/fields/pf.go similarity index 65% rename from r1csqap/r1csqap.go rename to fields/pf.go index 72803a4..5aeddcc 100644 --- a/r1csqap/r1csqap.go +++ b/fields/pf.go @@ -1,10 +1,8 @@ -package r1csqap +package fields import ( "bytes" "math/big" - - "github.com/arnaucube/go-snark/fields" ) // Transpose transposes the *big.Int matrix @@ -43,20 +41,20 @@ func BigArraysEqual(a, b []*big.Int) bool { return true } -// PolynomialField is the Polynomial over a Finite Field where the polynomial operations are performed -type PolynomialField struct { - F fields.Fq +// PF is the Polynomial over a Finite Field where the polynomial operations are performed +type PF struct { + F Fq } -// NewPolynomialField creates a new PolynomialField with the given FiniteField -func NewPolynomialField(f fields.Fq) PolynomialField { - return PolynomialField{ +// NewPF creates a new PF with the given FiniteField +func NewPF(f Fq) PF { + return PF{ f, } } // Mul multiplies two polinomials over the Finite Field -func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int { +func (pf PF) Mul(a, b []*big.Int) []*big.Int { r := ArrayOfBigZeros(len(a) + len(b) - 1) for i := 0; i < len(a); i++ { for j := 0; j < len(b); j++ { @@ -69,7 +67,7 @@ func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int { } // Div divides two polinomials over the Finite Field, returning the result and the remainder -func (pf PolynomialField) Div(a, b []*big.Int) ([]*big.Int, []*big.Int) { +func (pf PF) Div(a, b []*big.Int) ([]*big.Int, []*big.Int) { // https://en.wikipedia.org/wiki/Division_algorithm r := ArrayOfBigZeros(len(a) - len(b) + 1) rem := a @@ -93,7 +91,7 @@ func max(a, b int) int { } // Add adds two polinomials over the Finite Field -func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int { +func (pf PF) Add(a, b []*big.Int) []*big.Int { r := ArrayOfBigZeros(max(len(a), len(b))) for i := 0; i < len(a); i++ { r[i] = pf.F.Add(r[i], a[i]) @@ -105,7 +103,7 @@ func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int { } // Sub subtracts two polinomials over the Finite Field -func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int { +func (pf PF) Sub(a, b []*big.Int) []*big.Int { r := ArrayOfBigZeros(max(len(a), len(b))) for i := 0; i < len(a); i++ { r[i] = pf.F.Add(r[i], a[i]) @@ -117,7 +115,7 @@ func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int { } // Eval evaluates the polinomial over the Finite Field at the given value x -func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int { +func (pf PF) Eval(v []*big.Int, x *big.Int) *big.Int { r := big.NewInt(int64(0)) for i := 0; i < len(v); i++ { xi := pf.F.Exp(x, big.NewInt(int64(i))) @@ -128,7 +126,7 @@ func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int { } // NewPolZeroAt generates a new polynomial that has value zero at the given value -func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int { +func (pf PF) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int { fac := 1 for i := 1; i < totalPoints+1; i++ { if i != pointPos { @@ -149,7 +147,7 @@ func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.In } // LagrangeInterpolation performs the Lagrange Interpolation / Lagrange Polynomials operation -func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int { +func (pf PF) LagrangeInterpolation(v []*big.Int) []*big.Int { // https://en.wikipedia.org/wiki/Lagrange_polynomial var r []*big.Int for i := 0; i < len(v); i++ { @@ -159,38 +157,8 @@ func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int { return r } -// R1CSToQAP converts the R1CS values to the QAP values -func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) { - aT := Transpose(a) - bT := Transpose(b) - cT := Transpose(c) - var alphas [][]*big.Int - for i := 0; i < len(aT); i++ { - alphas = append(alphas, pf.LagrangeInterpolation(aT[i])) - } - var betas [][]*big.Int - for i := 0; i < len(bT); i++ { - betas = append(betas, pf.LagrangeInterpolation(bT[i])) - } - var gammas [][]*big.Int - for i := 0; i < len(cT); i++ { - gammas = append(gammas, pf.LagrangeInterpolation(cT[i])) - } - z := []*big.Int{big.NewInt(int64(1))} - 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 -} - // 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) { +func (pf PF) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) { var ax []*big.Int for i := 0; i < len(r); i++ { m := pf.Mul([]*big.Int{r[i]}, ap[i]) @@ -212,7 +180,7 @@ func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.I } // DivisorPolynomial returns the divisor polynomial given two polynomials -func (pf PolynomialField) DivisorPolynomial(px, z []*big.Int) []*big.Int { +func (pf PF) DivisorPolynomial(px, z []*big.Int) []*big.Int { quo, _ := pf.Div(px, z) return quo } diff --git a/r1csqap/r1csqap_test.go b/fields/pf_test.go similarity index 60% rename from r1csqap/r1csqap_test.go rename to fields/pf_test.go index 54dba62..44b5fdc 100644 --- a/r1csqap/r1csqap_test.go +++ b/fields/pf_test.go @@ -1,11 +1,10 @@ -package r1csqap +package fields import ( "bytes" "math/big" "testing" - "github.com/arnaucube/go-snark/fields" "github.com/stretchr/testify/assert" ) @@ -50,10 +49,10 @@ func TestPol(t *testing.T) { // new Finite Field r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) assert.True(nil, ok) - f := fields.NewFq(r) + f := NewFq(r) // new Polynomial Field - pf := NewPolynomialField(f) + pf := NewPF(f) // polynomial multiplication o := pf.Mul(a, b) @@ -98,9 +97,9 @@ func TestLagrangeInterpolation(t *testing.T) { // new Finite Field r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) assert.True(nil, ok) - f := fields.NewFq(r) + f := NewFq(r) // new Polynomial Field - pf := NewPolynomialField(f) + pf := NewPF(f) b0 := big.NewInt(int64(0)) b5 := big.NewInt(int64(5)) @@ -112,65 +111,3 @@ func TestLagrangeInterpolation(t *testing.T) { assert.Equal(t, aux, int64(0)) } - -func TestR1CSToQAP(t *testing.T) { - // new Finite Field - r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) - assert.True(nil, ok) - f := fields.NewFq(r) - // new Polynomial Field - 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.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) - - hx := pf.DivisorPolynomial(px, zx) - // fmt.Println(hx) - - // hx==px/zx so px==hx*zx - assert.Equal(t, px, pf.Mul(hx, zx)) - - // 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) - -} diff --git a/install b/install new file mode 100755 index 0000000..712070c --- /dev/null +++ b/install @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +go fmt ./... \ + && golint ./... \ + && go test ./... \ + && go install ./cmd/go-snark diff --git a/proof/groth16.go b/proof/groth16.go index b13a9b2..0f21583 100644 --- a/proof/groth16.go +++ b/proof/groth16.go @@ -9,7 +9,7 @@ import ( "github.com/arnaucube/go-snark/circuit" ) -// Groth16Setup is the data structure holding the Trusted Groth16Setup data. +// Groth16Setup is Groth16 system setup structure type Groth16Setup struct { Toxic struct { T *big.Int // trusted setup secret @@ -17,7 +17,7 @@ type Groth16Setup struct { Kbeta *big.Int Kgamma *big.Int Kdelta *big.Int - } + } `json:"-"` // public Pk struct { // Proving Key @@ -51,7 +51,7 @@ type Groth16Setup struct { } } -// Groth16Proof contains the parameters to proof the zkSNARK +// Groth16Proof is Groth16 proof structure type Groth16Proof struct { PiA [3]*big.Int PiB [3][2]*big.Int @@ -63,11 +63,10 @@ func (setup *Groth16Setup) Z() []*big.Int { return setup.Pk.Z } -// Init generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed -func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alphas, betas, gammas [][]*big.Int) error { +// Init setups the trusted setup from a compiled circuit +func (setup *Groth16Setup) Init(cir *circuit.Circuit, alphas, betas, gammas [][]*big.Int) error { var err error - // generate random t value setup.Toxic.T, err = Utils.FqR.Rand() if err != nil { return err @@ -90,7 +89,6 @@ func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alph return err } - // z pol zpol := []*big.Int{big.NewInt(int64(1))} for i := 1; i < len(alphas)-1; i++ { zpol = Utils.PF.Mul( @@ -131,7 +129,7 @@ func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alph setup.Vk.G2.Gamma = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kgamma) setup.Vk.G2.Delta = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kdelta) - for i := 0; i < len(circuit.Signals); i++ { + for i := 0; i < len(cir.Signals); i++ { // Pk.G1.At: {a(τ)} from 0 to m at := Utils.PF.Eval(alphas[i], setup.Toxic.T) a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, at) @@ -147,10 +145,10 @@ func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alph } zero3 := [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} - for i := 0; i < circuit.NPublic+1; i++ { + for i := 0; i < cir.NPublic+1; i++ { setup.Pk.BACDelta = append(setup.Pk.BACDelta, zero3) } - for i := circuit.NPublic + 1; i < circuit.NVars; i++ { + for i := cir.NPublic + 1; i < cir.NVars; i++ { // TODO calculate all at, bt, ct outside, to avoid repeating calculations at := Utils.PF.Eval(alphas[i], setup.Toxic.T) bt := Utils.PF.Eval(betas[i], setup.Toxic.T) @@ -171,7 +169,7 @@ func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alph setup.Pk.BACDelta = append(setup.Pk.BACDelta, g1c) } - for i := 0; i <= circuit.NPublic; i++ { + for i := 0; i <= cir.NPublic; i++ { at := Utils.PF.Eval(alphas[i], setup.Toxic.T) bt := Utils.PF.Eval(betas[i], setup.Toxic.T) ct := Utils.PF.Eval(gammas[i], setup.Toxic.T) @@ -193,8 +191,8 @@ func (setup *Groth16Setup) Init(witnessLength int, circuit circuit.Circuit, alph return nil } -// Generate generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness -func (setup Groth16Setup) Generate(circuit circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) { +// Generate generates Pinocchio proof +func (setup Groth16Setup) Generate(cir *circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) { proof := &Groth16Proof{} proof.PiA = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} proof.PiB = Utils.Bn.Fq6.Zero() @@ -212,12 +210,12 @@ func (setup Groth16Setup) Generate(circuit circuit.Circuit, w []*big.Int, px []* // piBG1 will hold all the same than proof.PiB but in G1 curve piBG1 := [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} - for i := 0; i < circuit.NVars; i++ { + for i := 0; i < cir.NVars; i++ { proof.PiA = Utils.Bn.G1.Add(proof.PiA, Utils.Bn.G1.MulScalar(setup.Pk.G1.At[i], w[i])) piBG1 = Utils.Bn.G1.Add(piBG1, Utils.Bn.G1.MulScalar(setup.Pk.G1.BACGamma[i], w[i])) proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(setup.Pk.G2.BACGamma[i], w[i])) } - for i := circuit.NPublic + 1; i < circuit.NVars; i++ { + for i := cir.NPublic + 1; i < cir.NVars; i++ { proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(setup.Pk.BACDelta[i], w[i])) } @@ -250,10 +248,10 @@ func (setup Groth16Setup) Generate(circuit circuit.Circuit, w []*big.Int, px []* } // Verify verifies over the BN128 the Pairings of the Proof -func (setup Groth16Setup) Verify(circuit circuit.Circuit, proof Proof, publicSignals []*big.Int, debug bool) bool { +func (setup Groth16Setup) Verify(proof Proof, publicSignals []*big.Int) (bool, error) { pproof, ok := proof.(*Groth16Proof) if !ok { - panic("bad proof") + return false, fmt.Errorf("bad proof type") } icPubl := setup.Vk.IC[0] @@ -267,15 +265,11 @@ func (setup Groth16Setup) Verify(circuit circuit.Circuit, proof Proof, publicSig Utils.Bn.Pairing(setup.Vk.G1.Alpha, setup.Vk.G2.Beta), Utils.Bn.Fq12.Mul( Utils.Bn.Pairing(icPubl, setup.Vk.G2.Gamma), - Utils.Bn.Pairing(pproof.PiC, setup.Vk.G2.Delta)))) { - if debug { - fmt.Println("❌ groth16 verification not passed") - } - return false - } - if debug { - fmt.Println("✓ groth16 verification passed") + Utils.Bn.Pairing(pproof.PiC, setup.Vk.G2.Delta), + ), + )) { + return false, nil } - return true + return true, nil } diff --git a/proof/groth16_test.go b/proof/groth16_test.go index b72af0b..ff08a5c 100644 --- a/proof/groth16_test.go +++ b/proof/groth16_test.go @@ -2,21 +2,17 @@ package proof import ( "bytes" - "fmt" "math/big" "strings" "testing" - "time" - "github.com/arnaucube/go-snark/circuit" - "github.com/arnaucube/go-snark/r1csqap" "github.com/stretchr/testify/assert" + + "github.com/arnaucube/go-snark/circuit" + "github.com/arnaucube/go-snark/fields" ) func TestGroth16MinimalFlow(t *testing.T) { - fmt.Println("testing Groth16 minimal flow") - // circuit function - // y = x^3 + x + 5 code := ` func main(private s0, public s1): s2 = s0 * s0 @@ -26,11 +22,9 @@ func TestGroth16MinimalFlow(t *testing.T) { equals(s1, s5) out = 1 * 1 ` - fmt.Print("\ncode of the circuit:") - // parse the code parser := circuit.NewParser(strings.NewReader(code)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) b3 := big.NewInt(int64(3)) @@ -38,22 +32,18 @@ func TestGroth16MinimalFlow(t *testing.T) { b35 := big.NewInt(int64(35)) publicSignals := []*big.Int{b35} - // wittness - w, err := circuit.CalculateWitness(privateInputs, publicSignals) + w, err := cir.CalculateWitness(privateInputs, publicSignals) assert.Nil(t, err) - // code to R1CS - fmt.Println("\ngenerating R1CS from code") - a, b, c := circuit.GenerateR1CS() - fmt.Println("\nR1CS:") - fmt.Println("a:", a) - fmt.Println("b:", b) - fmt.Println("c:", c) - - // R1CS to QAP - // TODO zxQAP is not used and is an old impl, TODO remove - alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c) - fmt.Println("qap") + cir.GenerateR1CS() + + // TODO zxQAP is not used and is an old impl + // TODO remove + alphas, betas, gammas, _ := R1CSToQAP( + cir.R1CS.A, + cir.R1CS.B, + cir.R1CS.C, + ) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) @@ -65,20 +55,14 @@ func TestGroth16MinimalFlow(t *testing.T) { assert.Equal(t, 7, len(cx)) assert.Equal(t, 13, len(px)) - // --- - // from here is the GROTH16 - // --- - // calculate trusted setup - fmt.Println("groth") setup := &Groth16Setup{} - err = setup.Init(len(w), *circuit, alphas, betas, gammas) + err = setup.Init(cir, alphas, betas, gammas) assert.Nil(t, err) - fmt.Println("\nt:", setup.Toxic.T) hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) div, rem := Utils.PF.Div(px, setup.Pk.Z) assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(6)) // hx==px/zx so px==hx*zx assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z)) @@ -86,23 +70,22 @@ func TestGroth16MinimalFlow(t *testing.T) { // check length of polynomials H(x) and Z(x) assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1) - proof, err := setup.Generate(*circuit, w, px) + proof, err := setup.Generate(cir, w, px) assert.Nil(t, err) - // fmt.Println("\n proofs:") - // fmt.Println(proof) - - // fmt.Println("public signals:", proof.PublicSignals) - fmt.Println("\nsignals:", circuit.Signals) - fmt.Println("witness:", w) b35Verif := big.NewInt(int64(35)) publicSignalsVerif := []*big.Int{b35Verif} - before := time.Now() - assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true)) - fmt.Println("verify proof time elapsed:", time.Since(before)) + { + r, err := setup.Verify(proof, publicSignalsVerif) + assert.Nil(t, err) + assert.True(t, r) + } - // check that with another public input the verification returns false bOtherWrongPublic := big.NewInt(int64(34)) wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} - assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false)) + { + r, err := setup.Verify(proof, wrongPublicSignalsVerif) + assert.Nil(t, err) + assert.False(t, r) + } } diff --git a/proof/pinocchio.go b/proof/pinocchio.go index 653b2db..75d9943 100644 --- a/proof/pinocchio.go +++ b/proof/pinocchio.go @@ -9,8 +9,7 @@ import ( "github.com/arnaucube/go-snark/circuit" ) -// PinocchioSetup is the data structure holding the Trusted Setup data. -// The Setup.Toxic sub struct must be destroyed after the Init function is completed +// PinocchioSetup is Pinocchio system setup structure type PinocchioSetup struct { Toxic struct { T *big.Int // trusted setup secret @@ -49,7 +48,7 @@ type PinocchioSetup struct { } } -// PinocchioProof contains the parameters to proof the zkSNARK +// PinocchioProof is Pinocchio proof structure type PinocchioProof struct { PiA [3]*big.Int PiAp [3]*big.Int @@ -59,7 +58,6 @@ type PinocchioProof struct { PiCp [3]*big.Int PiH [3]*big.Int PiKp [3]*big.Int - // PublicSignals []*big.Int } // Z is ... @@ -67,28 +65,15 @@ func (setup *PinocchioSetup) Z() []*big.Int { return setup.Pk.Z } -// Init generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed -func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, alphas, betas, gammas [][]*big.Int) error { +// Init setups the trusted setup from a compiled circuit +func (setup *PinocchioSetup) Init(cir *circuit.Circuit, alphas, betas, gammas [][]*big.Int) error { var err error - // input soundness - // 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.FqR.Zero().Bytes()) { - // alphas[i][j] = Utils.FqR.One() - // } - // } - // } - // } - - // generate random t value setup.Toxic.T, err = Utils.FqR.Rand() if err != nil { return err } - // k for calculating pi' and Vk setup.Toxic.Ka, err = Utils.FqR.Rand() if err != nil { return err @@ -102,7 +87,6 @@ func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, al return err } - // generate Kβ (Kbeta) and Kγ (Kgamma) setup.Toxic.Kbeta, err = Utils.FqR.Rand() if err != nil { return err @@ -111,8 +95,8 @@ func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, al if err != nil { return err } + kbg := Utils.FqR.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma) - // generate ρ (Rho): ρA, ρB, ρC setup.Toxic.RhoA, err = Utils.FqR.Rand() if err != nil { return err @@ -123,52 +107,30 @@ func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, al } setup.Toxic.RhoC = Utils.FqR.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB) - // 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) - // gt1 = append(gt1, tEncr1) - // tEncr2 := Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, tPow) - // gt2 = append(gt2, tEncr2) - // } - // gt1: g1, g1*t, g1*t^2, g1*t^3, ... - // gt2: g2, g2*t, g2*t^2, ... - 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) setup.Vk.Vkc = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kc) - /* - Verification keys: - - Vk_betagamma1: setup.G1Kbg = g1 * Kbeta*Kgamma - - Vk_betagamma2: setup.G2Kbg = g2 * Kbeta*Kgamma - - Vk_gamma: setup.G2Kg = g2 * Kgamma - */ - kbg := Utils.FqR.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma) setup.Vk.G1Kbg = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, kbg) 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 < len(circuit.Signals); i++ { + for i := 0; i < len(cir.Signals); i++ { at := Utils.PF.Eval(alphas[i], setup.Toxic.T) - // 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 { + if i <= cir.NPublic { setup.Vk.IC = append(setup.Vk.IC, a) } bt := Utils.PF.Eval(betas[i], setup.Toxic.T) - // 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.FqR.Mul(setup.Toxic.RhoC, ct) c := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoCct) setup.Pk.C = append(setup.Pk.C, c) @@ -184,36 +146,31 @@ func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, al setup.Pk.Ap = append(setup.Pk.Ap, Utils.Bn.G1.MulScalar(a, setup.Toxic.Ka)) setup.Pk.Bp = append(setup.Pk.Bp, Utils.Bn.G1.MulScalar(bg1, setup.Toxic.Kb)) setup.Pk.Cp = append(setup.Pk.Cp, Utils.Bn.G1.MulScalar(c, setup.Toxic.Kc)) + kk := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, kt) setup.Pk.Kp = append(setup.Pk.Kp, Utils.Bn.G1.MulScalar(kk, setup.Toxic.Kbeta)) } - // z pol zpol := []*big.Int{big.NewInt(int64(1))} - // for i := 0; i < len(circuit.Constraints); i++ { for i := 1; i < len(alphas)-1; i++ { zpol = Utils.PF.Mul( zpol, []*big.Int{ - Utils.FqR.Neg( // neg over R - big.NewInt(int64(i))), + Utils.FqR.Neg(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) 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 var gt1 [][3]*big.Int - gt1 = append(gt1, Utils.Bn.G1.G) // the first is t**0 * G1 = 1 * G1 = G1 + gt1 = append(gt1, Utils.Bn.G1.G) 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) + for i := 1; i < len(zpol); i++ { gt1 = append(gt1, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tEncr)) - // tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T) tEncr = Utils.FqR.Mul(tEncr, setup.Toxic.T) } setup.G1T = gt1 @@ -221,8 +178,8 @@ func (setup *PinocchioSetup) Init(witnessLength int, circuit circuit.Circuit, al return nil } -// Generate generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness -func (setup *PinocchioSetup) Generate(circuit circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) { +// Generate generates Pinocchio proof +func (setup *PinocchioSetup) Generate(cir *circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) { proof := &PinocchioProof{} 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()} @@ -233,12 +190,12 @@ func (setup *PinocchioSetup) Generate(circuit circuit.Circuit, w []*big.Int, px proof.PiH = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} proof.PiKp = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()} - for i := circuit.NPublic + 1; i < circuit.NVars; i++ { + for i := cir.NPublic + 1; i < cir.NVars; i++ { proof.PiA = Utils.Bn.G1.Add(proof.PiA, Utils.Bn.G1.MulScalar(setup.Pk.A[i], w[i])) proof.PiAp = Utils.Bn.G1.Add(proof.PiAp, Utils.Bn.G1.MulScalar(setup.Pk.Ap[i], w[i])) } - for i := 0; i < circuit.NVars; i++ { + for i := 0; i < cir.NVars; i++ { proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(setup.Pk.B[i], w[i])) proof.PiBp = Utils.Bn.G1.Add(proof.PiBp, Utils.Bn.G1.MulScalar(setup.Pk.Bp[i], w[i])) @@ -248,10 +205,7 @@ func (setup *PinocchioSetup) Generate(circuit circuit.Circuit, w []*big.Int, px proof.PiKp = Utils.Bn.G1.Add(proof.PiKp, Utils.Bn.G1.MulScalar(setup.Pk.Kp[i], w[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]) + hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) for i := 0; i < len(hx); i++ { proof.PiH = Utils.Bn.G1.Add(proof.PiH, Utils.Bn.G1.MulScalar(setup.G1T[i], hx[i])) } @@ -260,52 +214,32 @@ func (setup *PinocchioSetup) Generate(circuit circuit.Circuit, w []*big.Int, px } // Verify verifies over the BN128 the Pairings of the Proof -func (setup *PinocchioSetup) Verify(circuit circuit.Circuit, proof Proof, publicSignals []*big.Int, debug bool) bool { - // e(piA, Va) == e(piA', g2) - +func (setup *PinocchioSetup) Verify(proof Proof, publicSignals []*big.Int) (bool, error) { pproof, ok := proof.(*PinocchioProof) if !ok { - panic("bad type") + return false, fmt.Errorf("bad proof type") } pairingPiaVa := Utils.Bn.Pairing(pproof.PiA, setup.Vk.Vka) pairingPiapG2 := Utils.Bn.Pairing(pproof.PiAp, Utils.Bn.G2.G) if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) { - if debug { - fmt.Println("❌ e(piA, Va) == e(piA', g2), valid knowledge commitment for A") - } - return false - } - if debug { - fmt.Println("✓ e(piA, Va) == e(piA', g2), valid knowledge commitment for A") + return false, nil } // e(Vb, piB) == e(piB', g2) pairingVbPib := Utils.Bn.Pairing(setup.Vk.Vkb, pproof.PiB) pairingPibpG2 := Utils.Bn.Pairing(pproof.PiBp, Utils.Bn.G2.G) if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { - if debug { - fmt.Println("❌ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B") - } - return false - } - if debug { - fmt.Println("✓ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B") + return false, nil } // e(piC, Vc) == e(piC', g2) pairingPicVc := Utils.Bn.Pairing(pproof.PiC, setup.Vk.Vkc) pairingPicpG2 := Utils.Bn.Pairing(pproof.PiCp, Utils.Bn.G2.G) if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) { - if debug { - fmt.Println("❌ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C") - } - return false - } - if debug { - fmt.Println("✓ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C") + return false, nil } - // Vkx, to then calculate Vkx+piA + // Vkx+piA vkxpia := setup.Vk.IC[0] for i := 0; i < len(publicSignals); i++ { vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i+1], publicSignals[i])) @@ -313,33 +247,22 @@ func (setup *PinocchioSetup) Verify(circuit circuit.Circuit, proof Proof, public // e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2) if !Utils.Bn.Fq12.Equal( - Utils.Bn.Pairing(Utils.Bn.G1.Add(vkxpia, pproof.PiA), pproof.PiB), // TODO Add(vkxpia, proof.PiA) can go outside in order to save computation, as is reused later + Utils.Bn.Pairing(Utils.Bn.G1.Add(vkxpia, pproof.PiA), pproof.PiB), Utils.Bn.Fq12.Mul( Utils.Bn.Pairing(pproof.PiH, setup.Vk.Vkz), Utils.Bn.Pairing(pproof.PiC, Utils.Bn.G2.G))) { - if debug { - fmt.Println("❌ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked") - } - return false - } - if debug { - fmt.Println("✓ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked") + return false, nil } - // e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) - // == e(piK, g2Kgamma) + // e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma) piapic := Utils.Bn.G1.Add(Utils.Bn.G1.Add(vkxpia, pproof.PiA), pproof.PiC) pairingPiACG2Kbg := Utils.Bn.Pairing(piapic, setup.Vk.G2Kbg) pairingG1KbgPiB := Utils.Bn.Pairing(setup.Vk.G1Kbg, pproof.PiB) pairingL := Utils.Bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB) pairingR := Utils.Bn.Pairing(pproof.PiKp, setup.Vk.G2Kg) if !Utils.Bn.Fq12.Equal(pairingL, pairingR) { - fmt.Println("❌ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") - return false - } - if debug { - fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") + return false, nil } - return true + return true, nil } diff --git a/proof/pinocchio_test.go b/proof/pinocchio_test.go index 37f7baa..b1daade 100644 --- a/proof/pinocchio_test.go +++ b/proof/pinocchio_test.go @@ -2,23 +2,17 @@ package proof import ( "bytes" - "fmt" "math/big" "strings" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/arnaucube/go-snark/circuit" - "github.com/arnaucube/go-snark/r1csqap" + "github.com/arnaucube/go-snark/fields" ) func TestZkFromFlatCircuitCode(t *testing.T) { - // compile circuit and get the R1CS - - // circuit function - // y = x^3 + x + 5 code := ` func exp3(private a): b = a * a @@ -35,48 +29,26 @@ func TestZkFromFlatCircuitCode(t *testing.T) { equals(s1, s5) out = 1 * 1 ` - // the same code without the functions calling, all in one func - // code := ` - // func test(private s0, public s1): - // s2 = s0 * s0 - // s3 = s2 * s0 - // s4 = s3 + s0 - // s5 = s4 + 5 - // equals(s1, s5) - // out = 1 * 1 - // ` - fmt.Print("\ncode of the circuit:") - fmt.Println(code) - - // parse the code + parser := circuit.NewParser(strings.NewReader(code)) - circuit, err := parser.Parse() + cir, 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} b35 := big.NewInt(int64(35)) publicSignals := []*big.Int{b35} - // wittness - w, err := circuit.CalculateWitness(privateInputs, publicSignals) + w, err := cir.CalculateWitness(privateInputs, publicSignals) assert.Nil(t, err) - // code to R1CS - fmt.Println("\ngenerating R1CS from code") - a, b, c := circuit.GenerateR1CS() - fmt.Println("\nR1CS:") - fmt.Println("a:", a) - fmt.Println("b:", b) - fmt.Println("c:", c) + cir.GenerateR1CS() - // R1CS to QAP - // TODO zxQAP is not used and is an old impl, TODO remove - alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c) - fmt.Println("qap") + alphas, betas, gammas, zxQAP := R1CSToQAP( + cir.R1CS.A, + cir.R1CS.B, + cir.R1CS.C, + ) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) @@ -103,23 +75,23 @@ func TestZkFromFlatCircuitCode(t *testing.T) { div, rem := Utils.PF.Div(px, zxQAP) assert.Equal(t, hxQAP, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(6)) // calculate trusted setup setup := &PinocchioSetup{} - err = setup.Init(len(w), *circuit, alphas, betas, gammas) + err = setup.Init(cir, 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 + // 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) hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) assert.Equal(t, hx, hxQAP) - // assert.Equal(t, hxQAP, hx) div, rem = Utils.PF.Div(px, setup.Pk.Z) assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(6)) assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP)) // hx==px/zx so px==hx*zx @@ -129,25 +101,25 @@ func TestZkFromFlatCircuitCode(t *testing.T) { assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1) assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1) - proof, err := setup.Generate(*circuit, w, px) + proof, err := setup.Generate(cir, w, px) assert.Nil(t, err) - // fmt.Println("\n proofs:") - // fmt.Println(proof) - - // fmt.Println("public signals:", proof.PublicSignals) - fmt.Println("\nsignals:", circuit.Signals) - fmt.Println("witness:", w) b35Verif := big.NewInt(int64(35)) publicSignalsVerif := []*big.Int{b35Verif} - before := time.Now() - assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true)) - fmt.Println("verify proof time elapsed:", time.Since(before)) + { + r, err := setup.Verify(proof, publicSignalsVerif) + assert.Nil(t, err) + assert.True(t, r) + } // check that with another public input the verification returns false bOtherWrongPublic := big.NewInt(int64(34)) wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} - assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false)) + { + r, err := setup.Verify(proof, wrongPublicSignalsVerif) + assert.Nil(t, err) + assert.False(t, r) + } } func TestZkMultiplication(t *testing.T) { @@ -157,11 +129,9 @@ func TestZkMultiplication(t *testing.T) { equals(c, d) out = 1 * 1 ` - fmt.Println("code", code) - // parse the code parser := circuit.NewParser(strings.NewReader(code)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) b3 := big.NewInt(int64(3)) @@ -170,21 +140,19 @@ func TestZkMultiplication(t *testing.T) { b12 := big.NewInt(int64(12)) publicSignals := []*big.Int{b12} - // wittness - w, err := circuit.CalculateWitness(privateInputs, publicSignals) + w, err := cir.CalculateWitness(privateInputs, publicSignals) assert.Nil(t, err) - // code to R1CS - fmt.Println("\ngenerating R1CS from code") - a, b, c := circuit.GenerateR1CS() - fmt.Println("\nR1CS:") - fmt.Println("a:", a) - fmt.Println("b:", b) - fmt.Println("c:", c) + cir.GenerateR1CS() // R1CS to QAP - // TODO zxQAP is not used and is an old impl. TODO remove - alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c) + // TODO zxQAP is not used and is an old impl. + // TODO remove + alphas, betas, gammas, zxQAP := R1CSToQAP( + cir.R1CS.A, + cir.R1CS.B, + cir.R1CS.C, + ) assert.Equal(t, 6, len(alphas)) assert.Equal(t, 6, len(betas)) assert.Equal(t, 6, len(betas)) @@ -211,15 +179,15 @@ func TestZkMultiplication(t *testing.T) { div, rem := Utils.PF.Div(px, zxQAP) assert.Equal(t, hxQAP, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(4)) - // calculate trusted setup setup := &PinocchioSetup{} - err = setup.Init(len(w), *circuit, alphas, betas, gammas) + err = setup.Init(cir, 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 + // 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) hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) @@ -228,7 +196,7 @@ func TestZkMultiplication(t *testing.T) { div, rem = Utils.PF.Div(px, setup.Pk.Z) assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(4)) assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP)) // hx==px/zx so px==hx*zx @@ -238,30 +206,28 @@ func TestZkMultiplication(t *testing.T) { assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1) assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1) - proof, err := setup.Generate(*circuit, w, px) + proof, err := setup.Generate(cir, w, px) assert.Nil(t, err) - // fmt.Println("\n proofs:") - // fmt.Println(proof) - - // fmt.Println("public signals:", proof.PublicSignals) - fmt.Println("\n", circuit.Signals) - fmt.Println("witness", w) b12Verif := big.NewInt(int64(12)) publicSignalsVerif := []*big.Int{b12Verif} - before := time.Now() - assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true)) - fmt.Println("verify proof time elapsed:", time.Since(before)) + { + r, err := setup.Verify(proof, publicSignalsVerif) + assert.Nil(t, err) + assert.True(t, r) + } // check that with another public input the verification returns false bOtherWrongPublic := big.NewInt(int64(11)) wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} - assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false)) + { + r, err := setup.Verify(proof, wrongPublicSignalsVerif) + assert.Nil(t, err) + assert.False(t, r) + } } func TestMinimalFlow(t *testing.T) { - // circuit function - // y = x^3 + x + 5 code := ` func main(private s0, public s1): s2 = s0 * s0 @@ -271,12 +237,9 @@ func TestMinimalFlow(t *testing.T) { equals(s1, s5) out = 1 * 1 ` - fmt.Print("\ncode of the circuit:") - fmt.Println(code) - // parse the code parser := circuit.NewParser(strings.NewReader(code)) - circuit, err := parser.Parse() + cir, err := parser.Parse() assert.Nil(t, err) b3 := big.NewInt(int64(3)) @@ -284,22 +247,18 @@ func TestMinimalFlow(t *testing.T) { b35 := big.NewInt(int64(35)) publicSignals := []*big.Int{b35} - // wittness - w, err := circuit.CalculateWitness(privateInputs, publicSignals) + w, err := cir.CalculateWitness(privateInputs, publicSignals) assert.Nil(t, err) - // code to R1CS - fmt.Println("\ngenerating R1CS from code") - a, b, c := circuit.GenerateR1CS() - fmt.Println("\nR1CS:") - fmt.Println("a:", a) - fmt.Println("b:", b) - fmt.Println("c:", c) + cir.GenerateR1CS() // R1CS to QAP // TODO zxQAP is not used and is an old impl, TODO remove - alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c) - fmt.Println("qap") + alphas, betas, gammas, _ := R1CSToQAP( + cir.R1CS.A, + cir.R1CS.B, + cir.R1CS.C, + ) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) assert.Equal(t, 8, len(alphas)) @@ -313,14 +272,13 @@ func TestMinimalFlow(t *testing.T) { // calculate trusted setup setup := &PinocchioSetup{} - err = setup.Init(len(w), *circuit, alphas, betas, gammas) + err = setup.Init(cir, alphas, betas, gammas) assert.Nil(t, err) - fmt.Println("\nt:", setup.Toxic.T) hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) div, rem := Utils.PF.Div(px, setup.Pk.Z) assert.Equal(t, hx, div) - assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6)) + assert.Equal(t, rem, fields.ArrayOfBigZeros(6)) // hx==px/zx so px==hx*zx assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z)) @@ -328,23 +286,23 @@ func TestMinimalFlow(t *testing.T) { // check length of polynomials H(x) and Z(x) assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1) - proof, err := setup.Generate(*circuit, w, px) + proof, err := setup.Generate(cir, w, px) assert.Nil(t, err) - // fmt.Println("\n proofs:") - // fmt.Println(proof) - - // fmt.Println("public signals:", proof.PublicSignals) - fmt.Println("\nsignals:", circuit.Signals) - fmt.Println("witness:", w) b35Verif := big.NewInt(int64(35)) publicSignalsVerif := []*big.Int{b35Verif} - before := time.Now() - assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true)) - fmt.Println("verify proof time elapsed:", time.Since(before)) + { + r, err := setup.Verify(proof, publicSignalsVerif) + assert.Nil(t, err) + assert.True(t, r) + } // check that with another public input the verification returns false bOtherWrongPublic := big.NewInt(int64(34)) wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} - assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false)) + { + r, err := setup.Verify(proof, wrongPublicSignalsVerif) + assert.Nil(t, err) + assert.False(t, r) + } } diff --git a/proof/proof.go b/proof/proof.go index baa824d..a2f69f7 100644 --- a/proof/proof.go +++ b/proof/proof.go @@ -6,42 +6,31 @@ import ( "github.com/arnaucube/go-snark/bn128" "github.com/arnaucube/go-snark/circuit" "github.com/arnaucube/go-snark/fields" - "github.com/arnaucube/go-snark/r1csqap" ) -type utils struct { +// Proof is ... +type Proof interface{} + +// Setup is ... +type Setup interface { + Z() []*big.Int + Init(cir *circuit.Circuit, alphas, betas, gammas [][]*big.Int) error + Generate(cir *circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) + Verify(p Proof, publicSignals []*big.Int) (bool, error) +} + +// Utils is ... +var Utils struct { Bn bn128.Bn128 FqR fields.Fq - PF r1csqap.PolynomialField + PF fields.PF } -// Utils is the data structure holding the BN128, FqR Finite Field over R, PolynomialField, that will be used inside the snarks operations -var Utils = prepareUtils() - -func prepareUtils() utils { - bn, err := bn128.NewBn128() - if err != nil { +func init() { + var err error + if Utils.Bn, err = bn128.NewBn128(); err != nil { panic(err) } - // new Finite Field - fqR := fields.NewFq(bn.R) - // new Polynomial Field - pf := r1csqap.NewPolynomialField(fqR) - - return utils{ - Bn: bn, - FqR: fqR, - PF: pf, - } -} - -// Proof is -type Proof interface{} - -// Setup is -type Setup interface { - Z() []*big.Int - Init(witnessLength int, circuit circuit.Circuit, alphas, betas, gammas [][]*big.Int) error - Generate(circuit circuit.Circuit, w []*big.Int, px []*big.Int) (Proof, error) - Verify(circuit circuit.Circuit, proof Proof, publicSignals []*big.Int, debug bool) bool + Utils.FqR = fields.NewFq(Utils.Bn.R) + Utils.PF = fields.NewPF(Utils.FqR) } diff --git a/proof/qap.go b/proof/qap.go new file mode 100644 index 0000000..12e2989 --- /dev/null +++ b/proof/qap.go @@ -0,0 +1,37 @@ +package proof + +import ( + "math/big" + + "github.com/arnaucube/go-snark/fields" +) + +// R1CSToQAP converts the R1CS values to the QAP values +func R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) { + aT := fields.Transpose(a) + bT := fields.Transpose(b) + cT := fields.Transpose(c) + var alphas [][]*big.Int + for i := 0; i < len(aT); i++ { + alphas = append(alphas, Utils.PF.LagrangeInterpolation(aT[i])) + } + var betas [][]*big.Int + for i := 0; i < len(bT); i++ { + betas = append(betas, Utils.PF.LagrangeInterpolation(bT[i])) + } + var gammas [][]*big.Int + for i := 0; i < len(cT); i++ { + gammas = append(gammas, Utils.PF.LagrangeInterpolation(cT[i])) + } + z := []*big.Int{big.NewInt(int64(1))} + for i := 1; i < len(alphas)-1; i++ { + z = Utils.PF.Mul( + z, + []*big.Int{ + Utils.PF.F.Neg( + big.NewInt(int64(i))), + big.NewInt(int64(1)), + }) + } + return alphas, betas, gammas, z +} diff --git a/proof/qap_test.go b/proof/qap_test.go new file mode 100644 index 0000000..7e99471 --- /dev/null +++ b/proof/qap_test.go @@ -0,0 +1,73 @@ +package proof + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/arnaucube/go-snark/fields" +) + +func TestR1CSToQAP(t *testing.T) { + // new Finite Field + r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) + assert.True(nil, ok) + f := fields.NewFq(r) + Utils.FqR = f + // new Polynomial Field + Utils.PF = fields.NewPF(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 := R1CSToQAP(a, b, c) + // 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 := Utils.PF.CombinePolynomials(w, alphas, betas, gammas) + // fmt.Println(ax) + // fmt.Println(bx) + // fmt.Println(cx) + // fmt.Println(px) + + hx := Utils.PF.DivisorPolynomial(px, zx) + // fmt.Println(hx) + + // hx==px/zx so px==hx*zx + assert.Equal(t, px, Utils.PF.Mul(hx, zx)) + + // 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) + +} diff --git a/r1csqap/README.md b/r1csqap/README.md deleted file mode 100644 index 21c6054..0000000 --- a/r1csqap/README.md +++ /dev/null @@ -1,54 +0,0 @@ -## 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) -```