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 }