Jelajahi Sumber

working point addition

narodnik 5 tahun lalu
induk
melakukan
90c255aa0b
7 mengubah file dengan 377 tambahan dan 50 penghapusan
  1. 88 0
      proofs/jubjub.pism
  2. 2 1
      run_vmtest.sh
  3. 99 24
      scripts/vm.py
  4. 34 4
      scripts/vm_export_rust.py
  5. 16 1
      src/jubjub.rs
  6. 102 19
      src/vm.rs
  7. 36 1
      src/vmtest.rs

+ 88 - 0
proofs/jubjub.pism

@@ -0,0 +1,88 @@
+constant a 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000
+constant d 0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1
+constant one 0x0000000000000000000000000000000000000000000000000000000000000001
+
+{% macro jubjub_add(prefix, x1, y1, x2, y2) -%}
+    # Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)
+    #           = (x1 + y1) * (x2 + y2)
+    private {{prefix}}_U
+    set {{prefix}}_U {{ x1 }}
+    add {{prefix}}_U {{ y1 }}
+    local {{prefix}}_tmp
+    set {{prefix}}_tmp {{ x2 }}
+    add {{prefix}}_tmp {{ y2 }}
+    mul {{prefix}}_U {{prefix}}_tmp
+
+    # assert (x1 + y1) * (x2 + y2) == U
+    lc0_add {{ x1 }}
+    lc0_add {{ y1 }}
+    lc1_add {{ x2 }}
+    lc1_add {{ y2 }}
+    lc2_add {{prefix}}_U
+    enforce
+
+    # Compute A = y2 * x1
+    private {{prefix}}_A
+    set {{prefix}}_A {{ y2 }}
+    mul {{prefix}}_A {{ x1 }}
+    # Compute B = x2 * y1
+    private {{prefix}}_B
+    set {{prefix}}_B {{ x2 }}
+    mul {{prefix}}_B {{ y1 }}
+    # Compute C = d*A*B
+    private {{prefix}}_C
+    load {{prefix}}_C d
+    mul {{prefix}}_C {{prefix}}_A
+    mul {{prefix}}_C {{prefix}}_B
+
+    # assert (d * A) * (B) == C
+    lc0_add_coeff d {{prefix}}_A
+    lc1_add {{prefix}}_B
+    lc2_add {{prefix}}_C
+    enforce
+
+    # Compute u3 = (A + B) / (1 + C)
+    private {{prefix}}_u3
+    set {{prefix}}_u3 {{prefix}}_A
+    add {{prefix}}_u3 {{prefix}}_B
+    local {{prefix}}_u3_denom
+    load {{prefix}}_u3_denom one
+    add {{prefix}}_u3_denom {{prefix}}_C
+    divide {{prefix}}_u3 {{prefix}}_u3_denom
+
+    lc0_add_one
+    lc0_add {{prefix}}_C
+    lc1_add {{prefix}}_u3
+    lc2_add {{prefix}}_A
+    lc2_add {{prefix}}_B
+    enforce
+
+    # Compute v3 = (U - A - B) / (1 - C)
+    private {{prefix}}_v3
+    set {{prefix}}_v3 {{prefix}}_U
+    sub {{prefix}}_v3 {{prefix}}_A
+    sub {{prefix}}_v3 {{prefix}}_B
+    local {{prefix}}_v3_denom
+    load {{prefix}}_v3_denom one
+    sub {{prefix}}_v3_denom {{prefix}}_C
+    divide {{prefix}}_v3 {{prefix}}_v3_denom
+
+    lc0_add_one
+    lc0_sub {{prefix}}_C
+    lc1_add {{prefix}}_v3
+    lc2_add {{prefix}}_U
+    lc2_sub {{prefix}}_A
+    lc2_sub {{prefix}}_B
+    enforce
+{%- endmacro %}
+
+contract input_spend
+    param x1
+    param y1
+
+    param x2
+    param y2
+
+    {{ jubjub_add("P", "x1", "y1", "x2", "y2") }}
+end
+

