Browse Source

refactoring:

- avoid code duplication on cmd
- interface for proof system
pull/10/head
Ali Kefia 4 years ago
parent
commit
1bf5a75f01
35 changed files with 596 additions and 1034 deletions
  1. +5
    -0
      bn128/bn128.go
  2. +14
    -0
      bn128/g1.go
  3. +12
    -0
      bn128/g2.go
  4. +0
    -0
      circuit/circuit-test-1.circuit
  5. +0
    -0
      circuit/circuit-test-2.circuit
  6. +3
    -3
      circuit/circuit.go
  7. +1
    -1
      circuit/circuit_test.go
  8. +5
    -1
      circuit/lexer.go
  9. +1
    -1
      circuit/parser.go
  10. +98
    -0
      cmd/go-snark/compile.go
  11. +63
    -0
      cmd/go-snark/generate.go
  12. +45
    -0
      cmd/go-snark/loadsave.go
  13. +64
    -467
      cmd/go-snark/main.go
  14. +53
    -0
      cmd/go-snark/setup.go
  15. +50
    -0
      cmd/go-snark/verify.go
  16. +7
    -0
      fields/fq.go
  17. +6
    -0
      fields/fq12.go
  18. +6
    -0
      fields/fq2.go
  19. +6
    -0
      fields/fq6.go
  20. +30
    -51
      proof/groth16.go
  21. +8
    -7
      proof/groth16_test.go
  22. +48
    -69
      proof/pinocchio.go
  23. +22
    -112
      proof/pinocchio_test.go
  24. +47
    -0
      proof/proof.go
  25. +2
    -0
      r1csqap/r1csqap.go
  26. +0
    -185
      r1csqapFloat/r1csqapFloat.go
  27. +0
    -137
      r1csqapFloat/r1csqapFloat_test.go
  28. +0
    -0
      res/examples/factor.circuit
  29. +0
    -0
      res/examples/function.circuit
  30. +0
    -0
      res/examples/import-example.circuit
  31. +0
    -0
      res/examples/imported-example.circuit
  32. +0
    -0
      res/vim-syntax/README.md
  33. +0
    -0
      res/vim-syntax/ftdetect/go-snark-circuit.vim
  34. +0
    -0
      res/vim-syntax/screenshot.png
  35. +0
    -0
      res/vim-syntax/syntax/go-snark-circuit.vim

+ 5
- 0
bn128/bn128.go

