Просмотр исходного кода

vm intermediate language generating rust file for testing. serialization required.

narodnik 5 лет назад
Родитель
Сommit
8c66b8b148
6 измененных файлов с 165 добавлено и 110 удалено
  1. 2 2
      Cargo.toml
  2. 4 0
      run_vmtest.sh
  3. 62 36
      scripts/vm.py
  4. 60 0
      scripts/vm_export_rust.py
  5. 16 72
      src/vm.rs
  6. 21 0
      src/vmtest.rs

+ 2 - 2
Cargo.toml

@@ -65,8 +65,8 @@ name = "basic"
 path = "src/basic_minimal.rs"
 
 [[bin]]
-name = "vm"
-path = "src/vm.rs"
+name = "vmtest"
+path = "src/vmtest.rs"
 
 [[bin]]
 name = "jubjub"

+ 4 - 0
run_vmtest.sh

@@ -0,0 +1,4 @@
+#!/bin/bash -x
+python scripts/vm.py --rust proofs/vm.pism > src/vm_load.rs
+cargo run --release --bin vmtest
+

+ 62 - 36
scripts/vm.py

@@ -1,3 +1,4 @@
+import argparse
 import sys
 from enum import Enum
 
@@ -220,38 +221,44 @@ def generate_constraints_table(contract, alloc):
         constraints.append(Constraint(line, indexes))
     return constraints
 
+class Contract:
+
+    def __init__(self, alloc, ops, constraints):
+        self.alloc = alloc
+        self.ops = ops
+        self.constraints = constraints
+
+    def __repr__(self):
+        repr_str = ""
+        repr_str += "Alloc table:\n"
+        for symbol, variable in self.alloc.items():
+            repr_str += "    // %s\n" % symbol
+            repr_str += "    %s %s\n" % (variable.type, variable.index)
+
+        repr_str += "Operations:\n"
+        for op in self.ops:
+            repr_str += "    // %s\n" % op.line
+            repr_str += "    %s %s\n" % (op.command, op.args)
+
+        repr_str += "Constraints:\n"
+        for constraint in self.constraints:
+            if constraint.args:
+                repr_str += "    // %s\n" % constraint.args_comment()
+            repr_str += "    %s %s\n" % (constraint.command, constraint.args)
+
+        return repr_str
+
 def compile(contract, constants):
     # Allocation table
     # symbol: Private/Public, is_param, index
     alloc = generate_alloc_table(contract)
     # Operations lines list
     if (ops := generate_ops_table(contract, alloc)) is None:
-        return False
+        return None
     # Constraint commands
     if (constraints := generate_constraints_table(contract, alloc)) is None:
-        return False
-    display(alloc, ops, constraints)
-    return True
-
-def display(alloc, ops, constraints):
-    print("Alloc table:")
-    for symbol, variable in alloc.items():
-        print("  //", symbol)
-        print(" ", variable.type, variable.index)
-    print()
-
-    print("Operations:")
-    for op in ops:
-        print("  //", op.line)
-        print(" ", op.command, op.args)
-    print()
-
-    print("Constraints:")
-    for constraint in constraints:
-        if constraint.args:
-            print("  //", constraint.args_comment())
-        print(" ", constraint.command, constraint.args)
-    print()
+        return None
+    return Contract(alloc, ops, constraints)
 
 def process(contents):
     # Remove left whitespace
@@ -259,24 +266,43 @@ def process(contents):
     # Parse all constants
     constants = [line for line in contents if line.command() == "constant"]
     # Divide into contract sections
-    if (contracts := divide_sections(contents)) is None:
-        return False
+    if (pre_contracts := divide_sections(contents)) is None:
+        return None
     # Process each contract
-    for contract_name, contract in contracts.items():
-        if not compile(contract, constants):
-            return False
-    return True
+    contracts = {}
+    for contract_name, pre_contract in pre_contracts.items():
+        if (contract := compile(pre_contract, constants)) is None:
+            return None
+        contracts[contract_name] = contract
+    return contracts
 
 def main(argv):
-    if len(argv) != 2:
-        eprint("pism FILENAME")
-        return -1
-
-    src_filename = argv[1]
+    parser = argparse.ArgumentParser()
+    parser.add_argument("filename")
+    group = parser.add_mutually_exclusive_group()
+    group.add_argument('--display', action='store_true')
+    group.add_argument('--rust', action='store_true')
+    args = parser.parse_args()
+
+    src_filename = args.filename
     contents = open(src_filename).read()
