diff --git a/crates/specs/src/configure_table.rs b/crates/specs/src/configure_table.rs index a62c0a88f..3bff0ec57 100644 --- a/crates/specs/src/configure_table.rs +++ b/crates/specs/src/configure_table.rs @@ -4,7 +4,8 @@ use serde::Serialize; // A wasm page size is 64KB pub const WASM_BYTES_PER_PAGE: u64 = 64 * 1024_u64; -const WASM_32_MAXIMAL_PAGES_DEFAULT: u32 = 65536; +// Limit page size in u16 range +pub const WASM_32_MAXIMAL_PAGES_DEFAULT: u32 = 65535; #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct ConfigureTable { diff --git a/crates/specs/src/encode/br_table.rs b/crates/specs/src/encode/br_table.rs index fdd9db877..3124d28f2 100644 --- a/crates/specs/src/encode/br_table.rs +++ b/crates/specs/src/encode/br_table.rs @@ -1,17 +1,23 @@ use num_bigint::BigUint; +use static_assertions::const_assert; use crate::brtable::BrTableEntry; use crate::brtable::ElemEntry; use crate::brtable::IndirectClass; -use crate::encode::COMMON_RANGE_OFFSET; +use crate::encode::instruction_table::FID_BITS; +use crate::encode::instruction_table::IID_BITS; +use crate::encode::COMMON_RANGE_BITS; use super::FromBn; +const INDIRECT_CLASS_SHIFT: u32 = 192; lazy_static! { - static ref INDIRECT_CLASS_SHIFT: BigUint = BigUint::from(1u64) << 192; + static ref INDIRECT_CLASS_SHIFT_BN: BigUint = BigUint::from(1u64) << 192; } -pub(crate) const BR_TABLE_ENCODE_BOUNDARY: u32 = 224; +pub const BR_TABLE_ENCODE_BOUNDARY: u32 = 224; +// Tag only include 1 bit(BrTable or Elem) +const_assert!(INDIRECT_CLASS_SHIFT < BR_TABLE_ENCODE_BOUNDARY); pub fn encode_br_table_entry( fid: T, @@ -21,16 +27,17 @@ pub fn encode_br_table_entry( keep: T, dst_pc: T, ) -> T { - const FID_SHIFT: u32 = IID_SHIFT + COMMON_RANGE_OFFSET; - const IID_SHIFT: u32 = INDEX_SHIFT + COMMON_RANGE_OFFSET; - const INDEX_SHIFT: u32 = DROP_SHIFT + COMMON_RANGE_OFFSET; - const DROP_SHIFT: u32 = KEEP_SHIFT + COMMON_RANGE_OFFSET; - const KEEP_SHIFT: u32 = DST_PC_SHIFT + COMMON_RANGE_OFFSET; + const FID_SHIFT: u32 = IID_SHIFT + IID_BITS; + const IID_SHIFT: u32 = INDEX_SHIFT + COMMON_RANGE_BITS; + const INDEX_SHIFT: u32 = DROP_SHIFT + COMMON_RANGE_BITS; + const DROP_SHIFT: u32 = KEEP_SHIFT + COMMON_RANGE_BITS; + const KEEP_SHIFT: u32 = DST_PC_SHIFT + COMMON_RANGE_BITS; const DST_PC_SHIFT: u32 = 0; - assert!(FID_SHIFT + COMMON_RANGE_OFFSET <= BR_TABLE_ENCODE_BOUNDARY); + assert!(FID_SHIFT + FID_BITS <= INDIRECT_CLASS_SHIFT); - T::from_bn(&(BigUint::from(IndirectClass::BrTable as u64))) * T::from_bn(&INDIRECT_CLASS_SHIFT) + T::from_bn(&(BigUint::from(IndirectClass::BrTable as u64))) + * T::from_bn(&INDIRECT_CLASS_SHIFT_BN) + fid * T::from_bn(&(BigUint::from(1u64) << FID_SHIFT)) + iid * T::from_bn(&(BigUint::from(1u64) << IID_SHIFT)) + index * T::from_bn(&(BigUint::from(1u64) << INDEX_SHIFT)) @@ -40,15 +47,15 @@ pub fn encode_br_table_entry( } pub fn encode_elem_entry(table_idx: T, type_idx: T, offset: T, func_idx: T) -> T { - const TABLE_INDEX_SHIFT: u32 = TYPE_INDEX_SHIFT + COMMON_RANGE_OFFSET; - const TYPE_INDEX_SHIFT: u32 = OFFSET_SHIFT + COMMON_RANGE_OFFSET; - const OFFSET_SHIFT: u32 = FUNC_INDEX + COMMON_RANGE_OFFSET; + const TABLE_INDEX_SHIFT: u32 = TYPE_INDEX_SHIFT + COMMON_RANGE_BITS; + const TYPE_INDEX_SHIFT: u32 = OFFSET_SHIFT + COMMON_RANGE_BITS; + const OFFSET_SHIFT: u32 = FUNC_INDEX + FID_BITS; const FUNC_INDEX: u32 = 0; - assert!(TABLE_INDEX_SHIFT + COMMON_RANGE_OFFSET <= BR_TABLE_ENCODE_BOUNDARY); + assert!(TABLE_INDEX_SHIFT + COMMON_RANGE_BITS <= INDIRECT_CLASS_SHIFT); T::from_bn(&(BigUint::from(IndirectClass::CallIndirect as u64))) - * T::from_bn(&INDIRECT_CLASS_SHIFT) + * T::from_bn(&INDIRECT_CLASS_SHIFT_BN) + table_idx * T::from_bn(&(BigUint::from(1u64) << TABLE_INDEX_SHIFT)) + type_idx * T::from_bn(&(BigUint::from(1u64) << TYPE_INDEX_SHIFT)) + offset * T::from_bn(&(BigUint::from(1u64) << OFFSET_SHIFT)) diff --git a/crates/specs/src/encode/frame_table.rs b/crates/specs/src/encode/frame_table.rs index 36153b6e9..4a0b5145a 100644 --- a/crates/specs/src/encode/frame_table.rs +++ b/crates/specs/src/encode/frame_table.rs @@ -1,7 +1,7 @@ use num_bigint::BigUint; use num_bigint::ToBigUint; -use crate::encode::COMMON_RANGE_OFFSET; +use crate::encode::COMMON_RANGE_BITS; use crate::jtable::CalledFrameTableEntry; use crate::jtable::FrameTableEntryInternal; use crate::jtable::InheritedFrameTableEntry; @@ -15,10 +15,10 @@ pub fn encode_frame_table_entry( fid: T, iid: T, ) -> T { - const FRAME_ID_SHIFT: u32 = LAST_JUMP_FRAME_ID_SHIFT + COMMON_RANGE_OFFSET; - const LAST_JUMP_FRAME_ID_SHIFT: u32 = CALLEE_FID + COMMON_RANGE_OFFSET; - const CALLEE_FID: u32 = FID_SHIFT + COMMON_RANGE_OFFSET; - const FID_SHIFT: u32 = IID_SHIFT + COMMON_RANGE_OFFSET; + const FRAME_ID_SHIFT: u32 = LAST_JUMP_FRAME_ID_SHIFT + COMMON_RANGE_BITS; + const LAST_JUMP_FRAME_ID_SHIFT: u32 = CALLEE_FID + COMMON_RANGE_BITS; + const CALLEE_FID: u32 = FID_SHIFT + COMMON_RANGE_BITS; + const FID_SHIFT: u32 = IID_SHIFT + COMMON_RANGE_BITS; const IID_SHIFT: u32 = 0; frame_id * T::from_bn(&(1u64.to_biguint().unwrap() << FRAME_ID_SHIFT)) diff --git a/crates/specs/src/encode/image_table.rs b/crates/specs/src/encode/image_table.rs index 49c64aa90..16812d973 100644 --- a/crates/specs/src/encode/image_table.rs +++ b/crates/specs/src/encode/image_table.rs @@ -8,7 +8,7 @@ use crate::encode::instruction_table::INSTRUCTION_ENCODE_BOUNDARY; use super::FromBn; -const CLASS_SHIFT: u32 = 224; +const CLASS_SHIFT: u32 = 250; #[derive(Clone, Copy)] pub enum ImageTableEncoder { @@ -22,7 +22,7 @@ const_assert!(BR_TABLE_ENCODE_BOUNDARY <= CLASS_SHIFT); const_assert!(INIT_MEMORY_ENCODE_BOUNDARY <= CLASS_SHIFT); lazy_static! { - static ref INSTRUCTION_TAG: BigUint = (ImageTableEncoder::Instruction as u64) + pub static ref INSTRUCTION_TAG: BigUint = (ImageTableEncoder::Instruction as u64) .to_biguint() .unwrap() << CLASS_SHIFT; diff --git a/crates/specs/src/encode/instruction_table.rs b/crates/specs/src/encode/instruction_table.rs index d3a686241..1f860e7fd 100644 --- a/crates/specs/src/encode/instruction_table.rs +++ b/crates/specs/src/encode/instruction_table.rs @@ -1,21 +1,22 @@ use num_bigint::BigUint; use num_bigint::ToBigUint; +use static_assertions::const_assert; -use crate::encode::COMMON_RANGE_OFFSET; use crate::itable::InstructionTableEntry; use crate::itable::Opcode; use crate::itable::OPCODE_SHIFT; use super::FromBn; -pub(crate) const INSTRUCTION_ENCODE_BOUNDARY: u32 = 224; +pub const INSTRUCTION_ENCODE_BOUNDARY: u32 = 250; +pub(crate) const IID_BITS: u32 = 16; +pub(crate) const FID_BITS: u32 = 16; +const_assert!(OPCODE_SHIFT + IID_BITS + FID_BITS <= INSTRUCTION_ENCODE_BOUNDARY); pub fn encode_instruction_table_entry(fid: T, iid: T, opcode: T) -> T { - const FID_SHIFT: u32 = IID_SHIFT + COMMON_RANGE_OFFSET; + const FID_SHIFT: u32 = IID_SHIFT + IID_BITS; const IID_SHIFT: u32 = OPCODE_SHIFT; - assert!(FID_SHIFT + COMMON_RANGE_OFFSET <= INSTRUCTION_ENCODE_BOUNDARY); - fid * T::from_bn(&(1u64.to_biguint().unwrap() << FID_SHIFT)) + iid * T::from_bn(&(1u64.to_biguint().unwrap() << IID_SHIFT)) + opcode @@ -23,6 +24,9 @@ pub fn encode_instruction_table_entry(fid: T, iid: T, opcode: T) -> T impl InstructionTableEntry { pub(crate) fn encode(fid: u32, iid: u32, opcode: &Opcode) -> BigUint { + assert!(fid <= 1 << FID_BITS); + assert!(iid <= 1 << IID_BITS); + encode_instruction_table_entry(BigUint::from(fid), BigUint::from(iid), opcode.into()) } } diff --git a/crates/specs/src/encode/memory_table.rs b/crates/specs/src/encode/memory_table.rs index 08034f05a..f9a21e412 100644 --- a/crates/specs/src/encode/memory_table.rs +++ b/crates/specs/src/encode/memory_table.rs @@ -3,10 +3,10 @@ use num_traits::One; use static_assertions::const_assert; use super::FromBn; -use crate::encode::COMMON_RANGE_OFFSET; +use crate::encode::COMMON_RANGE_BITS; -const _END_SHIFT: u32 = OFFSET_SHIFT + COMMON_RANGE_OFFSET; -const OFFSET_SHIFT: u32 = LOCATION_TYPE_SHIFT + COMMON_RANGE_OFFSET; +const _END_SHIFT: u32 = OFFSET_SHIFT + COMMON_RANGE_BITS; +const OFFSET_SHIFT: u32 = LOCATION_TYPE_SHIFT + COMMON_RANGE_BITS; const LOCATION_TYPE_SHIFT: u32 = IS_I32_SHIFT + 1; const IS_I32_SHIFT: u32 = 0; diff --git a/crates/specs/src/encode/mod.rs b/crates/specs/src/encode/mod.rs index addd2db6c..c215ca623 100644 --- a/crates/specs/src/encode/mod.rs +++ b/crates/specs/src/encode/mod.rs @@ -13,7 +13,7 @@ pub mod instruction_table; pub mod memory_table; pub mod opcode; -pub(crate) const COMMON_RANGE_OFFSET: u32 = 32; +pub(crate) const COMMON_RANGE_BITS: u32 = 32; pub trait FromBn: Sized + Add + Mul { fn zero() -> Self; diff --git a/crates/specs/src/encode/opcode.rs b/crates/specs/src/encode/opcode.rs index fcdf96898..108e12033 100644 --- a/crates/specs/src/encode/opcode.rs +++ b/crates/specs/src/encode/opcode.rs @@ -1,60 +1,338 @@ use num_bigint::BigUint; +use num_traits::One; +use crate::itable::Opcode; use crate::itable::OpcodeClass; -use crate::itable::OPCODE_ARG0_SHIFT as OPCODE_ARG0; -use crate::itable::OPCODE_ARG1_SHIFT as OPCODE_ARG1; +use crate::itable::OpcodeClassPlain; +use crate::itable::UniArg; use crate::itable::OPCODE_CLASS_SHIFT as OPCODE_CLASS; +use super::instruction_table::FID_BITS; use super::FromBn; +const UNIARG_BITS: u32 = 66; + lazy_static! { static ref OPCODE_CLASS_SHIFT: BigUint = BigUint::from(1u64) << OPCODE_CLASS; - static ref OPCODE_ARG0_SHIFT: BigUint = BigUint::from(1u64) << OPCODE_ARG0; - static ref OPCODE_ARG1_SHIFT: BigUint = BigUint::from(1u64) << OPCODE_ARG1; + static ref OPCODE_U64_SHIFT: BigUint = BigUint::one() << u64::BITS; + static ref OPCODE_U32_SHIFT: BigUint = BigUint::one() << u32::BITS; + static ref OPCODE_UNIARG_SHIFT: BigUint = BigUint::from(1u64) << UNIARG_BITS; + static ref OPCODE_FUNC_SHIFT: BigUint = BigUint::one() << FID_BITS; + static ref OPCODE_BIT_SHIFT: BigUint = BigUint::one() << 1; +} + +enum EncoderType { + U64, + U32, + Func, + Bit, +} + +impl EncoderType { + fn bits(&self) -> u32 { + match self { + EncoderType::U64 => u64::BITS, + EncoderType::U32 => u32::BITS, + EncoderType::Func => FID_BITS, + EncoderType::Bit => 1, + } + } + + fn shift(&self) -> &BigUint { + match self { + EncoderType::U64 => &OPCODE_U64_SHIFT, + EncoderType::U32 => &OPCODE_U32_SHIFT, + EncoderType::Func => &OPCODE_FUNC_SHIFT, + EncoderType::Bit => &OPCODE_BIT_SHIFT, + } + } +} + +pub enum UniArgEncode { + Reserve, + Value([T; N]), +} + +impl From<&UniArg> for UniArgEncode<1, BigUint> { + fn from(uniarg: &UniArg) -> Self { + UniArgEncode::Value([uniarg.encode()]) + } +} + +impl From<&[UniArg; N]> for UniArgEncode { + fn from(uniargs: &[UniArg; N]) -> Self { + UniArgEncode::Value( + uniargs + .iter() + .map(|uniarg| uniarg.encode()) + .collect::>() + .try_into() + .unwrap(), + ) + } +} + +struct Encoder; + +impl Encoder { + fn encode_without_uniarg( + opcode_class: OpcodeClass, + values: Vec<(T, EncoderType)>, + ) -> T { + let mut encode = T::zero(); + let mut bits = 0; + + for (value, encoder_type) in values { + encode = encode * T::from_bn(encoder_type.shift()) + value; + bits += encoder_type.bits(); + } + + assert!(bits <= OPCODE_CLASS); + + T::from_bn(&(BigUint::from(opcode_class as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) + encode + } + + fn encode( + opcode_class: OpcodeClass, + values: Vec<(T, EncoderType)>, + uniargs: UniArgEncode, + ) -> T { + let mut encode = T::zero(); + let mut bits = 0; + + for (value, encoder_type) in values { + encode = encode * T::from_bn(encoder_type.shift()) + value; + bits += encoder_type.bits(); + } + + match uniargs { + UniArgEncode::Reserve => { + for _ in 0..N { + encode = encode * T::from_bn(&OPCODE_UNIARG_SHIFT); + bits += UNIARG_BITS; + } + } + UniArgEncode::Value(uniargs) => { + for uniarg in uniargs.into_iter() { + encode = encode * T::from_bn(&OPCODE_UNIARG_SHIFT) + uniarg; + bits += UNIARG_BITS; + } + } + } + + assert!(bits <= OPCODE_CLASS); + + T::from_bn(&(BigUint::from(opcode_class as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) + encode + } +} + +pub fn encode_local_get(vtype: T, offset: T) -> T { + Encoder::encode_without_uniarg( + OpcodeClass::LocalGet, + vec![(vtype, EncoderType::Bit), (offset, EncoderType::U32)], + ) +} + +pub fn encode_local_set(vtype: T, offset: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::LocalSet, + vec![(vtype, EncoderType::Bit), (offset, EncoderType::U32)], + uniarg, + ) +} + +pub fn encode_local_tee(vtype: T, offset: T) -> T { + Encoder::encode_without_uniarg( + OpcodeClass::LocalTee, + vec![(vtype, EncoderType::Bit), (offset, EncoderType::U32)], + ) } pub fn encode_global_get(globalidx: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::GlobalGet as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + globalidx + Encoder::encode_without_uniarg(OpcodeClass::GlobalGet, vec![(globalidx, EncoderType::U32)]) +} + +pub fn encode_global_set(globalidx: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::GlobalSet, + vec![(globalidx, EncoderType::U32)], + uniarg, + ) +} + +pub fn encode_const(vtype: T, value: T) -> T { + Encoder::encode_without_uniarg( + OpcodeClass::Const, + vec![(vtype, EncoderType::Bit), (value, EncoderType::U64)], + ) } -pub fn encode_global_set(globalidx: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::GlobalSet as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + globalidx +pub fn encode_drop() -> T { + Encoder::encode_without_uniarg(OpcodeClass::Drop, vec![]) +} + +pub fn encode_select(uniargs: UniArgEncode<3, T>) -> T { + Encoder::encode(OpcodeClass::Select, vec![], uniargs) +} + +pub fn encode_return(drop: T, keep: T, vtype: T) -> T { + Encoder::encode_without_uniarg( + OpcodeClass::Return, + vec![ + (drop, EncoderType::U32), + (keep, EncoderType::U32), + (vtype, EncoderType::Bit), + ], + ) +} + +pub fn encode_bin(class: T, vtype: T, uniargs: UniArgEncode<2, T>) -> T { + Encoder::encode( + OpcodeClass::Bin, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniargs, + ) +} + +pub fn encode_bin_shift(class: T, vtype: T, uniargs: UniArgEncode<2, T>) -> T { + Encoder::encode( + OpcodeClass::BinShift, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniargs, + ) +} + +pub fn encode_bin_bit(class: T, vtype: T, uniargs: UniArgEncode<2, T>) -> T { + Encoder::encode( + OpcodeClass::BinBit, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniargs, + ) +} + +pub fn encode_unary(class: T, vtype: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::Unary, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniarg, + ) +} + +pub fn encode_test(class: T, vtype: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::Test, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniarg, + ) +} + +pub fn encode_rel(class: T, vtype: T, uniargs: UniArgEncode<2, T>) -> T { + Encoder::encode( + OpcodeClass::Rel, + vec![(class, EncoderType::U32), (vtype, EncoderType::Bit)], + uniargs, + ) +} + +pub fn encode_br(drop: T, keep: T, dst_pc: T) -> T { + Encoder::encode_without_uniarg( + OpcodeClass::Br, + vec![ + (drop, EncoderType::U32), + (keep, EncoderType::U32), + (dst_pc, EncoderType::U32), + ], + ) +} + +pub fn encode_br_if(drop: T, keep: T, dst_pc: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::BrIf, + vec![ + (drop, EncoderType::U32), + (keep, EncoderType::U32), + (dst_pc, EncoderType::U32), + ], + uniarg, + ) +} + +pub fn encode_br_if_eqz(drop: T, keep: T, dst_pc: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::BrIfEqz, + vec![ + (drop, EncoderType::U32), + (keep, EncoderType::U32), + (dst_pc, EncoderType::U32), + ], + uniarg, + ) +} + +pub fn encode_br_table(len: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode(OpcodeClass::BrTable, vec![(len, EncoderType::U32)], uniarg) +} + +pub fn encode_unreachable() -> T { + Encoder::encode_without_uniarg(OpcodeClass::Unreachable, vec![]) } pub fn encode_call(function_index: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::Call as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + function_index * T::from_bn(&OPCODE_ARG0_SHIFT) + Encoder::encode_without_uniarg(OpcodeClass::Call, vec![(function_index, EncoderType::Func)]) } -pub fn encode_call_indirect(type_index: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::CallIndirect as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + type_index * T::from_bn(&OPCODE_ARG0_SHIFT) +pub fn encode_call_indirect(type_index: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::CallIndirect, + vec![(type_index, EncoderType::U32)], + uniarg, + ) } pub fn encode_call_host(op: T, is_ret: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::CallHost as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + op * T::from_bn(&OPCODE_ARG0_SHIFT) - + is_ret * T::from_bn(&OPCODE_ARG1_SHIFT) + Encoder::encode_without_uniarg( + OpcodeClass::CallHost, + vec![(op, EncoderType::U32), (is_ret, EncoderType::Bit)], + ) } -pub fn encode_br(drop: T, keep: T, dst_pc: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::Br as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + drop * T::from_bn(&OPCODE_ARG0_SHIFT) - + keep * T::from_bn(&OPCODE_ARG1_SHIFT) - + dst_pc +pub fn encode_call_internal_host(opcode: &Opcode, op_index_in_plugin: usize) -> T { + let opcode_class_plain: OpcodeClassPlain = opcode.into(); + + T::from_bn(&(BigUint::from(opcode_class_plain.0) << OPCODE_CLASS)) + + T::from_bn(&BigUint::from(op_index_in_plugin as u64)) +} + +pub fn encode_load(vtype: T, size: T, offset: T, uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode( + OpcodeClass::Load, + vec![ + (vtype, EncoderType::U32), + (size, EncoderType::U32), + (offset, EncoderType::U32), + ], + uniarg, + ) +} + +pub fn encode_store(vtype: T, size: T, offset: T, uniargs: UniArgEncode<2, T>) -> T { + Encoder::encode( + OpcodeClass::Store, + vec![ + (vtype, EncoderType::Bit), + (size, EncoderType::U32), + (offset, EncoderType::U32), + ], + uniargs, + ) } -pub fn encode_br_if_eqz(drop: T, keep: T, dst_pc: T) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::BrIfEqz as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + drop * T::from_bn(&OPCODE_ARG0_SHIFT) - + keep * T::from_bn(&OPCODE_ARG1_SHIFT) - + dst_pc +pub fn encode_memory_size() -> T { + Encoder::encode_without_uniarg(OpcodeClass::MemorySize, vec![]) } -pub fn encode_br_table(len: T) -> T { - T::from_bn(&BigUint::from(OpcodeClass::BrTable as u64)) + len +pub fn encode_memory_grow(uniarg: UniArgEncode<1, T>) -> T { + Encoder::encode(OpcodeClass::MemoryGrow, vec![], uniarg) } pub fn encode_conversion( @@ -66,14 +344,20 @@ pub fn encode_conversion( value_is_i64: T, res_is_i32: T, res_is_i64: T, + uniarg: UniArgEncode<1, T>, ) -> T { - T::from_bn(&(BigUint::from(OpcodeClass::Conversion as u64))) * T::from_bn(&OPCODE_CLASS_SHIFT) - + sign * T::from_bn(&BigUint::from(1u64 << 7)) - + value_type_is_i32 * T::from_bn(&BigUint::from(1u64 << 6)) - + value_is_i8 * T::from_bn(&BigUint::from(1u64 << 5)) - + value_is_i16 * T::from_bn(&BigUint::from(1u64 << 4)) - + value_is_i32 * T::from_bn(&BigUint::from(1u64 << 3)) - + value_is_i64 * T::from_bn(&BigUint::from(1u64 << 2)) - + res_is_i32 * T::from_bn(&BigUint::from(1u64 << 1)) - + res_is_i64 + Encoder::encode( + OpcodeClass::Conversion, + vec![ + (sign, EncoderType::Bit), + (value_type_is_i32, EncoderType::Bit), + (value_is_i8, EncoderType::Bit), + (value_is_i16, EncoderType::Bit), + (value_is_i32, EncoderType::Bit), + (value_is_i64, EncoderType::Bit), + (res_is_i32, EncoderType::Bit), + (res_is_i64, EncoderType::Bit), + ], + uniarg, + ) } diff --git a/crates/specs/src/itable.rs b/crates/specs/src/itable.rs index a4ae73e8d..2461d3ac4 100644 --- a/crates/specs/src/itable.rs +++ b/crates/specs/src/itable.rs @@ -1,23 +1,47 @@ use super::mtable::VarType; use crate::brtable::BrTable; use crate::brtable::BrTableEntry; +use crate::encode::opcode::encode_bin; +use crate::encode::opcode::encode_bin_bit; +use crate::encode::opcode::encode_bin_shift; +use crate::encode::opcode::encode_br; +use crate::encode::opcode::encode_br_if; use crate::encode::opcode::encode_br_if_eqz; use crate::encode::opcode::encode_br_table; use crate::encode::opcode::encode_call; use crate::encode::opcode::encode_call_host; use crate::encode::opcode::encode_call_indirect; +use crate::encode::opcode::encode_call_internal_host; +use crate::encode::opcode::encode_const; use crate::encode::opcode::encode_conversion; +use crate::encode::opcode::encode_drop; use crate::encode::opcode::encode_global_get; use crate::encode::opcode::encode_global_set; -use crate::encode::COMMON_RANGE_OFFSET; +use crate::encode::opcode::encode_load; +use crate::encode::opcode::encode_local_get; +use crate::encode::opcode::encode_local_set; +use crate::encode::opcode::encode_local_tee; +use crate::encode::opcode::encode_memory_grow; +use crate::encode::opcode::encode_memory_size; +use crate::encode::opcode::encode_rel; +use crate::encode::opcode::encode_return; +use crate::encode::opcode::encode_select; +use crate::encode::opcode::encode_store; +use crate::encode::opcode::encode_test; +use crate::encode::opcode::encode_unary; +use crate::encode::opcode::encode_unreachable; use crate::external_host_call_table::ExternalHostCallSignature; use crate::host_function::HostPlugin; use crate::mtable::MemoryReadSize; use crate::mtable::MemoryStoreSize; +use crate::types::Value; use crate::types::ValueType; use num_bigint::BigUint; +use num_traits::One; +use num_traits::Zero; use serde::Deserialize; use serde::Serialize; +use std::collections::HashSet; use std::fmt; use std::fmt::Debug; use std::fmt::Display; @@ -154,6 +178,76 @@ impl BitOp { } } +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub enum BinaryOp { + BinOp(BinOp), + ShiftOp(ShiftOp), + BitOp(BitOp), + RelOp(RelOp), +} + +impl From for BinaryOp { + fn from(value: BinOp) -> Self { + BinaryOp::BinOp(value) + } +} + +impl From for BinaryOp { + fn from(value: ShiftOp) -> Self { + BinaryOp::ShiftOp(value) + } +} + +impl From for BinaryOp { + fn from(value: BitOp) -> Self { + BinaryOp::BitOp(value) + } +} + +impl From for BinaryOp { + fn from(value: RelOp) -> Self { + BinaryOp::RelOp(value) + } +} + +impl BinaryOp { + pub fn is_bit_op(&self) -> bool { + matches!(self, BinaryOp::BitOp(_)) + } + + pub fn is_rel_op(&self) -> bool { + matches!(self, BinaryOp::RelOp(_)) + } + + pub fn as_bin_op(self) -> BinOp { + match self { + BinaryOp::BinOp(op) => op, + _ => panic!("Not a binary op"), + } + } + + pub fn as_shift_op(self) -> ShiftOp { + match self { + BinaryOp::ShiftOp(op) => op, + _ => panic!("Not a shift op"), + } + } + + pub fn as_bit_op(self) -> BitOp { + match self { + BinaryOp::BitOp(op) => op, + _ => panic!("Not a bit op"), + } + } + + pub fn as_rel_op(self) -> RelOp { + match self { + BinaryOp::RelOp(op) => op, + _ => panic!("Not a rel op"), + } + } +} + #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum RelOp { Eq, @@ -192,6 +286,74 @@ pub struct BrTarget { pub dst_pc: u32, } +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub enum UniArg { + Pop, + Stack(usize), + IConst(Value), +} + +impl UniArg { + pub fn is_pop(&self) -> bool { + matches!(self, UniArg::Pop) + } + + pub fn get_const_value(&self) -> u64 { + match self { + UniArg::Pop => 0, + UniArg::Stack(_) => 0, + UniArg::IConst(v) => match v { + Value::I32(v) => *v as u32 as u64, + Value::I64(v) => *v as u64, + }, + } + } + + pub fn try_decease_stack_depth(&mut self, diff: usize) { + if let UniArg::Stack(i) = self { + *self = UniArg::Stack(*i - diff); + } + } + + pub fn pop_tag() -> BigUint { + BigUint::from(0u64) << 64 + } + + pub fn stack_tag() -> BigUint { + BigUint::from(1u64) << 64 + } + + pub fn i64_const_tag() -> BigUint { + BigUint::from(2u64) << 64 + } + + pub fn i32_const_tag() -> BigUint { + BigUint::from(3u64) << 64 + } + + pub fn i64_i32_const_tag() -> BigUint { + Self::i32_const_tag() - Self::i64_const_tag() + } + + pub(crate) fn encode(&self) -> BigUint { + macro_rules! tag { + ($tag:expr, $value:expr) => { + $tag + $value + }; + } + match self { + UniArg::Pop => tag!(Self::pop_tag(), BigUint::zero()), + UniArg::Stack(usize) => tag!(Self::stack_tag(), BigUint::from(*usize as u64)), + UniArg::IConst(c) => match c { + Value::I32(value) => { + tag!(Self::i32_const_tag(), BigUint::from(*value as u32 as u64)) + } + Value::I64(value) => tag!(Self::i64_const_tag(), BigUint::from(*value as u64)), + }, + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum Opcode { LocalGet { @@ -201,6 +363,7 @@ pub enum Opcode { LocalSet { vtype: VarType, offset: u64, + uniarg: UniArg, }, LocalTee { vtype: VarType, @@ -211,15 +374,20 @@ pub enum Opcode { }, GlobalSet { idx: u64, + uniarg: UniArg, }, MemorySize, - MemoryGrow, + MemoryGrow { + uniarg: UniArg, + }, Const { vtype: VarType, value: u64, }, Drop, - Select, + Select { + uniargs: [UniArg; 3], + }, Return { drop: u32, keep: Vec, @@ -227,26 +395,32 @@ pub enum Opcode { Bin { class: BinOp, vtype: VarType, + uniargs: [UniArg; 2], }, BinShift { class: ShiftOp, vtype: VarType, + uniargs: [UniArg; 2], }, BinBit { class: BitOp, vtype: VarType, + uniargs: [UniArg; 2], }, Unary { class: UnaryOp, vtype: VarType, + uniarg: UniArg, }, Test { class: TestOp, vtype: VarType, + uniarg: UniArg, }, Rel { class: RelOp, vtype: VarType, + uniargs: [UniArg; 2], }, Br { drop: u32, @@ -257,14 +431,17 @@ pub enum Opcode { drop: u32, keep: Vec, dst_pc: u32, + uniarg: UniArg, }, BrIfEqz { drop: u32, keep: Vec, dst_pc: u32, + uniarg: UniArg, }, BrTable { targets: Vec, + uniarg: UniArg, }, Unreachable, Call { @@ -272,6 +449,7 @@ pub enum Opcode { }, CallIndirect { type_idx: u32, + uniarg: UniArg, }, InternalHostCall { plugin: HostPlugin, @@ -287,14 +465,18 @@ pub enum Opcode { offset: u32, vtype: VarType, size: MemoryReadSize, + uniarg: UniArg, }, Store { offset: u32, vtype: VarType, size: MemoryStoreSize, + // uniargs[0]: val, uniargs[1]: pos + uniargs: [UniArg; 2], }, Conversion { class: ConversionOp, + uniarg: UniArg, }, } @@ -319,110 +501,138 @@ impl Opcode { } } -pub const OPCODE_SHIFT: u32 = OPCODE_CLASS_SHIFT + 16; -pub const OPCODE_CLASS_SHIFT: u32 = OPCODE_ARG0_SHIFT + COMMON_RANGE_OFFSET; -pub const OPCODE_ARG0_SHIFT: u32 = OPCODE_ARG1_SHIFT + COMMON_RANGE_OFFSET; -pub const OPCODE_ARG1_SHIFT: u32 = 64; -pub const OPCODE_CELL: usize = 4; +pub const OPCODE_SHIFT: u32 = OPCODE_CLASS_SHIFT + 8; +pub const OPCODE_CLASS_SHIFT: u32 = 210; + +lazy_static! { + static ref ENCODE_BOUNDARY: BigUint = BigUint::one() << 250; +} impl From<&Opcode> for BigUint { fn from(opcode: &Opcode) -> BigUint { let bn = match opcode { Opcode::LocalGet { vtype, offset } => { - (BigUint::from(OpcodeClass::LocalGet as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + offset - } - Opcode::LocalSet { vtype, offset } => { - (BigUint::from(OpcodeClass::LocalSet as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + offset + encode_local_get(BigUint::from(*vtype as u64), BigUint::from(*offset)) } + Opcode::LocalSet { + vtype, + offset, + uniarg, + } => encode_local_set( + BigUint::from(*vtype as u64), + BigUint::from(*offset), + uniarg.into(), + ), Opcode::LocalTee { vtype, offset } => { - (BigUint::from(OpcodeClass::LocalTee as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + offset + encode_local_tee(BigUint::from(*vtype as u64), BigUint::from(*offset)) } + Opcode::GlobalGet { idx } => encode_global_get(BigUint::from(*idx)), - Opcode::GlobalSet { idx } => encode_global_set(BigUint::from(*idx)), - Opcode::Const { vtype, value } => { - (BigUint::from(OpcodeClass::Const as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + value - } - Opcode::Drop => BigUint::from(OpcodeClass::Drop as u64) << OPCODE_CLASS_SHIFT, - Opcode::Select => BigUint::from(OpcodeClass::Select as u64) << OPCODE_CLASS_SHIFT, - Opcode::Return { drop, keep } => { - (BigUint::from(OpcodeClass::Return as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*drop as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(keep.len() as u64) << OPCODE_ARG1_SHIFT) - + keep.first().map_or(0u64, |x| VarType::from(x) as u64) - } - Opcode::Bin { class, vtype } => { - (BigUint::from(OpcodeClass::Bin as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) + Opcode::GlobalSet { idx, uniarg } => { + encode_global_set(BigUint::from(*idx), uniarg.into()) } - Opcode::BinShift { class, vtype } => { - (BigUint::from(OpcodeClass::BinShift as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) - } - Opcode::BinBit { class, vtype } => { - (BigUint::from(OpcodeClass::BinBit as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) - } - Opcode::Unary { class, vtype } => { - (BigUint::from(OpcodeClass::Unary as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) - } - Opcode::Test { class, vtype } => { - (BigUint::from(OpcodeClass::Test as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) - } - Opcode::Rel { class, vtype } => { - (BigUint::from(OpcodeClass::Rel as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*class as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG1_SHIFT) - } - Opcode::Br { drop, keep, dst_pc } => { - // TODO: should encode type of keep values? - (BigUint::from(OpcodeClass::Br as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*drop as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(keep.len() as u64) << OPCODE_ARG1_SHIFT) - + dst_pc - } - Opcode::BrIf { drop, keep, dst_pc } => { - // TODO: should encode type of keep values? - (BigUint::from(OpcodeClass::BrIf as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*drop as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(keep.len() as u64) << OPCODE_ARG1_SHIFT) - + dst_pc + Opcode::Const { vtype, value } => { + encode_const(BigUint::from(*vtype as u64), BigUint::from(*value)) } - Opcode::BrIfEqz { drop, keep, dst_pc } => encode_br_if_eqz( + Opcode::Drop => encode_drop(), + Opcode::Select { uniargs } => encode_select(uniargs.into()), + Opcode::Return { drop, keep } => encode_return( + BigUint::from(*drop as u64), + BigUint::from(keep.len() as u64), + BigUint::from(keep.first().map_or(0u64, |x| VarType::from(x) as u64)), + ), + Opcode::Bin { + class, + vtype, + uniargs, + } => encode_bin( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniargs.into(), + ), + Opcode::BinShift { + class, + vtype, + uniargs, + } => encode_bin_shift( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniargs.into(), + ), + Opcode::BinBit { + class, + vtype, + uniargs, + } => encode_bin_bit( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniargs.into(), + ), + Opcode::Unary { + class, + vtype, + uniarg, + } => encode_unary( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniarg.into(), + ), + Opcode::Test { + class, + vtype, + uniarg, + } => encode_test( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniarg.into(), + ), + Opcode::Rel { + class, + vtype, + uniargs, + } => encode_rel( + BigUint::from(*class as u64), + BigUint::from(*vtype as u64), + uniargs.into(), + ), + Opcode::Br { drop, keep, dst_pc } => encode_br( + BigUint::from(*drop as u64), + BigUint::from(keep.len() as u64), + BigUint::from(*dst_pc), + ), + Opcode::BrIf { + drop, + keep, + dst_pc, + uniarg, + } => encode_br_if( + BigUint::from(*drop as u64), + BigUint::from(keep.len() as u64), + BigUint::from(*dst_pc), + uniarg.into(), + ), + Opcode::BrIfEqz { + drop, + keep, + dst_pc, + uniarg, + } => encode_br_if_eqz( BigUint::from(*drop as u64), BigUint::from(keep.len() as u64), BigUint::from(*dst_pc), + uniarg.into(), ), - Opcode::BrTable { targets } => encode_br_table(BigUint::from(targets.len())), - Opcode::Unreachable => { - BigUint::from(OpcodeClass::Unreachable as u64) << OPCODE_CLASS_SHIFT + Opcode::BrTable { targets, uniarg } => { + encode_br_table(BigUint::from(targets.len()), uniarg.into()) } + Opcode::Unreachable => encode_unreachable(), Opcode::Call { index } => encode_call(BigUint::from(*index as u64)), - Opcode::CallIndirect { type_idx } => { - encode_call_indirect(BigUint::from(*type_idx as u64)) + Opcode::CallIndirect { type_idx, uniarg } => { + encode_call_indirect(BigUint::from(*type_idx as u64), uniarg.into()) } Opcode::InternalHostCall { op_index_in_plugin, .. - } => { - let opcode_class_plain: OpcodeClassPlain = opcode.into(); - - (BigUint::from(opcode_class_plain.0) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*op_index_in_plugin as u64)) - } + } => encode_call_internal_host(opcode, *op_index_in_plugin), Opcode::ExternalHostCall { op, sig } => encode_call_host( BigUint::from(*op as u64), BigUint::from(sig.is_ret() as u64), @@ -432,29 +642,27 @@ impl From<&Opcode> for BigUint { offset, vtype, size, - } => { - (BigUint::from(OpcodeClass::Load as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*size as u64) << OPCODE_ARG1_SHIFT) - + offset - } + uniarg, + } => encode_load( + BigUint::from(*vtype as u64), + BigUint::from(*size as u64), + BigUint::from(*offset), + uniarg.into(), + ), Opcode::Store { offset, vtype, size, - } => { - (BigUint::from(OpcodeClass::Store as u64) << OPCODE_CLASS_SHIFT) - + (BigUint::from(*vtype as u64) << OPCODE_ARG0_SHIFT) - + (BigUint::from(*size as u64) << OPCODE_ARG1_SHIFT) - + offset - } - Opcode::MemorySize => { - BigUint::from(OpcodeClass::MemorySize as u64) << OPCODE_CLASS_SHIFT - } - Opcode::MemoryGrow => { - BigUint::from(OpcodeClass::MemoryGrow as u64) << OPCODE_CLASS_SHIFT - } - Opcode::Conversion { class } => match class { + uniargs, + } => encode_store( + BigUint::from(*vtype as u64), + BigUint::from(*size as u64), + BigUint::from(*offset), + uniargs.into(), + ), + Opcode::MemorySize => encode_memory_size(), + Opcode::MemoryGrow { uniarg } => encode_memory_grow(uniarg.into()), + Opcode::Conversion { class, uniarg } => match class { ConversionOp::I32WrapI64 => encode_conversion( 0u64.into(), 0u64.into(), @@ -464,6 +672,7 @@ impl From<&Opcode> for BigUint { 1u64.into(), 1u64.into(), 0u64.into(), + uniarg.into(), ), ConversionOp::I64ExtendI32s => encode_conversion( 1u64.into(), @@ -474,6 +683,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 0u64.into(), 1u64.into(), + uniarg.into(), ), ConversionOp::I64ExtendI32u => encode_conversion( 0u64.into(), @@ -484,6 +694,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 0u64.into(), 1u64.into(), + uniarg.into(), ), ConversionOp::I32Extend8S => encode_conversion( 1u64.into(), @@ -494,6 +705,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 1u64.into(), 0u64.into(), + uniarg.into(), ), ConversionOp::I32Extend16S => encode_conversion( 1u64.into(), @@ -504,6 +716,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 1u64.into(), 0u64.into(), + uniarg.into(), ), ConversionOp::I64Extend8S => encode_conversion( 1u64.into(), @@ -514,6 +727,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 0u64.into(), 1u64.into(), + uniarg.into(), ), ConversionOp::I64Extend16S => encode_conversion( 1u64.into(), @@ -524,6 +738,7 @@ impl From<&Opcode> for BigUint { 0u64.into(), 0u64.into(), 1u64.into(), + uniarg.into(), ), ConversionOp::I64Extend32S => encode_conversion( 1u64.into(), @@ -534,10 +749,13 @@ impl From<&Opcode> for BigUint { 0u64.into(), 0u64.into(), 1u64.into(), + uniarg.into(), ), }, }; + assert!(bn < BigUint::from(1u64) << OPCODE_SHIFT); + bn } } @@ -572,7 +790,7 @@ impl From<&Opcode> for OpcodeClass { Opcode::Load { .. } => OpcodeClass::Load, Opcode::Store { .. } => OpcodeClass::Store, Opcode::MemorySize => OpcodeClass::MemorySize, - Opcode::MemoryGrow => OpcodeClass::MemoryGrow, + Opcode::MemoryGrow { .. } => OpcodeClass::MemoryGrow, Opcode::Conversion { .. } => OpcodeClass::Conversion, } } @@ -668,7 +886,7 @@ impl InstructionTable { let entries: Vec> = self .iter() .map(|entry| match &entry.opcode { - Opcode::BrTable { targets } => targets + Opcode::BrTable { targets, .. } => targets .iter() .enumerate() .map(|(index, target)| BrTableEntry { @@ -694,6 +912,60 @@ impl InstructionTable { pub fn is_empty(&self) -> bool { self.len() == 0 } + + pub fn instruction_constants(&self) -> Vec { + let mut set = HashSet::::default(); + + // For default lookup + set.insert(0); + + for instruction in self.iter() { + match &instruction.opcode { + Opcode::LocalGet { .. } + | Opcode::LocalTee { .. } + | Opcode::GlobalGet { .. } + | Opcode::MemorySize + | Opcode::Const { .. } + | Opcode::Drop + | Opcode::Return { .. } + | Opcode::Br { .. } + | Opcode::Unreachable + | Opcode::Call { .. } + | Opcode::InternalHostCall { .. } + | Opcode::ExternalHostCall { .. } => (), + + Opcode::LocalSet { uniarg, .. } + | Opcode::GlobalSet { uniarg, .. } + | Opcode::MemoryGrow { uniarg } + | Opcode::Unary { uniarg, .. } + | Opcode::Test { uniarg, .. } + | Opcode::BrIf { uniarg, .. } + | Opcode::BrIfEqz { uniarg, .. } + | Opcode::BrTable { uniarg, .. } + | Opcode::CallIndirect { uniarg, .. } + | Opcode::Load { uniarg, .. } + | Opcode::Conversion { uniarg, .. } => { + set.insert(uniarg.get_const_value()); + } + + Opcode::Bin { uniargs, .. } + | Opcode::BinShift { uniargs, .. } + | Opcode::BinBit { uniargs, .. } + | Opcode::Rel { uniargs, .. } + | Opcode::Store { uniargs, .. } => uniargs.iter().for_each(|x| { + set.insert(x.get_const_value()); + }), + + Opcode::Select { uniargs } => uniargs.iter().for_each(|x| { + set.insert(x.get_const_value()); + }), + } + } + + let mut constants = set.into_iter().collect::>(); + constants.sort(); + constants + } } impl From for InstructionTable { diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index d73575adc..f562f2e73 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -1,5 +1,5 @@ #![feature(trait_alias)] -#![deny(warnings)] +// #![deny(warnings)] #![allow( clippy::assertions_on_constants, clippy::too_many_arguments, diff --git a/crates/specs/src/state.rs b/crates/specs/src/state.rs index 835052a2b..c4e989243 100644 --- a/crates/specs/src/state.rs +++ b/crates/specs/src/state.rs @@ -17,10 +17,11 @@ pub struct InitializationState { pub maximal_memory_pages: T, } +pub const INITIALIZATION_STATE_FIELD_COUNT: usize = 10; impl InitializationState { // TODO: try to remove the magic number pub fn field_count() -> usize { - 10 + INITIALIZATION_STATE_FIELD_COUNT } pub fn zip_for_each( diff --git a/crates/specs/src/step.rs b/crates/specs/src/step.rs index 4b4889a8f..8d33395a9 100644 --- a/crates/specs/src/step.rs +++ b/crates/specs/src/step.rs @@ -1,11 +1,9 @@ use crate::external_host_call_table::ExternalHostCallSignature; use crate::host_function::HostPlugin; use crate::host_function::Signature; -use crate::itable::BinOp; -use crate::itable::BitOp; -use crate::itable::RelOp; -use crate::itable::ShiftOp; +use crate::itable::BinaryOp; use crate::itable::UnaryOp; +use crate::itable::UniArg; use crate::mtable::MemoryReadSize; use crate::mtable::MemoryStoreSize; use crate::mtable::VarType; @@ -13,7 +11,7 @@ use crate::types::ValueType; use serde::Deserialize; use serde::Serialize; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum StepInfo { Br { dst_pc: u32, @@ -27,6 +25,7 @@ pub enum StepInfo { drop: u32, keep: Vec, keep_values: Vec, + uniarg: UniArg, }, BrIfNez { condition: i32, @@ -34,6 +33,7 @@ pub enum StepInfo { drop: u32, keep: Vec, keep_values: Vec, + uniarg: UniArg, }, BrTable { index: i32, @@ -41,6 +41,7 @@ pub enum StepInfo { drop: u32, keep: Vec, keep_values: Vec, + uniarg: UniArg, }, Return { drop: u32, @@ -50,9 +51,12 @@ pub enum StepInfo { Drop, Select { - val1: u64, - val2: u64, + lhs: u64, + lhs_uniarg: UniArg, + rhs: u64, + rhs_uniarg: UniArg, cond: u64, + cond_uniarg: UniArg, result: u64, vtype: VarType, }, @@ -65,6 +69,7 @@ pub enum StepInfo { type_index: u32, offset: u32, func_index: u32, + uniarg: UniArg, }, CallHost { plugin: HostPlugin, @@ -90,6 +95,7 @@ pub enum StepInfo { vtype: VarType, depth: u32, value: u64, + uniarg: UniArg, }, TeeLocal { vtype: VarType, @@ -108,6 +114,7 @@ pub enum StepInfo { vtype: VarType, is_mutable: bool, value: u64, + uniarg: UniArg, }, Load { @@ -119,6 +126,7 @@ pub enum StepInfo { value: u64, block_value1: u64, block_value2: u64, + uniarg: UniArg, }, Store { vtype: VarType, @@ -131,12 +139,15 @@ pub enum StepInfo { pre_block_value2: u64, updated_block_value2: u64, value: u64, + pos_uniarg: UniArg, + val_uniarg: UniArg, }, MemorySize, MemoryGrow { grow_size: i32, result: i32, + uniarg: UniArg, }, I32Const { @@ -147,41 +158,23 @@ pub enum StepInfo { }, I32BinOp { - class: BinOp, - left: i32, - right: i32, - value: i32, - }, - I32BinShiftOp { - class: ShiftOp, - left: i32, - right: i32, - value: i32, - }, - I32BinBitOp { - class: BitOp, + class: BinaryOp, left: i32, + lhs_uniarg: UniArg, right: i32, + rhs_uniarg: UniArg, value: i32, }, I64BinOp { - class: BinOp, - left: i64, - right: i64, - value: i64, - }, - I64BinShiftOp { - class: ShiftOp, - left: i64, - right: i64, - value: i64, - }, - I64BinBitOp { - class: BitOp, + class: BinaryOp, left: i64, + lhs_uniarg: UniArg, right: i64, + rhs_uniarg: UniArg, value: i64, + // rel should return i32, otherwise i64 + value_type: VarType, }, UnaryOp { @@ -189,53 +182,50 @@ pub enum StepInfo { vtype: VarType, operand: u64, result: u64, + uniarg: UniArg, }, Test { vtype: VarType, value: u64, result: i32, - }, - I32Comp { - class: RelOp, - left: i32, - right: i32, - value: bool, - }, - I64Comp { - class: RelOp, - left: i64, - right: i64, - value: bool, + uniarg: UniArg, }, I32WrapI64 { value: i64, result: i32, + uniarg: UniArg, }, I64ExtendI32 { value: i32, result: i64, sign: bool, + uniarg: UniArg, }, I32SignExtendI8 { value: i32, result: i32, + uniarg: UniArg, }, I32SignExtendI16 { value: i32, result: i32, + uniarg: UniArg, }, I64SignExtendI8 { value: i64, result: i64, + uniarg: UniArg, }, I64SignExtendI16 { value: i64, result: i64, + uniarg: UniArg, }, I64SignExtendI32 { value: i64, result: i64, + uniarg: UniArg, }, } diff --git a/crates/specs/src/types.rs b/crates/specs/src/types.rs index 045110c27..60fce044a 100644 --- a/crates/specs/src/types.rs +++ b/crates/specs/src/types.rs @@ -22,7 +22,7 @@ impl From for ValueType { } } -#[derive(Debug, Clone)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum Value { I32(i32), I64(i64), diff --git a/crates/zkwasm/src/circuits/bit_table/assign.rs b/crates/zkwasm/src/circuits/bit_table/assign.rs index 7465867b3..3b6852110 100644 --- a/crates/zkwasm/src/circuits/bit_table/assign.rs +++ b/crates/zkwasm/src/circuits/bit_table/assign.rs @@ -29,25 +29,27 @@ impl BitTableTrait for EventTableWithMemoryInfo { self.0 .iter() .filter_map(|entry| match &entry.eentry.step_info { - StepInfo::I32BinBitOp { + StepInfo::I32BinOp { class, left, right, value, - } => Some(BitTableAssign { - op: BitTableOp::BinaryBit(*class), + .. + } if class.is_bit_op() => Some(BitTableAssign { + op: BitTableOp::BinaryBit((*class).as_bit_op()), left: *left as u32 as u64, right: *right as u32 as u64, result: *value as u32 as u64, }), - StepInfo::I64BinBitOp { + StepInfo::I64BinOp { class, left, right, value, - } => Some(BitTableAssign { - op: BitTableOp::BinaryBit(*class), + .. + } if class.is_bit_op() => Some(BitTableAssign { + op: BitTableOp::BinaryBit((*class).as_bit_op()), left: *left as u64, right: *right as u64, result: *value as u64, diff --git a/crates/zkwasm/src/circuits/etable/allocator.rs b/crates/zkwasm/src/circuits/etable/allocator.rs index 5a70ac6eb..d729b9e5e 100644 --- a/crates/zkwasm/src/circuits/etable/allocator.rs +++ b/crates/zkwasm/src/circuits/etable/allocator.rs @@ -1,12 +1,15 @@ +use super::AllocatedStateCell; use super::AllocatedU32StateCell; use super::EVENT_TABLE_ENTRY_ROWS; use crate::circuits::bit_table::BitTableOp; use crate::circuits::cell::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::image_table::ImageTableConfig; use crate::circuits::rtable::RangeTableConfig; use crate::circuits::traits::ConfigureLookupTable; use crate::circuits::utils::bit::BitColumn; use crate::circuits::utils::common_range::CommonRangeColumn; +use crate::circuits::utils::table_entry::MemoryRWEntry; use crate::circuits::utils::u16::U16Column; use crate::circuits::utils::u8::U8Column; use crate::circuits::Context; @@ -24,9 +27,11 @@ use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; use specs::encode::memory_table::encode_memory_table_entry; use specs::mtable::LocationType; +use specs::mtable::VarType; use std::cmp::Ordering; use std::collections::BTreeMap; use std::marker::PhantomData; +use std::slice::Iter; pub(super) trait EventTableCellExpression { fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression; @@ -68,8 +73,8 @@ pub(crate) struct AllocatedMemoryTableLookupReadCell { pub(crate) encode_cell: AllocatedUnlimitedCell, pub(crate) start_eid_cell: AllocatedUnlimitedCell, pub(crate) end_eid_cell: AllocatedUnlimitedCell, - pub(crate) start_eid_diff_cell: AllocatedU32StateCell, - pub(crate) end_eid_diff_cell: AllocatedU32StateCell, + pub(crate) start_eid_diff_cell: AllocatedStateCell, + pub(crate) end_eid_diff_cell: AllocatedStateCell, pub(crate) value_cell: AllocatedUnlimitedCell, } @@ -116,6 +121,25 @@ impl AllocatedMemoryTableLookupReadCell { Ok(()) } + + pub fn assign_with_memory_entry( + &self, + ctx: &mut Context<'_, F>, + memory_entry: &mut Iter, + ) -> Result<(), Error> { + let entry = memory_entry.next().unwrap(); + + self.assign( + ctx, + entry.start_eid, + entry.entry.eid, + entry.end_eid, + entry.entry.offset, + entry.entry.ltype, + entry.entry.vtype == VarType::I32, + entry.entry.value, + ) + } } impl AllocatedMemoryTableLookupWriteCell { @@ -143,6 +167,24 @@ impl AllocatedMemoryTableLookupWriteCell { Ok(()) } + + pub(crate) fn assign_with_memory_entry( + &self, + ctx: &mut Context<'_, F>, + memory_entry: &mut Iter, + ) -> Result<(), Error> { + let entry = memory_entry.next().unwrap(); + + self.assign( + ctx, + entry.start_eid, + entry.end_eid, + entry.entry.offset, + entry.entry.ltype, + entry.entry.vtype == VarType::I32, + entry.entry.value, + ) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -153,26 +195,33 @@ pub(crate) enum EventTableCellType { CommonRange, Unlimited, MTableLookup, + ITableLookup, } -const BIT_COLUMNS: usize = 12; +const U16_PERMUTATION_CELLS: usize = 5; +const COMMON_RANGE_PERMUTATION_CELLS: usize = 5; +const UNLIMITED_PERMUTATION_CELLS: usize = 2; +const U32_OR_COMMON_RANGE_PERMUTATION_CELLS: usize = 2; + +const BIT_COLUMNS: usize = 15; const U8_COLUMNS: usize = 1; -const U32_CELLS: usize = 2; -const U32_PERMUTATION_CELLS: usize = if cfg!(feature = "continuation") { +const U32_CELLS: usize = if cfg!(feature = "continuation") { 10 } else { - 0 + 2 }; +const U32_PERMUTATION_CELLS: usize = if cfg!(feature = "continuation") { 2 } else { 0 }; const U64_CELLS: usize = 5; const U16_COLUMNS: usize = - U64_CELLS + ((U32_CELLS + U32_PERMUTATION_CELLS).next_multiple_of(2) / 2); -const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 6 }; + U64_CELLS + ((U32_CELLS + U32_PERMUTATION_CELLS).next_multiple_of(2) / 2) + 2; +const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 3 } else { 5 }; const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 10 } else { - 8 + 9 }; const MEMORY_TABLE_LOOKUP_COLUMNS: usize = 2; +const IMAGE_TABLE_LOOKUP_COLUMNS: usize = 1; #[derive(Clone, Copy)] pub(crate) struct AllocatedBitTableLookupCells { @@ -203,7 +252,6 @@ impl AllocatedBitTableLookupCells { pub(crate) struct AllocatorFreeCellsProfiler { free_cells: BTreeMap, free_u32_cells: usize, - free_u32_permutation_cells: usize, free_u64_cells: usize, } @@ -212,7 +260,6 @@ impl AllocatorFreeCellsProfiler { Self { free_cells: allocator.free_cells.clone(), free_u32_cells: allocator.free_u32_cells.len(), - free_u32_permutation_cells: allocator.free_u32_permutation_cells.len(), free_u64_cells: allocator.free_u64_cells.len(), } } @@ -232,10 +279,6 @@ impl AllocatorFreeCellsProfiler { } self.free_u32_cells = usize::min(self.free_u32_cells, allocator.free_u32_cells.len()); - self.free_u32_permutation_cells = usize::min( - self.free_u32_permutation_cells, - allocator.free_u32_permutation_cells.len(), - ); self.free_u64_cells = usize::min(self.free_u64_cells, allocator.free_u64_cells.len()); } @@ -251,16 +294,13 @@ impl AllocatorFreeCellsProfiler { ); } + assert!(allocator.reserved_permutation_cells.is_empty()); + assert!( self.free_u32_cells == 0, "unused u32 cells should be removed: {:?}.", self.free_u32_cells ); - assert!( - self.free_u32_permutation_cells == 0, - "unused u32 permutation cells should be removed: {:?}.", - self.free_u32_permutation_cells - ); assert!( self.free_u64_cells == 0, "unused u64 cells should be removed: {:?}.", @@ -269,36 +309,41 @@ impl AllocatorFreeCellsProfiler { } } +#[derive(Default, Debug, Clone)] +struct ReservedPermutationCells { + u16_cells: Vec>, + u32_or_common_range_cells: Vec>, + common_range_cells: Vec>, + unlimited_cells: Vec>, +} + +impl ReservedPermutationCells { + fn is_empty(&self) -> bool { + self.u16_cells.is_empty() + && self.u32_or_common_range_cells.is_empty() + && self.common_range_cells.is_empty() + && self.unlimited_cells.is_empty() + } +} + #[derive(Debug, Clone)] pub(crate) struct EventTableCellAllocator { pub(crate) free_cells: BTreeMap, all_cols: BTreeMap>>>, + reserved_permutation_cells: ReservedPermutationCells, free_u32_cells: Vec>, - free_u32_permutation_cells: Vec>, free_u64_cells: Vec>, _mark: PhantomData, } impl EventTableCellAllocator { - pub fn enable_equality( - &mut self, - meta: &mut ConstraintSystem, - t: &EventTableCellType, - count: usize, - ) { - for c in self.all_cols.get(t).unwrap().iter().take(count) { - for c in c { - meta.enable_equality(*c); - } - } - } - pub(super) fn prepare_alloc_u32_cell(&mut self) -> AllocatedU32Cell { let u16_cells_le = [0; 2].map(|_| self.alloc_u16_cell()); AllocatedU32Cell { u16_cells_le } } + #[allow(dead_code)] pub(super) fn prepare_alloc_u32_permutation_cell( &mut self, meta: &mut ConstraintSystem, @@ -351,6 +396,7 @@ impl EventTableCellAllocator { (l_0, l_active, l_active_last): (Column, Column, Column), rtable: &RangeTableConfig, mtable: &impl ConfigureLookupTable, + itable: &ImageTableConfig, cols: &mut impl Iterator>, ) -> Self { let mut allocator = Self::_new( @@ -359,18 +405,61 @@ impl EventTableCellAllocator { (l_0, l_active, l_active_last), rtable, mtable, + itable, cols, ); + + // Reserve permutation cells to make sure they are closed to each other. + { + for _ in 0..U16_PERMUTATION_CELLS { + let cell = allocator.alloc_u16_cell(); + meta.enable_equality(cell.cell.col); + allocator.reserved_permutation_cells.u16_cells.push(cell); + } + for _ in 0..COMMON_RANGE_PERMUTATION_CELLS { + let cell = allocator.alloc_common_range_cell(); + meta.enable_equality(cell.cell.col); + allocator + .reserved_permutation_cells + .common_range_cells + .push(cell); + } + for _ in 0..UNLIMITED_PERMUTATION_CELLS { + let cell = allocator.alloc_unlimited_cell(); + meta.enable_equality(cell.cell.col); + allocator + .reserved_permutation_cells + .unlimited_cells + .push(cell); + } + for _ in 0..U32_OR_COMMON_RANGE_PERMUTATION_CELLS { + #[cfg(feature = "continuation")] + { + let cell = allocator + .prepare_alloc_u32_permutation_cell(meta, |meta| fixed_curr!(meta, sel)); + meta.enable_equality(cell.u32_cell.cell.col); + allocator + .reserved_permutation_cells + .u32_or_common_range_cells + .push(cell); + } + + #[cfg(not(feature = "continuation"))] + { + let cell = allocator.alloc_common_range_cell(); + meta.enable_equality(cell.cell.col); + allocator + .reserved_permutation_cells + .u32_or_common_range_cells + .push(cell); + }; + } + } + for _ in 0..U32_CELLS { let cell = allocator.prepare_alloc_u32_cell(); allocator.free_u32_cells.push(cell); } - #[allow(clippy::reversed_empty_ranges)] - for _ in 0..U32_PERMUTATION_CELLS { - let cell = - allocator.prepare_alloc_u32_permutation_cell(meta, |meta| fixed_curr!(meta, sel)); - allocator.free_u32_permutation_cells.push(cell); - } for _ in 0..U64_CELLS { let cell = allocator.prepare_alloc_u64_cell(meta, |meta| fixed_curr!(meta, sel)); allocator.free_u64_cells.push(cell); @@ -384,6 +473,7 @@ impl EventTableCellAllocator { (l_0, l_active, l_active_last): (Column, Column, Column), rtable: &RangeTableConfig, mtable: &impl ConfigureLookupTable, + itable: &ImageTableConfig, cols: &mut impl Iterator>, ) -> Self { let mut all_cols = BTreeMap::new(); @@ -447,6 +537,19 @@ impl EventTableCellAllocator { .into_iter() .collect(), ); + all_cols.insert( + EventTableCellType::ITableLookup, + [0; IMAGE_TABLE_LOOKUP_COLUMNS] + .map(|_| { + let col = cols.next().unwrap(); + itable.instruction_lookup(meta, "c8a. itable_lookup in itable", |meta| { + [fixed_curr!(meta, sel) + constant_from!(1), curr!(meta, col)] + }); + vec![col] + }) + .into_iter() + .collect(), + ); Self { all_cols, @@ -458,12 +561,13 @@ impl EventTableCellAllocator { (EventTableCellType::CommonRange, (0, 0)), (EventTableCellType::Unlimited, (0, 0)), (EventTableCellType::MTableLookup, (0, 0)), + (EventTableCellType::ITableLookup, (0, 0)), ] .into_iter(), ), free_u32_cells: vec![], - free_u32_permutation_cells: vec![], free_u64_cells: vec![], + reserved_permutation_cells: ReservedPermutationCells::default(), _mark: PhantomData, } } @@ -486,7 +590,7 @@ impl EventTableCellAllocator { res } - fn alloc_group(&mut self, t: &EventTableCellType) -> Vec> { + pub(crate) fn alloc_group(&mut self, t: &EventTableCellType) -> Vec> { let v = self.free_cells.get_mut(t).unwrap(); let res = self.all_cols.get(t).unwrap()[v.0] @@ -519,16 +623,30 @@ impl EventTableCellAllocator { } } - pub(crate) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { + pub(crate) fn alloc_common_range_permutation_cell(&mut self) -> AllocatedCommonRangeCell { + self.reserved_permutation_cells + .common_range_cells + .pop() + .unwrap() + } + + pub(crate) fn alloc_state_cell(&mut self) -> AllocatedStateCell { cfg_if::cfg_if! { if #[cfg(feature = "continuation")] { - self.alloc_u32_permutation_cell() + self.alloc_u32_cell() } else { self.alloc_common_range_cell() } } } + pub(crate) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { + self.reserved_permutation_cells + .u32_or_common_range_cells + .pop() + .unwrap() + } + pub(crate) fn alloc_u8_cell(&mut self) -> AllocatedU8Cell { AllocatedU8Cell { cell: self.alloc(&EventTableCellType::U8), @@ -541,12 +659,29 @@ impl EventTableCellAllocator { } } + pub(crate) fn alloc_u16_permutation_cell(&mut self) -> AllocatedU16Cell { + self.reserved_permutation_cells.u16_cells.pop().unwrap() + } + pub(crate) fn alloc_unlimited_cell(&mut self) -> AllocatedUnlimitedCell { AllocatedUnlimitedCell { cell: self.alloc(&EventTableCellType::Unlimited), } } + pub(crate) fn alloc_unlimited_permutation_cell(&mut self) -> AllocatedUnlimitedCell { + self.reserved_permutation_cells + .unlimited_cells + .pop() + .unwrap() + } + + pub(crate) fn alloc_itable_lookup_cell(&mut self) -> AllocatedUnlimitedCell { + AllocatedUnlimitedCell { + cell: self.alloc(&EventTableCellType::ITableLookup), + } + } + pub(crate) fn alloc_memory_table_lookup_read_cell( &mut self, name: &'static str, @@ -569,8 +704,8 @@ impl EventTableCellAllocator { end_eid_cell: cells[1], encode_cell: cells[2], value_cell: cells[3], - start_eid_diff_cell: self.alloc_u32_state_cell(), - end_eid_diff_cell: self.alloc_u32_state_cell(), + start_eid_diff_cell: self.alloc_state_cell(), + end_eid_diff_cell: self.alloc_state_cell(), }; constraint_builder.constraints.push(( @@ -659,8 +794,8 @@ impl EventTableCellAllocator { end_eid_cell: cells[1], encode_cell: cells[2], value_cell: cells[3], - start_eid_diff_cell: self.alloc_u32_state_cell(), - end_eid_diff_cell: self.alloc_u32_state_cell(), + start_eid_diff_cell: self.alloc_state_cell(), + end_eid_diff_cell: self.alloc_state_cell(), }; constraint_builder.constraints.push(( @@ -729,13 +864,6 @@ impl EventTableCellAllocator { self.free_u32_cells.pop().expect("no more free u32 cells") } - #[allow(dead_code)] - pub(crate) fn alloc_u32_permutation_cell(&mut self) -> AllocatedU32PermutationCell { - self.free_u32_permutation_cells - .pop() - .expect("no more free u32 permutation cells") - } - pub(crate) fn alloc_u64_cell(&mut self) -> AllocatedU64Cell { self.free_u64_cells.pop().expect("no more free u64 cells") } @@ -747,8 +875,8 @@ impl EventTableCellAllocator { ) -> AllocatedU64CellWithFlagBitDyn { let value = self.free_u64_cells.pop().expect("no more free u64 cells"); let flag_bit_cell = self.alloc_bit_cell(); - let flag_u16_rem_cell = self.alloc_common_range_cell(); - let flag_u16_rem_diff_cell = self.alloc_common_range_cell(); + let flag_u16_rem_cell = self.alloc_common_range_cell(); // TODO: u16 + let flag_u16_rem_diff_cell = self.alloc_common_range_cell(); // TODO: u16 constraint_builder.push( "flag bit dyn", @@ -783,8 +911,8 @@ impl EventTableCellAllocator { ) -> AllocatedU64CellWithFlagBitDynSign { let value = self.free_u64_cells.pop().expect("no more free u64 cells"); let flag_bit_cell = self.alloc_bit_cell(); - let flag_u16_rem_cell = self.alloc_common_range_cell(); - let flag_u16_rem_diff_cell = self.alloc_common_range_cell(); + let flag_u16_rem_cell = self.alloc_common_range_cell(); // TODO: u16 + let flag_u16_rem_diff_cell = self.alloc_common_range_cell(); // TODO: u16 constraint_builder.push( "flag bit dyn sign", diff --git a/crates/zkwasm/src/circuits/etable/mod.rs b/crates/zkwasm/src/circuits/etable/mod.rs index 1d8e3b307..082433f70 100644 --- a/crates/zkwasm/src/circuits/etable/mod.rs +++ b/crates/zkwasm/src/circuits/etable/mod.rs @@ -10,6 +10,7 @@ use super::rtable::RangeTableConfig; use super::traits::ConfigureLookupTable; use super::utils::step_status::StepStatus; use super::utils::table_entry::EventTableEntryWithMemoryInfo; +use super::utils::table_entry::MemoryRWEntry; use super::utils::Context; use crate::circuits::etable::op_configure::op_bin::BinConfigBuilder; use crate::circuits::etable::op_configure::op_bin_bit::BinBitConfigBuilder; @@ -38,7 +39,10 @@ use crate::circuits::etable::op_configure::op_select::SelectConfigBuilder; use crate::circuits::etable::op_configure::op_store::StoreConfigBuilder; use crate::circuits::etable::op_configure::op_test::TestConfigBuilder; use crate::circuits::etable::op_configure::op_unary::UnaryConfigBuilder; +use crate::circuits::utils::bn_to_field; +use crate::constant; use crate::constant_from; +use crate::constant_from_bn; use crate::fixed_curr; use crate::foreign::context::etable_op_configure::ETableContextHelperTableConfigBuilder; use crate::foreign::require_helper::etable_op_configure::ETableRequireHelperTableConfigBuilder; @@ -58,7 +62,11 @@ use specs::encode::instruction_table::encode_instruction_table_entry; use specs::etable::EventTableEntry; use specs::itable::OpcodeClass; use specs::itable::OpcodeClassPlain; +use specs::itable::UniArg; +use specs::mtable::LocationType; +use specs::mtable::VarType; use std::collections::BTreeMap; +use std::slice::Iter; use std::sync::Arc; pub(super) mod assign; @@ -69,14 +77,119 @@ pub(crate) mod constraint_builder; #[cfg(feature = "continuation")] type AllocatedU32StateCell = AllocatedU32PermutationCell; +#[cfg(feature = "continuation")] +type AllocatedStateCell = AllocatedU32Cell; #[cfg(not(feature = "continuation"))] type AllocatedU32StateCell = AllocatedCommonRangeCell; +#[cfg(not(feature = "continuation"))] +type AllocatedStateCell = AllocatedCommonRangeCell; pub(crate) const EVENT_TABLE_ENTRY_ROWS: i32 = 4; pub(crate) const OP_CAPABILITY: usize = 32; const FOREIGN_LOOKUP_CAPABILITY: usize = 6; +#[derive(Clone)] +pub struct EventTableCommonArgsConfig { + pub(crate) is_enabled_cell: AllocatedBitCell, + + pub(crate) is_pop_cell: AllocatedBitCell, + + pub(crate) is_local_get_cell: AllocatedBitCell, + pub(crate) local_get_offset_cell: AllocatedU16Cell, + + pub(crate) is_const_cell: AllocatedBitCell, + pub(crate) is_i32_cell: AllocatedBitCell, + pub(crate) const_value_cell: AllocatedUnlimitedCell, + + pub(crate) is_stack_read_cell: AllocatedUnlimitedCell, + pub(crate) stack_offset_cell: AllocatedUnlimitedCell, + pub(crate) value_cell: AllocatedUnlimitedCell, + pub(crate) m_read_lookup_cell: AllocatedMemoryTableLookupReadCell, +} + +impl EventTableCommonArgsConfig { + fn _assign( + &self, + ctx: &mut Context<'_, F>, + arg_type: &UniArg, + // start_eid, eid, end_eid, offset, is_i32, value + mread_args: Option<(u32, u32, u32, u32, bool, u64)>, + ) -> Result<(), Error> { + self.is_enabled_cell.assign_bool(ctx, true)?; + match arg_type { + UniArg::Pop => { + self.is_pop_cell.assign_bool(ctx, true)?; + } + UniArg::Stack(offset) => { + self.is_local_get_cell.assign_bool(ctx, true)?; + self.local_get_offset_cell.assign_u32(ctx, *offset as u32)?; + } + UniArg::IConst(v) => { + self.is_const_cell.assign_bool(ctx, true)?; + self.const_value_cell + .assign(ctx, arg_type.get_const_value().into())?; + self.value_cell + .assign(ctx, arg_type.get_const_value().into())?; + match v { + specs::types::Value::I32(_) => { + self.is_i32_cell.assign_bool(ctx, true)?; + } + specs::types::Value::I64(_) => {} + } + } + } + + match arg_type { + UniArg::Pop | UniArg::Stack(_) => { + let (start_eid, eid, end_eid, offset, is_i32, value) = mread_args.unwrap(); + self.is_stack_read_cell.assign_bool(ctx, true)?; + self.stack_offset_cell.assign_u32(ctx, offset)?; + self.is_i32_cell.assign_bool(ctx, is_i32)?; + self.m_read_lookup_cell.assign( + ctx, + start_eid, + eid, + end_eid, + offset, + LocationType::Stack, + is_i32, + value, + )?; + self.value_cell.assign(ctx, value.into())?; + } + UniArg::IConst(_v) => {} + } + + Ok(()) + } + + pub(crate) fn assign( + &self, + ctx: &mut Context<'_, F>, + uniarg: &UniArg, + memory_entry: &mut Iter, + ) -> Result<(), Error> { + match uniarg { + UniArg::IConst(_) => self._assign(ctx, uniarg, None), + UniArg::Stack(_) | UniArg::Pop => { + let mread_args = memory_entry.next().map(|x| { + ( + x.start_eid, + x.entry.eid, + x.end_eid, + x.entry.offset, + x.entry.vtype == VarType::I32, + x.entry.value, + ) + }); + + self._assign(ctx, uniarg, mread_args) + } + } + } +} + #[derive(Clone)] pub struct EventTableCommonConfig { enabled_cell: AllocatedBitCell, @@ -89,13 +202,13 @@ pub struct EventTableCommonConfig { pub(crate) context_input_index_cell: AllocatedCommonRangeCell, pub(crate) context_output_index_cell: AllocatedCommonRangeCell, external_host_call_index_cell: AllocatedCommonRangeCell, - pub(crate) sp_cell: AllocatedCommonRangeCell, - mpages_cell: AllocatedCommonRangeCell, + pub(crate) sp_cell: AllocatedU16Cell, + mpages_cell: AllocatedU16Cell, frame_id_cell: AllocatedU32StateCell, pub(crate) eid_cell: AllocatedU32StateCell, - fid_cell: AllocatedCommonRangeCell, - iid_cell: AllocatedCommonRangeCell, - maximal_memory_pages_cell: AllocatedCommonRangeCell, + fid_cell: AllocatedU16Cell, + iid_cell: AllocatedU16Cell, + maximal_memory_pages_cell: AllocatedU16Cell, itable_lookup_cell: AllocatedUnlimitedCell, brtable_lookup_cell: AllocatedUnlimitedCell, @@ -106,14 +219,87 @@ pub struct EventTableCommonConfig { pow_table_lookup_power_cell: AllocatedUnlimitedCell, bit_table_lookup_cells: AllocatedBitTableLookupCells, external_foreign_call_lookup_cell: AllocatedUnlimitedCell, + + pub(crate) uniarg_configs: Vec>, } pub(in crate::circuits::etable) trait EventTableOpcodeConfigBuilder { + fn configure_all( + common_config: &EventTableCommonConfig, + allocator: &mut EventTableCellAllocator, + constraint_builder: &mut ConstraintBuilder, + uniarg_nr: usize, + ) -> Box> { + let used_args = common_config + .uniarg_configs + .iter() + .take(uniarg_nr) + .map(|x| x.is_enabled_cell) + .collect::>(); + let unused_args = common_config + .uniarg_configs + .iter() + .skip(uniarg_nr) + .map(|x| x.is_enabled_cell) + .collect::>(); + constraint_builder.push( + "uniarg enable", + Box::new(move |meta| { + let mut gates = vec![]; + if !used_args.is_empty() { + gates.push( + used_args + .iter() + .map(|x| x.expr(meta)) + .reduce(|a, b| a + b) + .unwrap() + - constant_from!(uniarg_nr), + ) + } + + if !unused_args.is_empty() { + gates.push( + unused_args + .iter() + .map(|x| x.expr(meta)) + .reduce(|a, b| a + b) + .unwrap(), + ); + } + gates + }), + ); + + let mut common_config = common_config.clone(); + common_config.uniarg_configs = common_config + .uniarg_configs + .into_iter() + .take(uniarg_nr) + .collect(); + Self::configure(&common_config, allocator, constraint_builder) + } + fn configure( - common: &EventTableCommonConfig, + common_config: &EventTableCommonConfig, allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box>; + + fn sp_after_uniarg( + sp_cell: AllocatedU16Cell, + uniarg_configs: &[EventTableCommonArgsConfig], + meta: &mut VirtualCells<'_, F>, + ) -> Expression { + let pops = uniarg_configs + .iter() + .map(|x| x.is_pop_cell) + .collect::>(); + + let acc = sp_cell.expr(meta); + pops.iter() + .map(|x| x.expr(meta)) + .fold(acc, |acc, x| acc + x) + } } pub trait EventTableOpcodeConfig { @@ -249,50 +435,37 @@ impl EventTableConfig { (l_0, l_active, l_active_last), rtable, mtable, + image_table, cols, ); let ops = [0; OP_CAPABILITY].map(|_| allocator.alloc_bit_cell()); let enabled_cell = allocator.alloc_bit_cell(); - let rest_mops_cell = allocator.alloc_common_range_cell(); - let rest_call_ops_cell = allocator.alloc_unlimited_cell(); - let rest_return_ops_cell = allocator.alloc_unlimited_cell(); - let input_index_cell = allocator.alloc_common_range_cell(); - let context_input_index_cell = allocator.alloc_common_range_cell(); - let context_output_index_cell = allocator.alloc_common_range_cell(); - let external_host_call_index_cell = allocator.alloc_common_range_cell(); - let sp_cell = allocator.alloc_common_range_cell(); - let mpages_cell = allocator.alloc_common_range_cell(); - let frame_id_cell = allocator.alloc_u32_state_cell(); + // Rest State + let rest_mops_cell = allocator.alloc_common_range_permutation_cell(); + let rest_call_ops_cell = allocator.alloc_unlimited_permutation_cell(); + let rest_return_ops_cell = allocator.alloc_unlimited_permutation_cell(); + + // Initialization State let eid_cell = allocator.alloc_u32_state_cell(); - let fid_cell = allocator.alloc_common_range_cell(); - let iid_cell = allocator.alloc_common_range_cell(); - let maximal_memory_pages_cell = allocator.alloc_common_range_cell(); - - // We only need to enable equality for the cells of states - let used_common_range_cells_for_state = allocator - .free_cells - .get(&EventTableCellType::CommonRange) - .unwrap(); - allocator.enable_equality( - meta, - &EventTableCellType::CommonRange, - used_common_range_cells_for_state.0 - + (used_common_range_cells_for_state.1 != 0) as usize, - ); + let fid_cell = allocator.alloc_u16_permutation_cell(); + let iid_cell = allocator.alloc_u16_permutation_cell(); + let frame_id_cell = allocator.alloc_u32_state_cell(); + let sp_cell = allocator.alloc_u16_permutation_cell(); + let input_index_cell = allocator.alloc_common_range_permutation_cell(); + let context_input_index_cell = allocator.alloc_common_range_permutation_cell(); + let context_output_index_cell = allocator.alloc_common_range_permutation_cell(); + let external_host_call_index_cell = allocator.alloc_common_range_permutation_cell(); + let mpages_cell = allocator.alloc_u16_permutation_cell(); + let maximal_memory_pages_cell = allocator.alloc_u16_permutation_cell(); - let used_unlimited_cells_for_state = allocator - .free_cells - .get(&EventTableCellType::Unlimited) - .unwrap(); - allocator.enable_equality( - meta, - &EventTableCellType::Unlimited, - used_unlimited_cells_for_state.0 + (used_unlimited_cells_for_state.1 != 0) as usize, - ); + let mut foreign_table_reserved_lookup_cells = [(); FOREIGN_LOOKUP_CAPABILITY] + .map(|_| allocator.alloc_unlimited_cell()) + .into_iter(); - let itable_lookup_cell = allocator.alloc_unlimited_cell(); + // MUST be the first cell of itable lookup column + let itable_lookup_cell = allocator.alloc_itable_lookup_cell(); let brtable_lookup_cell = allocator.alloc_unlimited_cell(); let jtable_lookup_cell = allocator.alloc_unlimited_cell(); let is_returned_cell = allocator.alloc_bit_cell(); @@ -301,9 +474,114 @@ impl EventTableConfig { let external_foreign_call_lookup_cell = allocator.alloc_unlimited_cell(); let bit_table_lookup_cells = allocator.alloc_bit_table_lookup_cells(); - let mut foreign_table_reserved_lookup_cells = [(); FOREIGN_LOOKUP_CAPABILITY] - .map(|_| allocator.alloc_unlimited_cell()) - .into_iter(); + let arg_is_enabled_cells = [0; 3].map(|_| allocator.alloc_bit_cell()); + let mut allocators = vec![allocator.clone()]; + let mut uniarg_configs: Vec> = vec![]; + + for (i, arg_is_enabled_cell) in arg_is_enabled_cells.into_iter().enumerate() { + let is_const_cell = allocator.alloc_bit_cell(); + let is_pop_cell = allocator.alloc_bit_cell(); + let is_local_get_cell = allocator.alloc_bit_cell(); + + let const_value_cell = allocator.alloc_itable_lookup_cell(); + let local_get_offset_cell = allocator.alloc_u16_cell(); + + let is_i32_cell = allocator.alloc_bit_cell(); + let value_cell = allocator.alloc_unlimited_cell(); + let stack_offset_cell = allocator.alloc_unlimited_cell(); + let is_stack_read_cell = allocator.alloc_unlimited_cell(); + + meta.create_gate("c_arg.0. type select", |meta| { + vec![ + (is_const_cell.expr(meta) + + is_pop_cell.expr(meta) + + is_local_get_cell.expr(meta) + - constant_from!(1)), + ] + .into_iter() + .map(|expr| expr * fixed_curr!(meta, step_sel) * arg_is_enabled_cell.expr(meta)) + .collect::>() + }); + + let cells: Vec<_> = allocator + .alloc_group(&EventTableCellType::MTableLookup) + .into_iter() + .map(|x| AllocatedUnlimitedCell { cell: x }) + .collect(); + + let m_read_lookup_cell = AllocatedMemoryTableLookupReadCell { + start_eid_cell: cells[0], + end_eid_cell: cells[1], + encode_cell: cells[2], + value_cell: cells[3], + start_eid_diff_cell: allocator.alloc_state_cell(), + end_eid_diff_cell: allocator.alloc_state_cell(), + }; + + meta.create_gate("c_arg.1. memory read", |meta| { + // By default, pop take the value on sp + 1 + let mut pop_sp_offset_expr = constant_from!(1); + + // Previous pop modify the diff by increasing 1 + for uniarg_config in uniarg_configs.iter().take(i) { + pop_sp_offset_expr = pop_sp_offset_expr + + uniarg_config.is_enabled_cell.expr(meta) + * uniarg_config.is_pop_cell.expr(meta); + } + + let is_stack_read = is_stack_read_cell.expr(meta); + + vec![ + // is_memory_read_cell = is_pop_cell + is_local_get_cell + is_stack_read.clone() - is_pop_cell.expr(meta) - is_local_get_cell.expr(meta), + // value_cell = if is_const_cell { const_value_cell } else { mlookup_cell.value_cell } + (value_cell.expr(meta) - const_value_cell.expr(meta)) + * is_const_cell.expr(meta), + (value_cell.expr(meta) - m_read_lookup_cell.value_cell.expr(meta)) + * is_stack_read.clone(), + // stack_offset = if is_pop { sp + 1 + previous_popped } else { sp + constant_offset } + stack_offset_cell.expr(meta) + - sp_cell.expr(meta) * is_stack_read.clone() + - is_pop_cell.expr(meta) * pop_sp_offset_expr + - is_local_get_cell.expr(meta) * local_get_offset_cell.expr(meta), + // on memory read + (eid_cell.expr(meta) + - m_read_lookup_cell.start_eid_cell.expr(meta) + - m_read_lookup_cell.start_eid_diff_cell.expr(meta) + - constant_from!(1)) + * is_stack_read.clone(), + (eid_cell.expr(meta) + m_read_lookup_cell.end_eid_diff_cell.expr(meta) + - m_read_lookup_cell.end_eid_cell.expr(meta)) + * is_stack_read.clone(), + (specs::encode::memory_table::encode_memory_table_entry( + stack_offset_cell.expr(meta), + constant_from!(specs::mtable::LocationType::Stack as u64), + is_i32_cell.expr(meta), + ) - m_read_lookup_cell.encode_cell.expr(meta)) + * is_stack_read, + ] + .into_iter() + .map(|expr| expr * fixed_curr!(meta, step_sel) * arg_is_enabled_cell.expr(meta)) + .collect::>() + }); + + uniarg_configs.push(EventTableCommonArgsConfig { + is_enabled_cell: arg_is_enabled_cell, + is_pop_cell, + is_const_cell, + is_local_get_cell, + const_value_cell, + local_get_offset_cell, + + is_stack_read_cell, + stack_offset_cell, + + is_i32_cell, + value_cell, + m_read_lookup_cell, + }); + allocators.push(allocator.clone()); + } let common_config = EventTableCommonConfig { enabled_cell, @@ -330,6 +608,7 @@ impl EventTableConfig { pow_table_lookup_power_cell, bit_table_lookup_cells, external_foreign_call_lookup_cell, + uniarg_configs: uniarg_configs.clone(), }; let mut op_bitmaps: BTreeMap = BTreeMap::new(); @@ -338,14 +617,19 @@ impl EventTableConfig { let mut profiler = AllocatorFreeCellsProfiler::new(&allocator); macro_rules! configure { - ($op:expr, $x:ident) => { + ($op:expr, $x:ident, $uniargs_nr:expr) => { let op = OpcodeClassPlain($op as usize); let foreign_table_configs = BTreeMap::new(); let mut constraint_builder = ConstraintBuilder::new(meta, &foreign_table_configs); - let mut allocator = allocator.clone(); - let config = $x::configure(&common_config, &mut allocator, &mut constraint_builder); + let mut allocator = allocators[$uniargs_nr].clone(); + let config = $x::configure_all( + &common_config, + &mut allocator, + &mut constraint_builder, + $uniargs_nr, + ); constraint_builder.finalize(|meta| { (fixed_curr!(meta, step_sel), ops[op.index()].curr_expr(meta)) @@ -358,33 +642,44 @@ impl EventTableConfig { }; } - configure!(OpcodeClass::BinShift, BinShiftConfigBuilder); - configure!(OpcodeClass::Bin, BinConfigBuilder); - configure!(OpcodeClass::BrIfEqz, BrIfEqzConfigBuilder); - configure!(OpcodeClass::BrIf, BrIfConfigBuilder); - configure!(OpcodeClass::Br, BrConfigBuilder); - configure!(OpcodeClass::Call, CallConfigBuilder); - configure!(OpcodeClass::CallHost, ExternalCallHostCircuitConfigBuilder); - configure!(OpcodeClass::Const, ConstConfigBuilder); - configure!(OpcodeClass::Conversion, ConversionConfigBuilder); - configure!(OpcodeClass::Drop, DropConfigBuilder); - configure!(OpcodeClass::GlobalGet, GlobalGetConfigBuilder); - configure!(OpcodeClass::GlobalSet, GlobalSetConfigBuilder); - configure!(OpcodeClass::LocalGet, LocalGetConfigBuilder); - configure!(OpcodeClass::LocalSet, LocalSetConfigBuilder); - configure!(OpcodeClass::LocalTee, LocalTeeConfigBuilder); - configure!(OpcodeClass::Rel, RelConfigBuilder); - configure!(OpcodeClass::Return, ReturnConfigBuilder); - configure!(OpcodeClass::Select, SelectConfigBuilder); - configure!(OpcodeClass::Test, TestConfigBuilder); - configure!(OpcodeClass::Unary, UnaryConfigBuilder); - configure!(OpcodeClass::Load, LoadConfigBuilder); - configure!(OpcodeClass::Store, StoreConfigBuilder); - configure!(OpcodeClass::BinBit, BinBitConfigBuilder); - configure!(OpcodeClass::MemorySize, MemorySizeConfigBuilder); - configure!(OpcodeClass::MemoryGrow, MemoryGrowConfigBuilder); - configure!(OpcodeClass::BrTable, BrTableConfigBuilder); - configure!(OpcodeClass::CallIndirect, CallIndirectConfigBuilder); + // 0 args + configure!(OpcodeClass::Drop, DropConfigBuilder, 0); + configure!(OpcodeClass::Const, ConstConfigBuilder, 0); + configure!(OpcodeClass::Return, ReturnConfigBuilder, 0); + configure!(OpcodeClass::Br, BrConfigBuilder, 0); + configure!(OpcodeClass::Call, CallConfigBuilder, 0); + configure!( + OpcodeClass::CallHost, + ExternalCallHostCircuitConfigBuilder, + 0 + ); + configure!(OpcodeClass::GlobalGet, GlobalGetConfigBuilder, 0); + configure!(OpcodeClass::LocalGet, LocalGetConfigBuilder, 0); + configure!(OpcodeClass::LocalTee, LocalTeeConfigBuilder, 0); + configure!(OpcodeClass::MemorySize, MemorySizeConfigBuilder, 0); + + // 1 args + configure!(OpcodeClass::BrIfEqz, BrIfEqzConfigBuilder, 1); + configure!(OpcodeClass::BrIf, BrIfConfigBuilder, 1); + configure!(OpcodeClass::BrTable, BrTableConfigBuilder, 1); + configure!(OpcodeClass::CallIndirect, CallIndirectConfigBuilder, 1); + configure!(OpcodeClass::Conversion, ConversionConfigBuilder, 1); + configure!(OpcodeClass::GlobalSet, GlobalSetConfigBuilder, 1); + configure!(OpcodeClass::Load, LoadConfigBuilder, 1); + configure!(OpcodeClass::LocalSet, LocalSetConfigBuilder, 1); + configure!(OpcodeClass::MemoryGrow, MemoryGrowConfigBuilder, 1); + configure!(OpcodeClass::Test, TestConfigBuilder, 1); + configure!(OpcodeClass::Unary, UnaryConfigBuilder, 1); + + // 2 args + configure!(OpcodeClass::BinBit, BinBitConfigBuilder, 2); + configure!(OpcodeClass::BinShift, BinShiftConfigBuilder, 2); + configure!(OpcodeClass::Bin, BinConfigBuilder, 2); + configure!(OpcodeClass::Rel, RelConfigBuilder, 2); + configure!(OpcodeClass::Store, StoreConfigBuilder, 2); + + // 3 args + configure!(OpcodeClass::Select, SelectConfigBuilder, 3); macro_rules! configure_foreign { ($x:ident, $i:expr) => { @@ -393,9 +688,9 @@ impl EventTableConfig { let op = OpcodeClassPlain(op); let mut constraint_builder = ConstraintBuilder::new(meta, foreign_table_configs); - let mut allocator = allocator.clone(); + let mut allocator = allocators[0].clone(); - let config = builder.configure( + let config = builder.configure_all( &common_config, &mut allocator, &mut constraint_builder, @@ -522,8 +817,14 @@ impl EventTableConfig { }); meta.create_gate("c5e. sp change", |meta| { + let popped = uniarg_configs + .iter() + .map(|c| c.is_enabled_cell.expr(meta) * c.is_pop_cell.expr(meta)) + .reduce(|a, b| a + b) + .unwrap(); + vec![sum_ops_expr_with_init( - sp_cell.curr_expr(meta) - sp_cell.next_expr(meta), + sp_cell.curr_expr(meta) + popped - sp_cell.next_expr(meta), meta, &|meta, config: &OpcodeConfig| config.0.sp_diff(meta), )] @@ -607,9 +908,33 @@ impl EventTableConfig { }); meta.create_gate("c7. itable_lookup_encode", |meta| { - let opcode = sum_ops_expr(meta, &|meta, config: &OpcodeConfig| { + let mut opcode = sum_ops_expr(meta, &|meta, config: &OpcodeConfig| { Some(config.0.opcode(meta)) }); + + let mut shift = F::one(); + let arg_shift = num_bigint::BigUint::from(1u64) << 66; + for uniarg_config in uniarg_configs.iter().take(3) { + opcode = opcode + + uniarg_config.is_enabled_cell.expr(meta) + * (uniarg_config.is_pop_cell.expr(meta) + * constant_from_bn!(&UniArg::pop_tag()) + + uniarg_config.is_local_get_cell.expr(meta) + * constant_from_bn!(&UniArg::stack_tag()) + + uniarg_config.is_local_get_cell.expr(meta) + * uniarg_config.local_get_offset_cell.expr(meta) + + uniarg_config.is_const_cell.expr(meta) + * constant_from_bn!(&UniArg::i64_const_tag()) + + uniarg_config.is_const_cell.expr(meta) + * uniarg_config.is_i32_cell.expr(meta) + * constant_from_bn!(&UniArg::i64_i32_const_tag()) + + uniarg_config.is_const_cell.expr(meta) + * uniarg_config.const_value_cell.expr(meta)) + * constant!(shift); + + shift *= bn_to_field::(&arg_shift); + } + vec![ (encode_instruction_table_entry(fid_cell.expr(meta), iid_cell.expr(meta), opcode) - itable_lookup_cell.curr_expr(meta)) @@ -618,10 +943,6 @@ impl EventTableConfig { ] }); - image_table.instruction_lookup(meta, "c8a. itable_lookup in itable", |meta| { - itable_lookup_cell.curr_expr(meta) * fixed_curr!(meta, step_sel) - }); - image_table.br_table_lookup(meta, "c8b. brtable_lookup in brtable", |meta| { brtable_lookup_cell.curr_expr(meta) * fixed_curr!(meta, step_sel) }); diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_bin.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_bin.rs index c7fd43aee..8019dbd28 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_bin.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_bin.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -16,22 +17,20 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_bin; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; use specs::itable::BinOp; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct BinConfig { + lhs_arg: EventTableCommonArgsConfig, + rhs_arg: EventTableCommonArgsConfig, lhs: AllocatedU64CellWithFlagBitDyn, rhs: AllocatedU64CellWithFlagBitDyn, - is_i32: AllocatedBitCell, - d: AllocatedU64Cell, d_flag_helper_diff: AllocatedCommonRangeCell, @@ -56,8 +55,6 @@ pub struct BinConfig { degree_helper1: AllocatedUnlimitedCell, degree_helper2: AllocatedUnlimitedCell, - memory_table_lookup_stack_read_lhs: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_rhs: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -69,14 +66,27 @@ impl EventTableOpcodeConfigBuilder for BinConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32 = allocator.alloc_bit_cell(); + let rhs_arg = common_config.uniarg_configs[0].clone(); + let lhs_arg = common_config.uniarg_configs[1].clone(); + let is_i32 = rhs_arg.is_i32_cell; let lhs = allocator .alloc_u64_with_flag_bit_cell_dyn(constraint_builder, move |meta| is_i32.expr(meta)); let rhs = allocator .alloc_u64_with_flag_bit_cell_dyn(constraint_builder, move |meta| is_i32.expr(meta)); + constraint_builder.push( + "op_bin: uniarg", + Box::new(move |meta| { + vec![ + rhs_arg.is_i32_cell.expr(meta) - lhs_arg.is_i32_cell.expr(meta), + rhs_arg.value_cell.expr(meta) - rhs.u64_cell.expr(meta), + lhs_arg.value_cell.expr(meta) - lhs.u64_cell.expr(meta), + ] + }), + ); + let d = allocator.alloc_u64_cell(); - let d_flag_helper_diff = allocator.alloc_common_range_cell(); + let d_flag_helper_diff = allocator.alloc_common_range_cell(); // TODO: u16?? let aux1 = allocator.alloc_u64_cell(); let aux2 = allocator.alloc_u64_cell(); @@ -103,35 +113,14 @@ impl EventTableOpcodeConfigBuilder for BinConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_rhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |meta| rhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - - let memory_table_lookup_stack_read_lhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), - move |meta| lhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator .alloc_memory_table_lookup_write_cell_with_value( "op_bin stack read", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| is_i32.expr(meta), move |____| constant_from!(1), ); @@ -311,9 +300,10 @@ impl EventTableOpcodeConfigBuilder for BinConfigBuilder { ); Box::new(BinConfig { + lhs_arg, + rhs_arg, lhs, rhs, - is_i32, d, d_flag_helper_diff, aux1, @@ -327,8 +317,6 @@ impl EventTableOpcodeConfigBuilder for BinConfigBuilder { is_div_s, is_rem_s, is_div_s_or_rem_s, - memory_table_lookup_stack_read_lhs, - memory_table_lookup_stack_read_rhs, memory_table_lookup_stack_write, size_modulus, res_flag, @@ -343,77 +331,84 @@ impl EventTableOpcodeConfigBuilder for BinConfigBuilder { impl EventTableOpcodeConfig for BinConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Bin as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_add.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::Add as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_sub.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::Sub as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_mul.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::Mul as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_div_u.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::UnsignedDiv as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_rem_u.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::UnsignedRem as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_div_s.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::SignedDiv as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_rem_s.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(BinOp::SignedRem as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) + encode_bin( + self.is_add.expr(meta) * constant_from_bn!(&BigUint::from(BinOp::Add as u64)) + + self.is_sub.expr(meta) * constant_from_bn!(&BigUint::from(BinOp::Sub as u64)) + + self.is_mul.expr(meta) * constant_from_bn!(&BigUint::from(BinOp::Mul as u64)) + + self.is_div_u.expr(meta) + * constant_from_bn!(&BigUint::from(BinOp::UnsignedDiv as u64)) + + self.is_rem_u.expr(meta) + * constant_from_bn!(&BigUint::from(BinOp::UnsignedRem as u64)) + + self.is_div_s.expr(meta) + * constant_from_bn!(&BigUint::from(BinOp::SignedDiv as u64)) + + self.is_rem_s.expr(meta) + * constant_from_bn!(&BigUint::from(BinOp::SignedRem as u64)), + self.rhs_arg.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { - let (class, var_type, shift, left, right, value) = match &entry.eentry.step_info { - StepInfo::I32BinOp { - class, - left, - right, - value, - } => { - let var_type = VarType::I32; - let left = *left as u32 as u64; - let right = *right as u32 as u64; - let value = *value as u32 as u64; - - (class, var_type, 32, left, right, value) - } - - StepInfo::I64BinOp { - class, - left, - right, - value, - } => { - let var_type = VarType::I64; - let left = *left as u64; - let right = *right as u64; - let value = *value as u64; - - (class, var_type, 64, left, right, value) - } - - _ => unreachable!(), - }; + let (class, var_type, shift, left, right, lhs_uniarg, rhs_uniarg, value) = + match &entry.eentry.step_info { + StepInfo::I32BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + } => { + let var_type = VarType::I32; + let left = *left as u32 as u64; + let right = *right as u32 as u64; + let value = *value as u32 as u64; + + ( + class.as_bin_op(), + var_type, + 32, + left, + right, + lhs_uniarg, + rhs_uniarg, + value, + ) + } + + StepInfo::I64BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + .. + } => { + let var_type = VarType::I64; + let left = *left as u64; + let right = *right as u64; + let value = *value as u64; + + ( + class.as_bin_op(), + var_type, + 64, + left, + right, + lhs_uniarg, + rhs_uniarg, + value, + ) + } + + _ => unreachable!(), + }; self.lhs.assign(ctx, left, var_type == VarType::I32)?; self.rhs.assign(ctx, right, var_type == VarType::I32)?; @@ -543,41 +538,11 @@ impl EventTableOpcodeConfig for BinConfig { _ => {} } - if var_type == VarType::I32 { - self.is_i32.assign(ctx, F::one())?; - }; - - self.memory_table_lookup_stack_read_rhs.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - var_type == VarType::I32, - right, - )?; - - self.memory_table_lookup_stack_read_lhs.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - var_type == VarType::I32, - left, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + 2, - LocationType::Stack, - var_type == VarType::I32, - value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.rhs_arg.assign(ctx, &rhs_uniarg, &mut memory_entries)?; + self.lhs_arg.assign(ctx, &lhs_uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -591,6 +556,6 @@ impl EventTableOpcodeConfig for BinConfig { } fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) + Some(constant!(-F::one())) } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_bin_bit.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_bin_bit.rs index 0b2053301..05a226eda 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_bin_bit.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_bin_bit.rs @@ -2,10 +2,10 @@ use crate::circuits::bit_table::BitTableOp; use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -15,24 +15,20 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_bin_bit; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; use specs::itable::BitOp; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct BinBitConfig { - is_i32: AllocatedBitCell, op_class: AllocatedCommonRangeCell, bit_table_lookup: AllocatedBitTableLookupCells, - memory_table_lookup_stack_read_lhs: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_rhs: AllocatedMemoryTableLookupReadCell, + lhs: EventTableCommonArgsConfig, + rhs: EventTableCommonArgsConfig, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -44,56 +40,40 @@ impl EventTableOpcodeConfigBuilder for BinBitConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32 = allocator.alloc_bit_cell(); - let op_class = allocator.alloc_common_range_cell(); + let op_class = allocator.alloc_common_range_cell(); // TODO: u16 let eid = common_config.eid_cell; let sp = common_config.sp_cell; let bit_table_lookup = common_config.bit_table_lookup_cells; - let memory_table_lookup_stack_read_rhs = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |____| constant_from!(1), - ); - let rhs = memory_table_lookup_stack_read_rhs.value_cell; - - let memory_table_lookup_stack_read_lhs = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), - move |____| constant_from!(1), - ); - let lhs = memory_table_lookup_stack_read_lhs.value_cell; + let rhs = common_config.uniarg_configs[0].clone(); + let lhs = common_config.uniarg_configs[1].clone(); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator .alloc_memory_table_lookup_write_cell_with_value( - "op_bin stack read", + "op_bin stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), + move |meta| rhs.is_i32_cell.expr(meta), move |____| constant_from!(1), ); let res = memory_table_lookup_stack_write.value_cell; + constraint_builder.push( + "op_bin_bit: uniarg type consistent", + Box::new(move |meta| vec![rhs.is_i32_cell.expr(meta) - lhs.is_i32_cell.expr(meta)]), + ); + constraint_builder.push( "op_bin_bit: lookup", Box::new(move |meta| { vec![ bit_table_lookup.op.expr(meta) - op_class.expr(meta), - bit_table_lookup.left.expr(meta) - lhs.expr(meta), - bit_table_lookup.right.expr(meta) - rhs.expr(meta), + bit_table_lookup.left.expr(meta) - lhs.value_cell.expr(meta), + bit_table_lookup.right.expr(meta) - rhs.value_cell.expr(meta), bit_table_lookup.result.expr(meta) - res.expr(meta), ] }), @@ -101,10 +81,9 @@ impl EventTableOpcodeConfigBuilder for BinBitConfigBuilder { Box::new(BinBitConfig { op_class, - is_i32, bit_table_lookup, - memory_table_lookup_stack_read_lhs, - memory_table_lookup_stack_read_rhs, + lhs, + rhs, memory_table_lookup_stack_write, }) } @@ -112,49 +91,68 @@ impl EventTableOpcodeConfigBuilder for BinBitConfigBuilder { impl EventTableOpcodeConfig for BinBitConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::BinBit as u64) << OPCODE_CLASS_SHIFT) - )) + self.op_class.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) + encode_bin_bit( + self.op_class.expr(meta), + self.rhs.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { - let (class, vtype, left, right, value) = match entry.eentry.step_info { - StepInfo::I32BinBitOp { - class, - left, - right, - value, - } => { - let vtype = VarType::I32; - let left = left as u32 as u64; - let right = right as u32 as u64; - let value = value as u32 as u64; - (class, vtype, left, right, value) - } - StepInfo::I64BinBitOp { - class, - left, - right, - value, - } => { - let vtype = VarType::I64; - let left = left as u64; - let right = right as u64; - let value = value as u64; - (class, vtype, left, right, value) - } - _ => unreachable!(), - }; - - self.is_i32.assign_bool(ctx, vtype == VarType::I32)?; + let (class, _vtype, left, right, value, lhs_uniarg, rhs_uniarg) = + match entry.eentry.step_info { + StepInfo::I32BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + } => { + let vtype = VarType::I32; + let left = left as u32 as u64; + let right = right as u32 as u64; + let value = value as u32 as u64; + ( + class.as_bit_op(), + vtype, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + ) + } + StepInfo::I64BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + .. + } => { + let vtype = VarType::I64; + let left = left as u64; + let right = right as u64; + let value = value as u64; + ( + class.as_bit_op(), + vtype, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + ) + } + _ => unreachable!(), + }; self.bit_table_lookup .assign(ctx, BitTableOp::BinaryBit(class), left, right, value)?; @@ -171,37 +169,11 @@ impl EventTableOpcodeConfig for BinBitConfig { } }; - self.memory_table_lookup_stack_read_rhs.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - vtype == VarType::I32, - right, - )?; - - self.memory_table_lookup_stack_read_lhs.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - vtype == VarType::I32, - left, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + 2, - LocationType::Stack, - vtype == VarType::I32, - value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.rhs.assign(ctx, &rhs_uniarg, &mut memory_entries)?; + self.lhs.assign(ctx, &lhs_uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -215,6 +187,6 @@ impl EventTableOpcodeConfig for BinBitConfig { } fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) + Some(constant!(-F::one())) } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_bin_shift.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_bin_shift.rs index 85a8c485f..bc7d0133a 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_bin_shift.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_bin_shift.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -17,18 +18,19 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_bin_shift; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; use specs::itable::ShiftOp; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::step::StepInfo; pub struct BinShiftConfig { + lhs_arg: EventTableCommonArgsConfig, + rhs_arg: EventTableCommonArgsConfig, lhs: AllocatedU64CellWithFlagBitDyn, rhs: AllocatedU64Cell, + round: AllocatedU64Cell, rem: AllocatedU64Cell, diff: AllocatedU64Cell, @@ -41,8 +43,6 @@ pub struct BinShiftConfig { rhs_rem: AllocatedCommonRangeCell, rhs_rem_diff: AllocatedCommonRangeCell, - is_i32: AllocatedBitCell, - is_shl: AllocatedBitCell, is_shr_u: AllocatedBitCell, is_shr_s: AllocatedBitCell, @@ -55,8 +55,6 @@ pub struct BinShiftConfig { lookup_pow_modulus: AllocatedUnlimitedCell, lookup_pow_power: AllocatedUnlimitedCell, - memory_table_lookup_stack_read_lhs: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_rhs: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -68,10 +66,24 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32 = allocator.alloc_bit_cell(); + let rhs_arg = common_config.uniarg_configs[0].clone(); + let lhs_arg = common_config.uniarg_configs[1].clone(); + let is_i32 = rhs_arg.is_i32_cell; let lhs = allocator .alloc_u64_with_flag_bit_cell_dyn(constraint_builder, move |meta| is_i32.expr(meta)); let rhs = allocator.alloc_u64_cell(); + + constraint_builder.push( + "op_bin_shift: uniarg", + Box::new(move |meta| { + vec![ + rhs_arg.is_i32_cell.expr(meta) - lhs_arg.is_i32_cell.expr(meta), + rhs_arg.value_cell.expr(meta) - rhs.u64_cell.expr(meta), + lhs_arg.value_cell.expr(meta) - lhs.u64_cell.expr(meta), + ] + }), + ); + let round = allocator.alloc_u64_cell(); let rem = allocator.alloc_u64_cell(); let diff = allocator.alloc_u64_cell(); @@ -79,9 +91,9 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { let rhs_modulus = allocator.alloc_unlimited_cell(); let size_modulus = allocator.alloc_unlimited_cell(); - let rhs_round = allocator.alloc_common_range_cell(); - let rhs_rem = allocator.alloc_common_range_cell(); - let rhs_rem_diff = allocator.alloc_common_range_cell(); + let rhs_round = allocator.alloc_common_range_cell(); // TODO: u16?? + let rhs_rem = allocator.alloc_common_range_cell(); // TODO: u16?? + let rhs_rem_diff = allocator.alloc_common_range_cell(); // TODO: u16?? let is_shl = allocator.alloc_bit_cell(); let is_shr_u = allocator.alloc_bit_cell(); @@ -100,35 +112,14 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_rhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin_shift stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |meta| rhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - - let memory_table_lookup_stack_read_lhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin_shift stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), - move |meta| lhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator .alloc_memory_table_lookup_write_cell_with_value( "op_bin_shift stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| is_i32.expr(meta), move |____| constant_from!(1), ); @@ -283,6 +274,8 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { ); Box::new(BinShiftConfig { + lhs_arg, + rhs_arg, lhs, rhs, round, @@ -293,7 +286,6 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { rhs_round, rhs_rem, rhs_rem_diff, - is_i32, is_shl, is_shr_u, is_shr_s, @@ -303,8 +295,6 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { is_r, lookup_pow_modulus, lookup_pow_power, - memory_table_lookup_stack_read_lhs, - memory_table_lookup_stack_read_rhs, memory_table_lookup_stack_write, rhs_modulus, size_modulus, @@ -315,44 +305,35 @@ impl EventTableOpcodeConfigBuilder for BinShiftConfigBuilder { impl EventTableOpcodeConfig for BinShiftConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::BinShift as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_shl.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(ShiftOp::Shl as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_shr_u.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(ShiftOp::UnsignedShr as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_shr_s.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(ShiftOp::SignedShr as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_rotl.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(ShiftOp::Rotl as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_rotr.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(ShiftOp::Rotr as u64) << OPCODE_ARG0_SHIFT) - )) - + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) + encode_bin_shift( + self.is_shl.expr(meta) * constant_from_bn!(&(BigUint::from(ShiftOp::Shl as u64))) + + self.is_shr_u.expr(meta) + * constant_from_bn!(&(BigUint::from(ShiftOp::UnsignedShr as u64))) + + self.is_shr_s.expr(meta) + * constant_from_bn!(&(BigUint::from(ShiftOp::SignedShr as u64))) + + self.is_rotl.expr(meta) + * constant_from_bn!(&(BigUint::from(ShiftOp::Rotl as u64))) + + self.is_rotr.expr(meta) + * constant_from_bn!(&(BigUint::from(ShiftOp::Rotr as u64))), + self.rhs_arg.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { - let (class, left, right, value, power, is_eight_bytes, _is_sign) = + let (class, left, right, value, power, is_eight_bytes, _is_sign, lhs_uniarg, rhs_uniarg) = match entry.eentry.step_info { - StepInfo::I32BinShiftOp { + StepInfo::I32BinOp { class, left, + lhs_uniarg, right, + rhs_uniarg, value, } => { let left = left as u32 as u64; @@ -361,14 +342,27 @@ impl EventTableOpcodeConfig for BinShiftConfig { let power = right % 32; let is_eight_bytes = false; let is_sign = true; - (class, left, right, value, power, is_eight_bytes, is_sign) + ( + class.as_shift_op(), + left, + right, + value, + power, + is_eight_bytes, + is_sign, + lhs_uniarg, + rhs_uniarg, + ) } - StepInfo::I64BinShiftOp { + StepInfo::I64BinOp { class, left, + lhs_uniarg, right, + rhs_uniarg, value, + .. } => { let left = left as u64; let right = right as u64; @@ -376,7 +370,17 @@ impl EventTableOpcodeConfig for BinShiftConfig { let power = right % 64; let is_eight_bytes = true; let is_sign = true; - (class, left, right, value, power, is_eight_bytes, is_sign) + ( + class.as_shift_op(), + left, + right, + value, + power, + is_eight_bytes, + is_sign, + lhs_uniarg, + rhs_uniarg, + ) } _ => { @@ -407,8 +411,6 @@ impl EventTableOpcodeConfig for BinShiftConfig { self.lookup_pow_modulus.assign(ctx, modulus.into())?; self.lookup_pow_power .assign_bn(ctx, &pow_table_power_encode(BigUint::from(power)))?; - self.is_i32 - .assign(ctx, if is_eight_bytes { F::zero() } else { F::one() })?; self.res.assign(ctx, F::from(value))?; self.rhs_modulus .assign_u32(ctx, if is_eight_bytes { 64 } else { 32 })?; @@ -479,37 +481,12 @@ impl EventTableOpcodeConfig for BinShiftConfig { } } - self.memory_table_lookup_stack_read_rhs.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - !is_eight_bytes, - right, - )?; - - self.memory_table_lookup_stack_read_lhs.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - !is_eight_bytes, - left, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + 2, - LocationType::Stack, - !is_eight_bytes, - value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + + self.rhs_arg.assign(ctx, &rhs_uniarg, &mut memory_entries)?; + self.lhs_arg.assign(ctx, &lhs_uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -523,6 +500,6 @@ impl EventTableOpcodeConfig for BinShiftConfig { } fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) + Some(constant!(-F::one())) } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_br.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_br.rs index 83b15c085..9bd5534d8 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_br.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_br.rs @@ -90,7 +90,7 @@ impl EventTableOpcodeConfig for BrConfig { fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { @@ -112,26 +112,11 @@ impl EventTableOpcodeConfig for BrConfig { self.value_cell.assign(ctx, keep_values[0])?; self.is_i32_cell.assign(ctx, F::from(keep_type as u64))?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + *drop + 1, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.memory_table_lookup_stack_read + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; } self.dst_pc_cell.assign(ctx, F::from((*dst_pc) as u64))?; diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_br_if.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_br_if.rs index fa8ce289a..4287e38f7 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_br_if.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_br_if.rs @@ -1,31 +1,28 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_br_if; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct BrIfConfig { - cond_cell: AllocatedU64Cell, + cond_arg: EventTableCommonArgsConfig, + cond_inv_cell: AllocatedUnlimitedCell, cond_is_zero_cell: AllocatedBitCell, cond_is_not_zero_cell: AllocatedBitCell, @@ -34,8 +31,7 @@ pub struct BrIfConfig { is_i32_cell: AllocatedBitCell, drop_cell: AllocatedCommonRangeCell, dst_pc_cell: AllocatedCommonRangeCell, - value_cell: AllocatedU64Cell, - memory_table_lookup_stack_read_cond: AllocatedMemoryTableLookupReadCell, + memory_table_lookup_stack_read_return_value: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write_return_value: AllocatedMemoryTableLookupWriteCell, } @@ -48,7 +44,13 @@ impl EventTableOpcodeConfigBuilder for BrIfConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let cond_cell = allocator.alloc_u64_cell(); + let cond_arg = common_config.uniarg_configs[0].clone(); + let cond_cell = cond_arg.value_cell; + constraint_builder.push( + "op_br_if: uniarg", + Box::new(move |meta| vec![cond_arg.is_i32_cell.expr(meta) - constant_from!(1)]), + ); + let cond_inv_cell = allocator.alloc_unlimited_cell(); let cond_is_zero_cell = allocator.alloc_bit_cell(); let cond_is_not_zero_cell = allocator.alloc_bit_cell(); @@ -57,9 +59,8 @@ impl EventTableOpcodeConfigBuilder for BrIfConfigBuilder { "op_br_if cond bit", Box::new(move |meta| { vec![ - cond_is_zero_cell.expr(meta) * cond_cell.u64_cell.expr(meta), - cond_is_zero_cell.expr(meta) - + cond_cell.u64_cell.expr(meta) * cond_inv_cell.expr(meta) + cond_is_zero_cell.expr(meta) * cond_cell.expr(meta), + cond_is_zero_cell.expr(meta) + cond_cell.expr(meta) * cond_inv_cell.expr(meta) - constant_from!(1), cond_is_zero_cell.expr(meta) + cond_is_not_zero_cell.expr(meta) - constant_from!(1), @@ -71,46 +72,42 @@ impl EventTableOpcodeConfigBuilder for BrIfConfigBuilder { let is_i32_cell = allocator.alloc_bit_cell(); let drop_cell = allocator.alloc_common_range_cell(); let dst_pc_cell = allocator.alloc_common_range_cell(); - let value_cell = allocator.alloc_u64_cell(); let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_cond = allocator.alloc_memory_table_lookup_read_cell( - "op_br_if stack read cond", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |meta| cond_cell.u64_cell.expr(meta), - move |____| constant_from!(1), - ); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_read_return_value = allocator - .alloc_memory_table_lookup_read_cell( + .alloc_memory_table_lookup_read_cell_with_value( "op_br_if stack read return value", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta) + constant_from!(1), move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), move |meta| keep_cell.expr(meta) * cond_is_not_zero_cell.expr(meta), ); + let value_cell = memory_table_lookup_stack_read_return_value.value_cell; + + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write_return_value = allocator .alloc_memory_table_lookup_write_cell( "op_br_if stack write return value", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + drop_cell.expr(meta) + constant_from!(2), + move |meta| { + Self::sp_after_uniarg(sp, &uniarg_configs, meta) + + drop_cell.expr(meta) + + constant_from!(1) + }, move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), + move |meta| value_cell.expr(meta), move |meta| keep_cell.expr(meta) * cond_is_not_zero_cell.expr(meta), ); Box::new(BrIfConfig { - cond_cell, + cond_arg, cond_inv_cell, cond_is_zero_cell, cond_is_not_zero_cell, @@ -118,8 +115,6 @@ impl EventTableOpcodeConfigBuilder for BrIfConfigBuilder { is_i32_cell, drop_cell, dst_pc_cell, - value_cell, - memory_table_lookup_stack_read_cond, memory_table_lookup_stack_read_return_value, memory_table_lookup_stack_write_return_value, }) @@ -128,13 +123,12 @@ impl EventTableOpcodeConfigBuilder for BrIfConfigBuilder { impl EventTableOpcodeConfig for BrIfConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::BrIf as u64) << OPCODE_CLASS_SHIFT) - )) + self.drop_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.keep_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) - + self.dst_pc_cell.expr(meta) + encode_br_if( + self.drop_cell.expr(meta), + self.keep_cell.expr(meta), + self.dst_pc_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -149,60 +143,34 @@ impl EventTableOpcodeConfig for BrIfConfig { dst_pc, drop, keep, - keep_values, + uniarg, + .. } => { assert!(keep.len() <= 1); let cond = *condition as u32 as u64; - self.memory_table_lookup_stack_read_cond.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - cond, - )?; - - self.drop_cell.assign(ctx, F::from(*drop as u64))?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.cond_arg.assign(ctx, &uniarg, &mut memory_entries)?; if !keep.is_empty() { let keep_type: VarType = keep[0].into(); self.keep_cell.assign(ctx, F::one())?; - self.value_cell.assign(ctx, keep_values[0])?; self.is_i32_cell.assign(ctx, F::from(keep_type as u64))?; if *condition != 0 { - self.memory_table_lookup_stack_read_return_value.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; - - self.memory_table_lookup_stack_write_return_value.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + *drop + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; + self.memory_table_lookup_stack_read_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; } } - self.cond_cell.assign(ctx, cond)?; if cond != 0 { self.cond_inv_cell .assign(ctx, step.field_helper.invert(cond))?; } + self.drop_cell.assign(ctx, F::from(*drop as u64))?; self.cond_is_zero_cell .assign(ctx, if cond == 0 { F::one() } else { F::zero() })?; self.cond_is_not_zero_cell @@ -216,7 +184,7 @@ impl EventTableOpcodeConfig for BrIfConfig { } fn sp_diff(&self, meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant_from!(1) + self.cond_is_not_zero_cell.expr(meta) * self.drop_cell.expr(meta)) + Some(self.cond_is_not_zero_cell.expr(meta) * self.drop_cell.expr(meta)) } fn mops(&self, meta: &mut VirtualCells<'_, F>) -> Option> { diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_br_if_eqz.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_br_if_eqz.rs index 75166f8a9..67ce23455 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_br_if_eqz.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_br_if_eqz.rs @@ -1,30 +1,27 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_br_if_eqz; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct BrIfEqzConfig { + cond_arg: EventTableCommonArgsConfig, cond_inv_cell: AllocatedUnlimitedCell, cond_is_zero_cell: AllocatedBitCell, cond_is_not_zero_cell: AllocatedBitCell, @@ -33,7 +30,6 @@ pub struct BrIfEqzConfig { is_i32_cell: AllocatedBitCell, drop_cell: AllocatedCommonRangeCell, dst_pc_cell: AllocatedCommonRangeCell, - memory_table_lookup_stack_read_cond: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_read_return_value: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write_return_value: AllocatedMemoryTableLookupWriteCell, } @@ -46,49 +42,50 @@ impl EventTableOpcodeConfigBuilder for BrIfEqzConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { + let cond_arg = common_config.uniarg_configs[0].clone(); + let cond_cell = cond_arg.value_cell; + constraint_builder.push( + "op_br_if: uniarg", + Box::new(move |meta| vec![cond_arg.is_i32_cell.expr(meta) - constant_from!(1)]), + ); + let cond_inv_cell = allocator.alloc_unlimited_cell(); let cond_is_zero_cell = allocator.alloc_bit_cell(); let cond_is_not_zero_cell = allocator.alloc_bit_cell(); let keep_cell = allocator.alloc_bit_cell(); let is_i32_cell = allocator.alloc_bit_cell(); - let drop_cell = allocator.alloc_common_range_cell(); - let dst_pc_cell = allocator.alloc_common_range_cell(); + let drop_cell = allocator.alloc_common_range_cell(); // TODO: u16?? + let dst_pc_cell = allocator.alloc_common_range_cell(); // TODO: u16?? let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_cond = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "op_br_if stack read cond", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |____| constant_from!(1), - ); - let cond_cell = memory_table_lookup_stack_read_cond.value_cell; - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_read_return_value = allocator .alloc_memory_table_lookup_read_cell_with_value( "op_br_if_eqz stack read return value", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta) + constant_from!(1), move |meta| is_i32_cell.expr(meta), move |meta| keep_cell.expr(meta) * cond_is_zero_cell.expr(meta), ); let value_cell = memory_table_lookup_stack_read_return_value.value_cell; + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write_return_value = allocator .alloc_memory_table_lookup_write_cell( "op_br_if_eqz stack write return value", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + drop_cell.expr(meta) + constant_from!(2), + move |meta| { + Self::sp_after_uniarg(sp, &uniarg_configs, meta) + + drop_cell.expr(meta) + + constant_from!(1) + }, move |meta| is_i32_cell.expr(meta), move |meta| value_cell.expr(meta), move |meta| keep_cell.expr(meta) * cond_is_zero_cell.expr(meta), @@ -108,6 +105,7 @@ impl EventTableOpcodeConfigBuilder for BrIfEqzConfigBuilder { )); Box::new(BrIfEqzConfig { + cond_arg, cond_inv_cell, cond_is_zero_cell, cond_is_not_zero_cell, @@ -115,7 +113,6 @@ impl EventTableOpcodeConfigBuilder for BrIfEqzConfigBuilder { is_i32_cell, drop_cell, dst_pc_cell, - memory_table_lookup_stack_read_cond, memory_table_lookup_stack_read_return_value, memory_table_lookup_stack_write_return_value, }) @@ -124,13 +121,12 @@ impl EventTableOpcodeConfigBuilder for BrIfEqzConfigBuilder { impl EventTableOpcodeConfig for BrIfEqzConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::BrIfEqz as u64) << OPCODE_CLASS_SHIFT) - )) + self.drop_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.keep_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) - + self.dst_pc_cell.expr(meta) + encode_br_if_eqz( + self.drop_cell.expr(meta), + self.keep_cell.expr(meta), + self.dst_pc_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -145,24 +141,15 @@ impl EventTableOpcodeConfig for BrIfEqzConfig { dst_pc, drop, keep, - keep_values, + uniarg, + .. } => { assert!(keep.len() <= 1); let cond = *condition as u32 as u64; - self.memory_table_lookup_stack_read_cond.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - cond, - )?; - - self.drop_cell.assign(ctx, F::from(*drop as u64))?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.cond_arg.assign(ctx, &uniarg, &mut memory_entries)?; if !keep.is_empty() { let keep_type: VarType = keep[0].into(); @@ -170,26 +157,10 @@ impl EventTableOpcodeConfig for BrIfEqzConfig { self.keep_cell.assign(ctx, F::one())?; self.is_i32_cell.assign(ctx, F::from(keep_type as u64))?; if *condition == 0 { - self.memory_table_lookup_stack_read_return_value.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; - - self.memory_table_lookup_stack_write_return_value.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + *drop + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; + self.memory_table_lookup_stack_read_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; } } @@ -197,6 +168,7 @@ impl EventTableOpcodeConfig for BrIfEqzConfig { self.cond_inv_cell .assign(ctx, step.field_helper.invert(cond))?; } + self.drop_cell.assign(ctx, F::from(*drop as u64))?; self.cond_is_zero_cell .assign(ctx, if cond == 0 { F::one() } else { F::zero() })?; self.cond_is_not_zero_cell @@ -210,7 +182,7 @@ impl EventTableOpcodeConfig for BrIfEqzConfig { } fn sp_diff(&self, meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant_from!(1) + self.cond_is_zero_cell.expr(meta) * self.drop_cell.expr(meta)) + Some(self.cond_is_zero_cell.expr(meta) * self.drop_cell.expr(meta)) } fn mops(&self, meta: &mut VirtualCells<'_, F>) -> Option> { diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_br_table.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_br_table.rs index a1808977e..4436e2bb3 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_br_table.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_br_table.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -15,6 +16,7 @@ use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; use specs::encode::br_table::encode_br_table_entry; use specs::encode::opcode::encode_br_table; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; use specs::mtable::LocationType; use specs::mtable::VarType; @@ -27,7 +29,7 @@ pub struct BrTableConfig { drop: AllocatedCommonRangeCell, dst_iid: AllocatedCommonRangeCell, - expected_index: AllocatedU64Cell, + expected_index_arg: EventTableCommonArgsConfig, effective_index: AllocatedCommonRangeCell, targets_len: AllocatedCommonRangeCell, is_out_of_bound: AllocatedBitCell, @@ -36,7 +38,6 @@ pub struct BrTableConfig { br_table_lookup: AllocatedUnlimitedCell, - memory_table_lookup_stack_read_index: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_read_return_value: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write_return_value: AllocatedMemoryTableLookupWriteCell, } @@ -54,13 +55,21 @@ impl EventTableOpcodeConfigBuilder for BrTableConfigBuilder { let keep_value = allocator.alloc_u64_cell(); let drop = allocator.alloc_common_range_cell(); let dst_iid = allocator.alloc_common_range_cell(); - let expected_index = allocator.alloc_u64_cell(); let effective_index = allocator.alloc_common_range_cell(); let targets_len = allocator.alloc_common_range_cell(); let is_out_of_bound = allocator.alloc_bit_cell(); let is_not_out_of_bound = allocator.alloc_bit_cell(); let diff = allocator.alloc_u64_cell(); + let expected_index_arg = common_config.uniarg_configs[0].clone(); + let expected_index = expected_index_arg.value_cell; + constraint_builder.push( + "select: uniarg", + Box::new(move |meta| { + vec![expected_index_arg.is_i32_cell.expr(meta) - constant_from!(1)] + }), + ); + constraint_builder.push( "op_br_table oob", Box::new(move |meta| { @@ -114,36 +123,31 @@ impl EventTableOpcodeConfigBuilder for BrTableConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_index = allocator.alloc_memory_table_lookup_read_cell( - "op_br_table stack read index", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |meta| expected_index.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_read_return_value = allocator .alloc_memory_table_lookup_read_cell( "op_br_table stack read index", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta) + constant_from!(1), move |meta| keep_is_i32.expr(meta), move |meta| keep_value.expr(meta), move |meta| keep.expr(meta), ); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write_return_value = allocator .alloc_memory_table_lookup_write_cell( "op_br stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + drop.expr(meta) + constant_from!(2), + move |meta| { + Self::sp_after_uniarg(sp, &uniarg_configs, meta) + + drop.expr(meta) + + constant_from!(1) + }, move |meta| keep_is_i32.expr(meta), move |meta| keep_value.expr(meta), move |meta| keep.expr(meta), @@ -155,14 +159,13 @@ impl EventTableOpcodeConfigBuilder for BrTableConfigBuilder { keep_value, drop, dst_iid, - expected_index, + expected_index_arg, effective_index, targets_len, is_out_of_bound, is_not_out_of_bound, diff, br_table_lookup, - memory_table_lookup_stack_read_index, memory_table_lookup_stack_read_return_value, memory_table_lookup_stack_write_return_value, }) @@ -171,7 +174,7 @@ impl EventTableOpcodeConfigBuilder for BrTableConfigBuilder { impl EventTableOpcodeConfig for BrTableConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - encode_br_table(self.targets_len.expr(meta)) + encode_br_table(self.targets_len.expr(meta), UniArgEncode::Reserve) } fn assign( @@ -187,12 +190,13 @@ impl EventTableOpcodeConfig for BrTableConfig { drop, keep, keep_values, + uniarg, } => { assert!(keep.len() <= 1); let index = *index as u32 as u64; let targets = match &entry.eentry.get_instruction(step.current.itable).opcode { - specs::itable::Opcode::BrTable { targets } => targets.clone(), + specs::itable::Opcode::BrTable { targets, .. } => targets.clone(), _ => unreachable!(), }; let targets_len = targets.len() as u64; @@ -200,16 +204,10 @@ impl EventTableOpcodeConfig for BrTableConfig { self.drop.assign(ctx, F::from(*drop as u64))?; self.dst_iid.assign(ctx, F::from(*dst_pc as u64))?; - self.memory_table_lookup_stack_read_index.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - index, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + + self.expected_index_arg + .assign(ctx, &uniarg, &mut memory_entries)?; if !keep.is_empty() { let keep_type: VarType = keep[0].into(); @@ -219,26 +217,10 @@ impl EventTableOpcodeConfig for BrTableConfig { self.keep_is_i32 .assign_bool(ctx, keep_type == VarType::I32)?; - self.memory_table_lookup_stack_read_return_value.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; - - self.memory_table_lookup_stack_write_return_value.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + drop + 2, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; + self.memory_table_lookup_stack_read_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write_return_value + .assign_with_memory_entry(ctx, &mut memory_entries)?; } self.targets_len.assign(ctx, F::from(targets_len))?; @@ -248,7 +230,6 @@ impl EventTableOpcodeConfig for BrTableConfig { } else { targets_len - 1 }; - self.expected_index.assign(ctx, index)?; self.effective_index.assign(ctx, F::from(effective_index))?; self.is_out_of_bound .assign_bool(ctx, index != effective_index)?; @@ -282,7 +263,7 @@ impl EventTableOpcodeConfig for BrTableConfig { } fn sp_diff(&self, meta: &mut VirtualCells<'_, F>) -> Option> { - Some(self.drop.expr(meta) + constant_from!(1)) + Some(self.drop.expr(meta)) } fn next_iid( diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_call_host_foreign_circuit.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_call_host_foreign_circuit.rs index d363bbd5d..da6ef2038 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_call_host_foreign_circuit.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_call_host_foreign_circuit.rs @@ -138,9 +138,9 @@ impl EventTableOpcodeConfig for ExternalCallHostCircuitConfig ExternalHostCallSignature::Argument => { self.memory_table_lookup_stack_read.assign( ctx, - entry.memory_rw_entires[0].start_eid, + entry.memory_rw_entries[0].start_eid, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp + 1, LocationType::Stack, false, @@ -151,7 +151,7 @@ impl EventTableOpcodeConfig for ExternalCallHostCircuitConfig self.memory_table_lookup_stack_write.assign( ctx, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp, LocationType::Stack, false, diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_call_indirect.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_call_indirect.rs index 135d990f2..62d67af35 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_call_indirect.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_call_indirect.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -9,7 +10,6 @@ use crate::circuits::jtable::JumpTableConfig; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; @@ -19,18 +19,19 @@ use num_bigint::BigUint; use specs::encode::br_table::encode_elem_entry; use specs::encode::frame_table::encode_frame_table_entry; use specs::encode::opcode::encode_call_indirect; -use specs::mtable::LocationType; +use specs::encode::opcode::UniArgEncode; use specs::step::StepInfo; pub struct CallIndirectConfig { + offset_arg: EventTableCommonArgsConfig, + offset: AllocatedCommonRangeCell, + is_returned_cell: AllocatedBitCell, type_index: AllocatedCommonRangeCell, func_index: AllocatedCommonRangeCell, - offset: AllocatedCommonRangeCell, table_index: AllocatedCommonRangeCell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, elem_lookup: AllocatedUnlimitedCell, frame_table_lookup: AllocatedUnlimitedCell, } @@ -71,18 +72,16 @@ impl EventTableOpcodeConfigBuilder for CallIndirectConfigBuilder }), ); - let eid = common_config.eid_cell; - let sp = common_config.sp_cell; - - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_call_indirect stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |meta| offset.expr(meta), - move |____| constant_from!(1), + let offset_arg = common_config.uniarg_configs[0].clone(); + constraint_builder.push( + "select: uniarg", + Box::new(move |meta| { + vec![ + offset_arg.is_i32_cell.expr(meta) - constant_from!(1), + // keep offset because it is limited by common range + offset.expr(meta) - offset_arg.value_cell.expr(meta), + ] + }), ); let fid_cell = common_config.fid_cell; @@ -108,12 +107,12 @@ impl EventTableOpcodeConfigBuilder for CallIndirectConfigBuilder )); Box::new(CallIndirectConfig { + offset_arg, + offset, is_returned_cell: common_config.is_returned_cell, type_index, func_index, - offset, table_index, - memory_table_lookup_stack_read, elem_lookup, frame_table_lookup, }) @@ -122,7 +121,7 @@ impl EventTableOpcodeConfigBuilder for CallIndirectConfigBuilder impl EventTableOpcodeConfig for CallIndirectConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - encode_call_indirect(self.type_index.expr(meta)) + encode_call_indirect(self.type_index.expr(meta), UniArgEncode::Reserve) } fn assign( @@ -137,6 +136,7 @@ impl EventTableOpcodeConfig for CallIndirectConfig { type_index, offset, func_index, + uniarg, .. } => { self.table_index.assign(ctx, F::from(*table_index as u64))?; @@ -154,16 +154,8 @@ impl EventTableOpcodeConfig for CallIndirectConfig { ), )?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - *offset as u64, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.offset_arg.assign(ctx, &uniarg, &mut memory_entries)?; self.frame_table_lookup.cell.assign_bn( ctx, @@ -192,10 +184,6 @@ impl EventTableOpcodeConfig for CallIndirectConfig { } } - fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) - } - fn call_ops_expr(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { Some(constant_from!(self.call_ops() as u64)) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_const.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_const.rs index 0aaba251d..ed4a34102 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_const.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_const.rs @@ -4,7 +4,6 @@ use crate::circuits::etable::ConstraintBuilder; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,11 +13,8 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_const; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::step::StepInfo; @@ -63,11 +59,7 @@ impl EventTableOpcodeConfigBuilder for ConstConfigBuilder { impl EventTableOpcodeConfig for ConstConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Const as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.value.u64_cell.expr(meta) + encode_const(self.is_i32.expr(meta), self.value.u64_cell.expr(meta)) } fn assign( @@ -83,7 +75,7 @@ impl EventTableOpcodeConfig for ConstConfig { self.memory_table_lookup_stack_write.assign( ctx, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp, LocationType::Stack, true, @@ -97,7 +89,7 @@ impl EventTableOpcodeConfig for ConstConfig { self.memory_table_lookup_stack_write.assign( ctx, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp, LocationType::Stack, false, diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_conversion.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_conversion.rs index 0cebbd0b3..843212348 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_conversion.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_conversion.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -8,6 +9,7 @@ use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; +use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; @@ -15,18 +17,20 @@ use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; use specs::encode::opcode::encode_conversion; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct ConversionConfig { + value_arg: EventTableCommonArgsConfig, + value: AllocatedU64Cell, value_is_i8: AllocatedBitCell, value_is_i16: AllocatedBitCell, value_is_i32: AllocatedBitCell, value_is_i64: AllocatedBitCell, - value_type_is_i32: AllocatedBitCell, res_is_i32: AllocatedBitCell, res_is_i64: AllocatedBitCell, @@ -43,7 +47,6 @@ pub struct ConversionConfig { shift: AllocatedUnlimitedCell, padding: AllocatedUnlimitedCell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -62,8 +65,6 @@ impl EventTableOpcodeConfigBuilder for ConversionConfigBuilder { let value_is_i32 = allocator.alloc_bit_cell(); let value_is_i64 = allocator.alloc_bit_cell(); - let value_type_is_i32 = allocator.alloc_bit_cell(); - let res_is_i32 = allocator.alloc_bit_cell(); let res_is_i64 = allocator.alloc_bit_cell(); @@ -82,24 +83,21 @@ impl EventTableOpcodeConfigBuilder for ConversionConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_conversion stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| value_type_is_i32.expr(meta), - move |meta| value.expr(meta), - move |____| constant_from!(1), + let value_arg = common_config.uniarg_configs[0].clone(); + + constraint_builder.push( + "select: uniarg", + Box::new(move |meta| vec![value_arg.value_cell.expr(meta) - value.expr(meta)]), ); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator .alloc_memory_table_lookup_write_cell_with_value( "op_conversion stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| res_is_i32.expr(meta), move |____| constant_from!(1), ); @@ -179,12 +177,12 @@ impl EventTableOpcodeConfigBuilder for ConversionConfigBuilder { ); Box::new(ConversionConfig { + value_arg, value, value_is_i8, value_is_i16, value_is_i32, value_is_i64, - value_type_is_i32, res_is_i32, res_is_i64, sign_op, @@ -196,7 +194,6 @@ impl EventTableOpcodeConfigBuilder for ConversionConfigBuilder { modulus, shift, padding, - memory_table_lookup_stack_read, memory_table_lookup_stack_write, }) } @@ -206,25 +203,26 @@ impl EventTableOpcodeConfig for ConversionConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { encode_conversion::>( self.sign_op.expr(meta), - self.value_type_is_i32.expr(meta), + self.value_arg.is_i32_cell.expr(meta), self.value_is_i8.expr(meta), self.value_is_i16.expr(meta), self.value_is_i32.expr(meta), self.value_is_i64.expr(meta), self.res_is_i32.expr(meta), self.res_is_i64.expr(meta), + UniArgEncode::Reserve, ) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { - let (is_sign_op, value, value_type, result, result_type, padding, shift) = + let (is_sign_op, value, _value_type, result_type, padding, shift, uniarg) = match &entry.eentry.step_info { - StepInfo::I32WrapI64 { value, result } => { + StepInfo::I32WrapI64 { value, uniarg, .. } => { self.value_is_i64.assign_bool(ctx, true)?; self.res_is_i32.assign_bool(ctx, true)?; self.is_i32_wrap_i64.assign_bool(ctx, true)?; @@ -233,16 +231,17 @@ impl EventTableOpcodeConfig for ConversionConfig { false, *value as u64, VarType::I64, - *result as u32 as u64, VarType::I32, 0, 1u64 << 31, // To meet `op_conversion: sign extension` constraint + uniarg, ) } StepInfo::I64ExtendI32 { value, - result, sign, + uniarg, + .. } => { self.value_is_i32.assign_bool(ctx, true)?; self.res_is_i64.assign_bool(ctx, true)?; @@ -251,13 +250,13 @@ impl EventTableOpcodeConfig for ConversionConfig { *sign, *value as u32 as u64, VarType::I32, - *result as u64, VarType::I64, u64::MAX << 32, 1 << 31, + uniarg, ) } - StepInfo::I32SignExtendI8 { value, result } => { + StepInfo::I32SignExtendI8 { value, uniarg, .. } => { self.value_is_i8.assign_bool(ctx, true)?; self.res_is_i32.assign_bool(ctx, true)?; @@ -265,13 +264,13 @@ impl EventTableOpcodeConfig for ConversionConfig { true, *value as u32 as u64, VarType::I32, - *result as u32 as u64, VarType::I32, (u32::MAX << 8) as u64, 1 << 7, + uniarg, ) } - StepInfo::I32SignExtendI16 { value, result } => { + StepInfo::I32SignExtendI16 { value, uniarg, .. } => { self.value_is_i16.assign_bool(ctx, true)?; self.res_is_i32.assign_bool(ctx, true)?; @@ -279,13 +278,13 @@ impl EventTableOpcodeConfig for ConversionConfig { true, *value as u32 as u64, VarType::I32, - *result as u32 as u64, VarType::I32, (u32::MAX << 16) as u64, 1 << 15, + uniarg, ) } - StepInfo::I64SignExtendI8 { value, result } => { + StepInfo::I64SignExtendI8 { value, uniarg, .. } => { self.value_is_i8.assign_bool(ctx, true)?; self.res_is_i64.assign_bool(ctx, true)?; @@ -293,13 +292,13 @@ impl EventTableOpcodeConfig for ConversionConfig { true, *value as u64, VarType::I64, - *result as u64, VarType::I64, u64::MAX << 8, 1 << 7, + uniarg, ) } - StepInfo::I64SignExtendI16 { value, result } => { + StepInfo::I64SignExtendI16 { value, uniarg, .. } => { self.value_is_i16.assign_bool(ctx, true)?; self.res_is_i64.assign_bool(ctx, true)?; @@ -307,13 +306,13 @@ impl EventTableOpcodeConfig for ConversionConfig { true, *value as u64, VarType::I64, - *result as u64, VarType::I64, u64::MAX << 16, 1 << 15, + uniarg, ) } - StepInfo::I64SignExtendI32 { value, result } => { + StepInfo::I64SignExtendI32 { value, uniarg, .. } => { self.value_is_i32.assign_bool(ctx, true)?; self.res_is_i64.assign_bool(ctx, true)?; @@ -321,18 +320,16 @@ impl EventTableOpcodeConfig for ConversionConfig { true, *value as u64, VarType::I64, - *result as u64, VarType::I64, u64::MAX << 32, 1 << 31, + uniarg, ) } _ => unreachable!(), }; self.value.assign(ctx, value)?; - self.value_type_is_i32 - .assign(ctx, F::from(value_type as u64))?; self.res_is_i32.assign(ctx, F::from(result_type as u64))?; self.sign_op.assign_bool(ctx, is_sign_op)?; @@ -349,26 +346,11 @@ impl EventTableOpcodeConfig for ConversionConfig { .assign(ctx, bn_to_field(&BigUint::from(modulus)))?; self.padding.assign(ctx, F::from(padding))?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - value_type == VarType::I32, - value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 1, - LocationType::Stack, - result_type == VarType::I32, - result, - )?; + let mut memory_rw_entries = entry.memory_rw_entries.iter(); + self.value_arg + .assign(ctx, &uniarg, &mut memory_rw_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; Ok(()) } @@ -380,4 +362,8 @@ impl EventTableOpcodeConfig for ConversionConfig { fn memory_writing_ops(&self, _: &EventTableEntry) -> u32 { 1 } + + fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { + Some(constant!(-F::one())) + } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_drop.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_drop.rs index 0095a7c09..66b388662 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_drop.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_drop.rs @@ -3,19 +3,15 @@ use crate::circuits::etable::ConstraintBuilder; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; use crate::constant_from; -use crate::constant_from_bn; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_CLASS_SHIFT; +use specs::encode::opcode::encode_drop; use specs::step::StepInfo; pub struct DropConfig; @@ -34,7 +30,7 @@ impl EventTableOpcodeConfigBuilder for DropConfigBuilder { impl EventTableOpcodeConfig for DropConfig { fn opcode(&self, _: &mut VirtualCells<'_, F>) -> Expression { - constant_from_bn!(&(BigUint::from(OpcodeClass::Drop as u64) << OPCODE_CLASS_SHIFT)) + encode_drop() } fn assign( diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_global_get.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_global_get.rs index 1c36f411e..64c0199de 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_global_get.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_global_get.rs @@ -16,7 +16,6 @@ use halo2_proofs::plonk::VirtualCells; use specs::encode::opcode::encode_global_get; use specs::etable::EventTableEntry; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct GlobalGetConfig { @@ -82,7 +81,7 @@ impl EventTableOpcodeConfig for GlobalGetConfig { fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { @@ -93,26 +92,11 @@ impl EventTableOpcodeConfig for GlobalGetConfig { self.is_i32_cell.assign(ctx, F::from(*vtype as u64))?; self.value_cell.assign(ctx, *value)?; - self.memory_table_lookup_global_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - *idx, - LocationType::Global, - *vtype == VarType::I32, - *value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; + let mut memory_rw_entries = entry.memory_rw_entries.iter(); + self.memory_table_lookup_global_read + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; Ok(()) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_global_set.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_global_set.rs index b56d0aa79..e7cd29c07 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_global_set.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_global_set.rs @@ -1,29 +1,27 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use specs::encode::opcode::encode_global_set; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct GlobalSetConfig { idx_cell: AllocatedCommonRangeCell, - is_i32_cell: AllocatedBitCell, - value_cell: AllocatedU64Cell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, + value_arg: EventTableCommonArgsConfig, memory_table_lookup_global_write: AllocatedMemoryTableLookupWriteCell, } @@ -35,23 +33,13 @@ impl EventTableOpcodeConfigBuilder for GlobalSetConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32_cell = allocator.alloc_bit_cell(); let idx_cell = allocator.alloc_common_range_cell(); - let value_cell = allocator.alloc_u64_cell(); - let sp_cell = common_config.sp_cell; let eid_cell = common_config.eid_cell; - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_global_set stack read", - constraint_builder, - eid_cell, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp_cell.expr(meta) + constant_from!(1), - move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), - move |____| constant_from!(1), - ); + let value_arg = common_config.uniarg_configs[0].clone(); + let is_i32_cell = value_arg.is_i32_cell; + let value_cell = value_arg.value_cell; let memory_table_lookup_global_write = allocator.alloc_memory_table_lookup_write_cell( "op_global_set global write", @@ -60,15 +48,13 @@ impl EventTableOpcodeConfigBuilder for GlobalSetConfigBuilder { move |____| constant_from!(LocationType::Global as u64), move |meta| idx_cell.expr(meta), move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), + move |meta| value_cell.expr(meta), move |____| constant_from!(1), ); Box::new(GlobalSetConfig { idx_cell, - is_i32_cell, - value_cell, - memory_table_lookup_stack_read, + value_arg, memory_table_lookup_global_write, }) } @@ -76,43 +62,23 @@ impl EventTableOpcodeConfigBuilder for GlobalSetConfigBuilder { impl EventTableOpcodeConfig for GlobalSetConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - encode_global_set(self.idx_cell.expr(meta)) + encode_global_set(self.idx_cell.expr(meta), UniArgEncode::Reserve) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { - StepInfo::SetGlobal { - idx, vtype, value, .. - } => { + StepInfo::SetGlobal { idx, uniarg, .. } => { self.idx_cell.assign(ctx, F::from(*idx as u64))?; - self.is_i32_cell.assign(ctx, F::from(*vtype as u64))?; - self.value_cell.assign(ctx, *value)?; - - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; - self.memory_table_lookup_global_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - *idx, - LocationType::Global, - *vtype == VarType::I32, - *value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.value_arg.assign(ctx, &uniarg, &mut memory_entries)?; + self.memory_table_lookup_global_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -121,10 +87,6 @@ impl EventTableOpcodeConfig for GlobalSetConfig { } } - fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) - } - fn mops(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { Some(constant_from!(1)) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_load.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_load.rs index 5679f2ba1..28642a7b7 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_load.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_load.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -22,16 +23,16 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_load; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct LoadConfig { + load_base_arg: EventTableCommonArgsConfig, + // offset in opcode opcode_load_offset: AllocatedU32Cell, @@ -71,7 +72,6 @@ pub struct LoadConfig { is_sign: AllocatedBitCell, is_i32: AllocatedBitCell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, memory_table_lookup_heap_read1: AllocatedMemoryTableLookupReadCell, memory_table_lookup_heap_read2: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, @@ -135,17 +135,11 @@ impl EventTableOpcodeConfigBuilder for LoadConfigBuilder { let sp = common_config.sp_cell; let eid = common_config.eid_cell; - let memory_table_lookup_stack_read = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "load read offset", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |____| constant_from!(1), - ); - + let load_base_arg = common_config.uniarg_configs[0].clone(); + constraint_builder.push( + "select: uniarg", + Box::new(move |meta| vec![load_base_arg.is_i32_cell.expr(meta) - constant_from!(1)]), + ); let memory_table_lookup_heap_read1 = allocator .alloc_memory_table_lookup_read_cell_with_value( "load read data1", @@ -168,18 +162,19 @@ impl EventTableOpcodeConfigBuilder for LoadConfigBuilder { move |meta| is_cross_block.expr(meta), ); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( "load write res", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| is_i32.expr(meta), move |meta| res.expr(meta), move |____| constant_from!(1), ); - let load_base = memory_table_lookup_stack_read.value_cell; + let load_base = load_base_arg.value_cell; let load_value_in_heap1 = memory_table_lookup_heap_read1.value_cell; let load_value_in_heap2 = memory_table_lookup_heap_read2.value_cell; @@ -368,6 +363,7 @@ impl EventTableOpcodeConfigBuilder for LoadConfigBuilder { ); Box::new(LoadConfig { + load_base_arg, opcode_load_offset, load_block_index, load_inner_pos, @@ -393,7 +389,6 @@ impl EventTableOpcodeConfigBuilder for LoadConfigBuilder { len_modulus, is_sign, is_i32, - memory_table_lookup_stack_read, memory_table_lookup_heap_read1, memory_table_lookup_heap_read2, memory_table_lookup_stack_write, @@ -415,12 +410,12 @@ impl EventTableOpcodeConfig for LoadConfig { + self.is_sign.expr(meta) + constant_from!(1); - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Load as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + load_size * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) - + self.opcode_load_offset.expr(meta) + encode_load( + self.is_i32.expr(meta), + load_size, + self.opcode_load_offset.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -434,11 +429,12 @@ impl EventTableOpcodeConfig for LoadConfig { vtype, load_size, offset, - raw_address, effective_address, value, block_value1, block_value2, + uniarg, + .. } => { let len = load_size.byte_size(); @@ -535,54 +531,21 @@ impl EventTableOpcodeConfig for LoadConfig { - (block_start_index + is_cross_block as u32 + 1), )?; - let mut i = 0; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[i].start_eid, - step.current.eid, - entry.memory_rw_entires[i].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - raw_address as u64, - )?; - i += 1; + let mut memory_entries = entry.memory_rw_entries.iter(); - self.memory_table_lookup_heap_read1.assign( - ctx, - entry.memory_rw_entires[i].start_eid, - step.current.eid, - entry.memory_rw_entires[i].end_eid, - effective_address >> 3, - LocationType::Heap, - false, - block_value1, - )?; - i += 1; + self.load_base_arg + .assign(ctx, &uniarg, &mut memory_entries)?; + + self.memory_table_lookup_heap_read1 + .assign_with_memory_entry(ctx, &mut memory_entries)?; if is_cross_block { - self.memory_table_lookup_heap_read2.assign( - ctx, - entry.memory_rw_entires[i].start_eid, - step.current.eid, - entry.memory_rw_entires[i].end_eid, - (effective_address >> 3) + 1, - LocationType::Heap, - false, - block_value2, - )?; - i += 1; + self.memory_table_lookup_heap_read2 + .assign_with_memory_entry(ctx, &mut memory_entries)?; } - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[i].end_eid, - step.current.sp + 1, - LocationType::Stack, - vtype == VarType::I32, - value, - )?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -597,4 +560,8 @@ impl EventTableOpcodeConfig for LoadConfig { fn memory_writing_ops(&self, _: &EventTableEntry) -> u32 { 1 } + + fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { + Some(constant!(-F::one())) + } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_local_get.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_local_get.rs index cb2c8b0dc..b05fbec5d 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_local_get.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_local_get.rs @@ -4,7 +4,6 @@ use crate::circuits::etable::ConstraintBuilder; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,13 +13,9 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_local_get; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct LocalGetConfig { @@ -80,17 +75,13 @@ impl EventTableOpcodeConfigBuilder for LocalGetConfigBuilder { impl EventTableOpcodeConfig for LocalGetConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::LocalGet as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.offset_cell.expr(meta) + encode_local_get(self.is_i32_cell.expr(meta), self.offset_cell.expr(meta)) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { @@ -103,26 +94,11 @@ impl EventTableOpcodeConfig for LocalGetConfig { self.value_cell.assign(ctx, *value)?; self.offset_cell.assign(ctx, F::from(*depth as u64))?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + depth, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.memory_table_lookup_stack_read + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_local_set.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_local_set.rs index 03aaedb73..2c53ddf32 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_local_set.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_local_set.rs @@ -1,33 +1,27 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_local_set; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct LocalSetConfig { + value_arg: EventTableCommonArgsConfig, offset_cell: AllocatedCommonRangeCell, - is_i32_cell: AllocatedBitCell, - value_cell: AllocatedU64Cell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -39,40 +33,31 @@ impl EventTableOpcodeConfigBuilder for LocalSetConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32_cell = allocator.alloc_bit_cell(); - let offset_cell = allocator.alloc_common_range_cell(); - let value_cell = allocator.alloc_u64_cell(); + let value_arg = common_config.uniarg_configs[0].clone(); + let is_i32_cell = value_arg.is_i32_cell; + let value_cell = value_arg.value_cell; + let offset_cell = allocator.alloc_common_range_cell(); let sp_cell = common_config.sp_cell; let eid_cell = common_config.eid_cell; - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_local_set stack read", - constraint_builder, - eid_cell, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp_cell.expr(meta) + constant_from!(1), - move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( "op_local_set stack write", constraint_builder, eid_cell, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp_cell.expr(meta) + constant_from!(1) + offset_cell.expr(meta), + move |meta| { + Self::sp_after_uniarg(sp_cell, &uniarg_configs, meta) + offset_cell.expr(meta) + }, move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), + move |meta| value_cell.expr(meta), move |____| constant_from!(1), ); Box::new(LocalSetConfig { + value_arg, offset_cell, - is_i32_cell, - value_cell, - memory_table_lookup_stack_read, memory_table_lookup_stack_write, }) } @@ -80,49 +65,27 @@ impl EventTableOpcodeConfigBuilder for LocalSetConfigBuilder { impl EventTableOpcodeConfig for LocalSetConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::LocalSet as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.offset_cell.expr(meta) + encode_local_set( + self.value_arg.is_i32_cell.expr(meta), + self.offset_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { - StepInfo::SetLocal { - vtype, - depth, - value, - } => { - self.is_i32_cell.assign(ctx, F::from(*vtype as u64))?; - self.value_cell.assign(ctx, *value)?; + StepInfo::SetLocal { depth, uniarg, .. } => { self.offset_cell.assign(ctx, F::from(*depth as u64))?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 1 + depth, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.value_arg.assign(ctx, &uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -131,10 +94,6 @@ impl EventTableOpcodeConfig for LocalSetConfig { } } - fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) - } - fn mops(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { Some(constant_from!(1)) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_local_tee.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_local_tee.rs index c67933bed..5f9bb805d 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_local_tee.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_local_tee.rs @@ -4,23 +4,17 @@ use crate::circuits::etable::ConstraintBuilder; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_local_tee; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct LocalTeeConfig { @@ -80,17 +74,13 @@ impl EventTableOpcodeConfigBuilder for LocalTeeConfigBuilder { impl EventTableOpcodeConfig for LocalTeeConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::LocalTee as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.offset_cell.expr(meta) + encode_local_tee(self.is_i32_cell.expr(meta), self.offset_cell.expr(meta)) } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { @@ -103,26 +93,11 @@ impl EventTableOpcodeConfig for LocalTeeConfig { self.value_cell.assign(ctx, *value)?; self.offset_cell.assign(ctx, F::from(*depth as u64))?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + depth, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.memory_table_lookup_stack_read + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_memory_grow.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_memory_grow.rs index 49be7cc3f..eb47c2c6d 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_memory_grow.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_memory_grow.rs @@ -1,10 +1,10 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,20 +14,19 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_memory_grow; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::step::StepInfo; pub struct MemoryGrowConfig { - grow_size: AllocatedU64Cell, + grow_size_arg: EventTableCommonArgsConfig, + result: AllocatedU64Cell, success: AllocatedBitCell, current_maximal_diff: AllocatedCommonRangeCell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -39,7 +38,13 @@ impl EventTableOpcodeConfigBuilder for MemoryGrowConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let grow_size = allocator.alloc_u64_cell(); + let grow_size_arg = common_config.uniarg_configs[0].clone(); + let grow_size = grow_size_arg.value_cell; + constraint_builder.push( + "select: uniarg", + Box::new(move |meta| vec![grow_size_arg.is_i32_cell.expr(meta) - constant_from!(1)]), + ); + let result = allocator.alloc_u64_cell(); let current_maximal_diff = allocator.alloc_common_range_cell(); @@ -76,34 +81,23 @@ impl EventTableOpcodeConfigBuilder for MemoryGrowConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_memory_grow stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |meta| grow_size.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( "op_memory_grow stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |____| constant_from!(1), move |meta| result.expr(meta), move |____| constant_from!(1), ); Box::new(MemoryGrowConfig { - grow_size, + grow_size_arg, result, success, current_maximal_diff, - memory_table_lookup_stack_read, memory_table_lookup_stack_write, }) } @@ -111,9 +105,7 @@ impl EventTableOpcodeConfigBuilder for MemoryGrowConfigBuilder { impl EventTableOpcodeConfig for MemoryGrowConfig { fn opcode(&self, _meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::MemoryGrow as u64) << OPCODE_CLASS_SHIFT) - )) + encode_memory_grow(UniArgEncode::Reserve) } fn assign( @@ -123,10 +115,13 @@ impl EventTableOpcodeConfig for MemoryGrowConfig { entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { - StepInfo::MemoryGrow { grow_size, result } => { + StepInfo::MemoryGrow { + grow_size, + result, + uniarg, + } => { let success = *result != -1; - self.grow_size.assign(ctx, *grow_size as u64)?; self.result.assign(ctx, *result as u32 as u64)?; self.success.assign_bool(ctx, success)?; if success { @@ -140,26 +135,11 @@ impl EventTableOpcodeConfig for MemoryGrowConfig { )?; } - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - *grow_size as u32 as u64, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - *result as u32 as u64, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.grow_size_arg + .assign(ctx, &uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -177,6 +157,10 @@ impl EventTableOpcodeConfig for MemoryGrowConfig { } fn allocated_memory_pages_diff(&self, meta: &mut VirtualCells<'_, F>) -> Option> { - Some(self.success.expr(meta) * self.grow_size.expr(meta)) + Some(self.success.expr(meta) * self.grow_size_arg.value_cell.expr(meta)) + } + + fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { + Some(constant!(-F::one())) } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_memory_size.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_memory_size.rs index 2e4abc09f..1e505b969 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_memory_size.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_memory_size.rs @@ -4,7 +4,6 @@ use crate::circuits::etable::ConstraintBuilder; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,10 +13,8 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_memory_size; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::step::StepInfo; @@ -56,28 +53,21 @@ impl EventTableOpcodeConfigBuilder for MemorySizeConfigBuilder { impl EventTableOpcodeConfig for MemorySizeConfig { fn opcode(&self, _meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::MemorySize as u64) << OPCODE_CLASS_SHIFT) - )) + encode_memory_size() } fn assign( &self, ctx: &mut Context<'_, F>, - step: &mut StepStatus, + _step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { match &entry.eentry.step_info { StepInfo::MemorySize => { - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp, - LocationType::Stack, - true, - step.current.allocated_memory_pages as u64, - )?; + let mut memory_rw_entries = entry.memory_rw_entries.iter(); + + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; Ok(()) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_rel.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_rel.rs index 9702d8aa1..fba5f4916 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_rel.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_rel.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -15,22 +16,21 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_rel; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; use specs::itable::RelOp; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; pub struct RelConfig { - is_i32: AllocatedBitCell, - lhs: AllocatedU64CellWithFlagBitDynSign, rhs: AllocatedU64CellWithFlagBitDynSign, + lhs_arg: EventTableCommonArgsConfig, + rhs_arg: EventTableCommonArgsConfig, + diff: AllocatedU64Cell, diff_inv: AllocatedUnlimitedCell, @@ -53,8 +53,6 @@ pub struct RelConfig { l_neg_r_pos: AllocatedUnlimitedCell, l_neg_r_neg: AllocatedUnlimitedCell, - memory_table_lookup_stack_read_lhs: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_rhs: AllocatedMemoryTableLookupReadCell, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -66,9 +64,11 @@ impl EventTableOpcodeConfigBuilder for RelConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32 = allocator.alloc_bit_cell(); - let op_is_sign = allocator.alloc_bit_cell(); + let rhs_arg = common_config.uniarg_configs[0].clone(); + let lhs_arg = common_config.uniarg_configs[1].clone(); + let is_i32 = lhs_arg.is_i32_cell; + let op_is_sign = allocator.alloc_bit_cell(); let lhs = allocator.alloc_u64_with_flag_bit_cell_dyn_sign( constraint_builder, move |meta| is_i32.expr(meta), @@ -80,6 +80,17 @@ impl EventTableOpcodeConfigBuilder for RelConfigBuilder { move |meta| op_is_sign.expr(meta), ); + constraint_builder.push( + "op_rel: uniarg", + Box::new(move |meta| { + vec![ + rhs_arg.is_i32_cell.expr(meta) - rhs_arg.is_i32_cell.expr(meta), + rhs.u64_cell.expr(meta) - rhs_arg.value_cell.expr(meta), + lhs.u64_cell.expr(meta) - lhs_arg.value_cell.expr(meta), + ] + }), + ); + let diff = allocator.alloc_u64_cell(); let diff_inv = allocator.alloc_unlimited_cell(); let res = allocator.alloc_unlimited_cell(); @@ -178,43 +189,23 @@ impl EventTableOpcodeConfigBuilder for RelConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read_rhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |meta| rhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - - let memory_table_lookup_stack_read_lhs = allocator.alloc_memory_table_lookup_read_cell( - "op_bin stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), - move |meta| lhs.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( - "op_bin stack read", + "op_rel stack read", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |____| constant_from!(1), move |meta| res.expr(meta), move |____| constant_from!(1), ); Box::new(RelConfig { - is_i32, lhs, rhs, + lhs_arg, + rhs_arg, diff, diff_inv, res, @@ -232,8 +223,6 @@ impl EventTableOpcodeConfigBuilder for RelConfigBuilder { l_neg_r_pos, l_pos_r_neg, l_neg_r_neg, - memory_table_lookup_stack_read_lhs, - memory_table_lookup_stack_read_rhs, memory_table_lookup_stack_write, }) } @@ -242,75 +231,53 @@ impl EventTableOpcodeConfigBuilder for RelConfigBuilder { impl EventTableOpcodeConfig for RelConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { let subop_eq = |meta: &mut VirtualCells| { - self.op_is_eq.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::Eq as u64) << OPCODE_ARG0_SHIFT) - )) + self.op_is_eq.expr(meta) * constant!(bn_to_field(&(BigUint::from(RelOp::Eq as u64)))) }; let subop_ne = |meta: &mut VirtualCells| { - self.op_is_ne.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::Ne as u64) << OPCODE_ARG0_SHIFT) - )) + self.op_is_ne.expr(meta) * constant!(bn_to_field(&(BigUint::from(RelOp::Ne as u64)))) }; let subop_gt_u = |meta: &mut VirtualCells| { self.op_is_gt.expr(meta) * (constant_from!(1) - self.op_is_sign.expr(meta)) - * constant!(bn_to_field( - &(BigUint::from(RelOp::UnsignedGt as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::UnsignedGt as u64)))) }; let subop_ge_u = |meta: &mut VirtualCells| { self.op_is_ge.expr(meta) * (constant_from!(1) - self.op_is_sign.expr(meta)) - * constant!(bn_to_field( - &(BigUint::from(RelOp::UnsignedGe as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::UnsignedGe as u64)))) }; let subop_lt_u = |meta: &mut VirtualCells| { self.op_is_lt.expr(meta) * (constant_from!(1) - self.op_is_sign.expr(meta)) - * constant!(bn_to_field( - &(BigUint::from(RelOp::UnsignedLt as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::UnsignedLt as u64)))) }; let subop_le_u = |meta: &mut VirtualCells| { self.op_is_le.expr(meta) * (constant_from!(1) - self.op_is_sign.expr(meta)) - * constant!(bn_to_field( - &(BigUint::from(RelOp::UnsignedLe as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::UnsignedLe as u64)))) }; let subop_gt_s = |meta: &mut VirtualCells| { self.op_is_gt.expr(meta) * self.op_is_sign.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::SignedGt as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::SignedGt as u64)))) }; let subop_ge_s = |meta: &mut VirtualCells| { self.op_is_ge.expr(meta) * self.op_is_sign.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::SignedGe as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::SignedGe as u64)))) }; let subop_lt_s = |meta: &mut VirtualCells| { self.op_is_lt.expr(meta) * self.op_is_sign.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::SignedLt as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::SignedLt as u64)))) }; let subop_le_s = |meta: &mut VirtualCells| { self.op_is_le.expr(meta) * self.op_is_sign.expr(meta) - * constant!(bn_to_field( - &(BigUint::from(RelOp::SignedLe as u64) << OPCODE_ARG0_SHIFT) - )) + * constant!(bn_to_field(&(BigUint::from(RelOp::SignedLe as u64)))) }; - let subop = |meta: &mut VirtualCells| { + let class = |meta: &mut VirtualCells| { subop_eq(meta) + subop_ne(meta) + subop_ge_u(meta) @@ -323,11 +290,11 @@ impl EventTableOpcodeConfig for RelConfig { + subop_lt_s(meta) }; - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Rel as u64) << OPCODE_CLASS_SHIFT) - )) + subop(meta) - + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) + encode_rel( + class(meta), + self.lhs_arg.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -336,41 +303,61 @@ impl EventTableOpcodeConfig for RelConfig { step: &mut StepStatus, entry: &EventTableEntryWithMemoryInfo, ) -> Result<(), Error> { - let (class, var_type, lhs, rhs, value, diff) = match entry.eentry.step_info { - StepInfo::I32Comp { - class, - left, - right, - value, - } => { - let var_type = VarType::I32; - let lhs = left as u32 as u64; - let rhs = right as u32 as u64; - let diff = if lhs < rhs { rhs - lhs } else { lhs - rhs }; - - (class, var_type, lhs, rhs, value, diff) - } - - StepInfo::I64Comp { - class, - left, - right, - value, - } => { - let var_type = VarType::I64; - let lhs = left as u64; - let rhs = right as u64; - let diff = if lhs < rhs { rhs - lhs } else { lhs - rhs }; - - (class, var_type, lhs, rhs, value, diff) - } - - _ => unreachable!(), - }; - - if var_type == VarType::I32 { - self.is_i32.assign(ctx, F::one())?; - } + let (class, var_type, lhs, rhs, value, diff, lhs_uniarg, rhs_uniarg) = + match entry.eentry.step_info { + StepInfo::I32BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + } => { + let var_type = VarType::I32; + let lhs = left as u32 as u64; + let rhs = right as u32 as u64; + let diff = if lhs < rhs { rhs - lhs } else { lhs - rhs }; + + ( + class.as_rel_op(), + var_type, + lhs, + rhs, + value as u32 as u64, + diff, + lhs_uniarg, + rhs_uniarg, + ) + } + + StepInfo::I64BinOp { + class, + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + .. + } => { + let var_type = VarType::I64; + let lhs = left as u64; + let rhs = right as u64; + let diff = if lhs < rhs { rhs - lhs } else { lhs - rhs }; + + ( + class.as_rel_op(), + var_type, + lhs, + rhs, + value as u64, + diff, + lhs_uniarg, + rhs_uniarg, + ) + } + + _ => unreachable!(), + }; let op_is_sign = vec![ RelOp::SignedGt, @@ -421,8 +408,7 @@ impl EventTableOpcodeConfig for RelConfig { self.res_is_gt.assign_bool(ctx, lhs > rhs)?; self.res_is_lt.assign_bool(ctx, lhs < rhs)?; } - self.res - .assign(ctx, if value { F::one() } else { F::zero() })?; + self.res.assign(ctx, F::from(value))?; match class { RelOp::Eq => { @@ -457,37 +443,11 @@ impl EventTableOpcodeConfig for RelConfig { } }; - self.memory_table_lookup_stack_read_rhs.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - var_type == VarType::I32, - rhs, - )?; - - self.memory_table_lookup_stack_read_lhs.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - var_type == VarType::I32, - lhs, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + 2, - LocationType::Stack, - true, - value as u64, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.rhs_arg.assign(ctx, &rhs_uniarg, &mut memory_entries)?; + self.lhs_arg.assign(ctx, &lhs_uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -501,6 +461,6 @@ impl EventTableOpcodeConfig for RelConfig { } fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant!(F::one())) + Some(constant!(-F::one())) } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_return.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_return.rs index 0a9c6f3e2..380839c18 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_return.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_return.rs @@ -6,24 +6,18 @@ use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; use crate::circuits::jtable::expression::JtableLookupEntryEncode; use crate::circuits::jtable::JumpTableConfig; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; use num_bigint::ToBigUint; use specs::encode::frame_table::encode_frame_table_entry; +use specs::encode::opcode::encode_return; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; @@ -119,13 +113,11 @@ impl EventTableOpcodeConfigBuilder for ReturnConfigBuilder { impl EventTableOpcodeConfig for ReturnConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Return as u64) << OPCODE_CLASS_SHIFT) - )) + self.drop.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.keep.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) - + self.is_i32.expr(meta) + encode_return( + self.drop.expr(meta), + self.keep.expr(meta), + self.is_i32.expr(meta), + ) } fn assign( @@ -154,26 +146,11 @@ impl EventTableOpcodeConfig for ReturnConfig { .assign(ctx, (VarType::from(keep[0]) as u64).into())?; self.value.assign(ctx, keep_values[0])?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + drop + 1, - LocationType::Stack, - VarType::from(keep[0]) == VarType::I32, - keep_values[0], - )?; + let mut memory_rw_entries = entry.memory_rw_entries.iter(); + self.memory_table_lookup_stack_read + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_rw_entries)?; } self.frame_table_lookup.cell.assign_bn( diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_select.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_select.rs index fe966e0ee..94dd92dc1 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_select.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_select.rs @@ -1,10 +1,10 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,26 +14,19 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_select; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct SelectConfig { - cond: AllocatedU64Cell, cond_inv: AllocatedUnlimitedCell, + res: AllocatedUnlimitedCell, - val1: AllocatedU64Cell, - val2: AllocatedU64Cell, - res: AllocatedU64Cell, - is_i32: AllocatedBitCell, - - memory_table_lookup_stack_read_cond: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_val2: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_val1: AllocatedMemoryTableLookupReadCell, + cond_arg: EventTableCommonArgsConfig, + rhs_arg: EventTableCommonArgsConfig, + lhs_arg: EventTableCommonArgsConfig, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -45,90 +38,62 @@ impl EventTableOpcodeConfigBuilder for SelectConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let cond = allocator.alloc_u64_cell(); let cond_inv = allocator.alloc_unlimited_cell(); + let res = allocator.alloc_unlimited_cell(); - let val1 = allocator.alloc_u64_cell(); - let val2 = allocator.alloc_u64_cell(); - let res = allocator.alloc_u64_cell(); - let is_i32 = allocator.alloc_bit_cell(); + let eid = common_config.eid_cell; + let sp = common_config.sp_cell; + let cond_arg = common_config.uniarg_configs[0].clone(); + let rhs_arg = common_config.uniarg_configs[1].clone(); + let lhs_arg = common_config.uniarg_configs[2].clone(); + let is_i32 = lhs_arg.is_i32_cell; + let cond = cond_arg.value_cell; + let lhs = lhs_arg.value_cell; + let rhs = rhs_arg.value_cell; constraint_builder.push( - "select: cond is zero", + "select: uniarg", Box::new(move |meta| { vec![ - (constant_from!(1) - cond.u64_cell.expr(meta) * cond_inv.expr(meta)) - * (res.u64_cell.expr(meta) - val2.u64_cell.expr(meta)), + cond_arg.is_i32_cell.expr(meta) - constant_from!(1), + rhs_arg.is_i32_cell.expr(meta) - lhs_arg.is_i32_cell.expr(meta), ] }), ); constraint_builder.push( - "select: cond is not zero", + "select: cond is zero", Box::new(move |meta| { vec![ - cond.u64_cell.expr(meta) * (res.u64_cell.expr(meta) - val1.u64_cell.expr(meta)), + (constant_from!(1) - cond.expr(meta) * cond_inv.expr(meta)) + * (res.expr(meta) - rhs.expr(meta)), ] }), ); - let eid = common_config.eid_cell; - let sp = common_config.sp_cell; - - let memory_table_lookup_stack_read_cond = allocator.alloc_memory_table_lookup_read_cell( - "op_select stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |____| constant_from!(1), - move |meta| cond.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - - let memory_table_lookup_stack_read_val2 = allocator.alloc_memory_table_lookup_read_cell( - "op_select stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |meta| is_i32.expr(meta), - move |meta| val2.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - - let memory_table_lookup_stack_read_val1 = allocator.alloc_memory_table_lookup_read_cell( - "op_select stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(3), - move |meta| is_i32.expr(meta), - move |meta| val1.u64_cell.expr(meta), - move |____| constant_from!(1), + constraint_builder.push( + "select: cond is not zero", + Box::new(move |meta| vec![cond.expr(meta) * (res.expr(meta) - lhs.expr(meta))]), ); + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( "op_select stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(3), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| is_i32.expr(meta), - move |meta| res.u64_cell.expr(meta), + move |meta| res.expr(meta), move |____| constant_from!(1), ); Box::new(SelectConfig { - cond, cond_inv, - val1, - val2, res, - is_i32, - memory_table_lookup_stack_read_cond, - memory_table_lookup_stack_read_val2, - memory_table_lookup_stack_read_val1, + cond_arg, + rhs_arg, + lhs_arg, memory_table_lookup_stack_write, }) } @@ -136,9 +101,7 @@ impl EventTableOpcodeConfigBuilder for SelectConfigBuilder { impl EventTableOpcodeConfig for SelectConfig { fn opcode(&self, _: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Select as u64) << OPCODE_CLASS_SHIFT) - )) + encode_select(UniArgEncode::Reserve) } fn assign( @@ -149,63 +112,25 @@ impl EventTableOpcodeConfig for SelectConfig { ) -> Result<(), Error> { match &entry.eentry.step_info { StepInfo::Select { - val1, - val2, cond, result, - vtype, + lhs_uniarg, + rhs_uniarg, + cond_uniarg, + .. } => { - self.val1.assign(ctx, *val1)?; - self.val2.assign(ctx, *val2)?; - self.cond.assign(ctx, *cond)?; if *cond != 0 { self.cond_inv.assign(ctx, step.field_helper.invert(*cond))?; } - self.res.assign(ctx, *result)?; - self.is_i32.assign_bool(ctx, *vtype == VarType::I32)?; - - self.memory_table_lookup_stack_read_cond.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - *cond, - )?; - - self.memory_table_lookup_stack_read_val2.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - *vtype == VarType::I32, - *val2, - )?; - - self.memory_table_lookup_stack_read_val1.assign( - ctx, - entry.memory_rw_entires[2].start_eid, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - step.current.sp + 3, - LocationType::Stack, - *vtype == VarType::I32, - *val1, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[3].end_eid, - step.current.sp + 3, - LocationType::Stack, - *vtype == VarType::I32, - *result, - )?; + self.res.assign(ctx, F::from(*result))?; + + let mut memory_entries = entry.memory_rw_entries.iter(); + self.cond_arg + .assign(ctx, &cond_uniarg, &mut memory_entries)?; + self.rhs_arg.assign(ctx, &rhs_uniarg, &mut memory_entries)?; + self.lhs_arg.assign(ctx, &lhs_uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -215,7 +140,7 @@ impl EventTableOpcodeConfig for SelectConfig { } fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant_from!(2)) + Some(constant!(-F::one())) } fn mops(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_store.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_store.rs index b08a7c9c2..6200be888 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_store.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_store.rs @@ -1,6 +1,7 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -14,7 +15,6 @@ use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; -use crate::constant; use crate::constant_from; use crate::constant_from_bn; use halo2_proofs::arithmetic::FieldExt; @@ -22,13 +22,10 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_store; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct StoreConfig { @@ -65,10 +62,10 @@ pub struct StoreConfig { is_two_bytes: AllocatedBitCell, is_four_bytes: AllocatedBitCell, is_eight_bytes: AllocatedBitCell, - is_i32: AllocatedBitCell, - memory_table_lookup_stack_read_pos: AllocatedMemoryTableLookupReadCell, - memory_table_lookup_stack_read_val: AllocatedMemoryTableLookupReadCell, + val_arg: EventTableCommonArgsConfig, + pos_arg: EventTableCommonArgsConfig, + memory_table_lookup_heap_read1: AllocatedMemoryTableLookupReadCell, memory_table_lookup_heap_read2: AllocatedMemoryTableLookupReadCell, memory_table_lookup_heap_write1: AllocatedMemoryTableLookupWriteCell, @@ -117,32 +114,21 @@ impl EventTableOpcodeConfigBuilder for StoreConfigBuilder { let is_two_bytes = allocator.alloc_bit_cell(); let is_four_bytes = allocator.alloc_bit_cell(); let is_eight_bytes = allocator.alloc_bit_cell(); - let is_i32 = allocator.alloc_bit_cell(); - let sp = common_config.sp_cell; let eid = common_config.eid_cell; - let memory_table_lookup_stack_read_val = allocator.alloc_memory_table_lookup_read_cell( - "store read data", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |meta| store_value.expr(meta), - move |____| constant_from!(1), - ); + let val_arg = common_config.uniarg_configs[0].clone(); + let pos_arg = common_config.uniarg_configs[1].clone(); - let memory_table_lookup_stack_read_pos = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "store read pos", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(2), - move |____| constant_from!(1), - move |____| constant_from!(1), - ); + constraint_builder.push( + "op_store: uniarg", + Box::new(move |meta| { + vec![ + pos_arg.is_i32_cell.expr(meta) - constant_from!(1), + store_value.expr(meta) - val_arg.value_cell.expr(meta), + ] + }), + ); let memory_table_lookup_heap_read1 = allocator .alloc_memory_table_lookup_read_cell_with_value( @@ -188,7 +174,7 @@ impl EventTableOpcodeConfigBuilder for StoreConfigBuilder { move |meta| is_cross_block.expr(meta), ); - let store_base = memory_table_lookup_stack_read_pos.value_cell; + let store_base = pos_arg.value_cell; let store_value_in_heap1 = memory_table_lookup_heap_write1.value_cell; let store_value_in_heap2 = memory_table_lookup_heap_write2.value_cell; @@ -415,9 +401,8 @@ impl EventTableOpcodeConfigBuilder for StoreConfigBuilder { is_two_bytes, is_four_bytes, is_eight_bytes, - is_i32, - memory_table_lookup_stack_read_pos, - memory_table_lookup_stack_read_val, + pos_arg, + val_arg, memory_table_lookup_heap_read1, memory_table_lookup_heap_read2, memory_table_lookup_heap_write1, @@ -439,12 +424,12 @@ impl EventTableOpcodeConfig for StoreConfig { + self.is_two_bytes.expr(meta) * constant_from!(1) + constant_from!(1); - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Store as u64) << OPCODE_CLASS_SHIFT) - )) + self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + store_size * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) - + self.opcode_store_offset.expr(meta) + encode_store( + self.val_arg.is_i32_cell.expr(meta), + store_size, + self.opcode_store_offset.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -455,16 +440,15 @@ impl EventTableOpcodeConfig for StoreConfig { ) -> Result<(), Error> { match entry.eentry.step_info { StepInfo::Store { - vtype, store_size, offset, - raw_address, effective_address, pre_block_value1, - updated_block_value1, pre_block_value2, - updated_block_value2, value, + val_uniarg, + pos_uniarg, + .. } => { let len = store_size.byte_size() as u32; @@ -544,7 +528,6 @@ impl EventTableOpcodeConfig for StoreConfig { self.is_four_bytes.assign_bool(ctx, len == 4)?; self.is_eight_bytes.assign_bool(ctx, len == 8)?; self.bytes.assign(ctx, (len as u64).into())?; - self.is_i32.assign_bool(ctx, vtype == VarType::I32)?; self.address_within_allocated_pages_helper.assign_u32( ctx, @@ -552,70 +535,19 @@ impl EventTableOpcodeConfig for StoreConfig { - (block_start_index + is_cross_block as u32 + 1), )?; - self.memory_table_lookup_stack_read_val.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - vtype == VarType::I32, - value, - )?; - - self.memory_table_lookup_stack_read_pos.assign( - ctx, - entry.memory_rw_entires[1].start_eid, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 2, - LocationType::Stack, - true, - raw_address as u64, - )?; - - self.memory_table_lookup_heap_read1.assign( - ctx, - entry.memory_rw_entires[2].start_eid, - step.current.eid, - entry.memory_rw_entires[2].end_eid, - effective_address >> 3, - LocationType::Heap, - false, - pre_block_value1, - )?; - - self.memory_table_lookup_heap_write1.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[3].end_eid, - effective_address >> 3, - LocationType::Heap, - false, - updated_block_value1, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.val_arg.assign(ctx, &val_uniarg, &mut memory_entries)?; + self.pos_arg.assign(ctx, &pos_uniarg, &mut memory_entries)?; + self.memory_table_lookup_heap_read1 + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_heap_write1 + .assign_with_memory_entry(ctx, &mut memory_entries)?; if is_cross_block { - self.memory_table_lookup_heap_read2.assign( - ctx, - entry.memory_rw_entires[4].start_eid, - step.current.eid, - entry.memory_rw_entires[4].end_eid, - (effective_address >> 3) + 1, - LocationType::Heap, - false, - pre_block_value2, - )?; - - self.memory_table_lookup_heap_write2.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[5].end_eid, - (effective_address >> 3) + 1, - LocationType::Heap, - false, - updated_block_value2, - )?; + self.memory_table_lookup_heap_read2 + .assign_with_memory_entry(ctx, &mut memory_entries)?; + self.memory_table_lookup_heap_write2 + .assign_with_memory_entry(ctx, &mut memory_entries)?; } Ok(()) } @@ -623,10 +555,6 @@ impl EventTableOpcodeConfig for StoreConfig { } } - fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { - Some(constant_from!(2)) - } - fn mops(&self, meta: &mut VirtualCells<'_, F>) -> Option> { Some(constant_from!(1) + self.is_cross_block.expr(meta)) } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_test.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_test.rs index 7ffed12ed..5e61c1a34 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_test.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_test.rs @@ -1,10 +1,10 @@ use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; -use crate::circuits::utils::bn_to_field; use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableEntryWithMemoryInfo; use crate::circuits::utils::Context; @@ -14,24 +14,18 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; +use specs::encode::opcode::encode_test; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; use specs::itable::TestOp; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; -use specs::mtable::VarType; use specs::step::StepInfo; pub struct TestConfig { - is_i32_cell: AllocatedBitCell, res_cell: AllocatedBitCell, value_inv_cell: AllocatedUnlimitedCell, - value_cell: AllocatedU64Cell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, + operand_arg: EventTableCommonArgsConfig, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } @@ -43,53 +37,42 @@ impl EventTableOpcodeConfigBuilder for TestConfigBuilder { allocator: &mut EventTableCellAllocator, constraint_builder: &mut ConstraintBuilder, ) -> Box> { - let is_i32_cell = allocator.alloc_bit_cell(); let res_cell = allocator.alloc_bit_cell(); - let value_cell = allocator.alloc_u64_cell(); let value_inv_cell = allocator.alloc_unlimited_cell(); + let eid = common_config.eid_cell; + let sp = common_config.sp_cell; + + let operand_arg = common_config.uniarg_configs[0].clone(); + let value_cell = operand_arg.value_cell; + constraint_builder.constraints.push(( "op_test res = !value", Box::new(move |meta| { vec![ - res_cell.expr(meta) * value_cell.u64_cell.expr(meta), - value_cell.u64_cell.expr(meta) * value_inv_cell.expr(meta) - constant_from!(1) + res_cell.expr(meta) * value_cell.expr(meta), + value_cell.expr(meta) * value_inv_cell.expr(meta) - constant_from!(1) + res_cell.expr(meta), ] }), )); - let eid = common_config.eid_cell; - let sp = common_config.sp_cell; - - let memory_table_lookup_stack_read = allocator.alloc_memory_table_lookup_read_cell( - "op_test stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32_cell.expr(meta), - move |meta| value_cell.u64_cell.expr(meta), - move |____| constant_from!(1), - ); - + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator.alloc_memory_table_lookup_write_cell( "op_test stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |____| constant_from!(1), move |meta| res_cell.expr(meta), move |____| constant_from!(1), ); Box::new(TestConfig { - is_i32_cell, res_cell, value_inv_cell, - value_cell, - memory_table_lookup_stack_read, + operand_arg, memory_table_lookup_stack_write, }) } @@ -97,12 +80,11 @@ impl EventTableOpcodeConfigBuilder for TestConfigBuilder { impl EventTableOpcodeConfig for TestConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Test as u64) << OPCODE_CLASS_SHIFT) - )) + constant_from!(TestOp::Eqz as u16) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG0_SHIFT))) - + self.is_i32_cell.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))) + encode_test( + constant_from!(TestOp::Eqz as u16), + self.operand_arg.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -113,39 +95,21 @@ impl EventTableOpcodeConfig for TestConfig { ) -> Result<(), Error> { match &entry.eentry.step_info { StepInfo::Test { - vtype, value, result, + uniarg, + .. } => { - self.is_i32_cell.assign_u32(ctx, *vtype as u32)?; - - self.value_cell.assign(ctx, *value)?; if *value != 0 { self.value_inv_cell .assign(ctx, step.field_helper.invert(*value))?; } self.res_cell.assign_u32(ctx, *result as u32)?; - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *value, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 1, - LocationType::Stack, - true, - *result as u32 as u64, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.operand_arg.assign(ctx, &uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -161,4 +125,8 @@ impl EventTableOpcodeConfig for TestConfig { fn memory_writing_ops(&self, _: &EventTableEntry) -> u32 { 1 } + + fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { + Some(constant!(-F::one())) + } } diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_unary.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_unary.rs index 9874be2eb..260c43df9 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_unary.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_unary.rs @@ -2,6 +2,7 @@ use crate::circuits::bit_table::BitTableOp; use crate::circuits::cell::*; use crate::circuits::etable::allocator::*; use crate::circuits::etable::ConstraintBuilder; +use crate::circuits::etable::EventTableCommonArgsConfig; use crate::circuits::etable::EventTableCommonConfig; use crate::circuits::etable::EventTableOpcodeConfig; use crate::circuits::etable::EventTableOpcodeConfigBuilder; @@ -17,12 +18,10 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use specs::encode::opcode::encode_unary; +use specs::encode::opcode::UniArgEncode; use specs::etable::EventTableEntry; -use specs::itable::OpcodeClass; use specs::itable::UnaryOp; -use specs::itable::OPCODE_ARG0_SHIFT; -use specs::itable::OPCODE_ARG1_SHIFT; -use specs::itable::OPCODE_CLASS_SHIFT; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::step::StepInfo; @@ -35,7 +34,6 @@ pub struct UnaryConfig { is_ctz: AllocatedBitCell, is_clz: AllocatedBitCell, is_popcnt: AllocatedBitCell, - is_i32: AllocatedBitCell, aux1: AllocatedU64Cell, aux2: AllocatedU64Cell, @@ -47,17 +45,17 @@ pub struct UnaryConfig { ctz_degree_helper: AllocatedUnlimitedCell, - memory_table_lookup_stack_read: AllocatedMemoryTableLookupReadCell, + operand_arg: EventTableCommonArgsConfig, memory_table_lookup_stack_write: AllocatedMemoryTableLookupWriteCell, } pub struct UnaryConfigBuilder {} impl EventTableOpcodeConfigBuilder for UnaryConfigBuilder { - fn configure( - common_config: &EventTableCommonConfig, - allocator: &mut EventTableCellAllocator, - constraint_builder: &mut ConstraintBuilder, + fn configure<'a>( + common_config: &'a EventTableCommonConfig, + allocator: &'a mut EventTableCellAllocator, + constraint_builder: &'a mut ConstraintBuilder, ) -> Box> { let operand_is_zero = allocator.alloc_bit_cell(); let operand_inv = allocator.alloc_unlimited_cell(); @@ -66,7 +64,6 @@ impl EventTableOpcodeConfigBuilder for UnaryConfigBuilder { let is_ctz = allocator.alloc_bit_cell(); let is_clz = allocator.alloc_bit_cell(); let is_popcnt = allocator.alloc_bit_cell(); - let is_i32 = allocator.alloc_bit_cell(); let aux1 = allocator.alloc_u64_cell(); let aux2 = allocator.alloc_u64_cell(); @@ -80,25 +77,18 @@ impl EventTableOpcodeConfigBuilder for UnaryConfigBuilder { let eid = common_config.eid_cell; let sp = common_config.sp_cell; - let memory_table_lookup_stack_read = allocator - .alloc_memory_table_lookup_read_cell_with_value( - "op_unary stack read", - constraint_builder, - eid, - move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), - move |meta| is_i32.expr(meta), - move |____| constant_from!(1), - ); - let operand = memory_table_lookup_stack_read.value_cell; + let operand_arg = common_config.uniarg_configs[0].clone(); + let operand = operand_arg.value_cell; + let is_i32 = operand_arg.is_i32_cell; + let uniarg_configs = common_config.uniarg_configs.clone(); let memory_table_lookup_stack_write = allocator .alloc_memory_table_lookup_write_cell_with_value( "op_unary stack write", constraint_builder, eid, move |____| constant_from!(LocationType::Stack as u64), - move |meta| sp.expr(meta) + constant_from!(1), + move |meta| Self::sp_after_uniarg(sp, &uniarg_configs, meta), move |meta| is_i32.expr(meta), move |____| constant_from!(1), ); @@ -200,14 +190,13 @@ impl EventTableOpcodeConfigBuilder for UnaryConfigBuilder { is_ctz, is_clz, is_popcnt, - is_i32, aux1, aux2, lookup_pow_modulus, lookup_pow_power, ctz_degree_helper, bit_table_lookup: lookup_popcnt, - memory_table_lookup_stack_read, + operand_arg, memory_table_lookup_stack_write, }) } @@ -217,23 +206,19 @@ impl EventTableOpcodeConfig for UnaryConfig { fn opcode(&self, meta: &mut VirtualCells<'_, F>) -> Expression { macro_rules! op_expr { ($op: expr, $field: ident) => { - self.$field.expr(meta) - * constant!(bn_to_field( - &(BigUint::from($op as u64) << OPCODE_ARG0_SHIFT) - )) + self.$field.expr(meta) * constant!(bn_to_field(&(BigUint::from($op as u64)))) }; } - let opcode_class = constant!(bn_to_field( - &(BigUint::from(OpcodeClass::Unary as u64) << OPCODE_CLASS_SHIFT) - )); - let var_type = self.is_i32.expr(meta) - * constant!(bn_to_field(&(BigUint::from(1u64) << OPCODE_ARG1_SHIFT))); let op = op_expr!(UnaryOp::Ctz, is_ctz) + op_expr!(UnaryOp::Clz, is_clz) + op_expr!(UnaryOp::Popcnt, is_popcnt); - opcode_class + var_type + op + encode_unary( + op, + self.operand_arg.is_i32_cell.expr(meta), + UniArgEncode::Reserve, + ) } fn assign( @@ -248,9 +233,8 @@ impl EventTableOpcodeConfig for UnaryConfig { vtype, operand, result, + uniarg, } => { - self.is_i32.assign_bool(ctx, *vtype == VarType::I32)?; - if *operand != 0 { self.operand_inv .assign(ctx, step.field_helper.invert(*operand))?; @@ -335,26 +319,10 @@ impl EventTableOpcodeConfig for UnaryConfig { } } - self.memory_table_lookup_stack_read.assign( - ctx, - entry.memory_rw_entires[0].start_eid, - step.current.eid, - entry.memory_rw_entires[0].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *operand, - )?; - - self.memory_table_lookup_stack_write.assign( - ctx, - step.current.eid, - entry.memory_rw_entires[1].end_eid, - step.current.sp + 1, - LocationType::Stack, - *vtype == VarType::I32, - *result as u32 as u64, - )?; + let mut memory_entries = entry.memory_rw_entries.iter(); + self.operand_arg.assign(ctx, &uniarg, &mut memory_entries)?; + self.memory_table_lookup_stack_write + .assign_with_memory_entry(ctx, &mut memory_entries)?; Ok(()) } @@ -370,4 +338,8 @@ impl EventTableOpcodeConfig for UnaryConfig { fn memory_writing_ops(&self, _: &EventTableEntry) -> u32 { 1 } + + fn sp_diff(&self, _meta: &mut VirtualCells<'_, F>) -> Option> { + Some(constant!(-F::one())) + } } diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 30afadfed..89743577a 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -11,6 +11,7 @@ use specs::jtable::INHERITED_FRAME_TABLE_ENTRIES; use super::ImageTableChip; use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::image_table::ImageTableLayouter; +use crate::circuits::utils::image_table::INSTRUCTION_CAPABILITY; use crate::circuits::utils::Context; cfg_if::cfg_if! { @@ -57,6 +58,17 @@ macro_rules! assign { }}; } +macro_rules! assign_fixed { + ($ctx:expr, $col: expr, $v: expr) => {{ + let cell = $ctx + .region + .assign_fixed(|| "pre image table prefix", $col, $ctx.offset, || $v) + .unwrap(); + + Ok::<_, Error>(cell) + }}; +} + impl ImageTableChip { pub(crate) fn assign( &self, @@ -93,6 +105,23 @@ impl ImageTableChip { Ok(cells.try_into().unwrap()) }; + let f_two = F::one() + F::one(); + let constant_handler = |base_offset| { + let mut ctx = Context::new(region); + ctx.offset = base_offset; + + let mut cells = Vec::with_capacity(INSTRUCTION_CAPABILITY); + + for entry in image_table.constants.iter() { + assign_fixed!(ctx, self.config.opcode_prefix, Ok(F::one()))?; + let cell = assign!(ctx, self.config.col, *entry)?; + + cells.push(cell); + } + + Ok(cells.try_into().unwrap()) + }; + let instruction_handler = |base_offset| { let mut ctx = Context::new(region); ctx.offset = base_offset; @@ -100,7 +129,10 @@ impl ImageTableChip { image_table .instructions .iter() - .map(|entry| assign!(ctx, self.config.col, *entry)) + .map(|entry| { + assign_fixed!(ctx, self.config.opcode_prefix, Ok(f_two))?; + assign!(ctx, self.config.col, *entry) + }) .collect::, Error>>() }; @@ -111,7 +143,10 @@ impl ImageTableChip { image_table .br_table_entires .iter() - .map(|entry| assign!(ctx, self.config.col, *entry)) + .map(|entry| { + assign_fixed!(ctx, self.config.opcode_prefix, Ok(f_two))?; + assign!(ctx, self.config.col, *entry) + }) .collect::, Error>>() }; @@ -120,7 +155,10 @@ impl ImageTableChip { ctx.offset = start_offset; (start_offset..end_offset) - .map(|_| assign!(ctx, self.config.col, F::zero())) + .map(|_| { + assign_fixed!(ctx, self.config.opcode_prefix, Ok(f_two))?; + assign!(ctx, self.config.col, F::zero()) + }) .collect::, Error>>() }; @@ -162,6 +200,7 @@ impl ImageTableChip { let result = image_table_assigner.exec( initialization_state_handler, inherited_frame_entries_handler, + constant_handler, instruction_handler, br_table_handler, padding_handler, @@ -171,6 +210,7 @@ impl ImageTableChip { Ok(ImageTableLayouter { initialization_state: result.initialization_state, inherited_frame_entries: result.inherited_frame_entries, + constants: result.constants, instructions: result.instructions, br_table_entires: result.br_table_entires, padding_entires: result.padding_entires, diff --git a/crates/zkwasm/src/circuits/image_table/configure.rs b/crates/zkwasm/src/circuits/image_table/configure.rs index d9556e934..f3efe15c8 100644 --- a/crates/zkwasm/src/circuits/image_table/configure.rs +++ b/crates/zkwasm/src/circuits/image_table/configure.rs @@ -8,6 +8,8 @@ use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; use specs::encode::image_table::ImageTableEncoder; +use crate::fixed_curr; + use super::ImageTableConfig; impl ImageTableConfig { @@ -28,8 +30,11 @@ impl ImageTableConfig { meta.enable_equality(col); + let opcode_prefix = meta.fixed_column(); + Self { memory_addr_sel, + opcode_prefix, col, _mark: PhantomData, } @@ -39,13 +44,17 @@ impl ImageTableConfig { &self, meta: &mut ConstraintSystem, key: &'static str, - expr: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, + expr: impl FnOnce(&mut VirtualCells<'_, F>) -> [Expression; 2], ) { meta.lookup_any(key, |meta| { - vec![( - ImageTableEncoder::Instruction.encode(expr(meta)), - self.expr(meta), - )] + let [prefix, content] = expr(meta); + vec![ + (prefix, fixed_curr!(meta, self.opcode_prefix)), + ( + ImageTableEncoder::Instruction.encode(content), + self.expr(meta), + ), + ] }); } @@ -56,8 +65,6 @@ impl ImageTableConfig { key: &'static str, expr: impl FnOnce(&mut VirtualCells<'_, F>) -> (Expression, Expression), ) { - use crate::fixed_curr; - meta.lookup_any(key, |meta| { let (addr, encode) = expr(meta); diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index 0e42faaa1..7ef34c728 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -42,6 +42,7 @@ pub fn compute_maximal_pages(k: u32) -> u32 { #[allow(dead_code)] #[derive(Clone)] pub struct ImageTableConfig { + opcode_prefix: Column, memory_addr_sel: Option>, #[cfg(feature = "uniform-circuit")] col: Column, diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 7798413ce..11c84584d 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -233,6 +233,18 @@ impl PostImageTableChip { Ok(cells.try_into().unwrap()) }; + let constant_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + Ok(post_image_table + .constants + .iter() + .map(|entry| Ok(assign!(ctx, self.config.post_image_table, *entry)?)) + .collect::, Error>>()? + .try_into() + .unwrap()) + }; + let instruction_handler = |base_offset| { ctx.borrow_mut().offset = base_offset; @@ -417,6 +429,7 @@ impl PostImageTableChip { let layouter = image_table_assigner.exec( initialization_state_handler, inherited_frame_entries_handler, + constant_handler, instruction_handler, br_table_handler, padding_handler, diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index f8d64d360..938050256 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -19,6 +19,7 @@ use specs::mtable::LocationType; use specs::mtable::VarType; use specs::slice::Slice; use specs::state::InitializationState; +use specs::state::INITIALIZATION_STATE_FIELD_COUNT; use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::compute_maximal_pages; @@ -27,7 +28,13 @@ use crate::circuits::utils::bn_to_field; pub const STACK_CAPABILITY: usize = DEFAULT_VALUE_STACK_LIMIT; pub const GLOBAL_CAPABILITY: usize = DEFAULT_VALUE_STACK_LIMIT; -pub const INIT_MEMORY_ENTRIES_OFFSET: usize = 40960; +pub const INSTRUCTION_CAPABILITY: usize = 65535; +// 10 for InitializationState fields count +// 2 * INSTRUCTION_CAPABILITY for instructions and constants +pub const INIT_MEMORY_ENTRIES_OFFSET: usize = INITIALIZATION_STATE_FIELD_COUNT + + INHERITED_FRAME_TABLE_ENTRIES + + INSTRUCTION_CAPABILITY + + INSTRUCTION_CAPABILITY; pub(crate) struct InitMemoryLayouter { pub(crate) pages: u32, @@ -81,6 +88,9 @@ pub fn image_table_offset_to_memory_location(offset: usize) -> (LocationType, u3 * -------------------- * Static Frame Entries * -------------------- + * Constants extracted + * from instruction(u64) + * -------------------- * Instructions * -------------------- * Br Table @@ -98,6 +108,7 @@ pub fn image_table_offset_to_memory_location(offset: usize) -> (LocationType, u3 pub struct ImageTableLayouter { pub(crate) initialization_state: InitializationState, pub(crate) inherited_frame_entries: Box<[T; INHERITED_FRAME_TABLE_ENTRIES]>, + pub(crate) constants: Box<[T; INSTRUCTION_CAPABILITY]>, pub(crate) instructions: Vec, pub(crate) br_table_entires: Vec, // NOTE: unused instructions and br_table entries. @@ -111,6 +122,7 @@ pub struct ImageTableAssigner { initialization_state_offset: usize, inherited_frame_entries_offset: usize, + constant_offset: usize, instruction_offset: usize, br_table_offset: usize, padding_offset: usize, @@ -124,11 +136,16 @@ impl ImageTableAssigner { let initialization_state_offset = 0; let inherited_frame_entries_offset = initialization_state_offset + InitializationState::::field_count(); - let instruction_offset = inherited_frame_entries_offset + INHERITED_FRAME_TABLE_ENTRIES; + let constant_offset = inherited_frame_entries_offset + INHERITED_FRAME_TABLE_ENTRIES; + let instruction_offset = constant_offset + INSTRUCTION_CAPABILITY; let br_table_offset = instruction_offset + instruction_number; let padding_offset = br_table_offset + br_table_number; let init_memory_offset = INIT_MEMORY_ENTRIES_OFFSET; + assert_eq!( + instruction_offset + INSTRUCTION_CAPABILITY, + init_memory_offset + ); assert!( padding_offset <= init_memory_offset, "The number of instructions of the image({}) is too large", @@ -140,6 +157,7 @@ impl ImageTableAssigner { initialization_state_offset, inherited_frame_entries_offset, + constant_offset, instruction_offset, br_table_offset, padding_offset, @@ -166,6 +184,13 @@ impl ImageTableAssigner { inherited_frame_entries_handler(self.inherited_frame_entries_offset) } + pub fn exec_constant( + &self, + mut handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + handler(self.constant_offset) + } + pub fn exec_instruction( &self, mut instruction_handler: impl FnMut(usize) -> Result, Error>, @@ -203,6 +228,7 @@ impl ImageTableAssigner { Box<[T; INHERITED_FRAME_TABLE_ENTRIES]>, Error, >, + constant_handler: impl FnMut(usize) -> Result, Error>, instruction_handler: impl FnMut(usize) -> Result, Error>, br_table_handler: impl FnMut(usize) -> Result, Error>, padding_handler: impl FnMut(usize, usize) -> Result, Error>, @@ -211,6 +237,7 @@ impl ImageTableAssigner { let initialization_state = self.exec_initialization_state(initialization_state_handler)?; let inherited_frame_entries = self.exec_inherited_frame_entries(inherited_frame_entries_handler)?; + let constants = self.exec_constant(constant_handler)?; let instructions = self.exec_instruction(instruction_handler)?; let br_table_entires = self.exec_br_table_entires(br_table_handler)?; let padding_entires = self.exec_padding_entires(padding_handler)?; @@ -218,6 +245,7 @@ impl ImageTableAssigner { Ok(ImageTableLayouter { initialization_state, inherited_frame_entries, + constants, instructions, br_table_entires, padding_entires, @@ -249,6 +277,17 @@ pub(crate) fn encode_compilation_table_values( Ok(cells) }; + let constant_handler = |_| { + let mut cells = vec![F::zero(); INSTRUCTION_CAPABILITY].into_boxed_slice(); + + for (index, entry) in itable.instruction_constants().iter().enumerate() { + cells[index] = + bn_to_field(&ImageTableEncoder::Instruction.encode(BigUint::from(*entry))) + } + + Ok(cells.try_into().unwrap()) + }; + let instruction_handler = |_| { let mut cells = vec![]; @@ -378,6 +417,7 @@ pub(crate) fn encode_compilation_table_values( .exec::<_, Error>( initialization_state_handler, inherited_frame_entries_handler, + constant_handler, instruction_handler, br_table_handler, padding_handler, diff --git a/crates/zkwasm/src/circuits/utils/table_entry.rs b/crates/zkwasm/src/circuits/utils/table_entry.rs index 19d7b6f97..5b626021b 100644 --- a/crates/zkwasm/src/circuits/utils/table_entry.rs +++ b/crates/zkwasm/src/circuits/utils/table_entry.rs @@ -117,7 +117,7 @@ pub struct MemoryRWEntry { pub struct EventTableEntryWithMemoryInfo { pub eentry: EventTableEntry, - pub memory_rw_entires: Vec, + pub memory_rw_entries: Vec, } pub(crate) struct EventTableWithMemoryInfo( @@ -162,7 +162,7 @@ impl EventTableWithMemoryInfo { .par_iter() .map(|eentry| EventTableEntryWithMemoryInfo { eentry: eentry.clone(), - memory_rw_entires: memory_event_of_step(eentry) + memory_rw_entries: memory_event_of_step(eentry) .iter() .map(|mentry| { let (start_eid, end_eid) = lookup_mtable_eid(( diff --git a/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs b/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs index d33cddf3b..3a5279077 100644 --- a/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs @@ -61,7 +61,11 @@ use super::post_image_table::PostImageTableConfig; use super::LastSliceCircuit; use super::OngoingCircuit; -pub const VAR_COLUMNS: usize = 40; +pub const VAR_COLUMNS: usize = if cfg!(feature = "continuation") { + 43 +} else { + 44 +}; // Reserve 128 rows(greater than step size of all tables) to keep usable rows away from // blind rows and range checking rows. @@ -576,6 +580,14 @@ macro_rules! impl_zkwasm_circuit { // 6. fixed part(instructions, br_tables, padding) within pre image chip and post image chip if let Some((post_image_table_cells, _)) = post_image_table_cells.as_ref() { + for (l, r) in pre_image_table_cells + .constants + .iter() + .zip(post_image_table_cells.constants.iter()) + { + region.constrain_equal(l.cell(), r.cell())?; + } + for (l, r) in pre_image_table_cells .instructions .iter() diff --git a/crates/zkwasm/src/foreign/context/etable_op_configure.rs b/crates/zkwasm/src/foreign/context/etable_op_configure.rs index ec021936d..423fa3796 100644 --- a/crates/zkwasm/src/foreign/context/etable_op_configure.rs +++ b/crates/zkwasm/src/foreign/context/etable_op_configure.rs @@ -176,7 +176,7 @@ impl EventTableOpcodeConfig for ETableContextHelperTableConfig EventTableOpcodeConfig for ETableContextHelperTableConfig { ); } -pub(crate) trait EventTableForeignCallConfigBuilder { +pub(crate) trait EventTableForeignCallConfigBuilder: Sized { + fn configure_all( + self, + common_config: &EventTableCommonConfig, + allocator: &mut EventTableCellAllocator, + constraint_builder: &mut ConstraintBuilder, + lookup_cells: &mut (impl Iterator> + Clone), + ) -> Box> { + let unused_args = common_config + .uniarg_configs + .iter() + .map(|x| x.is_enabled_cell) + .collect::>(); + constraint_builder.push( + "op_unary: uniarg", + Box::new(move |meta| { + vec![unused_args + .iter() + .map(|x| x.expr(meta)) + .reduce(|a, b| a + b) + .unwrap()] + }), + ); + + let mut common_config = common_config.clone(); + common_config.uniarg_configs = common_config.uniarg_configs.into_iter().take(0).collect(); + self.configure(&common_config, allocator, constraint_builder, lookup_cells) + } + fn configure( self, common_config: &EventTableCommonConfig, diff --git a/crates/zkwasm/src/foreign/require_helper/etable_op_configure.rs b/crates/zkwasm/src/foreign/require_helper/etable_op_configure.rs index 867027c74..a98ae2ec9 100644 --- a/crates/zkwasm/src/foreign/require_helper/etable_op_configure.rs +++ b/crates/zkwasm/src/foreign/require_helper/etable_op_configure.rs @@ -108,9 +108,9 @@ impl EventTableOpcodeConfig for ETableRequireHelperTableConfig EventTableOpcodeConfig for ETableWasmInputHelperTableConfig self.lookup_read_stack.assign( ctx, - entry.memory_rw_entires[0].start_eid, + entry.memory_rw_entries[0].start_eid, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp + 1, LocationType::Stack, true, @@ -225,7 +225,7 @@ impl EventTableOpcodeConfig for ETableWasmInputHelperTableConfig self.lookup_write_stack.assign( ctx, step.current.eid, - entry.memory_rw_entires[1].end_eid, + entry.memory_rw_entries[1].end_eid, step.current.sp + 1, LocationType::Stack, false, @@ -248,9 +248,9 @@ impl EventTableOpcodeConfig for ETableWasmInputHelperTableConfig self.lookup_read_stack.assign( ctx, - entry.memory_rw_entires[0].start_eid, + entry.memory_rw_entries[0].start_eid, step.current.eid, - entry.memory_rw_entires[0].end_eid, + entry.memory_rw_entries[0].end_eid, step.current.sp + 1, LocationType::Stack, false, diff --git a/crates/zkwasm/src/runtime/mod.rs b/crates/zkwasm/src/runtime/mod.rs index 0166f0703..77f8666c1 100644 --- a/crates/zkwasm/src/runtime/mod.rs +++ b/crates/zkwasm/src/runtime/mod.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use halo2_proofs::arithmetic::FieldExt; use specs::etable::EventTableEntry; use specs::external_host_call_table::ExternalHostCallSignature; +use specs::itable::UniArg; use specs::mtable::AccessType; use specs::mtable::LocationType; use specs::mtable::MemoryTableEntry; @@ -107,61 +108,55 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { drop, keep, keep_values, + uniarg, .. } => { assert_eq!(keep.len(), keep_values.len()); assert!(keep.len() <= 1); - let mut sp = sp_before_execution + 1; - - let mut ops = vec![MemoryTableEntry { + let (mut sp, mut ops) = _mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *condition as u32 as u64, - }]; + &[(VarType::I32, *uniarg, *condition as u32 as u64)], + None, + ); - sp += 1; - - if *condition != 0 { - return ops; - } - - { - for i in 0..keep.len() { - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: keep[i].into(), - is_mutable: true, - value: keep_values[i], - }); - - sp += 1; + if *condition == 0 { + sp += 1; + + { + for i in 0..keep.len() { + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Read, + vtype: keep[i].into(), + is_mutable: true, + value: keep_values[i], + }); + + sp += 1; + } } - } - - sp += drop; - sp -= 1; - - { - for i in 0..keep.len() { - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Write, - vtype: keep[i].into(), - is_mutable: true, - value: keep_values[i], - }); - sp -= 1; + sp += drop; + sp -= 1; + + { + for i in 0..keep.len() { + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Write, + vtype: keep[i].into(), + is_mutable: true, + value: keep_values[i], + }); + + sp -= 1; + } } } @@ -172,61 +167,55 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { drop, keep, keep_values, + uniarg, .. } => { assert_eq!(keep.len(), keep_values.len()); assert!(keep.len() <= 1); - let mut sp = sp_before_execution + 1; - - let mut ops = vec![MemoryTableEntry { + let (mut sp, mut ops) = _mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *condition as u32 as u64, - }]; - - sp += 1; - - if *condition == 0 { - return ops; - } + &[(VarType::I32, *uniarg, *condition as u32 as u64)], + None, + ); - { - for i in 0..keep.len() { - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: keep[i].into(), - is_mutable: true, - value: keep_values[i], - }); - - sp += 1; + if *condition != 0 { + sp += 1; + + { + for i in 0..keep.len() { + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Read, + vtype: keep[i].into(), + is_mutable: true, + value: keep_values[i], + }); + + sp += 1; + } } - } - sp += drop; - sp -= 1; - - { - for i in 0..keep.len() { - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Write, - vtype: keep[i].into(), - is_mutable: true, - value: keep_values[i], - }); - - sp -= 1; + sp += drop; + sp -= 1; + + { + for i in 0..keep.len() { + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Write, + vtype: keep[i].into(), + is_mutable: true, + value: keep_values[i], + }); + + sp -= 1; + } } } @@ -237,24 +226,18 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { drop, keep, keep_values, + uniarg, .. } => { assert_eq!(keep.len(), keep_values.len()); assert!(keep.len() <= 1); - let mut sp = sp_before_execution + 1; - - let mut ops = vec![MemoryTableEntry { + let (mut sp, mut ops) = _mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *index as u32 as u64, - }]; - - sp += 1; + &[(VarType::I32, *uniarg, *index as u32 as u64)], + None, + ); { for i in 0..keep.len() { @@ -343,75 +326,33 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { } StepInfo::Drop { .. } => vec![], StepInfo::Select { - val1, - val2, + lhs, + lhs_uniarg, + rhs, + rhs_uniarg, cond, + cond_uniarg, result, vtype, - } => { - let mut sp = sp_before_execution + 1; - let mut ops = vec![]; - - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *cond, - }); - sp += 1; - - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: *vtype, - is_mutable: true, - value: *val2, - }); - sp += 1; - - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: *vtype, - is_mutable: true, - value: *val1, - }); - - ops.push(MemoryTableEntry { - eid, - offset: sp, - ltype: LocationType::Stack, - atype: AccessType::Write, - vtype: *vtype, - is_mutable: true, - value: *result, - }); - - ops - } + } => mem_ops_from_stack_only_step( + sp_before_execution, + eid, + &[ + (*vtype, *lhs_uniarg, *lhs as u64), + (*vtype, *rhs_uniarg, *rhs as u64), + (VarType::I32, *cond_uniarg, *cond as u64), + ], + Some((*vtype, *result as u64)), + ), StepInfo::Call { index: _ } => { vec![] } - StepInfo::CallIndirect { offset, .. } => { - let stack_read = MemoryTableEntry { - eid, - offset: sp_before_execution + 1, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *offset as u64, - }; - - vec![stack_read] - } + StepInfo::CallIndirect { offset, uniarg, .. } => mem_ops_from_stack_only_step( + sp_before_execution, + eid, + &[(VarType::I32, *uniarg, *offset as u64)], + None, + ), StepInfo::CallHost { args, ret_val, @@ -508,22 +449,16 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { vtype, depth, value, + uniarg, } => { - let mut sp = sp_before_execution; - - let read = MemoryTableEntry { + let (sp, mut ops) = _mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp + 1, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: *vtype, - is_mutable: true, - value: *value, - }; + &[(*vtype, *uniarg, *value)], + None, + ); - sp += 1; - - let write = MemoryTableEntry { + ops.push(MemoryTableEntry { eid, offset: sp + depth, ltype: LocationType::Stack, @@ -531,9 +466,9 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { vtype: *vtype, is_mutable: true, value: *value, - }; + }); - vec![read, write] + ops } StepInfo::TeeLocal { vtype, @@ -597,16 +532,14 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { vtype, is_mutable, value, + uniarg, } => { - let stack_read = MemoryTableEntry { + let mut ops = mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp_before_execution + 1, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: *vtype, - is_mutable: true, - value: *value, - }; + &[(*vtype, *uniarg, *value)], + None, + ); let global_set = MemoryTableEntry { eid, @@ -618,7 +551,9 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { value: *value, }; - vec![stack_read, global_set] + ops.push(global_set); + + ops } StepInfo::Load { @@ -629,19 +564,20 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { value, block_value1, block_value2, + uniarg, .. } => { - let load_address_from_stack = MemoryTableEntry { + let mut ops = mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp_before_execution + 1, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *raw_address as u64, - }; + &[(VarType::I32, *uniarg, *raw_address as u64)], + Some((*vtype, *value)), + ); + + let write_result = ops.pop().unwrap(); - let load_value1 = MemoryTableEntry { + // load first block + ops.push(MemoryTableEntry { eid, offset: (*effective_address) / 8, ltype: LocationType::Heap, @@ -651,10 +587,11 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { is_mutable: true, // The value will be used to lookup within imtable, hence block_value is given here value: *block_value1, - }; + }); - let load_value2 = if *effective_address % 8 + load_size.byte_size() > 8 { - Some(MemoryTableEntry { + // load second block if it is cross access + if *effective_address % 8 + load_size.byte_size() > 8 { + ops.push(MemoryTableEntry { eid, offset: effective_address / 8 + 1, ltype: LocationType::Heap, @@ -665,26 +602,11 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { // The value will be used to lookup within imtable, hence block_value is given here value: *block_value2, }) - } else { - None - }; + } - let push_value = MemoryTableEntry { - eid, - offset: sp_before_execution + 1, - ltype: LocationType::Stack, - atype: AccessType::Write, - vtype: *vtype, - is_mutable: true, - value: *value, - }; + ops.push(write_result); - vec![ - vec![load_address_from_stack, load_value1], - load_value2.map_or(vec![], |v| vec![v]), - vec![push_value], - ] - .concat() + ops } StepInfo::Store { vtype, @@ -696,29 +618,22 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { updated_block_value1, pre_block_value2, updated_block_value2, + val_uniarg, + pos_uniarg, .. } => { - let load_value_from_stack = MemoryTableEntry { + let mut ops = mem_ops_from_stack_only_step( + sp_before_execution, eid, - offset: sp_before_execution + 1, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: *vtype, - is_mutable: true, - value: *value, - }; - - let load_address_from_stack = MemoryTableEntry { - eid, - offset: sp_before_execution + 2, - ltype: LocationType::Stack, - atype: AccessType::Read, - vtype: VarType::I32, - is_mutable: true, - value: *raw_address as u64, - }; - - let load_value1 = MemoryTableEntry { + &[ + (VarType::I32, *pos_uniarg, *raw_address as u64), + (*vtype, *val_uniarg, *value), + ], + None, + ); + + // load first block + ops.push(MemoryTableEntry { eid, offset: effective_address / 8, ltype: LocationType::Heap, @@ -728,9 +643,10 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { is_mutable: true, // The value will be used to lookup within imtable, hence block_value is given here value: *pre_block_value1, - }; + }); - let write_value1 = MemoryTableEntry { + // write first block + ops.push(MemoryTableEntry { eid, offset: effective_address / 8, ltype: LocationType::Heap, @@ -740,10 +656,11 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { is_mutable: true, // The value will be used to lookup within imtable, hence block_value is given here value: *updated_block_value1, - }; + }); if *effective_address % 8 + store_size.byte_size() as u32 > 8 { - let load_value2 = MemoryTableEntry { + // load second block if cross + ops.push(MemoryTableEntry { eid, offset: effective_address / 8 + 1, ltype: LocationType::Heap, @@ -753,9 +670,10 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { is_mutable: true, // The value will be used to lookup within imtable, hence block_value is given here value: *pre_block_value2, - }; + }); - let write_value2 = MemoryTableEntry { + // write second block if cross + ops.push(MemoryTableEntry { eid, offset: effective_address / 8 + 1, ltype: LocationType::Heap, @@ -765,23 +683,10 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { is_mutable: true, // The value will be used to lookup within imtable, hence block_value is given here value: *updated_block_value2, - }; - vec![ - load_value_from_stack, - load_address_from_stack, - load_value1, - write_value1, - load_value2, - write_value2, - ] - } else { - vec![ - load_value_from_stack, - load_address_from_stack, - load_value1, - write_value1, - ] + }); } + + ops } StepInfo::MemorySize => mem_op_from_stack_only_step( @@ -792,13 +697,15 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { &[], &[event.allocated_memory_pages as u64], ), - StepInfo::MemoryGrow { grow_size, result } => mem_op_from_stack_only_step( + StepInfo::MemoryGrow { + grow_size, + result, + uniarg, + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I32, - VarType::I32, - &[*grow_size as u32 as u64], - &[*result as u32 as u64], + &[(VarType::I32, *uniarg, *grow_size as u32 as u64)], + Some((VarType::I32, *result as u32 as u64)), ), StepInfo::I32Const { value } => mem_op_from_stack_only_step( @@ -810,47 +717,37 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { &[*value as u32 as u64], ), StepInfo::I32BinOp { - left, right, value, .. - } - | StepInfo::I32BinShiftOp { - left, right, value, .. - } - | StepInfo::I32BinBitOp { - left, right, value, .. - } => mem_op_from_stack_only_step( + left, + right, + value, + lhs_uniarg, + rhs_uniarg, + .. + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I32, - VarType::I32, - &[*right as u32 as u64, *left as u32 as u64], - &[*value as u32 as u64], + &[ + (VarType::I32, *lhs_uniarg, *left as u32 as u64), + (VarType::I32, *rhs_uniarg, *right as u32 as u64), + ], + Some((VarType::I32, *value as u32 as u64)), ), - StepInfo::I32Comp { - left, right, value, .. - } => mem_op_from_stack_only_step( - sp_before_execution, - eid, - VarType::I32, - VarType::I32, - &[*right as u32 as u64, *left as u32 as u64], - &[*value as u32 as u64], - ), - StepInfo::I64BinOp { - left, right, value, .. - } - | StepInfo::I64BinShiftOp { - left, right, value, .. - } - | StepInfo::I64BinBitOp { - left, right, value, .. - } => mem_op_from_stack_only_step( + left, + right, + value, + value_type, + lhs_uniarg, + rhs_uniarg, + .. + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I64, - VarType::I64, - &[*right as u64, *left as u64], - &[*value as u64], + &[ + (VarType::I64, *lhs_uniarg, *left as u64), + (VarType::I64, *rhs_uniarg, *right as u64), + ], + Some((*value_type, *value as u64)), ), StepInfo::I64Const { value } => mem_op_from_stack_only_step( @@ -861,81 +758,159 @@ pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { &[], &[*value as u64], ), - StepInfo::I64Comp { - left, right, value, .. - } => mem_op_from_stack_only_step( - sp_before_execution, - eid, - VarType::I64, - VarType::I32, - &[*right as u64, *left as u64], - &[*value as u32 as u64], - ), StepInfo::UnaryOp { vtype, operand, result, + uniarg, .. - } => mem_op_from_stack_only_step( + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - *vtype, - *vtype, - &[*operand], - &[*result], + &[(*vtype, *uniarg, *operand)], + Some((*vtype, *result)), ), StepInfo::Test { vtype, value, result, - } => mem_op_from_stack_only_step( + uniarg, + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - *vtype, - VarType::I32, - &[*value], - &[*result as u32 as u64], + &[(*vtype, *uniarg, *value)], + Some((VarType::I32, *result as u32 as u64)), ), - StepInfo::I32WrapI64 { value, result } => mem_op_from_stack_only_step( + StepInfo::I32WrapI64 { + value, + result, + uniarg, + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I64, - VarType::I32, - &[*value as u64], - &[*result as u32 as u64], + &[(VarType::I64, *uniarg, *value as u64)], + Some((VarType::I32, *result as u32 as u64)), ), - StepInfo::I64ExtendI32 { value, result, .. } => mem_op_from_stack_only_step( + StepInfo::I64ExtendI32 { + value, + result, + uniarg, + .. + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I32, - VarType::I64, - &[*value as u32 as u64], - &[*result as u64], + &[(VarType::I32, *uniarg, *value as u32 as u64)], + Some((VarType::I64, *result as u64)), ), - StepInfo::I32SignExtendI8 { value, result } - | StepInfo::I32SignExtendI16 { value, result } => mem_op_from_stack_only_step( + StepInfo::I32SignExtendI8 { + value, + result, + uniarg, + } + | StepInfo::I32SignExtendI16 { + value, + result, + uniarg, + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I32, - VarType::I32, - &[*value as u32 as u64], - &[*result as u32 as u64], + &[(VarType::I32, *uniarg, *value as u32 as u64)], + Some((VarType::I32, *result as u32 as u64)), ), - StepInfo::I64SignExtendI8 { value, result } - | StepInfo::I64SignExtendI16 { value, result } - | StepInfo::I64SignExtendI32 { value, result } => mem_op_from_stack_only_step( + StepInfo::I64SignExtendI8 { + value, + result, + uniarg, + } + | StepInfo::I64SignExtendI16 { + value, + result, + uniarg, + } + | StepInfo::I64SignExtendI32 { + value, + result, + uniarg, + } => mem_ops_from_stack_only_step( sp_before_execution, eid, - VarType::I64, - VarType::I64, - &[*value as u64], - &[*result as u64], + &[(VarType::I64, *uniarg, *value as u64)], + Some((VarType::I64, *result as u64)), ), } } +fn _mem_ops_from_stack_only_step( + sp_before_execution: u32, + eid: u32, + inputs: &[(VarType, UniArg, u64)], + output: Option<(VarType, u64)>, +) -> (u32, Vec) { + let (sp, mut ops) = inputs.iter().rev().fold( + (sp_before_execution, vec![]), + |(mut sp, mut ops), (vtype, arg, input)| { + match arg { + UniArg::Pop => { + sp += 1; + + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Read, + vtype: *vtype, + is_mutable: true, + value: *input, + }); + } + UniArg::Stack(depth) => { + ops.push(MemoryTableEntry { + eid, + offset: sp + *depth as u32, + ltype: LocationType::Stack, + atype: AccessType::Read, + vtype: *vtype, + is_mutable: true, + value: *input, + }); + } + UniArg::IConst(_) => (), + }; + + (sp, ops) + }, + ); + + let sp = if let Some((vtype, value)) = output { + ops.push(MemoryTableEntry { + eid, + offset: sp, + ltype: LocationType::Stack, + atype: AccessType::Write, + vtype, + is_mutable: true, + value, + }); + + sp - 1 + } else { + sp + }; + + (sp, ops) +} + +fn mem_ops_from_stack_only_step( + sp_before_execution: u32, + eid: u32, + inputs: &[(VarType, UniArg, u64)], + output: Option<(VarType, u64)>, +) -> Vec { + _mem_ops_from_stack_only_step(sp_before_execution, eid, inputs, output).1 +} + pub(crate) fn mem_op_from_stack_only_step( sp_before_execution: u32, eid: u32, diff --git a/crates/zkwasm/src/runtime/monitor/plugins/table/instruction.rs b/crates/zkwasm/src/runtime/monitor/plugins/table/instruction.rs index 0b782dd9b..898847a18 100644 --- a/crates/zkwasm/src/runtime/monitor/plugins/table/instruction.rs +++ b/crates/zkwasm/src/runtime/monitor/plugins/table/instruction.rs @@ -1,6 +1,7 @@ use parity_wasm::elements::ValueType; use specs::external_host_call_table::ExternalHostCallSignature; use specs::itable::BinOp; +use specs::itable::BinaryOp; use specs::itable::BitOp; use specs::itable::BrTarget; use specs::itable::ConversionOp; @@ -9,6 +10,7 @@ use specs::itable::RelOp; use specs::itable::ShiftOp; use specs::itable::TestOp; use specs::itable::UnaryOp; +use specs::itable::UniArg; use specs::mtable::MemoryReadSize; use specs::mtable::MemoryStoreSize; use specs::mtable::VarType; @@ -33,6 +35,30 @@ use wasmi::Signature; use super::TablePlugin; use super::DEFAULT_TABLE_INDEX; +// uniargs: from nearest +pub fn value_from_uniargs(uniargs: &[UniArg], stack: &ValueStack) -> Vec { + uniargs + .iter() + .fold( + (0usize, vec![]), + |(delta, mut values), uniarg| match uniarg { + UniArg::Pop => { + values.push(*stack.pick(delta + 1)); + (delta + 1, values) + } + UniArg::Stack(depth) => { + values.push(*stack.pick(depth + delta)); + (delta, values) + } + UniArg::IConst(value) => { + values.push(value.into()); + (delta, values) + } + }, + ) + .1 +} + #[derive(Debug)] pub struct FuncDesc { pub ftype: FunctionType, @@ -55,7 +81,7 @@ impl PhantomFunction { instructions.push(Instruction::Call(wasm_input_function_idx)); if sig.return_type() != Some(wasmi::ValueType::I64) { - instructions.push(Instruction::I32WrapI64); + instructions.push(Instruction::I32WrapI64(UniArg::Pop)); } } @@ -83,11 +109,12 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { offset: offset as u64, vtype: typ.into(), }, - Instruction::SetLocal(offset, typ) => Opcode::LocalSet { + Instruction::SetLocal(offset, typ, uniarg) => Opcode::LocalSet { offset: offset as u64, vtype: typ.into(), + uniarg, }, - Instruction::TeeLocal(offset, typ) => Opcode::LocalTee { + Instruction::TeeLocal(offset, typ, ..) => Opcode::LocalTee { offset: offset as u64, vtype: typ.into(), }, @@ -100,7 +127,7 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { }, dst_pc, }, - Instruction::BrIfEqz(Target { dst_pc, drop_keep }) => Opcode::BrIfEqz { + Instruction::BrIfEqz(Target { dst_pc, drop_keep }, uniarg) => Opcode::BrIfEqz { drop: drop_keep.drop, keep: if let Keep::Single(t) = drop_keep.keep { vec![t.into()] @@ -108,8 +135,9 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { vec![] }, dst_pc, + uniarg, }, - Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { + Instruction::BrIfNez(Target { dst_pc, drop_keep }, uniarg) => Opcode::BrIf { drop: drop_keep.drop, keep: if let Keep::Single(t) = drop_keep.keep { vec![t.into()] @@ -117,8 +145,9 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { vec![] }, dst_pc, + uniarg, }, - Instruction::BrTable(targets) => Opcode::BrTable { + Instruction::BrTable(targets, uniarg) => Opcode::BrTable { targets: targets .stream .iter() @@ -139,6 +168,7 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { } }) .collect(), + uniarg, }, Instruction::Unreachable => Opcode::Unreachable, Instruction::Return(drop_keep) => Opcode::Return { @@ -170,112 +200,139 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { } } } - Instruction::CallIndirect(idx) => Opcode::CallIndirect { type_idx: idx }, + Instruction::CallIndirect(idx, uniarg) => Opcode::CallIndirect { + type_idx: idx, + uniarg, + }, Instruction::Drop => Opcode::Drop, - Instruction::Select(_) => Opcode::Select, - Instruction::GetGlobal(idx) => Opcode::GlobalGet { idx: idx as u64 }, - Instruction::SetGlobal(idx) => Opcode::GlobalSet { idx: idx as u64 }, - Instruction::I32Load(offset) => Opcode::Load { + Instruction::Select(_, lhs, rhs, cond) => Opcode::Select { + uniargs: [lhs, rhs, cond], + }, + Instruction::GetGlobal(idx, ..) => Opcode::GlobalGet { idx: idx as u64 }, + Instruction::SetGlobal(idx, uniarg) => Opcode::GlobalSet { + idx: idx as u64, + uniarg, + }, + Instruction::I32Load(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I32, size: MemoryReadSize::U32, + uniarg, }, - Instruction::I64Load(offset) => Opcode::Load { + Instruction::I64Load(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::I64, + uniarg, }, Instruction::F32Load(_) => todo!(), Instruction::F64Load(_) => todo!(), - Instruction::I32Load8S(offset) => Opcode::Load { + Instruction::I32Load8S(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I32, size: MemoryReadSize::S8, + uniarg, }, - Instruction::I32Load8U(offset) => Opcode::Load { + Instruction::I32Load8U(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I32, size: MemoryReadSize::U8, + uniarg, }, - Instruction::I32Load16S(offset) => Opcode::Load { + Instruction::I32Load16S(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I32, size: MemoryReadSize::S16, + uniarg, }, - Instruction::I32Load16U(offset) => Opcode::Load { + Instruction::I32Load16U(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I32, size: MemoryReadSize::U16, + uniarg, }, - Instruction::I64Load8S(offset) => Opcode::Load { + Instruction::I64Load8S(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::S8, + uniarg, }, - Instruction::I64Load8U(offset) => Opcode::Load { + Instruction::I64Load8U(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::U8, + uniarg, }, - Instruction::I64Load16S(offset) => Opcode::Load { + Instruction::I64Load16S(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::S16, + uniarg, }, - Instruction::I64Load16U(offset) => Opcode::Load { + Instruction::I64Load16U(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::U16, + uniarg, }, - Instruction::I64Load32S(offset) => Opcode::Load { + Instruction::I64Load32S(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::S32, + uniarg, }, - Instruction::I64Load32U(offset) => Opcode::Load { + Instruction::I64Load32U(offset, uniarg) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::U32, + uniarg, }, - Instruction::I32Store(offset) => Opcode::Store { + Instruction::I32Store(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I32, size: MemoryStoreSize::Byte32, + uniargs: [val, pos], }, - Instruction::I64Store(offset) => Opcode::Store { + Instruction::I64Store(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I64, size: MemoryStoreSize::Byte64, + uniargs: [val, pos], }, Instruction::F32Store(_) => todo!(), Instruction::F64Store(_) => todo!(), - Instruction::I32Store8(offset) => Opcode::Store { + Instruction::I32Store8(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I32, size: MemoryStoreSize::Byte8, + uniargs: [val, pos], }, - Instruction::I32Store16(offset) => Opcode::Store { + Instruction::I32Store16(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I32, size: MemoryStoreSize::Byte16, + uniargs: [val, pos], }, - Instruction::I64Store8(offset) => Opcode::Store { + Instruction::I64Store8(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I64, size: MemoryStoreSize::Byte8, + uniargs: [val, pos], }, - Instruction::I64Store16(offset) => Opcode::Store { + Instruction::I64Store16(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I64, size: MemoryStoreSize::Byte16, + uniargs: [val, pos], }, - Instruction::I64Store32(offset) => Opcode::Store { + Instruction::I64Store32(offset, val, pos) => Opcode::Store { offset, vtype: VarType::I64, size: MemoryStoreSize::Byte32, + uniargs: [val, pos], }, Instruction::CurrentMemory => Opcode::MemorySize, - Instruction::GrowMemory => Opcode::MemoryGrow, + Instruction::GrowMemory(uniarg) => Opcode::MemoryGrow { uniarg }, Instruction::I32Const(v) => Opcode::Const { vtype: VarType::I32, value: v as u32 as u64, @@ -286,93 +343,115 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { }, Instruction::F32Const(_) => todo!(), Instruction::F64Const(_) => todo!(), - Instruction::I32Eqz => Opcode::Test { + Instruction::I32Eqz(uniarg) => Opcode::Test { class: TestOp::Eqz, vtype: VarType::I32, + uniarg, }, - Instruction::I32Eq => Opcode::Rel { + Instruction::I32Eq(arg0, arg1) => Opcode::Rel { class: RelOp::Eq, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Ne => Opcode::Rel { + Instruction::I32Ne(arg0, arg1) => Opcode::Rel { class: RelOp::Ne, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32LtS => Opcode::Rel { + Instruction::I32LtS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedLt, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32LtU => Opcode::Rel { + Instruction::I32LtU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedLt, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32GtS => Opcode::Rel { + Instruction::I32GtS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedGt, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32GtU => Opcode::Rel { + Instruction::I32GtU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedGt, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32LeS => Opcode::Rel { + Instruction::I32LeS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedLe, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32LeU => Opcode::Rel { + Instruction::I32LeU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedLe, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32GeS => Opcode::Rel { + Instruction::I32GeS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedGe, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32GeU => Opcode::Rel { + Instruction::I32GeU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedGe, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I64Eqz => Opcode::Test { + Instruction::I64Eqz(uniarg) => Opcode::Test { class: TestOp::Eqz, vtype: VarType::I64, + uniarg, }, - Instruction::I64Eq => Opcode::Rel { + Instruction::I64Eq(arg0, arg1) => Opcode::Rel { class: RelOp::Eq, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Ne => Opcode::Rel { + Instruction::I64Ne(arg0, arg1) => Opcode::Rel { class: RelOp::Ne, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64LtS => Opcode::Rel { + Instruction::I64LtS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedLt, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64LtU => Opcode::Rel { + Instruction::I64LtU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedLt, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64GtS => Opcode::Rel { + Instruction::I64GtS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedGt, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64GtU => Opcode::Rel { + Instruction::I64GtU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedGt, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64LeS => Opcode::Rel { + Instruction::I64LeS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedLe, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64LeU => Opcode::Rel { + Instruction::I64LeU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedLe, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64GeS => Opcode::Rel { + Instruction::I64GeS(arg0, arg1) => Opcode::Rel { class: RelOp::SignedGe, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64GeU => Opcode::Rel { + Instruction::I64GeU(arg0, arg1) => Opcode::Rel { class: RelOp::UnsignedGe, vtype: VarType::I64, + uniargs: [arg0, arg1], }, Instruction::F32Eq => todo!(), Instruction::F32Ne => todo!(), @@ -386,149 +465,163 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { Instruction::F64Gt => todo!(), Instruction::F64Le => todo!(), Instruction::F64Ge => todo!(), - Instruction::I32Clz => Opcode::Unary { + Instruction::I32Clz(uniarg) => Opcode::Unary { class: UnaryOp::Clz, vtype: VarType::I32, + uniarg, }, - Instruction::I32Ctz => Opcode::Unary { + Instruction::I32Ctz(uniarg) => Opcode::Unary { class: UnaryOp::Ctz, vtype: VarType::I32, + uniarg, }, - Instruction::I32Popcnt => Opcode::Unary { + Instruction::I32Popcnt(uniarg) => Opcode::Unary { class: UnaryOp::Popcnt, vtype: VarType::I32, + uniarg, }, - Instruction::I32Add => Opcode::Bin { - class: BinOp::Add, - vtype: VarType::I32, - }, - Instruction::I32Sub => Opcode::Bin { - class: BinOp::Sub, - vtype: VarType::I32, - }, - Instruction::I32Mul => Opcode::Bin { - class: BinOp::Mul, - vtype: VarType::I32, - }, - Instruction::I32DivS => Opcode::Bin { - class: BinOp::SignedDiv, - vtype: VarType::I32, - }, - Instruction::I32DivU => Opcode::Bin { - class: BinOp::UnsignedDiv, - vtype: VarType::I32, - }, - Instruction::I32RemS => Opcode::Bin { - class: BinOp::SignedRem, - vtype: VarType::I32, - }, - Instruction::I32RemU => Opcode::Bin { - class: BinOp::UnsignedRem, + + Instruction::I32Add(lhs, rhs) + | Instruction::I32Sub(lhs, rhs) + | Instruction::I32Mul(lhs, rhs) + | Instruction::I32DivS(lhs, rhs) + | Instruction::I32DivU(lhs, rhs) + | Instruction::I32RemS(lhs, rhs) + | Instruction::I32RemU(lhs, rhs) => Opcode::Bin { + class: BinOp::from(&self), vtype: VarType::I32, + uniargs: [lhs, rhs], }, - Instruction::I32And => Opcode::BinBit { + + Instruction::I32And(arg0, arg1) => Opcode::BinBit { class: BitOp::And, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Or => Opcode::BinBit { + Instruction::I32Or(arg0, arg1) => Opcode::BinBit { class: BitOp::Or, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Xor => Opcode::BinBit { + Instruction::I32Xor(arg0, arg1) => Opcode::BinBit { class: BitOp::Xor, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Shl => Opcode::BinShift { + Instruction::I32Shl(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Shl, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32ShrS => Opcode::BinShift { + Instruction::I32ShrS(arg0, arg1) => Opcode::BinShift { class: ShiftOp::SignedShr, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32ShrU => Opcode::BinShift { + Instruction::I32ShrU(arg0, arg1) => Opcode::BinShift { class: ShiftOp::UnsignedShr, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Rotl => Opcode::BinShift { + Instruction::I32Rotl(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Rotl, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I32Rotr => Opcode::BinShift { + Instruction::I32Rotr(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Rotr, vtype: VarType::I32, + uniargs: [arg0, arg1], }, - Instruction::I64Clz => Opcode::Unary { + Instruction::I64Clz(uniarg) => Opcode::Unary { class: UnaryOp::Clz, vtype: VarType::I64, + uniarg, }, - Instruction::I64Ctz => Opcode::Unary { + Instruction::I64Ctz(uniarg) => Opcode::Unary { class: UnaryOp::Ctz, vtype: VarType::I64, + uniarg, }, - Instruction::I64Popcnt => Opcode::Unary { + Instruction::I64Popcnt(uniarg) => Opcode::Unary { class: UnaryOp::Popcnt, vtype: VarType::I64, + uniarg, }, - Instruction::I64Add => Opcode::Bin { + Instruction::I64Add(arg0, arg1) => Opcode::Bin { class: BinOp::Add, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Sub => Opcode::Bin { + Instruction::I64Sub(arg0, arg1) => Opcode::Bin { class: BinOp::Sub, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Mul => Opcode::Bin { + Instruction::I64Mul(arg0, arg1) => Opcode::Bin { class: BinOp::Mul, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64DivS => Opcode::Bin { + Instruction::I64DivS(arg0, arg1) => Opcode::Bin { class: BinOp::SignedDiv, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64DivU => Opcode::Bin { + Instruction::I64DivU(arg0, arg1) => Opcode::Bin { class: BinOp::UnsignedDiv, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64RemS => Opcode::Bin { + Instruction::I64RemS(arg0, arg1) => Opcode::Bin { class: BinOp::SignedRem, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64RemU => Opcode::Bin { + Instruction::I64RemU(arg0, arg1) => Opcode::Bin { class: BinOp::UnsignedRem, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64And => Opcode::BinBit { + Instruction::I64And(arg0, arg1) => Opcode::BinBit { class: BitOp::And, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Or => Opcode::BinBit { + Instruction::I64Or(arg0, arg1) => Opcode::BinBit { class: BitOp::Or, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Xor => Opcode::BinBit { + Instruction::I64Xor(arg0, arg1) => Opcode::BinBit { class: BitOp::Xor, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Shl => Opcode::BinShift { + Instruction::I64Shl(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Shl, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64ShrS => Opcode::BinShift { + Instruction::I64ShrS(arg0, arg1) => Opcode::BinShift { class: ShiftOp::SignedShr, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64ShrU => Opcode::BinShift { + Instruction::I64ShrU(arg0, arg1) => Opcode::BinShift { class: ShiftOp::UnsignedShr, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Rotl => Opcode::BinShift { + Instruction::I64Rotl(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Rotl, vtype: VarType::I64, + uniargs: [arg0, arg1], }, - Instruction::I64Rotr => Opcode::BinShift { + Instruction::I64Rotr(arg0, arg1) => Opcode::BinShift { class: ShiftOp::Rotr, vtype: VarType::I64, + uniargs: [arg0, arg1], }, Instruction::F32Abs => todo!(), Instruction::F32Neg => todo!(), @@ -558,18 +651,21 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { Instruction::F64Min => todo!(), Instruction::F64Max => todo!(), Instruction::F64Copysign => todo!(), - Instruction::I32WrapI64 => Opcode::Conversion { + Instruction::I32WrapI64(uniarg) => Opcode::Conversion { class: ConversionOp::I32WrapI64, + uniarg, }, Instruction::I32TruncSF32 => todo!(), Instruction::I32TruncUF32 => todo!(), Instruction::I32TruncSF64 => todo!(), Instruction::I32TruncUF64 => todo!(), - Instruction::I64ExtendSI32 => Opcode::Conversion { + Instruction::I64ExtendSI32(uniarg) => Opcode::Conversion { class: ConversionOp::I64ExtendI32s, + uniarg, }, - Instruction::I64ExtendUI32 => Opcode::Conversion { + Instruction::I64ExtendUI32(uniarg) => Opcode::Conversion { class: ConversionOp::I64ExtendI32u, + uniarg, }, Instruction::I64TruncSF32 => todo!(), Instruction::I64TruncUF32 => todo!(), @@ -589,20 +685,25 @@ impl<'a> InstructionIntoOpcode for wasmi::isa::Instruction<'a> { Instruction::I64ReinterpretF64 => todo!(), Instruction::F32ReinterpretI32 => todo!(), Instruction::F64ReinterpretI64 => todo!(), - Instruction::I32Extend8S => Opcode::Conversion { + Instruction::I32Extend8S(uniarg) => Opcode::Conversion { class: ConversionOp::I32Extend8S, + uniarg, }, - Instruction::I32Extend16S => Opcode::Conversion { + Instruction::I32Extend16S(uniarg) => Opcode::Conversion { class: ConversionOp::I32Extend16S, + uniarg, }, - Instruction::I64Extend8S => Opcode::Conversion { + Instruction::I64Extend8S(uniarg) => Opcode::Conversion { class: ConversionOp::I64Extend8S, + uniarg, }, - Instruction::I64Extend16S => Opcode::Conversion { + Instruction::I64Extend16S(uniarg) => Opcode::Conversion { class: ConversionOp::I64Extend16S, + uniarg, }, - Instruction::I64Extend32S => Opcode::Conversion { + Instruction::I64Extend32S(uniarg) => Opcode::Conversion { class: ConversionOp::I64Extend32S, + uniarg, }, } } @@ -652,6 +753,8 @@ pub(super) enum RunInstructionTracePre { GrowMemory(i32), + I32(i32), + I64(i64), I32BinOp { left: i32, right: i32, @@ -663,38 +766,12 @@ pub(super) enum RunInstructionTracePre { }, I32Single(i32), - I32Comp { - left: i32, - right: i32, - }, I64Single(i64), - I64Comp { - left: i64, - right: i64, - }, - I32WrapI64 { - value: i64, - }, I64ExtendI32 { value: i32, sign: bool, }, - I32SignExtendI8 { - value: i32, - }, - I32SignExtendI16 { - value: i32, - }, - I64SignExtendI8 { - value: i64, - }, - I64SignExtendI16 { - value: i64, - }, - I64SignExtendI32 { - value: i64, - }, UnaryOp { operand: u64, @@ -703,8 +780,8 @@ pub(super) enum RunInstructionTracePre { Drop, Select { - val1: u64, - val2: u64, + lhs: u64, + rhs: u64, cond: u64, }, } @@ -716,11 +793,11 @@ pub(super) fn run_instruction_pre( ) -> Option { match *instructions { isa::Instruction::GetLocal(..) => None, - isa::Instruction::SetLocal(depth, vtype) => { - let value = value_stack.top(); + isa::Instruction::SetLocal(depth, vtype, uniarg) => { + let value = value_from_uniargs(&[uniarg], value_stack)[0]; Some(RunInstructionTracePre::SetLocal { depth, - value: *value, + value, vtype, }) } @@ -729,23 +806,23 @@ pub(super) fn run_instruction_pre( isa::Instruction::SetGlobal(..) => Some(RunInstructionTracePre::SetGlobal), isa::Instruction::Br(_) => None, - isa::Instruction::BrIfEqz(_) => Some(RunInstructionTracePre::BrIfEqz { - value: <_>::from_value_internal(*value_stack.top()), + isa::Instruction::BrIfEqz(_, uniarg) => Some(RunInstructionTracePre::BrIfEqz { + value: <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), }), - isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { - value: <_>::from_value_internal(*value_stack.top()), + isa::Instruction::BrIfNez(_, uniarg) => Some(RunInstructionTracePre::BrIfNez { + value: <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), }), - isa::Instruction::BrTable(_) => Some(RunInstructionTracePre::BrTable { - index: <_>::from_value_internal(*value_stack.top()), + isa::Instruction::BrTable(_, uniarg) => Some(RunInstructionTracePre::BrTable { + index: <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), }), isa::Instruction::Unreachable => None, isa::Instruction::Return(..) => None, isa::Instruction::Call(..) => Some(RunInstructionTracePre::Call), - isa::Instruction::CallIndirect(type_idx) => { + isa::Instruction::CallIndirect(type_idx, uniarg) => { let table_idx = DEFAULT_TABLE_INDEX; - let offset = <_>::from_value_internal(*value_stack.top()); + let offset = <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]); Some(RunInstructionTracePre::CallIndirect { table_idx, @@ -755,17 +832,21 @@ pub(super) fn run_instruction_pre( } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::Select(vtype) => Some(RunInstructionTracePre::Select { - cond: from_value_internal_to_u64_with_typ(VarType::I32, *value_stack.pick(1)), - val2: from_value_internal_to_u64_with_typ(vtype.into(), *value_stack.pick(2)), - val1: from_value_internal_to_u64_with_typ(vtype.into(), *value_stack.pick(3)), - }), + isa::Instruction::Select(vtype, lhs, rhs, cond) => { + let values = value_from_uniargs(&[cond, rhs, lhs], value_stack); + + Some(RunInstructionTracePre::Select { + cond: from_value_internal_to_u64_with_typ(VarType::I32, values[0]), + rhs: from_value_internal_to_u64_with_typ(vtype.into(), values[1]), + lhs: from_value_internal_to_u64_with_typ(vtype.into(), values[2]), + }) + } - isa::Instruction::I32Load(offset) - | isa::Instruction::I32Load8S(offset) - | isa::Instruction::I32Load8U(offset) - | isa::Instruction::I32Load16S(offset) - | isa::Instruction::I32Load16U(offset) => { + isa::Instruction::I32Load(offset, uniarg) + | isa::Instruction::I32Load8S(offset, uniarg) + | isa::Instruction::I32Load8U(offset, uniarg) + | isa::Instruction::I32Load16S(offset, uniarg) + | isa::Instruction::I32Load16U(offset, uniarg) => { let load_size = match *instructions { isa::Instruction::I32Load(..) => MemoryReadSize::U32, isa::Instruction::I32Load8S(..) => MemoryReadSize::S8, @@ -775,7 +856,8 @@ pub(super) fn run_instruction_pre( _ => unreachable!(), }; - let raw_address = <_>::from_value_internal(*value_stack.top()); + let raw_address = + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]); let address = effective_address(offset, raw_address).ok(); Some(RunInstructionTracePre::Load { @@ -786,13 +868,13 @@ pub(super) fn run_instruction_pre( load_size, }) } - isa::Instruction::I64Load(offset) - | isa::Instruction::I64Load8S(offset) - | isa::Instruction::I64Load8U(offset) - | isa::Instruction::I64Load16S(offset) - | isa::Instruction::I64Load16U(offset) - | isa::Instruction::I64Load32S(offset) - | isa::Instruction::I64Load32U(offset) => { + isa::Instruction::I64Load(offset, uniarg) + | isa::Instruction::I64Load8S(offset, uniarg) + | isa::Instruction::I64Load8U(offset, uniarg) + | isa::Instruction::I64Load16S(offset, uniarg) + | isa::Instruction::I64Load16U(offset, uniarg) + | isa::Instruction::I64Load32S(offset, uniarg) + | isa::Instruction::I64Load32U(offset, uniarg) => { let load_size = match *instructions { isa::Instruction::I64Load(..) => MemoryReadSize::I64, isa::Instruction::I64Load8S(..) => MemoryReadSize::S8, @@ -803,7 +885,8 @@ pub(super) fn run_instruction_pre( isa::Instruction::I64Load32U(..) => MemoryReadSize::U32, _ => unreachable!(), }; - let raw_address = <_>::from_value_internal(*value_stack.top()); + let raw_address = + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]); let address = effective_address(offset, raw_address).ok(); Some(RunInstructionTracePre::Load { @@ -814,18 +897,20 @@ pub(super) fn run_instruction_pre( load_size, }) } - isa::Instruction::I32Store(offset) - | isa::Instruction::I32Store8(offset) - | isa::Instruction::I32Store16(offset) => { + isa::Instruction::I32Store(offset, pos_uniarg, val_uniarg) + | isa::Instruction::I32Store8(offset, pos_uniarg, val_uniarg) + | isa::Instruction::I32Store16(offset, pos_uniarg, val_uniarg) => { let store_size = match *instructions { - isa::Instruction::I32Store8(_) => MemoryStoreSize::Byte8, - isa::Instruction::I32Store16(_) => MemoryStoreSize::Byte16, - isa::Instruction::I32Store(_) => MemoryStoreSize::Byte32, + isa::Instruction::I32Store8(..) => MemoryStoreSize::Byte8, + isa::Instruction::I32Store16(..) => MemoryStoreSize::Byte16, + isa::Instruction::I32Store(..) => MemoryStoreSize::Byte32, _ => unreachable!(), }; - let value: u32 = <_>::from_value_internal(*value_stack.pick(1)); - let raw_address = <_>::from_value_internal(*value_stack.pick(2)); + let values = value_from_uniargs(&[val_uniarg, pos_uniarg], value_stack); + + let value: u32 = <_>::from_value_internal(values[0]); + let raw_address = <_>::from_value_internal(values[1]); let address = effective_address(offset, raw_address).ok(); let pre_block_value1 = address.map(|address| { @@ -865,10 +950,10 @@ pub(super) fn run_instruction_pre( pre_block_value2, }) } - isa::Instruction::I64Store(offset) - | isa::Instruction::I64Store8(offset) - | isa::Instruction::I64Store16(offset) - | isa::Instruction::I64Store32(offset) => { + isa::Instruction::I64Store(offset, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store8(offset, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store16(offset, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store32(offset, pos_uniarg, val_uniarg) => { let store_size = match *instructions { isa::Instruction::I64Store(..) => MemoryStoreSize::Byte64, isa::Instruction::I64Store8(..) => MemoryStoreSize::Byte8, @@ -877,8 +962,10 @@ pub(super) fn run_instruction_pre( _ => unreachable!(), }; - let value = <_>::from_value_internal(*value_stack.pick(1)); - let raw_address = <_>::from_value_internal(*value_stack.pick(2)); + let values = value_from_uniargs(&[val_uniarg, pos_uniarg], value_stack); + + let value = <_>::from_value_internal(values[0]); + let raw_address = <_>::from_value_internal(values[1]); let address = effective_address(offset, raw_address).ok(); let pre_block_value1 = address.map(|address| { @@ -920,125 +1007,126 @@ pub(super) fn run_instruction_pre( } isa::Instruction::CurrentMemory => None, - isa::Instruction::GrowMemory => Some(RunInstructionTracePre::GrowMemory( - <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::GrowMemory(uniarg) => Some(RunInstructionTracePre::GrowMemory( + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), )), isa::Instruction::I32Const(_) => None, isa::Instruction::I64Const(_) => None, - isa::Instruction::I32Eqz => Some(RunInstructionTracePre::I32Single( - <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::I32Eqz(uniarg) => Some(RunInstructionTracePre::I32Single( + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), )), - isa::Instruction::I64Eqz => Some(RunInstructionTracePre::I64Single( - <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::I64Eqz(uniarg) => Some(RunInstructionTracePre::I64Single( + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), )), - isa::Instruction::I32Eq - | isa::Instruction::I32Ne - | isa::Instruction::I32GtS - | isa::Instruction::I32GtU - | isa::Instruction::I32GeS - | isa::Instruction::I32GeU - | isa::Instruction::I32LtU - | isa::Instruction::I32LeU - | isa::Instruction::I32LtS - | isa::Instruction::I32LeS => Some(RunInstructionTracePre::I32Comp { - left: <_>::from_value_internal(*value_stack.pick(2)), - right: <_>::from_value_internal(*value_stack.pick(1)), - }), - - isa::Instruction::I64Eq - | isa::Instruction::I64Ne - | isa::Instruction::I64GtS - | isa::Instruction::I64GtU - | isa::Instruction::I64GeS - | isa::Instruction::I64GeU - | isa::Instruction::I64LtU - | isa::Instruction::I64LeU - | isa::Instruction::I64LtS - | isa::Instruction::I64LeS => Some(RunInstructionTracePre::I64Comp { - left: <_>::from_value_internal(*value_stack.pick(2)), - right: <_>::from_value_internal(*value_stack.pick(1)), - }), - - isa::Instruction::I32Add - | isa::Instruction::I32Sub - | isa::Instruction::I32Mul - | isa::Instruction::I32DivS - | isa::Instruction::I32DivU - | isa::Instruction::I32RemS - | isa::Instruction::I32RemU - | isa::Instruction::I32Shl - | isa::Instruction::I32ShrU - | isa::Instruction::I32ShrS - | isa::Instruction::I32And - | isa::Instruction::I32Or - | isa::Instruction::I32Xor - | isa::Instruction::I32Rotl - | isa::Instruction::I32Rotr => Some(RunInstructionTracePre::I32BinOp { - left: <_>::from_value_internal(*value_stack.pick(2)), - right: <_>::from_value_internal(*value_stack.pick(1)), - }), - - isa::Instruction::I64Add - | isa::Instruction::I64Sub - | isa::Instruction::I64Mul - | isa::Instruction::I64DivS - | isa::Instruction::I64DivU - | isa::Instruction::I64RemS - | isa::Instruction::I64RemU - | isa::Instruction::I64Shl - | isa::Instruction::I64ShrU - | isa::Instruction::I64ShrS - | isa::Instruction::I64And - | isa::Instruction::I64Or - | isa::Instruction::I64Xor - | isa::Instruction::I64Rotl - | isa::Instruction::I64Rotr => Some(RunInstructionTracePre::I64BinOp { - left: <_>::from_value_internal(*value_stack.pick(2)), - right: <_>::from_value_internal(*value_stack.pick(1)), - }), - - isa::Instruction::I32Ctz | isa::Instruction::I32Clz | isa::Instruction::I32Popcnt => { - Some(RunInstructionTracePre::UnaryOp { - operand: from_value_internal_to_u64_with_typ(VarType::I32, *value_stack.pick(1)), - vtype: VarType::I32, + isa::Instruction::I32Eq(lhs, rhs) + | isa::Instruction::I32Ne(lhs, rhs) + | isa::Instruction::I32GtS(lhs, rhs) + | isa::Instruction::I32GtU(lhs, rhs) + | isa::Instruction::I32GeS(lhs, rhs) + | isa::Instruction::I32GeU(lhs, rhs) + | isa::Instruction::I32LtU(lhs, rhs) + | isa::Instruction::I32LeU(lhs, rhs) + | isa::Instruction::I32LtS(lhs, rhs) + | isa::Instruction::I32LeS(lhs, rhs) + | isa::Instruction::I32Add(lhs, rhs) + | isa::Instruction::I32Sub(lhs, rhs) + | isa::Instruction::I32Mul(lhs, rhs) + | isa::Instruction::I32DivS(lhs, rhs) + | isa::Instruction::I32DivU(lhs, rhs) + | isa::Instruction::I32RemS(lhs, rhs) + | isa::Instruction::I32RemU(lhs, rhs) + | isa::Instruction::I32Shl(lhs, rhs) + | isa::Instruction::I32ShrU(lhs, rhs) + | isa::Instruction::I32ShrS(lhs, rhs) + | isa::Instruction::I32And(lhs, rhs) + | isa::Instruction::I32Or(lhs, rhs) + | isa::Instruction::I32Xor(lhs, rhs) + | isa::Instruction::I32Rotl(lhs, rhs) + | isa::Instruction::I32Rotr(lhs, rhs) => { + let uniargs = &[rhs, lhs]; + let values = value_from_uniargs(uniargs, value_stack); + Some(RunInstructionTracePre::I32BinOp { + left: <_>::from_value_internal(values[1]), + right: <_>::from_value_internal(values[0]), }) } - isa::Instruction::I64Ctz | isa::Instruction::I64Clz | isa::Instruction::I64Popcnt => { - Some(RunInstructionTracePre::UnaryOp { - operand: from_value_internal_to_u64_with_typ(VarType::I64, *value_stack.pick(1)), - vtype: VarType::I64, + + isa::Instruction::I64Eq(lhs, rhs) + | isa::Instruction::I64Ne(lhs, rhs) + | isa::Instruction::I64GtS(lhs, rhs) + | isa::Instruction::I64GtU(lhs, rhs) + | isa::Instruction::I64GeS(lhs, rhs) + | isa::Instruction::I64GeU(lhs, rhs) + | isa::Instruction::I64LtU(lhs, rhs) + | isa::Instruction::I64LeU(lhs, rhs) + | isa::Instruction::I64LtS(lhs, rhs) + | isa::Instruction::I64LeS(lhs, rhs) + | isa::Instruction::I64Add(lhs, rhs) + | isa::Instruction::I64Sub(lhs, rhs) + | isa::Instruction::I64Mul(lhs, rhs) + | isa::Instruction::I64DivS(lhs, rhs) + | isa::Instruction::I64DivU(lhs, rhs) + | isa::Instruction::I64RemS(lhs, rhs) + | isa::Instruction::I64RemU(lhs, rhs) + | isa::Instruction::I64Shl(lhs, rhs) + | isa::Instruction::I64ShrU(lhs, rhs) + | isa::Instruction::I64ShrS(lhs, rhs) + | isa::Instruction::I64And(lhs, rhs) + | isa::Instruction::I64Or(lhs, rhs) + | isa::Instruction::I64Xor(lhs, rhs) + | isa::Instruction::I64Rotl(lhs, rhs) + | isa::Instruction::I64Rotr(lhs, rhs) => { + let uniargs = &[rhs, lhs]; + let values = value_from_uniargs(uniargs, value_stack); + Some(RunInstructionTracePre::I64BinOp { + left: <_>::from_value_internal(values[1]), + right: <_>::from_value_internal(values[0]), }) } - isa::Instruction::I32WrapI64 => Some(RunInstructionTracePre::I32WrapI64 { - value: <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::I32Ctz(uniarg) + | isa::Instruction::I32Clz(uniarg) + | isa::Instruction::I32Popcnt(uniarg) => Some(RunInstructionTracePre::UnaryOp { + operand: from_value_internal_to_u64_with_typ( + VarType::I32, + value_from_uniargs(&[uniarg], value_stack)[0], + ), + vtype: VarType::I32, }), - isa::Instruction::I64ExtendUI32 => Some(RunInstructionTracePre::I64ExtendI32 { - value: <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::I64Ctz(uniarg) + | isa::Instruction::I64Clz(uniarg) + | isa::Instruction::I64Popcnt(uniarg) => Some(RunInstructionTracePre::UnaryOp { + operand: from_value_internal_to_u64_with_typ( + VarType::I64, + value_from_uniargs(&[uniarg], value_stack)[0], + ), + vtype: VarType::I64, + }), + + isa::Instruction::I32WrapI64(uniarg) => Some(RunInstructionTracePre::I64( + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), + )), + isa::Instruction::I64ExtendUI32(uniarg) => Some(RunInstructionTracePre::I64ExtendI32 { + value: <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), sign: false, }), - isa::Instruction::I64ExtendSI32 => Some(RunInstructionTracePre::I64ExtendI32 { - value: <_>::from_value_internal(*value_stack.pick(1)), + isa::Instruction::I64ExtendSI32(uniarg) => Some(RunInstructionTracePre::I64ExtendI32 { + value: <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), sign: true, }), - isa::Instruction::I32Extend8S => Some(RunInstructionTracePre::I32SignExtendI8 { - value: <_>::from_value_internal(*value_stack.pick(1)), - }), - isa::Instruction::I32Extend16S => Some(RunInstructionTracePre::I32SignExtendI16 { - value: <_>::from_value_internal(*value_stack.pick(1)), - }), - isa::Instruction::I64Extend8S => Some(RunInstructionTracePre::I64SignExtendI8 { - value: <_>::from_value_internal(*value_stack.pick(1)), - }), - isa::Instruction::I64Extend16S => Some(RunInstructionTracePre::I64SignExtendI16 { - value: <_>::from_value_internal(*value_stack.pick(1)), - }), - isa::Instruction::I64Extend32S => Some(RunInstructionTracePre::I64SignExtendI32 { - value: <_>::from_value_internal(*value_stack.pick(1)), - }), + isa::Instruction::I32Extend8S(uniarg) | isa::Instruction::I32Extend16S(uniarg) => { + Some(RunInstructionTracePre::I32(<_>::from_value_internal( + value_from_uniargs(&[uniarg], value_stack)[0], + ))) + } + isa::Instruction::I64Extend8S(uniarg) + | isa::Instruction::I64Extend16S(uniarg) + | isa::Instruction::I64Extend32S(uniarg) => Some(RunInstructionTracePre::I64( + <_>::from_value_internal(value_from_uniargs(&[uniarg], value_stack)[0]), + )), _ => { println!("{:?}", *instructions); @@ -1054,15 +1142,15 @@ impl TablePlugin { current_event: Option, value_stack: &ValueStack, context: &FunctionContext, - instructions: &isa::Instruction, + instruction: &isa::Instruction, ) -> StepInfo { - match *instructions { + match *instruction { isa::Instruction::GetLocal(depth, vtype) => StepInfo::GetLocal { depth, value: from_value_internal_to_u64_with_typ(vtype.into(), *value_stack.top()), vtype: vtype.into(), }, - isa::Instruction::SetLocal(..) => { + isa::Instruction::SetLocal(_, _, uniarg) => { if let RunInstructionTracePre::SetLocal { depth, value, @@ -1073,6 +1161,7 @@ impl TablePlugin { depth, value: from_value_internal_to_u64_with_typ(vtype.into(), value), vtype: vtype.into(), + uniarg, } } else { unreachable!() @@ -1099,7 +1188,7 @@ impl TablePlugin { value, } } - isa::Instruction::SetGlobal(idx) => { + isa::Instruction::SetGlobal(idx, uniarg) => { let global_ref = context.module().global_by_index(idx).unwrap(); let is_mutable = global_ref.is_mutable(); let vtype: VarType = global_ref.value_type().into_elements().into(); @@ -1113,6 +1202,7 @@ impl TablePlugin { vtype, is_mutable, value, + uniarg, } } @@ -1132,7 +1222,7 @@ impl TablePlugin { Keep::None => vec![], }, }, - isa::Instruction::BrIfEqz(target) => { + isa::Instruction::BrIfEqz(target, uniarg) => { if let RunInstructionTracePre::BrIfEqz { value } = current_event.unwrap() { StepInfo::BrIfEqz { condition: value, @@ -1150,12 +1240,13 @@ impl TablePlugin { )], Keep::None => vec![], }, + uniarg, } } else { unreachable!() } } - isa::Instruction::BrIfNez(target) => { + isa::Instruction::BrIfNez(target, uniarg) => { if let RunInstructionTracePre::BrIfNez { value } = current_event.unwrap() { StepInfo::BrIfNez { condition: value, @@ -1173,12 +1264,13 @@ impl TablePlugin { )], Keep::None => vec![], }, + uniarg, } } else { unreachable!() } } - isa::Instruction::BrTable(targets) => { + isa::Instruction::BrTable(targets, uniarg) => { if let RunInstructionTracePre::BrTable { index } = current_event.unwrap() { StepInfo::BrTable { index, @@ -1196,6 +1288,7 @@ impl TablePlugin { )], Keep::None => vec![], }, + uniarg, } } else { unreachable!() @@ -1233,13 +1326,15 @@ impl TablePlugin { unreachable!() } } - isa::Instruction::Select(vtype) => { - if let RunInstructionTracePre::Select { val1, val2, cond } = current_event.unwrap() - { + isa::Instruction::Select(vtype, lhs_uniarg, rhs_uniarg, cond_uniarg) => { + if let RunInstructionTracePre::Select { lhs, rhs, cond } = current_event.unwrap() { StepInfo::Select { - val1, - val2, + lhs, + lhs_uniarg, + rhs, + rhs_uniarg, cond, + cond_uniarg, result: from_value_internal_to_u64_with_typ( vtype.into(), *value_stack.top(), @@ -1305,7 +1400,7 @@ impl TablePlugin { unreachable!() } } - isa::Instruction::CallIndirect(_) => { + isa::Instruction::CallIndirect(_idx, uniarg) => { if let RunInstructionTracePre::CallIndirect { table_idx, type_idx, @@ -1324,24 +1419,25 @@ impl TablePlugin { type_index: type_idx, offset, func_index, + uniarg, } } else { unreachable!() } } - isa::Instruction::I32Load(..) - | isa::Instruction::I32Load8U(..) - | isa::Instruction::I32Load8S(..) - | isa::Instruction::I32Load16U(..) - | isa::Instruction::I32Load16S(..) - | isa::Instruction::I64Load(..) - | isa::Instruction::I64Load8U(..) - | isa::Instruction::I64Load8S(..) - | isa::Instruction::I64Load16U(..) - | isa::Instruction::I64Load16S(..) - | isa::Instruction::I64Load32U(..) - | isa::Instruction::I64Load32S(..) => { + isa::Instruction::I32Load(_offset, uniarg) + | isa::Instruction::I32Load8U(_offset, uniarg) + | isa::Instruction::I32Load8S(_offset, uniarg) + | isa::Instruction::I32Load16U(_offset, uniarg) + | isa::Instruction::I32Load16S(_offset, uniarg) + | isa::Instruction::I64Load(_offset, uniarg) + | isa::Instruction::I64Load8U(_offset, uniarg) + | isa::Instruction::I64Load8S(_offset, uniarg) + | isa::Instruction::I64Load16U(_offset, uniarg) + | isa::Instruction::I64Load16S(_offset, uniarg) + | isa::Instruction::I64Load32U(_offset, uniarg) + | isa::Instruction::I64Load32S(_offset, uniarg) => { if let RunInstructionTracePre::Load { offset, raw_address, @@ -1387,18 +1483,19 @@ impl TablePlugin { ), block_value1, block_value2, + uniarg, } } else { unreachable!() } } - isa::Instruction::I32Store(..) - | isa::Instruction::I32Store8(..) - | isa::Instruction::I32Store16(..) - | isa::Instruction::I64Store(..) - | isa::Instruction::I64Store8(..) - | isa::Instruction::I64Store16(..) - | isa::Instruction::I64Store32(..) => { + isa::Instruction::I32Store(_, pos_uniarg, val_uniarg) + | isa::Instruction::I32Store8(_, pos_uniarg, val_uniarg) + | isa::Instruction::I32Store16(_, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store(_, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store8(_, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store16(_, pos_uniarg, val_uniarg) + | isa::Instruction::I64Store32(_, pos_uniarg, val_uniarg) => { if let RunInstructionTracePre::Store { offset, raw_address, @@ -1446,6 +1543,8 @@ impl TablePlugin { pre_block_value2: pre_block_value2.unwrap_or(0u64), updated_block_value1, updated_block_value2, + pos_uniarg, + val_uniarg, } } else { unreachable!() @@ -1453,11 +1552,12 @@ impl TablePlugin { } isa::Instruction::CurrentMemory => StepInfo::MemorySize, - isa::Instruction::GrowMemory => { + isa::Instruction::GrowMemory(uniarg) => { if let RunInstructionTracePre::GrowMemory(grow_size) = current_event.unwrap() { StepInfo::MemoryGrow { grow_size, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() @@ -1467,716 +1567,210 @@ impl TablePlugin { isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, isa::Instruction::I64Const(value) => StepInfo::I64Const { value }, - isa::Instruction::I32Eqz => { + isa::Instruction::I32Eqz(uniarg) => { if let RunInstructionTracePre::I32Single(value) = current_event.unwrap() { StepInfo::Test { vtype: VarType::I32, value: value as u32 as u64, result: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Eq => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::Eq, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Ne => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::Ne, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GtS => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedGt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GtU => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedGt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GeS => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedGe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GeU => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedGe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LtS => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedLt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LtU => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedLt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LeS => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedLe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LeU => { - if let RunInstructionTracePre::I32Comp { left, right } = current_event.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedLe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I64Eqz => { + isa::Instruction::I64Eqz(uniarg) => { if let RunInstructionTracePre::I64Single(value) = current_event.unwrap() { StepInfo::Test { vtype: VarType::I64, value: value as u64, result: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Eq => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::Eq, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Ne => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::Ne, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GtS => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedGt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GtU => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedGt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LtU => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedLt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LtS => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedLt, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LeU => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedLe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LeS => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedLe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GeU => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedGe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GeS => { - if let RunInstructionTracePre::I64Comp { left, right } = current_event.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedGe, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I32Add => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Add, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Sub => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Sub, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Mul => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Mul, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32DivU => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::UnsignedDiv, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32RemU => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::UnsignedRem, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32DivS => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinOp { - class: BinOp::SignedDiv, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32RemS => { + uniarg, + } + } else { + unreachable!() + } + } + + isa::Instruction::I32Add(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Sub(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Mul(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32DivU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32RemU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32DivS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32RemS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32And(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Or(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Xor(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Shl(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32ShrU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32ShrS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Rotl(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Rotr(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Eq(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32Ne(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32GtS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32GtU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32GeS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32GeU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32LtS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32LtU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32LeS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I32LeU(lhs_uniarg, rhs_uniarg) => { if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { StepInfo::I32BinOp { - class: BinOp::SignedRem, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32And => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::And, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Or => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::Or, + class: BinaryOp::from(instruction), left, + lhs_uniarg, right, + rhs_uniarg, value: <_>::from_value_internal(*value_stack.top()), } } else { unreachable!() } } - isa::Instruction::I32Xor => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::Xor, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Shl => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Shl, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32ShrU => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::UnsignedShr, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32ShrS => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::SignedShr, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Rotl => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Rotl, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Rotr => { - if let RunInstructionTracePre::I32BinOp { left, right } = current_event.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Rotr, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Add => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Add, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Sub => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Sub, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Mul => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Mul, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64DivU => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::UnsignedDiv, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64RemU => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::UnsignedRem, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64DivS => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinOp { - class: BinOp::SignedDiv, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64RemS => { + isa::Instruction::I64Add(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Sub(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Mul(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64DivU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64RemU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64DivS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64RemS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64And(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Or(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Xor(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Shl(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64ShrU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64ShrS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Rotl(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Rotr(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Eq(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64Ne(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64GtS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64GtU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64GeS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64GeU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64LtS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64LtU(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64LeS(lhs_uniarg, rhs_uniarg) + | isa::Instruction::I64LeU(lhs_uniarg, rhs_uniarg) => { if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { + let class: BinaryOp = BinaryOp::from(instruction).into(); + let value_type = if class.is_rel_op() { + VarType::I32 + } else { + VarType::I64 + }; + StepInfo::I64BinOp { - class: BinOp::SignedRem, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64And => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::And, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Or => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::Or, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Xor => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::Xor, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Shl => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Shl, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64ShrU => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::UnsignedShr, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64ShrS => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::SignedShr, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Rotl => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Rotl, - left, - right, - value: <_>::from_value_internal(*value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Rotr => { - if let RunInstructionTracePre::I64BinOp { left, right } = current_event.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Rotr, + class, left, + lhs_uniarg, right, + rhs_uniarg, value: <_>::from_value_internal(*value_stack.top()), + value_type, } } else { unreachable!() } } - isa::Instruction::I32Ctz - | isa::Instruction::I32Clz - | isa::Instruction::I32Popcnt - | isa::Instruction::I64Ctz - | isa::Instruction::I64Clz - | isa::Instruction::I64Popcnt => { + isa::Instruction::I32Ctz(uniarg) + | isa::Instruction::I32Clz(uniarg) + | isa::Instruction::I32Popcnt(uniarg) + | isa::Instruction::I64Ctz(uniarg) + | isa::Instruction::I64Clz(uniarg) + | isa::Instruction::I64Popcnt(uniarg) => { if let RunInstructionTracePre::UnaryOp { operand, vtype } = current_event.unwrap() { StepInfo::UnaryOp { - class: UnaryOp::from(instructions.clone()), + class: UnaryOp::from(instruction), vtype, operand, result: from_value_internal_to_u64_with_typ(vtype, *value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I32WrapI64 => { - if let RunInstructionTracePre::I32WrapI64 { value } = current_event.unwrap() { + isa::Instruction::I32WrapI64(uniarg) => { + if let RunInstructionTracePre::I64(value) = current_event.unwrap() { StepInfo::I32WrapI64 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I64ExtendSI32 | isa::Instruction::I64ExtendUI32 => { + isa::Instruction::I64ExtendSI32(uniarg) | isa::Instruction::I64ExtendUI32(uniarg) => { if let RunInstructionTracePre::I64ExtendI32 { value, sign } = current_event.unwrap() { StepInfo::I64ExtendI32 { value, result: <_>::from_value_internal(*value_stack.top()), sign, + uniarg, } } else { unreachable!() } } - isa::Instruction::I32Extend8S => { - if let RunInstructionTracePre::I32SignExtendI8 { value } = current_event.unwrap() { + isa::Instruction::I32Extend8S(uniarg) => { + if let RunInstructionTracePre::I32(value) = current_event.unwrap() { StepInfo::I32SignExtendI8 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I32Extend16S => { - if let RunInstructionTracePre::I32SignExtendI16 { value } = current_event.unwrap() { + isa::Instruction::I32Extend16S(uniarg) => { + if let RunInstructionTracePre::I32(value) = current_event.unwrap() { StepInfo::I32SignExtendI16 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I64Extend8S => { - if let RunInstructionTracePre::I64SignExtendI8 { value } = current_event.unwrap() { + isa::Instruction::I64Extend8S(uniarg) => { + if let RunInstructionTracePre::I64(value) = current_event.unwrap() { StepInfo::I64SignExtendI8 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I64Extend16S => { - if let RunInstructionTracePre::I64SignExtendI16 { value } = current_event.unwrap() { + isa::Instruction::I64Extend16S(uniarg) => { + if let RunInstructionTracePre::I64(value) = current_event.unwrap() { StepInfo::I64SignExtendI16 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() } } - isa::Instruction::I64Extend32S => { - if let RunInstructionTracePre::I64SignExtendI32 { value } = current_event.unwrap() { + isa::Instruction::I64Extend32S(uniarg) => { + if let RunInstructionTracePre::I64(value) = current_event.unwrap() { StepInfo::I64SignExtendI32 { value, result: <_>::from_value_internal(*value_stack.top()), + uniarg, } } else { unreachable!() @@ -2184,7 +1778,7 @@ impl TablePlugin { } _ => { - println!("{:?}", instructions); + println!("{:?}", instruction); unimplemented!() } } diff --git a/crates/zkwasm/src/runtime/monitor/plugins/table/mod.rs b/crates/zkwasm/src/runtime/monitor/plugins/table/mod.rs index b24b6d15f..d009a1fec 100644 --- a/crates/zkwasm/src/runtime/monitor/plugins/table/mod.rs +++ b/crates/zkwasm/src/runtime/monitor/plugins/table/mod.rs @@ -6,12 +6,14 @@ use specs::brtable::ElemEntry; use specs::brtable::ElemTable; use specs::configure_table::ConfigureTable; use specs::etable::EventTableEntry; +use specs::configure_table::WASM_32_MAXIMAL_PAGES_DEFAULT; use specs::host_function::HostFunctionDesc; use specs::host_function::HostPlugin; use specs::imtable::InitMemoryTable; use specs::imtable::InitMemoryTableEntry; use specs::itable::InstructionTable; use specs::itable::InstructionTableInternal; +use specs::itable::UniArg; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::slice_backend::SliceBackendBuilder; @@ -315,6 +317,7 @@ impl TablePlugin { StepInfo::I32WrapI64 { value: keep_value.unwrap() as i64, result: keep_value.unwrap() as i32, + uniarg: UniArg::Pop, }, ); @@ -492,7 +495,9 @@ impl Monitor for TablePlugin { const ENTRIES: u32 = 8192; let init_memory_pages = memory_ref.initial().0 as u32; - let maximal_memory_pages = memory_ref.maximum().map_or(65536, |max| max.0 as u32); + let maximal_memory_pages = memory_ref + .maximum() + .map_or(WASM_32_MAXIMAL_PAGES_DEFAULT, |max| max.0 as u32); self.configure_table = ConfigureTable { init_memory_pages, diff --git a/crates/zkwasm/src/test/mod.rs b/crates/zkwasm/src/test/mod.rs index 2516a13b3..954fa65bf 100644 --- a/crates/zkwasm/src/test/mod.rs +++ b/crates/zkwasm/src/test/mod.rs @@ -1,3 +1,4 @@ +use crate::circuits::MIN_K; use crate::loader::slice::Slices; use crate::loader::ZkWasmLoader; use crate::runtime::host::default_env::DefaultHostEnvBuilder; @@ -57,6 +58,19 @@ pub fn test_circuit_with_env( Ok(()) } +/// Run test function and generate trace, then test circuit with mock prover. Only tests should +/// use this function. +fn test_instruction(textual_repr: &str) -> Result<()> { + let mut features = Features::new(); + features.enable_sign_extension(); + + let wasm = wat2wasm_with_features(textual_repr, features).expect("failed to parse wat"); + + test_circuit_with_env(MIN_K, wasm, "zkmain".to_string(), vec![], vec![])?; + + Ok(()) +} + /// Run test function and generate trace, then test circuit with mock prover. Only tests should /// use this function. fn test_circuit_noexternal(textual_repr: &str) -> Result<()> { diff --git a/crates/zkwasm/src/test/test_rlp_slice.rs b/crates/zkwasm/src/test/test_rlp_slice.rs index adbb4f232..aa0533851 100644 --- a/crates/zkwasm/src/test/test_rlp_slice.rs +++ b/crates/zkwasm/src/test/test_rlp_slice.rs @@ -1,13 +1,16 @@ use crate::circuits::config::MIN_K; -use crate::foreign::context::ContextOutput; +use crate::loader::slice::Slices; use crate::loader::ZkWasmLoader; use crate::runtime::host::default_env::DefaultHostEnvBuilder; use crate::runtime::host::default_env::ExecutionArg; - +use crate::runtime::host::HostEnvBuilder; +use crate::test::Fr; +use crate::test::TableMonitor; use anyhow::Result; -use halo2_proofs::pairing::bn256::Bn256; use specs::TraceBackend; +const K: u32 = MIN_K; + fn test_slices() -> Result<()> { let public_inputs = vec![133]; let private_inputs: Vec = vec![ @@ -147,24 +150,25 @@ fn test_slices() -> Result<()> { ]; let wasm = std::fs::read("wasm/rlp.wasm").unwrap(); + let module = ZkWasmLoader::parse_module(&wasm)?; - let loader = ZkWasmLoader::::new(18, wasm, vec![])?; - - let execution_result = loader.run( + let env = DefaultHostEnvBuilder.create_env( + K, ExecutionArg { public_inputs, private_inputs, context_inputs: vec![], - context_outputs: ContextOutput::default(), }, - (), - false, - TraceBackend::Memory, - )?; - let instances = execution_result.public_inputs_and_outputs(); + ); + + let mut monitor = TableMonitor::new(K, &[], TraceBackend::Memory, &env); + let loader = ZkWasmLoader::new(K, env)?; + + let runner = loader.compile(&module, &mut monitor)?; + let result = loader.run(runner, &mut monitor)?; - let slices = loader.slice(execution_result).into_iter(); - slices.mock_test_all(MIN_K, instances)?; + let slices: Slices = Slices::new(K, monitor.into_tables(), None)?; + slices.mock_test_all(result.public_inputs_and_outputs())?; Ok(()) } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_bin.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_bin.rs index 059fab6c8..f89eda118 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_bin.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_bin.rs @@ -1,10 +1,10 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] -fn test_bin_add() { +fn test_bin() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (i32.const 1) (i32.const 1) (i32.add) @@ -22,18 +22,7 @@ fn test_bin_add() { (i64.const 18446744073709551615) (i64.add) (drop) - ) - ) - "#; - test_circuit_noexternal(textual_repr).unwrap() -} - -#[test] -fn test_bin_sub() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 1) (i32.const 1) (i32.sub) @@ -51,18 +40,7 @@ fn test_bin_sub() { (i64.const 1) (i64.sub) (drop) - ) - ) - "#; - test_circuit_noexternal(textual_repr).unwrap() -} - -#[test] -fn test_bin_mul() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 4) (i32.const 3) (i32.mul) @@ -80,18 +58,7 @@ fn test_bin_mul() { (i64.const 18446744073709551615) (i64.mul) (drop) - ) - ) - "#; - - test_circuit_noexternal(textual_repr).unwrap() -} -#[test] -fn test_bin_div_u() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 4) (i32.const 3) (i32.div_u) @@ -117,18 +84,7 @@ fn test_bin_div_u() { (i64.const 1) (i64.div_u) (drop) - ) - ) - "#; - test_circuit_noexternal(textual_repr).unwrap() -} - -#[test] -fn test_bin_div_s() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 4) (i32.const 3) (i32.div_s) @@ -178,18 +134,7 @@ fn test_bin_div_s() { (i64.const 1) (i64.div_s) (drop) - ) - ) - "#; - - test_circuit_noexternal(textual_repr).unwrap() -} -#[test] -fn test_bin_rem_u() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 4) (i32.const 3) (i32.rem_u) @@ -207,18 +152,7 @@ fn test_bin_rem_u() { (i64.const 4) (i64.rem_u) (drop) - ) - ) - "#; - - test_circuit_noexternal(textual_repr).unwrap() -} -#[test] -fn test_bin_rem_s() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 4) (i32.const 3) (i32.rem_s) @@ -264,5 +198,47 @@ fn test_bin_rem_s() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() +} + +#[test] +fn test_bin_uniarg() { + let textual_repr = r#" + (module + (func (export "zkmain") + (local i32) + + (i32.const 1) + (i32.const 2) + (i32.add) + (drop) + + (local.get 0) + (i32.const 1) + (i32.add) + (drop) + + (i32.const 1) + (local.get 0) + (i32.add) + (drop) + + (i32.const 0) + (i32.const 1) + (i32.const 2) + (i32.add) + (i32.add) + (drop) + + (i32.const 0) + (i32.const 1) + (i32.add) + (i32.const 2) + (i32.add) + (drop) + ) + ) + "#; + + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_call_indirect.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_call_indirect.rs index 29bec5147..f2d832c7f 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_call_indirect.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_call_indirect.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_call_indirect() { @@ -19,10 +19,10 @@ fn test_call_indirect() { i32.const 1 call_indirect (type 0)) (table (;0;) 2 2 funcref) - (export "test" (func 2)) + (export "zkmain" (func 2)) (elem (;0;) (i32.const 0) func 0 1) ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_global_get.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_global_get.rs index 674454df9..079e0bc90 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_global_get.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_global_get.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_global_get() { @@ -7,7 +7,7 @@ fn test_global_get() { (global $global_i32 i32 (i32.const 0)) (global $global_i64 i64 (i64.const 0)) - (func (export "test") + (func (export "zkmain") (global.get $global_i32) (drop) (global.get $global_i64) @@ -16,5 +16,5 @@ fn test_global_get() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_global_set.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_global_set.rs index 8251cc9ec..2b4ef7126 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_global_set.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_global_set.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_global_set() { @@ -7,7 +7,7 @@ fn test_global_set() { (global $global_i32 (mut i32) (i32.const 10)) (global $global_i64 (mut i64) (i64.const 10)) - (func (export "test") + (func (export "zkmain") (i32.const 0) (global.set $global_i32) (i64.const 0) @@ -16,5 +16,5 @@ fn test_global_set() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_load.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_load.rs index b1d62ae88..328de1b0a 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_load.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_load.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_load_normal() { @@ -6,7 +6,7 @@ fn test_load_normal() { (module (memory $0 1) (data (i32.const 0) "\ff\00\00\00\fe\00\00\00") - (func (export "test") + (func (export "zkmain") (i32.const 0) (i64.load offset=0) (drop) @@ -54,7 +54,7 @@ fn test_load_normal() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] @@ -63,7 +63,7 @@ fn test_load_cross() { (module (memory $0 1) (data (i32.const 0) "\ff\00\00\00\fe\00\00\00\fd\00\00\00\fc\00\00\00") - (func (export "test") + (func (export "zkmain") (i32.const 4) (i64.load offset=0) (drop) @@ -84,7 +84,7 @@ fn test_load_cross() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] @@ -92,7 +92,7 @@ fn test_load_memory_overflow_circuit() { let textual_repr = r#" (module (memory $0 26) - (func (export "test") + (func (export "zkmain") (i32.const 0) (i64.load offset=1638400) (drop) @@ -100,21 +100,21 @@ fn test_load_memory_overflow_circuit() { ) "#; - assert!(test_circuit_noexternal(textual_repr).is_err()); + assert!(test_instruction(textual_repr).is_err()); } #[test] fn test_load_maximal_memory() { - // k18 support 21 pages at most. + // k18 support 10 pages at most. let textual_repr = r#" (module - (memory $0 21) - (func (export "test") + (memory $0 10) + (func (export "zkmain") (i32.const 0) - (i64.load offset=1376248) + (i64.load offset=655352) (drop) - (i32.const 1376248) + (i32.const 655352) (i64.load offset=0) (drop) @@ -125,5 +125,5 @@ fn test_load_maximal_memory() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_local_get.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_local_get.rs index 20b717386..a7075fac8 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_local_get.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_local_get.rs @@ -1,19 +1,18 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_local_get() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (local i32 i64) (local.get 0) (drop) (local.get 1) (drop) - ) ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_local_set.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_local_set.rs index 2f286af0c..1eb080a99 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_local_set.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_local_set.rs @@ -1,12 +1,12 @@ #[cfg(test)] mod tests { - use crate::test::test_circuit_noexternal; + use crate::test::test_instruction; #[test] fn test_local_set() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (local i32 i64) (i32.const 0) (local.set 0) @@ -16,6 +16,6 @@ mod tests { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_local_tee.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_local_tee.rs index d8d2ab10f..b34e201a9 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_local_tee.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_local_tee.rs @@ -1,10 +1,10 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_local_tee() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (local i32 i64) (i32.const 0) (local.tee 0) @@ -16,5 +16,5 @@ fn test_local_tee() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_memory_grow.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_memory_grow.rs index 1987cde9f..e2000d42a 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_memory_grow.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_memory_grow.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_memory_grow() { @@ -6,14 +6,14 @@ fn test_memory_grow() { (module (memory 1 2) - (func (export "test") + (func (export "zkmain") (memory.grow (i32.const 1)) (drop) ) ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } #[test] @@ -22,14 +22,14 @@ fn test_memory_grow_fail() { (module (memory 1 2) - (func (export "test") + (func (export "zkmain") (memory.grow (i32.const 2)) (drop) ) ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } #[test] @@ -38,7 +38,7 @@ fn test_memory_grow_lazy_init() { (module (memory 0 1) - (func (export "test") + (func (export "zkmain") (memory.grow (i32.const 1)) (drop) (i32.const 0) @@ -48,7 +48,7 @@ fn test_memory_grow_lazy_init() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } #[test] @@ -57,7 +57,7 @@ fn test_memory_grow_lazy_init_2() { (module (memory 1 2) - (func (export "test") + (func (export "zkmain") (memory.grow (i32.const 1)) (drop) (i32.const 65536) @@ -67,5 +67,5 @@ fn test_memory_grow_lazy_init_2() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_memory_size.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_memory_size.rs index 5b848a709..9852ffb05 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_memory_size.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_memory_size.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_memory_size() { @@ -6,12 +6,12 @@ fn test_memory_size() { (module (memory 2) - (func (export "test") + (func (export "zkmain") (memory.size) (drop) ) ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_rel.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_rel.rs index ffaa654d7..a5f9b5638 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_rel.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_rel.rs @@ -1,6 +1,6 @@ use std::vec; -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_op_rel() { @@ -28,7 +28,7 @@ fn test_op_rel() { let mut textual_repr = r#" (module - (func (export "test")"# + (func (export "zkmain")"# .to_owned(); for (t, values) in tys { @@ -50,5 +50,5 @@ fn test_op_rel() { } textual_repr = format!("{}))", textual_repr); - test_circuit_noexternal(&textual_repr).unwrap() + test_instruction(&textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_return.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_return.rs index 6fed7e0f6..c0a980af6 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_return.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_return.rs @@ -1,23 +1,23 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_trivial_return() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") return ) ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] fn test_return_with_drop_ok() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (block (i32.const 0) (i32.const 0) @@ -27,18 +27,18 @@ fn test_return_with_drop_ok() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] fn test_return_with_keep_ok() { let textual_repr = r#" (module - (func (export "test") (result i32) + (func (export "zkmain") (result i32) (i32.const 0) ) ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_select.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_select.rs index 766462088..2c3e78bbd 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_select.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_select.rs @@ -1,10 +1,10 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_select() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (i32.const 1) (i32.const 2) (i32.const 0) @@ -12,12 +12,12 @@ fn test_select() { drop (i64.const 1) (i64.const 2) - (i32.const 0) + (i32.const 1) select drop ) ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_store.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_store.rs index de09eb67f..fad7b3adb 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_store.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_store.rs @@ -1,4 +1,4 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_store_normal() { @@ -6,7 +6,7 @@ fn test_store_normal() { (module (memory $0 1) (data (i32.const 0) "\ff\00\00\00\fe\00\00\00") - (func (export "test") + (func (export "zkmain") (i32.const 0) (i64.const 0) (i64.store offset=0) @@ -45,7 +45,7 @@ fn test_store_normal() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] @@ -54,7 +54,7 @@ fn test_store_cross() { (module (memory $0 1) (data (i32.const 0) "\ff\00\00\00\fe\00\00\00") - (func (export "test") + (func (export "zkmain") (i32.const 6) (i64.const 32) (i64.store32 offset=0) @@ -78,22 +78,22 @@ fn test_store_cross() { ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } #[test] fn test_store_large_memory() { let textual_repr = r#" (module - (memory $0 20) + (memory $0 10) (data (i32.const 0) "\ff\00\00\00\fe\00\00\00") - (func (export "test") - (i32.const 7) + (func (export "zkmain") + (i32.const 0) (i32.const 16) - (i32.store16 offset=1010720) + (i32.store16 offset=655352) ) ) "#; - test_circuit_noexternal(textual_repr).unwrap(); + test_instruction(textual_repr).unwrap(); } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_test.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_test.rs index 1d635e32a..3911be908 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_test.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_test.rs @@ -1,10 +1,10 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] fn test_eqz() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (i32.const 0) (i32.eqz) (drop) @@ -24,5 +24,5 @@ fn test_eqz() { ) "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/crates/zkwasm/src/test/test_wasm_instructions/op_unary.rs b/crates/zkwasm/src/test/test_wasm_instructions/op_unary.rs index 343dd79e7..66ee42b54 100644 --- a/crates/zkwasm/src/test/test_wasm_instructions/op_unary.rs +++ b/crates/zkwasm/src/test/test_wasm_instructions/op_unary.rs @@ -1,10 +1,10 @@ -use crate::test::test_circuit_noexternal; +use crate::test::test_instruction; #[test] -fn test_ctz() { +fn test_unary() { let textual_repr = r#" (module - (func (export "test") + (func (export "zkmain") (i32.const 0x00100000) (i32.ctz) (drop) @@ -36,18 +36,7 @@ fn test_ctz() { (i64.const 0x0000000000000000) (i64.ctz) (drop) - ) - ) - "#; - - test_circuit_noexternal(textual_repr).unwrap() -} -#[test] -fn test_clz() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 0x00000001) (i32.clz) (drop) @@ -79,18 +68,7 @@ fn test_clz() { (i64.const 0xffffffffffffffff) (i64.clz) (drop) - ) - ) - "#; - test_circuit_noexternal(textual_repr).unwrap() -} - -#[test] -fn test_popcnt() { - let textual_repr = r#" - (module - (func (export "test") (i32.const 0x00000000) (i32.popcnt) (drop) @@ -106,9 +84,9 @@ fn test_popcnt() { (i64.const 0xffffffffffffffff) (i64.popcnt) (drop) - ) - ) - "#; + ) + ) + "#; - test_circuit_noexternal(textual_repr).unwrap() + test_instruction(textual_repr).unwrap() } diff --git a/third-party/wasmi b/third-party/wasmi index 2dc8a321b..efa82b3a5 160000 --- a/third-party/wasmi +++ b/third-party/wasmi @@ -1 +1 @@ -Subproject commit 2dc8a321b2f560e82abcb2325666fa993873c357 +Subproject commit efa82b3a5484faadbe0661f623eb34c54f8cf1f3