@ -185,6 +185,7 @@ func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) [2][3][2]*big.Int
return res
}
// AteG1Precomp is ...
type AteG1Precomp struct {
Px *big.Int
Py *big.Int
@ -199,11 +200,14 @@ func (bn128 Bn128) preComputeG1(p [3]*big.Int) AteG1Precomp {
return res
}
// EllCoeffs is ...
type EllCoeffs struct {
Ell0 [2]*big.Int
EllVW [2]*big.Int
EllVV [2]*big.Int
}
// AteG2Precomp is ...
type AteG2Precomp struct {
Qx [2]*big.Int
Qy [2]*big.Int
@ -345,6 +349,7 @@ func (bn128 Bn128) g2MulByQ(p [3][2]*big.Int) [3][2]*big.Int {
}
}
// MillerLoop is ...
func (bn128 Bn128) MillerLoop(pre1 AteG1Precomp, pre2 AteG2Precomp) [2][3][2]*big.Int {
// https://cryptojedi.org/papers/dclxvi-20100714.pdf
// https://eprint.iacr.org/2008/096.pdf

+ 14
- 0
bn128/g1.go

@ -6,11 +6,13 @@ import (
"github.com/arnaucube/go-snark/fields"
)
// G1 is ...
type G1 struct {
F fields.Fq
G [3]*big.Int
}
// NewG1 is ...
func NewG1(f fields.Fq, g [2]*big.Int) G1 {
var g1 G1
g1.F = f
@ -22,13 +24,17 @@ func NewG1(f fields.Fq, g [2]*big.Int) G1 {
return g1
}
// Zero is ...
func (g1 G1) Zero() [2]*big.Int {
return [2]*big.Int{g1.F.Zero(), g1.F.Zero()}
}
// IsZero is ...
func (g1 G1) IsZero(p [3]*big.Int) bool {
return g1.F.IsZero(p[2])
}
// Add is ...
func (g1 G1) Add(p1, p2 [3]*big.Int) [3]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
@ -88,6 +94,7 @@ func (g1 G1) Add(p1, p2 [3]*big.Int) [3]*big.Int {
return [3]*big.Int{x3, y3, z3}
}
// Neg is ...
func (g1 G1) Neg(p [3]*big.Int) [3]*big.Int {
return [3]*big.Int{
p[0],
@ -95,9 +102,13 @@ func (g1 G1) Neg(p [3]*big.Int) [3]*big.Int {
p[2],
}
}
// Sub is ...
func (g1 G1) Sub(a, b [3]*big.Int) [3]*big.Int {
return g1.Add(a, g1.Neg(b))
}
// Double is ...
func (g1 G1) Double(p [3]*big.Int) [3]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
@ -137,6 +148,7 @@ func (g1 G1) Double(p [3]*big.Int) [3]*big.Int {
return [3]*big.Int{x3, y3, z3}
}
// MulScalar is ...
func (g1 G1) MulScalar(p [3]*big.Int, e *big.Int) [3]*big.Int {
// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add
// for more possible implementations see g2.go file, at the function g2.MulScalar()
@ -154,6 +166,7 @@ func (g1 G1) MulScalar(p [3]*big.Int, e *big.Int) [3]*big.Int {
return q
}
// Affine is ...
func (g1 G1) Affine(p [3]*big.Int) [2]*big.Int {
if g1.IsZero(p) {
return g1.Zero()
@ -169,6 +182,7 @@ func (g1 G1) Affine(p [3]*big.Int) [2]*big.Int {
return [2]*big.Int{x, y}
}
// Equal is ...
func (g1 G1) Equal(p1, p2 [3]*big.Int) bool {
if g1.IsZero(p1) {
return g1.IsZero(p2)

+ 12
- 0
bn128/g2.go

@ -6,11 +6,13 @@ import (
"github.com/arnaucube/go-snark/fields"
)
// G2 is ...
type G2 struct {
F fields.Fq2
G [3][2]*big.Int
}
// NewG2 is ...
func NewG2(f fields.Fq2, g [2][2]*big.Int) G2 {
var g2 G2
g2.F = f
@ -22,13 +24,17 @@ func NewG2(f fields.Fq2, g [2][2]*big.Int) G2 {
return g2
}
// Zero is ...
func (g2 G2) Zero() [3][2]*big.Int {
return [3][2]*big.Int{g2.F.Zero(), g2.F.One(), g2.F.Zero()}
}
// IsZero is ...
func (g2 G2) IsZero(p [3][2]*big.Int) bool {
return g2.F.IsZero(p[2])
}
// Add is ...
func (g2 G2) Add(p1, p2 [3][2]*big.Int) [3][2]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
@ -88,6 +94,7 @@ func (g2 G2) Add(p1, p2 [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{x3, y3, z3}
}
// Neg is ...
func (g2 G2) Neg(p [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{
p[0],
@ -96,10 +103,12 @@ func (g2 G2) Neg(p [3][2]*big.Int) [3][2]*big.Int {
}
}
// Sub is ...
func (g2 G2) Sub(a, b [3][2]*big.Int) [3][2]*big.Int {
return g2.Add(a, g2.Neg(b))
}
// Double is ...
func (g2 G2) Double(p [3][2]*big.Int) [3][2]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
@ -139,6 +148,7 @@ func (g2 G2) Double(p [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{x3, y3, z3}
}
// MulScalar is ...
func (g2 G2) MulScalar(p [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add
@ -180,6 +190,7 @@ func (g2 G2) MulScalar(p [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
return q
}
// Affine is ...
func (g2 G2) Affine(p [3][2]*big.Int) [3][2]*big.Int {
if g2.IsZero(p) {
return g2.Zero()
@ -199,6 +210,7 @@ func (g2 G2) Affine(p [3][2]*big.Int) [3][2]*big.Int {
}
}
// Equal is ...
func (g2 G2) Equal(p1, p2 [3][2]*big.Int) bool {
if g2.IsZero(p1) {
return g2.IsZero(p2)

circuitcompiler/circuit-test-1.circuit → circuit/circuit-test-1.circuit


circuitcompiler/circuit-test-2.circuit → circuit/circuit-test-2.circuit


circuitcompiler/circuit.go → circuit/circuit.go

@ -1,4 +1,4 @@
package circuitcompiler
package circuit
import (
"errors"
@ -143,11 +143,11 @@ func grabVar(signals []string, w []*big.Int, vStr string) *big.Int {
vBig := big.NewInt(int64(v))
if isVal {
return vBig
} else {
return w[indexInArray(signals, vStr)]
}
return w[indexInArray(signals, vStr)]
}
// Inputs is ...
type Inputs struct {
Private []*big.Int
Public []*big.Int

circuitcompiler/circuit_test.go → circuit/circuit_test.go

@ -1,4 +1,4 @@
package circuitcompiler
package circuit
import (
"bufio"

circuitcompiler/lexer.go → circuit/lexer.go

@ -1,4 +1,4 @@
package circuitcompiler
package circuit
import (
"bufio"
@ -6,9 +6,13 @@ import (
"io"
)
// OperatorSymbol is ...
type OperatorSymbol int
// Token is ...
type Token int
// Tokens
const (
ILLEGAL Token = iota
WS

circuitcompiler/parser.go → circuit/parser.go

@ -1,4 +1,4 @@
package circuitcompiler
package circuit
import (
"bufio"

+ 98
- 0
cmd/go-snark/compile.go

@ -0,0 +1,98 @@
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
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)
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")
}
}
// save circuit
return saveToFile(compiledFileName, cir)
}

+ 63
- 0
cmd/go-snark/generate.go

@ -0,0 +1,63 @@
package main
import (
"log"
"github.com/arnaucube/go-snark/circuit"
"github.com/arnaucube/go-snark/proof"
"github.com/urfave/cli"
)
func generate(context *cli.Context) error {
// load circuit
var cir circuit.Circuit
if err := loadFromFile(compiledFileName, &cir); 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)
if err != nil {
return err
}
log.Printf("w: %v\n", w)
// load setup
setup, err := newSetup()
if err != nil {
return err
}
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(
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)
}

+ 45
- 0
cmd/go-snark/loadsave.go

@ -0,0 +1,45 @@
package main
import (
"bytes"
"encoding/json"
"io"
"os"
)
func loadFromReader(r io.Reader, obj interface{}) error {
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(r); err != nil {
return err
}
return json.Unmarshal(buf.Bytes(), obj)
}
func loadFromFile(path string, obj interface{}) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
return loadFromReader(f, obj)
}
func saveToWriter(w io.Writer, obj interface{}) error {
b, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
if _, err := w.Write(b); err != nil {
return err
}
return nil
}
func saveToFile(path string, obj interface{}) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return saveToWriter(f, obj)
}

+ 64
- 467
cmd/go-snark/main.go

@ -1,509 +1,106 @@
package main
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"math/big"
"os"
snark "github.com/arnaucube/go-snark"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/urfave/cli"
"github.com/arnaucube/go-snark/proof"
)
func panicErr(err error) {
if err != nil {
panic(err)
}
}
const (
compiledFileName = "compiled.json"
setupFileName = "setup.json"
privateFileName = "private.json"
publicFileName = "public.json"
proofFileName = "proof.json"
)
const (
proofSystemPinocchio = iota
proofSystemGroth16
)
var proofSystem int
var commands = []cli.Command{
{
Name: "compile",
Aliases: []string{},
Usage: "compile a circuit",
Action: CompileCircuit,
Action: compile,
},
{
Name: "trustedsetup",
Name: "setup",
Aliases: []string{},
Usage: "generate trusted setup for a circuit",
Action: TrustedSetup,
Action: setup,
},
{
Name: "genproofs",
Name: "generate",
Aliases: []string{},
Usage: "generate the snark proofs",
Action: GenerateProofs,
Action: generate,
},
{
Name: "verify",
Aliases: []string{},
Usage: "verify the snark proofs",
Action: VerifyProofs,
},
{
Name: "groth16",
Aliases: []string{},
Usage: "use groth16 protocol",
Subcommands: []cli.Command{
{
Name: "trustedsetup",
Aliases: []string{},
Usage: "generate trusted setup for a circuit",
Action: Groth16TrustedSetup,
},
{
Name: "genproofs",
Aliases: []string{},
Usage: "generate the snark proofs",
Action: Groth16GenerateProofs,
},
{
Name: "verify",
Aliases: []string{},
Usage: "verify the snark proofs",
Action: Groth16VerifyProofs,
},
},
Action: verify,
},
}
func main() {
app := cli.NewApp()
app.Name = "go-snarks-cli"
app.Version = "0.0.3-alpha"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "config"},
}
app.Commands = commands
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
func CompileCircuit(context *cli.Context) error {
fmt.Println("cli")
circuitPath := context.Args().Get(0)
// read circuit file
circuitFile, err := os.Open(circuitPath)
panicErr(err)
// parse circuit code
parser := circuitcompiler.NewParser(bufio.NewReader(circuitFile))
circuit, err := parser.Parse()
panicErr(err)
fmt.Println("\ncircuit data:", circuit)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
fmt.Println("\nwitness", w)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
// R1CS to QAP
alphas, betas, gammas, zx := snark.Utils.PF.R1CSToQAP(a, b, c)
fmt.Println("qap")
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
ax, bx, cx, px := snark.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
hx := snark.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, snark.Utils.PF.Mul(hx, zx)) {
panic(errors.New("px != hx*zx"))
}
// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
abc := snark.Utils.PF.Sub(snark.Utils.PF.Mul(ax, bx), cx)
// assert.Equal(t, abc, px)
if !r1csqap.BigArraysEqual(abc, px) {
panic(errors.New("abc != px"))
}
hz := snark.Utils.PF.Mul(hx, zx)
if !r1csqap.BigArraysEqual(abc, hz) {
panic(errors.New("abc != hz"))
}
// assert.Equal(t, abc, hz)
div, rem := snark.Utils.PF.Div(px, zx)
if !r1csqap.BigArraysEqual(hx, div) {
panic(errors.New("hx != div"))
func initProofSystem() error {
switch p := os.Getenv("PROOF_SYSTEM"); p {
case "", "PINOCCHIO":
proofSystem = proofSystemPinocchio
case "GROTH16":
proofSystem = proofSystemGroth16
default:
return fmt.Errorf("proof system not supported: %v", p)
}
// 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()) {
panic(errors.New("error:error: px/zx rem not equal to zeros"))
}
}
// store circuit to json
jsonData, err := json.Marshal(circuit)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("compiledcircuit.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Compiled Circuit data written to ", jsonFile.Name())
return nil
}
func TrustedSetup(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
// R1CS to QAP
alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
fmt.Println("qap")
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
// calculate trusted setup
setup, err := snark.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
panicErr(err)
fmt.Println("\nt:", setup.Toxic.T)
// remove setup.Toxic
var tsetup snark.Setup
tsetup.Pk = setup.Pk
tsetup.Vk = setup.Vk
tsetup.G1T = setup.G1T
tsetup.G2T = setup.G2T
// store setup to json
jsonData, err := json.Marshal(tsetup)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("trustedsetup.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name())
return nil
}
func GenerateProofs(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup snark.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
fmt.Println("witness", w)
// flat code to R1CS
a := circuit.R1CS.A
b := circuit.R1CS.B
c := circuit.R1CS.C
// R1CS to QAP
alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(a, b, c)
_, _, _, px := snark.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
hx := snark.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
fmt.Println(circuit)
fmt.Println(trustedsetup.G1T)
fmt.Println(hx)
fmt.Println(w)
proof, err := snark.GenerateProofs(circuit, trustedsetup, w, px)
panicErr(err)
fmt.Println("\n proofs:")
fmt.Println(proof)
// store proofs to json
jsonData, err := json.Marshal(proof)
panicErr(err)
// store proof into file
jsonFile, err := os.Create("proofs.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Proofs data written to ", jsonFile.Name())
return nil
}
func VerifyProofs(context *cli.Context) error {
// open proofs.json
proofsFile, err := ioutil.ReadFile("proofs.json")
panicErr(err)
var proof snark.Proof
json.Unmarshal([]byte(string(proofsFile)), &proof)
panicErr(err)
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup snark.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
var publicSignals []*big.Int
err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
panicErr(err)
verified := snark.VerifyProof(circuit, trustedsetup, proof, publicSignals, true)
if !verified {
fmt.Println("ERROR: proofs not verified")
} else {
fmt.Println("Proofs verified")
func newSetup() (proof.Setup, error) {
var s proof.Setup
switch proofSystem {
case proofSystemPinocchio:
s = &proof.PinocchioSetup{}
case proofSystemGroth16:
s = &proof.Groth16Setup{}
default:
return nil, fmt.Errorf("proof system not supported: %v", proofSystem)
}
return nil
}
func Groth16TrustedSetup(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
// R1CS to QAP
alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
fmt.Println("qap")
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
// calculate trusted setup
setup, err := groth16.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
panicErr(err)
fmt.Println("\nt:", setup.Toxic.T)
// remove setup.Toxic
var tsetup groth16.Setup
tsetup.Pk = setup.Pk
tsetup.Vk = setup.Vk
// store setup to json
jsonData, err := json.Marshal(tsetup)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("trustedsetup.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name())
return nil
return s, nil
}
func Groth16GenerateProofs(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup groth16.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
fmt.Println("witness", w)
// flat code to R1CS
a := circuit.R1CS.A
b := circuit.R1CS.B
c := circuit.R1CS.C
// R1CS to QAP
alphas, betas, gammas, _ := groth16.Utils.PF.R1CSToQAP(a, b, c)
_, _, _, px := groth16.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
hx := groth16.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
fmt.Println(circuit)
fmt.Println(trustedsetup.Pk.PowersTauDelta)
fmt.Println(hx)
fmt.Println(w)
proof, err := groth16.GenerateProofs(circuit, trustedsetup, w, px)
panicErr(err)
fmt.Println("\n proofs:")
fmt.Println(proof)
// store proofs to json
jsonData, err := json.Marshal(proof)
panicErr(err)
// store proof into file
jsonFile, err := os.Create("proofs.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Proofs data written to ", jsonFile.Name())
return nil
func newProof() (proof.Proof, error) {
var p proof.Proof
switch proofSystem {
case proofSystemPinocchio:
p = &proof.PinocchioProof{}
case proofSystemGroth16:
p = &proof.Groth16Proof{}
default:
return nil, fmt.Errorf("proof system not supported: %v", proofSystem)
}
return p, nil
}
func Groth16VerifyProofs(context *cli.Context) error {
// open proofs.json
proofsFile, err := ioutil.ReadFile("proofs.json")
panicErr(err)
var proof groth16.Proof
json.Unmarshal([]byte(string(proofsFile)), &proof)
panicErr(err)
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup groth16.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
var publicSignals []*big.Int
err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
panicErr(err)
verified := groth16.VerifyProof(circuit, trustedsetup, proof, publicSignals, true)
if !verified {
fmt.Println("ERROR: proofs not verified")
} else {
fmt.Println("Proofs verified")
func main() {
if err := initProofSystem(); err != nil {
panic(err)
}
app := cli.NewApp()
app.Name = "go-snark"
app.Version = "0.0.3-alpha"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "config"},
}
app.Commands = commands
if err := app.Run(os.Args); err != nil {
panic(err)
}
return nil
}

+ 53
- 0
cmd/go-snark/setup.go

@ -0,0 +1,53 @@
package main
import (
"log"
"github.com/arnaucube/go-snark/circuit"
"github.com/arnaucube/go-snark/proof"
"github.com/urfave/cli"
)
func setup(context *cli.Context) error {
// load circuit
var cir circuit.Circuit
if err := loadFromFile(compiledFileName, &cir); 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)
if err != nil {
return err
}
log.Printf("w: %v\n", w)
// R1CS to QAP
alphas, betas, gammas, _ := proof.Utils.PF.R1CSToQAP(
cir.R1CS.A,
cir.R1CS.B,
cir.R1CS.C)
// calculate trusted setup
setup, err := newSetup()
if err != nil {
return err
}
if err := setup.Init(len(w), cir, alphas, betas, gammas); err != nil {
return err
}
log.Printf("setup: %v\n", setup)
// save setup
return saveToFile(setupFileName, setup)
}

+ 50
- 0
cmd/go-snark/verify.go

@ -0,0 +1,50 @@
package main
import (
"fmt"
"log"
"github.com/arnaucube/go-snark/circuit"
"github.com/urfave/cli"
)
func verify(context *cli.Context) error {
// load circuit
var cir circuit.Circuit
if err := loadFromFile(compiledFileName, &cir); err != nil {
return err
}
log.Printf("circuit: %v\n", cir)
// load inputs
var inputs circuit.Inputs
if err := loadFromFile(publicFileName, &inputs.Public); err != nil {
return err
}
// load setup
setup, err := newSetup()
if err != nil {
return err
}
if err := loadFromFile(setupFileName, setup); err != nil {
return err
}
log.Printf("setup: %v\n", setup)
// load proof
proof, err := newProof()
if err != nil {
return err
}
if err := loadFromFile(proofFileName, proof); err != nil {
return err
}
// verify proof
if ok := setup.Verify(cir, proof, inputs.Public, true); !ok {
return fmt.Errorf("verif KO")
}
log.Printf("verif OK\n")
return nil
}

+ 7
- 0
fields/fq.go

@ -58,6 +58,7 @@ func (fq Fq) Mul(a, b *big.Int) *big.Int {
return new(big.Int).Mod(m, fq.Q)
}
// MulScalar is ...
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
return fq.Mul(base, e)
}
@ -113,6 +114,7 @@ func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
return res
}
// Rand is ...
func (fq Fq) Rand() (*big.Int, error) {
// twoexp := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(maxbits)), nil)
@ -131,14 +133,17 @@ func (fq Fq) Rand() (*big.Int, error) {
return rq, nil
}
// IsZero is ...
func (fq Fq) IsZero(a *big.Int) bool {
return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
}
// Copy is ...
func (fq Fq) Copy(a *big.Int) *big.Int {
return new(big.Int).SetBytes(a.Bytes())
}
// Affine is ...
func (fq Fq) Affine(a *big.Int) *big.Int {
nq := fq.Neg(fq.Q)
@ -158,12 +163,14 @@ func (fq Fq) Affine(a *big.Int) *big.Int {
return aux
}
// Equal is ...
func (fq Fq) Equal(a, b *big.Int) bool {
aAff := fq.Affine(a)
bAff := fq.Affine(b)
return bytes.Equal(aAff.Bytes(), bAff.Bytes())
}
// BigIsOdd is ...
func BigIsOdd(n *big.Int) bool {
one := big.NewInt(int64(1))
and := new(big.Int).And(n, one)

+ 6
- 0
fields/fq12.go

@ -83,6 +83,7 @@ func (fq12 Fq12) Mul(a, b [2][3][2]*big.Int) [2][3][2]*big.Int {
}
}
// MulScalar is ...
func (fq12 Fq12) MulScalar(base [2][3][2]*big.Int, e *big.Int) [2][3][2]*big.Int {
// for more possible implementations see g2.go file, at the function g2.MulScalar()
@ -136,6 +137,7 @@ func (fq12 Fq12) Square(a [2][3][2]*big.Int) [2][3][2]*big.Int {
}
}
// Exp is ...
func (fq12 Fq12) Exp(base [2][3][2]*big.Int, e *big.Int) [2][3][2]*big.Int {
// TODO fix bottleneck
@ -154,12 +156,16 @@ func (fq12 Fq12) Exp(base [2][3][2]*big.Int, e *big.Int) [2][3][2]*big.Int {
// fmt.Println("time elapsed:", time.Since(before))
return res
}
// Affine is ...
func (fq12 Fq12) Affine(a [2][3][2]*big.Int) [2][3][2]*big.Int {
return [2][3][2]*big.Int{
fq12.F.Affine(a[0]),
fq12.F.Affine(a[1]),
}
}
// Equal is ...
func (fq12 Fq12) Equal(a, b [2][3][2]*big.Int) bool {
return fq12.F.Equal(a[0], b[0]) && fq12.F.Equal(a[1], b[1])
}

+ 6
- 0
fields/fq2.go

@ -75,6 +75,7 @@ func (fq2 Fq2) Mul(a, b [2]*big.Int) [2]*big.Int {
}
}
// MulScalar is ...
func (fq2 Fq2) MulScalar(p [2]*big.Int, e *big.Int) [2]*big.Int {
// for more possible implementations see g2.go file, at the function g2.MulScalar()
@ -132,20 +133,25 @@ func (fq2 Fq2) Square(a [2]*big.Int) [2]*big.Int {
}
}
// IsZero is ...
func (fq2 Fq2) IsZero(a [2]*big.Int) bool {
return fq2.F.IsZero(a[0]) && fq2.F.IsZero(a[1])
}
// Affine is ...
func (fq2 Fq2) Affine(a [2]*big.Int) [2]*big.Int {
return [2]*big.Int{
fq2.F.Affine(a[0]),
fq2.F.Affine(a[1]),
}
}
// Equal is ...
func (fq2 Fq2) Equal(a, b [2]*big.Int) bool {
return fq2.F.Equal(a[0], b[0]) && fq2.F.Equal(a[1], b[1])
}
// Copy is ...
func (fq2 Fq2) Copy(a [2]*big.Int) [2]*big.Int {
return [2]*big.Int{
fq2.F.Copy(a[0]),

+ 6
- 0
fields/fq6.go

@ -43,6 +43,7 @@ func (fq6 Fq6) Add(a, b [3][2]*big.Int) [3][2]*big.Int {
}
}
// Double is ...
func (fq6 Fq6) Double(a [3][2]*big.Int) [3][2]*big.Int {
return fq6.Add(a, a)
}
@ -94,6 +95,7 @@ func (fq6 Fq6) Mul(a, b [3][2]*big.Int) [3][2]*big.Int {
}
}
// MulScalar is ...
func (fq6 Fq6) MulScalar(base [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
// for more possible implementations see g2.go file, at the function g2.MulScalar()
@ -172,6 +174,7 @@ func (fq6 Fq6) Square(a [3][2]*big.Int) [3][2]*big.Int {
}
}
// Affine is ...
func (fq6 Fq6) Affine(a [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{
fq6.F.Affine(a[0]),
@ -179,10 +182,13 @@ func (fq6 Fq6) Affine(a [3][2]*big.Int) [3][2]*big.Int {
fq6.F.Affine(a[2]),
}
}
// Equal is ...
func (fq6 Fq6) Equal(a, b [3][2]*big.Int) bool {
return fq6.F.Equal(a[0], b[0]) && fq6.F.Equal(a[1], b[1]) && fq6.F.Equal(a[2], b[2])
}
// Copy is ...
func (fq6 Fq6) Copy(a [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{
fq6.F.Copy(a[0]),

groth16/groth16.go → proof/groth16.go

@ -1,19 +1,16 @@
// implementation of https://eprint.iacr.org/2016/260.pdf
package groth16
package proof
import (
"fmt"
"math/big"
"github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark/circuit"
)
// Setup is the data structure holding the Trusted Setup data. The Setup.Toxic sub struct must be destroyed after the GenerateTrustedSetup function is completed
type Setup struct {
// Groth16Setup is the data structure holding the Trusted Groth16Setup data.
type Groth16Setup struct {
Toxic struct {
T *big.Int // trusted setup secret
Kalpha *big.Int
@ -54,65 +51,43 @@ type Setup struct {
}
}
// Proof contains the parameters to proof the zkSNARK
type Proof struct {
// Groth16Proof contains the parameters to proof the zkSNARK
type Groth16Proof struct {
PiA [3]*big.Int
PiB [3][2]*big.Int
PiC [3]*big.Int
}
type utils struct {
Bn bn128.Bn128
FqR fields.Fq
PF r1csqap.PolynomialField
// Z is ...
func (setup *Groth16Setup) Z() []*big.Int {
return setup.Pk.Z
}
// 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 {
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,
}
}
// GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed
func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error) {
var setup Setup
// 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 {
var err error
// generate random t value
setup.Toxic.T, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kalpha, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kbeta, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kgamma, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kdelta, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
// z pol
@ -215,23 +190,23 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
setup.Vk.IC = append(setup.Vk.IC, g1ic)
}
return setup, nil
return nil
}
// GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness
func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, px []*big.Int) (Proof, error) {
var proof Proof
// 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) {
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()
proof.PiC = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
r, err := Utils.FqR.Rand()
if err != nil {
return Proof{}, err
return &Groth16Proof{}, err
}
s, err := Utils.FqR.Rand()
if err != nil {
return Proof{}, err
return &Groth16Proof{}, err
}
// piBG1 will hold all the same than proof.PiB but in G1 curve
@ -274,8 +249,12 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int,
return proof, nil
}
// VerifyProof verifies over the BN128 the Pairings of the Proof
func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, debug bool) bool {
// 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 {
pproof, ok := proof.(*Groth16Proof)
if !ok {
panic("bad proof")
}
icPubl := setup.Vk.IC[0]
for i := 0; i < len(publicSignals); i++ {
@ -283,12 +262,12 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
if !Utils.Bn.Fq12.Equal(
Utils.Bn.Pairing(proof.PiA, proof.PiB),
Utils.Bn.Pairing(pproof.PiA, pproof.PiB),
Utils.Bn.Fq12.Mul(
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(proof.PiC, setup.Vk.G2.Delta)))) {
Utils.Bn.Pairing(pproof.PiC, setup.Vk.G2.Delta)))) {
if debug {
fmt.Println("❌ groth16 verification not passed")
}

groth16/groth16_test.go → proof/groth16_test.go

@ -1,4 +1,4 @@
package groth16
package proof
import (
"bytes"
@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/circuit"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/stretchr/testify/assert"
)
@ -29,7 +29,7 @@ func TestGroth16MinimalFlow(t *testing.T) {
fmt.Print("\ncode of the circuit:")
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
parser := circuit.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
@ -70,7 +70,8 @@ func TestGroth16MinimalFlow(t *testing.T) {
// ---
// calculate trusted setup
fmt.Println("groth")
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
setup := &Groth16Setup{}
err = setup.Init(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
@ -85,7 +86,7 @@ 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 := GenerateProofs(*circuit, setup, w, px)
proof, err := setup.Generate(*circuit, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@ -97,11 +98,11 @@ func TestGroth16MinimalFlow(t *testing.T) {
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false))
}

snark.go → proof/pinocchio.go

@ -1,20 +1,17 @@
// implementation of https://eprint.iacr.org/2013/879.pdf
package snark
package proof
import (
"fmt"
"math/big"
"os"
"github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark/circuit"
)
// Setup is the data structure holding the Trusted Setup data. The Setup.Toxic sub struct must be destroyed after the GenerateTrustedSetup function is completed
type Setup struct {
// PinocchioSetup is the data structure holding the Trusted Setup data.
// The Setup.Toxic sub struct must be destroyed after the Init function is completed
type PinocchioSetup struct {
Toxic struct {
T *big.Int // trusted setup secret
Ka *big.Int // prover
@ -25,7 +22,7 @@ type Setup struct {
RhoA *big.Int
RhoB *big.Int
RhoC *big.Int
}
} `json:"-"`
// public
G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H
@ -52,8 +49,8 @@ type Setup struct {
}
}
// Proof contains the parameters to proof the zkSNARK
type Proof struct {
// PinocchioProof contains the parameters to proof the zkSNARK
type PinocchioProof struct {
PiA [3]*big.Int
PiAp [3]*big.Int
PiB [3][2]*big.Int
@ -65,35 +62,13 @@ type Proof struct {
// PublicSignals []*big.Int
}
type utils struct {
Bn bn128.Bn128
FqR fields.Fq
PF r1csqap.PolynomialField
// Z is ...
func (setup *PinocchioSetup) Z() []*big.Int {
return setup.Pk.Z
}
// 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 {
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,
}
}
// GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed
func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error) {
var setup Setup
// 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 {
var err error
// input soundness
@ -110,41 +85,41 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
// generate random t value
setup.Toxic.T, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
// k for calculating pi' and Vk
setup.Toxic.Ka, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kb, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kc, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
// generate Kβ (Kbeta) and Kγ (Kgamma)
setup.Toxic.Kbeta, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.Kgamma, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
// generate ρ (Rho): ρA, ρB, ρC
setup.Toxic.RhoA, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.RhoB, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
return err
}
setup.Toxic.RhoC = Utils.FqR.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB)
@ -203,15 +178,14 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
ktest := Utils.Bn.G1.Affine(Utils.Bn.G1.Add(Utils.Bn.G1.Add(a, bg1), c))
if !Utils.Bn.Fq2.Equal(k, ktest) {
os.Exit(1)
return setup, err
return err
}
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))
k_ := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, kt)
setup.Pk.Kp = append(setup.Pk.Kp, Utils.Bn.G1.MulScalar(k_, setup.Toxic.Kbeta))
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
@ -244,12 +218,12 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
}
setup.G1T = gt1
return setup, nil
return nil
}
// GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness
func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, px []*big.Int) (Proof, error) {
var proof Proof
// 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) {
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()}
proof.PiB = Utils.Bn.Fq6.Zero()
@ -285,11 +259,16 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int,
return proof, nil
}
// VerifyProof verifies over the BN128 the Pairings of the Proof
func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, debug bool) bool {
// 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)
pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka)
pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G)
pproof, ok := proof.(*PinocchioProof)
if !ok {
panic("bad 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")
@ -301,8 +280,8 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
// e(Vb, piB) == e(piB', g2)
pairingVbPib := Utils.Bn.Pairing(setup.Vk.Vkb, proof.PiB)
pairingPibpG2 := Utils.Bn.Pairing(proof.PiBp, Utils.Bn.G2.G)
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")
@ -314,8 +293,8 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
// e(piC, Vc) == e(piC', g2)
pairingPicVc := Utils.Bn.Pairing(proof.PiC, setup.Vk.Vkc)
pairingPicpG2 := Utils.Bn.Pairing(proof.PiCp, Utils.Bn.G2.G)
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")
@ -334,10 +313,10 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
// e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2)
if !Utils.Bn.Fq12.Equal(
Utils.Bn.Pairing(Utils.Bn.G1.Add(vkxpia, proof.PiA), proof.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), // TODO Add(vkxpia, proof.PiA) can go outside in order to save computation, as is reused later
Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(proof.PiH, setup.Vk.Vkz),
Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) {
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")
}
@ -349,11 +328,11 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
// e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB)
// == e(piK, g2Kgamma)
piApiC := Utils.Bn.G1.Add(Utils.Bn.G1.Add(vkxpia, proof.PiA), proof.PiC)
pairingPiACG2Kbg := Utils.Bn.Pairing(piApiC, setup.Vk.G2Kbg)
pairingG1KbgPiB := Utils.Bn.Pairing(setup.Vk.G1Kbg, proof.PiB)
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(proof.PiKp, setup.Vk.G2Kg)
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

snark_test.go → proof/pinocchio_test.go

@ -1,4 +1,4 @@
package snark
package proof
import (
"bytes"
@ -8,104 +8,11 @@ import (
"testing"
"time"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/stretchr/testify/assert"
)
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
s3 = s2 * s0
s4 = s3 + s0
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1
`
fmt.Print("\ncode of the circuit:")
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
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)
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")
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
assert.Equal(t, 7, len(ax))
assert.Equal(t, 7, len(bx))
assert.Equal(t, 7, len(cx))
assert.Equal(t, 13, len(px))
// ---
// from here is the GROTH16
// ---
// calculate trusted setup
fmt.Println("groth")
setup, err := groth16.GenerateTrustedSetup(len(w), *circuit, 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))
// hx==px/zx so px==hx*zx
assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
// check length of polynomials H(x) and Z(x)
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
proof, err := groth16.GenerateProofs(*circuit, setup, 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, groth16.VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !groth16.VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
}
"github.com/arnaucube/go-snark/circuit"
"github.com/arnaucube/go-snark/r1csqap"
)
func TestZkFromFlatCircuitCode(t *testing.T) {
// compile circuit and get the R1CS
@ -142,7 +49,7 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
fmt.Println(code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
parser := circuit.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
// fmt.Println("\ncircuit data:", circuit)
@ -199,7 +106,8 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
setup := &PinocchioSetup{}
err = setup.Init(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
@ -221,7 +129,7 @@ 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 := GenerateProofs(*circuit, setup, w, px)
proof, err := setup.Generate(*circuit, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@ -233,13 +141,13 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false))
}
func TestZkMultiplication(t *testing.T) {
@ -252,7 +160,7 @@ func TestZkMultiplication(t *testing.T) {
fmt.Println("code", code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
parser := circuit.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
@ -306,7 +214,8 @@ func TestZkMultiplication(t *testing.T) {
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
setup := &PinocchioSetup{}
err = setup.Init(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
// fmt.Println("\nt:", setup.Toxic.T)
@ -329,7 +238,7 @@ 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 := GenerateProofs(*circuit, setup, w, px)
proof, err := setup.Generate(*circuit, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@ -341,13 +250,13 @@ func TestZkMultiplication(t *testing.T) {
b12Verif := big.NewInt(int64(12))
publicSignalsVerif := []*big.Int{b12Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(11))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false))
}
func TestMinimalFlow(t *testing.T) {
@ -366,7 +275,7 @@ func TestMinimalFlow(t *testing.T) {
fmt.Println(code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
parser := circuit.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
@ -403,7 +312,8 @@ func TestMinimalFlow(t *testing.T) {
assert.Equal(t, 13, len(px))
// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
setup := &PinocchioSetup{}
err = setup.Init(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
@ -418,7 +328,7 @@ 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 := GenerateProofs(*circuit, setup, w, px)
proof, err := setup.Generate(*circuit, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@ -430,11 +340,11 @@ func TestMinimalFlow(t *testing.T) {
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, setup.Verify(*circuit, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
assert.True(t, !setup.Verify(*circuit, proof, wrongPublicSignalsVerif, false))
}

+ 47
- 0
proof/proof.go

@ -0,0 +1,47 @@
package proof
import (
"math/big"
"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 {
Bn bn128.Bn128
FqR fields.Fq
PF r1csqap.PolynomialField
}
// 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 {
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
}

+ 2
- 0
r1csqap/r1csqap.go

@ -29,6 +29,8 @@ func ArrayOfBigZeros(num int) []*big.Int {
}
return r
}
// BigArraysEqual is ...
func BigArraysEqual(a, b []*big.Int) bool {
if len(a) != len(b) {
return false

+ 0
- 185
r1csqapFloat/r1csqapFloat.go

@ -1,185 +0,0 @@
package r1csqapFloat
import "math/big"
func Transpose(matrix [][]*big.Float) [][]*big.Float {
var r [][]*big.Float
for i := 0; i < len(matrix[0]); i++ {
var row []*big.Float
for j := 0; j < len(matrix); j++ {
row = append(row, matrix[j][i])
}
r = append(r, row)
}
return r
}
func ArrayOfBigZeros(num int) []*big.Float {
bigZero := big.NewFloat(float64(0))
var r []*big.Float
for i := 0; i < num; i++ {
r = append(r, bigZero)
}
return r
}
func PolMul(a, b []*big.Float) []*big.Float {
r := ArrayOfBigZeros(len(a) + len(b) - 1)
for i := 0; i < len(a); i++ {
for j := 0; j < len(b); j++ {
r[i+j] = new(big.Float).Add(
r[i+j],
new(big.Float).Mul(a[i], b[j]))
}
}
return r
}
func PolDiv(a, b []*big.Float) ([]*big.Float, []*big.Float) {
// https://en.wikipedia.org/wiki/Division_algorithm
r := ArrayOfBigZeros(len(a) - len(b) + 1)
rem := a
for len(rem) >= len(b) {
l := new(big.Float).Quo(rem[len(rem)-1], b[len(b)-1])
pos := len(rem) - len(b)
r[pos] = l
aux := ArrayOfBigZeros(pos)
aux1 := append(aux, l)
aux2 := PolSub(rem, PolMul(b, aux1))
rem = aux2[:len(aux2)-1]
}
return r, rem
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func PolAdd(a, b []*big.Float) []*big.Float {
r := ArrayOfBigZeros(max(len(a), len(b)))
for i := 0; i < len(a); i++ {
r[i] = new(big.Float).Add(r[i], a[i])
}
for i := 0; i < len(b); i++ {
r[i] = new(big.Float).Add(r[i], b[i])
}
return r
}
func PolSub(a, b []*big.Float) []*big.Float {
r := ArrayOfBigZeros(max(len(a), len(b)))
for i := 0; i < len(a); i++ {
r[i] = new(big.Float).Add(r[i], a[i])
}
for i := 0; i < len(b); i++ {
bneg := new(big.Float).Mul(b[i], big.NewFloat(float64(-1)))
r[i] = new(big.Float).Add(r[i], bneg)
}
return r
}
func FloatPow(a *big.Float, e int) *big.Float {
if e == 0 {
return big.NewFloat(float64(1))
}
result := new(big.Float).Copy(a)
for i := 0; i < e-1; i++ {
result = new(big.Float).Mul(result, a)
}
return result
}
func PolEval(v []*big.Float, x *big.Float) *big.Float {
r := big.NewFloat(float64(0))
for i := 0; i < len(v); i++ {
xi := FloatPow(x, i)
elem := new(big.Float).Mul(v[i], xi)
r = new(big.Float).Add(r, elem)
}
return r
}
func NewPolZeroAt(pointPos, totalPoints int, height *big.Float) []*big.Float {
fac := 1
for i := 1; i < totalPoints+1; i++ {
if i != pointPos {
fac = fac * (pointPos - i)
}
}
facBig := big.NewFloat(float64(fac))
hf := new(big.Float).Quo(height, facBig)
r := []*big.Float{hf}
for i := 1; i < totalPoints+1; i++ {
if i != pointPos {
ineg := big.NewFloat(float64(-i))
b1 := big.NewFloat(float64(1))
r = PolMul(r, []*big.Float{ineg, b1})
}
}
return r
}
func LagrangeInterpolation(v []*big.Float) []*big.Float {
// https://en.wikipedia.org/wiki/Lagrange_polynomial
var r []*big.Float
for i := 0; i < len(v); i++ {
r = PolAdd(r, NewPolZeroAt(i+1, len(v), v[i]))
}
//
return r
}
func R1CSToQAP(a, b, c [][]*big.Float) ([][]*big.Float, [][]*big.Float, [][]*big.Float, []*big.Float) {
aT := Transpose(a)
bT := Transpose(b)
cT := Transpose(c)
var alphas [][]*big.Float
for i := 0; i < len(aT); i++ {
alphas = append(alphas, LagrangeInterpolation(aT[i]))
}
var betas [][]*big.Float
for i := 0; i < len(bT); i++ {
betas = append(betas, LagrangeInterpolation(bT[i]))
}
var gammas [][]*big.Float
for i := 0; i < len(cT); i++ {
gammas = append(gammas, LagrangeInterpolation(cT[i]))
}
z := []*big.Float{big.NewFloat(float64(1))}
for i := 1; i < len(aT[0])+1; i++ {
ineg := big.NewFloat(float64(-i))
b1 := big.NewFloat(float64(1))
z = PolMul(z, []*big.Float{ineg, b1})
}
return alphas, betas, gammas, z
}
func CombinePolynomials(r []*big.Float, ap, bp, cp [][]*big.Float) ([]*big.Float, []*big.Float, []*big.Float, []*big.Float) {
var alpha []*big.Float
for i := 0; i < len(r); i++ {
m := PolMul([]*big.Float{r[i]}, ap[i])
alpha = PolAdd(alpha, m)
}
var beta []*big.Float
for i := 0; i < len(r); i++ {
m := PolMul([]*big.Float{r[i]}, bp[i])
beta = PolAdd(beta, m)
}
var gamma []*big.Float
for i := 0; i < len(r); i++ {
m := PolMul([]*big.Float{r[i]}, cp[i])
gamma = PolAdd(gamma, m)
}
px := PolSub(PolMul(alpha, beta), gamma)
return alpha, beta, gamma, px
}
func DivisorPolinomial(px, z []*big.Float) []*big.Float {
quo, _ := PolDiv(px, z)
return quo
}

+ 0
- 137
r1csqapFloat/r1csqapFloat_test.go

@ -1,137 +0,0 @@
package r1csqapFloat
import (
"fmt"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func TestTranspose(t *testing.T) {
b0 := big.NewFloat(float64(0))
b1 := big.NewFloat(float64(1))
bFive := big.NewFloat(float64(5))
a := [][]*big.Float{
[]*big.Float{b0, b1, b0, b0, b0, b0},
[]*big.Float{b0, b0, b0, b1, b0, b0},
[]*big.Float{b0, b1, b0, b0, b1, b0},
[]*big.Float{bFive, b0, b0, b0, b0, b1},
}
aT := Transpose(a)
assert.Equal(t, aT, [][]*big.Float{
[]*big.Float{b0, b0, b0, bFive},
[]*big.Float{b1, b0, b1, b0},
[]*big.Float{b0, b0, b0, b0},
[]*big.Float{b0, b1, b0, b0},
[]*big.Float{b0, b0, b1, b0},
[]*big.Float{b0, b0, b0, b1},
})
}
func TestPol(t *testing.T) {
b0 := big.NewFloat(float64(0))
b1 := big.NewFloat(float64(1))
// b1neg := big.NewFloat(float64(-1))
// b2 := big.NewFloat(float64(2))
b2neg := big.NewFloat(float64(-2))
b3 := big.NewFloat(float64(3))
b4 := big.NewFloat(float64(4))
b5 := big.NewFloat(float64(5))
b6 := big.NewFloat(float64(6))
b16 := big.NewFloat(float64(16))
a := []*big.Float{b1, b0, b5}
b := []*big.Float{b3, b0, b1}
// polynomial multiplication
c := PolMul(a, b)
assert.Equal(t, c, []*big.Float{b3, b0, b16, b0, b5})
// polynomial addition
c = PolAdd(a, b)
assert.Equal(t, c, []*big.Float{b4, b0, b6})
// polynomial subtraction
c = PolSub(a, b)
assert.Equal(t, c, []*big.Float{b2neg, b0, b4})
// FloatPow
p := FloatPow(big.NewFloat(float64(5)), 3)
assert.Equal(t, p, big.NewFloat(float64(125)))
p = FloatPow(big.NewFloat(float64(5)), 0)
assert.Equal(t, p, big.NewFloat(float64(1)))
// NewPolZeroAt
r := NewPolZeroAt(3, 4, b4)
assert.Equal(t, PolEval(r, big.NewFloat(3)), b4)
r = NewPolZeroAt(2, 4, b3)
assert.Equal(t, PolEval(r, big.NewFloat(2)), b3)
}
func TestLagrangeInterpolation(t *testing.T) {
b0 := big.NewFloat(float64(0))
b5 := big.NewFloat(float64(5))
a := []*big.Float{b0, b0, b0, b5}
alpha := LagrangeInterpolation(a)
assert.Equal(t, PolEval(alpha, big.NewFloat(4)), b5)
aux, _ := PolEval(alpha, big.NewFloat(3)).Int64()
assert.Equal(t, aux, int64(0))
}
func TestR1CSToQAP(t *testing.T) {
b0 := big.NewFloat(float64(0))
b1 := big.NewFloat(float64(1))
b3 := big.NewFloat(float64(3))
b5 := big.NewFloat(float64(5))
b9 := big.NewFloat(float64(9))
b27 := big.NewFloat(float64(27))
b30 := big.NewFloat(float64(30))
b35 := big.NewFloat(float64(35))
a := [][]*big.Float{
[]*big.Float{b0, b1, b0, b0, b0, b0},
[]*big.Float{b0, b0, b0, b1, b0, b0},
[]*big.Float{b0, b1, b0, b0, b1, b0},
[]*big.Float{b5, b0, b0, b0, b0, b1},
}
b := [][]*big.Float{
[]*big.Float{b0, b1, b0, b0, b0, b0},
[]*big.Float{b0, b1, b0, b0, b0, b0},
[]*big.Float{b1, b0, b0, b0, b0, b0},
[]*big.Float{b1, b0, b0, b0, b0, b0},
}
c := [][]*big.Float{
[]*big.Float{b0, b0, b0, b1, b0, b0},
[]*big.Float{b0, b0, b0, b0, b1, b0},
[]*big.Float{b0, b0, b0, b0, b0, b1},
[]*big.Float{b0, b0, b1, b0, b0, b0},
}
// alphas, betas, gammas
alphas, betas, gammas, zx := R1CSToQAP(a, b, c)
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
fmt.Print("Z(x): ")
fmt.Println(zx)
zexpected := []*big.Float{big.NewFloat(float64(24)), big.NewFloat(float64(-50)), big.NewFloat(float64(35)), big.NewFloat(float64(-10)), big.NewFloat(float64(1))}
assert.Equal(t, zx, zexpected)
// witness
w := []*big.Float{b1, b3, b35, b9, b27, b30}
fmt.Print("w: ")
fmt.Println(w)
// QAP A(x), B(x), C(x)
ax, bx, cx, px := CombinePolynomials(w, alphas, betas, gammas)
fmt.Print("A(x), B(x), C(x), P(x): ")
fmt.Println(ax)
fmt.Println(bx)
fmt.Println(cx)
fmt.Println(px)
hx := DivisorPolinomial(px, zx)
fmt.Print("H(x): ")
fmt.Println(hx)
}

circuitexamples/factor.circuit → res/examples/factor.circuit


circuitexamples/function.circuit → res/examples/function.circuit


circuitexamples/import-example.circuit → res/examples/import-example.circuit


circuitexamples/imported-example.circuit → res/examples/imported-example.circuit


vim-syntax/README.md → res/vim-syntax/README.md


vim-syntax/ftdetect/go-snark-circuit.vim → res/vim-syntax/ftdetect/go-snark-circuit.vim


vim-syntax/screenshot.png → res/vim-syntax/screenshot.png


vim-syntax/syntax/go-snark-circuit.vim → res/vim-syntax/syntax/go-snark-circuit.vim


Loading…
Cancel
Save