-    if not process(contents):
+    if (contracts := process(contents)) is None:
         return -2
 
+    def default_display():
+        for contract_name, contract in contracts.items():
+            print("Contract:", contract_name)
+            print(contract)
+
+    if args.display:
+        default_display()
+    elif args.rust:
+        import vm_export_rust
+        for contract_name, contract in contracts.items():
+            vm_export_rust.display(contract)
+    else:
+        default_display()
+
     return 0
 
 if __name__ == "__main__":

+ 60 - 0
scripts/vm_export_rust.py

@@ -0,0 +1,60 @@
+from vm import VariableType
+
+def to_initial_caps(snake_str):
+    components = snake_str.split("_")
+    return "".join(x.title() for x in components)
+
+def display(contract):
+    indent = " " * 4
+
+    print(r"""use super::vm::{ZKVirtualMachine, CryptoOperation, AllocType, ConstraintInstruction};
+
+pub fn load_zkvm() -> ZKVirtualMachine {
+    ZKVirtualMachine {
+        alloc: vec![""")
+
+    for symbol, variable in contract.alloc.items():
+        print("%s // %s" % (indent * 3, symbol))
+
+        if variable.type.name == VariableType.PRIVATE.name:
+            typestring = "Private"
+        elif variable.type.name == VariableType.PUBLIC.name:
+            typestring = "Public"
+        else:
+            assert False
+
+        print("%s(AllocType::%s, %s)," % (indent * 3, typestring,
+                                          variable.index))
+
+    print("%s]," % (indent * 2))
+    print("%sops: vec![" % (indent * 2))
+
+    for op in contract.ops:
+        print("%s// %s" % (indent * 3, op.line))
+        print("%sCryptoOperation::%s(%s)," % (
+            indent * 3,
+            to_initial_caps(op.command),
+            ", ".join(str(index) for index in op.args)
+        ))
+
+    print("%s]," % (indent * 2))
+    print("%sconstraints: vec![" % (indent * 2))
+
+    for constraint in contract.constraints:
+        args_part = ""
+        if constraint.args:
+            print("%s// %s" % (indent *3, constraint.args_comment()))
+            args_part = ", ".join(str(index) for index in constraint.args)
+            args_part = "(%s)" % args_part
+        print("%sConstraintInstruction::%s%s," % (
+            indent * 3,
+            to_initial_caps(constraint.command),
+            args_part
+        ))
+    print(r"""        ],
+        aux: vec![],
+        params: None,
+        verifying_key: None,
+    }
+}""")
+

+ 16 - 72
src/vm.rs

@@ -13,32 +13,30 @@ use rand::rngs::OsRng;
 use std::ops::{MulAssign, Neg, SubAssign};
 use std::time::Instant;
 
-pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
-
-struct ZKVirtualMachine {
-    ops: Vec<CryptoOperation>,
-    aux: Vec<Scalar>,
-    alloc: Vec<(AllocType, VariableIndex)>,
-    constraints: Vec<ConstraintInstruction>,
-    params: Option<groth16::Parameters<Bls12>>,
-    verifying_key: Option<groth16::PreparedVerifyingKey<Bls12>>,
+pub struct ZKVirtualMachine {
+    pub ops: Vec<CryptoOperation>,
+    pub aux: Vec<Scalar>,
+    pub alloc: Vec<(AllocType, VariableIndex)>,
+    pub constraints: Vec<ConstraintInstruction>,
+    pub params: Option<groth16::Parameters<Bls12>>,
+    pub verifying_key: Option<groth16::PreparedVerifyingKey<Bls12>>,
 }
 
 type VariableIndex = usize;
 
-enum CryptoOperation {
+pub enum CryptoOperation {
     Set(VariableIndex, VariableIndex),
     Mul(VariableIndex, VariableIndex),
 }
 
 #[derive(Clone)]
-enum AllocType {
+pub enum AllocType {
     Private,
     Public,
 }
 
 impl ZKVirtualMachine {
-    fn initialize(&mut self, params: &Vec<(VariableIndex, Scalar)>) {
+    pub fn initialize(&mut self, params: &Vec<(VariableIndex, Scalar)>) {
         // Resize array
         self.aux = vec![Scalar::zero(); self.alloc.len()];
 
@@ -69,7 +67,7 @@ impl ZKVirtualMachine {
         }
     }
 
-    fn public(&self) -> Vec<Scalar> {
+    pub fn public(&self) -> Vec<Scalar> {
         let mut publics = Vec::new();
         for (alloc_type, index) in &self.alloc {
             match alloc_type {
@@ -83,7 +81,7 @@ impl ZKVirtualMachine {
         publics
     }
 
-    fn setup(&mut self) {
+    pub fn setup(&mut self) {
         let start = Instant::now();
         // Create parameters for our circuit. In a production deployment these would
         // be generated securely using a multiparty computation.
@@ -103,7 +101,7 @@ impl ZKVirtualMachine {
         ))
     }
 
-    fn prove(&self) -> groth16::Proof<Bls12> {
+    pub fn prove(&self) -> groth16::Proof<Bls12> {
         let aux = self.aux.iter().map(|scalar| Some(scalar.clone())).collect();
         // Create an instance of our circuit (with the preimage as a witness).
         let circuit = ZKVMCircuit {
@@ -121,7 +119,7 @@ impl ZKVirtualMachine {
         proof
     }
 
-    fn verify(&self, proof: &groth16::Proof<Bls12>, public_values: &Vec<Scalar>) -> bool {
+    pub fn verify(&self, proof: &groth16::Proof<Bls12>, public_values: &Vec<Scalar>) -> bool {
         let start = Instant::now();
         let is_passed =
             groth16::verify_proof(self.verifying_key.as_ref().unwrap(), proof, public_values)
@@ -131,7 +129,7 @@ impl ZKVirtualMachine {
     }
 }
 
-struct ZKVMCircuit {
+pub struct ZKVMCircuit {
     aux: Vec<Option<bls12_381::Scalar>>,
     alloc: Vec<(AllocType, VariableIndex)>,
     constraints: Vec<ConstraintInstruction>,
@@ -201,7 +199,7 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
 }
 
 #[derive(Clone)]
-enum ConstraintInstruction {
+pub enum ConstraintInstruction {
     Lc0Add(VariableIndex),
     Lc1Add(VariableIndex),
     Lc2Add(VariableIndex),
@@ -211,57 +209,3 @@ enum ConstraintInstruction {
     Enforce,
 }
 
-fn main() {
-    let mut vm = ZKVirtualMachine {
-        ops: vec![
-            // x2 = x
-            CryptoOperation::Set(1, 0),
-            // x2 *= x
-            CryptoOperation::Mul(1, 0),
-            // x3 = x2
-            CryptoOperation::Set(2, 1),
-            // x3 *= x
-            CryptoOperation::Mul(2, 0),
-            // input = x3
-            CryptoOperation::Set(3, 2),
-        ],
-        aux: vec![],
-        alloc: vec![
-            (AllocType::Private, 0),
-            (AllocType::Private, 1),
-            (AllocType::Private, 2),
-            (AllocType::Public, 3),
-        ],
-        constraints: vec![
-            // x * x = x2
-            ConstraintInstruction::Lc0Add(0),
-            ConstraintInstruction::Lc1Add(0),
-            ConstraintInstruction::Lc2Add(1),
-            ConstraintInstruction::Enforce,
-            // x2 * x = x3
-            ConstraintInstruction::Lc0Add(1),
-            ConstraintInstruction::Lc1Add(0),
-            ConstraintInstruction::Lc2Add(2),
-            ConstraintInstruction::Enforce,
-            // x3 * 1 = public_x3
-            ConstraintInstruction::Lc0Add(2),
-            ConstraintInstruction::Lc1AddOne,
-            ConstraintInstruction::Lc2Add(3),
-            ConstraintInstruction::Enforce,
-        ],
-        params: None,
-        verifying_key: None,
-    };
-
-    vm.setup();
-
-    let params = vec![
-        (0, Scalar::from(3))
-    ];
-    vm.initialize(&params);
-
-    let proof = vm.prove();
-
-    let public = vm.public();
-    assert!(vm.verify(&proof, &public));
-}

+ 21 - 0
src/vmtest.rs

@@ -0,0 +1,21 @@
+use bls12_381::Scalar;
+
+mod vm;
+mod vm_load;
+use vm_load::load_zkvm;
+
+fn main() {
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let params = vec![
+        (0, Scalar::from(3))
+    ];
+    vm.initialize(&params);
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+    assert!(vm.verify(&proof, &public));
+}