mod opcode;
pub use opcode::*;
mod operand;
pub use operand::*;
mod operation;
pub use operation::*;
mod bytes;
mod parse;
use crate::{RegistersCircuit, RegistersSigner, RegistersTrait, StackTrait, instruction};
use console::{
network::Network,
prelude::{
Debug,
Display,
Error,
Formatter,
FromBytes,
FromStr,
IoResult,
Parser,
ParserResult,
Read,
Result,
Sanitizer,
ToBytes,
Write,
alt,
bail,
ensure,
error,
fmt,
map,
tag,
},
program::{Register, RegisterType},
};
use snarkvm_synthesizer_error::*;
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Instruction<N: Network> {
Abs(Abs<N>),
AbsWrapped(AbsWrapped<N>),
Add(Add<N>),
AddWrapped(AddWrapped<N>),
And(And<N>),
AssertEq(AssertEq<N>),
AssertNeq(AssertNeq<N>),
Async(Async<N>),
Call(Call<N>),
CallDynamic(CallDynamic<N>),
Cast(Cast<N>),
CastLossy(CastLossy<N>),
CommitBHP256(CommitBHP256<N>),
CommitBHP512(CommitBHP512<N>),
CommitBHP768(CommitBHP768<N>),
CommitBHP1024(CommitBHP1024<N>),
CommitPED64(CommitPED64<N>),
CommitPED128(CommitPED128<N>),
DeserializeBits(DeserializeBits<N>),
DeserializeBitsRaw(DeserializeBitsRaw<N>),
Div(Div<N>),
DivWrapped(DivWrapped<N>),
Double(Double<N>),
ECDSAVerifyDigest(ECDSAVerifyDigest<N>),
ECDSAVerifyDigestEth(ECDSAVerifyDigestEth<N>),
ECDSAVerifyKeccak256(ECDSAVerifyKeccak256<N>),
ECDSAVerifyKeccak256Raw(ECDSAVerifyKeccak256Raw<N>),
ECDSAVerifyKeccak256Eth(ECDSAVerifyKeccak256Eth<N>),
ECDSAVerifyKeccak384(ECDSAVerifyKeccak384<N>),
ECDSAVerifyKeccak384Raw(ECDSAVerifyKeccak384Raw<N>),
ECDSAVerifyKeccak384Eth(ECDSAVerifyKeccak384Eth<N>),
ECDSAVerifyKeccak512(ECDSAVerifyKeccak512<N>),
ECDSAVerifyKeccak512Raw(ECDSAVerifyKeccak512Raw<N>),
ECDSAVerifyKeccak512Eth(ECDSAVerifyKeccak512Eth<N>),
ECDSAVerifySha3_256(ECDSAVerifySha3_256<N>),
ECDSAVerifySha3_256Raw(ECDSAVerifySha3_256Raw<N>),
ECDSAVerifySha3_256Eth(ECDSAVerifySha3_256Eth<N>),
ECDSAVerifySha3_384(ECDSAVerifySha3_384<N>),
ECDSAVerifySha3_384Raw(ECDSAVerifySha3_384Raw<N>),
ECDSAVerifySha3_384Eth(ECDSAVerifySha3_384Eth<N>),
ECDSAVerifySha3_512(ECDSAVerifySha3_512<N>),
ECDSAVerifySha3_512Raw(ECDSAVerifySha3_512Raw<N>),
ECDSAVerifySha3_512Eth(ECDSAVerifySha3_512Eth<N>),
GetRecordDynamic(GetRecordDynamic<N>),
GreaterThan(GreaterThan<N>),
GreaterThanOrEqual(GreaterThanOrEqual<N>),
HashBHP256(HashBHP256<N>),
HashBHP256Raw(HashBHP256Raw<N>),
HashBHP512(HashBHP512<N>),
HashBHP512Raw(HashBHP512Raw<N>),
HashBHP768(HashBHP768<N>),
HashBHP768Raw(HashBHP768Raw<N>),
HashBHP1024(HashBHP1024<N>),
HashBHP1024Raw(HashBHP1024Raw<N>),
HashKeccak256(HashKeccak256<N>),
HashKeccak256Raw(HashKeccak256Raw<N>),
HashKeccak256Native(HashKeccak256Native<N>),
HashKeccak256NativeRaw(HashKeccak256NativeRaw<N>),
HashKeccak384(HashKeccak384<N>),
HashKeccak384Raw(HashKeccak384Raw<N>),
HashKeccak384Native(HashKeccak384Native<N>),
HashKeccak384NativeRaw(HashKeccak384NativeRaw<N>),
HashKeccak512(HashKeccak512<N>),
HashKeccak512Raw(HashKeccak512Raw<N>),
HashKeccak512Native(HashKeccak512Native<N>),
HashKeccak512NativeRaw(HashKeccak512NativeRaw<N>),
HashPED64(HashPED64<N>),
HashPED64Raw(HashPED64Raw<N>),
HashPED128(HashPED128<N>),
HashPED128Raw(HashPED128Raw<N>),
HashPSD2(HashPSD2<N>),
HashPSD2Raw(HashPSD2Raw<N>),
HashPSD4(HashPSD4<N>),
HashPSD4Raw(HashPSD4Raw<N>),
HashPSD8(HashPSD8<N>),
HashPSD8Raw(HashPSD8Raw<N>),
HashSha3_256(HashSha3_256<N>),
HashSha3_256Raw(HashSha3_256Raw<N>),
HashSha3_256Native(HashSha3_256Native<N>),
HashSha3_256NativeRaw(HashSha3_256NativeRaw<N>),
HashSha3_384(HashSha3_384<N>),
HashSha3_384Raw(HashSha3_384Raw<N>),
HashSha3_384Native(HashSha3_384Native<N>),
HashSha3_384NativeRaw(HashSha3_384NativeRaw<N>),
HashSha3_512(HashSha3_512<N>),
HashSha3_512Raw(HashSha3_512Raw<N>),
HashSha3_512Native(HashSha3_512Native<N>),
HashSha3_512NativeRaw(HashSha3_512NativeRaw<N>),
HashManyPSD2(HashManyPSD2<N>),
HashManyPSD4(HashManyPSD4<N>),
HashManyPSD8(HashManyPSD8<N>),
Inv(Inv<N>),
IsEq(IsEq<N>),
IsNeq(IsNeq<N>),
LessThan(LessThan<N>),
LessThanOrEqual(LessThanOrEqual<N>),
Modulo(Modulo<N>),
Mul(Mul<N>),
MulWrapped(MulWrapped<N>),
Nand(Nand<N>),
Neg(Neg<N>),
Nor(Nor<N>),
Not(Not<N>),
Or(Or<N>),
Pow(Pow<N>),
PowWrapped(PowWrapped<N>),
Rem(Rem<N>),
RemWrapped(RemWrapped<N>),
SerializeBits(SerializeBits<N>),
SerializeBitsRaw(SerializeBitsRaw<N>),
Shl(Shl<N>),
ShlWrapped(ShlWrapped<N>),
Shr(Shr<N>),
ShrWrapped(ShrWrapped<N>),
SignVerify(SignVerify<N>),
SnarkVerify(SnarkVerify<N>),
SnarkVerifyBatch(SnarkVerifyBatch<N>),
Square(Square<N>),
SquareRoot(SquareRoot<N>),
Sub(Sub<N>),
SubWrapped(SubWrapped<N>),
Ternary(Ternary<N>),
Xor(Xor<N>),
}
#[macro_export]
macro_rules! instruction {
($object:expr, |$input:ident| $operation:block) => {{ $crate::instruction!(instruction, $object, |$input| $operation) }};
($object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!(instruction, $object, |$input| { $operation }) }};
($macro_:ident, $object:expr, |$input:ident| $operation:block) => {
$macro_!{$object, |$input| $operation, {
Abs,
AbsWrapped,
Add,
AddWrapped,
And,
AssertEq,
AssertNeq,
Async,
Call,
Cast,
CastLossy,
CommitBHP256,
CommitBHP512,
CommitBHP768,
CommitBHP1024,
CommitPED64,
CommitPED128,
Div,
DivWrapped,
Double,
GreaterThan,
GreaterThanOrEqual,
HashBHP256,
HashBHP512,
HashBHP768,
HashBHP1024,
HashKeccak256,
HashKeccak384,
HashKeccak512,
HashPED64,
HashPED128,
HashPSD2,
HashPSD4,
HashPSD8,
HashSha3_256,
HashSha3_384,
HashSha3_512,
HashManyPSD2,
HashManyPSD4,
HashManyPSD8,
Inv,
IsEq,
IsNeq,
LessThan,
LessThanOrEqual,
Modulo,
Mul,
MulWrapped,
Nand,
Neg,
Nor,
Not,
Or,
Pow,
PowWrapped,
Rem,
RemWrapped,
Shl,
ShlWrapped,
Shr,
ShrWrapped,
SignVerify,
Square,
SquareRoot,
Sub,
SubWrapped,
Ternary,
Xor,
DeserializeBits,
DeserializeBitsRaw,
ECDSAVerifyDigest,
ECDSAVerifyDigestEth,
ECDSAVerifyKeccak256,
ECDSAVerifyKeccak256Raw,
ECDSAVerifyKeccak256Eth,
ECDSAVerifyKeccak384,
ECDSAVerifyKeccak384Raw,
ECDSAVerifyKeccak384Eth,
ECDSAVerifyKeccak512,
ECDSAVerifyKeccak512Raw,
ECDSAVerifyKeccak512Eth,
ECDSAVerifySha3_256,
ECDSAVerifySha3_256Raw,
ECDSAVerifySha3_256Eth,
ECDSAVerifySha3_384,
ECDSAVerifySha3_384Raw,
ECDSAVerifySha3_384Eth,
ECDSAVerifySha3_512,
ECDSAVerifySha3_512Raw,
ECDSAVerifySha3_512Eth,
HashBHP256Raw,
HashBHP512Raw,
HashBHP768Raw,
HashBHP1024Raw,
HashKeccak256Raw,
HashKeccak256Native,
HashKeccak256NativeRaw,
HashKeccak384Raw,
HashKeccak384Native,
HashKeccak384NativeRaw,
HashKeccak512Raw,
HashKeccak512Native,
HashKeccak512NativeRaw,
HashPED64Raw,
HashPED128Raw,
HashPSD2Raw,
HashPSD4Raw,
HashPSD8Raw,
HashSha3_256Raw,
HashSha3_256Native,
HashSha3_256NativeRaw,
HashSha3_384Raw,
HashSha3_384Native,
HashSha3_384NativeRaw,
HashSha3_512Raw,
HashSha3_512Native,
HashSha3_512NativeRaw,
SerializeBits,
SerializeBitsRaw,
CallDynamic,
GetRecordDynamic,
SnarkVerify,
SnarkVerifyBatch,
}}
};
($macro_:ident, $object:expr, |$input:ident| $operation:expr) => {{ $crate::instruction!($macro_, $object, |$input| { $operation }) }};
($macro_:ident!($object:expr, $input:ident)) => {{ $crate::instruction!($macro_, $object, |$input| {}) }};
($object:expr, |InstructionMember| $operation:block, { $( $variant:ident, )+ }) => {{
match $object {
$( Self::$variant(..) => {{
type InstructionMember<N> = $variant<N>;
$operation
}} ),+
}
}};
($object:expr, |InstructionMember| $operation:expr, { $( $variant:ident, )+ }) => {{
$crate::instruction!($object, |InstructionMember| { $operation }, { $( $variant, )+ })
}};
($object:expr, |$instruction:ident| $operation:block, { $( $variant:ident, )+ }) => {{
match $object { $( Self::$variant($instruction) => { $operation } ),+ }
}};
($object:expr, |$instruction:ident| $operation:expr, { $( $variant:ident, )+ }) => {{
$crate::instruction!($object, |$instruction| { $operation }, { $( $variant, )+ })
}};
}
macro_rules! derive_from_operation {
($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => {
$(impl<N: Network> From<$variant<N>> for Instruction<N> {
#[inline]
fn from(operation: $variant<N>) -> Self {
Self::$variant(operation)
}
})+
}
}
instruction!(derive_from_operation, Instruction, |None| {});
macro_rules! opcodes {
($_object:expr, |$_reader:ident| $_operation:block, { $( $variant:ident, )+ }) => { [$( $variant::<N>::opcode() ),+] }
}
impl<N: Network> Instruction<N> {
pub const OPCODES: &'static [Opcode] = &instruction!(opcodes, Instruction, |None| {});
pub fn is_reserved_opcode(name: &str) -> bool {
Instruction::<N>::OPCODES.iter().any(|opcode| **opcode == name)
}
#[inline]
pub fn operands(&self) -> &[Operand<N>] {
instruction!(self, |instruction| instruction.operands())
}
#[inline]
pub fn destinations(&self) -> Vec<Register<N>> {
instruction!(self, |instruction| instruction.destinations())
}
#[inline]
pub fn call_operator(&self) -> Option<&CallOperator<N>> {
match self {
Self::Call(call) => Some(call.operator()),
_ => None,
}
}
#[inline]
pub const fn opcode(&self) -> Opcode {
instruction!(self, |InstructionMember| InstructionMember::<N>::opcode())
}
#[allow(clippy::useless_conversion)]
#[inline]
pub fn evaluate(
&self,
stack: &impl StackTrait<N>,
registers: &mut impl RegistersSigner<N>,
) -> Result<(), EvalError> {
instruction!(self, |instruction| instruction.evaluate(stack, registers).map_err(Into::into))
}
#[allow(clippy::useless_conversion)]
#[inline]
pub fn execute<A: circuit::Aleo<Network = N>>(
&self,
stack: &impl StackTrait<N>,
registers: &mut impl RegistersCircuit<N, A>,
) -> Result<(), ExecError> {
instruction!(self, |instruction| instruction.execute::<A>(stack, registers).map_err(Into::into))
}
#[allow(clippy::useless_conversion)]
#[inline]
pub fn finalize(
&self,
stack: &impl StackTrait<N>,
registers: &mut impl RegistersTrait<N>,
) -> Result<(), FinalizeError> {
instruction!(self, |instruction| instruction.finalize(stack, registers).map_err(Into::into))
}
#[inline]
pub fn output_types(
&self,
stack: &impl StackTrait<N>,
input_types: &[RegisterType<N>],
) -> Result<Vec<RegisterType<N>>> {
instruction!(self, |instruction| instruction.output_types(stack, input_types))
}
pub fn contains_external_struct(&self) -> bool {
instruction!(self, |instruction| instruction.contains_external_struct())
}
pub fn contains_string_type(&self) -> bool {
self.operands().iter().any(|operand| operand.contains_string_type())
}
pub fn contains_identifier_type(&self) -> Result<bool> {
match self {
Self::Cast(instruction) => instruction.cast_type().contains_identifier_type(),
Self::CastLossy(instruction) => instruction.cast_type().contains_identifier_type(),
Self::SerializeBits(instruction) => instruction.operand_type().contains_identifier_type(),
Self::SerializeBitsRaw(instruction) => instruction.operand_type().contains_identifier_type(),
Self::DeserializeBits(instruction) => instruction.destination_type().contains_identifier_type(),
Self::DeserializeBitsRaw(instruction) => instruction.destination_type().contains_identifier_type(),
_ => Ok(false),
}
}
pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
match self {
Self::Cast(instruction) => instruction.cast_type().exceeds_max_array_size(max_array_size),
Self::SerializeBits(instruction) => instruction.destination_type().exceeds_max_array_size(max_array_size),
Self::SerializeBitsRaw(instruction) => {
instruction.destination_type().exceeds_max_array_size(max_array_size)
}
Self::DeserializeBits(instruction) => instruction.operand_type().exceeds_max_array_size(max_array_size),
Self::DeserializeBitsRaw(instruction) => instruction.operand_type().exceeds_max_array_size(max_array_size),
_ => false,
}
}
}
impl<N: Network> Debug for Instruction<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl<N: Network> Display for Instruction<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
instruction!(self, |instruction| write!(f, "{instruction};"))
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::MainnetV0;
type CurrentNetwork = MainnetV0;
#[test]
fn test_opcodes() {
assert_eq!(
123,
Instruction::<CurrentNetwork>::OPCODES.len(),
"Update me if the number of instructions changes."
);
}
}