From 157cf796b1ae3b054449842dc825afaa7db67ac0 Mon Sep 17 00:00:00 2001 From: Junyu <83873214+junyu0312@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:01:33 +0800 Subject: [PATCH] chore: extract initialization state (#198) * feat: preparation for continuation * fix comments --- Cargo.lock | 1 + crates/cli/Cargo.toml | 3 +- crates/specs/Cargo.toml | 3 +- crates/specs/src/encode/init_memory_table.rs | 12 +- crates/specs/src/imtable.rs | 174 +++++----- crates/specs/src/itable.rs | 16 +- crates/specs/src/lib.rs | 45 ++- crates/specs/src/mtable.rs | 7 - crates/specs/src/state.rs | 90 ++++++ crates/zkwasm/Cargo.toml | 2 + crates/zkwasm/src/circuits/cell.rs | 59 +--- .../zkwasm/src/circuits/etable/allocator.rs | 40 ++- crates/zkwasm/src/circuits/etable/assign.rs | 306 +++++++++++------- crates/zkwasm/src/circuits/etable/mod.rs | 27 +- .../circuits/etable/op_configure/op_call.rs | 2 +- .../etable/op_configure/op_call_indirect.rs | 2 +- .../zkwasm/src/circuits/image_table/assign.rs | 66 +++- crates/zkwasm/src/circuits/image_table/mod.rs | 35 +- crates/zkwasm/src/circuits/jtable/assign.rs | 2 - crates/zkwasm/src/circuits/mod.rs | 1 - .../zkwasm/src/circuits/mtable/allocator.rs | 71 +++- crates/zkwasm/src/circuits/mtable/assign.rs | 49 ++- crates/zkwasm/src/circuits/mtable/mod.rs | 39 +-- .../zkwasm/src/circuits/test_circuit/mod.rs | 129 ++++---- crates/zkwasm/src/circuits/utils/mod.rs | 1 + .../zkwasm/src/circuits/utils/table_entry.rs | 2 +- .../src/circuits/utils/u32_state/mod.rs | 11 + crates/zkwasm/src/loader/mod.rs | 15 +- .../zkwasm/src/profile/instruction_merge.rs | 8 +- .../src/profile/instruction_statistic.rs | 6 +- crates/zkwasm/src/runtime/mod.rs | 109 +------ crates/zkwasm/src/runtime/state.rs | 200 ++++++++++++ .../zkwasm/src/runtime/wasmi_interpreter.rs | 58 +++- .../zkwasm/src/test/test_uniform_verifier.rs | 2 - third-party/wasmi | 2 +- 35 files changed, 979 insertions(+), 616 deletions(-) create mode 100644 crates/specs/src/state.rs create mode 100644 crates/zkwasm/src/circuits/utils/u32_state/mod.rs create mode 100644 crates/zkwasm/src/runtime/state.rs diff --git a/Cargo.lock b/Cargo.lock index fc6415f3a..71bd7c78b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,6 +424,7 @@ dependencies = [ "anyhow", "ark-std", "bitvec", + "cfg-if 1.0.0", "downcast-rs", "halo2_proofs", "halo2aggregator-s", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 474274cbe..7a8dc9e96 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -25,4 +25,5 @@ wasmi.workspace = true [features] default = [] -cuda = ["delphinus-zkwasm/cuda"] \ No newline at end of file +cuda = ["delphinus-zkwasm/cuda"] +continuation = ["delphinus-zkwasm/continuation", "specs/continuation"] \ No newline at end of file diff --git a/crates/specs/Cargo.toml b/crates/specs/Cargo.toml index 3ffeaf68a..578478fc8 100644 --- a/crates/specs/Cargo.toml +++ b/crates/specs/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] lazy_static = "1.4.0" num-bigint = { version = "0.4", features = ["rand"] } -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" strum = "0.24.1" strum_macros = "0.24.1" @@ -19,3 +19,4 @@ rayon.workspace = true [features] default = [] cuda = ["halo2_proofs/cuda"] +continuation = [] \ No newline at end of file diff --git a/crates/specs/src/encode/init_memory_table.rs b/crates/specs/src/encode/init_memory_table.rs index f5d930a34..949c2e2ff 100644 --- a/crates/specs/src/encode/init_memory_table.rs +++ b/crates/specs/src/encode/init_memory_table.rs @@ -12,20 +12,23 @@ pub fn encode_init_memory_table_entry( is_mutable: T, start_offset: T, end_offset: T, + eid: T, value: T, ) -> T { - const LTYPE_SHIFT: u32 = IS_MUTABLE_SHIFT + COMMON_RANGE_OFFSET; + const LTYPE_SHIFT: u32 = IS_MUTABLE_SHIFT + 1; const IS_MUTABLE_SHIFT: u32 = START_OFFSET_SHIFT + COMMON_RANGE_OFFSET; - const START_OFFSET_SHIFT: u32 = END_OFFSET_SHIFT + 64; - const END_OFFSET_SHIFT: u32 = VALUE_SHIFT + 64; + const START_OFFSET_SHIFT: u32 = END_OFFSET_SHIFT + COMMON_RANGE_OFFSET; + const END_OFFSET_SHIFT: u32 = EID_OFFSET_SHIFT + 32; + const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + 64; const VALUE_SHIFT: u32 = 0; - assert!(LTYPE_SHIFT + COMMON_RANGE_OFFSET <= INIT_MEMORY_ENCODE_BOUNDARY); + assert!(LTYPE_SHIFT + 8 <= INIT_MEMORY_ENCODE_BOUNDARY); ltype * T::from_bn(&(1u64.to_biguint().unwrap() << LTYPE_SHIFT)) + is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) + start_offset * T::from_bn(&(1u64.to_biguint().unwrap() << START_OFFSET_SHIFT)) + end_offset * T::from_bn(&(1u64.to_biguint().unwrap() << END_OFFSET_SHIFT)) + + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) + value } @@ -36,6 +39,7 @@ impl InitMemoryTableEntry { BigUint::from(self.is_mutable as u32), BigUint::from(self.start_offset), BigUint::from(self.end_offset), + BigUint::from(self.eid), self.value.to_biguint().unwrap(), ) } diff --git a/crates/specs/src/imtable.rs b/crates/specs/src/imtable.rs index 8e7081279..bc7b6a9eb 100644 --- a/crates/specs/src/imtable.rs +++ b/crates/specs/src/imtable.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering; +use std::collections::BTreeMap; use crate::mtable::LocationType; use crate::mtable::VarType; @@ -13,53 +14,97 @@ pub struct InitMemoryTableEntry { pub vtype: VarType, /// convert from [u8; 8] via u64::from_le_bytes pub value: u64, + pub eid: u32, } #[derive(Serialize, Default, Debug, Clone)] pub struct InitMemoryTable { entries: Vec, - sorted_global_init_entries: Vec, + sorted_global_init_entries: BTreeMap, + sorted_stack_init_entries: BTreeMap, sorted_heap_init_entries: Vec, } impl InitMemoryTable { - pub fn new(entries: Vec, k: u32) -> Self { - let mut imtable = Self { - entries: entries - .into_iter() - .map(|entry| InitMemoryTableEntry { - ltype: entry.ltype, - is_mutable: entry.is_mutable, - start_offset: entry.start_offset, - end_offset: if entry.end_offset == u32::MAX { - (1u32 << (k - 1)) - 1 + pub fn new(mut entries: Vec) -> Self { + fn sort(entries: &mut Vec) { + entries.sort_by_key(|item| (item.ltype, item.start_offset)); + } + + fn merge(entries: Vec) -> Vec { + let mut merged_entries: Vec<_> = entries + .iter() + .filter(|entry| entry.ltype != LocationType::Heap) + .map(|entry| entry.clone()) + .collect(); + + let heap_initial: Vec<_> = entries + .iter() + .filter(|entry| entry.ltype == LocationType::Heap) + .collect(); + + if !heap_initial.is_empty() { + let mut scan = 0; + let mut cursor = scan + 1; + while scan < heap_initial.len() && cursor < heap_initial.len() { + if heap_initial[scan].value == heap_initial[cursor].value + && heap_initial[scan].eid == heap_initial[cursor].eid + { + cursor += 1; } else { - entry.end_offset - }, - vtype: entry.vtype, - value: entry.value, - }) - .collect(), - sorted_global_init_entries: vec![], - sorted_heap_init_entries: vec![], - }; - imtable.sort(); - imtable.merge(); - - imtable.sorted_heap_init_entries = imtable - .entries + merged_entries.push(InitMemoryTableEntry { + ltype: LocationType::Heap, + is_mutable: true, + start_offset: heap_initial[scan].start_offset, + end_offset: heap_initial[cursor - 1].end_offset, + vtype: VarType::I64, + value: heap_initial[scan].value, + eid: heap_initial[scan].eid, + }); + + scan = cursor; + cursor = scan + 1; + } + } + merged_entries.push(InitMemoryTableEntry { + ltype: LocationType::Heap, + is_mutable: true, + start_offset: heap_initial[scan].start_offset, + end_offset: heap_initial[cursor - 1].end_offset, + vtype: VarType::I64, + value: heap_initial[scan].value, + eid: heap_initial[scan].eid, + }); + } + + merged_entries + } + + sort(&mut entries); + let entries = merge(entries); + + let sorted_heap_init_entries = entries .iter() .filter(|entry| entry.ltype == LocationType::Heap) .map(|entry| entry.clone()) .collect(); - imtable.sorted_global_init_entries = imtable - .entries + let sorted_global_init_entries = entries .iter() .filter(|entry| entry.ltype == LocationType::Global) - .map(|entry| entry.clone()) + .map(|entry| (entry.start_offset, entry.clone())) + .collect(); + let sorted_stack_init_entries = entries + .iter() + .filter(|entry| entry.ltype == LocationType::Stack) + .map(|entry| (entry.start_offset, entry.clone())) .collect(); - imtable + InitMemoryTable { + entries, + sorted_global_init_entries, + sorted_stack_init_entries, + sorted_heap_init_entries, + } } pub fn entries(&self) -> &Vec { @@ -70,7 +115,7 @@ impl InitMemoryTable { serde_json::to_string(&self.entries).unwrap() } - pub fn try_find(&self, ltype: LocationType, offset: u32) -> Option<(u32, u32, u64)> { + pub fn try_find(&self, ltype: LocationType, offset: u32) -> Option<(u32, u32, u32, u64)> { match ltype { LocationType::Heap => { let idx = self @@ -89,72 +134,23 @@ impl InitMemoryTable { return Some(( self.sorted_heap_init_entries[idx].start_offset, self.sorted_heap_init_entries[idx].end_offset, + self.sorted_heap_init_entries[idx].eid, self.sorted_heap_init_entries[idx].value, )); } LocationType::Global => { - for entry in self.sorted_global_init_entries.iter() { - if entry.start_offset == offset { - return Some((offset, offset, entry.value)); - } - } + return self + .sorted_global_init_entries + .get(&offset) + .map(|entry| (entry.start_offset, entry.end_offset, entry.eid, entry.value)); } - LocationType::Stack => unreachable!(), - } - - None - } - - fn sort(&mut self) { - self.entries - .sort_by_key(|item| (item.ltype, item.start_offset)) - } - - fn merge(&mut self) { - let mut merged_entries: Vec<_> = self - .entries() - .iter() - .filter(|entry| entry.ltype == LocationType::Global) - .map(|entry| entry.clone()) - .collect(); - - let heap_initial: Vec<_> = self - .entries() - .iter() - .filter(|entry| entry.ltype == LocationType::Heap) - .collect(); - - if !heap_initial.is_empty() { - let mut scan = 0; - let mut cursor = scan + 1; - while scan < heap_initial.len() && cursor < heap_initial.len() { - if heap_initial[scan].value == heap_initial[cursor].value { - cursor += 1; - } else { - merged_entries.push(InitMemoryTableEntry { - ltype: LocationType::Heap, - is_mutable: true, - start_offset: heap_initial[scan].start_offset, - end_offset: heap_initial[cursor - 1].end_offset, - vtype: VarType::I64, - value: heap_initial[scan].value, - }); - - scan = cursor; - cursor = scan + 1; - } + LocationType::Stack => { + return self + .sorted_stack_init_entries + .get(&offset) + .map(|entry| (entry.start_offset, entry.end_offset, entry.eid, entry.value)); } - merged_entries.push(InitMemoryTableEntry { - ltype: LocationType::Heap, - is_mutable: true, - start_offset: heap_initial[scan].start_offset, - end_offset: heap_initial[cursor - 1].end_offset, - vtype: VarType::I64, - value: heap_initial[scan].value, - }); } - - self.entries = merged_entries; } pub fn filter(&self, ltype: LocationType) -> Vec<&InitMemoryTableEntry> { diff --git a/crates/specs/src/itable.rs b/crates/specs/src/itable.rs index 3e7cc9ec4..e24a2214a 100644 --- a/crates/specs/src/itable.rs +++ b/crates/specs/src/itable.rs @@ -296,12 +296,12 @@ pub enum Opcode { impl Opcode { pub fn mops(&self) -> u64 { - let opcode_class: OpcodeClass = self.clone().into(); + let opcode_class: OpcodeClass = self.into(); opcode_class.mops() } pub fn jops(&self) -> u64 { - let opcode_class: OpcodeClass = self.clone().into(); + let opcode_class: OpcodeClass = self.into(); opcode_class.jops() } @@ -414,7 +414,7 @@ impl Into for Opcode { Opcode::InternalHostCall { op_index_in_plugin, .. } => { - let opcode_class_plain: OpcodeClassPlain = self.into(); + let opcode_class_plain: OpcodeClassPlain = (&self).into(); (BigUint::from(opcode_class_plain.0) << OPCODE_CLASS_SHIFT) + (BigUint::from(op_index_in_plugin as u64)) @@ -537,7 +537,7 @@ impl Into for Opcode { } } -impl Into for Opcode { +impl Into for &Opcode { fn into(self) -> OpcodeClass { match self { Opcode::LocalGet { .. } => OpcodeClass::LocalGet, @@ -573,12 +573,12 @@ impl Into for Opcode { } } -impl Into for Opcode { +impl Into for &Opcode { fn into(self) -> OpcodeClassPlain { - let class: OpcodeClass = self.clone().into(); + let class: OpcodeClass = self.into(); if let Opcode::InternalHostCall { plugin, .. } = self { - OpcodeClassPlain(class as usize + plugin as usize) + OpcodeClassPlain(class as usize + (*plugin) as usize) } else { OpcodeClassPlain(class as usize) } @@ -645,7 +645,7 @@ impl InstructionTable { let mut opcodeclass: HashSet = HashSet::new(); self.entries().iter().for_each(|entry| { - opcodeclass.insert(entry.opcode.clone().into()); + opcodeclass.insert((&entry.opcode).into()); }); opcodeclass diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index e18ccf3e5..bbc65227a 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -6,6 +6,7 @@ use std::collections::HashSet; use std::env; use std::io::Write; use std::path::PathBuf; +use std::sync::Arc; use brtable::ElemTable; use configure_table::ConfigureTable; @@ -16,12 +17,12 @@ use itable::InstructionTable; use jtable::JumpTable; use jtable::StaticFrameEntry; use mtable::AccessType; -use mtable::LocationType; use mtable::MTable; use mtable::MemoryTableEntry; use rayon::prelude::IntoParallelRefIterator; use rayon::prelude::ParallelIterator; use serde::Serialize; +use state::InitializationState; #[macro_use] extern crate lazy_static; @@ -36,59 +37,53 @@ pub mod imtable; pub mod itable; pub mod jtable; pub mod mtable; +pub mod state; pub mod step; pub mod types; #[derive(Default, Serialize, Debug, Clone)] pub struct CompilationTable { - pub itable: InstructionTable, + pub itable: Arc, pub imtable: InitMemoryTable, - pub elem_table: ElemTable, - pub configure_table: ConfigureTable, - pub static_jtable: Vec, - pub fid_of_entry: u32, + pub elem_table: Arc, + pub configure_table: Arc, + pub static_jtable: Arc>, + pub initialization_state: InitializationState, } #[derive(Default, Serialize, Clone)] pub struct ExecutionTable { pub etable: EventTable, - pub jtable: JumpTable, + pub jtable: Arc, } #[derive(Default, Clone)] pub struct Tables { pub compilation_tables: CompilationTable, pub execution_tables: ExecutionTable, + pub post_image_table: CompilationTable, } impl Tables { pub fn create_memory_table( &self, - memory_event_of_step: fn(&EventTableEntry, &mut u32) -> Vec, + memory_event_of_step: fn(&EventTableEntry) -> Vec, ) -> MTable { let mut memory_entries = self .execution_tables .etable .entries() .par_iter() - .map(|entry| memory_event_of_step(entry, &mut 1)) + .map(|entry| memory_event_of_step(entry)) .collect::>>() .concat(); let init_value = memory_entries .par_iter() .map(|entry| { - if entry.ltype == LocationType::Heap || entry.ltype == LocationType::Global { - let (_, _, value) = self - .compilation_tables - .imtable - .try_find(entry.ltype, entry.offset) - .unwrap(); - - Some(value) - } else { - None - } + self.compilation_tables + .imtable + .try_find(entry.ltype, entry.offset) }) .collect::>(); @@ -97,12 +92,10 @@ impl Tables { memory_entries .iter() .zip(init_value.into_iter()) - .for_each(|(entry, init_value)| { - // If it's heap or global - if let Some(value) = init_value { + .for_each(|(entry, init_memory_entry)| { + if let Some((_, _, eid, value)) = init_memory_entry { set.insert(MemoryTableEntry { - eid: 0, - emid: 0, + eid, offset: entry.offset, ltype: entry.ltype, atype: AccessType::Init, @@ -115,7 +108,7 @@ impl Tables { memory_entries.append(&mut set.into_iter().collect()); - memory_entries.sort_by_key(|item| (item.ltype, item.offset, item.eid, item.emid)); + memory_entries.sort_by_key(|item| (item.ltype, item.offset, item.eid)); MTable::new(memory_entries) } diff --git a/crates/specs/src/mtable.rs b/crates/specs/src/mtable.rs index 07ce40950..904ade899 100644 --- a/crates/specs/src/mtable.rs +++ b/crates/specs/src/mtable.rs @@ -112,13 +112,6 @@ impl MemoryReadSize { #[derive(Clone, Debug, Serialize, Hash, Eq, PartialEq)] pub struct MemoryTableEntry { pub eid: u32, - /* - Emid is sub memory op id of eid. - E.g. an opcode gets a value from stack top and changes it. - This event has two memory ops on the same memory address, - So we need emid to seq the r/w op, which is an incremental value starting from 1. - */ - pub emid: u32, pub offset: u32, pub ltype: LocationType, pub atype: AccessType, diff --git a/crates/specs/src/state.rs b/crates/specs/src/state.rs new file mode 100644 index 000000000..a64c67559 --- /dev/null +++ b/crates/specs/src/state.rs @@ -0,0 +1,90 @@ +use serde::Serialize; + +#[derive(Clone, Debug, Serialize)] +pub struct InitializationState { + pub eid: T, + pub fid: T, + pub iid: T, + pub frame_id: T, + pub sp: T, + + pub host_public_inputs: T, + pub context_in_index: T, + pub context_out_index: T, + pub external_host_call_call_index: T, + + pub initial_memory_pages: T, + pub maximal_memory_pages: T, + + #[cfg(feature = "continuation")] + pub jops: T, +} + +impl Default for InitializationState { + fn default() -> Self { + Self { + eid: Default::default(), + fid: Default::default(), + iid: Default::default(), + frame_id: Default::default(), + sp: Default::default(), + + host_public_inputs: Default::default(), + context_in_index: Default::default(), + context_out_index: Default::default(), + external_host_call_call_index: Default::default(), + + initial_memory_pages: Default::default(), + maximal_memory_pages: Default::default(), + + #[cfg(feature = "continuation")] + jops: Default::default(), + } + } +} + +impl InitializationState { + pub fn plain(&self) -> Vec { + let mut v = vec![]; + + v.push(self.eid.clone()); + v.push(self.fid.clone()); + v.push(self.iid.clone()); + v.push(self.frame_id.clone()); + v.push(self.sp.clone()); + + v.push(self.host_public_inputs.clone()); + v.push(self.context_in_index.clone()); + v.push(self.context_out_index.clone()); + v.push(self.external_host_call_call_index.clone()); + + v.push(self.initial_memory_pages.clone()); + v.push(self.maximal_memory_pages.clone()); + + #[cfg(feature = "continuation")] + v.push(self.jops.clone()); + + v + } + + pub fn map(&self, f: impl Fn(&T) -> U) -> InitializationState { + InitializationState { + eid: f(&self.eid), + fid: f(&self.fid), + iid: f(&self.iid), + frame_id: f(&self.frame_id), + sp: f(&self.sp), + + host_public_inputs: f(&self.host_public_inputs), + context_in_index: f(&self.context_in_index), + context_out_index: f(&self.context_out_index), + external_host_call_call_index: f(&self.external_host_call_call_index), + + initial_memory_pages: f(&self.initial_memory_pages), + maximal_memory_pages: f(&self.maximal_memory_pages), + + #[cfg(feature = "continuation")] + jops: f(&self.jops), + } + } +} diff --git a/crates/zkwasm/Cargo.toml b/crates/zkwasm/Cargo.toml index 4e95923d4..e98e2c54a 100644 --- a/crates/zkwasm/Cargo.toml +++ b/crates/zkwasm/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } bitvec = "1.0.1" +cfg-if = "1.0.0" downcast-rs = "1.2.0" hex = "0.4.3" log = "0.4.17" @@ -34,3 +35,4 @@ rusty-fork = "0.3.0" [features] default = [] cuda = ["halo2_proofs/cuda", "specs/cuda"] +continuation = ["specs/continuation"] \ No newline at end of file diff --git a/crates/zkwasm/src/circuits/cell.rs b/crates/zkwasm/src/circuits/cell.rs index b2070166f..c88a4eeb2 100644 --- a/crates/zkwasm/src/circuits/cell.rs +++ b/crates/zkwasm/src/circuits/cell.rs @@ -48,11 +48,6 @@ pub(crate) trait CellExpression { ) -> Result, Error> { self.assign(ctx, if value { F::one() } else { F::zero() }) } - fn assign_constant( - &self, - ctx: &mut Context<'_, F>, - value: F, - ) -> Result, Error>; } impl CellExpression for AllocatedCell { @@ -68,19 +63,6 @@ impl CellExpression for AllocatedCell { || Ok(value), ) } - - fn assign_constant( - &self, - ctx: &mut Context<'_, F>, - value: F, - ) -> Result, Error> { - ctx.region.assign_advice_from_constant( - || "assign cell", - self.col, - (ctx.offset as i32 + self.rot) as usize, - value, - ) - } } #[derive(Debug, Clone, Copy)] @@ -101,12 +83,6 @@ pub(crate) struct AllocatedU32Cell { pub(crate) u32_cell: AllocatedUnlimitedCell, } -impl AllocatedU32Cell { - pub(crate) fn expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - self.u32_cell.expr(meta) - } -} - #[derive(Debug, Clone, Copy)] pub(crate) struct AllocatedU64CellWithFlagBitDyn { pub(crate) u16_cells_le: [AllocatedU16Cell; 4], @@ -149,21 +125,6 @@ macro_rules! define_cell { self.0.assign(ctx, value) } - - fn assign_constant( - &self, - ctx: &mut Context<'_, F>, - value: F, - ) -> Result, Error> { - assert!( - value <= $limit, - "assigned value {:?} exceeds the limit {:?}", - value, - $limit - ); - - self.0.assign_constant(ctx, value) - } } }; } @@ -178,25 +139,23 @@ define_cell!(AllocatedU16Cell, F::from(u16::MAX as u64)); define_cell!(AllocatedUnlimitedCell, -F::one()); impl AllocatedU32Cell { - pub(crate) fn assign(&self, ctx: &mut Context<'_, F>, value: u32) -> Result<(), Error> { - for i in 0..2 { - self.u16_cells_le[i].assign(ctx, (((value >> (i * 16)) & 0xffffu32) as u64).into())?; - } - self.u32_cell.assign(ctx, (value as u64).into())?; - Ok(()) + pub(crate) fn expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + self.u32_cell.curr_expr(meta) + } + + pub(crate) fn curr_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + self.expr(meta) } - pub(crate) fn assign_constant( + pub(crate) fn assign( &self, ctx: &mut Context<'_, F>, value: u32, - ) -> Result<(), Error> { + ) -> Result, Error> { for i in 0..2 { self.u16_cells_le[i].assign(ctx, (((value >> (i * 16)) & 0xffffu32) as u64).into())?; } - - self.u32_cell.assign_constant(ctx, (value as u64).into())?; - Ok(()) + self.u32_cell.assign(ctx, (value as u64).into()) } } diff --git a/crates/zkwasm/src/circuits/etable/allocator.rs b/crates/zkwasm/src/circuits/etable/allocator.rs index 66f0d7a22..aad01b045 100644 --- a/crates/zkwasm/src/circuits/etable/allocator.rs +++ b/crates/zkwasm/src/circuits/etable/allocator.rs @@ -8,6 +8,7 @@ use crate::circuits::traits::ConfigureLookupTable; use crate::circuits::utils::bit::BitColumn; use crate::circuits::utils::common_range::CommonRangeColumn; use crate::circuits::utils::u16::U16Column; +use crate::circuits::utils::u32_state::AllocatedU32StateCell; use crate::circuits::utils::u8::U8Column; use crate::circuits::Context; use crate::circuits::Lookup; @@ -64,6 +65,24 @@ impl_cell!(AllocatedU16Cell); impl_cell!(AllocatedUnlimitedCell); impl_cell!(AllocatedJumpTableLookupCell); +impl EventTableCellExpression for AllocatedU32Cell { + fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + nextn!( + meta, + self.u32_cell.0.col, + self.u32_cell.0.rot + EVENT_TABLE_ENTRY_ROWS as i32 + ) + } + + fn prev_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + nextn!( + meta, + self.u32_cell.0.col, + self.u32_cell.0.rot - EVENT_TABLE_ENTRY_ROWS as i32 + ) + } +} + #[derive(Debug, Clone, Copy)] pub(crate) struct AllocatedJumpTableLookupCell(pub(crate) AllocatedCell); @@ -231,6 +250,8 @@ impl EventTableCellAllocator { * enable(meta), ] }); + meta.enable_equality(u32_cell.0.col); + AllocatedU32Cell { u16_cells_le, u32_cell, @@ -430,6 +451,16 @@ impl EventTableCellAllocator { AllocatedCommonRangeCell(self.alloc(&EventTableCellType::CommonRange)) } + pub(crate) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + self.alloc_u32_cell() + } else { + self.alloc_common_range_cell() + } + } + } + pub(crate) fn alloc_u8_cell(&mut self) -> AllocatedU8Cell { AllocatedU8Cell(self.alloc(&EventTableCellType::U8)) } @@ -450,7 +481,7 @@ impl EventTableCellAllocator { &mut self, name: &'static str, constraint_builder: &mut ConstraintBuilder, - eid: AllocatedU32Cell, + eid: AllocatedU32StateCell, location_type: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, offset: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, is_i32: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, @@ -500,7 +531,7 @@ impl EventTableCellAllocator { &mut self, name: &'static str, constraint_builder: &mut ConstraintBuilder, - eid: AllocatedU32Cell, + eid: AllocatedU32StateCell, location_type: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, offset: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, is_i32: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, @@ -541,7 +572,7 @@ impl EventTableCellAllocator { &mut self, name: &'static str, constraint_builder: &mut ConstraintBuilder, - eid: AllocatedU32Cell, + eid: AllocatedU32StateCell, location_type: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, offset: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, is_i32: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, @@ -589,7 +620,7 @@ impl EventTableCellAllocator { &mut self, name: &'static str, constraint_builder: &mut ConstraintBuilder, - eid: AllocatedU32Cell, + eid: AllocatedU32StateCell, location_type: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, offset: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, is_i32: impl Fn(&mut VirtualCells<'_, F>) -> Expression + 'static, @@ -624,6 +655,7 @@ impl EventTableCellAllocator { cell } + #[allow(dead_code)] pub(crate) fn alloc_u32_cell(&mut self) -> AllocatedU32Cell { self.free_u32_cells.pop().expect("no more free u32 cells") } diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index 9254ea762..0904445d1 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -5,9 +5,9 @@ use log::debug; use specs::configure_table::ConfigureTable; use specs::itable::Opcode; use specs::itable::OpcodeClassPlain; +use specs::state::InitializationState; use std::collections::BTreeMap; use std::rc::Rc; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use super::EventTableChip; use super::EventTableOpcodeConfig; @@ -21,10 +21,10 @@ use crate::circuits::utils::Context; pub(in crate::circuits) struct EventTablePermutationCells { pub(in crate::circuits) rest_mops: Option, + pub(in crate::circuits) pre_initialization_state: InitializationState, pub(in crate::circuits) rest_jops: Option, - pub(in crate::circuits) fid_of_entry: Cell, - pub(in crate::circuits) initial_memory_pages: Cell, - pub(in crate::circuits) maximal_memory_pages: Cell, + // TODO + // pub(in crate::circuits) post_initialization_state: InitializationState, } impl EventTableChip { @@ -32,31 +32,31 @@ impl EventTableChip { &self, op_configs: &BTreeMap>>>, event_table: &EventTableWithMemoryInfo, - ) -> Vec<(u32, u32)> { - let mut rest_ops = vec![]; - - event_table - .0 - .iter() - .rev() - .fold((0, 0), |(rest_mops_sum, rest_jops_sum), entry| { - let op_config = op_configs - .get(&entry.eentry.inst.opcode.clone().into()) - .unwrap(); - - let acc = ( - rest_mops_sum + op_config.memory_writing_ops(&entry.eentry), - rest_jops_sum + op_config.jops(), - ); - - rest_ops.push(acc); - - acc - }); - - rest_ops.reverse(); - - rest_ops + #[cfg(feature = "continuation")] initialization_state: &InitializationState, + ) -> (u32, u32) { + let (rest_mops, _rest_jops) = + event_table + .0 + .iter() + .rev() + .fold((0, 0), |(rest_mops_sum, rest_jops_sum), entry| { + let op_config = op_configs + .get(&((&entry.eentry.inst.opcode).into())) + .unwrap(); + + ( + rest_mops_sum + op_config.memory_writing_ops(&entry.eentry), + rest_jops_sum + op_config.jops(), + ) + }); + + cfg_if::cfg_if! { + if #[cfg(feature="continuation")] { + (rest_mops, initialization_state.jops) + } else { + (rest_mops, _rest_jops) + } + } } fn init(&self, ctx: &mut Context<'_, F>) -> Result<(), Error> { @@ -80,9 +80,10 @@ impl EventTableChip { F::zero(), )?; + #[cfg(not(feature = "continuation"))] ctx.region.assign_advice_from_constant( || "etable: rest jops terminates", - self.config.common_config.rest_jops_cell.0.col, + self.config.common_config.jops_cell.0.col, ctx.offset, F::zero(), )?; @@ -90,25 +91,99 @@ impl EventTableChip { Ok(()) } - fn assign_rest_ops_first_step( - &self, - ctx: &mut Context<'_, F>, - rest_mops: u32, - rest_jops: u32, - ) -> Result<(Cell, Cell), Error> { + // Get the cell to permutation, the meaningless value should be overwritten. + fn assign_rest_ops_first_step(&self, ctx: &mut Context<'_, F>) -> Result<(Cell, Cell), Error> { let rest_mops_cell = self .config .common_config .rest_mops_cell - .assign(ctx, F::from(rest_mops as u64))?; + .assign(ctx, F::zero())?; - let rest_mops_jell = self - .config - .common_config - .rest_jops_cell - .assign(ctx, F::from(rest_jops as u64))?; + let rest_jops_cell = self.config.common_config.jops_cell.assign(ctx, F::zero())?; - Ok((rest_mops_cell.cell(), rest_mops_jell.cell())) + Ok((rest_mops_cell.cell(), rest_jops_cell.cell())) + } + + fn assign_initialization_state( + &self, + ctx: &mut Context<'_, F>, + initialization_state: &InitializationState, + ) -> Result, Error> { + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + self.config.common_config.$cell.assign(ctx, $value)?.cell() + } + } + } else { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + assign_common_range_advice!($cell, $value) + } + } + } + } + + macro_rules! assign_common_range_advice { + ($cell:ident, $value:expr) => { + self.config + .common_config + .$cell + .assign(ctx, F::from($value as u64))? + .cell() + }; + } + + let eid = assign_u32_state!(eid_cell, initialization_state.eid); + let fid = assign_common_range_advice!(fid_cell, initialization_state.fid); + let iid = assign_common_range_advice!(iid_cell, initialization_state.iid); + let sp = assign_common_range_advice!(sp_cell, initialization_state.sp); + let frame_id = assign_u32_state!(frame_id_cell, initialization_state.frame_id); + + let host_public_inputs = + assign_common_range_advice!(input_index_cell, initialization_state.host_public_inputs); + let context_in_index = assign_common_range_advice!( + context_input_index_cell, + initialization_state.context_in_index + ); + let context_out_index = assign_common_range_advice!( + context_output_index_cell, + initialization_state.context_out_index + ); + let external_host_call_call_index = assign_common_range_advice!( + external_host_call_index_cell, + initialization_state.external_host_call_call_index + ); + + let initial_memory_pages = + assign_common_range_advice!(mpages_cell, initialization_state.initial_memory_pages); + let maximal_memory_pages = assign_common_range_advice!( + maximal_memory_pages_cell, + initialization_state.maximal_memory_pages + ); + + #[cfg(feature = "continuation")] + let jops = assign_common_range_advice!(jops_cell, initialization_state.jops); + + Ok(InitializationState { + eid, + fid, + iid, + frame_id, + sp, + + host_public_inputs, + context_in_index, + context_out_index, + external_host_call_call_index, + + initial_memory_pages, + maximal_memory_pages, + + #[cfg(feature = "continuation")] + jops, + }) } fn assign_entries( @@ -117,9 +192,10 @@ impl EventTableChip { op_configs: &BTreeMap>>>, event_table: &EventTableWithMemoryInfo, configure_table: &ConfigureTable, - fid_of_entry: u32, - rest_ops: Vec<(u32, u32)>, - ) -> Result<(Cell, Cell, Cell), Error> { + initialization_state: &InitializationState, + mut rest_mops: u32, + mut jops: u32, + ) -> Result<(), Error> { macro_rules! assign_advice { ($cell:ident, $value:expr) => { self.config.common_config.$cell.assign(ctx, $value)? @@ -132,40 +208,26 @@ impl EventTableChip { }; } - macro_rules! assign_constant { - ($cell:ident, $value:expr) => { - self.config - .common_config - .$cell - .assign_constant(ctx, $value)? - }; - } - - let mut host_public_inputs = 1u32; - let mut context_in_index = 1u32; - let mut context_out_index = 1u32; - let mut external_host_call_call_index = 1u32; - - assign_constant!(input_index_cell, F::from(host_public_inputs as u64)); - assign_constant!(context_input_index_cell, F::from(context_in_index as u64)); - assign_constant!(context_output_index_cell, F::from(context_out_index as u64)); - assign_constant!( - external_host_call_index_cell, - F::from(external_host_call_call_index as u64) - ); - let initial_memory_pages_cell = assign_advice!( - mpages_cell, - F::from(configure_table.init_memory_pages as u64) - ); - let maximal_memory_pages_cell = assign_advice!( - maximal_memory_pages_cell, - F::from(configure_table.maximal_memory_pages as u64) + cfg_if::cfg_if!( + if #[cfg(feature = "continuation")] { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + self.config.common_config.$cell.assign(ctx, $value)? + }; + } + } else { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + assign_advice!($cell, F::from($value as u64)) + }; + } + } ); - assign_constant!(sp_cell, F::from(DEFAULT_VALUE_STACK_LIMIT as u64 - 1)); - assign_constant!(frame_id_cell, F::zero()); - assign_constant!(eid_cell, 1); - let fid_of_entry_cell = assign_advice!(fid_cell, F::from(fid_of_entry as u64)); - assign_constant!(iid_cell, F::zero()); + + let mut host_public_inputs = initialization_state.host_public_inputs; + let mut context_in_index = initialization_state.context_in_index; + let mut context_out_index = initialization_state.context_out_index; + let mut external_host_call_call_index = initialization_state.external_host_call_call_index; /* * Skip subsequent advice assignment in the first pass to enhance performance. @@ -173,11 +235,7 @@ impl EventTableChip { { let assigned_cell = assign_advice!(enabled_cell, F::zero()); if assigned_cell.value().is_none() { - return Ok(( - fid_of_entry_cell.cell(), - initial_memory_pages_cell.cell(), - maximal_memory_pages_cell.cell(), - )); + return Ok(()); } } @@ -185,11 +243,7 @@ impl EventTableChip { * The length of event_table equals 0: without_witness */ if event_table.0.len() == 0 { - return Ok(( - fid_of_entry_cell.cell(), - initial_memory_pages_cell.cell(), - maximal_memory_pages_cell.cell(), - )); + return Ok(()); } let status = { @@ -227,9 +281,7 @@ impl EventTableChip { status }; - for (index, (entry, (rest_mops, rest_jops))) in - event_table.0.iter().zip(rest_ops.iter()).enumerate() - { + for (index, entry) in event_table.0.iter().enumerate() { let step_status = StepStatus { current: &status[index], next: &status[index + 1], @@ -241,15 +293,15 @@ impl EventTableChip { }; { - let class: OpcodeClassPlain = entry.eentry.inst.opcode.clone().into(); + let class: OpcodeClassPlain = (&entry.eentry.inst.opcode).into(); let op = self.config.common_config.ops[class.index()]; assign_advice_cell!(op, F::one()); } assign_advice!(enabled_cell, F::one()); - assign_advice!(rest_mops_cell, F::from(*rest_mops as u64)); - assign_advice!(rest_jops_cell, F::from(*rest_jops as u64)); + assign_advice!(rest_mops_cell, F::from(rest_mops as u64)); + assign_advice!(jops_cell, F::from(jops as u64)); assign_advice!(input_index_cell, F::from(host_public_inputs as u64)); assign_advice!(context_input_index_cell, F::from(context_in_index as u64)); assign_advice!(context_output_index_cell, F::from(context_out_index as u64)); @@ -266,14 +318,14 @@ impl EventTableChip { maximal_memory_pages_cell, F::from(configure_table.maximal_memory_pages as u64) ); - assign_advice!(frame_id_cell, F::from(entry.eentry.last_jump_eid as u64)); - assign_advice!(eid_cell, entry.eentry.eid); + assign_u32_state!(frame_id_cell, entry.eentry.last_jump_eid); + assign_u32_state!(eid_cell, entry.eentry.eid); assign_advice!(fid_cell, F::from(entry.eentry.inst.fid as u64)); assign_advice!(iid_cell, F::from(entry.eentry.inst.iid as u64)); assign_advice!(itable_lookup_cell, bn_to_field(&entry.eentry.inst.encode())); let op_config = op_configs - .get(&entry.eentry.inst.opcode.clone().into()) + .get(&((&entry.eentry.inst.opcode).into())) .unwrap(); op_config.assign(ctx, &step_status, &entry)?; @@ -290,18 +342,22 @@ impl EventTableChip { external_host_call_call_index += 1; } + rest_mops -= op_config.memory_writing_ops(&entry.eentry); + if cfg!(feature = "continuation") { + jops += op_config.jops() + } else { + jops -= op_config.jops() + } + ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); } // Assign terminate status - assign_advice!(eid_cell, status.last().unwrap().eid); + assign_u32_state!(eid_cell, status.last().unwrap().eid); assign_advice!(fid_cell, F::from(status.last().unwrap().fid as u64)); assign_advice!(iid_cell, F::from(status.last().unwrap().iid as u64)); assign_advice!(sp_cell, F::from(status.last().unwrap().sp as u64)); - assign_advice!( - frame_id_cell, - F::from(status.last().unwrap().last_jump_eid as u64) - ); + assign_u32_state!(frame_id_cell, status.last().unwrap().last_jump_eid); assign_advice!( mpages_cell, F::from(status.last().unwrap().allocated_memory_pages as u64) @@ -318,11 +374,7 @@ impl EventTableChip { F::from(external_host_call_call_index as u64) ); - Ok(( - fid_of_entry_cell.cell(), - initial_memory_pages_cell.cell(), - maximal_memory_pages_cell.cell(), - )) + Ok(()) } pub(in crate::circuits) fn assign( @@ -330,39 +382,45 @@ impl EventTableChip { ctx: &mut Context<'_, F>, event_table: &EventTableWithMemoryInfo, configure_table: &ConfigureTable, - fid_of_entry: u32, + initialization_state: &InitializationState, ) -> Result { debug!("size of execution table: {}", event_table.0.len()); assert!(event_table.0.len() * EVENT_TABLE_ENTRY_ROWS as usize <= self.max_available_rows); - let rest_ops = self.compute_rest_mops_and_jops(&self.config.op_configs, event_table); - self.init(ctx)?; ctx.reset(); - let (rest_mops_cell, rest_jops_cell) = self.assign_rest_ops_first_step( - ctx, - rest_ops.first().map_or(0u32, |(rest_mops, _)| *rest_mops), - rest_ops.first().map_or(0u32, |(_, rest_jops)| *rest_jops), - )?; - ctx.reset(); + let (rest_mops_cell, jops_cell) = self.assign_rest_ops_first_step(ctx)?; - let (fid_of_entry, initial_memory_pages, maximal_memory_pages) = self.assign_entries( + let (rest_mops, jops) = self.compute_rest_mops_and_jops( + &self.config.op_configs, + event_table, + #[cfg(feature = "continuation")] + initialization_state, + ); + + let pre_initialization_state_cells = + self.assign_initialization_state(ctx, &initialization_state)?; + + self.assign_entries( ctx, &self.config.op_configs, event_table, configure_table, - fid_of_entry, - rest_ops, + &initialization_state, + rest_mops, + jops, )?; ctx.reset(); Ok(EventTablePermutationCells { rest_mops: Some(rest_mops_cell), - rest_jops: Some(rest_jops_cell), - fid_of_entry, - initial_memory_pages, - maximal_memory_pages, + pre_initialization_state: pre_initialization_state_cells, + rest_jops: if cfg!(feature = "continuation") { + Some(jops_cell) + } else { + None + }, }) } } diff --git a/crates/zkwasm/src/circuits/etable/mod.rs b/crates/zkwasm/src/circuits/etable/mod.rs index 04305a2bd..ae40cc599 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::u32_state::AllocatedU32StateCell; use super::utils::Context; use crate::circuits::etable::op_configure::op_bin::BinConfigBuilder; use crate::circuits::etable::op_configure::op_bin_bit::BinBitConfigBuilder; @@ -78,15 +79,16 @@ pub struct EventTableCommonConfig { ops: [AllocatedBitCell; OP_CAPABILITY], rest_mops_cell: AllocatedCommonRangeCell, - rest_jops_cell: AllocatedCommonRangeCell, + // If continuation is enabled, it's an incremental counter; otherwise, it's decremental. + jops_cell: AllocatedCommonRangeCell, pub(crate) input_index_cell: AllocatedCommonRangeCell, 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, - frame_id_cell: AllocatedCommonRangeCell, - pub(crate) eid_cell: AllocatedU32Cell, + frame_id_cell: AllocatedU32StateCell, + pub(crate) eid_cell: AllocatedU32StateCell, fid_cell: AllocatedCommonRangeCell, iid_cell: AllocatedCommonRangeCell, maximal_memory_pages_cell: AllocatedCommonRangeCell, @@ -230,20 +232,19 @@ impl EventTableConfig { let enabled_cell = allocator.alloc_bit_cell(); let rest_mops_cell = allocator.alloc_common_range_cell(); - let rest_jops_cell = allocator.alloc_common_range_cell(); + let jops_cell = allocator.alloc_common_range_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_common_range_cell(); - let eid_cell = allocator.alloc_u32_cell(); + let frame_id_cell = allocator.alloc_u32_state_cell(); + 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(); - meta.enable_equality(eid_cell.u32_cell.0.col); // We only need to enable equality for the cells of states let used_common_range_cells_for_state = allocator .free_cells @@ -272,7 +273,7 @@ impl EventTableConfig { enabled_cell, ops, rest_mops_cell, - rest_jops_cell, + jops_cell, input_index_cell, context_input_index_cell, context_output_index_cell, @@ -446,7 +447,11 @@ impl EventTableConfig { meta.create_gate("c5b. rest_jops change", |meta| { vec![sum_ops_expr_with_init( - rest_jops_cell.next_expr(meta) - rest_jops_cell.curr_expr(meta), + if cfg!(feature = "continuation") { + jops_cell.curr_expr(meta) - jops_cell.next_expr(meta) + } else { + jops_cell.next_expr(meta) - jops_cell.curr_expr(meta) + }, meta, &|meta, config: &Rc>>| config.jops_expr(meta), None, @@ -521,9 +526,7 @@ impl EventTableConfig { meta.create_gate("c6a. eid change", |meta| { vec![ - (eid_cell.u32_cell.next_expr(meta) - - eid_cell.u32_cell.curr_expr(meta) - - constant_from!(1)) + (eid_cell.next_expr(meta) - eid_cell.curr_expr(meta) - constant_from!(1)) * enabled_cell.curr_expr(meta) * fixed_curr!(meta, step_sel), ] diff --git a/crates/zkwasm/src/circuits/etable/op_configure/op_call.rs b/crates/zkwasm/src/circuits/etable/op_configure/op_call.rs index a06471ead..3f6e88976 100644 --- a/crates/zkwasm/src/circuits/etable/op_configure/op_call.rs +++ b/crates/zkwasm/src/circuits/etable/op_configure/op_call.rs @@ -107,7 +107,7 @@ impl EventTableOpcodeConfig for CallConfig { meta: &mut VirtualCells<'_, F>, common_config: &EventTableCommonConfig, ) -> Option> { - Some(common_config.eid_cell.u32_cell.curr_expr(meta)) + Some(common_config.eid_cell.curr_expr(meta)) } fn next_fid( 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 5921e2f45..745df4c92 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 @@ -196,7 +196,7 @@ impl EventTableOpcodeConfig for CallIndirectConfig { meta: &mut VirtualCells<'_, F>, common_config: &EventTableCommonConfig, ) -> Option> { - Some(common_config.eid_cell.u32_cell.curr_expr(meta)) + Some(common_config.eid_cell.curr_expr(meta)) } fn next_fid( diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index bb9c5fe43..7e898f102 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -1,7 +1,10 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::Cell; use halo2_proofs::circuit::Layouter; +use halo2_proofs::plonk::Advice; +use halo2_proofs::plonk::Column; use halo2_proofs::plonk::Error; +use specs::state::InitializationState; use super::ImageTableChip; use super::ImageTableLayouter; @@ -14,6 +17,50 @@ impl ImageTableChip { image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter, ) -> Result<(), Error> { + fn assign_and_perm_initialization_state( + ctx: &mut Context, + col: Column, + initialization_state: &InitializationState, + permutation_cells: &InitializationState, + ) -> Result<(), Error> { + macro_rules! assign_and_perm { + ($field:ident) => { + let cell = ctx + .region + .assign_advice( + || "image table", + col, + ctx.offset, + || Ok(initialization_state.$field), + )? + .cell(); + + ctx.region.constrain_equal(cell, permutation_cells.$field)?; + + ctx.next(); + }; + } + + assign_and_perm!(eid); + assign_and_perm!(fid); + assign_and_perm!(iid); + assign_and_perm!(frame_id); + assign_and_perm!(sp); + + assign_and_perm!(host_public_inputs); + assign_and_perm!(context_in_index); + assign_and_perm!(context_out_index); + assign_and_perm!(external_host_call_call_index); + + assign_and_perm!(initial_memory_pages); + assign_and_perm!(maximal_memory_pages); + + #[cfg(feature = "continuation")] + assign_and_perm!(jops); + + Ok(()) + } + layouter.assign_region( || "image table", |region| { @@ -37,20 +84,11 @@ impl ImageTableChip { }}; } - let entry_fid_cell = assign_one_line!(image_table.entry_fid); - ctx.region - .constrain_equal(permutation_cells.entry_fid, entry_fid_cell)?; - - let initial_memory_pages_cell = assign_one_line!(image_table.initial_memory_pages); - ctx.region.constrain_equal( - permutation_cells.initial_memory_pages, - initial_memory_pages_cell, - )?; - - let maximal_memory_pages_cell = assign_one_line!(image_table.maximal_memory_pages); - ctx.region.constrain_equal( - permutation_cells.maximal_memory_pages, - maximal_memory_pages_cell, + assign_and_perm_initialization_state( + &mut ctx, + self.config.col, + &image_table.initialization_state, + &permutation_cells.initialization_state, )?; for (static_frame_entry, cell_in_frame_table) in image_table diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index 777f2a8d6..8f25c8726 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -9,6 +9,7 @@ use specs::imtable::InitMemoryTable; use specs::itable::InstructionTable; use specs::jtable::StaticFrameEntry; use specs::mtable::LocationType; +use specs::state::InitializationState; use specs::CompilationTable; use std::marker::PhantomData; @@ -21,9 +22,7 @@ mod configure; pub const IMAGE_COL_NAME: &str = "img_col"; pub struct ImageTableLayouter { - pub entry_fid: T, - pub initial_memory_pages: T, - pub maximal_memory_pages: T, + pub initialization_state: InitializationState, pub static_frame_entries: Vec<(T, T)>, /* * include: @@ -39,9 +38,7 @@ impl ImageTableLayouter { pub fn plain(&self) -> Vec { let mut buf = vec![]; - buf.push(self.entry_fid.clone()); - buf.push(self.initial_memory_pages.clone()); - buf.push(self.maximal_memory_pages.clone()); + buf.append(&mut self.initialization_state.plain()); buf.append( &mut self .static_frame_entries @@ -64,6 +61,12 @@ pub trait EncodeCompilationTableValues { impl EncodeCompilationTableValues for CompilationTable { fn encode_compilation_table_values(&self) -> ImageTableLayouter { + fn msg_of_initialization_state( + initialization_state: &InitializationState, + ) -> InitializationState { + initialization_state.map(|field| F::from(*field as u64)) + } + fn msg_of_instruction_table(instruction_table: &InstructionTable) -> Vec { let mut cells = vec![]; @@ -165,22 +168,8 @@ impl EncodeCompilationTableValues for CompilationTable { cells } - fn msg_of_memory_pages( - init_memory_pages: u32, - maximal_memory_pages: u32, - ) -> (F, F) { - ( - F::from(init_memory_pages as u64), - F::from(maximal_memory_pages as u64), - ) - } - - let entry_fid = F::from(self.fid_of_entry as u64); + let initialization_state = msg_of_initialization_state(&self.initialization_state); let static_frame_entries = msg_of_static_frame_table(&self.static_jtable); - let (initial_memory_pages, maximal_memory_pages) = msg_of_memory_pages( - self.configure_table.init_memory_pages, - self.configure_table.maximal_memory_pages, - ); let lookup_entries = msg_of_image_table( &self.itable, &self.itable.create_brtable(), @@ -189,10 +178,8 @@ impl EncodeCompilationTableValues for CompilationTable { ); ImageTableLayouter { - entry_fid, + initialization_state, static_frame_entries, - initial_memory_pages, - maximal_memory_pages, lookup_entries: Some(lookup_entries), } } diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 89fab14ca..837388c92 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -69,8 +69,6 @@ impl JumpTableChip { ) -> Result, Error> { let mut static_entries = static_entries.clone(); - assert!(static_entries.len() == 1 || static_entries.len() == 2); - let mut cells = vec![]; static_entries.resize( diff --git a/crates/zkwasm/src/circuits/mod.rs b/crates/zkwasm/src/circuits/mod.rs index 4546e91e8..f89bed64d 100644 --- a/crates/zkwasm/src/circuits/mod.rs +++ b/crates/zkwasm/src/circuits/mod.rs @@ -57,7 +57,6 @@ pub(self) trait Lookup { pub struct ZkWasmCircuitBuilder { pub tables: Tables, - pub public_inputs_and_outputs: Vec, } impl ZkWasmCircuitBuilder { diff --git a/crates/zkwasm/src/circuits/mtable/allocator.rs b/crates/zkwasm/src/circuits/mtable/allocator.rs index 423a7c709..875f89fa0 100644 --- a/crates/zkwasm/src/circuits/mtable/allocator.rs +++ b/crates/zkwasm/src/circuits/mtable/allocator.rs @@ -14,6 +14,7 @@ use crate::circuits::rtable::RangeTableConfig; use crate::circuits::utils::bit::BitColumn; use crate::circuits::utils::common_range::CommonRangeColumn; use crate::circuits::utils::u16::U16Column; +use crate::circuits::utils::u32_state::AllocatedU32StateCell; use crate::constant_from; use crate::fixed_curr; use crate::nextn; @@ -54,6 +55,24 @@ impl_cell!(AllocatedCommonRangeCell); impl_cell!(AllocatedU16Cell); impl_cell!(AllocatedUnlimitedCell); +impl MemoryTableCellExpression for AllocatedU32Cell { + fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + nextn!( + meta, + self.u32_cell.0.col, + self.u32_cell.0.rot + MEMORY_TABLE_ENTRY_ROWS as i32 + ) + } + + fn prev_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + nextn!( + meta, + self.u32_cell.0.col, + self.u32_cell.0.rot - MEMORY_TABLE_ENTRY_ROWS as i32 + ) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub(super) enum MemoryTableCellType { Bit = 1, @@ -63,15 +82,17 @@ pub(super) enum MemoryTableCellType { } const BIT_COLUMNS: usize = 3; -const U16_COLUMNS: usize = 1; -const COMMON_RANGE_COLUMNS: usize = 3; -const UNLIMITED_COLUMNS: usize = 2; +const U16_COLUMNS: usize = U32_CELLS / 2 + U64_CELLS; +const COMMON_RANGE_COLUMNS: usize = 2; +const UNLIMITED_COLUMNS: usize = 3; +const U32_CELLS: usize = 6; const U64_CELLS: usize = 1; #[derive(Debug, Clone)] pub(super) struct MemoryTableCellAllocator { all_cols: BTreeMap>>, free_cells: BTreeMap, + free_u32_cells: Vec>, free_u64_cells: Vec>, _mark: PhantomData, } @@ -83,6 +104,29 @@ impl MemoryTableCellAllocator { } } + pub(super) fn prepare_alloc_u32_cell( + &mut self, + meta: &mut ConstraintSystem, + enable: impl Fn(&mut VirtualCells<'_, F>) -> Expression, + ) -> AllocatedU32Cell { + let u16_cells_le = [0; 2].map(|_| self.alloc_u16_cell()); + let u32_cell = self.alloc_unlimited_cell(); + meta.create_gate("mc9. value", |meta| { + let init = u32_cell.curr_expr(meta); + vec![ + (0..2) + .into_iter() + .map(|x| u16_cells_le[x].curr_expr(meta) * constant_from!(1u64 << (16 * x))) + .fold(init, |acc, x| acc - x) + * enable(meta), + ] + }); + AllocatedU32Cell { + u16_cells_le, + u32_cell, + } + } + pub(super) fn prepare_alloc_u64_cell( &mut self, meta: &mut ConstraintSystem, @@ -113,6 +157,10 @@ impl MemoryTableCellAllocator { cols: &mut impl Iterator>, ) -> Self { let mut allocator = Self::_new(meta, sel.clone(), rtable, cols); + for _ in 0..U32_CELLS { + let cell = allocator.prepare_alloc_u32_cell(meta, |meta| fixed_curr!(meta, sel)); + allocator.free_u32_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); @@ -168,6 +216,7 @@ impl MemoryTableCellAllocator { ] .into_iter(), ), + free_u32_cells: vec![], free_u64_cells: vec![], _mark: PhantomData, } @@ -181,8 +230,6 @@ impl MemoryTableCellAllocator { _mark: PhantomData, }; - assert!(v.0 < BIT_COLUMNS); - v.1 += 1; if v.1 == MEMORY_TABLE_ENTRY_ROWS as u32 { v.0 += 1; @@ -200,6 +247,16 @@ impl MemoryTableCellAllocator { AllocatedCommonRangeCell(self.alloc(&MemoryTableCellType::CommonRange)) } + pub(super) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + self.alloc_u32_cell() + } else { + AllocatedCommonRangeCell(self.alloc(&MemoryTableCellType::CommonRange)) + } + } + } + pub(super) fn alloc_u16_cell(&mut self) -> AllocatedU16Cell { AllocatedU16Cell(self.alloc(&MemoryTableCellType::U16)) } @@ -208,6 +265,10 @@ impl MemoryTableCellAllocator { AllocatedUnlimitedCell(self.alloc(&MemoryTableCellType::Unlimited)) } + pub(super) fn alloc_u32_cell(&mut self) -> AllocatedU32Cell { + self.free_u32_cells.pop().expect("no more free u32 cells") + } + pub(super) fn alloc_u64_cell(&mut self) -> AllocatedU64Cell { self.free_u64_cells.pop().expect("no more free u64 cells") } diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index c799cb5c6..5fb0a35d1 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -78,6 +78,22 @@ impl MemoryTableChip { }; } + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + self.config.$cell.assign(ctx, $value)? + } + } + } else { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + assign_advice!($cell, F::from($value as u64)) + } + } + } + } + macro_rules! assign_bit { ($cell:ident) => { assign_advice!($cell, F::one()) @@ -113,19 +129,19 @@ impl MemoryTableChip { assign_bit_if!(entry.entry.atype.is_init(), is_init_cell); if entry.entry.atype.is_init() { - let (left_offset, right_offset, value) = imtable + let (left_offset, right_offset, _, value) = imtable .try_find(entry.entry.ltype, entry.entry.offset) .unwrap(); - assign_advice!(offset_align_left, F::from(left_offset as u64)); - assign_advice!(offset_align_right, F::from(right_offset as u64)); + assign_advice!(offset_align_left, left_offset); + assign_advice!(offset_align_right, right_offset); assign_advice!( offset_align_left_diff_cell, - F::from((entry.entry.offset - left_offset) as u64) + entry.entry.offset - left_offset ); assign_advice!( offset_align_right_diff_cell, - F::from((right_offset - entry.entry.offset) as u64) + right_offset - entry.entry.offset ); assign_advice!( @@ -135,19 +151,17 @@ impl MemoryTableChip { (entry.entry.is_mutable as u64).into(), left_offset.into(), right_offset.into(), + entry.entry.eid.into(), value.into() )) ); } - assign_advice!(start_eid_cell, F::from(entry.entry.eid as u64)); - assign_advice!(end_eid_cell, F::from(entry.end_eid as u64)); - assign_advice!( - eid_diff_cell, - F::from((entry.end_eid - entry.entry.eid - 1) as u64) - ); + assign_u32_state!(start_eid_cell, entry.entry.eid); + assign_u32_state!(end_eid_cell, entry.end_eid); + assign_u32_state!(eid_diff_cell, entry.end_eid - entry.entry.eid - 1); assign_advice!(rest_mops_cell, F::from(rest_mops)); - assign_advice!(offset_cell, F::from(entry.entry.offset as u64)); + assign_advice!(offset_cell, entry.entry.offset); assign_advice!(value, entry.entry.value); assign_advice!( @@ -175,7 +189,7 @@ impl MemoryTableChip { let mut cache = HashMap::new(); for (curr, next) in mtable.0.iter().zip(mtable.0.iter().skip(1)) { if curr.entry.ltype == next.entry.ltype { - let offset_diff = (next.entry.offset - curr.entry.offset) as u64; + let offset_diff = next.entry.offset - curr.entry.offset; assign_bit!(is_next_same_ltype_cell); @@ -183,16 +197,19 @@ impl MemoryTableChip { curr.entry.offset == next.entry.offset, is_next_same_offset_cell ); - assign_advice!(offset_diff_cell, F::from(offset_diff)); + assign_advice!(offset_diff_cell, offset_diff); let invert = if let Some(f) = cache.get(&offset_diff) { *f } else { - let f = F::from(offset_diff).invert().unwrap_or(F::zero()); + let f = F::from(offset_diff as u64).invert().unwrap_or(F::zero()); cache.insert(offset_diff, f); f }; assign_advice!(offset_diff_inv_cell, invert); - assign_advice!(offset_diff_inv_helper_cell, invert * F::from(offset_diff)); + assign_advice!( + offset_diff_inv_helper_cell, + invert * F::from(offset_diff as u64) + ); } ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index fabe522aa..03c6317cb 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -3,6 +3,7 @@ use super::cell::*; use super::image_table::ImageTableConfig; use super::rtable::RangeTableConfig; use super::traits::ConfigureLookupTable; +use super::utils::u32_state::AllocatedU32StateCell; use crate::constant_from; use crate::fixed_curr; use halo2_proofs::arithmetic::FieldExt; @@ -39,16 +40,16 @@ pub struct MemoryTableConfig { is_i64_cell: AllocatedBitCell, is_init_cell: AllocatedBitCell, - start_eid_cell: AllocatedCommonRangeCell, - end_eid_cell: AllocatedCommonRangeCell, - eid_diff_cell: AllocatedCommonRangeCell, + start_eid_cell: AllocatedU32StateCell, + end_eid_cell: AllocatedU32StateCell, + eid_diff_cell: AllocatedU32StateCell, rest_mops_cell: AllocatedCommonRangeCell, - offset_align_left: AllocatedCommonRangeCell, - offset_align_right: AllocatedCommonRangeCell, - offset_align_left_diff_cell: AllocatedCommonRangeCell, - offset_align_right_diff_cell: AllocatedCommonRangeCell, - offset_cell: AllocatedCommonRangeCell, - offset_diff_cell: AllocatedCommonRangeCell, + offset_align_left: AllocatedU32Cell, + offset_align_right: AllocatedU32Cell, + offset_align_left_diff_cell: AllocatedU32Cell, + offset_align_right_diff_cell: AllocatedU32Cell, + offset_cell: AllocatedU32Cell, + offset_diff_cell: AllocatedU32Cell, offset_diff_inv_cell: AllocatedUnlimitedCell, offset_diff_inv_helper_cell: AllocatedUnlimitedCell, @@ -82,18 +83,18 @@ impl MemoryTableConfig { let is_i64_cell = allocator.alloc_bit_cell(); let is_init_cell = allocator.alloc_bit_cell(); - let start_eid_cell = allocator.alloc_common_range_cell(); - let end_eid_cell = allocator.alloc_common_range_cell(); - let eid_diff_cell = allocator.alloc_common_range_cell(); + let start_eid_cell = allocator.alloc_u32_state_cell(); + let end_eid_cell = allocator.alloc_u32_state_cell(); + let eid_diff_cell = allocator.alloc_u32_state_cell(); let rest_mops_cell = allocator.alloc_common_range_cell(); - let offset_align_left = allocator.alloc_common_range_cell(); - let offset_align_right = allocator.alloc_common_range_cell(); - let offset_cell = allocator.alloc_common_range_cell(); - let offset_align_left_diff_cell = allocator.alloc_common_range_cell(); - let offset_align_right_diff_cell = allocator.alloc_common_range_cell(); + let offset_align_left = allocator.alloc_u32_cell(); + let offset_align_right = allocator.alloc_u32_cell(); + let offset_cell = allocator.alloc_u32_cell(); + let offset_align_left_diff_cell = allocator.alloc_u32_cell(); + let offset_align_right_diff_cell = allocator.alloc_u32_cell(); - let offset_diff_cell = allocator.alloc_common_range_cell(); + let offset_diff_cell = allocator.alloc_u32_cell(); let offset_diff_inv_cell = allocator.alloc_unlimited_cell(); let offset_diff_inv_helper_cell = allocator.alloc_unlimited_cell(); let encode_cell = allocator.alloc_unlimited_cell(); @@ -188,6 +189,7 @@ impl MemoryTableConfig { meta.create_gate("mc7a. init", |meta| { vec![ + // TODO: This may not be true if continuation is enabled. is_init_cell.curr_expr(meta) * start_eid_cell.curr_expr(meta), // offset_left_align <= offset && offset <= offset_right_align is_init_cell.curr_expr(meta) @@ -229,6 +231,7 @@ impl MemoryTableConfig { is_mutable.curr_expr(meta), offset_align_left.curr_expr(meta), offset_align_right.curr_expr(meta), + start_eid_cell.curr_expr(meta), value.u64_cell.curr_expr(meta), ) - init_encode_cell.curr_expr(meta), diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index a796dd1a9..9d055ab82 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -11,6 +11,7 @@ use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; use log::debug; +use specs::CompilationTable; use specs::ExecutionTable; use specs::Tables; @@ -47,7 +48,7 @@ use crate::runtime::memory_event_of_step; use super::config::zkwasm_k; use super::image_table::ImageTableConfig; -pub const VAR_COLUMNS: usize = 53; +pub const VAR_COLUMNS: usize = 56; // Reserve a few rows to keep usable rows away from blind rows. // The maximal step size of all tables is bit_table::STEP_SIZE. @@ -76,8 +77,9 @@ impl Circuit for TestCircuit { fn without_witnesses(&self) -> Self { TestCircuit::new(Tables { - compilation_tables: self.tables.compilation_tables.clone(), + compilation_tables: CompilationTable::default(), execution_tables: ExecutionTable::default(), + post_image_table: CompilationTable::default(), }) } @@ -196,75 +198,66 @@ impl Circuit for TestCircuit { )? ); - let (entry_fid, static_frame_entries, initial_memory_pages, maximal_memory_pages) = - layouter.assign_region( - || "jtable mtable etable", - |region| { - let mut ctx = Context::new(region); - - let memory_writing_table: MemoryWritingTable = - self.tables.create_memory_table(memory_event_of_step).into(); - - let etable = exec_with_profile!( - || "Prepare memory info for etable", - EventTableWithMemoryInfo::new( - &self.tables.execution_tables.etable, + let (etable_permutation_cells, static_frame_entries) = layouter.assign_region( + || "jtable mtable etable", + |region| { + let mut ctx = Context::new(region); + + let memory_writing_table: MemoryWritingTable = + self.tables.create_memory_table(memory_event_of_step).into(); + + let etable = exec_with_profile!( + || "Prepare memory info for etable", + EventTableWithMemoryInfo::new( + &self.tables.execution_tables.etable, + &memory_writing_table, + ) + ); + + let etable_permutation_cells = exec_with_profile!( + || "Assign etable", + echip.assign( + &mut ctx, + &etable, + &self.tables.compilation_tables.configure_table, + &self.tables.compilation_tables.initialization_state, + )? + ); + + { + ctx.reset(); + exec_with_profile!( + || "Assign mtable", + mchip.assign( + &mut ctx, + etable_permutation_cells.rest_mops, &memory_writing_table, - ) + &self.tables.compilation_tables.imtable + )? ); + } - let etable_permutation_cells = exec_with_profile!( - || "Assign etable", - echip.assign( + let jtable_info = { + ctx.reset(); + exec_with_profile!( + || "Assign frame table", + jchip.assign( &mut ctx, - &etable, - &self.tables.compilation_tables.configure_table, - self.tables.compilation_tables.fid_of_entry, + &self.tables.execution_tables.jtable, + etable_permutation_cells.rest_jops, + &self.tables.compilation_tables.static_jtable, )? - ); + ) + }; + + { + ctx.reset(); + exec_with_profile!(|| "Assign bit table", bit_chip.assign(&mut ctx, &etable)?); + } - { - ctx.reset(); - exec_with_profile!( - || "Assign mtable", - mchip.assign( - &mut ctx, - etable_permutation_cells.rest_mops, - &memory_writing_table, - &self.tables.compilation_tables.imtable - )? - ); - } - - let jtable_info = { - ctx.reset(); - exec_with_profile!( - || "Assign frame table", - jchip.assign( - &mut ctx, - &self.tables.execution_tables.jtable, - etable_permutation_cells.rest_jops, - &self.tables.compilation_tables.static_jtable, - )? - ) - }; - - { - ctx.reset(); - exec_with_profile!( - || "Assign bit table", - bit_chip.assign(&mut ctx, &etable)? - ); - } - - Ok(( - etable_permutation_cells.fid_of_entry, - jtable_info, - etable_permutation_cells.initial_memory_pages, - etable_permutation_cells.maximal_memory_pages, - )) - }, - )?; + Ok((etable_permutation_cells, jtable_info)) + }, + )?; exec_with_profile!( || "Assign context cont chip", @@ -276,17 +269,15 @@ impl Circuit for TestCircuit { ); exec_with_profile!( - || "Assign Image Table", + || "Assign Pre Image Table", image_chip.assign( &mut layouter, self.tables .compilation_tables .encode_compilation_table_values(), ImageTableLayouter { - entry_fid, + initialization_state: etable_permutation_cells.pre_initialization_state, static_frame_entries, - initial_memory_pages, - maximal_memory_pages, lookup_entries: None } )? diff --git a/crates/zkwasm/src/circuits/utils/mod.rs b/crates/zkwasm/src/circuits/utils/mod.rs index cae726470..83703b4d6 100644 --- a/crates/zkwasm/src/circuits/utils/mod.rs +++ b/crates/zkwasm/src/circuits/utils/mod.rs @@ -8,6 +8,7 @@ pub mod common_range; pub mod row_diff; pub mod step_status; pub mod u16; +pub mod u32_state; pub mod u8; pub mod table_entry; diff --git a/crates/zkwasm/src/circuits/utils/table_entry.rs b/crates/zkwasm/src/circuits/utils/table_entry.rs index 5baf7a8c3..ad84b718e 100644 --- a/crates/zkwasm/src/circuits/utils/table_entry.rs +++ b/crates/zkwasm/src/circuits/utils/table_entry.rs @@ -161,7 +161,7 @@ impl EventTableWithMemoryInfo { .iter() .map(|eentry| EventTableEntryWithMemoryInfo { eentry: eentry.clone(), - memory_rw_entires: memory_event_of_step(eentry, &mut 1) + memory_rw_entires: memory_event_of_step(eentry) .iter() .map(|mentry| { let (start_eid, end_eid) = lookup_mtable_eid(( diff --git a/crates/zkwasm/src/circuits/utils/u32_state/mod.rs b/crates/zkwasm/src/circuits/utils/u32_state/mod.rs new file mode 100644 index 000000000..542bc3ead --- /dev/null +++ b/crates/zkwasm/src/circuits/utils/u32_state/mod.rs @@ -0,0 +1,11 @@ +cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + use crate::circuits::cell::AllocatedU32Cell; + + pub(crate) type AllocatedU32StateCell = AllocatedU32Cell; + } else { + use crate::circuits::cell::AllocatedCommonRangeCell; + + pub(crate) type AllocatedU32StateCell = AllocatedCommonRangeCell; + } +} diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index 2b09a4d29..e08009309 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -15,6 +15,7 @@ use halo2_proofs::poly::commitment::ParamsVerifier; use halo2aggregator_s::circuits::utils::load_or_create_proof; use halo2aggregator_s::circuits::utils::TranscriptHash; use halo2aggregator_s::transcript::poseidon::PoseidonRead; +use specs::CompilationTable; use specs::ExecutionTable; use specs::Tables; use wasmi::tracer::Tracer; @@ -109,21 +110,12 @@ impl ZkWasmLoader { } fn circuit_without_witness(&self) -> Result> { - let (env, wasm_runtime_io) = HostEnv::new_with_full_foreign_plugins( - vec![], - vec![], - vec![], - Arc::new(Mutex::new(vec![])), - ); - - let compiled_module = self.compile(&env)?; - let builder = ZkWasmCircuitBuilder { tables: Tables { - compilation_tables: compiled_module.tables, + compilation_tables: CompilationTable::default(), execution_tables: ExecutionTable::default(), + post_image_table: CompilationTable::default(), }, - public_inputs_and_outputs: wasm_runtime_io.public_inputs_and_outputs.borrow().clone(), }; Ok(builder.build_circuit::()) @@ -218,7 +210,6 @@ impl ZkWasmLoader { let builder = ZkWasmCircuitBuilder { tables: execution_result.tables, - public_inputs_and_outputs: execution_result.public_inputs_and_outputs, }; println!("output:"); diff --git a/crates/zkwasm/src/profile/instruction_merge.rs b/crates/zkwasm/src/profile/instruction_merge.rs index 0655bb09e..4f91501e7 100644 --- a/crates/zkwasm/src/profile/instruction_merge.rs +++ b/crates/zkwasm/src/profile/instruction_merge.rs @@ -40,19 +40,19 @@ impl InstructionMergingProfile for EventTable { } if let Opcode::Const { .. } = &entry.inst.opcode { - match const_opt.get_mut(&(next_entry.inst.opcode.clone().into())) { + match const_opt.get_mut(&((&next_entry.inst.opcode).into())) { Some(counter) => *counter = *counter + 1, None => { - const_opt.insert(next_entry.inst.opcode.clone().into(), 1); + const_opt.insert((&next_entry.inst.opcode).into(), 1); } } } if let Opcode::LocalGet { .. } = &entry.inst.opcode { - match local_get_opt.get_mut(&(next_entry.inst.opcode.clone().into())) { + match local_get_opt.get_mut(&((&next_entry.inst.opcode).into())) { Some(counter) => *counter = *counter + 1, None => { - local_get_opt.insert(next_entry.inst.opcode.clone().into(), 1); + local_get_opt.insert((&next_entry.inst.opcode).into(), 1); } } } diff --git a/crates/zkwasm/src/profile/instruction_statistic.rs b/crates/zkwasm/src/profile/instruction_statistic.rs index d3c85bfe4..59a1a5418 100644 --- a/crates/zkwasm/src/profile/instruction_statistic.rs +++ b/crates/zkwasm/src/profile/instruction_statistic.rs @@ -21,14 +21,14 @@ impl InstructionStatistic for EventTable { let mut map = BTreeMap::::new(); for entry in self.entries() { - let mut mentries = memory_event_of_step(entry, &mut 1); + let mut mentries = memory_event_of_step(entry); - if let Some(counter) = map.get_mut(&entry.inst.opcode.clone().into()) { + if let Some(counter) = map.get_mut(&((&entry.inst.opcode).into())) { counter.counter += 1; counter.mentries.append(&mut mentries); } else { map.insert( - entry.inst.opcode.clone().into(), + (&entry.inst.opcode).into(), Counter { counter: 1, mentries, diff --git a/crates/zkwasm/src/runtime/mod.rs b/crates/zkwasm/src/runtime/mod.rs index afb43d21c..8050b3ba4 100644 --- a/crates/zkwasm/src/runtime/mod.rs +++ b/crates/zkwasm/src/runtime/mod.rs @@ -14,6 +14,7 @@ use specs::Tables; use self::wasmi_interpreter::WasmiRuntime; pub mod host; +pub mod state; pub mod wasmi_interpreter; pub struct CompiledImage { @@ -34,7 +35,7 @@ pub struct ExecutionResult { // TODO: use feature pub type WasmInterpreter = WasmiRuntime; -pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec { +pub fn memory_event_of_step(event: &EventTableEntry) -> Vec { let eid = event.eid; let sp_before_execution = event.sp; @@ -55,7 +56,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec { let stack_read = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -431,7 +396,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec Vec Vec Vec { let stack_read = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -490,14 +447,12 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec { let stack_write = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution, ltype: LocationType::Stack, atype: AccessType::Write, @@ -505,7 +460,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec { let read = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + depth, ltype: LocationType::Stack, atype: AccessType::Read, @@ -526,11 +479,9 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec Vec Vec Vec { let read = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -592,11 +537,8 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec { let global_get = MemoryTableEntry { eid, - emid: *emid, offset: *idx, ltype: LocationType::Global, atype: AccessType::Read, @@ -625,11 +566,9 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec { let stack_read = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -657,11 +594,9 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec { let load_address_from_stack = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -694,11 +627,9 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec 8 { - *emid = (*emid).checked_add(1).unwrap(); Some(MemoryTableEntry { eid, - emid: *emid, offset: effective_address / 8 + 1, ltype: LocationType::Heap, atype: AccessType::Read, @@ -727,10 +656,8 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec { let load_value_from_stack = MemoryTableEntry { eid, - emid: *emid, offset: sp_before_execution + 1, ltype: LocationType::Stack, atype: AccessType::Read, @@ -768,11 +694,9 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec Vec Vec 8 { - *emid = (*emid).checked_add(1).unwrap(); let load_value2 = MemoryTableEntry { eid, - emid: *emid, offset: effective_address / 8 + 1, ltype: LocationType::Heap, atype: AccessType::Read, @@ -824,10 +742,8 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[], @@ -867,7 +782,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[*grow_size as u32 as u64], @@ -877,7 +791,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[], @@ -894,7 +807,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[*right as u32 as u64, *left as u32 as u64], @@ -905,7 +817,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[*right as u32 as u64, *left as u32 as u64], @@ -923,7 +834,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I64, VarType::I64, &[*right as u64, *left as u64], @@ -933,7 +843,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I64, VarType::I64, &[], @@ -944,7 +853,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I64, VarType::I32, &[*right as u64, *left as u64], @@ -958,7 +866,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, *vtype, *vtype, &[*operand], @@ -972,7 +879,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, *vtype, VarType::I32, &[*value], @@ -982,7 +888,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I64, VarType::I32, &[*value as u64], @@ -991,7 +896,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I64, &[*value as u32 as u64], @@ -1001,7 +905,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I32, VarType::I32, &[*value as u32 as u64], @@ -1012,7 +915,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec mem_op_from_stack_only_step( sp_before_execution, eid, - emid, VarType::I64, VarType::I64, &[*value as u64], @@ -1024,7 +926,6 @@ pub fn memory_event_of_step(event: &EventTableEntry, emid: &mut u32) -> Vec InitMemoryTable; + + fn update_initialization_state( + &self, + execution_table: &EventTable, + is_last_slice: bool, + ) -> InitializationState; +} + +impl UpdateCompilationTable for CompilationTable { + fn update_init_memory_table(&self, execution_table: &EventTable) -> InitMemoryTable { + let mut local_map = BTreeMap::::new(); + let mut global_map = BTreeMap::::new(); + let mut memory_map = BTreeMap::::new(); + + // First insert origin imtable entries which may be overwritten. + for entry in self.imtable.entries() { + match entry.ltype { + LocationType::Stack => { + assert_eq!(entry.start_offset, entry.end_offset); + + local_map.insert(entry.start_offset, entry.clone()); + } + LocationType::Heap => { + for offset in entry.start_offset..=entry.end_offset { + memory_map.insert( + offset, + InitMemoryTableEntry { + ltype: entry.ltype, + is_mutable: entry.is_mutable, + start_offset: offset, + end_offset: offset, + vtype: entry.vtype, + value: entry.value, + eid: entry.eid, + }, + ); + } + } + LocationType::Global => { + assert_eq!(entry.start_offset, entry.end_offset); + + global_map.insert(entry.start_offset, entry.clone()); + } + } + } + + for etable_entry in execution_table.entries() { + let memory_writing_entires = memory_event_of_step(etable_entry) + .into_iter() + .filter(|entry| entry.atype == AccessType::Write); + + for mentry in memory_writing_entires { + let map = match mentry.ltype { + LocationType::Stack => &mut local_map, + LocationType::Heap => &mut memory_map, + LocationType::Global => &mut global_map, + }; + + map.insert( + mentry.offset, + InitMemoryTableEntry { + ltype: mentry.ltype, + is_mutable: mentry.is_mutable, + start_offset: mentry.offset, + end_offset: mentry.offset, + vtype: mentry.vtype, + value: mentry.value, + eid: etable_entry.eid, + }, + ); + } + } + + let init_memory_entries = vec![] + .into_iter() + .chain(local_map.into_values()) + .chain(global_map.into_values()) + .chain(memory_map.into_values()) + .collect(); + + InitMemoryTable::new(init_memory_entries) + } + + fn update_initialization_state( + &self, + execution_table: &EventTable, + is_last_slice: bool, + ) -> InitializationState { + let mut host_public_inputs = self.initialization_state.host_public_inputs; + let mut context_in_index = self.initialization_state.context_in_index; + let mut context_out_index = self.initialization_state.context_out_index; + let mut external_host_call_call_index = + self.initialization_state.external_host_call_call_index; + + #[cfg(feature = "continuation")] + let mut jops = self.initialization_state.jops; + + for entry in execution_table.entries() { + match &entry.step_info { + // TODO: fix hard code + StepInfo::CallHost { + function_name, + args, + op_index_in_plugin, + .. + } => { + if *op_index_in_plugin == HostPlugin::HostInput as usize { + if function_name == "wasm_input" && args[0] != 0 + || function_name == "wasm_output" + { + host_public_inputs += 1; + } + } else if *op_index_in_plugin == HostPlugin::Context as usize { + if function_name == "wasm_read_context" { + context_in_index += 1; + } else if function_name == "wasm_write_context" { + context_out_index += 1; + } + } + } + StepInfo::ExternalHostCall { .. } => external_host_call_call_index += 1, + StepInfo::Call { .. } | StepInfo::CallIndirect { .. } | StepInfo::Return { .. } => { + #[cfg(feature = "continuation")] + { + jops += 1; + } + } + _ => (), + } + } + + let last_entry = execution_table.entries().last().unwrap(); + + let post_initialization_state = if is_last_slice { + InitializationState { + eid: last_entry.eid + 1, + fid: 0, + iid: 0, + frame_id: 0, + // TODO: why not constant 4095? + sp: last_entry.sp + + if let Opcode::Return { drop, .. } = last_entry.inst.opcode { + drop + } else { + 0 + }, + + host_public_inputs, + context_in_index, + context_out_index, + external_host_call_call_index, + + initial_memory_pages: last_entry.allocated_memory_pages, + maximal_memory_pages: self.configure_table.maximal_memory_pages, + + #[cfg(feature = "continuation")] + jops, + } + } else { + InitializationState { + eid: last_entry.eid, + fid: last_entry.inst.fid, + iid: last_entry.inst.iid, + frame_id: last_entry.last_jump_eid, + // TODO: why not constant 4095? + sp: last_entry.sp, + + host_public_inputs, + context_in_index, + context_out_index, + external_host_call_call_index, + + initial_memory_pages: last_entry.allocated_memory_pages, + maximal_memory_pages: self.configure_table.maximal_memory_pages, + + #[cfg(feature = "continuation")] + jops, + } + }; + + post_initialization_state + } +} diff --git a/crates/zkwasm/src/runtime/wasmi_interpreter.rs b/crates/zkwasm/src/runtime/wasmi_interpreter.rs index 2dc7e5b94..9ac65a03d 100644 --- a/crates/zkwasm/src/runtime/wasmi_interpreter.rs +++ b/crates/zkwasm/src/runtime/wasmi_interpreter.rs @@ -1,10 +1,12 @@ use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; +use std::sync::Arc; use anyhow::Result; use specs::host_function::HostFunctionDesc; use specs::jtable::StaticFrameEntry; +use specs::state::InitializationState; use specs::CompilationTable; use specs::ExecutionTable; use specs::Tables; @@ -12,9 +14,9 @@ use wasmi::Externals; use wasmi::ImportResolver; use wasmi::ModuleInstance; use wasmi::RuntimeValue; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; -use crate::circuits::config::zkwasm_k; - +use super::state::UpdateCompilationTable; use super::CompiledImage; use super::ExecutionResult; @@ -71,14 +73,32 @@ impl Execution ExecutionTable { etable: tracer.etable.clone(), - jtable: tracer.jtable.clone(), + jtable: Arc::new(tracer.jtable.clone()), + } + }; + + let updated_init_memory_table = self + .tables + .update_init_memory_table(&execution_tables.etable); + + let post_image_table = { + CompilationTable { + itable: self.tables.itable.clone(), + imtable: updated_init_memory_table, + elem_table: self.tables.elem_table.clone(), + configure_table: self.tables.configure_table.clone(), + static_jtable: self.tables.static_jtable.clone(), + initialization_state: self + .tables + .update_initialization_state(&execution_tables.etable, true), } }; Ok(ExecutionResult { tables: Tables { - compilation_tables: self.tables.clone(), + compilation_tables: self.tables, execution_tables, + post_image_table, }, result, public_inputs_and_outputs: wasm_io.public_inputs_and_outputs.borrow().clone(), @@ -145,11 +165,29 @@ impl WasmiRuntime { } }; - let itable = tracer.borrow().itable.clone(); - let imtable = tracer.borrow().imtable.finalized(zkwasm_k()); - let elem_table = tracer.borrow().elem_table.clone(); - let configure_table = tracer.borrow().configure_table.clone(); - let static_jtable = tracer.borrow().static_jtable_entries.clone(); + let itable = Arc::new(tracer.borrow().itable.clone()); + let imtable = tracer.borrow().imtable.finalized(); + let elem_table = Arc::new(tracer.borrow().elem_table.clone()); + let configure_table = Arc::new(tracer.borrow().configure_table.clone()); + let static_jtable = Arc::new(tracer.borrow().static_jtable_entries.clone()); + let initialization_state = InitializationState { + eid: 1, + fid: fid_of_entry, + iid: 0, + frame_id: 0, + sp: DEFAULT_VALUE_STACK_LIMIT as u32 - 1, + + host_public_inputs: 1, + context_in_index: 1, + context_out_index: 1, + external_host_call_call_index: 1, + + initial_memory_pages: configure_table.init_memory_pages, + maximal_memory_pages: configure_table.maximal_memory_pages, + + #[cfg(feature = "continuation")] + jops: 0, + }; Ok(CompiledImage { entry: entry.to_owned(), @@ -159,7 +197,7 @@ impl WasmiRuntime { elem_table, configure_table, static_jtable, - fid_of_entry, + initialization_state, }, instance, tracer, diff --git a/crates/zkwasm/src/test/test_uniform_verifier.rs b/crates/zkwasm/src/test/test_uniform_verifier.rs index 39d636de3..d113c6c05 100644 --- a/crates/zkwasm/src/test/test_uniform_verifier.rs +++ b/crates/zkwasm/src/test/test_uniform_verifier.rs @@ -33,7 +33,6 @@ fn setup_uniform_verifier() -> Result<(Params, ProvingKey)> let builder = ZkWasmCircuitBuilder { tables: execution_result.tables, - public_inputs_and_outputs: execution_result.public_inputs_and_outputs, }; let circuit: TestCircuit = builder.build_circuit(); @@ -135,7 +134,6 @@ mod tests { let builder = ZkWasmCircuitBuilder { tables: execution_result.tables, - public_inputs_and_outputs: execution_result.public_inputs_and_outputs, }; let proof = { diff --git a/third-party/wasmi b/third-party/wasmi index 339c17f57..83b80ed0d 160000 --- a/third-party/wasmi +++ b/third-party/wasmi @@ -1 +1 @@ -Subproject commit 339c17f5767776a21dd98a57265ded44ab2e717e +Subproject commit 83b80ed0d7957f3f9a3f65f7e9d22c884306873f