/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2024 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use super::VarType; /// Opcodes supported by the zkas VM #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] #[repr(u8)] pub enum Opcode { /// Intermediate opcode for the compiler, should never appear in the result Noop = 0x00, /// Elliptic curve addition EcAdd = 0x01, /// Elliptic curve multiplication EcMul = 0x02, /// Elliptic curve multiplication with a Base field element EcMulBase = 0x03, /// Elliptic curve multiplication with a Base field element of 64bit width EcMulShort = 0x04, /// Variable Elliptic curve multiplication with a Base field element EcMulVarBase = 0x05, /// Get the x coordinate of an elliptic curve point EcGetX = 0x08, /// Get the y coordinate of an elliptic curve point EcGetY = 0x09, /// Poseidon hash of N Base field elements PoseidonHash = 0x10, /// Calculate Merkle root, given a position, Merkle path, and an element MerkleRoot = 0x20, /// Calculate sparse Merkle root, given the position, path and a member SparseMerkleRoot = 0x21, /// Base field element addition BaseAdd = 0x30, /// Base field element multiplication BaseMul = 0x31, /// Base field element subtraction BaseSub = 0x32, /// Witness an unsigned integer into a Base field element WitnessBase = 0x40, /// Range check a Base field element, given bit-width (up to 253) RangeCheck = 0x50, /// Strictly compare two Base field elements and see if a is less than b /// This enforces the sum of remaining bits to be zero. LessThanStrict = 0x51, /// Loosely two Base field elements and see if a is less than b /// This does not enforce the sum of remaining bits to be zero. LessThanLoose = 0x52, /// Check if a field element fits in a boolean (Either 0 or 1) BoolCheck = 0x53, /// Conditionally select between two base field elements given a boolean CondSelect = 0x60, /// Conditionally select between a and b (return a if a is zero, and b if a is nonzero) ZeroCondSelect = 0x61, /// Constrain equality of two Base field elements inside the circuit ConstrainEqualBase = 0xe0, /// Constrain equality of two EcPoint elements inside the circuit ConstrainEqualPoint = 0xe1, /// 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 { 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 { 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, Vec) { 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]) } 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]), } } }