@ -0,0 +1,10 @@ |
|||||
|
package circuitcompiler |
||||
|
|
||||
|
type Circuit struct { |
||||
|
NVars int |
||||
|
NPublic int |
||||
|
NSignals int |
||||
|
Inputs []int |
||||
|
Witness []int |
||||
|
Constraints []Constraint |
||||
|
} |
@ -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
|
||||
|
} |
@ -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() |
||||
|
} |
@ -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 |
||||
|
} |
@ -1,7 +0,0 @@ |
|||||
package compiler |
|
||||
|
|
||||
type Circuit struct { |
|
||||
NVars int |
|
||||
NPublic int |
|
||||
NSignals int |
|
||||
} |
|
@ -1,9 +1,8 @@ |
|||||
module github.com/arnaucube/go-snark |
module github.com/arnaucube/go-snark |
||||
|
|
||||
require ( |
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 |
github.com/stretchr/testify v1.2.2 |
||||
) |
) |
@ -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-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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= |
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= |
||||
|