Browse Source

move pf to fields and qap conversion to proof module

pull/10/head
Ali Kefia 4 years ago
parent
commit
54a265e73b
19 changed files with 452 additions and 646 deletions
  1. +5
    -5
      circuit/circuit.go
  2. +37
    -46
      circuit/circuit_test.go
  3. +4
    -70
      cmd/go-snark/compile.go
  4. +4
    -11
      cmd/go-snark/generate.go
  5. +6
    -0
      cmd/go-snark/main.go
  6. +4
    -15
      cmd/go-snark/setup.go
  7. +77
    -0
      cmd/go-snark/test.go
  8. +10
    -8
      cmd/go-snark/verify.go
  9. +16
    -48
      fields/pf.go
  10. +5
    -68
      fields/pf_test.go
  11. +6
    -0
      install
  12. +20
    -26
      proof/groth16.go
  13. +27
    -44
      proof/groth16_test.go
  14. +27
    -104
      proof/pinocchio.go
  15. +75
    -117
      proof/pinocchio_test.go
  16. +19
    -30
      proof/proof.go
  17. +37
    -0
      proof/qap.go
  18. +73
    -0
      proof/qap_test.go
  19. +0
    -54
      r1csqap/README.md

+ 5
- 5
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

+ 37
- 46
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)
}

+ 4
- 70
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)

+ 4
- 11
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)

+ 6
- 0
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{},

+ 4
- 15
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)

+ 77
- 0
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
}

+ 10
- 8
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
}

r1csqap/r1csqap.go → 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
}

r1csqap/r1csqap_test.go → 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)
}

+ 6
- 0
install

@ -0,0 +1,6 @@
#!/usr/bin/env bash
go fmt ./... \
&& golint ./... \
&& go test ./... \
&& go install ./cmd/go-snark

+ 20
- 26
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
}

+ 27
- 44
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)
}
}

+ 27
- 104
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
}

+ 75
- 117
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)
}
}

+ 19
- 30
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)
}

+ 37
- 0
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
}

+ 73
- 0
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)
}

+ 0
- 54
r1csqap/README.md

@ -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)
```

Loading…
Cancel
Save