/ src / zkas / opcode.rs
opcode.rs
  1  /* This file is part of DarkFi (https://dark.fi)
  2   *
  3   * Copyright (C) 2020-2025 Dyne.org foundation
  4   *
  5   * This program is free software: you can redistribute it and/or modify
  6   * it under the terms of the GNU Affero General Public License as
  7   * published by the Free Software Foundation, either version 3 of the
  8   * License, or (at your option) any later version.
  9   *
 10   * This program is distributed in the hope that it will be useful,
 11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13   * GNU Affero General Public License for more details.
 14   *
 15   * You should have received a copy of the GNU Affero General Public License
 16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17   */
 18  
 19  use super::VarType;
 20  
 21  /// Opcodes supported by the zkas VM
 22  #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
 23  #[repr(u8)]
 24  pub enum Opcode {
 25      /// Intermediate opcode for the compiler, should never appear in the result
 26      Noop = 0x00,
 27  
 28      /// Elliptic curve addition
 29      EcAdd = 0x01,
 30  
 31      /// Elliptic curve multiplication
 32      EcMul = 0x02,
 33  
 34      /// Elliptic curve multiplication with a Base field element
 35      EcMulBase = 0x03,
 36  
 37      /// Elliptic curve multiplication with a Base field element of 64bit width
 38      EcMulShort = 0x04,
 39  
 40      /// Variable Elliptic curve multiplication with a Base field element
 41      EcMulVarBase = 0x05,
 42  
 43      /// Get the x coordinate of an elliptic curve point
 44      EcGetX = 0x08,
 45  
 46      /// Get the y coordinate of an elliptic curve point
 47      EcGetY = 0x09,
 48  
 49      /// Poseidon hash of N Base field elements
 50      PoseidonHash = 0x10,
 51  
 52      /// Calculate Merkle root, given a position, Merkle path, and an element
 53      MerkleRoot = 0x20,
 54  
 55      /// Calculate sparse Merkle root, given the position, path and a member
 56      SparseMerkleRoot = 0x21,
 57  
 58      /// Base field element addition
 59      BaseAdd = 0x30,
 60  
 61      /// Base field element multiplication
 62      BaseMul = 0x31,
 63  
 64      /// Base field element subtraction
 65      BaseSub = 0x32,
 66  
 67      /// Witness an unsigned integer into a Base field element
 68      WitnessBase = 0x40,
 69  
 70      /// Range check a Base field element, given bit-width (up to 253)
 71      RangeCheck = 0x50,
 72  
 73      /// Strictly compare two Base field elements and see if a is less than b
 74      /// This enforces the sum of remaining bits to be zero.
 75      LessThanStrict = 0x51,
 76  
 77      /// Loosely two Base field elements and see if a is less than b
 78      /// This does not enforce the sum of remaining bits to be zero.
 79      LessThanLoose = 0x52,
 80  
 81      /// Check if a field element fits in a boolean (Either 0 or 1)
 82      BoolCheck = 0x53,
 83  
 84      /// Conditionally select between two base field elements given a boolean
 85      CondSelect = 0x60,
 86  
 87      /// Conditionally select between a and b (return a if a is zero, and b if a is nonzero)
 88      ZeroCondSelect = 0x61,
 89  
 90      /// Constrain equality of two Base field elements inside the circuit
 91      ConstrainEqualBase = 0xe0,
 92  
 93      /// Constrain equality of two EcPoint elements inside the circuit
 94      ConstrainEqualPoint = 0xe1,
 95  
 96      /// Constrain a Base field element to a circuit's public input
 97      ConstrainInstance = 0xf0,
 98  
 99      /// Debug a variable's value in the ZK circuit table.
100      DebugPrint = 0xff,
101  }
102  
103  impl Opcode {
104      pub fn from_name(n: &str) -> Option<Self> {
105          match n {
106              "ec_add" => Some(Self::EcAdd),
107              "ec_mul" => Some(Self::EcMul),
108              "ec_mul_base" => Some(Self::EcMulBase),
109              "ec_mul_short" => Some(Self::EcMulShort),
110              "ec_mul_var_base" => Some(Self::EcMulVarBase),
111              "ec_get_x" => Some(Self::EcGetX),
112              "ec_get_y" => Some(Self::EcGetY),
113              "poseidon_hash" => Some(Self::PoseidonHash),
114              "merkle_root" => Some(Self::MerkleRoot),
115              "sparse_merkle_root" => Some(Self::SparseMerkleRoot),
116              "base_add" => Some(Self::BaseAdd),
117              "base_mul" => Some(Self::BaseMul),
118              "base_sub" => Some(Self::BaseSub),
119              "witness_base" => Some(Self::WitnessBase),
120              "range_check" => Some(Self::RangeCheck),
121              "less_than_strict" => Some(Self::LessThanStrict),
122              "less_than_loose" => Some(Self::LessThanLoose),
123              "bool_check" => Some(Self::BoolCheck),
124              "cond_select" => Some(Self::CondSelect),
125              "zero_cond" => Some(Self::ZeroCondSelect),
126              "constrain_equal_base" => Some(Self::ConstrainEqualBase),
127              "constrain_equal_point" => Some(Self::ConstrainEqualPoint),
128              "constrain_instance" => Some(Self::ConstrainInstance),
129              "debug" => Some(Self::DebugPrint),
130              _ => None,
131          }
132      }
133  
134      pub fn from_repr(b: u8) -> Option<Self> {
135          match b {
136              0x01 => Some(Self::EcAdd),
137              0x02 => Some(Self::EcMul),
138              0x03 => Some(Self::EcMulBase),
139              0x04 => Some(Self::EcMulShort),
140              0x05 => Some(Self::EcMulVarBase),
141              0x08 => Some(Self::EcGetX),
142              0x09 => Some(Self::EcGetY),
143              0x10 => Some(Self::PoseidonHash),
144              0x20 => Some(Self::MerkleRoot),
145              0x21 => Some(Self::SparseMerkleRoot),
146              0x30 => Some(Self::BaseAdd),
147              0x31 => Some(Self::BaseMul),
148              0x32 => Some(Self::BaseSub),
149              0x40 => Some(Self::WitnessBase),
150              0x50 => Some(Self::RangeCheck),
151              0x51 => Some(Self::LessThanStrict),
152              0x52 => Some(Self::LessThanLoose),
153              0x53 => Some(Self::BoolCheck),
154              0x60 => Some(Self::CondSelect),
155              0x61 => Some(Self::ZeroCondSelect),
156              0xe0 => Some(Self::ConstrainEqualBase),
157              0xe1 => Some(Self::ConstrainEqualPoint),
158              0xf0 => Some(Self::ConstrainInstance),
159              0xff => Some(Self::DebugPrint),
160              _ => None,
161          }
162      }
163  
164      pub fn name(&self) -> &str {
165          match self {
166              Self::Noop => "noop",
167              Self::EcAdd => "ec_add",
168              Self::EcMul => "ec_mul",
169              Self::EcMulBase => "ec_mul_base",
170              Self::EcMulShort => "ec_mul_short",
171              Self::EcMulVarBase => "ec_mul_var_base",
172              Self::EcGetX => "ec_get_x",
173              Self::EcGetY => "ec_get_y",
174              Self::PoseidonHash => "poseidon_hash",
175              Self::MerkleRoot => "merkle_root",
176              Self::SparseMerkleRoot => "sparse_merkle_root",
177              Self::BaseAdd => "base_add",
178              Self::BaseMul => "base_mul",
179              Self::BaseSub => "base_sub",
180              Self::WitnessBase => "witness_base",
181              Self::RangeCheck => "range_check",
182              Self::LessThanStrict => "less_than_strict",
183              Self::LessThanLoose => "less_than_loose",
184              Self::BoolCheck => "bool_check",
185              Self::CondSelect => "cond_select",
186              Self::ZeroCondSelect => "zero_cond",
187              Self::ConstrainEqualBase => "constrain_equal_base",
188              Self::ConstrainEqualPoint => "constrain_equal_point",
189              Self::ConstrainInstance => "constrain_instance",
190              Self::DebugPrint => "debug",
191          }
192      }
193  
194      /// Return a tuple of vectors of types that are accepted by a specific opcode.
195      /// `r.0` is the return type(s), and `r.1` is the argument type(s).
196      pub fn arg_types(&self) -> (Vec<VarType>, Vec<VarType>) {
197          match self {
198              Opcode::Noop => (vec![], vec![]),
199  
200              Opcode::EcAdd => (vec![VarType::EcPoint], vec![VarType::EcPoint, VarType::EcPoint]),
201  
202              Opcode::EcMul => (vec![VarType::EcPoint], vec![VarType::Scalar, VarType::EcFixedPoint]),
203  
204              Opcode::EcMulBase => {
205                  (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcFixedPointBase])
206              }
207  
208              Opcode::EcMulShort => {
209                  (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcFixedPointShort])
210              }
211  
212              Opcode::EcMulVarBase => {
213                  (vec![VarType::EcPoint], vec![VarType::Base, VarType::EcNiPoint])
214              }
215  
216              Opcode::EcGetX => (vec![VarType::Base], vec![VarType::EcPoint]),
217  
218              Opcode::EcGetY => (vec![VarType::Base], vec![VarType::EcPoint]),
219  
220              Opcode::PoseidonHash => (vec![VarType::Base], vec![VarType::BaseArray]),
221  
222              Opcode::MerkleRoot => {
223                  (vec![VarType::Base], vec![VarType::Uint32, VarType::MerklePath, VarType::Base])
224              }
225  
226              Opcode::SparseMerkleRoot => {
227                  (vec![VarType::Base], vec![VarType::Base, VarType::SparseMerklePath, VarType::Base])
228              }
229  
230              Opcode::BaseAdd => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
231  
232              Opcode::BaseMul => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
233  
234              Opcode::BaseSub => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
235  
236              Opcode::WitnessBase => (vec![VarType::Base], vec![VarType::Uint64]),
237  
238              Opcode::RangeCheck => (vec![], vec![VarType::Uint64, VarType::Base]),
239  
240              Opcode::LessThanStrict => (vec![], vec![VarType::Base, VarType::Base]),
241  
242              Opcode::LessThanLoose => (vec![], vec![VarType::Base, VarType::Base]),
243  
244              Opcode::BoolCheck => (vec![], vec![VarType::Base]),
245  
246              Opcode::CondSelect => {
247                  (vec![VarType::Base], vec![VarType::Base, VarType::Base, VarType::Base])
248              }
249  
250              Opcode::ZeroCondSelect => (vec![VarType::Base], vec![VarType::Base, VarType::Base]),
251  
252              Opcode::ConstrainEqualBase => (vec![], vec![VarType::Base, VarType::Base]),
253  
254              Opcode::ConstrainEqualPoint => (vec![], vec![VarType::EcPoint, VarType::EcPoint]),
255  
256              Opcode::ConstrainInstance => (vec![], vec![VarType::Base]),
257  
258              Opcode::DebugPrint => (vec![], vec![VarType::Any]),
259          }
260      }
261  }