arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/circuitcompiler/parser.go
circuitcompiler/parser.goRaw
  1package circuitcompiler
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"io"
  7	"os"
  8	"regexp"
  9	"strings"
 10)
 11
 12// Parser data structure holds the Scanner and the Parsing functions
 13type Parser struct {
 14	s   *Scanner
 15	buf struct {
 16		tok Token  // last read token
 17		lit string // last read literal
 18		n   int    // buffer size (max=1)
 19	}
 20}
 21
 22// NewParser creates a new parser from a io.Reader
 23func NewParser(r io.Reader) *Parser {
 24	return &Parser{s: NewScanner(r)}
 25}
 26
 27func (p *Parser) scan() (tok Token, lit string) {
 28	// if there is a token in the buffer return it
 29	if p.buf.n != 0 {
 30		p.buf.n = 0
 31		return p.buf.tok, p.buf.lit
 32	}
 33	tok, lit = p.s.scan()
 34
 35	p.buf.tok, p.buf.lit = tok, lit
 36
 37	return
 38}
 39
 40func (p *Parser) unscan() {
 41	p.buf.n = 1
 42}
 43
 44func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
 45	tok, lit = p.scan()
 46	if tok == WS {
 47		tok, lit = p.scan()
 48	}
 49	return
 50}
 51
 52// parseLine parses the current line
 53func (p *Parser) parseLine() (*Constraint, error) {
 54	/*
 55		in this version,
 56		line will be for example s3 = s1 * s4
 57		this is:
 58		val eq val op val
 59	*/
 60	c := &Constraint{}
 61	tok, lit := p.scanIgnoreWhitespace()
 62	c.Out = lit
 63	c.Literal += lit
 64
 65	if c.Literal == "func" {
 66		// format: `func name(in):`
 67		line, err := p.s.r.ReadString(':')
 68		if err != nil {
 69			return c, err
 70		}
 71		// read string inside ( )
 72		rgx := regexp.MustCompile(`\((.*?)\)`)
 73		insideParenthesis := rgx.FindStringSubmatch(line)
 74		varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
 75		allInputs := strings.Split(varsString, ",")
 76
 77		// from allInputs, get the private and the public separated
 78		for _, in := range allInputs {
 79			if strings.Contains(in, "private") {
 80				input := strings.Replace(in, "private", "", -1)
 81				c.PrivateInputs = append(c.PrivateInputs, input)
 82			} else if strings.Contains(in, "public") {
 83				input := strings.Replace(in, "public", "", -1)
 84				c.PublicInputs = append(c.PublicInputs, input)
 85			} else {
 86				// TODO give more info about the circuit code error
 87				fmt.Println("error on declaration of public and private inputs")
 88				os.Exit(0)
 89			}
 90		}
 91		return c, nil
 92	}
 93	if c.Literal == "equals" {
 94		// format: `equals(a, b)`
 95		line, err := p.s.r.ReadString(')')
 96		if err != nil {
 97			return c, err
 98		}
 99		// read string inside ( )
100		rgx := regexp.MustCompile(`\((.*?)\)`)
101		insideParenthesis := rgx.FindStringSubmatch(line)
102		varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
103		params := strings.Split(varsString, ",")
104		fmt.Println("params", params)
105		// TODO
106		c.V1 = params[0]
107		c.V2 = params[1]
108		return c, nil
109	}
110	// if c.Literal == "out" {
111	//         // TODO
112	//         return c, nil
113	// }
114
115	_, lit = p.scanIgnoreWhitespace() // skip =
116	c.Literal += lit
117
118	// v1
119	_, lit = p.scanIgnoreWhitespace()
120	c.V1 = lit
121	c.Literal += lit
122	// operator
123	_, lit = p.scanIgnoreWhitespace()
124	c.Op = lit
125	c.Literal += lit
126	// v2
127	_, lit = p.scanIgnoreWhitespace()
128	c.V2 = lit
129	c.Literal += lit
130	if tok == EOF {
131		return nil, errors.New("eof in parseline")
132	}
133	return c, nil
134}
135
136func existInArray(arr []string, elem string) bool {
137	for _, v := range arr {
138		if v == elem {
139			return true
140		}
141	}
142	return false
143}
144
145func addToArrayIfNotExist(arr []string, elem string) []string {
146	for _, v := range arr {
147		if v == elem {
148			return arr
149		}
150	}
151	arr = append(arr, elem)
152	return arr
153}
154
155// Parse parses the lines and returns the compiled Circuit
156func (p *Parser) Parse() (*Circuit, error) {
157	circuit := &Circuit{}
158	circuit.Signals = append(circuit.Signals, "one")
159	nInputs := 0
160	for {
161		constraint, err := p.parseLine()
162		if err != nil {
163			break
164		}
165		fmt.Println(constraint)
166		if constraint.Literal == "func" {
167			// one constraint for each input
168			for _, in := range constraint.PublicInputs {
169				newConstr := &Constraint{
170					Op:  "in",
171					Out: in,
172				}
173				circuit.Constraints = append(circuit.Constraints, *newConstr)
174				nInputs++
175				circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
176				circuit.NPublic++
177			}
178			for _, in := range constraint.PrivateInputs {
179				newConstr := &Constraint{
180					Op:  "in",
181					Out: in,
182				}
183				circuit.Constraints = append(circuit.Constraints, *newConstr)
184				nInputs++
185				circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
186			}
187			circuit.PublicInputs = constraint.PublicInputs
188			circuit.PrivateInputs = constraint.PrivateInputs
189			continue
190		}
191		if constraint.Literal == "equals" {
192			// TODO
193			fmt.Println("circuit.Signals", circuit.Signals)
194			constr1 := &Constraint{
195				Op:      "*",
196				V1:      constraint.V2,
197				V2:      "1",
198				Out:     constraint.V1,
199				Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
200			}
201			circuit.Constraints = append(circuit.Constraints, *constr1)
202			constr2 := &Constraint{
203				Op:      "*",
204				V1:      constraint.V1,
205				V2:      "1",
206				Out:     constraint.V2,
207				Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
208			}
209			circuit.Constraints = append(circuit.Constraints, *constr2)
210			continue
211		}
212		circuit.Constraints = append(circuit.Constraints, *constraint)
213		isVal, _ := isValue(constraint.V1)
214		if !isVal {
215			circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
216		}
217		isVal, _ = isValue(constraint.V2)
218		if !isVal {
219			circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
220		}
221
222		// if constraint.Out == "out" {
223		// if Out is "out", put it after first value (one) and before the inputs
224		// if constraint.Out == circuit.PublicInputs[0] {
225		// if existInArray(circuit.PublicInputs, constraint.Out) {
226		//         // if Out is a public signal, put it after first value (one) and before the private inputs
227		//         if !existInArray(circuit.Signals, constraint.Out) {
228		//                 // if already don't exists in signal array
229		//                 signalsCopy := copyArray(circuit.Signals)
230		//                 var auxSignals []string
231		//                 auxSignals = append(auxSignals, signalsCopy[0])
232		//                 auxSignals = append(auxSignals, constraint.Out)
233		//                 auxSignals = append(auxSignals, signalsCopy[1:]...)
234		//                 circuit.Signals = auxSignals
235		//                 // circuit.PublicInputs = append(circuit.PublicInputs, constraint.Out)
236		//                 circuit.NPublic++
237		//         }
238		// } else {
239		circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
240		// }
241	}
242	circuit.NVars = len(circuit.Signals)
243	circuit.NSignals = len(circuit.Signals)
244	return circuit, nil
245}
246func copyArray(in []string) []string { // tmp
247	var out []string
248	for _, e := range in {
249		out = append(out, e)
250	}
251	return out
252}