+ 2 - 1
run_vmtest.sh

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

+ 99 - 24
scripts/vm.py

@@ -11,6 +11,10 @@ alloc_commands = {
 op_commands = {
     "set": 2,
     "mul": 2,
+    "add": 2, 
+    "sub": 2,
+    "divide": 2,
+    "load": 2,
     "local": 1,
 }
 
@@ -18,9 +22,15 @@ constraint_commands = {
     "lc0_add": 1,
     "lc1_add": 1,
     "lc2_add": 1,
+    "lc0_sub": 1,
+    "lc1_sub": 1,
+    "lc2_sub": 1,
     "lc0_add_one": 0,
     "lc1_add_one": 0,
     "lc2_add_one": 0,
+    "lc0_add_coeff": 2,
+    "lc1_add_coeff": 2,
+    "lc2_add_coeff": 2,
     "enforce": 0,
 }
 
@@ -172,6 +182,11 @@ def generate_alloc_table(contract):
         else:
             assert False
 
+        if symbol in alloc_table:
+            eprint("error: duplicate symbol '%s'" % symbol)
+            eprint(line)
+            return None
+
         alloc_table[symbol] = Variable(symbol, i, type, is_param)
 
     return alloc_table
@@ -186,6 +201,7 @@ class Operation:
 class VariableRefType(Enum):
     AUX = 1
     LOCAL = 2
+    CONST = 3
 
 class VariableRef:
 
@@ -196,7 +212,7 @@ class VariableRef:
     def __repr__(self):
         return "%s(%s)" % (self.type.name, self.index)
 
-def symbols_list_to_refs(line, alloc, local_vars):
+def symbols_list_to_refs(line, alloc, local_vars, constants):
     indexes = []
     for symbol in line.args():
         if symbol in alloc:
@@ -206,14 +222,17 @@ def symbols_list_to_refs(line, alloc, local_vars):
         elif symbol in local_vars:
             index = local_vars[symbol]
             index = VariableRef(VariableRefType.LOCAL, index)
+        elif symbol in constants:
+            index = constants[symbol][0]
+            index = VariableRef(VariableRefType.CONST, index)
         else:
-            eprint("error: missing unallocated symbol")
+            eprint("error: missing unallocated symbol '%s'" % symbol)
             eprint(line)
             return None
         indexes.append(index)
     return indexes
 
-def generate_ops_table(contract, alloc):
+def generate_ops_table(contract, alloc, constants):
     relevant_lines = extract_relevant_lines(contract, op_commands)
     ops = []
     local_vars = {}
@@ -226,7 +245,21 @@ def generate_ops_table(contract, alloc):
             indexes = []
         else:
             if (indexes := symbols_list_to_refs(line, alloc, 
-                                                local_vars)) is None:
+                                                local_vars, constants)) is None:
+                return None
+
+            # Handle this here directly since only the
+            # load command deals with constants
+            if line.command() == "load":
+                assert len(indexes) == 2
+                # This is the only command which uses consts
+                if indexes[1].type != VariableRefType.CONST:
+                    eprint("error: load command takes a const argument")
+                    eprint(line)
+                    return None
+            elif any(index.type == VariableRefType.CONST for index in indexes):
+                eprint("error: invalid const arg")
+                eprint(line)
                 return None
 
         ops.append(Operation(line, indexes))
@@ -234,45 +267,55 @@ def generate_ops_table(contract, alloc):
 
 class Constraint:
 
-    def __init__(self, line, indexes):
+    def __init__(self, line, lcargs):
         self.command = line.command()
-        self.args = indexes
+        self.args = lcargs
         self.line = line
 
     def args_comment(self):
         return ", ".join("%s" % symbol for symbol in self.line.args())
 
-def symbols_list_to_indexes(line, alloc):
-    indexes = []
+def symbols_list_to_lcargs(line, alloc, constants):
+    lcargs = []
     for symbol in line.args():
