Эх сурвалжийг харах

zk: Add base_sub opcode to VM and arithmetic chip.

parazyd 4 жил өмнө
parent
commit
230ff6fcc6

+ 1 - 1
contrib/zk.lua

@@ -32,7 +32,7 @@ local type = token(l.TYPE, word_match{
 local instruction = token('instruction', word_match{
   'ec_add', 'ec_mul', 'ec_mul_base', 'ec_mul_short',
   'ec_get_x', 'ec_get_y',
-  'base_add', 'base_mul',
+  'base_add', 'base_mul', 'base_sub',
   'poseidon_hash', 'calculate_merkle_root',
   'constrain_instance',
 })

+ 2 - 1
proof/arithmetic.rs

@@ -37,8 +37,9 @@ fn main() -> Result<()> {
     // Create the public inputs
     let sum = a + b;
     let product = a * b;
+    let difference = a - b;
 
-    let public_inputs = vec![sum, product];
+    let public_inputs = vec![sum, product, difference];
 
     // Create the circuit
     let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());

+ 3 - 0
proof/arithmetic.zk

@@ -11,4 +11,7 @@ circuit "Arith" {
 
 	product = base_mul(a, b);
 	constrain_instance(product);
+
+	difference = base_sub(a, b);
+	constrain_instance(difference);
 }

+ 9 - 2
src/error.rs

@@ -77,8 +77,8 @@ pub enum Error {
     MissingParams,
 
     #[cfg(feature = "crypto")]
-    #[error(transparent)]
-    PlonkError(#[from] halo2_proofs::plonk::Error),
+    #[error("Plonk error: `{0}`")]
+    PlonkError(String),
 
     #[cfg(feature = "crypto")]
     #[error("Unable to decrypt mint note")]
@@ -277,3 +277,10 @@ impl From<std::convert::Infallible> for Error {
         Error::InfallibleError(err.to_string())
     }
 }
+
+#[cfg(feature = "crypto")]
+impl From<halo2_proofs::plonk::Error> for Error {
+    fn from(err: halo2_proofs::plonk::Error) -> Error {
+        Error::PlonkError(err.to_string())
+    }
+}

+ 64 - 1
src/zk/arith_chip.rs

@@ -18,6 +18,7 @@ pub struct ArithmeticChipConfig {
     //permute: Permutation,
     s_add: Selector,
     s_mul: Selector,
+    s_sub: Selector,
     //s_pub: Selector,
 }
 
@@ -60,6 +61,7 @@ impl ArithmeticChip {
 
         let s_add = cs.selector();
         let s_mul = cs.selector();
+        let s_sub = cs.selector();
         //let s_pub = cs.selector();
 
         cs.create_gate("add", |cs| {
@@ -80,6 +82,15 @@ impl ArithmeticChip {
             vec![s_mul * (lhs * rhs - out)]
         });
 
+        cs.create_gate("sub", |cs| {
+            let lhs = cs.query_advice(a_col, Rotation::cur());
+            let rhs = cs.query_advice(b_col, Rotation::cur());
+            let out = cs.query_advice(a_col, Rotation::next());
+            let s_sub = cs.query_selector(s_sub);
+
+            vec![s_sub * (lhs - rhs - out)]
+        });
+
         /*
         cs.create_gate("pub", |cs| {
             let a = cs.query_advice(a_col, Rotation::cur());
@@ -90,7 +101,13 @@ impl ArithmeticChip {
         });
         */
 
-        ArithmeticChipConfig { a_col, b_col, /* permute, */ s_add, s_mul /* , s_pub */ }
+        ArithmeticChipConfig {
+            a_col,
+            b_col,
+            /* permute, */ s_add,
+            s_mul,
+            s_sub, /* , s_pub */
+        }
     }
 
     pub fn add(
@@ -185,6 +202,52 @@ impl ArithmeticChip {
         Ok(out.unwrap())
     }
 
+    pub fn sub(
+        &self,
+        mut layouter: impl Layouter<Fp>,
+        a: Variable,
+        b: Variable,
+    ) -> Result<Variable, Error> {
+        let mut out = None;
+
+        layouter.assign_region(
+            || "sub",
+            |mut region| {
+                self.config.s_sub.enable(&mut region, 0)?;
+
+                let lhs = region.assign_advice(
+                    || "lhs",
+                    self.config.a_col,
+                    0,
+                    || Ok(*a.value().ok_or(Error::Synthesis)?),
+                )?;
+
+                let rhs = region.assign_advice(
+                    || "rhs",
+                    self.config.b_col,
+                    0,
+                    || Ok(*b.value().ok_or(Error::Synthesis)?),
+                )?;
+
+                region.constrain_equal(a.cell(), lhs.cell())?;
+                region.constrain_equal(b.cell(), rhs.cell())?;
+
+                let value = a.value().and_then(|a| b.value().map(|b| a - b));
+                let cell = region.assign_advice(
+                    || "lhs * rhs",
+                    self.config.a_col,
+                    1,
+                    || value.ok_or(Error::Synthesis),
+                )?;
+
+                out = Some(cell);
+                Ok(())
+            },
+        )?;
+
+        Ok(out.unwrap())
+    }
+
     /*
     fn expose_public(&self, layouter: &mut impl Layouter<Fp>, num: Number) -> Result<(), Error> {
         layouter.assign_region(

+ 14 - 0
src/zk/vm.rs

@@ -535,6 +535,20 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     stack.push(StackVar::Base(product));
                 }
 
+                Opcode::BaseSub => {
+                    debug!("Executing `BaseSub{:?}` opcode", opcode.1);
+                    let args = &opcode.1;
+
+                    let lhs = stack[args[0]].clone().into();
+                    let rhs = stack[args[1]].clone().into();
+
+                    let difference =
+                        arith_chip.sub(layouter.namespace(|| "BaseSub()"), lhs, rhs)?;
+
+                    debug!("Pushing difference to stack index {}", stack.len());
+                    stack.push(StackVar::Base(difference));
+                }
+
                 Opcode::ConstrainInstance => {
                     debug!("Executing `ConstrainInstance{:?}` opcode", opcode.1);
                     let args = &opcode.1;

+ 5 - 0
src/zkas/opcode.rs

@@ -34,6 +34,9 @@ pub enum Opcode {
     /// Base field element multiplication
     BaseMul = 0x31,
 
+    /// Base field element subtraction
+    BaseSub = 0x32,
+
     /// Constrain a Base field element to a circuit's public input
     ConstrainInstance = 0xf0,
 
@@ -59,6 +62,7 @@ impl Opcode {
             }
             Opcode::BaseAdd => (vec![Type::Base], vec![Type::Base, Type::Base]),
             Opcode::BaseMul => (vec![Type::Base], vec![Type::Base, Type::Base]),
+            Opcode::BaseSub => (vec![Type::Base], vec![Type::Base, Type::Base]),
             Opcode::ConstrainInstance => (vec![], vec![Type::Base]),
             Opcode::Noop => (vec![], vec![]),
         }
@@ -76,6 +80,7 @@ impl Opcode {
             0x20 => Self::CalculateMerkleRoot,
             0x30 => Self::BaseAdd,
             0x31 => Self::BaseMul,
+            0x32 => Self::BaseSub,
             0xf0 => Self::ConstrainInstance,
             _ => unimplemented!(),
         }

+ 10 - 0
src/zkas/parser.rs

@@ -658,6 +658,16 @@ impl Parser {
                         continue
                     }
 
+                    "base_sub" => {
+                        stmt.args = self.parse_function_call(token, &mut iter);
+                        stmt.opcode = Opcode::BaseSub;
+                        stmt.line = token.line;
+                        stmts.push(stmt.clone());
+
+                        parsing = false;
+                        continue
+                    }
+
                     x => {
                         self.error.emit(
                             format!("Unimplemented function call `{}`", x),