arnaucube
arnaucube/go-snarkPublic Self-hosted repository
starting circuitcompiler, lexer and parser (simple version)
arnaucube arnaucube@gmail.com
Mon, 24 Dec 2018 16:53:38 +0100
commit

d42dffff22e48b2428769d4922afbfbcc78692fd

parent

f555ae4b18988b7a00fe44135252c6b387c6d1bd

M README.md → README.md

@@ -12,6 +12,7 @@ - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark

- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128) - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields operations - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap) +- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler) Circuit Compiler Example: ```go
A circuitcompiler/circuit.go

@@ -0,0 +1,10 @@

+package circuitcompiler + +type Circuit struct { + NVars int + NPublic int + NSignals int + Inputs []int + Witness []int + Constraints []Constraint +}
A circuitcompiler/circuit_test.go

@@ -0,0 +1,36 @@

+package circuitcompiler + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCircuitParser(t *testing.T) { + /* + input: + def test(): + y = x**3 + return x + y + 5 + + flattened: + m1 = s1 * s1 + m2 = m1 * s1 + m3 = m2 + s1 + out = m3 + 5 + */ + raw := ` + y = x^x + z = x + y + out = z + 5 + ` + parser := NewParser(strings.NewReader(raw)) + res, err := parser.Parse() + assert.Nil(t, err) + fmt.Println(res) + + // flat code + // flat code to R1CS +}
A circuitcompiler/lexer.go

@@ -0,0 +1,144 @@

+package circuitcompiler + +import ( + "bufio" + "bytes" + "io" +) + +type OperatorSymbol int +type Token int + +const ( + ILLEGAL Token = iota + WS + EOF + + IDENT // val + + VAR // var + CONST // const value + + EQ // = + PLUS // + + MINUS // - + MULTIPLY // * + DIVIDE // / + EXP // ^ + + OUT +) + +var eof = rune(0) + +func isWhitespace(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\n' +} + +func isLetter(ch rune) bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') +} +func isDigit(ch rune) bool { + return (ch >= '0' && ch <= '9') +} + +type Scanner struct { + r *bufio.Reader +} + +func NewScanner(r io.Reader) *Scanner { + return &Scanner{r: bufio.NewReader(r)} +} + +func (s *Scanner) read() rune { + ch, _, err := s.r.ReadRune() + if err != nil { + return eof + } + return ch +} + +func (s *Scanner) unread() { + _ = s.r.UnreadRune() +} + +func (s *Scanner) Scan() (tok Token, lit string) { + ch := s.read() + + if isWhitespace(ch) { + // space + s.unread() + return s.scanWhitespace() + } else if isLetter(ch) { + // letter + s.unread() + return s.scanIndent() + } else if isDigit(ch) { + s.unread() + return s.scanIndent() + } + + switch ch { + case eof: + return EOF, "" + case '=': + return EQ, "=" + case '+': + return PLUS, "+" + case '-': + return MINUS, "-" + case '*': + return MULTIPLY, "*" + case '/': + return DIVIDE, "/" + case '^': + return EXP, "^" + } + + return ILLEGAL, string(ch) +} + +func (s *Scanner) scanWhitespace() (token Token, lit string) { + var buf bytes.Buffer + buf.WriteRune(s.read()) + + for { + if ch := s.read(); ch == eof { + break + } else if !isWhitespace(ch) { + s.unread() + break + } else { + _, _ = buf.WriteRune(ch) + } + } + return WS, buf.String() +} + +func (s *Scanner) scanIndent() (tok Token, lit string) { + var buf bytes.Buffer + buf.WriteRune(s.read()) + + for { + if ch := s.read(); ch == eof { + break + } else if !isLetter(ch) && !isDigit(ch) { + s.unread() + break + } else { + _, _ = buf.WriteRune(ch) + } + } + switch buf.String() { + case "var": + return VAR, buf.String() + } + + if len(buf.String()) == 1 { + return Token(rune(buf.String()[0])), buf.String() + } + if buf.String() == "out" { + return OUT, buf.String() + } + return IDENT, buf.String() +}
A circuitcompiler/parser.go

@@ -0,0 +1,92 @@

+package circuitcompiler + +import ( + "errors" + "io" +) + +type Parser struct { + s *Scanner + buf struct { + tok Token // last read token + lit string // last read literal + n int // buffer size (max=1) + } +} + +type Constraint struct { + // v1 op v2 = out + Op Token + V1 Token + V2 Token + Out Token + Literal string +} + +func NewParser(r io.Reader) *Parser { + return &Parser{s: NewScanner(r)} +} + +func (p *Parser) scan() (tok Token, lit string) { + // if there is a token in the buffer return it + if p.buf.n != 0 { + p.buf.n = 0 + return p.buf.tok, p.buf.lit + } + tok, lit = p.s.Scan() + + p.buf.tok, p.buf.lit = tok, lit + + return +} + +func (p *Parser) unscan() { + p.buf.n = 1 +} + +func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) { + tok, lit = p.scan() + if tok == WS { + tok, lit = p.scan() + } + return +} + +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 + */ + c := &Constraint{} + var lit string + c.Out, lit = p.scanIgnoreWhitespace() + c.Literal += lit + _, lit = p.scanIgnoreWhitespace() // skip = + c.Literal += lit + c.V1, lit = p.scanIgnoreWhitespace() + c.Literal += lit + c.Op, lit = p.scanIgnoreWhitespace() + c.Literal += lit + c.V2, lit = p.scanIgnoreWhitespace() + c.Literal += lit + if c.Out == EOF { + return nil, errors.New("eof in parseline") + } + return c, nil +} + +func (p *Parser) Parse() (*Circuit, error) { + circuit := &Circuit{} + for { + constraint, err := p.ParseLine() + if err != nil { + // return circuit, err + break + } + circuit.Constraints = append(circuit.Constraints, *constraint) + } + return circuit, nil +}
D compiler/circuit.go

@@ -1,7 +0,0 @@

-package compiler - -type Circuit struct { - NVars int - NPublic int - NSignals int -}
M go.mod → go.mod

@@ -1,9 +1,8 @@

module github.com/arnaucube/go-snark require ( - github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd - github.com/fatih/color v1.7.0 - github.com/mattn/go-colorable v0.0.9 // indirect - github.com/mattn/go-isatty v0.0.4 // indirect + 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 )
M go.sum → go.sum

@@ -1,13 +1,11 @@

-github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd h1:NDpNBTFeHNE2IHya+msmKlCzIPGzn8qN3Z2jtegFYT0= +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/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
M snark.go → snark.go

@@ -6,7 +6,7 @@ "math/big"

"os" "github.com/arnaucube/go-snark/bn128" - "github.com/arnaucube/go-snark/compiler" + "github.com/arnaucube/go-snark/circuitcompiler" "github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/r1csqap" )

@@ -60,7 +60,7 @@ PiKp [3]*big.Int

PublicSignals []*big.Int } -func GenerateTrustedSetup(bn bn128.Bn128, fqR fields.Fq, pf r1csqap.PolynomialField, witnessLength int, circuit compiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) { +func GenerateTrustedSetup(bn bn128.Bn128, fqR fields.Fq, pf r1csqap.PolynomialField, witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) { var setup Setup var err error // generate random t value

@@ -98,7 +98,7 @@ setup.Toxic.RhoA, err = fqR.Rand()

if err != nil { return Setup{}, err } - setup.Toxic.RhoB, err = fqR.Rand() + setup.Toxic.RhoB, err = fqR.Rand() if err != nil { return Setup{}, err }

@@ -172,7 +172,7 @@

return setup, nil } -func GenerateProofs(bn bn128.Bn128, f fields.Fq, circuit compiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) { +func GenerateProofs(bn bn128.Bn128, f fields.Fq, circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) { var proof Proof proof.PiA = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiAp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()}

@@ -206,7 +206,7 @@

return proof, nil } -func VerifyProof(bn bn128.Bn128, circuit compiler.Circuit, setup Setup, proof Proof) bool { +func VerifyProof(bn bn128.Bn128, circuit circuitcompiler.Circuit, setup Setup, proof Proof) bool { // e(piA, Va) == e(piA', g2) pairingPiaVa := bn.Pairing(proof.PiA, setup.Vk.Vka)

@@ -262,7 +262,7 @@ pairingR := bn.Pairing(proof.PiKp, setup.Vk.G2Kg)

if !bn.Fq12.Equal(pairingL, pairingR) { return false } else { - fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") + fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)") } return true
M snark_test.go → snark_test.go

@@ -6,7 +6,7 @@ "math/big"

"testing" "github.com/arnaucube/go-snark/bn128" - "github.com/arnaucube/go-snark/compiler" + "github.com/arnaucube/go-snark/circuitcompiler" "github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/r1csqap" "github.com/stretchr/testify/assert"

@@ -52,7 +52,7 @@ alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c)

// wittness = 1, 3, 35, 9, 27, 30 w := []*big.Int{b1, b3, b35, b9, b27, b30} - circuit := compiler.Circuit{ + circuit := circuitcompiler.Circuit{ NVars: 6, NPublic: 0, NSignals: len(w),

@@ -69,7 +69,7 @@ abc := pf.Sub(pf.Mul(ax, bx), cx)

assert.Equal(t, abc, px) hz := pf.Mul(hx, zx) assert.Equal(t, abc, hz) - + div, rem := pf.Div(px, zx) assert.Equal(t, hx, div) assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))