-        if symbol not in alloc:
-            eprint("error: missing unallocated symbol")
+        if symbol in alloc:
+            # Lookup variable index
+            index = alloc[symbol].index
+            lcargs.append(index)
+        elif symbol in constants:
+            value = constants[symbol]
+            lcargs.append(value)
+        else:
+            eprint("error: missing unallocated symbol '%s'" % symbol)
             eprint(line)
             return None
+    return lcargs
 
-        # Lookup variable index
-        index = alloc[symbol].index
-        indexes.append(index)
-    return indexes
-
-def generate_constraints_table(contract, alloc):
+def generate_constraints_table(contract, alloc, constants):
     relevant_lines = extract_relevant_lines(contract, constraint_commands)
     constraints = []
     for line in relevant_lines:
-        if (indexes := symbols_list_to_indexes(line, alloc)) is None:
+        if (lcargs := symbols_list_to_lcargs(line, alloc, constants)) is None:
             return None
-        constraints.append(Constraint(line, indexes))
+        constraints.append(Constraint(line, lcargs))
     return constraints
 
 class Contract:
 
-    def __init__(self, alloc, ops, constraints):
+    def __init__(self, constants, alloc, ops, constraints):
+        self.constants = constants
         self.alloc = alloc
         self.ops = ops
         self.constraints = constraints
 
     def __repr__(self):
         repr_str = ""
+
+        repr_str += "Constants:\n"
+        for symbol, value in self.constants.items():
+            repr_str += "    // %s\n" % symbol
+            repr_str += "    %s: %s\n" % value
+
         repr_str += "Alloc table:\n"
         for symbol, variable in self.alloc.items():
             repr_str += "    // %s\n" % symbol
@@ -294,20 +337,52 @@ class Contract:
 def compile(contract, constants):
     # Allocation table
     # symbol: Private/Public, is_param, index
-    alloc = generate_alloc_table(contract)
+    if (alloc := generate_alloc_table(contract)) is None:
+        return None
     # Operations lines list
-    if (ops := generate_ops_table(contract, alloc)) is None:
+    if (ops := generate_ops_table(contract, alloc, constants)) is None:
         return None
     # Constraint commands
-    if (constraints := generate_constraints_table(contract, alloc)) is None:
+    if (constraints := generate_constraints_table(
+            contract, alloc, constants)) is None:
         return None
-    return Contract(alloc, ops, constraints)
+    return Contract(constants, alloc, ops, constraints)
+
+def parse_constants(contents):
+    relevant_lines = [line for line in contents if line.command() == "constant"]
+    constants = {}
+    for line in relevant_lines:
+        assert line.command() == "constant"
+        if len(line.args()) != 2:
+            eprint("error: wrong number of args for constant")
+            eprint(line)
+            return None
+        symbol, value = line.args()
+
+        try:
+            int(value, 16)
+        except ValueError:
+            eprint("error: invalid constant value for '%s'" % symbol)
+            eprint(line)
+            return None
+
+        if len(value) != 32*2 + 2 or value[:2] != "0x":
+            eprint("error: invalid hex value for constant")
+            eprint(line)
+            return None
+
+        # Remove 0x prefix
+        value = value[2:]
+
+        constants[symbol] = (len(constants), value)
+    return constants
 
 def process(contents):
     # Remove left whitespace
     contents = clean(contents)
     # Parse all constants
-    constants = [line for line in contents if line.command() == "constant"]
+    if (constants := parse_constants(contents)) is None:
+        return None
     # Divide into contract sections
     if (pre_contracts := divide_sections(contents)) is None:
         return None

+ 34 - 4
scripts/vm_export_rust.py

