|
|
@@ -110,9 +110,11 @@ def classify(sections):
|
|
|
|
|
|
def tokenize_const(text):
|
|
|
parser = lark.Lark(r"""
|
|
|
- value_map: NAME ":" type_def
|
|
|
+ value_map: name ":" type_def
|
|
|
|
|
|
- type_def: point
|
|
|
+ name: NAME
|
|
|
+
|
|
|
+ ?type_def: point
|
|
|
| blake2s_personalization
|
|
|
| pedersen_personalization
|
|
|
| list
|
|
|
@@ -131,13 +133,324 @@ def tokenize_const(text):
|
|
|
""", start="value_map")
|
|
|
return parser.parse(text)
|
|
|
|
|
|
+class ConstTransformer(lark.Transformer):
|
|
|
+ def name(self, name):
|
|
|
+ return str(name[0])
|
|
|
+
|
|
|
+ def point(self, _):
|
|
|
+ return "Point"
|
|
|
+ def blake2s_personalization(self, _):
|
|
|
+ return "Blake2sPersonalization"
|
|
|
+ def pedersen_personalization(self, _):
|
|
|
+ return "PedersenPersonalization"
|
|
|
+ value_map = tuple
|
|
|
+ list = list
|
|
|
+
|
|
|
def read_consts(consts):
|
|
|
+ consts_map = {}
|
|
|
+
|
|
|
for subsection in consts:
|
|
|
assert subsection[0].text == "const:"
|
|
|
|
|
|
for ldesc in subsection[1:]:
|
|
|
- tokens = tokenize_const(ldesc.text)
|
|
|
- print(tokens)
|
|
|
+ tree = tokenize_const(ldesc.text)
|
|
|
+ tokens = ConstTransformer().transform(tree)
|
|
|
+ #print(tokens)
|
|
|
+ name, typedesc = tokens
|
|
|
+ consts_map[name] = typedesc
|
|
|
+
|
|
|
+ #pprint.pprint(consts_map)
|
|
|
+ return consts_map
|
|
|
+
|
|
|
+class FuncDefTransformer(lark.Transformer):
|
|
|
+ def func_name(self, name):
|
|
|
+ return str(name[0])
|
|
|
+
|
|
|
+ def param(self, obj):
|
|
|
+ return tuple(obj)
|
|
|
+
|
|
|
+ def param_name(self, name):
|
|
|
+ return str(name[0])
|
|
|
+
|
|
|
+ def u64(self, _):
|
|
|
+ return "U64"
|
|
|
+ def scalar(self, _):
|
|
|
+ return "Scalar"
|
|
|
+ def point(self, _):
|
|
|
+ return "Point"
|
|
|
+ def binary(self, _):
|
|
|
+ return "Binary"
|
|
|
+
|
|
|
+ def type(self, obj):
|
|
|
+ return obj[0]
|
|
|
+
|
|
|
+ func_def = list
|
|
|
+ params = list
|
|
|
+ type_list = list
|
|
|
+
|
|
|
+def parse_func_def(text):
|
|
|
+ parser = lark.Lark(r"""
|
|
|
+ func_def: "def" func_name "(" params+ ")" "->" type_list ":"
|
|
|
+
|
|
|
+ func_name: NAME
|
|
|
+ params: param ("," param)*
|
|
|
+
|
|
|
+ type_list: type
|
|
|
+ | "(" type ("," type)* ")"
|
|
|
+
|
|
|
+ param: param_name ":" type
|
|
|
+ param_name: NAME
|
|
|
+
|
|
|
+ type: u64 | scalar | point | binary
|
|
|
+
|
|
|
+ u64: "U64"
|
|
|
+ scalar: "Scalar"
|
|
|
+ point: "Point"
|
|
|
+ binary: "Binary"
|
|
|
+
|
|
|
+ %import common.CNAME -> NAME
|
|
|
+ %import common.WS
|
|
|
+ %ignore WS
|
|
|
+ """, start="func_def")
|
|
|
+ tree = parser.parse(text)
|
|
|
+ tokens = FuncDefTransformer().transform(tree)
|
|
|
+ assert len(tokens) == 3
|
|
|
+ return tokens
|
|
|
+
|
|
|
+def interpret_func(func, consts):
|
|
|
+ func_def = parse_func_def(func[0].text)
|
|
|
+
|
|
|
+ func_name, params, retvals = func_def
|
|
|
+ #print("Function:", func_name)
|
|
|
+ #print("Params:", params)
|
|
|
+ #print("Return values:", retvals)
|
|
|
+ #print()
|
|
|
+
|
|
|
+ param_str = ""
|
|
|
+ for param, type in params:
|
|
|
+ if param_str:
|
|
|
+ param_str += ", "
|
|
|
+ param_str += param + ": "
|
|
|
+ if type == "U64":
|
|
|
+ param_str += "u64"
|
|
|
+ elif type == "Scalar":
|
|
|
+ param_str += "&jubjub::Fr"
|
|
|
+ else:
|
|
|
+ print("error: unsupported param type", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ converted_retvals = []
|
|
|
+ for type in retvals:
|
|
|
+ if type == "Binary":
|
|
|
+ converted_retvals.append("boolean::Boolean")
|
|
|
+ else:
|
|
|
+ print("error: unsupported return type", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+ retvals = converted_retvals
|
|
|
+
|
|
|
+ if len(retvals) == 1:
|
|
|
+ retstr = retvals[0]
|
|
|
+ else:
|
|
|
+ retstr = "(" + ", ".join(retvals) + ")"
|
|
|
+
|
|
|
+ subroutine = r"""
|
|
|
+fn %s<CS>(
|
|
|
+ mut cs: CS,
|
|
|
+ %s
|
|
|
+) -> Result<%s, SynthesisError>
|
|
|
+where
|
|
|
+ CS: ConstraintSystem<bls12_381::Scalar>,
|
|
|
+{
|
|
|
+""" % (func_name, param_str, retstr)
|
|
|
+
|
|
|
+ indent = " " * 4
|
|
|
+
|
|
|
+ stack = dict(params)
|
|
|
+ emitted_types = []
|
|
|
+ for line in func[1:]:
|
|
|
+ statement_type, statement = interpret_func_line(line.text, stack, consts)
|
|
|
+ if statement_type == "let":
|
|
|
+ is_mutable = False
|
|
|
+ if statement[0] == "mut":
|
|
|
+ is_mutable = True
|
|
|
+ statement = statement[1:]
|
|
|
+ variable_name, variable_type = statement[0], statement[1]
|
|
|
+ expr = statement[2]
|
|
|
+ #print("LET", is_mutable, variable_name, variable_type)
|
|
|
+ #print(" ", expr)
|
|
|
+ code = "let " + ("mut " if is_mutable else "") + variable_name + " = "
|
|
|
+
|
|
|
+ if expr.data == "as_expr":
|
|
|
+ var_from, type_to = expr.children
|
|
|
+ if var_from not in stack:
|
|
|
+ print("error: variable from not in stack frame:", var_from,
|
|
|
+ file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ type_from = stack[var_from]
|
|
|
+
|
|
|
+ if type_from == "U64" and type_to == "Binary":
|
|
|
+ code += "boolean::u64_into_boolean_vec_le(" + \
|
|
|
+ "cs.namespace(|| \"" + line.text + "\"), " + var_from + \
|
|
|
+ ")?;"
|
|
|
+ elif type_from == "Scalar" and type_to == "Binary":
|
|
|
+ code += "boolean::field_into_boolean_vec_le(" + \
|
|
|
+ "cs.namespace(|| \"" + line.text + "\"), &" + var_from + \
|
|
|
+ ")?;"
|
|
|
+ else:
|
|
|
+ print("error: unknown type conversion!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ #print(var_from, type_from, type_to)
|
|
|
+ stack[variable_name] = type_to
|
|
|
+
|
|
|
+ elif expr.data == "mul_expr":
|
|
|
+ var_a, var_b = expr.children
|
|
|
+ #print("MUL", var_a, var_b)
|
|
|
+
|
|
|
+ if var_b not in consts:
|
|
|
+ print("error: unknown base!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ base_type = consts[var_b]
|
|
|
+ if base_type != "Point":
|
|
|
+ print("error: unknown base type!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ code += "ecc::fixed_base_multiplication(" + \
|
|
|
+ "cs.namespace(|| \"" + line.text + "\"), &" + var_b + \
|
|
|
+ ", &" + var_a + ")?;"
|
|
|
+ stack[variable_name] = "Point"
|
|
|
+
|
|
|
+ elif expr.data == "add_expr":
|
|
|
+ var_a, var_b = expr.children
|
|
|
+
|
|
|
+ if var_a not in stack or var_b not in stack:
|
|
|
+ print("error: missing stack item!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ result_type = stack[var_a]
|
|
|
+ if stack[var_b] != result_type:
|
|
|
+ print("error: non matching items for addition!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ code += var_a + ".add(cs.namespace(|| \"" + line.text \
|
|
|
+ + "\"), &" + var_b + ")?;"
|
|
|
+ stack[variable_name] = result_type
|
|
|
+
|
|
|
+ subroutine += indent + code + "\n"
|
|
|
+
|
|
|
+ elif statement_type == "return":
|
|
|
+ for var in statement:
|
|
|
+ if var not in stack:
|
|
|
+ print("error: missing variable in stack!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ if len(statement) == 1:
|
|
|
+ code = "Ok(" + statement[0] + ")"
|
|
|
+ else:
|
|
|
+ code = "Ok(" + ",".join(statement) + ")"
|
|
|
+ subroutine += indent + code + "\n"
|
|
|
+
|
|
|
+ elif statement_type == "emit":
|
|
|
+ assert len(statement) == 1
|
|
|
+ variable = statement[0]
|
|
|
+ if variable not in stack:
|
|
|
+ print("error: missing variable in stack!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ variable_type = stack[variable]
|
|
|
+
|
|
|
+ if variable_type == "Point":
|
|
|
+ code = variable + ".inputize(cs.namespace(|| \"" + \
|
|
|
+ line.text + "\"))?;"
|
|
|
+ else:
|
|
|
+ print("error: unable to inputize type!", file=sys.stderr)
|
|
|
+ print("line:", line.text, "line:", line.lineno)
|
|
|
+ return None
|
|
|
+
|
|
|
+ emitted_types.append(variable_type)
|
|
|
+ subroutine += indent + code + "\n"
|
|
|
+
|
|
|
+ subroutine += "}"
|
|
|
+ print(subroutine)
|
|
|
+
|
|
|
+class CodeLineTransformer(lark.Transformer):
|
|
|
+ def variable_name(self, name):
|
|
|
+ return str(name[0])
|
|
|
+
|
|
|
+ def let_statement(self, obj):
|
|
|
+ return ("let", obj)
|
|
|
+ def return_statement(self, obj):
|
|
|
+ return ("return", obj)
|
|
|
+ def emit_statement(self, obj):
|
|
|
+ return ("emit", obj)
|
|
|
+
|
|
|
+ def point(self, _):
|
|
|
+ return "Point"
|
|
|
+ def scalar(self, _):
|
|
|
+ return "Scalar"
|
|
|
+ def binary(self, _):
|
|
|
+ return "Binary"
|
|
|
+ def u64(self, _):
|
|
|
+ return "U64"
|
|
|
+
|
|
|
+ def type(self, typename):
|
|
|
+ return str(typename[0])
|
|
|
+
|
|
|
+ def mutable(self, _):
|
|
|
+ return "mut"
|
|
|
+
|
|
|
+ statement = list
|
|
|
+
|
|
|
+def interpret_func_line(text, stack, consts):
|
|
|
+ parser = lark.Lark(r"""
|
|
|
+ statement: let_statement
|
|
|
+ | return_statement
|
|
|
+ | emit_statement
|
|
|
+
|
|
|
+ let_statement: "let" [mutable] variable_name ":" type "=" expr
|
|
|
+ mutable: "mut"
|
|
|
+
|
|
|
+ ?expr: as_expr
|
|
|
+ | mul_expr
|
|
|
+ | add_expr
|
|
|
+
|
|
|
+ as_expr: variable_name "as" type
|
|
|
+ mul_expr: variable_name "*" variable_name
|
|
|
+ add_expr: variable_name "+" variable_name
|
|
|
+
|
|
|
+ return_statement: "return" variable_name
|
|
|
+ | "return" variable_tuple
|
|
|
+ variable_tuple: "(" variable_name ("," variable_name)* ")"
|
|
|
+
|
|
|
+ emit_statement: "emit" variable_name
|
|
|
+
|
|
|
+ variable_name: NAME
|
|
|
+ type: u64 | scalar | point | binary
|
|
|
+
|
|
|
+ u64: "U64"
|
|
|
+ scalar: "Scalar"
|
|
|
+ point: "Point"
|
|
|
+ binary: "Binary"
|
|
|
+
|
|
|
+ %import common.CNAME -> NAME
|
|
|
+ %import common.WS
|
|
|
+ %ignore WS
|
|
|
+ """, start="statement")
|
|
|
+ tree = parser.parse(text)
|
|
|
+ tokens = CodeLineTransformer().transform(tree)[0]
|
|
|
+ return tokens
|
|
|
|
|
|
def main(argv):
|
|
|
if len(argv) == 1:
|
|
|
@@ -153,7 +466,10 @@ def main(argv):
|
|
|
|
|
|
consts, funcs, contracts = classify(sections)
|
|
|
|
|
|
- read_consts(consts)
|
|
|
+ consts = read_consts(consts)
|
|
|
+
|
|
|
+ for func in funcs:
|
|
|
+ interpret_func(func, consts)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
main(sys.argv)
|