diff --git a/README.md b/README.md index bfac522..5f2a46e 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,14 @@ zkSNARK library implementation in Go +- `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 +- `Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf + +## Caution +Implementation from scratch in Go to understand the concepts. Do not use in production. + +Not finished, implementing this in my free time to understand it better, so I don't have much time. -`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 -`Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf ### Usage - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark @@ -79,7 +84,5 @@ go test ./... -v --- -## Caution -Not finished, work in progress (implementing this in my free time to understand it better, so I don't have much time). -Thanks to [@jbaylina](https://github.com/jbaylina), [@bellesmarta](https://github.com/bellesmarta), [@adriamb](https://github.com/adriamb) for their explanations that helped to understand this a little bit. +Thanks to [@jbaylina](https://github.com/jbaylina), [@bellesmarta](https://github.com/bellesmarta), [@adriamb](https://github.com/adriamb) for their explanations that helped to understand this a little bit. Also thanks to [@vbuterin](https://github.com/vbuterin) for all the published articles explaining the zkSNARKs. diff --git a/bn128/g1_test.go b/bn128/g1_test.go index e2bf533..1c38337 100644 --- a/bn128/g1_test.go +++ b/bn128/g1_test.go @@ -1,10 +1,10 @@ package bn128 import ( + "encoding/hex" "math/big" "testing" - "github.com/arnaucube/cryptofun/utils" "github.com/stretchr/testify/assert" ) @@ -26,6 +26,6 @@ func TestG1(t *testing.T) { a := bn128.G1.Affine(grsum1) b := bn128.G1.Affine(grsum2) assert.Equal(t, a, b) - assert.Equal(t, "0x2f978c0ab89ebaa576866706b14787f360c4d6c3869efe5a72f7c3651a72ff00", utils.BytesToHex(a[0].Bytes())) - assert.Equal(t, "0x12e4ba7f0edca8b4fa668fe153aebd908d322dc26ad964d4cd314795844b62b2", utils.BytesToHex(a[1].Bytes())) + assert.Equal(t, "2f978c0ab89ebaa576866706b14787f360c4d6c3869efe5a72f7c3651a72ff00", hex.EncodeToString(a[0].Bytes())) + assert.Equal(t, "12e4ba7f0edca8b4fa668fe153aebd908d322dc26ad964d4cd314795844b62b2", hex.EncodeToString(a[1].Bytes())) } diff --git a/circuitcompiler/circuit.go b/circuitcompiler/circuit.go index a70ce2b..3f2e14a 100644 --- a/circuitcompiler/circuit.go +++ b/circuitcompiler/circuit.go @@ -1,10 +1,32 @@ package circuitcompiler +import ( + "fmt" + "math/big" +) + type Circuit struct { NVars int NPublic int NSignals int - Inputs []int - Witness []int + Inputs []string + Signals []string + Witness []*big.Int Constraints []Constraint + R1CS struct { + A [][]*big.Int + B [][]*big.Int + C [][]*big.Int + } +} + +func (c *Circuit) GenerateR1CS() { + fmt.Print("function with inputs: ") + fmt.Println(c.Inputs) + fmt.Print("signals: ") + fmt.Println(c.Signals) + for _, constraint := range c.Constraints { + fmt.Println(constraint.Literal) + + } } diff --git a/circuitcompiler/circuit_test.go b/circuitcompiler/circuit_test.go index 70decd9..b61d8a8 100644 --- a/circuitcompiler/circuit_test.go +++ b/circuitcompiler/circuit_test.go @@ -21,16 +21,22 @@ func TestCircuitParser(t *testing.T) { m3 = m2 + s1 out = m3 + 5 */ - raw := ` - y = x^x - z = x + y - out = z + 5 + + // flat code + flat := ` + func test(x): + aux = x*x + y = aux*x + z = x + y + out = z + 5 ` - parser := NewParser(strings.NewReader(raw)) - res, err := parser.Parse() + parser := NewParser(strings.NewReader(flat)) + circuit, err := parser.Parse() assert.Nil(t, err) - fmt.Println(res) + fmt.Println(circuit) - // flat code // flat code to R1CS + fmt.Println("generating R1CS from flat code") + circuit.GenerateR1CS() + fmt.Println(circuit.Inputs) } diff --git a/circuitcompiler/parser.go b/circuitcompiler/parser.go index 033d2d4..972fd7b 100644 --- a/circuitcompiler/parser.go +++ b/circuitcompiler/parser.go @@ -3,6 +3,8 @@ package circuitcompiler import ( "errors" "io" + "regexp" + "strings" ) type Parser struct { @@ -17,10 +19,12 @@ type Parser struct { type Constraint struct { // v1 op v2 = out Op Token - V1 Token - V2 Token - Out Token + V1 string + V2 string + Out string Literal string + + Inputs []string // in func delcaration case } func NewParser(r io.Reader) *Parser { @@ -57,36 +61,72 @@ func (p *Parser) ParseLine() (*Constraint, error) { in this version, line will be for example s3 = s1 * s4 this is: - val op val op val - ident op ident op ident + val eq val op val */ c := &Constraint{} - var lit string - c.Out, lit = p.scanIgnoreWhitespace() + tok, lit := p.scanIgnoreWhitespace() + c.Out = lit c.Literal += lit + + if c.Literal == "func" { + // format: `func name(in):` + line, err := p.s.r.ReadString(':') + if err != nil { + return c, err + } + // read string inside ( ) + rgx := regexp.MustCompile(`\((.*?)\)`) + insideParenthesis := rgx.FindStringSubmatch(line) + varsString := strings.Replace(insideParenthesis[1], " ", "", -1) + c.Inputs = strings.Split(varsString, ",") + return c, nil + } + _, lit = p.scanIgnoreWhitespace() // skip = c.Literal += lit - c.V1, lit = p.scanIgnoreWhitespace() + + // v1 + _, lit = p.scanIgnoreWhitespace() + c.V1 = lit c.Literal += lit + // operator c.Op, lit = p.scanIgnoreWhitespace() c.Literal += lit - c.V2, lit = p.scanIgnoreWhitespace() + // v2 + _, lit = p.scanIgnoreWhitespace() + c.V2 = lit c.Literal += lit - if c.Out == EOF { + if tok == EOF { return nil, errors.New("eof in parseline") } return c, nil } +func addToArrayIfNotExist(arr []string, elem string) []string { + for _, v := range arr { + if v == elem { + return arr + } + } + arr = append(arr, elem) + return arr +} func (p *Parser) Parse() (*Circuit, error) { circuit := &Circuit{} + circuit.Signals = append(circuit.Signals, "one") for { constraint, err := p.ParseLine() if err != nil { - // return circuit, err break } + if constraint.Literal == "func" { + circuit.Inputs = constraint.Inputs + continue + } circuit.Constraints = append(circuit.Constraints, *constraint) + circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1) + circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2) + circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out) } return circuit, nil } diff --git a/go.mod b/go.mod index 6bc629d..3593c67 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,6 @@ module github.com/arnaucube/go-snark require ( - github.com/arnaucube/cryptofun v0.0.0-20181210231954-f5d913b6a74c github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 diff --git a/go.sum b/go.sum index a6c76b7..e03ee77 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,3 @@ -github.com/arnaucube/bn128 v0.0.0-20181124004642-3bb6b68ddbe4/go.mod h1:bIKGJe1ZaHy7HYQML7Me4q38pOpggn3JO1VPPyMe3zI= -github.com/arnaucube/cryptofun v0.0.0-20181124001128-d55d875d7a54/go.mod h1:PZE8kKpHPD1UMrS3mTfAMmEEinGtijSwjxLRqRcD64A= -github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd/go.mod h1:PZE8kKpHPD1UMrS3mTfAMmEEinGtijSwjxLRqRcD64A= -github.com/arnaucube/cryptofun v0.0.0-20181210231954-f5d913b6a74c h1:i0PwrCdHaQXw6KhbIS+VVj1x/GmqHgOs/LCXLeevE3c= -github.com/arnaucube/cryptofun v0.0.0-20181210231954-f5d913b6a74c/go.mod h1:jLYDEjM/9/Q/bpdj+9ZdKh2qDIgS2gqcywjg+93MyGI= -github.com/arnaucube/go-snark v0.0.0-20181207210027-19f7216d0e3d/go.mod h1:gLycS/B43DufBaH0jH8kqiE4A7w5FdOM8I9S416xh2Y= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=