@@ -8,13 +8,35 @@ def display(contract):
     indent = " " * 4
 
     print(r"""use super::vm::{ZKVirtualMachine, CryptoOperation, AllocType, ConstraintInstruction, VariableRef};
+use bls12_381::Scalar;
 
 pub fn load_zkvm() -> ZKVirtualMachine {
     ZKVirtualMachine {
-        alloc: vec![""")
+        constants: vec![""")
+
+    constants = list(contract.constants.items())
+    constants.sort(key=lambda obj: obj[1][0])
+    constants = [(obj[0], obj[1][1]) for obj in constants]
+    for symbol, value in constants:
+        print("%s// %s" % (indent * 3, symbol))
+        assert len(value) == 32*2
+        chunk_str = lambda line, n: \
+            [line[i:i + n] for i in range(0, len(line), n)]
+        chunks = chunk_str(value, 2)
+        # Reverse the endianness
+        # We allow literal numbers but rust wants little endian
+        chunks = chunks[::-1]
+        print("%sScalar::from_bytes(&[" % (indent * 3))
+        for i in range(0, 32, 4):
+            print("%s0x%s, 0x%s, 0x%s, 0x%s," % (indent * 4,
+                chunks[i], chunks[i + 1], chunks[i + 2], chunks[i + 3]))
+        print("%s]).unwrap()," % (indent * 3))
+
+    print("%s]," % (indent * 2))
+    print("%salloc: vec![" % (indent * 2))
 
     for symbol, variable in contract.alloc.items():
-        print("%s // %s" % (indent * 3, symbol))
+        print("%s// %s" % (indent * 3, symbol))
 
         if variable.type.name == VariableType.PRIVATE.name:
             typestring = "Private"
@@ -40,7 +62,10 @@ pub fn load_zkvm() -> ZKVirtualMachine {
     for op in contract.ops:
         print("%s// %s" % (indent * 3, op.line))
         args_part = ""
-        if op.args:
+        if op.command == "load":
+            assert len(op.args) == 2
+            args_part = "(%s, %s)" % (var_ref_str(op.args[0]), op.args[1].index)
+        elif op.args:
             args_part = ", ".join(var_ref_str(var_ref) for var_ref in op.args)
             args_part = "(%s)" % args_part
         print("%sCryptoOperation::%s%s," % (
@@ -56,7 +81,12 @@ pub fn load_zkvm() -> ZKVirtualMachine {
         args_part = ""
         if constraint.args:
             print("%s// %s" % (indent *3, constraint.args_comment()))
-            args_part = ", ".join(str(index) for index in constraint.args)
+            args = constraint.args[:]
+            if (constraint.command == "lc0_add_coeff" or
+                constraint.command == "lc1_add_coeff" or
+                constraint.command == "lc2_add_coeff"):
+                args[0] = args[0][0]
+            args_part = ", ".join(str(index) for index in args)
             args_part = "(%s)" % args_part
         print("%sConstraintInstruction::%s%s," % (
             indent * 3,

+ 16 - 1
src/jubjub.rs

@@ -1,6 +1,7 @@
 use ff::PrimeField;
 use group::Group;
 use jubjub::SubgroupPoint;
+use bls12_381::Scalar;
 
 fn main() {
     let g = SubgroupPoint::from_raw_unchecked(
@@ -20,5 +21,19 @@ fn main() {
     let x = g + g;
     let x = jubjub::AffinePoint::from(jubjub::ExtendedPoint::from(x));
     println!("{:?}", x);
-}
 
+    let one = Scalar::from_bytes(&[
+        0x01, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+    ]).unwrap();
+    assert_eq!(Scalar::one(), one);
+}

+ 102 - 19
src/vm.rs

@@ -10,7 +10,7 @@ use bls12_381::Scalar;
 use ff::{Field, PrimeField};
 use group::Curve;
 use rand::rngs::OsRng;
-use std::ops::{MulAssign, Neg, SubAssign};
+use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
 use std::time::Instant;
 
 pub struct ZKVirtualMachine {
@@ -20,19 +20,24 @@ pub struct ZKVirtualMachine {
     pub constraints: Vec<ConstraintInstruction>,
     pub params: Option<groth16::Parameters<Bls12>>,
     pub verifying_key: Option<groth16::PreparedVerifyingKey<Bls12>>,
+    pub constants: Vec<Scalar>,
 }
 
 type VariableIndex = usize;
 
 pub enum VariableRef {
     Aux(VariableIndex),
-    Local(VariableIndex)
+    Local(VariableIndex),
 }
 
 pub enum CryptoOperation {
     Set(VariableRef, VariableRef),
     Mul(VariableRef, VariableRef),
-    Local
+    Add(VariableRef, VariableRef),
+    Sub(VariableRef, VariableRef),
+    Load(VariableRef, VariableIndex),
+    Divide(VariableRef, VariableRef),
+    Local,
 }
 
 #[derive(Clone)]
@@ -41,8 +46,29 @@ pub enum AllocType {
     Public,
 }
 
+#[derive(Clone)]
+pub enum ConstraintInstruction {
+    Lc0Add(VariableIndex),
+    Lc1Add(VariableIndex),
+    Lc2Add(VariableIndex),
+    Lc0Sub(VariableIndex),
+    Lc1Sub(VariableIndex),
+    Lc2Sub(VariableIndex),
+    Lc0AddOne,
+    Lc1AddOne,
+    Lc2AddOne,
+    Lc0AddCoeff(VariableIndex, VariableIndex),
+    Lc1AddCoeff(VariableIndex, VariableIndex),
+    Lc2AddCoeff(VariableIndex, VariableIndex),
+    Enforce,
+}
+
+pub enum ZKVMError {
+    DivisionByZero,
+}
+
 impl ZKVirtualMachine {
-    pub fn initialize(&mut self, params: &Vec<(VariableIndex, Scalar)>) {
+    pub fn initialize(&mut self, params: &Vec<(VariableIndex, Scalar)>) -> std::result::Result<(), ZKVMError> {
         // Resize array
         self.aux = vec![Scalar::zero(); self.alloc.len()];
 
@@ -59,30 +85,77 @@ impl ZKVirtualMachine {
                 CryptoOperation::Set(self_, other) => {
                     let other = match other {
                         VariableRef::Aux(index) => self.aux[*index].clone(),
-                        VariableRef::Local(index) => local_stack[*index].clone()
+                        VariableRef::Local(index) => local_stack[*index].clone(),
                     };
                     let self_ = match self_ {
                         VariableRef::Aux(index) => &mut self.aux[*index],
-                        VariableRef::Local(index) => &mut local_stack[*index]
+                        VariableRef::Local(index) => &mut local_stack[*index],
                     };
                     *self_ = other;
                 }
                 CryptoOperation::Mul(self_, other) => {
                     let other = match other {
                         VariableRef::Aux(index) => self.aux[*index].clone(),
-                        VariableRef::Local(index) => local_stack[*index].clone()
+                        VariableRef::Local(index) => local_stack[*index].clone(),
                     };
                     let self_ = match self_ {
                         VariableRef::Aux(index) => &mut self.aux[*index],
-                        VariableRef::Local(index) => &mut local_stack[*index]
+                        VariableRef::Local(index) => &mut local_stack[*index],
                     };
                     self_.mul_assign(other);
                 }
+                CryptoOperation::Add(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    self_.add_assign(other);
+                }
+                CryptoOperation::Sub(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    self_.sub_assign(other);
+                }
+                CryptoOperation::Load(self_, const_index) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = self.constants[*const_index];
+                }
+                CryptoOperation::Divide(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    let ret = other.invert().map(|other| *self_ * other);
+                    if bool::from(ret.is_some()) {
+                        *self_ = ret.unwrap();
+                    } else {
+                        return Err(ZKVMError::DivisionByZero);
+                    }
+                }
                 CryptoOperation::Local => {
                     local_stack.push(Scalar::zero());
                 }
             }
         }
+
+        Ok(())
     }
 
     pub fn public(&self) -> Vec<Scalar> {
@@ -108,6 +181,7 @@ impl ZKVirtualMachine {
                 aux: vec![None; self.aux.len()],
                 alloc: self.alloc.clone(),
                 constraints: self.constraints.clone(),
+                constants: self.constants.clone(),
             };
             groth16::generate_random_parameters::<Bls12, _, _>(circuit, &mut OsRng).unwrap()
         });
@@ -126,6 +200,7 @@ impl ZKVirtualMachine {
             aux,
             alloc: self.alloc.clone(),
             constraints: self.constraints.clone(),
+            constants: self.constants.clone(),
         };
 
         let start = Instant::now();
@@ -151,6 +226,7 @@ pub struct ZKVMCircuit {
     aux: Vec<Option<bls12_381::Scalar>>,
     alloc: Vec<(AllocType, VariableIndex)>,
     constraints: Vec<ConstraintInstruction>,
+    constants: Vec<Scalar>,
 }
 
 impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
@@ -189,6 +265,15 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
                 ConstraintInstruction::Lc2Add(index) => {
                     lc2 = lc2 + (coeff_one, variables[index]);
                 }
+                ConstraintInstruction::Lc0Sub(index) => {
+                    lc0 = lc0 - (coeff_one, variables[index]);
+                }
+                ConstraintInstruction::Lc1Sub(index) => {
+                    lc1 = lc1 - (coeff_one, variables[index]);
+                }
+                ConstraintInstruction::Lc2Sub(index) => {
+                    lc2 = lc2 - (coeff_one, variables[index]);
+                }
                 ConstraintInstruction::Lc0AddOne => {
                     lc0 = lc0 + CS::one();
                 }
@@ -198,6 +283,15 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
                 ConstraintInstruction::Lc2AddOne => {
                     lc2 = lc2 + CS::one();
                 }
+                ConstraintInstruction::Lc0AddCoeff(const_index, index) => {
+                    lc0 = lc0 + (self.constants[const_index], variables[index]);
+                }
+                ConstraintInstruction::Lc1AddCoeff(const_index, index) => {
+                    lc1 = lc1 + (self.constants[const_index], variables[index]);
+                }
+                ConstraintInstruction::Lc2AddCoeff(const_index, index) => {
+                    lc2 = lc2 + (self.constants[const_index], variables[index]);
+                }
                 ConstraintInstruction::Enforce => {
                     cs.enforce(
                         || "constraint",
@@ -216,14 +310,3 @@ impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
     }
 }
 
-#[derive(Clone)]
-pub enum ConstraintInstruction {
-    Lc0Add(VariableIndex),
-    Lc1Add(VariableIndex),
-    Lc2Add(VariableIndex),
-    Lc0AddOne,
-    Lc1AddOne,
-    Lc2AddOne,
-    Enforce,
-}
-

+ 36 - 1
src/vmtest.rs

@@ -10,7 +10,42 @@ fn main() {
     vm.setup();
 
     let params = vec![
-        (0, Scalar::from(3))
+        (
+            0,
+            Scalar::from_raw([
+                0xb981_9dc8_2d90_607e,
+                0xa361_ee3f_d48f_df77,
+                0x52a3_5a8c_1908_dd87,
+                0x15a3_6d1f_0f39_0d88,
+            ]),
+        ),
+        (
+            1,
+            Scalar::from_raw([
+                0x7b0d_c53c_4ebf_1891,
+                0x1f3a_beeb_98fa_d3e8,
+                0xf789_1142_c001_d925,
+                0x015d_8c7f_5b43_fe33,
+            ]),
+        ),
+        (
+            2,
+            Scalar::from_raw([
+                0xb981_9dc8_2d90_607e,
+                0xa361_ee3f_d48f_df77,
+                0x52a3_5a8c_1908_dd87,
+                0x15a3_6d1f_0f39_0d88,
+            ]),
+        ),
+        (
+            3,
+            Scalar::from_raw([
+                0x7b0d_c53c_4ebf_1891,
+                0x1f3a_beeb_98fa_d3e8,
+                0xf789_1142_c001_d925,
+                0x015d_8c7f_5b43_fe33,
+            ]),
+        ),
     ];
     vm.initialize(&params);