Преглед изворни кода

zkas: Implement a macro for opcode definition.

This lets us have a single source of truth.
x пре 7 месеци
родитељ
комит
589e40bc32
1 измењених фајлова са 131 додато и 192 уклоњено
  1. 131 192
      src/zkas/opcode.rs

+ 131 - 192
src/zkas/opcode.rs

@@ -18,244 +18,183 @@
 
 
 use super::VarType;
 use super::VarType;
 
 
-/// Opcodes supported by the zkas VM
-#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
-#[repr(u8)]
-pub enum Opcode {
+/// Macro to define all opcodes in a single place.
+/// This generates the enum definition, `from_name`, `from_repr`, `name`, and `arg_types` methods.
+///
+/// Format for each opcode:
+/// ```text
+/// [doc_comments]
+/// VariantName = 0xNN, "string_name", (return_types), (arg_types)
+/// ```
+///
+/// Note: Noop is handled specially - it's excluded from `from_repr` and `from_name`
+/// as it should never appear in compiled binaries or source code.
+macro_rules! define_opcodes {
+    (
+        // Special case for Noop which shouldn't be in from_repr/from_name
+        $(#[doc = $noop_doc:literal])*
+        Noop = $noop_value:literal, $noop_name:literal,
+            ($($noop_ret:expr),*), ($($noop_arg:expr),*);
+
+        // All other opcodes
+        $(
+            $(#[doc = $doc:literal])*
+            $variant:ident = $value:literal, $name:literal,
+            ($($ret:expr),*), ($($arg:expr),*)
+        );* $(;)?
+    ) => {
+        /// Opcodes supported by the zkas VM
+        #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
+        #[repr(u8)]
+        pub enum Opcode {
+            $(#[doc = $noop_doc])*
+            Noop = $noop_value,
+
+            $(
+                $(#[doc = $doc])*
+                $variant = $value,
+            )*
+        }
+
+        impl Opcode {
+            /// Look up an opcode by its string name (used in source code).
+            /// Note: Noop cannot be looked up by name as it's an internal compiler opcode.
+            pub fn from_name(n: &str) -> Option<Self> {
+                match n {
+                    $($name => Some(Self::$variant),)*
+                    _ => None,
+                }
+            }
+
+            /// Look up an opcode by its binary representation.
+            /// Note: Noop (0x00) is not valid in binary as it should never be compiled.
+            pub fn from_repr(b: u8) -> Option<Self> {
+                match b {
+                    $($value => Some(Self::$variant),)*
+                    _ => None,
+                }
+            }
+
+            /// Get the string name of an opcode.
+            pub fn name(&self) -> &'static str {
+                match self {
+                    Self::Noop => $noop_name,
+                    $(Self::$variant => $name,)*
+                }
+            }
+
+            /// Return a tuple of vectors of types that are accepted by a specific opcode.
+            /// `r.0` is the return type(s), and `r.1` is the argument type(s).
+            pub fn arg_types(&self) -> (Vec<VarType>, Vec<VarType>) {
+                match self {
+                    Self::Noop => (vec![$($noop_ret),*], vec![$($noop_arg),*]),
+                    $(Self::$variant => (vec![$($ret),*], vec![$($arg),*]),)*
+                }
+            }
+        }
+    };
+}
+
+define_opcodes! {
     /// Intermediate opcode for the compiler, should never appear in the result
     /// Intermediate opcode for the compiler, should never appear in the result
-    Noop = 0x00,
+    Noop = 0x00, "noop",
+        (), ();
 
 
     /// Elliptic curve addition
     /// Elliptic curve addition
-    EcAdd = 0x01,
+    EcAdd = 0x01, "ec_add",
+        (VarType::EcPoint), (VarType::EcPoint, VarType::EcPoint);
 
 
     /// Elliptic curve multiplication
     /// Elliptic curve multiplication
-    EcMul = 0x02,
+    EcMul = 0x02, "ec_mul",
+        (VarType::EcPoint), (VarType::Scalar, VarType::EcFixedPoint);
 
 
     /// Elliptic curve multiplication with a Base field element
     /// Elliptic curve multiplication with a Base field element
-    EcMulBase = 0x03,
+    EcMulBase = 0x03, "ec_mul_base",
+        (VarType::EcPoint), (VarType::Base, VarType::EcFixedPointBase);
 
 
     /// Elliptic curve multiplication with a Base field element of 64bit width
     /// Elliptic curve multiplication with a Base field element of 64bit width
-    EcMulShort = 0x04,
+    EcMulShort = 0x04, "ec_mul_short",
+        (VarType::EcPoint), (VarType::Base, VarType::EcFixedPointShort);
 
 
     /// Variable Elliptic curve multiplication with a Base field element
     /// Variable Elliptic curve multiplication with a Base field element
-    EcMulVarBase = 0x05,
+    EcMulVarBase = 0x05, "ec_mul_var_base",
+        (VarType::EcPoint), (VarType::Base, VarType::EcNiPoint);
 
 
     /// Get the x coordinate of an elliptic curve point
     /// Get the x coordinate of an elliptic curve point
-    EcGetX = 0x08,
+    EcGetX = 0x08, "ec_get_x",
+        (VarType::Base), (VarType::EcPoint);
 
 
     /// Get the y coordinate of an elliptic curve point
     /// Get the y coordinate of an elliptic curve point
-    EcGetY = 0x09,
+    EcGetY = 0x09, "ec_get_y",
+        (VarType::Base), (VarType::EcPoint);
 
 
     /// Poseidon hash of N Base field elements
     /// Poseidon hash of N Base field elements
-    PoseidonHash = 0x10,
+    PoseidonHash = 0x10, "poseidon_hash",
+        (VarType::Base), (VarType::BaseArray);
 
 
     /// Calculate Merkle root, given a position, Merkle path, and an element
     /// Calculate Merkle root, given a position, Merkle path, and an element
-    MerkleRoot = 0x20,
+    MerkleRoot = 0x20, "merkle_root",
+        (VarType::Base), (VarType::Uint32, VarType::MerklePath, VarType::Base);
 
 
     /// Calculate sparse Merkle root, given the position, path and a member
     /// Calculate sparse Merkle root, given the position, path and a member
-    SparseMerkleRoot = 0x21,
+    SparseMerkleRoot = 0x21, "sparse_merkle_root",
+        (VarType::Base), (VarType::Base, VarType::SparseMerklePath, VarType::Base);
 
 
     /// Base field element addition
     /// Base field element addition
-    BaseAdd = 0x30,
+    BaseAdd = 0x30, "base_add",
+        (VarType::Base), (VarType::Base, VarType::Base);
 
 
     /// Base field element multiplication
     /// Base field element multiplication
-    BaseMul = 0x31,
+    BaseMul = 0x31, "base_mul",
+        (VarType::Base), (VarType::Base, VarType::Base);
 
 
     /// Base field element subtraction
     /// Base field element subtraction
-    BaseSub = 0x32,
+    BaseSub = 0x32, "base_sub",
+        (VarType::Base), (VarType::Base, VarType::Base);
 
 
     /// Witness an unsigned integer into a Base field element
     /// Witness an unsigned integer into a Base field element
-    WitnessBase = 0x40,
+    WitnessBase = 0x40, "witness_base",
+        (VarType::Base), (VarType::Uint64);
 
 
     /// Range check a Base field element, given bit-width (up to 253)
     /// Range check a Base field element, given bit-width (up to 253)
-    RangeCheck = 0x50,
+    RangeCheck = 0x50, "range_check",
+        (), (VarType::Uint64, VarType::Base);
 
 
-    /// Strictly compare two Base field elements and see if a is less than b
+    /// Strictly compare two Base field elements and see if a is less than b.
     /// This enforces the sum of remaining bits to be zero.
     /// This enforces the sum of remaining bits to be zero.
-    LessThanStrict = 0x51,
+    LessThanStrict = 0x51, "less_than_strict",
+        (), (VarType::Base, VarType::Base);
 
 
-    /// Loosely two Base field elements and see if a is less than b
+    /// Loosely compare two Base field elements and see if a is less than b.
     /// This does not enforce the sum of remaining bits to be zero.
     /// This does not enforce the sum of remaining bits to be zero.
-    LessThanLoose = 0x52,
+    LessThanLoose = 0x52, "less_than_loose",
+        (), (VarType::Base, VarType::Base);
 
 
     /// Check if a field element fits in a boolean (Either 0 or 1)
     /// Check if a field element fits in a boolean (Either 0 or 1)
-    BoolCheck = 0x53,
+    BoolCheck = 0x53, "bool_check",
+        (), (VarType::Base);
 
 
     /// Conditionally select between two base field elements given a boolean
     /// Conditionally select between two base field elements given a boolean
-    CondSelect = 0x60,
+    CondSelect = 0x60, "cond_select",
+        (VarType::Base), (VarType::Base, VarType::Base, VarType::Base);
 
 
     /// Conditionally select between a and b (return a if a is zero, and b if a is nonzero)
     /// Conditionally select between a and b (return a if a is zero, and b if a is nonzero)
-    ZeroCondSelect = 0x61,
+    ZeroCondSelect = 0x61, "zero_cond",
+        (VarType::Base), (VarType::Base, VarType::Base);
 
 
     /// Constrain equality of two Base field elements inside the circuit
     /// Constrain equality of two Base field elements inside the circuit
-    ConstrainEqualBase = 0xe0,
+    ConstrainEqualBase = 0xe0, "constrain_equal_base",
+        (), (VarType::Base, VarType::Base);
 
 
     /// Constrain equality of two EcPoint elements inside the circuit
     /// Constrain equality of two EcPoint elements inside the circuit
-    ConstrainEqualPoint = 0xe1,
+    ConstrainEqualPoint = 0xe1, "constrain_equal_point",
+        (), (VarType::EcPoint, VarType::EcPoint);
 
 
     /// Constrain a Base field element to a circuit's public input
     /// Constrain a Base field element to a circuit's public input
-    ConstrainInstance = 0xf0,
-
-    /// Debug a variable's value in the ZK circuit table.
-    DebugPrint = 0xff,
-}
-
-impl Opcode {
-    pub fn from_name(n: &str) -> Option<Self> {
-        match n {
-            "ec_add" => Some(Self::EcAdd),
-            "ec_mul" => Some(Self::EcMul),
-            "ec_mul_base" => Some(Self::EcMulBase),
-            "ec_mul_short" => Some(Self::EcMulShort),
-            "ec_mul_var_base" => Some(Self::EcMulVarBase),
-            "ec_get_x" => Some(Self::EcGetX),
-            "ec_get_y" => Some(Self::EcGetY),
-            "poseidon_hash" => Some(Self::PoseidonHash),
-            "merkle_root" => Some(Self::MerkleRoot),
-            "sparse_merkle_root" => Some(Self::SparseMerkleRoot),
-            "base_add" => Some(Self::BaseAdd),
-            "base_mul" => Some(Self::BaseMul),
-            "base_sub" => Some(Self::BaseSub),
-            "witness_base" => Some(Self::WitnessBase),
-            "range_check" => Some(Self::RangeCheck),
-            "less_than_strict" => Some(Self::LessThanStrict),
-            "less_than_loose" => Some(Self::LessThanLoose),
-            "bool_check" => Some(Self::BoolCheck),
-            "cond_select" => Some(Self::CondSelect),
-            "zero_cond" => Some(Self::ZeroCondSelect),
-            "constrain_equal_base" => Some(Self::ConstrainEqualBase),
-            "constrain_equal_point" => Some(Self::ConstrainEqualPoint),
-            "constrain_instance" => Some(Self::ConstrainInstance),
-            "debug" => Some(Self::DebugPrint),
-            _ => None,
-        }
-    }
-
-    pub fn from_repr(b: u8) -> Option<Self> {
-        match b {
-            0x01 => Some(Self::EcAdd),
-            0x02 => Some(Self::EcMul),
-            0x03 => Some(Self::EcMulBase),
-            0x04 => Some(Self::EcMulShort),
-            0x05 => Some(Self::EcMulVarBase),
-            0x08 => Some(Self::EcGetX),
-            0x09 => Some(Self::EcGetY),
-            0x10 => Some(Self::PoseidonHash),
-            0x20 => Some(Self::MerkleRoot),
-            0x21 => Some(Self::SparseMerkleRoot),
-            0x30 => Some(Self::BaseAdd),
-            0x31 => Some(Self::BaseMul),
-            0x32 => Some(Self::BaseSub),
-            0x40 => Some(Self::WitnessBase),
-            0x50 => Some(Self::RangeCheck),
-            0x51 => Some(Self::LessThanStrict),
-            0x52 => Some(Self::LessThanLoose),
-            0x53 => Some(Self::BoolCheck),
-            0x60 => Some(Self::CondSelect),
-            0x61 => Some(Self::ZeroCondSelect),
-            0xe0 => Some(Self::ConstrainEqualBase),
-            0xe1 => Some(Self::ConstrainEqualPoint),
-            0xf0 => Some(Self::ConstrainInstance),
-            0xff => Some(Self::DebugPrint),
-            _ => None,
-        }
-    }
-
-    pub fn name(&self) -> &str {
-        match self {
-            Self::Noop => "noop",
-            Self::EcAdd => "ec_add",
-            Self::EcMul => "ec_mul",
-            Self::EcMulBase => "ec_mul_base",
-            Self::EcMulShort => "ec_mul_short",
-            Self::EcMulVarBase => "ec_mul_var_base",
-            Self::EcGetX => "ec_get_x",
-            Self::EcGetY => "ec_get_y",
-            Self::PoseidonHash => "poseidon_hash",
-            Self::MerkleRoot => "merkle_root",
-            Self::SparseMerkleRoot => "sparse_merkle_root",
-            Self::BaseAdd => "base_add",
-            Self::BaseMul => "base_mul",
-            Self::BaseSub => "base_sub",
-            Self::WitnessBase => "witness_base",
-            Self::RangeCheck => "range_check",
-            Self::LessThanStrict => "less_than_strict",
-            Self::LessThanLoose => "less_than_loose",
-            Self::BoolCheck => "bool_check",
-            Self::CondSelect => "cond_select",
-            Self::ZeroCondSelect => "zero_cond",
-            Self::ConstrainEqualBase => "constrain_equal_base",
-            Self::ConstrainEqualPoint => "constrain_equal_point",
-            Self::ConstrainInstance => "constrain_instance",
-            Self::DebugPrint => "debug",
-        }
-    }
-
-    /// Return a tuple of vectors of types that are accepted by a specific opcode.
-    /// `r.0` is the return type(s), and `r.1` is the argument type(s).
-    pub fn arg_types(&self) -> (Vec<VarType>, Vec<VarType>) {
-        match self {
-            Opcode::Noop => (vec![], vec![]),
-
-            Opcode::EcAdd => (vec![VarType::EcPoint], vec![VarType::EcPoint, VarType::EcPoint]),
-
-            Opcode::EcMul => (vec![VarType::EcPoint], vec![VarType::Scalar, VarType::EcFixedPoint]),
-
-            Opcode::EcMulBase => {
-                (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcFixedPointBase])
-            }
-
-            Opcode::EcMulShort => {
-                (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcFixedPointShort])
-            }
+    ConstrainInstance = 0xf0, "constrain_instance",
+        (), (VarType::Base);
 
 
-            Opcode::EcMulVarBase => {
-                (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcNiPoint])
-            }
-
-            Opcode::EcGetX => (vec![VarType::Base], vec![VarType::EcPoint]),
-
-            Opcode::EcGetY => (vec![VarType::Base], vec![VarType::EcPoint]),
-
-            Opcode::PoseidonHash => (vec![VarType::Base], vec![VarType::BaseArray]),
-
-            Opcode::MerkleRoot => {
-                (vec![VarType::Base], vec![VarType::Uint32, VarType::MerklePath, VarType::Base])
-            }
-
-            Opcode::SparseMerkleRoot => {
-                (vec![VarType::Base], vec![VarType::Base, VarType::SparseMerklePath, VarType::Base])
-            }
-
-            Opcode::BaseAdd => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
-
-            Opcode::BaseMul => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
-
-            Opcode::BaseSub => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
-
-            Opcode::WitnessBase => (vec![VarType::Base], vec![VarType::Uint64]),
-
-            Opcode::RangeCheck => (vec![], vec![VarType::Uint64, VarType::Base]),
-
-            Opcode::LessThanStrict => (vec![], vec![VarType::Base, VarType::Base]),
-
-            Opcode::LessThanLoose => (vec![], vec![VarType::Base, VarType::Base]),
-
-            Opcode::BoolCheck => (vec![], vec![VarType::Base]),
-
-            Opcode::CondSelect => {
-                (vec![VarType::Base], vec![VarType::Base, VarType::Base, VarType::Base])
-            }
-
-            Opcode::ZeroCondSelect => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
-
-            Opcode::ConstrainEqualBase => (vec![], vec![VarType::Base, VarType::Base]),
-
-            Opcode::ConstrainEqualPoint => (vec![], vec![VarType::EcPoint, VarType::EcPoint]),
-
-            Opcode::ConstrainInstance => (vec![], vec![VarType::Base]),
-
-            Opcode::DebugPrint => (vec![], vec![VarType::Any]),
-        }
-    }
+    /// Debug a variable's value in the ZK circuit table
+    DebugPrint = 0xff, "debug",
+        (), (VarType::Any);
 }
 }