From cbb0f3c4cb730a18a497d7dc41c35b047ad25724 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 14 Nov 2023 22:53:17 +0800 Subject: [PATCH 01/28] feat: support continuation --- Cargo.lock | 3 +- Cargo.toml | 3 +- crates/cli/src/exec.rs | 2 +- crates/specs/Cargo.toml | 1 + crates/specs/src/encode/image_table.rs | 15 +- crates/specs/src/encode/init_memory_table.rs | 35 +- crates/specs/src/etable.rs | 4 + crates/specs/src/imtable.rs | 142 +------ crates/specs/src/lib.rs | 24 +- crates/specs/src/state.rs | 6 +- crates/zkwasm/Cargo.toml | 2 +- crates/zkwasm/src/circuits/config.rs | 4 - .../zkwasm/src/circuits/etable/allocator.rs | 39 +- crates/zkwasm/src/circuits/etable/assign.rs | 219 +++++++--- crates/zkwasm/src/circuits/etable/mod.rs | 69 ++-- .../zkwasm/src/circuits/image_table/assign.rs | 198 +++++---- .../src/circuits/image_table/configure.rs | 31 +- crates/zkwasm/src/circuits/image_table/mod.rs | 137 +++++-- crates/zkwasm/src/circuits/jtable/assign.rs | 46 +-- crates/zkwasm/src/circuits/mod.rs | 11 +- .../zkwasm/src/circuits/mtable/allocator.rs | 6 +- crates/zkwasm/src/circuits/mtable/assign.rs | 167 ++++++-- crates/zkwasm/src/circuits/mtable/mod.rs | 167 ++++++-- .../circuits/post_image_table/continuation.rs | 385 ++++++++++++++++++ .../src/circuits/post_image_table/mod.rs | 53 +++ .../src/circuits/post_image_table/trivial.rs | 54 +++ .../zkwasm/src/circuits/test_circuit/mod.rs | 200 +++++---- .../zkwasm/src/circuits/utils/table_entry.rs | 7 +- crates/zkwasm/src/continuation/loader.rs | 18 + crates/zkwasm/src/continuation/mod.rs | 2 + crates/zkwasm/src/continuation/slice.rs | 127 ++++++ crates/zkwasm/src/lib.rs | 5 +- crates/zkwasm/src/loader/mod.rs | 26 +- crates/zkwasm/src/runtime/state.rs | 76 +--- .../zkwasm/src/runtime/wasmi_interpreter.rs | 5 +- crates/zkwasm/src/test/mod.rs | 5 +- crates/zkwasm/src/test/test_rlp_slice.rs | 189 +++++++++ .../zkwasm/src/test/test_uniform_verifier.rs | 4 +- third-party/wasmi | 2 +- 39 files changed, 1852 insertions(+), 637 deletions(-) create mode 100644 crates/zkwasm/src/circuits/post_image_table/continuation.rs create mode 100644 crates/zkwasm/src/circuits/post_image_table/mod.rs create mode 100644 crates/zkwasm/src/circuits/post_image_table/trivial.rs create mode 100644 crates/zkwasm/src/continuation/loader.rs create mode 100644 crates/zkwasm/src/continuation/mod.rs create mode 100644 crates/zkwasm/src/continuation/slice.rs create mode 100644 crates/zkwasm/src/test/test_rlp_slice.rs diff --git a/Cargo.lock b/Cargo.lock index 71bd7c78b..c389443d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -741,7 +741,7 @@ dependencies = [ [[package]] name = "halo2_proofs" version = "0.1.0-beta.1" -source = "git+https://github.com/DelphinusLab/halo2-gpu-specific.git#64ccffddc97faff24a00d248270fe84f6693c130" +source = "git+https://github.com/DelphinusLab/halo2-gpu-specific.git#9ac108049b488df640eecdd5eb18751062442898" dependencies = [ "ark-std", "blake2b_simd", @@ -1661,6 +1661,7 @@ dependencies = [ name = "specs" version = "0.1.0" dependencies = [ + "cfg-if 1.0.0", "halo2_proofs", "lazy_static", "num-bigint", diff --git a/Cargo.toml b/Cargo.toml index 275fbbfbc..0cb2bac1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ exclude = ["third-party/wasmi", "crates/playground"] [workspace.dependencies] anyhow = { version = "1.0.68", features = ["backtrace"] } +cfg-if = "1.0.0" halo2aggregator-s = { git = "https://github.com/DelphinusLab/halo2aggregator-s.git", branch = "main", features = ["unsafe"] } halo2_proofs = { git = "https://github.com/DelphinusLab/halo2-gpu-specific.git", default-features = true } parity-wasm = { version = "0.42.0", features = ["sign_ext"] } @@ -11,4 +12,4 @@ rayon = "1.8.0" wasmi = { path = "third-party/wasmi" } [profile.dev] -opt-level = 3 +opt-level = 3 \ No newline at end of file diff --git a/crates/cli/src/exec.rs b/crates/cli/src/exec.rs index 9014faaf5..e5d0ec7b3 100644 --- a/crates/cli/src/exec.rs +++ b/crates/cli/src/exec.rs @@ -78,7 +78,7 @@ pub fn exec_setup( info!("Create Verifying to {:?}", vk_path); let loader = ZkWasmLoader::::new(zkwasm_k, wasm_binary, phantom_functions)?; - let vkey = loader.create_vkey(¶ms)?; + let vkey = loader.create_vkey(¶ms, true)?; let mut fd = std::fs::File::create(&vk_path)?; vkey.write(&mut fd)?; diff --git a/crates/specs/Cargo.toml b/crates/specs/Cargo.toml index 578478fc8..d19e1db49 100644 --- a/crates/specs/Cargo.toml +++ b/crates/specs/Cargo.toml @@ -12,6 +12,7 @@ serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" strum = "0.24.1" strum_macros = "0.24.1" +cfg-if.workspace = true halo2_proofs.workspace = true parity-wasm.workspace = true rayon.workspace = true diff --git a/crates/specs/src/encode/image_table.rs b/crates/specs/src/encode/image_table.rs index 032bfc0ec..8a8182049 100644 --- a/crates/specs/src/encode/image_table.rs +++ b/crates/specs/src/encode/image_table.rs @@ -1,3 +1,4 @@ +use num_bigint::BigUint; use num_bigint::ToBigUint; use crate::encode::br_table::BR_TABLE_ENCODE_BOUNDARY; @@ -6,7 +7,7 @@ use crate::encode::instruction_table::INSTRUCTION_ENCODE_BOUNDARY; use super::FromBn; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub enum ImageTableEncoder { Instruction = 1, BrTable = 2, @@ -21,8 +22,14 @@ impl ImageTableEncoder { assert!(BR_TABLE_ENCODE_BOUNDARY <= CLASS_SHIFT); assert!(INIT_MEMORY_ENCODE_BOUNDARY <= CLASS_SHIFT); - T::from_bn(&(*self as u64).to_biguint().unwrap()) - * T::from_bn(&(1u64.to_biguint().unwrap() << CLASS_SHIFT)) - + data + let tag = if cfg!(feature = "continuation") && *self == ImageTableEncoder::InitMemory { + // Memory Initialization Lookup with continuation + T::from_bn(&BigUint::zero()) + } else { + T::from_bn(&(*self as u64).to_biguint().unwrap()) + * T::from_bn(&(1u64.to_biguint().unwrap() << CLASS_SHIFT)) + }; + + tag + data } } diff --git a/crates/specs/src/encode/init_memory_table.rs b/crates/specs/src/encode/init_memory_table.rs index 949c2e2ff..f3a59e5f2 100644 --- a/crates/specs/src/encode/init_memory_table.rs +++ b/crates/specs/src/encode/init_memory_table.rs @@ -2,43 +2,48 @@ use num_bigint::BigUint; use num_bigint::ToBigUint; use super::FromBn; -use crate::encode::COMMON_RANGE_OFFSET; use crate::imtable::InitMemoryTableEntry; pub(crate) const INIT_MEMORY_ENCODE_BOUNDARY: u32 = 224; +pub fn encode_init_memory_table_address(location_type: T, offset: T) -> T { + location_type * T::from_bn(&(1u64.to_biguint().unwrap() << 32)) + offset +} + pub fn encode_init_memory_table_entry( ltype: T, + offset: T, is_mutable: T, - start_offset: T, - end_offset: T, eid: T, value: T, ) -> T { - 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 + COMMON_RANGE_OFFSET; - const END_OFFSET_SHIFT: u32 = EID_OFFSET_SHIFT + 32; + const LTYPE_SHIFT: u32 = OFFSET_SHIFT + 32; + const OFFSET_SHIFT: u32 = IS_MUTABLE_SHIFT + 1; + const IS_MUTABLE_SHIFT: u32 = EID_OFFSET_SHIFT + 32; const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + 64; const VALUE_SHIFT: u32 = 0; 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 + if cfg!(feature = "continuation") { + ltype * T::from_bn(&(1u64.to_biguint().unwrap() << LTYPE_SHIFT)) + + offset * T::from_bn(&(1u64.to_biguint().unwrap() << OFFSET_SHIFT)) + + is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) + + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) + + value + } else { + is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) + + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) + + value + } } impl InitMemoryTableEntry { pub fn encode(&self) -> BigUint { encode_init_memory_table_entry( BigUint::from(self.ltype as u32), + BigUint::from(self.offset), 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/etable.rs b/crates/specs/src/etable.rs index dfa4ef695..8824e8864 100644 --- a/crates/specs/src/etable.rs +++ b/crates/specs/src/etable.rs @@ -46,6 +46,10 @@ impl EventTable { Self(entries) } + pub fn unwrap(self) -> Vec { + self.0 + } + pub fn entries(&self) -> &Vec { &self.0 } diff --git a/crates/specs/src/imtable.rs b/crates/specs/src/imtable.rs index bc7b6a9eb..f61b00874 100644 --- a/crates/specs/src/imtable.rs +++ b/crates/specs/src/imtable.rs @@ -1,4 +1,3 @@ -use std::cmp::Ordering; use std::collections::BTreeMap; use crate::mtable::LocationType; @@ -9,8 +8,7 @@ use serde::Serialize; pub struct InitMemoryTableEntry { pub ltype: LocationType, pub is_mutable: bool, - pub start_offset: u32, - pub end_offset: u32, + pub offset: u32, pub vtype: VarType, /// convert from [u8; 8] via u64::from_le_bytes pub value: u64, @@ -18,142 +16,28 @@ pub struct InitMemoryTableEntry { } #[derive(Serialize, Default, Debug, Clone)] -pub struct InitMemoryTable { - entries: Vec, - sorted_global_init_entries: BTreeMap, - sorted_stack_init_entries: BTreeMap, - sorted_heap_init_entries: Vec, -} +pub struct InitMemoryTable(pub BTreeMap<(LocationType, u32), InitMemoryTableEntry>); impl InitMemoryTable { - 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 { - 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, - }); - } + pub fn new(entries: Vec) -> Self { + let mut map = BTreeMap::new(); - merged_entries - } + entries.into_iter().for_each(|entry| { + map.insert((entry.ltype, entry.offset), entry); + }); - 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(); - let sorted_global_init_entries = entries - .iter() - .filter(|entry| entry.ltype == LocationType::Global) - .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(); - - InitMemoryTable { - entries, - sorted_global_init_entries, - sorted_stack_init_entries, - sorted_heap_init_entries, - } + Self(map) } - pub fn entries(&self) -> &Vec { - &self.entries + pub fn entries(&self) -> &BTreeMap<(LocationType, u32), InitMemoryTableEntry> { + &self.0 } pub fn to_string(&self) -> String { - serde_json::to_string(&self.entries).unwrap() - } - - pub fn try_find(&self, ltype: LocationType, offset: u32) -> Option<(u32, u32, u32, u64)> { - match ltype { - LocationType::Heap => { - let idx = self - .sorted_heap_init_entries - .binary_search_by(|entry| { - if offset >= entry.start_offset && offset <= entry.end_offset { - Ordering::Equal - } else if offset < entry.start_offset { - Ordering::Greater - } else { - Ordering::Less - } - }) - .unwrap(); - - 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 => { - return self - .sorted_global_init_entries - .get(&offset) - .map(|entry| (entry.start_offset, entry.end_offset, entry.eid, entry.value)); - } - LocationType::Stack => { - return self - .sorted_stack_init_entries - .get(&offset) - .map(|entry| (entry.start_offset, entry.end_offset, entry.eid, entry.value)); - } - } + serde_json::to_string(&self.0).unwrap() } - pub fn filter(&self, ltype: LocationType) -> Vec<&InitMemoryTableEntry> { - self.entries.iter().filter(|e| e.ltype == ltype).collect() + pub fn try_find(&self, ltype: LocationType, offset: u32) -> Option<&InitMemoryTableEntry> { + self.0.get(&(ltype, offset)) } } diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index bbc65227a..97c65d416 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -57,11 +57,23 @@ pub struct ExecutionTable { pub jtable: Arc, } -#[derive(Default, Clone)] +#[derive(Clone)] pub struct Tables { pub compilation_tables: CompilationTable, pub execution_tables: ExecutionTable, pub post_image_table: CompilationTable, + pub is_last_slice: bool, +} + +impl Tables { + pub fn default(last_slice_circuit: bool) -> Self { + Self { + compilation_tables: CompilationTable::default(), + execution_tables: ExecutionTable::default(), + post_image_table: CompilationTable::default(), + is_last_slice: last_slice_circuit, + } + } } impl Tables { @@ -93,15 +105,15 @@ impl Tables { .iter() .zip(init_value.into_iter()) .for_each(|(entry, init_memory_entry)| { - if let Some((_, _, eid, value)) = init_memory_entry { + if let Some(init_memory_entry) = init_memory_entry { set.insert(MemoryTableEntry { - eid, + eid: init_memory_entry.eid, offset: entry.offset, ltype: entry.ltype, atype: AccessType::Init, vtype: entry.vtype, is_mutable: entry.is_mutable, - value, + value: init_memory_entry.value, }); } }); @@ -124,7 +136,7 @@ impl Tables { } let itable = serde_json::to_string_pretty(&self.compilation_tables.itable).unwrap(); - let imtable = serde_json::to_string_pretty(&self.compilation_tables.imtable).unwrap(); + // let imtable = serde_json::to_string_pretty(&self.compilation_tables.imtable).unwrap(); let etable = serde_json::to_string_pretty(&self.execution_tables.etable).unwrap(); let external_host_call_table = serde_json::to_string_pretty( &self @@ -137,7 +149,7 @@ impl Tables { let dir = dir.unwrap_or(env::current_dir().unwrap()); write_file(&dir, "itable.json", &itable); - write_file(&dir, "imtable.json", &imtable); + // write_file(&dir, "imtable.json", &imtable); write_file(&dir, "etable.json", &etable); write_file(&dir, "jtable.json", &jtable); write_file(&dir, "external_host_table.json", &external_host_call_table); diff --git a/crates/specs/src/state.rs b/crates/specs/src/state.rs index a64c67559..8b0144e0a 100644 --- a/crates/specs/src/state.rs +++ b/crates/specs/src/state.rs @@ -67,7 +67,11 @@ impl InitializationState { v } - pub fn map(&self, f: impl Fn(&T) -> U) -> InitializationState { + pub fn for_each(&self, f: impl FnMut(&T) -> U) { + self.map(f); + } + + pub fn map(&self, mut f: impl FnMut(&T) -> U) -> InitializationState { InitializationState { eid: f(&self.eid), fid: f(&self.fid), diff --git a/crates/zkwasm/Cargo.toml b/crates/zkwasm/Cargo.toml index e98e2c54a..f07d0f752 100644 --- a/crates/zkwasm/Cargo.toml +++ b/crates/zkwasm/Cargo.toml @@ -8,7 +8,6 @@ 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" @@ -24,6 +23,7 @@ strum_macros = "0.24.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow.workspace = true +cfg-if.workspace = true halo2aggregator-s.workspace = true halo2_proofs.workspace = true parity-wasm.workspace = true diff --git a/crates/zkwasm/src/circuits/config.rs b/crates/zkwasm/src/circuits/config.rs index 98e208136..cff1c1714 100644 --- a/crates/zkwasm/src/circuits/config.rs +++ b/crates/zkwasm/src/circuits/config.rs @@ -24,7 +24,3 @@ pub fn zkwasm_k() -> u32 { pub fn init_zkwasm_runtime(k: u32) { set_zkwasm_k(k); } - -pub(crate) fn max_image_table_rows() -> u32 { - 8192 -} diff --git a/crates/zkwasm/src/circuits/etable/allocator.rs b/crates/zkwasm/src/circuits/etable/allocator.rs index aad01b045..5a44429a4 100644 --- a/crates/zkwasm/src/circuits/etable/allocator.rs +++ b/crates/zkwasm/src/circuits/etable/allocator.rs @@ -91,8 +91,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: AllocatedCommonRangeCell, - pub(crate) end_eid_diff_cell: AllocatedCommonRangeCell, + pub(crate) start_eid_diff_cell: AllocatedU32StateCell, + pub(crate) end_eid_diff_cell: AllocatedU32StateCell, pub(crate) value_cell: AllocatedUnlimitedCell, } @@ -125,10 +125,16 @@ impl AllocatedMemoryTableLookupReadCell { ), )?; self.start_eid_cell.assign_u32(ctx, start_eid)?; - self.start_eid_diff_cell - .assign_u32(ctx, eid - start_eid - 1)?; + cfg_if::cfg_if! { + if #[cfg(feature="continuation")] { + self.start_eid_diff_cell.assign(ctx, eid - start_eid - 1)?; + self.end_eid_diff_cell.assign(ctx, end_eid - eid)?; + } else { + self.start_eid_diff_cell.assign_u32(ctx, eid - start_eid - 1)?; + self.end_eid_diff_cell.assign_u32(ctx, end_eid - eid)?; + } + } self.end_eid_cell.assign_u32(ctx, end_eid)?; - self.end_eid_diff_cell.assign_u32(ctx, end_eid - eid)?; self.value_cell.assign(ctx, value.into())?; Ok(()) @@ -175,12 +181,19 @@ pub(crate) enum EventTableCellType { const BIT_COLUMNS: usize = 12; const U8_COLUMNS: usize = 1; -// Should be the multiple of 2. -const U32_CELLS: usize = 2; +const U32_CELLS: usize = if cfg!(feature = "continuation") { + 10 +} else { + 0 +}; const U64_CELLS: usize = 5; const U16_COLUMNS: usize = U64_CELLS + (U32_CELLS / 2); -const COMMON_RANGE_COLUMNS: usize = 7; -const UNLIMITED_COLUMNS: usize = 8; +const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 5 } else { 7 }; +const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { + 10 +} else { + 7 +}; const MEMORY_TABLE_LOOKUP_COLUMNS: usize = 2; const JUMP_TABLE_LOOKUP_COLUMNS: usize = 1; @@ -499,8 +512,8 @@ impl EventTableCellAllocator { end_eid_cell: cells[1], encode_cell: cells[2], value_cell: cells[3], - start_eid_diff_cell: self.alloc_common_range_cell(), - end_eid_diff_cell: self.alloc_common_range_cell(), + start_eid_diff_cell: self.alloc_u32_state_cell(), + end_eid_diff_cell: self.alloc_u32_state_cell(), }; constraint_builder.constraints.push(( @@ -589,8 +602,8 @@ impl EventTableCellAllocator { end_eid_cell: cells[1], encode_cell: cells[2], value_cell: cells[3], - start_eid_diff_cell: self.alloc_common_range_cell(), - end_eid_diff_cell: self.alloc_common_range_cell(), + start_eid_diff_cell: self.alloc_u32_state_cell(), + end_eid_diff_cell: self.alloc_u32_state_cell(), }; constraint_builder.constraints.push(( diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index 0904445d1..85ff77263 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -1,5 +1,5 @@ use halo2_proofs::arithmetic::FieldExt; -use halo2_proofs::circuit::Cell; +use halo2_proofs::circuit::AssignedCell; use halo2_proofs::plonk::Error; use log::debug; use specs::configure_table::ConfigureTable; @@ -19,12 +19,37 @@ use crate::circuits::utils::step_status::StepStatus; use crate::circuits::utils::table_entry::EventTableWithMemoryInfo; 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, - // TODO - // pub(in crate::circuits) post_initialization_state: InitializationState, +/* + * Etable Layouter with Continuation + * + * Not last slice + * | ---- | ------ | ---------- | --------- | + * | sel | enable | rest_mops | states ... | + * | ---- + ------ | ---------- + --------- | + * | 1 | 1 | | ... | + * | 1 | 1 | | ... | + * | 1 | 1 | | ... | + * | 0 | 0 | constant 0 | ... | permutation row(status should keep consistent with previous row) + * + * + * Not last slice + * | ---- | ------ | ---------- | ------ | + * | sel | enable | rest_mops | states | + * | ---- + ------ | ---------- + -------| + * | 1 | 1 | | ... | + * | 1 | 1 | | ... | + * | 1 | 0 | | ... | + * | 1 | 0 | | ... | + * | 1 | 0 | | ... | + * | 1 | 0 | | ... | + * | 0 | 0 | constant 0 | ... | permutation row + */ + +pub(in crate::circuits) struct EventTablePermutationCells { + pub(in crate::circuits) rest_mops: Option>, + pub(in crate::circuits) rest_jops: Option>, + pub(in crate::circuits) pre_initialization_state: InitializationState>, + pub(in crate::circuits) post_initialization_state: InitializationState>, } impl EventTableChip { @@ -38,7 +63,6 @@ impl EventTableChip { 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())) @@ -60,9 +84,7 @@ impl EventTableChip { } fn init(&self, ctx: &mut Context<'_, F>) -> Result<(), Error> { - let capability = self.max_available_rows / EVENT_TABLE_ENTRY_ROWS as usize; - - for _ in 0..capability { + for _ in 0..self.capability { ctx.region.assign_fixed( || "etable: step sel", self.config.step_sel, @@ -92,7 +114,10 @@ impl EventTableChip { } // 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> { + fn assign_rest_ops_first_step( + &self, + ctx: &mut Context<'_, F>, + ) -> Result<(AssignedCell, AssignedCell), Error> { let rest_mops_cell = self .config .common_config @@ -101,19 +126,19 @@ impl EventTableChip { let rest_jops_cell = self.config.common_config.jops_cell.assign(ctx, F::zero())?; - Ok((rest_mops_cell.cell(), rest_jops_cell.cell())) + Ok((rest_mops_cell, rest_jops_cell)) } fn assign_initialization_state( &self, ctx: &mut Context<'_, F>, initialization_state: &InitializationState, - ) -> Result, Error> { + ) -> 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() + self.config.common_config.$cell.assign(ctx, $value)? } } } else { @@ -131,7 +156,6 @@ impl EventTableChip { .common_config .$cell .assign(ctx, F::from($value as u64))? - .cell() }; } @@ -186,6 +210,105 @@ impl EventTableChip { }) } + fn assign_post_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)? + }; + } + } else { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + self.config.common_config.$cell.assign_u32(ctx, $value)? + }; + } + } + } + + macro_rules! assign_common_range_advice { + ($cell:ident, $value:expr) => { + self.config + .common_config + .$cell + .assign(ctx, F::from($value as u64))? + }; + } + + macro_rules! assign_one_step { + () => {{ + 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); + + 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, + } + }}; + } + + while ctx.offset < self.capability * EVENT_TABLE_ENTRY_ROWS as usize { + assign_one_step!(); + + ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); + } + + let post_initialization_state = assign_one_step!(); + + Ok(post_initialization_state) + } + fn assign_entries( &self, ctx: &mut Context<'_, F>, @@ -270,7 +393,7 @@ impl EventTableChip { { *drop } else { - unreachable!() + 0 }, last_jump_eid: 0, allocated_memory_pages: status.last().unwrap().allocated_memory_pages, @@ -352,28 +475,6 @@ impl EventTableChip { ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); } - // Assign terminate status - 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_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) - ); - assign_advice!( - maximal_memory_pages_cell, - F::from(configure_table.maximal_memory_pages 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)); - assign_advice!( - external_host_call_index_cell, - F::from(external_host_call_call_index as u64) - ); - Ok(()) } @@ -383,14 +484,16 @@ impl EventTableChip { event_table: &EventTableWithMemoryInfo, configure_table: &ConfigureTable, initialization_state: &InitializationState, - ) -> Result { + post_initialization_state: &InitializationState, + _is_last_slice: bool, + ) -> Result, Error> { debug!("size of execution table: {}", event_table.0.len()); - assert!(event_table.0.len() * EVENT_TABLE_ENTRY_ROWS as usize <= self.max_available_rows); + assert!(event_table.0.len() <= self.capability); self.init(ctx)?; ctx.reset(); - let (rest_mops_cell, jops_cell) = self.assign_rest_ops_first_step(ctx)?; + let (rest_mops_cell, _jops_cell) = self.assign_rest_ops_first_step(ctx)?; let (rest_mops, jops) = self.compute_rest_mops_and_jops( &self.config.op_configs, @@ -411,16 +514,30 @@ impl EventTableChip { rest_mops, jops, )?; - ctx.reset(); - Ok(EventTablePermutationCells { - rest_mops: Some(rest_mops_cell), - pre_initialization_state: pre_initialization_state_cells, - rest_jops: if cfg!(feature = "continuation") { - Some(jops_cell) + let post_initialization_state_cells = + self.assign_post_initialization_state(ctx, &post_initialization_state)?; + + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + Ok(EventTablePermutationCells { + rest_mops: Some(rest_mops_cell), + rest_jops: if _is_last_slice { + Some(post_initialization_state_cells.jops.clone()) + } else { + None + }, + pre_initialization_state: pre_initialization_state_cells, + post_initialization_state: post_initialization_state_cells, + }) } else { - None - }, - }) + Ok(EventTablePermutationCells { + rest_mops: Some(rest_mops_cell), + rest_jops: Some(_jops_cell), + pre_initialization_state: pre_initialization_state_cells, + post_initialization_state: post_initialization_state_cells, + }) + } + } } } diff --git a/crates/zkwasm/src/circuits/etable/mod.rs b/crates/zkwasm/src/circuits/etable/mod.rs index ae40cc599..fb68ba3cc 100644 --- a/crates/zkwasm/src/circuits/etable/mod.rs +++ b/crates/zkwasm/src/circuits/etable/mod.rs @@ -55,6 +55,7 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; +use num_integer::Integer; use specs::encode::instruction_table::encode_instruction_table_entry; use specs::etable::EventTableEntry; use specs::itable::OpcodeClass; @@ -389,10 +390,10 @@ impl EventTableConfig { .into_iter() .reduce(|acc, x| acc + x) .unwrap() - - enabled_cell.curr_expr(meta), + - constant_from!(1), ] .into_iter() - .map(|expr| expr * fixed_curr!(meta, step_sel)) + .map(|expr| expr * enabled_cell.curr_expr(meta) * fixed_curr!(meta, step_sel)) .collect::>() }); @@ -445,7 +446,7 @@ impl EventTableConfig { )] }); - meta.create_gate("c5b. rest_jops change", |meta| { + meta.create_gate("c5b. jops change(increase if continuation)", |meta| { vec![sum_ops_expr_with_init( if cfg!(feature = "continuation") { jops_cell.curr_expr(meta) - jops_cell.next_expr(meta) @@ -465,7 +466,8 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.input_index_increase(meta, &common_config) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -477,7 +479,8 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.external_host_call_index_increase(meta, &common_config) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + //Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -486,7 +489,8 @@ impl EventTableConfig { sp_cell.curr_expr(meta) - sp_cell.next_expr(meta), meta, &|meta, config: &Rc>>| config.sp_diff(meta), - Some(&|meta| enabled_cell.curr_expr(meta)), + //Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -497,7 +501,8 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.allocated_memory_pages_diff(meta) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -508,7 +513,8 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.context_input_index_increase(meta, &common_config) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + //Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -520,14 +526,16 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.context_output_index_increase(meta, &common_config) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); meta.create_gate("c6a. eid change", |meta| { vec![ - (eid_cell.next_expr(meta) - eid_cell.curr_expr(meta) - constant_from!(1)) - * enabled_cell.curr_expr(meta) + (eid_cell.next_expr(meta) + - eid_cell.curr_expr(meta) + - enabled_cell.curr_expr(meta)) * fixed_curr!(meta, step_sel), ] }); @@ -541,20 +549,22 @@ impl EventTableConfig { .next_fid(meta, &common_config) .map(|x| x - fid_cell.curr_expr(meta)) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); meta.create_gate("c6c. iid change", |meta| { vec![sum_ops_expr_with_init( - iid_cell.next_expr(meta) - iid_cell.curr_expr(meta) - constant_from!(1), + iid_cell.next_expr(meta) - iid_cell.curr_expr(meta) - enabled_cell.curr_expr(meta), meta, &|meta, config: &Rc>>| { config .next_iid(meta, &common_config) - .map(|x| iid_cell.curr_expr(meta) + constant_from!(1) - x) + .map(|x| iid_cell.curr_expr(meta) + enabled_cell.curr_expr(meta) - x) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -567,7 +577,8 @@ impl EventTableConfig { .next_frame_id(meta, &common_config) .map(|x| x - frame_id_cell.curr_expr(meta)) }, - Some(&|meta| enabled_cell.curr_expr(meta)), + // Some(&|meta| enabled_cell.curr_expr(meta)), + None, )] }); @@ -623,7 +634,7 @@ impl EventTableConfig { vec![ (maximal_memory_pages_cell.next_expr(meta) - maximal_memory_pages_cell.curr_expr(meta)) - * enabled_cell.expr(meta) +// * enabled_cell.expr(meta) * fixed_curr!(meta, step_sel), ] }); @@ -638,15 +649,25 @@ impl EventTableConfig { pub struct EventTableChip { config: EventTableConfig, - max_available_rows: usize, + // The maximal number of entries(which sel = 1) of etable + capability: usize, } impl EventTableChip { - pub(super) fn new(config: EventTableConfig, max_available_rows: usize) -> Self { - Self { - config, - max_available_rows: max_available_rows / EVENT_TABLE_ENTRY_ROWS as usize - * EVENT_TABLE_ENTRY_ROWS as usize, - } + pub(super) fn new( + config: EventTableConfig, + slice_capability: Option, + max_available_rows: usize, + ) -> Self { + let capability = if let Some(slice_capability) = slice_capability { + assert!(slice_capability * EVENT_TABLE_ENTRY_ROWS as usize <= max_available_rows); + + slice_capability + } else { + max_available_rows.prev_multiple_of(&(EVENT_TABLE_ENTRY_ROWS as usize)) + / EVENT_TABLE_ENTRY_ROWS as usize + }; + + Self { config, capability } } } diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 7e898f102..eff3c4544 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -1,5 +1,5 @@ use halo2_proofs::arithmetic::FieldExt; -use halo2_proofs::circuit::Cell; +use halo2_proofs::circuit::AssignedCell; use halo2_proofs::circuit::Layouter; use halo2_proofs::plonk::Advice; use halo2_proofs::plonk::Column; @@ -8,6 +8,7 @@ use specs::state::InitializationState; use super::ImageTableChip; use super::ImageTableLayouter; +use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::utils::Context; impl ImageTableChip { @@ -15,100 +16,151 @@ impl ImageTableChip { self, layouter: &mut impl Layouter, image_table: ImageTableLayouter, - permutation_cells: ImageTableLayouter, - ) -> Result<(), Error> { + permutation_cells: ImageTableLayouter>, + ) -> Result>, Error> { + macro_rules! assign { + ($ctx:expr, $col:expr, $v:expr) => {{ + let cell = + $ctx.region + .assign_advice(|| "image table", $col, $ctx.offset, || Ok($v))?; + + $ctx.next(); + + Ok::, Error>(cell) + }}; + } + fn assign_and_perm_initialization_state( ctx: &mut Context, col: Column, - initialization_state: &InitializationState, - permutation_cells: &InitializationState, + initialization_state: &InitializationState>, + ) -> Result>, Error> { + let initialization_state = initialization_state.map(|field| { + field + .copy_advice( + || "image table: initialization state", + &mut ctx.region, + col, + ctx.offset, + ) + .unwrap(); + + ctx.next(); + + field.clone() + }); + + Ok::<_, Error>(initialization_state) + } + + fn assign_static_frame_entries( + ctx: &mut Context, + col: Column, + static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, ) -> 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(); - }; + for (enable, entry) in static_frame_entries { + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.region, + col, + ctx.offset, + )?; + ctx.next(); + + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.region, + col, + ctx.offset, + )?; + ctx.next(); } - assign_and_perm!(eid); - assign_and_perm!(fid); - assign_and_perm!(iid); - assign_and_perm!(frame_id); - assign_and_perm!(sp); + Ok(()) + } - 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); + fn assign_instructions( + ctx: &mut Context, + col: Column, + instructions: &Vec, + ) -> Result>, Error> { + let entries = instructions + .iter() + .map(|entry| assign!(ctx, col, *entry)) + .collect::, Error>>()?; + + Ok(entries) + } - assign_and_perm!(initial_memory_pages); - assign_and_perm!(maximal_memory_pages); + fn assign_br_table( + ctx: &mut Context, + col: Column, + br_table: &Vec, + ) -> Result>, Error> { + let entries = br_table + .iter() + .map(|entry| assign!(ctx, col, *entry)) + .collect::, Error>>()?; + + Ok(entries) + } - #[cfg(feature = "continuation")] - assign_and_perm!(jops); + fn assign_init_memory_entries( + ctx: &mut Context, + col: Column, + init_memory_entries: &Vec, + ) -> Result<(), Error> { + assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); + ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; + + for entry in init_memory_entries { + assign!(ctx, col, *entry)?; + } Ok(()) } layouter.assign_region( - || "image table", + || "pre image table", |region| { let mut ctx = Context::new(region); - macro_rules! assign_one_line { - ($v: expr) => {{ - let cell = ctx - .region - .assign_advice( - || "image table", - self.config.col, - ctx.offset, - || Ok($v), - )? - .cell(); - - ctx.next(); - - cell - }}; - } - - assign_and_perm_initialization_state( + let initialization_state = assign_and_perm_initialization_state( &mut ctx, self.config.col, - &image_table.initialization_state, &permutation_cells.initialization_state, )?; + assign_static_frame_entries( + &mut ctx, + self.config.col, + &permutation_cells.static_frame_entries, + )?; + let instructions = assign_instructions( + &mut ctx, + self.config.col, + image_table.instructions.as_ref().unwrap(), + ) + .ok(); + let br_table = assign_br_table( + &mut ctx, + self.config.col, + image_table.br_table.as_ref().unwrap(), + ) + .ok(); + assign_init_memory_entries( + &mut ctx, + self.config.col, + &image_table.init_memory_entries.as_ref().unwrap(), + )?; - for (static_frame_entry, cell_in_frame_table) in image_table - .static_frame_entries - .iter() - .zip(permutation_cells.static_frame_entries.iter()) - { - // Enable cell - let cell = assign_one_line!(static_frame_entry.0); - ctx.region.constrain_equal(cell, cell_in_frame_table.0)?; - - let cell = assign_one_line!(static_frame_entry.1); - ctx.region.constrain_equal(cell, cell_in_frame_table.1)?; - } - - for value in image_table.lookup_entries.as_ref().unwrap() { - assign_one_line!(*value); - } - - Ok(()) + Ok(ImageTableLayouter { + initialization_state, + static_frame_entries: permutation_cells.static_frame_entries.clone(), + instructions, + br_table, + init_memory_entries: None, + rest_memory_writing_ops: None, + }) }, ) } diff --git a/crates/zkwasm/src/circuits/image_table/configure.rs b/crates/zkwasm/src/circuits/image_table/configure.rs index 02c36cc54..14d5a880d 100644 --- a/crates/zkwasm/src/circuits/image_table/configure.rs +++ b/crates/zkwasm/src/circuits/image_table/configure.rs @@ -1,8 +1,10 @@ use std::marker::PhantomData; use halo2_proofs::arithmetic::FieldExt; +use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Expression; +use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; use specs::encode::image_table::ImageTableEncoder; @@ -11,10 +13,14 @@ use super::IMAGE_COL_NAME; use crate::curr; impl ImageTableConfig { - pub(in crate::circuits) fn configure(meta: &mut ConstraintSystem) -> Self { + pub(in crate::circuits) fn configure( + meta: &mut ConstraintSystem, + _memory_addr_sel: Column, + ) -> Self { let col = meta.named_advice_column(IMAGE_COL_NAME.to_owned()); meta.enable_equality(col); Self { + _memory_addr_sel, col, _mark: PhantomData, } @@ -34,6 +40,29 @@ impl ImageTableConfig { }); } + #[cfg(feature = "continuation")] + pub fn init_memory_lookup( + &self, + meta: &mut ConstraintSystem, + 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); + + vec![ + (addr, fixed_curr!(meta, self._memory_addr_sel)), + ( + ImageTableEncoder::InitMemory.encode(encode), + curr!(meta, self.col), + ), + ] + }); + } + + #[cfg(not(feature = "continuation"))] pub fn init_memory_lookup( &self, meta: &mut ConstraintSystem, diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index 8f25c8726..a53aaf726 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -1,6 +1,9 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::plonk::Advice; use halo2_proofs::plonk::Column; +use halo2_proofs::plonk::Expression; +use halo2_proofs::plonk::Fixed; +use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; use specs::brtable::BrTable; use specs::brtable::ElemTable; @@ -12,30 +15,72 @@ use specs::mtable::LocationType; use specs::state::InitializationState; use specs::CompilationTable; use std::marker::PhantomData; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; -use crate::circuits::config::max_image_table_rows; +use crate::circuits::config::zkwasm_k; use crate::circuits::utils::bn_to_field; +use crate::curr; + +use super::test_circuit::RESERVE_ROWS; mod assign; mod configure; pub const IMAGE_COL_NAME: &str = "img_col"; +pub const INIT_MEMORY_ENTRIES_OFFSET: usize = 40960; +/* + * 8192: 64 * 1024 / 8 + * A page is 64KB, an entry is 8B + */ +pub const PAGE_ENTRIES: u32 = 8192; + +/// Compute maximal number of pages supported by the circuit. +/// circuit size - reserved rows for blind - initialization_state/static frame entries/instructions/br_table +/// - stack entries - global entries +pub fn compute_maximal_pages(k: u32) -> u32 { + let bytes: u32 = + ((1usize << k) - RESERVE_ROWS - INIT_MEMORY_ENTRIES_OFFSET - DEFAULT_VALUE_STACK_LIMIT * 2) + .try_into() + .unwrap(); + + let pages = bytes / PAGE_ENTRIES; + + pages +} + +pub(crate) struct InitMemoryLayouter { + pub(crate) stack: u32, + pub(crate) global: u32, + pub(crate) pages: u32, +} + +impl InitMemoryLayouter { + fn for_each(self, mut f: impl FnMut((LocationType, u32))) { + for offset in 0..self.stack { + f((LocationType::Stack, offset)) + } + + for offset in 0..self.global { + f((LocationType::Global, offset)) + } + + for offset in 0..(self.pages * PAGE_ENTRIES) { + f((LocationType::Heap, offset)) + } + } +} pub struct ImageTableLayouter { pub initialization_state: InitializationState, pub static_frame_entries: Vec<(T, T)>, - /* - * include: - * instruction table - * br table - * elem table - * init memory table - */ - pub lookup_entries: Option>, + pub instructions: Option>, + pub br_table: Option>, + pub init_memory_entries: Option>, + pub rest_memory_writing_ops: Option, } -impl ImageTableLayouter { - pub fn plain(&self) -> Vec { +impl ImageTableLayouter { + pub fn plain(&self) -> Vec { let mut buf = vec![]; buf.append(&mut self.initialization_state.plain()); @@ -49,7 +94,10 @@ impl ImageTableLayouter { .collect::>>() .concat(), ); - buf.append(&mut self.lookup_entries.clone().unwrap()); + buf.append(&mut self.instructions.clone().unwrap()); + buf.append(&mut self.br_table.clone().unwrap()); + buf.append(&mut vec![F::zero(); INIT_MEMORY_ENTRIES_OFFSET - buf.len()]); + buf.append(&mut self.init_memory_entries.clone().unwrap()); buf } @@ -102,39 +150,29 @@ impl EncodeCompilationTableValues for CompilationTable { } fn msg_of_init_memory_table(init_memory_table: &InitMemoryTable) -> Vec { - let heap_entries = init_memory_table.filter(LocationType::Heap); - let global_entries = init_memory_table.filter(LocationType::Global); - let mut cells = vec![]; cells.push(bn_to_field( &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), )); - for v in heap_entries.into_iter().chain(global_entries.into_iter()) { - cells.push(bn_to_field::( - &ImageTableEncoder::InitMemory.encode(v.encode()), - )); - } - - cells - } - - fn msg_of_image_table( - instruction_table: &InstructionTable, - br_table: &BrTable, - elem_table: &ElemTable, - init_memory_table: &InitMemoryTable, - ) -> Vec { - let mut cells = vec![]; - - cells.append(&mut msg_of_instruction_table(instruction_table)); - cells.append(&mut msg_of_br_table(br_table, elem_table)); - cells.append(&mut msg_of_init_memory_table(init_memory_table)); - - for _ in cells.len()..(max_image_table_rows() as usize) { - cells.push(F::zero()); - } + let layouter = InitMemoryLayouter { + stack: DEFAULT_VALUE_STACK_LIMIT as u32, + global: DEFAULT_VALUE_STACK_LIMIT as u32, + pages: compute_maximal_pages(zkwasm_k()), + }; + + layouter.for_each(|(ltype, offset)| { + if let Some(entry) = init_memory_table.try_find(ltype, offset) { + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(entry.encode()), + )); + } else { + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), + )); + } + }); cells } @@ -170,27 +208,38 @@ impl EncodeCompilationTableValues for CompilationTable { let initialization_state = msg_of_initialization_state(&self.initialization_state); let static_frame_entries = msg_of_static_frame_table(&self.static_jtable); - let lookup_entries = msg_of_image_table( - &self.itable, + + let instructions = Some(msg_of_instruction_table(&self.itable)); + let br_table = Some(msg_of_br_table( &self.itable.create_brtable(), &self.elem_table, - &self.imtable, - ); + )); + let init_memory_entries = Some(msg_of_init_memory_table(&self.imtable)); ImageTableLayouter { initialization_state, static_frame_entries, - lookup_entries: Some(lookup_entries), + instructions, + br_table, + init_memory_entries, + rest_memory_writing_ops: None, } } } #[derive(Clone)] pub struct ImageTableConfig { + _memory_addr_sel: Column, col: Column, _mark: PhantomData, } +impl ImageTableConfig { + pub fn expr(&self, meta: &mut VirtualCells) -> Expression { + curr!(meta, self.col) + } +} + #[derive(Clone)] pub struct ImageTableChip { config: ImageTableConfig, diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 837388c92..8f6afd195 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -1,5 +1,5 @@ use halo2_proofs::arithmetic::FieldExt; -use halo2_proofs::circuit::Cell; +use halo2_proofs::circuit::AssignedCell; use halo2_proofs::plonk::Error; use specs::jtable::JumpTable; use specs::jtable::StaticFrameEntry; @@ -14,7 +14,7 @@ impl JumpTableChip { fn constraint_to_etable_jops( &self, ctx: &mut Context<'_, F>, - etable_rest_jops_cell: Cell, + etable_rest_jops_cell: &AssignedCell, ) -> Result<(), Error> { /* * Assign a meaningless rest_jops value to get the cell which should equal to the @@ -30,7 +30,7 @@ impl JumpTableChip { )?; ctx.region - .constrain_equal(cell.cell(), etable_rest_jops_cell)?; + .constrain_equal(cell.cell(), etable_rest_jops_cell.cell())?; Ok(()) } @@ -66,7 +66,7 @@ impl JumpTableChip { ctx: &mut Context<'_, F>, rest_jops: &mut u64, static_entries: &Vec, - ) -> Result, Error> { + ) -> Result, AssignedCell)>, Error> { let mut static_entries = static_entries.clone(); let mut cells = vec![]; @@ -91,15 +91,12 @@ impl JumpTableChip { || Ok(F::one()), )?; - let enable_cell = ctx - .region - .assign_advice( - || "jtable enable", - self.config.data, - ctx.offset, - || Ok(F::from(entry.enable as u64)), - )? - .cell(); + let enable_cell = ctx.region.assign_advice( + || "jtable enable", + self.config.data, + ctx.offset, + || Ok(F::from(entry.enable as u64)), + )?; ctx.next(); ctx.region.assign_advice( @@ -110,15 +107,12 @@ impl JumpTableChip { )?; ctx.next(); - let entry_cell = ctx - .region - .assign_advice( - || "jtable entry", - self.config.data, - ctx.offset, - || Ok(bn_to_field(&entry.encode())), - )? - .cell(); + let entry_cell = ctx.region.assign_advice( + || "jtable entry", + self.config.data, + ctx.offset, + || Ok(bn_to_field(&entry.encode())), + )?; ctx.next(); cells.push((enable_cell, entry_cell)); @@ -201,11 +195,11 @@ impl JumpTableChip { &self, ctx: &mut Context<'_, F>, jtable: &JumpTable, - etable_rest_jops_cell: Option, + etable_jops_cell: &Option>, static_entries: &Vec, - ) -> Result, Error> { - if etable_rest_jops_cell.is_some() { - self.constraint_to_etable_jops(ctx, etable_rest_jops_cell.unwrap())?; + ) -> Result, AssignedCell)>, Error> { + if etable_jops_cell.is_some() { + self.constraint_to_etable_jops(ctx, etable_jops_cell.as_ref().unwrap())?; } self.init(ctx)?; diff --git a/crates/zkwasm/src/circuits/mod.rs b/crates/zkwasm/src/circuits/mod.rs index f89bed64d..672f3b1c3 100644 --- a/crates/zkwasm/src/circuits/mod.rs +++ b/crates/zkwasm/src/circuits/mod.rs @@ -19,20 +19,23 @@ mod traits; pub mod config; pub mod image_table; pub mod jtable; +pub mod post_image_table; pub mod rtable; pub mod test_circuit; pub mod utils; -#[derive(Default, Clone)] +#[derive(Clone)] pub struct TestCircuit { pub tables: Tables, + pub slice_capability: Option, _data: PhantomData, } impl TestCircuit { - pub fn new(tables: Tables) -> Self { + pub fn new(tables: Tables, slice_capability: Option) -> Self { TestCircuit { tables, + slice_capability, _data: PhantomData, } } @@ -60,7 +63,7 @@ pub struct ZkWasmCircuitBuilder { } impl ZkWasmCircuitBuilder { - pub fn build_circuit(&self) -> TestCircuit { - TestCircuit::new(self.tables.clone()) + pub fn build_circuit(self, slice_capability: Option) -> TestCircuit { + TestCircuit::new(self.tables, slice_capability) } } diff --git a/crates/zkwasm/src/circuits/mtable/allocator.rs b/crates/zkwasm/src/circuits/mtable/allocator.rs index 875f89fa0..5440a982b 100644 --- a/crates/zkwasm/src/circuits/mtable/allocator.rs +++ b/crates/zkwasm/src/circuits/mtable/allocator.rs @@ -82,10 +82,10 @@ pub(super) enum MemoryTableCellType { } const BIT_COLUMNS: usize = 3; -const U16_COLUMNS: usize = U32_CELLS / 2 + U64_CELLS; +const U16_COLUMNS: usize = U32_CELLS.next_multiple_of(2) / 2 + U64_CELLS; const COMMON_RANGE_COLUMNS: usize = 2; -const UNLIMITED_COLUMNS: usize = 3; -const U32_CELLS: usize = 6; +const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 3 }; +const U32_CELLS: usize = if cfg!(feature = "continuation") { 9 } else { 6 }; const U64_CELLS: usize = 1; #[derive(Debug, Clone)] diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index 5fb0a35d1..0acb7ea27 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -2,12 +2,12 @@ use std::collections::HashMap; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; -use halo2_proofs::circuit::Cell; use halo2_proofs::plonk::Error; use log::debug; use specs::encode::init_memory_table::encode_init_memory_table_entry; use specs::encode::memory_table::encode_memory_table_entry; use specs::imtable::InitMemoryTable; +use specs::mtable::AccessType; use specs::mtable::LocationType; use specs::mtable::VarType; @@ -35,7 +35,15 @@ impl MemoryTableChip { ctx.region.assign_advice_from_constant( || "rest_mops terminate", self.config.rest_mops_cell.0.col, - ctx.offset, + ctx.offset + self.config.rest_mops_cell.0.rot as usize, + F::zero(), + )?; + + #[cfg(feature = "continuation")] + ctx.region.assign_advice_from_constant( + || "rest_memory_updating_ops terminate", + self.config.rest_memory_updating_ops.0.col, + ctx.offset + self.config.rest_memory_updating_ops.0.rot as usize, F::zero(), )?; } @@ -46,10 +54,25 @@ impl MemoryTableChip { Ok(()) } - fn constraint_rest_mops_permutation( + #[cfg(feature = "continuation")] + fn constrain_rest_memory_updating_ops( &self, ctx: &mut Context<'_, F>, - etable_rest_mops_cell: Option, + rest_memory_updating_ops: u32, + ) -> Result, Error> { + // Overwrite in assign_entries + let cell = self + .config + .rest_memory_updating_ops + .assign(ctx, F::from(rest_memory_updating_ops as u64))?; + + Ok(cell) + } + + fn constrain_rest_mops_permutation( + &self, + ctx: &mut Context<'_, F>, + etable_rest_mops_cell: &Option>, init_rest_mops: u64, ) -> Result, Error> { let cell = self @@ -59,7 +82,7 @@ impl MemoryTableChip { if etable_rest_mops_cell.is_some() { ctx.region - .constrain_equal(cell.cell(), etable_rest_mops_cell.unwrap())?; + .constrain_equal(cell.cell(), etable_rest_mops_cell.as_ref().unwrap().cell())?; } Ok(cell) @@ -70,7 +93,8 @@ impl MemoryTableChip { ctx: &mut Context<'_, F>, mtable: &MemoryWritingTable, init_rest_mops: u64, - imtable: &InitMemoryTable, + _imtable: &InitMemoryTable, + mut _rest_memory_updating_ops: u32, ) -> Result<(), Error> { macro_rules! assign_advice { ($cell:ident, $value:expr) => { @@ -110,7 +134,9 @@ impl MemoryTableChip { let mut rest_mops = init_rest_mops; - for entry in &mtable.0 { + let mut iter = mtable.0.iter().peekable(); + + while let Some(entry) = iter.next() { assign_bit!(enabled_cell); match entry.entry.ltype { @@ -128,34 +154,37 @@ 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 - .try_find(entry.entry.ltype, entry.entry.offset) - .unwrap(); + if ctx.offset == 207328 { + println!("is init: {}", entry.entry.atype.is_init()); + } - assign_advice!(offset_align_left, left_offset); - assign_advice!(offset_align_right, right_offset); - assign_advice!( - offset_align_left_diff_cell, - entry.entry.offset - left_offset - ); - assign_advice!( - offset_align_right_diff_cell, - right_offset - entry.entry.offset - ); + //if entry.entry.atype.is_init() { + // let init_memory_entry = imtable + // .try_find(entry.entry.ltype, entry.entry.offset) + // .unwrap(); + + // assign_advice!(offset_align_left, left_offset); + // assign_advice!(offset_align_right, right_offset); + // assign_advice!( + // offset_align_left_diff_cell, + // entry.entry.offset - left_offset + // ); + // assign_advice!( + // offset_align_right_diff_cell, + // right_offset - entry.entry.offset + // ); - assign_advice!( - init_encode_cell, - bn_to_field(&encode_init_memory_table_entry( - (entry.entry.ltype as u64).into(), - (entry.entry.is_mutable as u64).into(), - left_offset.into(), - right_offset.into(), - entry.entry.eid.into(), - value.into() - )) - ); - } + assign_advice!( + init_encode_cell, + bn_to_field(&encode_init_memory_table_entry( + (entry.entry.ltype as u64).into(), + entry.entry.offset.into(), + (entry.entry.is_mutable as u64).into(), + entry.entry.eid.into(), + entry.entry.value.into() + )) + ); + //} assign_u32_state!(start_eid_cell, entry.entry.eid); assign_u32_state!(end_eid_cell, entry.end_eid); @@ -164,6 +193,12 @@ impl MemoryTableChip { assign_advice!(offset_cell, entry.entry.offset); assign_advice!(value, entry.entry.value); + #[cfg(feature = "continuation")] + assign_advice!( + rest_memory_updating_ops, + F::from(_rest_memory_updating_ops as u64) + ); + assign_advice!( encode_cell, bn_to_field(&encode_memory_table_entry( @@ -181,6 +216,20 @@ impl MemoryTableChip { rest_mops -= 1; } + if let Some(next_entry) = iter.peek() { + if entry.entry.atype == AccessType::Write + && !entry.entry.is_same_location(&next_entry.entry) + { + _rest_memory_updating_ops -= 1; + } + } else { + // It's last entry + + if entry.entry.atype == AccessType::Write { + _rest_memory_updating_ops -= 1; + } + } + ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); } @@ -215,16 +264,40 @@ impl MemoryTableChip { ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); } + println!("mtable end: {}", ctx.offset); + Ok(()) } + fn compute_rest_memory_updating_ops(&self, mtable: &MemoryWritingTable) -> u32 { + let mut ops = 0u32; + + let mut iter = mtable.0.iter().peekable(); + + while let Some(entry) = iter.next() { + if let Some(next_entry) = iter.peek() { + if entry.entry.atype == AccessType::Write + && !entry.entry.is_same_location(&next_entry.entry) + { + ops += 1; + } + } else { + if entry.entry.atype == AccessType::Write { + ops += 1; + } + } + } + + ops + } + pub(crate) fn assign( &self, ctx: &mut Context<'_, F>, - etable_rest_mops_cell: Option, + etable_rest_mops_cell: &Option>, mtable: &MemoryWritingTable, imtable: &InitMemoryTable, - ) -> Result<(), Error> { + ) -> Result>, Error> { debug!("size of memory writing table: {}", mtable.0.len()); assert!(mtable.0.len() * (MEMORY_TABLE_ENTRY_ROWS as usize) < self.maximal_available_rows); @@ -236,17 +309,35 @@ impl MemoryTableChip { self.assign_fixed(ctx)?; ctx.reset(); + let _rest_memory_updating_ops = self.compute_rest_memory_updating_ops(mtable); + + #[cfg(feature = "continuation")] + let rest_memory_updating_ops = + self.constrain_rest_memory_updating_ops(ctx, _rest_memory_updating_ops)?; + let rest_mops_cell = - self.constraint_rest_mops_permutation(ctx, etable_rest_mops_cell, rest_mops)?; + self.constrain_rest_mops_permutation(ctx, etable_rest_mops_cell, rest_mops)?; /* * Skip subsequent advice assignment in the first pass to enhance performance. */ if rest_mops_cell.value().is_some() { - self.assign_entries(ctx, mtable, rest_mops, imtable)?; + self.assign_entries( + ctx, + mtable, + rest_mops, + imtable, + self.compute_rest_memory_updating_ops(mtable), + )?; ctx.reset(); } - Ok(()) + cfg_if::cfg_if! { + if #[cfg(feature="continuation")] { + Ok(Some(rest_memory_updating_ops)) + } else { + Ok(None) + } + } } } diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index 03c6317cb..2eace1f46 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -13,6 +13,8 @@ use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; +use specs::encode::image_table::ImageTableEncoder; +use specs::encode::init_memory_table::encode_init_memory_table_address; use specs::encode::init_memory_table::encode_init_memory_table_entry; use specs::encode::memory_table::encode_memory_table_entry; use specs::mtable::LocationType; @@ -44,10 +46,10 @@ pub struct MemoryTableConfig { end_eid_cell: AllocatedU32StateCell, eid_diff_cell: AllocatedU32StateCell, rest_mops_cell: AllocatedCommonRangeCell, - offset_align_left: AllocatedU32Cell, - offset_align_right: AllocatedU32Cell, - offset_align_left_diff_cell: AllocatedU32Cell, - offset_align_right_diff_cell: AllocatedU32Cell, + // 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, @@ -56,6 +58,9 @@ pub struct MemoryTableConfig { encode_cell: AllocatedUnlimitedCell, init_encode_cell: AllocatedUnlimitedCell, + #[cfg(feature = "continuation")] + rest_memory_updating_ops: AllocatedUnlimitedCell, + value: AllocatedU64Cell, } @@ -88,11 +93,8 @@ impl MemoryTableConfig { let eid_diff_cell = allocator.alloc_u32_state_cell(); let rest_mops_cell = allocator.alloc_common_range_cell(); - let offset_align_left = allocator.alloc_u32_cell(); - let offset_align_right = allocator.alloc_u32_cell(); + // TODO: cut allocated 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_u32_cell(); let offset_diff_inv_cell = allocator.alloc_unlimited_cell(); @@ -100,6 +102,14 @@ impl MemoryTableConfig { let encode_cell = allocator.alloc_unlimited_cell(); let init_encode_cell = allocator.alloc_unlimited_cell(); + #[cfg(feature = "continuation")] + let rest_memory_updating_ops = { + let cell = allocator.alloc_unlimited_cell(); + // FIXME: try to avoid this? + meta.enable_equality(cell.0.col); + cell + }; + let value = allocator.alloc_u64_cell(); meta.create_gate("mc1. enable seq", |meta| { @@ -187,22 +197,28 @@ impl MemoryTableConfig { .collect::>() }); - 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) - * (offset_align_left.curr_expr(meta) - + offset_align_left_diff_cell.curr_expr(meta) - - offset_cell.curr_expr(meta)), - is_init_cell.curr_expr(meta) - * (offset_cell.curr_expr(meta) + offset_align_right_diff_cell.curr_expr(meta) - - offset_align_right.curr_expr(meta)), - ] - .into_iter() - .map(|x| x * fixed_curr!(meta, entry_sel)) - .collect::>() + // meta.create_gate("mc7a. init", |meta| { + // vec![ + // // offset_left_align <= offset && offset <= offset_right_align + // is_init_cell.curr_expr(meta) + // * (offset_align_left.curr_expr(meta) + // + offset_align_left_diff_cell.curr_expr(meta) + // - offset_cell.curr_expr(meta)), + // is_init_cell.curr_expr(meta) + // * (offset_cell.curr_expr(meta) + offset_align_right_diff_cell.curr_expr(meta) + // - offset_align_right.curr_expr(meta)), + // ] + // .into_iter() + // .map(|x| x * fixed_curr!(meta, entry_sel)) + // .collect::>() + // }); + + #[cfg(not(feature = "continuation"))] + meta.create_gate("mc7a. init start_eid equals 0", |meta| { + vec![is_init_cell.curr_expr(meta) * start_eid_cell.curr_expr(meta)] + .into_iter() + .map(|x| x * fixed_curr!(meta, entry_sel)) + .collect::>() }); meta.create_gate( @@ -221,20 +237,16 @@ impl MemoryTableConfig { meta.create_gate("mc7c. init encode.", |meta| { vec![ - is_init_cell.curr_expr(meta) - * encode_init_memory_table_entry( - is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) - + is_heap_cell.curr_expr(meta) - * constant_from!(LocationType::Heap as u64) - + is_global_cell.curr_expr(meta) - * constant_from!(LocationType::Global as u64), - 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), + encode_init_memory_table_entry( + is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) + + is_heap_cell.curr_expr(meta) * constant_from!(LocationType::Heap as u64) + + is_global_cell.curr_expr(meta) + * constant_from!(LocationType::Global as u64), + offset_cell.curr_expr(meta), + is_mutable.curr_expr(meta), + start_eid_cell.curr_expr(meta), + value.u64_cell.curr_expr(meta), + ) - init_encode_cell.curr_expr(meta), ] .into_iter() .map(|x| x * fixed_curr!(meta, entry_sel)) @@ -242,7 +254,23 @@ impl MemoryTableConfig { }); image_table.init_memory_lookup(meta, "mc7c. imtable init", |meta| { - init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) + cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + ( + encode_init_memory_table_address( + is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) + + is_heap_cell.curr_expr(meta) + * constant_from!(LocationType::Heap as u64) + + is_global_cell.curr_expr(meta) + * constant_from!(LocationType::Global as u64), + offset_cell.curr_expr(meta), + ) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta), + init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta), + ) + } else { + init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta) + } + } }); meta.create_gate("mc8. vtype", |meta| { @@ -315,6 +343,21 @@ impl MemoryTableConfig { .collect::>() }); + #[cfg(feature = "continuation")] + { + meta.create_gate("mc13. rest memory updating ops", |meta| { + vec![ + rest_memory_updating_ops.curr_expr(meta) + - rest_memory_updating_ops.next_expr(meta) + - (constant_from!(1) - is_next_same_offset_cell.curr_expr(meta)) + * (constant_from!(1) - is_init_cell.curr_expr(meta)), + ] + .into_iter() + .map(|x| x * enabled_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel)) + .collect::>() + }); + } + Self { entry_sel, enabled_cell, @@ -335,13 +378,16 @@ impl MemoryTableConfig { offset_diff_cell, offset_diff_inv_cell, offset_diff_inv_helper_cell, - offset_align_left, - offset_align_right, - offset_align_left_diff_cell, - offset_align_right_diff_cell, + // offset_align_left, + // offset_align_right, + // offset_align_left_diff_cell, + // offset_align_right_diff_cell, value, init_encode_cell, encode_cell, + + #[cfg(feature = "continuation")] + rest_memory_updating_ops, } } } @@ -378,6 +424,41 @@ impl ConfigureLookupTable for MemoryTableConfig { } } +impl MemoryTableConfig { + pub(in crate::circuits) fn configure_in_post_init_memory_table( + &self, + meta: &mut ConstraintSystem, + name: &'static str, + expr: impl FnOnce(&mut VirtualCells<'_, F>) -> (Expression, Expression), + ) { + meta.lookup_any(name, |meta| { + let (address, encode) = expr(meta); + vec![ + ( + address, + // FIXME: Add a bit cell to indicate finalized state + encode_init_memory_table_address( + self.is_stack_cell.expr(meta) + + self.is_heap_cell.expr(meta) * constant_from!(LocationType::Heap) + + self.is_global_cell.expr(meta) * constant_from!(LocationType::Global), + self.offset_cell.expr(meta), + ) * fixed_curr!(meta, self.entry_sel) + * (constant_from!(1) - self.is_init_cell.expr(meta)) + * (constant_from!(1) - self.is_next_same_offset_cell.expr(meta)), + ), + ( + encode, + // FIXME: Add a bit cell to indicate finalized state + ImageTableEncoder::InitMemory.encode(self.init_encode_cell.expr(meta)) + * fixed_curr!(meta, self.entry_sel) + * (constant_from!(1) - self.is_init_cell.expr(meta)) + * (constant_from!(1) - self.is_next_same_offset_cell.expr(meta)), + ), + ] + }); + } +} + pub(super) struct MemoryTableChip { config: MemoryTableConfig, maximal_available_rows: usize, diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs new file mode 100644 index 000000000..82fb19ad3 --- /dev/null +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -0,0 +1,385 @@ +use std::marker::PhantomData; + +use halo2_proofs::arithmetic::FieldExt; +use halo2_proofs::circuit::AssignedCell; +use halo2_proofs::circuit::Layouter; +use halo2_proofs::circuit::Region; +use halo2_proofs::plonk::Advice; +use halo2_proofs::plonk::Column; +use halo2_proofs::plonk::ConstraintSystem; +use halo2_proofs::plonk::Error; +use halo2_proofs::plonk::Fixed; +use num_bigint::BigUint; +use specs::encode::init_memory_table::encode_init_memory_table_address; +use specs::mtable::LocationType; +use specs::state::InitializationState; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; + +use crate::circuits::image_table::ImageTableConfig; +use crate::circuits::image_table::ImageTableLayouter; +use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; +use crate::circuits::image_table::PAGE_ENTRIES; +use crate::circuits::mtable::MemoryTableConfig; +use crate::circuits::utils::bn_to_field; +use crate::circuits::utils::Context; +use crate::constant_from; +use crate::curr; +use crate::fixed_curr; +use crate::next; + +use super::PostImageTableChipTrait; +use super::PostImageTableConfigTrait; + +#[derive(Clone)] +pub(in crate::circuits) struct ContinuationPostImageTableConfig { + memory_addr_sel: Column, + post_image_table: Column, + update: Column, + rest_memory_finalized_count: Column, + _mark: PhantomData, +} + +impl PostImageTableConfigTrait for ContinuationPostImageTableConfig { + fn configure( + meta: &mut ConstraintSystem, + memory_addr_sel: Column, + memory_table: &MemoryTableConfig, + pre_image_table: &ImageTableConfig, + ) -> Self { + let update = meta.advice_column(); + let rest_memory_finalized_count = meta.advice_column(); + let post_image_table = meta.advice_column(); + + meta.enable_equality(rest_memory_finalized_count); + meta.enable_equality(post_image_table); + + meta.create_gate("post image table: update", |meta| { + vec![ + // Update is a bit. + fixed_curr!(meta, memory_addr_sel) + * curr!(meta, update) + * (curr!(meta, update) - constant_from!(1)), + // count -= 1 iff update = 1. + fixed_curr!(meta, memory_addr_sel) + * (curr!(meta, rest_memory_finalized_count) + - next!(meta, rest_memory_finalized_count) + - curr!(meta, update)), + // If update is 0, value should keep the same. + fixed_curr!(meta, memory_addr_sel) + * (constant_from!(1) - curr!(meta, update)) + * (curr!(meta, post_image_table) - pre_image_table.expr(meta)), + ] + }); + + memory_table.configure_in_post_init_memory_table( + meta, + "post image table: lookup updating value", + |meta| { + ( + fixed_curr!(meta, memory_addr_sel) * curr!(meta, update), + curr!(meta, post_image_table) * curr!(meta, update), + ) + }, + ); + + Self { + memory_addr_sel, + post_image_table, + update, + rest_memory_finalized_count, + _mark: PhantomData, + } + } +} + +pub(in crate::circuits) struct ContinuationPostImageTableChip { + config: ContinuationPostImageTableConfig, + circuit_maximal_pages: u32, +} + +impl PostImageTableChipTrait> + for ContinuationPostImageTableChip +{ + fn new(config: ContinuationPostImageTableConfig, circuit_maximal_pages: u32) -> Self { + Self { + config, + circuit_maximal_pages, + } + } + + fn assign( + self, + layouter: &mut impl Layouter, + pre_image_table: ImageTableLayouter, + post_image_table: ImageTableLayouter, + permutation_cells: ImageTableLayouter>, + ) -> Result<(), Error> { + fn init_sel( + region: &mut Region, + sel: Column, + rest_memory_finalized_count: Column, + circuit_maximal_pages: u32, + ) -> Result<(), Error> { + let mut offset = INIT_MEMORY_ENTRIES_OFFSET; + + region.assign_fixed(|| "post image table: init", sel, offset, || Ok(F::zero()))?; + + offset += 1; + + macro_rules! assign_address { + ($l:expr, $o:expr) => {{ + region.assign_fixed( + || "post image table: init", + sel, + offset, + || { + Ok(bn_to_field(&encode_init_memory_table_address( + BigUint::from($l as u64), + BigUint::from($o as u64), + ))) + }, + )?; + + offset += 1; + + Ok::<_, Error>(()) + }}; + } + + for i in 0..DEFAULT_VALUE_STACK_LIMIT { + assign_address!(LocationType::Stack, i)?; + } + + for i in 0..DEFAULT_VALUE_STACK_LIMIT { + assign_address!(LocationType::Global, i)?; + } + + for i in 0..(circuit_maximal_pages * PAGE_ENTRIES) { + assign_address!(LocationType::Heap, i)?; + } + + region.assign_advice_from_constant( + || "post image table: init memory", + rest_memory_finalized_count, + offset, + F::zero(), + )?; + + Ok(()) + } + + fn assign_and_perm_initialization_state( + ctx: &mut Context, + post_image_table_col: Column, + initialization_state: &InitializationState>, + ) -> Result<(), Error> { + Ok::<_, Error>(initialization_state.for_each(|field| { + field + .copy_advice( + || "image table: initialization state", + &mut ctx.region, + post_image_table_col, + ctx.offset, + ) + .unwrap(); + + ctx.next(); + })) + } + + fn assign_static_frame_entries( + ctx: &mut Context, + post_image_table_col: Column, + static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, + ) -> Result<(), Error> { + for (enable, entry) in static_frame_entries { + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.region, + post_image_table_col, + ctx.offset, + )?; + ctx.next(); + + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.region, + post_image_table_col, + ctx.offset, + )?; + ctx.next(); + } + + Ok(()) + } + + fn assign_instructions( + ctx: &mut Context, + post_image_table_col: Column, + instructions: &Vec>, + ) -> Result<(), Error> { + for cell in instructions { + cell.copy_advice( + || "post image table: instructions", + &mut ctx.region, + post_image_table_col, + ctx.offset, + )?; + + ctx.next(); + } + + Ok(()) + } + + fn assign_br_table( + ctx: &mut Context, + post_image_table_col: Column, + br_table: &Vec>, + ) -> Result<(), Error> { + for cell in br_table { + cell.copy_advice( + || "post image table: instructions", + &mut ctx.region, + post_image_table_col, + ctx.offset, + )?; + + ctx.next(); + } + + Ok(()) + } + + fn assign_init_memory_entries( + ctx: &mut Context, + sel: Column, + post_image_table_col: Column, + update_col: Column, + rest_memory_finalized_ops_col: Column, + pre_image_table: &ImageTableLayouter, + post_image_table: &ImageTableLayouter, + permutation_cells: &ImageTableLayouter>, + circuit_maximal_pages: u32, + ) -> Result<(), Error> { + assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); + ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; + + assert_eq!( + pre_image_table.init_memory_entries.as_ref().unwrap().len(), + post_image_table.init_memory_entries.as_ref().unwrap().len() + ); + + init_sel( + &mut ctx.region, + sel, + rest_memory_finalized_ops_col, + circuit_maximal_pages, + )?; + + permutation_cells + .rest_memory_writing_ops + .as_ref() + .unwrap() + .copy_advice( + || "post image table: init memory", + &mut ctx.region, + rest_memory_finalized_ops_col, + ctx.offset, + )?; + + let mut rest_memory_writing_ops = *permutation_cells + .rest_memory_writing_ops + .as_ref() + .unwrap() + .value() + .unwrap(); + + for (pre, post) in pre_image_table + .init_memory_entries + .as_ref() + .unwrap() + .iter() + .zip( + post_image_table + .init_memory_entries + .as_ref() + .unwrap() + .iter(), + ) + { + ctx.region.assign_advice( + || "post image table: init memory", + post_image_table_col, + ctx.offset, + || Ok(*post), + )?; + + ctx.region.assign_advice( + || "post image table: init memory", + rest_memory_finalized_ops_col, + ctx.offset, + || Ok(rest_memory_writing_ops), + )?; + + if pre != post { + ctx.region.assign_advice( + || "post image table: init memory", + update_col, + ctx.offset, + || Ok(F::one()), + )?; + + rest_memory_writing_ops = rest_memory_writing_ops - F::one(); + } + + ctx.next(); + } + + assert_eq!(rest_memory_writing_ops, F::zero()); + + Ok::<_, Error>(()) + } + + layouter.assign_region( + || "post image table", + |region| { + let mut ctx = Context::new(region); + + assign_and_perm_initialization_state( + &mut ctx, + self.config.post_image_table, + &permutation_cells.initialization_state, + )?; + assign_static_frame_entries( + &mut ctx, + self.config.post_image_table, + &permutation_cells.static_frame_entries, + )?; + assign_instructions( + &mut ctx, + self.config.post_image_table, + permutation_cells.instructions.as_ref().unwrap(), + )?; + assign_br_table( + &mut ctx, + self.config.post_image_table, + permutation_cells.br_table.as_ref().unwrap(), + )?; + assign_init_memory_entries( + &mut ctx, + self.config.memory_addr_sel, + self.config.post_image_table, + self.config.update, + self.config.rest_memory_finalized_count, + &pre_image_table, + &post_image_table, + &permutation_cells, + self.circuit_maximal_pages, + )?; + + Ok(()) + }, + ) + } +} diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs new file mode 100644 index 000000000..3dae42d6c --- /dev/null +++ b/crates/zkwasm/src/circuits/post_image_table/mod.rs @@ -0,0 +1,53 @@ +use halo2_proofs::arithmetic::FieldExt; +use halo2_proofs::circuit::AssignedCell; +use halo2_proofs::circuit::Layouter; +use halo2_proofs::plonk::Column; +use halo2_proofs::plonk::ConstraintSystem; +use halo2_proofs::plonk::Error; +use halo2_proofs::plonk::Fixed; + +use super::image_table::ImageTableConfig; +use super::image_table::ImageTableLayouter; +use super::mtable::MemoryTableConfig; + +pub(self) mod continuation; +pub(self) mod trivial; + +pub(in crate::circuits) trait PostImageTableConfigTrait { + fn configure( + _meta: &mut ConstraintSystem, + _memory_addr_sel: Column, + _memory_table: &MemoryTableConfig, + _pre_image_table: &ImageTableConfig, + ) -> Self; +} + +pub(in crate::circuits) trait PostImageTableChipTrait< + F: FieldExt, + Config: PostImageTableConfigTrait, +> +{ + fn new(config: Config, circuit_maximal_pages: u32) -> Self; + fn assign( + self, + layouter: &mut impl Layouter, + pre_image_table: ImageTableLayouter, + post_image_table: ImageTableLayouter, + permutation_cells: ImageTableLayouter>, + ) -> Result<(), Error>; +} + +cfg_if::cfg_if! { + if #[cfg(feature = "continuation")] { + use self::continuation::*; + + pub(in crate::circuits) type PostImageTableConfig = ContinuationPostImageTableConfig; + pub(in crate::circuits) type PostImageTableChip = ContinuationPostImageTableChip; + + } else { + use self::trivial::*; + + pub(in crate::circuits) type PostImageTableConfig = TrivialPostImageTableConfig; + pub(in crate::circuits) type PostImageTableChip = TrivialPostImageTableChip; + } +} diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs new file mode 100644 index 000000000..4bbef6a48 --- /dev/null +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -0,0 +1,54 @@ +use std::marker::PhantomData; + +use halo2_proofs::arithmetic::FieldExt; +use halo2_proofs::circuit::AssignedCell; +use halo2_proofs::circuit::Layouter; +use halo2_proofs::plonk::Column; +use halo2_proofs::plonk::ConstraintSystem; +use halo2_proofs::plonk::Error; +use halo2_proofs::plonk::Fixed; + +use crate::circuits::image_table::ImageTableConfig; +use crate::circuits::image_table::ImageTableLayouter; +use crate::circuits::mtable::MemoryTableConfig; + +use super::PostImageTableChipTrait; +use super::PostImageTableConfigTrait; + +#[derive(Clone)] +pub(in crate::circuits) struct TrivialPostImageTableConfig { + _mark: PhantomData, +} + +impl PostImageTableConfigTrait for TrivialPostImageTableConfig { + fn configure( + _meta: &mut ConstraintSystem, + _memory_addr_sel: Column, + _memory_table: &MemoryTableConfig, + _pre_image_table: &ImageTableConfig, + ) -> Self { + Self { _mark: PhantomData } + } +} + +pub(in crate::circuits) struct TrivialPostImageTableChip { + _mark: PhantomData, +} + +impl PostImageTableChipTrait> + for TrivialPostImageTableChip +{ + fn new(_config: TrivialPostImageTableConfig, _circuit_maximal_pages: u32) -> Self { + Self { _mark: PhantomData } + } + + fn assign( + self, + _layouter: &mut impl Layouter, + _pre_image_table: ImageTableLayouter, + _post_image_table: ImageTableLayouter, + _permutation_cells: ImageTableLayouter>, + ) -> Result<(), Error> { + Ok(()) + } +} diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 9d055ab82..7e4798fd3 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -11,8 +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 log::info; use specs::Tables; use crate::circuits::bit_table::BitTableChip; @@ -21,6 +20,7 @@ use crate::circuits::etable::EventTableChip; use crate::circuits::etable::EventTableConfig; use crate::circuits::external_host_call_table::ExternalHostCallChip; use crate::circuits::external_host_call_table::ExternalHostCallTableConfig; +use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::EncodeCompilationTableValues; use crate::circuits::image_table::ImageTableChip; use crate::circuits::image_table::ImageTableLayouter; @@ -28,6 +28,9 @@ use crate::circuits::jtable::JumpTableChip; use crate::circuits::jtable::JumpTableConfig; use crate::circuits::mtable::MemoryTableChip; use crate::circuits::mtable::MemoryTableConfig; +use crate::circuits::post_image_table::PostImageTableChip; +use crate::circuits::post_image_table::PostImageTableChipTrait; +use crate::circuits::post_image_table::PostImageTableConfigTrait; use crate::circuits::rtable::RangeTableChip; use crate::circuits::rtable::RangeTableConfig; use crate::circuits::utils::table_entry::EventTableWithMemoryInfo; @@ -47,17 +50,23 @@ use crate::runtime::memory_event_of_step; use super::config::zkwasm_k; use super::image_table::ImageTableConfig; +use super::post_image_table::PostImageTableConfig; -pub const VAR_COLUMNS: usize = 56; +pub const VAR_COLUMNS: usize = if cfg!(feature = "continuation") { + 63 +} else { + 54 +}; // Reserve a few rows to keep usable rows away from blind rows. // The maximal step size of all tables is bit_table::STEP_SIZE. -const RESERVE_ROWS: usize = crate::circuits::bit_table::STEP_SIZE; +pub(crate) const RESERVE_ROWS: usize = crate::circuits::bit_table::STEP_SIZE; #[derive(Clone)] pub struct TestCircuitConfig { rtable: RangeTableConfig, image_table: ImageTableConfig, + post_image_table: PostImageTableConfig, mtable: MemoryTableConfig, jtable: JumpTableConfig, etable: EventTableConfig, @@ -68,6 +77,7 @@ pub struct TestCircuitConfig { foreign_table_from_zero_index: Column, max_available_rows: usize, + circuit_maximal_pages: u32, } impl Circuit for TestCircuit { @@ -76,11 +86,10 @@ impl Circuit for TestCircuit { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - TestCircuit::new(Tables { - compilation_tables: CompilationTable::default(), - execution_tables: ExecutionTable::default(), - post_image_table: CompilationTable::default(), - }) + TestCircuit::new( + Tables::default(self.tables.is_last_slice), + self.slice_capability, + ) } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -92,13 +101,17 @@ impl Circuit for TestCircuit { meta.enable_constant(constants); meta.enable_equality(constants); } + let memory_addr_sel = meta.fixed_column(); + let foreign_table_from_zero_index = meta.fixed_column(); let mut cols = [(); VAR_COLUMNS].map(|_| meta.advice_column()).into_iter(); let rtable = RangeTableConfig::configure(meta); - let image_table = ImageTableConfig::configure(meta); + let image_table = ImageTableConfig::configure(meta, memory_addr_sel); let mtable = MemoryTableConfig::configure(meta, &mut cols, &rtable, &image_table); + let post_image_table = + PostImageTableConfig::configure(meta, memory_addr_sel, &mtable, &image_table); let jtable = JumpTableConfig::configure(meta, &mut cols); let external_host_call_table = ExternalHostCallTableConfig::configure(meta); let bit_table = BitTableConfig::configure(meta, &rtable); @@ -133,12 +146,21 @@ impl Circuit for TestCircuit { assert_eq!(cols.count(), 0); - let max_available_rows = (1 << zkwasm_k()) - (meta.blinding_factors() + 1 + RESERVE_ROWS); + let k = zkwasm_k(); + + let max_available_rows = (1 << k) - (meta.blinding_factors() + 1 + RESERVE_ROWS); debug!("max_available_rows: {:?}", max_available_rows); + let circuit_maximal_pages = compute_maximal_pages(k); + info!( + "Circuit K: {} supports up to {} pages.", + k, max_available_rows + ); + Self::Config { rtable, image_table, + post_image_table, mtable, jtable, etable, @@ -148,6 +170,7 @@ impl Circuit for TestCircuit { foreign_table_from_zero_index, max_available_rows, + circuit_maximal_pages, } } @@ -160,9 +183,15 @@ impl Circuit for TestCircuit { let rchip = RangeTableChip::new(config.rtable); let image_chip = ImageTableChip::new(config.image_table); + let post_image_chip = + PostImageTableChip::new(config.post_image_table, config.circuit_maximal_pages); let mchip = MemoryTableChip::new(config.mtable, config.max_available_rows); let jchip = JumpTableChip::new(config.jtable, config.max_available_rows); - let echip = EventTableChip::new(config.etable, config.max_available_rows); + let echip = EventTableChip::new( + config.etable, + self.slice_capability, + config.max_available_rows, + ); let bit_chip = BitTableChip::new(config.bit_table, config.max_available_rows); let external_host_call_chip = ExternalHostCallChip::new(config.external_host_call_table, config.max_available_rows); @@ -198,66 +227,77 @@ impl Circuit for TestCircuit { )? ); - 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, + let (etable_permutation_cells, rest_memory_writing_ops, 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, - &self.tables.compilation_tables.imtable - )? + ) ); - } - let jtable_info = { - ctx.reset(); - exec_with_profile!( - || "Assign frame table", - jchip.assign( + let etable_permutation_cells = exec_with_profile!( + || "Assign etable", + echip.assign( &mut ctx, - &self.tables.execution_tables.jtable, - etable_permutation_cells.rest_jops, - &self.tables.compilation_tables.static_jtable, + &etable, + &self.tables.compilation_tables.configure_table, + &self.tables.compilation_tables.initialization_state, + &self.tables.post_image_table.initialization_state, + self.tables.is_last_slice, )? - ) - }; - - { - ctx.reset(); - exec_with_profile!(|| "Assign bit table", bit_chip.assign(&mut ctx, &etable)?); - } + ); - Ok((etable_permutation_cells, jtable_info)) - }, - )?; + let rest_memory_writing_ops = { + 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, + rest_memory_writing_ops, + jtable_info, + )) + }, + )?; exec_with_profile!( || "Assign context cont chip", @@ -268,7 +308,7 @@ impl Circuit for TestCircuit { )? ); - exec_with_profile!( + let pre_image_table_cells = exec_with_profile!( || "Assign Pre Image Table", image_chip.assign( &mut layouter, @@ -278,7 +318,31 @@ impl Circuit for TestCircuit { ImageTableLayouter { initialization_state: etable_permutation_cells.pre_initialization_state, static_frame_entries, - lookup_entries: None + instructions: None, + br_table: None, + init_memory_entries: None, + rest_memory_writing_ops: None, + } + )? + ); + + exec_with_profile!( + || "Assign Post Image Table", + post_image_chip.assign( + &mut layouter, + self.tables + .compilation_tables + .encode_compilation_table_values(), + self.tables + .post_image_table + .encode_compilation_table_values(), + ImageTableLayouter { + initialization_state: etable_permutation_cells.post_initialization_state, + static_frame_entries: pre_image_table_cells.static_frame_entries, + instructions: pre_image_table_cells.instructions, + br_table: pre_image_table_cells.br_table, + init_memory_entries: pre_image_table_cells.init_memory_entries, + rest_memory_writing_ops, } )? ); diff --git a/crates/zkwasm/src/circuits/utils/table_entry.rs b/crates/zkwasm/src/circuits/utils/table_entry.rs index ad84b718e..c081f92e5 100644 --- a/crates/zkwasm/src/circuits/utils/table_entry.rs +++ b/crates/zkwasm/src/circuits/utils/table_entry.rs @@ -32,7 +32,11 @@ pub struct MemoryWritingTable(pub(in crate::circuits) Vec); impl From for MemoryWritingTable { fn from(value: MTable) -> Self { - let maximal_eid = (1u32 << (zkwasm_k() - 1)) - 1; + let maximal_eid = if cfg!(feature = "continuation") { + u32::MAX + } else { + (1u32 << (zkwasm_k() - 1)) - 1 + }; let mut index = 0; let mut entries: Vec = value @@ -151,6 +155,7 @@ impl EventTableWithMemoryInfo { } }) .unwrap(); + records[idx] } }; diff --git a/crates/zkwasm/src/continuation/loader.rs b/crates/zkwasm/src/continuation/loader.rs new file mode 100644 index 000000000..d98848813 --- /dev/null +++ b/crates/zkwasm/src/continuation/loader.rs @@ -0,0 +1,18 @@ +use halo2_proofs::arithmetic::MultiMillerLoop; +use wasmi::RuntimeValue; + +use crate::circuits::etable::EVENT_TABLE_ENTRY_ROWS; +use crate::loader::ZkWasmLoader; +use crate::runtime::ExecutionResult; + +use super::slice::Slices; + +impl ZkWasmLoader { + fn compute_slice_capability(&self) -> usize { + ((1 << self.k) - 200) / EVENT_TABLE_ENTRY_ROWS as usize + } + + pub fn slice(&self, execution_result: ExecutionResult) -> Slices { + Slices::new(execution_result.tables, self.compute_slice_capability()) + } +} diff --git a/crates/zkwasm/src/continuation/mod.rs b/crates/zkwasm/src/continuation/mod.rs new file mode 100644 index 000000000..37ace1100 --- /dev/null +++ b/crates/zkwasm/src/continuation/mod.rs @@ -0,0 +1,2 @@ +pub mod loader; +pub mod slice; diff --git a/crates/zkwasm/src/continuation/slice.rs b/crates/zkwasm/src/continuation/slice.rs new file mode 100644 index 000000000..9ec90bd68 --- /dev/null +++ b/crates/zkwasm/src/continuation/slice.rs @@ -0,0 +1,127 @@ +use halo2_proofs::arithmetic::FieldExt; +use specs::etable::EventTable; +use specs::etable::EventTableEntry; +use specs::CompilationTable; +use specs::ExecutionTable; +use specs::Tables; + +use crate::circuits::TestCircuit; +use crate::circuits::ZkWasmCircuitBuilder; +use crate::runtime::state::UpdateCompilationTable; + +pub struct Slice { + table: Tables, + capability: usize, +} + +impl Slice { + pub fn build_circuit(self) -> TestCircuit { + println!( + "etable entries: {}", + self.table.execution_tables.etable.entries().len() + ); + + let builder = ZkWasmCircuitBuilder { tables: self.table }; + + builder.build_circuit(Some(self.capability)) + } +} + +pub struct Slices { + remaining_etable_entries: Vec, + last_compilation_table: CompilationTable, + + // the length of etable entries + capability: usize, + + origin_table: Tables, +} + +impl Slices { + pub fn new(tables: Tables, capability: usize) -> Self { + Self { + remaining_etable_entries: tables.execution_tables.etable.entries().clone(), + last_compilation_table: tables.compilation_tables.clone(), + capability, + origin_table: tables, + } + } + + fn pop_etable_entries(&mut self) -> Vec { + self.remaining_etable_entries + .drain(0..self.capability.min(self.remaining_etable_entries.len())) + .collect::>() + } +} + +impl Iterator for Slices { + type Item = Slice; + + fn next(&mut self) -> Option { + if self.remaining_etable_entries.is_empty() { + return None; + } + + let mut etable_entries = self.pop_etable_entries(); + // let etable = EventTable::new(etable_entries); + + // let is_last_slice = self.remaining_etable_entries.is_empty(); + + // if !is_last_slice { + // self.remaining_etable_entries + // .insert(0, etable.entries().last().unwrap().clone()); + // } + + let (updated_init_memory_table, updated_post_initialization_state) = { + let updated_init_memory_table = self + .last_compilation_table + .update_init_memory_table(&etable_entries); + + let is_last_slice = self.remaining_etable_entries.is_empty(); + + // If it is not the last slice, push a helper step to get the post initialization state. + if !is_last_slice { + etable_entries.push(self.remaining_etable_entries.first().unwrap().clone()); + } + + let updated_post_initialization_state = self + .last_compilation_table + .update_initialization_state(&etable_entries, is_last_slice); + + if !is_last_slice { + etable_entries.pop(); + } + + (updated_init_memory_table, updated_post_initialization_state) + }; + + let execution_tables = ExecutionTable { + etable: EventTable::new(etable_entries), + jtable: self.origin_table.execution_tables.jtable.clone(), + }; + + let post_image_table = CompilationTable { + itable: self.origin_table.compilation_tables.itable.clone(), + imtable: updated_init_memory_table, + elem_table: self.origin_table.compilation_tables.elem_table.clone(), + configure_table: self.origin_table.compilation_tables.configure_table.clone(), + static_jtable: self.origin_table.compilation_tables.static_jtable.clone(), + initialization_state: updated_post_initialization_state, + }; + + let compilation_tables = + std::mem::replace(&mut self.last_compilation_table, post_image_table.clone()); + + let slice = Slice { + table: Tables { + compilation_tables, + execution_tables, + post_image_table, + is_last_slice: self.remaining_etable_entries.is_empty(), + }, + capability: self.capability, + }; + + Some(slice) + } +} diff --git a/crates/zkwasm/src/lib.rs b/crates/zkwasm/src/lib.rs index c850e7b5a..f2c52430e 100644 --- a/crates/zkwasm/src/lib.rs +++ b/crates/zkwasm/src/lib.rs @@ -1,10 +1,13 @@ #![deny(dead_code)] #![deny(unused_variables)] #![deny(unused_imports)] -#![feature(thread_local)] +#![feature(int_roundings)] +#![feature(stmt_expr_attributes)] pub mod checksum; pub mod circuits; +#[cfg(feature = "continuation")] +pub mod continuation; pub mod foreign; pub mod loader; pub mod runtime; diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index e08009309..86778ebbe 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -15,8 +15,6 @@ 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; use wasmi::ImportsBuilder; @@ -60,7 +58,7 @@ pub struct ExecutionReturn { } pub struct ZkWasmLoader { - k: u32, + pub k: u32, module: wasmi::Module, phantom_functions: Vec, _data: PhantomData, @@ -109,16 +107,12 @@ impl ZkWasmLoader { ) } - fn circuit_without_witness(&self) -> Result> { + fn circuit_without_witness(&self, last_slice_circuit: bool) -> Result> { let builder = ZkWasmCircuitBuilder { - tables: Tables { - compilation_tables: CompilationTable::default(), - execution_tables: ExecutionTable::default(), - post_image_table: CompilationTable::default(), - }, + tables: Tables::default(last_slice_circuit), }; - Ok(builder.build_circuit::()) + Ok(builder.build_circuit::(None)) } pub fn new(k: u32, image: Vec, phantom_functions: Vec) -> Result { @@ -139,8 +133,12 @@ impl ZkWasmLoader { Ok(loader) } - pub fn create_vkey(&self, params: &Params) -> Result> { - let circuit = self.circuit_without_witness()?; + pub fn create_vkey( + &self, + params: &Params, + last_slice_circuit: bool, + ) -> Result> { + let circuit = self.circuit_without_witness(last_slice_circuit)?; Ok(keygen_vk(¶ms, &circuit).unwrap()) } @@ -215,7 +213,7 @@ impl ZkWasmLoader { println!("output:"); println!("{:?}", execution_result.outputs); - Ok((builder.build_circuit(), instance)) + Ok((builder.build_circuit(None), instance)) } pub fn mock_test( @@ -337,7 +335,7 @@ mod tests { } let params = prepare_param(self.k); - let vkey = self.create_vkey(¶ms).unwrap(); + let vkey = self.create_vkey(¶ms, true).unwrap(); let proof = self .create_proof(¶ms, vkey.clone(), circuit, &instances) diff --git a/crates/zkwasm/src/runtime/state.rs b/crates/zkwasm/src/runtime/state.rs index 78cb8b418..d87998f73 100644 --- a/crates/zkwasm/src/runtime/state.rs +++ b/crates/zkwasm/src/runtime/state.rs @@ -1,12 +1,9 @@ -use std::collections::BTreeMap; - -use specs::etable::EventTable; +use specs::etable::EventTableEntry; use specs::host_function::HostPlugin; use specs::imtable::InitMemoryTable; use specs::imtable::InitMemoryTableEntry; use specs::itable::Opcode; use specs::mtable::AccessType; -use specs::mtable::LocationType; use specs::state::InitializationState; use specs::step::StepInfo; use specs::CompilationTable; @@ -14,72 +11,33 @@ use specs::CompilationTable; use super::memory_event_of_step; pub(crate) trait UpdateCompilationTable { - fn update_init_memory_table(&self, execution_table: &EventTable) -> InitMemoryTable; + fn update_init_memory_table(&self, execution_table: &Vec) -> InitMemoryTable; fn update_initialization_state( &self, - execution_table: &EventTable, + execution_table: &Vec, 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(); - + fn update_init_memory_table(&self, execution_table: &Vec) -> InitMemoryTable { // 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); + let mut map = self.imtable.entries().clone(); - 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 mut it = execution_table.iter(); + while let Some(etable_entry) = it.next() { 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, + (mentry.ltype, mentry.offset), InitMemoryTableEntry { ltype: mentry.ltype, is_mutable: mentry.is_mutable, - start_offset: mentry.offset, - end_offset: mentry.offset, + offset: mentry.offset, vtype: mentry.vtype, value: mentry.value, eid: etable_entry.eid, @@ -88,19 +46,12 @@ impl UpdateCompilationTable for CompilationTable { } } - 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) + InitMemoryTable(map) } fn update_initialization_state( &self, - execution_table: &EventTable, + execution_table: &Vec, is_last_slice: bool, ) -> InitializationState { let mut host_public_inputs = self.initialization_state.host_public_inputs; @@ -112,7 +63,7 @@ impl UpdateCompilationTable for CompilationTable { #[cfg(feature = "continuation")] let mut jops = self.initialization_state.jops; - for entry in execution_table.entries() { + for entry in execution_table { match &entry.step_info { // TODO: fix hard code StepInfo::CallHost { @@ -146,7 +97,7 @@ impl UpdateCompilationTable for CompilationTable { } } - let last_entry = execution_table.entries().last().unwrap(); + let last_entry = execution_table.last().unwrap(); let post_initialization_state = if is_last_slice { InitializationState { @@ -179,7 +130,6 @@ impl UpdateCompilationTable for CompilationTable { 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, diff --git a/crates/zkwasm/src/runtime/wasmi_interpreter.rs b/crates/zkwasm/src/runtime/wasmi_interpreter.rs index 9ac65a03d..7153f317a 100644 --- a/crates/zkwasm/src/runtime/wasmi_interpreter.rs +++ b/crates/zkwasm/src/runtime/wasmi_interpreter.rs @@ -79,7 +79,7 @@ impl Execution let updated_init_memory_table = self .tables - .update_init_memory_table(&execution_tables.etable); + .update_init_memory_table(&execution_tables.etable.entries()); let post_image_table = { CompilationTable { @@ -90,7 +90,7 @@ impl Execution static_jtable: self.tables.static_jtable.clone(), initialization_state: self .tables - .update_initialization_state(&execution_tables.etable, true), + .update_initialization_state(&execution_tables.etable.entries(), true), } }; @@ -99,6 +99,7 @@ impl Execution compilation_tables: self.tables, execution_tables, post_image_table, + is_last_slice: true, }, result, public_inputs_and_outputs: wasm_io.public_inputs_and_outputs.borrow().clone(), diff --git a/crates/zkwasm/src/test/mod.rs b/crates/zkwasm/src/test/mod.rs index d087077f7..776387dc8 100644 --- a/crates/zkwasm/src/test/mod.rs +++ b/crates/zkwasm/src/test/mod.rs @@ -16,11 +16,12 @@ use wabt::Features; use wasmi::ImportsBuilder; use wasmi::RuntimeValue; -#[cfg(test)] mod test_wasm_instructions; mod spec; mod test_rlp; +#[cfg(feature = "continuation")] +mod test_rlp_slice; mod test_start; mod test_uniform_verifier; @@ -46,7 +47,7 @@ fn test_circuit_mock( execution_result.tables.profile_tables(); - let circuit = TestCircuit::new(execution_result.tables); + let circuit = TestCircuit::new(execution_result.tables, None); let prover = MockProver::run(zkwasm_k(), &circuit, vec![instance])?; assert_eq!(prover.verify(), Ok(())); diff --git a/crates/zkwasm/src/test/test_rlp_slice.rs b/crates/zkwasm/src/test/test_rlp_slice.rs new file mode 100644 index 000000000..89ead8347 --- /dev/null +++ b/crates/zkwasm/src/test/test_rlp_slice.rs @@ -0,0 +1,189 @@ +use std::sync::Arc; +use std::sync::Mutex; + +use crate::loader::ExecutionArg; +use crate::loader::ZkWasmLoader; + +use anyhow::Result; +use halo2_proofs::pairing::bn256::Bn256; + +fn test_slices() -> Result<()> { + let public_inputs = vec![133]; + let private_inputs: Vec = vec![ + 14625441452057167097, + 441, + 0, + 0, + 144115188084244480, + 17592186044416, + 0, + 0, + 2, + 0, + 281474976710656, + 72057594037928224, + 0, + 144115188075855872, + 4398046511104, + 2048, + 0, + 288230376151711744, + 562949953421312, + 36033195065475072, + 0, + 1152921504606846992, + 0, + 72057594037927936, + 0, + 0, + 72057594037927936, + 274877906944, + 0, + 8192, + 0, + 0, + 0, + 142172368092004352, + 10663670667014018268, + 15598333267600830878, + 4825637194728734969, + 11537926770794296992, + 8941585237026987872, + 1060144843738714138, + 15286290987074524363, + 41041, + 0, + 0, + 0, + 549784760702, + 0, + 0, + 13839280179932823552, + 9466528, + 0, + 1245741926200423424, + 9993052845762533317, + 643603743268, + 0, + 0, + 0, + 687194767360, + 0, + 0, + 0, + 274894684160, + 0, + 17752714368831347629, + 14734568103978781184, + 16340025600, + 0, + 0, + 0, + 17179869184, + 0, + 0, + 13839280179932823552, + 9466528, + 0, + 0, + 13839280179932823552, + 9466528, + 0, + 0, + 13839280179932823552, + 9466528, + 0, + 0, + 13983395368008679424, + 180934170288, + 0, + 0, + 0, + 216736848758702080, + 0, + 0, + 0, + 10708425217887174656, + 8187143887307480351, + 70325280878010241, + 117203507575396024, + 11486502108844260361, + 13539931197926996738, + 18161434576524511916, + 11561024771253616253, + 0, + 0, + 0, + 12789659991778787328, + 160, + 0, + 0, + 0, + 40960, + 0, + 0, + 15880255236061790208, + 17950538412901046486, + 8547692942764276983, + 8509190860294355049, + 5730928406529570843, + 18210150271972058323, + 3994395479395232905, + 6563862530498629762, + 688805136118, + 0, + 0, + 13839280179932823552, + 175921869910688, + 0, + 0, + 0, + 45231150997700608, + 0, + 0, + 0, + 43020438485336064, + ]; + + let wasm = std::fs::read("wasm/rlp.wasm").unwrap(); + + let loader = ZkWasmLoader::::new(18, wasm, vec![])?; + + let execution_result = loader.run(ExecutionArg { + public_inputs, + private_inputs, + context_inputs: vec![], + context_outputs: Arc::new(Mutex::new(vec![])), + })?; + + let instances = execution_result + .public_inputs_and_outputs + .iter() + .map(|v| (*v).into()) + .collect(); + + let mut slices = loader.slice(execution_result).into_iter(); + + let mut index = 0; + + while let Some(slice) = slices.next() { + println!("slice {}", index); + + let circuit = slice.build_circuit(); + + loader.mock_test(&circuit, &instances)?; + + index += 1; + } + + Ok(()) +} + +mod tests { + use super::*; + + #[test] + fn test_rlp_slice_mock() { + test_slices().unwrap(); + } +} diff --git a/crates/zkwasm/src/test/test_uniform_verifier.rs b/crates/zkwasm/src/test/test_uniform_verifier.rs index d113c6c05..d256b5ae3 100644 --- a/crates/zkwasm/src/test/test_uniform_verifier.rs +++ b/crates/zkwasm/src/test/test_uniform_verifier.rs @@ -35,7 +35,7 @@ fn setup_uniform_verifier() -> Result<(Params, ProvingKey)> tables: execution_result.tables, }; - let circuit: TestCircuit = builder.build_circuit(); + let circuit: TestCircuit = builder.build_circuit(None); let params = Params::::unsafe_setup::(K); let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); @@ -142,7 +142,7 @@ mod tests { create_proof( ¶ms, &uniform_verifier_pk, - &[builder.build_circuit()], + &[builder.build_circuit(None)], &[&[&instances]], OsRng, &mut transcript, diff --git a/third-party/wasmi b/third-party/wasmi index 83b80ed0d..7cc3411de 160000 --- a/third-party/wasmi +++ b/third-party/wasmi @@ -1 +1 @@ -Subproject commit 83b80ed0d7957f3f9a3f65f7e9d22c884306873f +Subproject commit 7cc3411de4ca5ab800dec894781bd7accf668046 From b1a0d92467aa77c89e9f61b332173ac5800f51ef Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sun, 26 Nov 2023 22:47:47 +0800 Subject: [PATCH 02/28] refine pre image table assignment --- crates/specs/src/state.rs | 10 + .../zkwasm/src/circuits/image_table/assign.rs | 391 ++++++++++++------ .../zkwasm/src/circuits/test_circuit/mod.rs | 23 ++ .../zkwasm/src/circuits/utils/image_table.rs | 144 +++++++ crates/zkwasm/src/circuits/utils/mod.rs | 1 + 5 files changed, 453 insertions(+), 116 deletions(-) create mode 100644 crates/zkwasm/src/circuits/utils/image_table.rs diff --git a/crates/specs/src/state.rs b/crates/specs/src/state.rs index 8b0144e0a..11712c014 100644 --- a/crates/specs/src/state.rs +++ b/crates/specs/src/state.rs @@ -20,6 +20,16 @@ pub struct InitializationState { pub jops: T, } +impl InitializationState { + pub fn field_count() -> usize { + if cfg!(feature = "continuation") { + 12 + } else { + 11 + } + } +} + impl Default for InitializationState { fn default() -> Self { Self { diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index eff3c4544..c02e30000 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -1,20 +1,27 @@ +use std::cell::RefCell; +use std::rc::Rc; + use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; 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 wasmi::DEFAULT_VALUE_STACK_LIMIT; use super::ImageTableChip; use super::ImageTableLayouter; use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; +use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::Context; impl ImageTableChip { - pub fn assign( + pub(crate) fn assign( self, layouter: &mut impl Layouter, + image_table_assigner: &mut ImageTableAssigner< + INIT_MEMORY_ENTRIES_OFFSET, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_VALUE_STACK_LIMIT, + >, image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, ) -> Result>, Error> { @@ -30,134 +37,286 @@ impl ImageTableChip { }}; } - fn assign_and_perm_initialization_state( - ctx: &mut Context, - col: Column, - initialization_state: &InitializationState>, - ) -> Result>, Error> { - let initialization_state = initialization_state.map(|field| { - field - .copy_advice( - || "image table: initialization state", - &mut ctx.region, - col, - ctx.offset, - ) - .unwrap(); - - ctx.next(); - - field.clone() - }); - - Ok::<_, Error>(initialization_state) - } + // fn assign_and_perm_initialization_state( + // ctx: &mut Context, + // col: Column, + // initialization_state: &InitializationState>, + // ) -> Result>, Error> { + // let initialization_state = initialization_state.map(|field| { + // field + // .copy_advice( + // || "image table: initialization state", + // &mut ctx.region, + // col, + // ctx.offset, + // ) + // .unwrap(); - fn assign_static_frame_entries( - ctx: &mut Context, - col: Column, - static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, - ) -> Result<(), Error> { - for (enable, entry) in static_frame_entries { - enable.copy_advice( - || "image table: static frame entry", - &mut ctx.region, - col, - ctx.offset, - )?; - ctx.next(); + // ctx.next(); - entry.copy_advice( - || "image table: static frame entry", - &mut ctx.region, - col, - ctx.offset, - )?; - ctx.next(); - } + // field.clone() + // }); - Ok(()) - } + // Ok::<_, Error>(initialization_state) + // } - fn assign_instructions( - ctx: &mut Context, - col: Column, - instructions: &Vec, - ) -> Result>, Error> { - let entries = instructions - .iter() - .map(|entry| assign!(ctx, col, *entry)) - .collect::, Error>>()?; - - Ok(entries) - } + // fn assign_static_frame_entries( + // ctx: &mut Context, + // col: Column, + // static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, + // ) -> Result<(), Error> { + // for (enable, entry) in static_frame_entries { + // enable.copy_advice( + // || "image table: static frame entry", + // &mut ctx.region, + // col, + // ctx.offset, + // )?; + // ctx.next(); - fn assign_br_table( - ctx: &mut Context, - col: Column, - br_table: &Vec, - ) -> Result>, Error> { - let entries = br_table - .iter() - .map(|entry| assign!(ctx, col, *entry)) - .collect::, Error>>()?; - - Ok(entries) - } + // entry.copy_advice( + // || "image table: static frame entry", + // &mut ctx.region, + // col, + // ctx.offset, + // )?; + // ctx.next(); + // } - fn assign_init_memory_entries( - ctx: &mut Context, - col: Column, - init_memory_entries: &Vec, - ) -> Result<(), Error> { - assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); - ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; + // Ok(()) + // } - for entry in init_memory_entries { - assign!(ctx, col, *entry)?; - } + // fn assign_instructions( + // ctx: &mut Context, + // col: Column, + // instructions: &Vec, + // ) -> Result>, Error> { + // let entries = instructions + // .iter() + // .map(|entry| assign!(ctx, col, *entry)) + // .collect::, Error>>()?; - Ok(()) - } + // Ok(entries) + // } + + // fn assign_br_table( + // ctx: &mut Context, + // col: Column, + // br_table: &Vec, + // ) -> Result>, Error> { + // let entries = br_table + // .iter() + // .map(|entry| assign!(ctx, col, *entry)) + // .collect::, Error>>()?; + + // Ok(entries) + // } + + // fn assign_init_memory_entries( + // ctx: &mut Context, + // col: Column, + // init_memory_entries: &Vec, + // ) -> Result<(), Error> { + // assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); + // ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; + + // for entry in init_memory_entries { + // assign!(ctx, col, *entry)?; + // } + + // Ok(()) + // } layouter.assign_region( || "pre image table", |region| { - let mut ctx = Context::new(region); + let ctx = Rc::new(RefCell::new(Context::new(region))); - let initialization_state = assign_and_perm_initialization_state( - &mut ctx, - self.config.col, - &permutation_cells.initialization_state, - )?; - assign_static_frame_entries( - &mut ctx, - self.config.col, - &permutation_cells.static_frame_entries, - )?; - let instructions = assign_instructions( - &mut ctx, - self.config.col, - image_table.instructions.as_ref().unwrap(), - ) - .ok(); - let br_table = assign_br_table( - &mut ctx, - self.config.col, - image_table.br_table.as_ref().unwrap(), - ) - .ok(); - assign_init_memory_entries( - &mut ctx, - self.config.col, - &image_table.init_memory_entries.as_ref().unwrap(), + let initialization_state_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + let initialization_state = + permutation_cells.initialization_state.map(|field| { + let offset = ctx.borrow().offset; + + field + .copy_advice( + || "image table: initialization state", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + ) + .unwrap(); + + ctx.borrow_mut().next(); + + field.clone() + }); + + Ok::<_, Error>(initialization_state) + }; + + let static_frame_entries_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + permutation_cells + .static_frame_entries + .iter() + .map(|(enable, entry)| { + let offset = ctx.borrow().offset; + + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + )?; + ctx.borrow_mut().next(); + + let offset = ctx.borrow().offset; + + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + )?; + ctx.borrow_mut().next(); + + Ok::<_, Error>((enable.clone(), entry.clone())) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let instruction_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + image_table + .instructions + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + + let cell = ctx.borrow_mut().region.assign_advice( + || "image table", + self.config.col, + offset, + || Ok(*entry), + ); + + ctx.borrow_mut().next(); + + cell + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let br_table_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + image_table + .br_table + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + + let cell = ctx.borrow_mut().region.assign_advice( + || "image table", + self.config.col, + offset, + || Ok(*entry), + ); + + ctx.borrow_mut().next(); + + cell + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let padding_handler = |start_offset, end_offset| { + (start_offset..end_offset) + .map(|offset| { + ctx.borrow_mut().region.assign_advice( + || "image table: padding", + self.config.col, + offset, + || Ok(F::zero()), + ) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let init_memory_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + image_table + .init_memory_entries + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + let cell = ctx.borrow_mut().region.assign_advice( + || "image table", + self.config.col, + offset, + || Ok(*entry), + ); + + ctx.borrow_mut().next(); + + cell + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let result = image_table_assigner.exec( + initialization_state_handler, + static_frame_entries_handler, + instruction_handler, + br_table_handler, + padding_handler, + init_memory_handler, )?; + // let instructions = assign_instructions( + // &mut ctx, + // self.config.col, + // image_table.instructions.as_ref().unwrap(), + // ) + // .ok(); + // let br_table = assign_br_table( + // &mut ctx, + // self.config.col, + // image_table.br_table.as_ref().unwrap(), + // ) + // .ok(); + // assign_init_memory_entries( + // &mut ctx, + // self.config.col, + // &image_table.init_memory_entries.as_ref().unwrap(), + // )?; + Ok(ImageTableLayouter { - initialization_state, - static_frame_entries: permutation_cells.static_frame_entries.clone(), - instructions, - br_table, + initialization_state: result.initialization_state, + static_frame_entries: result.static_frame_entries, + instructions: Some(result.instructions), + br_table: Some(result.br_table_entires), init_memory_entries: None, rest_memory_writing_ops: None, }) diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 7e4798fd3..0755d7d9c 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -13,6 +13,7 @@ use halo2_proofs::plonk::Fixed; use log::debug; use log::info; use specs::Tables; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::bit_table::BitTableChip; use crate::circuits::bit_table::BitTableConfig; @@ -24,6 +25,7 @@ use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::EncodeCompilationTableValues; use crate::circuits::image_table::ImageTableChip; use crate::circuits::image_table::ImageTableLayouter; +use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::jtable::JumpTableChip; use crate::circuits::jtable::JumpTableConfig; use crate::circuits::mtable::MemoryTableChip; @@ -33,6 +35,7 @@ use crate::circuits::post_image_table::PostImageTableChipTrait; use crate::circuits::post_image_table::PostImageTableConfigTrait; use crate::circuits::rtable::RangeTableChip; use crate::circuits::rtable::RangeTableConfig; +use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::table_entry::EventTableWithMemoryInfo; use crate::circuits::utils::table_entry::MemoryWritingTable; use crate::circuits::utils::Context; @@ -308,10 +311,30 @@ impl Circuit for TestCircuit { )? ); + let mut image_table_assigner = ImageTableAssigner::< + INIT_MEMORY_ENTRIES_OFFSET, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_VALUE_STACK_LIMIT, + >::new( + // Add one for default lookup value + self.tables.compilation_tables.itable.entries().len() + 1, + // FIXME: avoid compute + self.tables + .compilation_tables + .itable + .create_brtable() + .entries() + .len() + + self.tables.compilation_tables.elem_table.entries().len() + + 1, + compute_maximal_pages(zkwasm_k()), + ); + let pre_image_table_cells = exec_with_profile!( || "Assign Pre Image Table", image_chip.assign( &mut layouter, + &mut image_table_assigner, self.tables .compilation_tables .encode_compilation_table_values(), diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs new file mode 100644 index 000000000..e32bd7cc3 --- /dev/null +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -0,0 +1,144 @@ +use specs::state::InitializationState; + +use crate::circuits::image_table::PAGE_ENTRIES; + +/* + * -------------------- + * Initialization State + * -------------------- + * Static Frame Entries + * -------------------- + * Instructions + * -------------------- + * Br Table + * -------------------- + * Padding + * -------------------- Init Memory Offset + * Stack + * -------------------- + * Global + * -------------------- + * Heap + * -------------------- + */ +pub(crate) struct Layouter { + pub(crate) initialization_state: InitializationState, + pub(crate) static_frame_entries: Vec<(T, T)>, + pub(crate) instructions: Vec, + pub(crate) br_table_entires: Vec, + // NOTE: padding entries also need constain_equal for other image + pub(crate) _padding_entires: Vec, + pub(crate) _init_memory_entires: Vec, +} + +pub(crate) struct ImageTableAssigner< + const INIT_MEMORY_OFFSET: usize, + const STACK_CAPABILITY: usize, + const GLOBAL_CAPABILITY: usize, +> { + _heap_capability: u32, + initialization_state_offset: usize, + static_frame_entries_offset: usize, + instruction_offset: usize, + br_table_offset: usize, + padding_offset: usize, + init_memory_offset: usize, +} + +impl< + const INIT_MEMORY_OFFSET: usize, + const STACK_CAPABILITY: usize, + const GLOBAL_CAPABILITY: usize, + > ImageTableAssigner +{ + pub fn new(instruction_number: usize, br_table_number: usize, pages_capability: u32) -> Self { + let initialization_state_offset = 0; + let static_frame_entries_offset = + initialization_state_offset + InitializationState::::field_count(); + // FIXME: magic number + let instruction_offset = static_frame_entries_offset + 4; + let br_table_offset = instruction_offset + instruction_number; + let padding_offset = br_table_offset + br_table_number; + let init_memory_offset = INIT_MEMORY_OFFSET; + + assert!(padding_offset <= init_memory_offset); + + Self { + _heap_capability: pages_capability * PAGE_ENTRIES, + initialization_state_offset, + static_frame_entries_offset, + instruction_offset, + br_table_offset, + padding_offset, + init_memory_offset, + } + } + + pub fn exec_initialization_state( + &mut self, + mut initialization_state_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + initialization_state_handler(self.initialization_state_offset) + } + + pub fn exec_static_frame_entries( + &mut self, + mut static_frame_entries_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + static_frame_entries_handler(self.static_frame_entries_offset) + } + + pub fn exec_instruction( + &mut self, + mut instruction_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + instruction_handler(self.instruction_offset) + } + + pub fn exec_br_table_entires( + &mut self, + mut br_table_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + br_table_handler(self.br_table_offset) + } + + pub fn exec_padding_entires( + &mut self, + mut padding_handler: impl FnMut(usize, usize) -> Result, Error>, + ) -> Result, Error> { + padding_handler(self.padding_offset, self.padding_offset) + } + + pub fn exec_init_memory_entires( + &mut self, + mut init_memory_entries_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + init_memory_entries_handler(self.init_memory_offset) + } + + pub fn exec( + &mut self, + initialization_state_handler: impl FnMut(usize) -> Result, Error>, + static_frame_entries_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>, + init_memory_entries_handler: impl FnMut(usize) -> Result, Error>, + ) -> Result, Error> { + let initialization_state = self.exec_initialization_state(initialization_state_handler)?; + let static_frame_entries = self.exec_static_frame_entries(static_frame_entries_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)?; + let _init_memory_entires = self.exec_init_memory_entires(init_memory_entries_handler)?; + + Ok(Layouter { + initialization_state, + static_frame_entries, + instructions, + br_table_entires, + _padding_entires, + _init_memory_entires, + }) + } +} diff --git a/crates/zkwasm/src/circuits/utils/mod.rs b/crates/zkwasm/src/circuits/utils/mod.rs index 83703b4d6..28276c6ef 100644 --- a/crates/zkwasm/src/circuits/utils/mod.rs +++ b/crates/zkwasm/src/circuits/utils/mod.rs @@ -5,6 +5,7 @@ use num_bigint::BigUint; pub mod bit; pub mod common_range; +pub mod image_table; pub mod row_diff; pub mod step_status; pub mod u16; From 07c872422192aa3d6633e71a7200e155ab17422e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 27 Nov 2023 00:12:44 +0800 Subject: [PATCH 03/28] refine post image table --- .../zkwasm/src/circuits/image_table/assign.rs | 121 +-- crates/zkwasm/src/circuits/image_table/mod.rs | 2 + .../circuits/post_image_table/continuation.rs | 782 ++++++++++++------ .../src/circuits/post_image_table/mod.rs | 10 +- .../src/circuits/post_image_table/trivial.rs | 10 +- .../zkwasm/src/circuits/test_circuit/mod.rs | 8 +- .../zkwasm/src/circuits/utils/image_table.rs | 10 +- 7 files changed, 546 insertions(+), 397 deletions(-) diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index c02e30000..4fb7035c7 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -25,108 +25,6 @@ impl ImageTableChip { image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, ) -> Result>, Error> { - macro_rules! assign { - ($ctx:expr, $col:expr, $v:expr) => {{ - let cell = - $ctx.region - .assign_advice(|| "image table", $col, $ctx.offset, || Ok($v))?; - - $ctx.next(); - - Ok::, Error>(cell) - }}; - } - - // fn assign_and_perm_initialization_state( - // ctx: &mut Context, - // col: Column, - // initialization_state: &InitializationState>, - // ) -> Result>, Error> { - // let initialization_state = initialization_state.map(|field| { - // field - // .copy_advice( - // || "image table: initialization state", - // &mut ctx.region, - // col, - // ctx.offset, - // ) - // .unwrap(); - - // ctx.next(); - - // field.clone() - // }); - - // Ok::<_, Error>(initialization_state) - // } - - // fn assign_static_frame_entries( - // ctx: &mut Context, - // col: Column, - // static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, - // ) -> Result<(), Error> { - // for (enable, entry) in static_frame_entries { - // enable.copy_advice( - // || "image table: static frame entry", - // &mut ctx.region, - // col, - // ctx.offset, - // )?; - // ctx.next(); - - // entry.copy_advice( - // || "image table: static frame entry", - // &mut ctx.region, - // col, - // ctx.offset, - // )?; - // ctx.next(); - // } - - // Ok(()) - // } - - // fn assign_instructions( - // ctx: &mut Context, - // col: Column, - // instructions: &Vec, - // ) -> Result>, Error> { - // let entries = instructions - // .iter() - // .map(|entry| assign!(ctx, col, *entry)) - // .collect::, Error>>()?; - - // Ok(entries) - // } - - // fn assign_br_table( - // ctx: &mut Context, - // col: Column, - // br_table: &Vec, - // ) -> Result>, Error> { - // let entries = br_table - // .iter() - // .map(|entry| assign!(ctx, col, *entry)) - // .collect::, Error>>()?; - - // Ok(entries) - // } - - // fn assign_init_memory_entries( - // ctx: &mut Context, - // col: Column, - // init_memory_entries: &Vec, - // ) -> Result<(), Error> { - // assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); - // ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; - - // for entry in init_memory_entries { - // assign!(ctx, col, *entry)?; - // } - - // Ok(()) - // } - layouter.assign_region( || "pre image table", |region| { @@ -294,29 +192,12 @@ impl ImageTableChip { init_memory_handler, )?; - // let instructions = assign_instructions( - // &mut ctx, - // self.config.col, - // image_table.instructions.as_ref().unwrap(), - // ) - // .ok(); - // let br_table = assign_br_table( - // &mut ctx, - // self.config.col, - // image_table.br_table.as_ref().unwrap(), - // ) - // .ok(); - // assign_init_memory_entries( - // &mut ctx, - // self.config.col, - // &image_table.init_memory_entries.as_ref().unwrap(), - // )?; - Ok(ImageTableLayouter { initialization_state: result.initialization_state, static_frame_entries: result.static_frame_entries, instructions: Some(result.instructions), br_table: Some(result.br_table_entires), + padding: Some(result.padding_entires), init_memory_entries: None, rest_memory_writing_ops: None, }) diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index a53aaf726..2eae9ceee 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -75,6 +75,7 @@ pub struct ImageTableLayouter { pub static_frame_entries: Vec<(T, T)>, pub instructions: Option>, pub br_table: Option>, + pub padding: Option>, pub init_memory_entries: Option>, pub rest_memory_writing_ops: Option, } @@ -221,6 +222,7 @@ impl EncodeCompilationTableValues for CompilationTable { static_frame_entries, instructions, br_table, + padding: None, init_memory_entries, rest_memory_writing_ops: None, } diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 82fb19ad3..2cfaba863 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -1,9 +1,10 @@ +use std::cell::RefCell; use std::marker::PhantomData; +use std::rc::Rc; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; use halo2_proofs::circuit::Layouter; -use halo2_proofs::circuit::Region; use halo2_proofs::plonk::Advice; use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; @@ -12,15 +13,14 @@ use halo2_proofs::plonk::Fixed; use num_bigint::BigUint; use specs::encode::init_memory_table::encode_init_memory_table_address; use specs::mtable::LocationType; -use specs::state::InitializationState; use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::ImageTableConfig; use crate::circuits::image_table::ImageTableLayouter; use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; -use crate::circuits::image_table::PAGE_ENTRIES; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::bn_to_field; +use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::Context; use crate::constant_from; use crate::curr; @@ -94,288 +94,536 @@ impl PostImageTableConfigTrait for ContinuationPostImageTableCon pub(in crate::circuits) struct ContinuationPostImageTableChip { config: ContinuationPostImageTableConfig, - circuit_maximal_pages: u32, } impl PostImageTableChipTrait> for ContinuationPostImageTableChip { - fn new(config: ContinuationPostImageTableConfig, circuit_maximal_pages: u32) -> Self { - Self { - config, - circuit_maximal_pages, - } + fn new(config: ContinuationPostImageTableConfig) -> Self { + Self { config } } fn assign( self, layouter: &mut impl Layouter, + image_table_assigner: &mut ImageTableAssigner< + INIT_MEMORY_ENTRIES_OFFSET, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_VALUE_STACK_LIMIT, + >, pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, ) -> Result<(), Error> { - fn init_sel( - region: &mut Region, - sel: Column, - rest_memory_finalized_count: Column, - circuit_maximal_pages: u32, - ) -> Result<(), Error> { - let mut offset = INIT_MEMORY_ENTRIES_OFFSET; - - region.assign_fixed(|| "post image table: init", sel, offset, || Ok(F::zero()))?; - - offset += 1; - - macro_rules! assign_address { - ($l:expr, $o:expr) => {{ - region.assign_fixed( - || "post image table: init", - sel, - offset, - || { - Ok(bn_to_field(&encode_init_memory_table_address( - BigUint::from($l as u64), - BigUint::from($o as u64), - ))) - }, - )?; - - offset += 1; - - Ok::<_, Error>(()) - }}; - } - - for i in 0..DEFAULT_VALUE_STACK_LIMIT { - assign_address!(LocationType::Stack, i)?; - } - - for i in 0..DEFAULT_VALUE_STACK_LIMIT { - assign_address!(LocationType::Global, i)?; - } - - for i in 0..(circuit_maximal_pages * PAGE_ENTRIES) { - assign_address!(LocationType::Heap, i)?; - } - - region.assign_advice_from_constant( - || "post image table: init memory", - rest_memory_finalized_count, - offset, - F::zero(), - )?; - - Ok(()) - } - - fn assign_and_perm_initialization_state( - ctx: &mut Context, - post_image_table_col: Column, - initialization_state: &InitializationState>, - ) -> Result<(), Error> { - Ok::<_, Error>(initialization_state.for_each(|field| { - field - .copy_advice( - || "image table: initialization state", - &mut ctx.region, - post_image_table_col, - ctx.offset, - ) - .unwrap(); - - ctx.next(); - })) - } - - fn assign_static_frame_entries( - ctx: &mut Context, - post_image_table_col: Column, - static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, - ) -> Result<(), Error> { - for (enable, entry) in static_frame_entries { - enable.copy_advice( - || "image table: static frame entry", - &mut ctx.region, - post_image_table_col, - ctx.offset, - )?; - ctx.next(); - - entry.copy_advice( - || "image table: static frame entry", - &mut ctx.region, - post_image_table_col, - ctx.offset, - )?; - ctx.next(); - } - - Ok(()) - } - - fn assign_instructions( - ctx: &mut Context, - post_image_table_col: Column, - instructions: &Vec>, - ) -> Result<(), Error> { - for cell in instructions { - cell.copy_advice( - || "post image table: instructions", - &mut ctx.region, - post_image_table_col, - ctx.offset, - )?; - - ctx.next(); - } - - Ok(()) - } - - fn assign_br_table( - ctx: &mut Context, - post_image_table_col: Column, - br_table: &Vec>, - ) -> Result<(), Error> { - for cell in br_table { - cell.copy_advice( - || "post image table: instructions", - &mut ctx.region, - post_image_table_col, - ctx.offset, - )?; - - ctx.next(); - } - - Ok(()) - } - - fn assign_init_memory_entries( - ctx: &mut Context, - sel: Column, - post_image_table_col: Column, - update_col: Column, - rest_memory_finalized_ops_col: Column, - pre_image_table: &ImageTableLayouter, - post_image_table: &ImageTableLayouter, - permutation_cells: &ImageTableLayouter>, - circuit_maximal_pages: u32, - ) -> Result<(), Error> { - assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); - ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; - - assert_eq!( - pre_image_table.init_memory_entries.as_ref().unwrap().len(), - post_image_table.init_memory_entries.as_ref().unwrap().len() - ); - - init_sel( - &mut ctx.region, - sel, - rest_memory_finalized_ops_col, - circuit_maximal_pages, - )?; - - permutation_cells - .rest_memory_writing_ops - .as_ref() - .unwrap() - .copy_advice( - || "post image table: init memory", - &mut ctx.region, - rest_memory_finalized_ops_col, - ctx.offset, - )?; - - let mut rest_memory_writing_ops = *permutation_cells - .rest_memory_writing_ops - .as_ref() - .unwrap() - .value() - .unwrap(); - - for (pre, post) in pre_image_table - .init_memory_entries - .as_ref() - .unwrap() - .iter() - .zip( - post_image_table - .init_memory_entries - .as_ref() - .unwrap() - .iter(), - ) - { - ctx.region.assign_advice( - || "post image table: init memory", - post_image_table_col, - ctx.offset, - || Ok(*post), - )?; - - ctx.region.assign_advice( - || "post image table: init memory", - rest_memory_finalized_ops_col, - ctx.offset, - || Ok(rest_memory_writing_ops), - )?; - - if pre != post { - ctx.region.assign_advice( - || "post image table: init memory", - update_col, - ctx.offset, - || Ok(F::one()), - )?; - - rest_memory_writing_ops = rest_memory_writing_ops - F::one(); - } - - ctx.next(); - } - - assert_eq!(rest_memory_writing_ops, F::zero()); - - Ok::<_, Error>(()) - } + // fn init_sel( + // region: &mut Region, + // sel: Column, + // rest_memory_finalized_count: Column, + // circuit_maximal_pages: u32, + // ) -> Result<(), Error> { + // let mut offset = INIT_MEMORY_ENTRIES_OFFSET; + + // region.assign_fixed(|| "post image table: init", sel, offset, || Ok(F::zero()))?; + + // offset += 1; + + // macro_rules! assign_address { + // ($l:expr, $o:expr) => {{ + // region.assign_fixed( + // || "post image table: init", + // sel, + // offset, + // || { + // Ok(bn_to_field(&encode_init_memory_table_address( + // BigUint::from($l as u64), + // BigUint::from($o as u64), + // ))) + // }, + // )?; + + // offset += 1; + + // Ok::<_, Error>(()) + // }}; + // } + + // for i in 0..DEFAULT_VALUE_STACK_LIMIT { + // assign_address!(LocationType::Stack, i)?; + // } + + // for i in 0..DEFAULT_VALUE_STACK_LIMIT { + // assign_address!(LocationType::Global, i)?; + // } + + // for i in 0..(circuit_maximal_pages * PAGE_ENTRIES) { + // assign_address!(LocationType::Heap, i)?; + // } + + // region.assign_advice_from_constant( + // || "post image table: init memory", + // rest_memory_finalized_count, + // offset, + // F::zero(), + // )?; + + // Ok(()) + // } + + // fn assign_static_frame_entries( + // ctx: &mut Context, + // post_image_table_col: Column, + // static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, + // ) -> Result<(), Error> { + // for (enable, entry) in static_frame_entries { + // enable.copy_advice( + // || "image table: static frame entry", + // &mut ctx.region, + // post_image_table_col, + // ctx.offset, + // )?; + // ctx.next(); + + // entry.copy_advice( + // || "image table: static frame entry", + // &mut ctx.region, + // post_image_table_col, + // ctx.offset, + // )?; + // ctx.next(); + // } + + // Ok(()) + // } + + // fn assign_instructions( + // ctx: &mut Context, + // post_image_table_col: Column, + // instructions: &Vec>, + // ) -> Result<(), Error> { + // for cell in instructions { + // cell.copy_advice( + // || "post image table: instruction and br table", + // &mut ctx.region, + // post_image_table_col, + // ctx.offset, + // )?; + + // ctx.next(); + // } + + // Ok(()) + // } + + // fn assign_br_table( + // ctx: &mut Context, + // post_image_table_col: Column, + // br_table: &Vec>, + // ) -> Result<(), Error> { + // for cell in br_table { + // cell.copy_advice( + // || "post image table: instruction and br table", + // &mut ctx.region, + // post_image_table_col, + // ctx.offset, + // )?; + + // ctx.next(); + // } + + // Ok(()) + // } + + // fn assign_padding( + // ctx: &mut Context, + // post_image_table_col: Column, + // padding: &Vec>, + // ) -> Result<(), Error> { + // for cell in padding { + // cell.copy_advice( + // || "post image table: instruction and br table", + // &mut ctx.region, + // post_image_table_col, + // ctx.offset, + // )?; + + // ctx.next(); + // } + + // Ok(()) + // } + + // fn assign_init_memory_entries( + // ctx: &mut Context, + // sel: Column, + // post_image_table_col: Column, + // update_col: Column, + // rest_memory_finalized_ops_col: Column, + // pre_image_table: &ImageTableLayouter, + // post_image_table: &ImageTableLayouter, + // permutation_cells: &ImageTableLayouter>, + // circuit_maximal_pages: u32, + // ) -> Result<(), Error> { + // assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); + // ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; + + // assert_eq!( + // pre_image_table.init_memory_entries.as_ref().unwrap().len(), + // post_image_table.init_memory_entries.as_ref().unwrap().len() + // ); + + // init_sel( + // &mut ctx.region, + // sel, + // rest_memory_finalized_ops_col, + // circuit_maximal_pages, + // )?; + + // permutation_cells + // .rest_memory_writing_ops + // .as_ref() + // .unwrap() + // .copy_advice( + // || "post image table: init memory", + // &mut ctx.region, + // rest_memory_finalized_ops_col, + // ctx.offset, + // )?; + + // let mut rest_memory_writing_ops = *permutation_cells + // .rest_memory_writing_ops + // .as_ref() + // .unwrap() + // .value() + // .unwrap(); + + // for (pre, post) in pre_image_table + // .init_memory_entries + // .as_ref() + // .unwrap() + // .iter() + // .zip( + // post_image_table + // .init_memory_entries + // .as_ref() + // .unwrap() + // .iter(), + // ) + // { + // ctx.region.assign_advice( + // || "post image table: init memory", + // post_image_table_col, + // ctx.offset, + // || Ok(*post), + // )?; + + // ctx.region.assign_advice( + // || "post image table: init memory", + // rest_memory_finalized_ops_col, + // ctx.offset, + // || Ok(rest_memory_writing_ops), + // )?; + + // if pre != post { + // ctx.region.assign_advice( + // || "post image table: init memory", + // update_col, + // ctx.offset, + // || Ok(F::one()), + // )?; + + // rest_memory_writing_ops = rest_memory_writing_ops - F::one(); + // } + + // ctx.next(); + // } + + // assert_eq!(rest_memory_writing_ops, F::zero()); + + // Ok::<_, Error>(()) + // } layouter.assign_region( || "post image table", |region| { - let mut ctx = Context::new(region); - - assign_and_perm_initialization_state( - &mut ctx, - self.config.post_image_table, - &permutation_cells.initialization_state, - )?; - assign_static_frame_entries( - &mut ctx, - self.config.post_image_table, - &permutation_cells.static_frame_entries, - )?; - assign_instructions( - &mut ctx, - self.config.post_image_table, - permutation_cells.instructions.as_ref().unwrap(), - )?; - assign_br_table( - &mut ctx, - self.config.post_image_table, - permutation_cells.br_table.as_ref().unwrap(), - )?; - assign_init_memory_entries( - &mut ctx, - self.config.memory_addr_sel, - self.config.post_image_table, - self.config.update, - self.config.rest_memory_finalized_count, - &pre_image_table, - &post_image_table, - &permutation_cells, - self.circuit_maximal_pages, + let ctx = Rc::new(RefCell::new(Context::new(region))); + + let initialization_state_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + let initialization_state = + permutation_cells.initialization_state.map(|field| { + let offset = ctx.borrow().offset; + + field + .copy_advice( + || "image table: initialization state", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + ) + .unwrap(); + + ctx.borrow_mut().next(); + + field.clone() + }); + + Ok::<_, Error>(initialization_state) + }; + + let static_frame_entries_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + permutation_cells + .static_frame_entries + .iter() + .map(|(enable, entry)| { + let offset = ctx.borrow().offset; + + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + ctx.borrow_mut().next(); + + let offset = ctx.borrow().offset; + + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + ctx.borrow_mut().next(); + + Ok::<_, Error>((enable.clone(), entry.clone())) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let instruction_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + permutation_cells + .instructions + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + + let entry = entry.copy_advice( + || "image table", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + + ctx.borrow_mut().next(); + + Ok(entry) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let br_table_handler = |base_offset| { + ctx.borrow_mut().offset = base_offset; + + permutation_cells + .br_table + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + + let entry = entry.copy_advice( + || "image table", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + + ctx.borrow_mut().next(); + + Ok(entry) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let padding_handler = |start_offset, _| { + ctx.borrow_mut().offset = start_offset; + + permutation_cells + .padding + .as_ref() + .unwrap() + .iter() + .map(|entry| { + let offset = ctx.borrow().offset; + + let entry = entry.copy_advice( + || "image table", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + + ctx.borrow_mut().next(); + + Ok(entry) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }; + + let heap_capability = image_table_assigner.heap_capability; + let init_memory_entries_handler = |base_offset| { + // Assign fixed and constant + { + let mut offset = base_offset; + + ctx.borrow_mut().region.assign_fixed( + || "post image table", + self.config.memory_addr_sel, + offset, + || Ok(F::zero()), + )?; + + offset += 1; + + macro_rules! assign_address { + ($l:expr, $o:expr) => {{ + ctx.borrow_mut().region.assign_fixed( + || "post image table: init", + self.config.memory_addr_sel, + offset, + || { + Ok(bn_to_field(&encode_init_memory_table_address( + BigUint::from($l as u64), + BigUint::from($o as u64), + ))) + }, + )?; + + offset += 1; + + Ok::<_, Error>(()) + }}; + } + + for i in 0..DEFAULT_VALUE_STACK_LIMIT { + assign_address!(LocationType::Stack, i)?; + } + + for i in 0..DEFAULT_VALUE_STACK_LIMIT { + assign_address!(LocationType::Global, i)?; + } + + for i in 0..heap_capability { + assign_address!(LocationType::Heap, i)?; + } + + ctx.borrow_mut().region.assign_advice_from_constant( + || "post image table: init memory", + self.config.rest_memory_finalized_count, + offset, + F::zero(), + )?; + } + + { + // First line is placeholder for default lookup + let offset = base_offset + 1; + + permutation_cells + .rest_memory_writing_ops + .as_ref() + .unwrap() + .copy_advice( + || "post image table: init memory", + &mut ctx.borrow_mut().region, + self.config.rest_memory_finalized_count, + offset, + )?; + } + + let entries = { + let mut offset = base_offset; + + let mut rest_memory_writing_ops = *permutation_cells + .rest_memory_writing_ops + .as_ref() + .unwrap() + .value() + .unwrap(); + + pre_image_table + .init_memory_entries + .as_ref() + .unwrap() + .iter() + .zip( + post_image_table + .init_memory_entries + .as_ref() + .unwrap() + .iter(), + ) + .map(|(pre, post)| { + let entry = ctx.borrow_mut().region.assign_advice( + || "post image table: init memory", + self.config.post_image_table, + offset, + || Ok(*post), + )?; + + ctx.borrow_mut().region.assign_advice( + || "post image table: init memory", + self.config.rest_memory_finalized_count, + offset, + || Ok(rest_memory_writing_ops), + )?; + + if pre != post { + ctx.borrow_mut().region.assign_advice( + || "post image table: init memory", + self.config.update, + offset, + || Ok(F::one()), + )?; + + rest_memory_writing_ops = rest_memory_writing_ops - F::one(); + } + + offset += 1; + + Ok(entry) + }) + .collect::>>() + .into_iter() + .collect::, Error>>() + }?; + + Ok(entries) + }; + + image_table_assigner.exec( + initialization_state_handler, + static_frame_entries_handler, + instruction_handler, + br_table_handler, + padding_handler, + init_memory_entries_handler, )?; Ok(()) diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs index 3dae42d6c..d84f60fef 100644 --- a/crates/zkwasm/src/circuits/post_image_table/mod.rs +++ b/crates/zkwasm/src/circuits/post_image_table/mod.rs @@ -5,10 +5,13 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; use super::image_table::ImageTableConfig; use super::image_table::ImageTableLayouter; +use super::image_table::INIT_MEMORY_ENTRIES_OFFSET; use super::mtable::MemoryTableConfig; +use super::utils::image_table::ImageTableAssigner; pub(self) mod continuation; pub(self) mod trivial; @@ -27,10 +30,15 @@ pub(in crate::circuits) trait PostImageTableChipTrait< Config: PostImageTableConfigTrait, > { - fn new(config: Config, circuit_maximal_pages: u32) -> Self; + fn new(config: Config) -> Self; fn assign( self, layouter: &mut impl Layouter, + image_table_assigner: &mut ImageTableAssigner< + INIT_MEMORY_ENTRIES_OFFSET, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_VALUE_STACK_LIMIT, + >, pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs index 4bbef6a48..2ff070cc8 100644 --- a/crates/zkwasm/src/circuits/post_image_table/trivial.rs +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -7,10 +7,13 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::ImageTableConfig; use crate::circuits::image_table::ImageTableLayouter; +use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::mtable::MemoryTableConfig; +use crate::circuits::utils::image_table::ImageTableAssigner; use super::PostImageTableChipTrait; use super::PostImageTableConfigTrait; @@ -38,13 +41,18 @@ pub(in crate::circuits) struct TrivialPostImageTableChip { impl PostImageTableChipTrait> for TrivialPostImageTableChip { - fn new(_config: TrivialPostImageTableConfig, _circuit_maximal_pages: u32) -> Self { + fn new(_config: TrivialPostImageTableConfig) -> Self { Self { _mark: PhantomData } } fn assign( self, _layouter: &mut impl Layouter, + _image_table_assigner: &mut ImageTableAssigner< + INIT_MEMORY_ENTRIES_OFFSET, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_VALUE_STACK_LIMIT, + >, _pre_image_table: ImageTableLayouter, _post_image_table: ImageTableLayouter, _permutation_cells: ImageTableLayouter>, diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 0755d7d9c..0a272060a 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -186,8 +186,7 @@ impl Circuit for TestCircuit { let rchip = RangeTableChip::new(config.rtable); let image_chip = ImageTableChip::new(config.image_table); - let post_image_chip = - PostImageTableChip::new(config.post_image_table, config.circuit_maximal_pages); + let post_image_chip = PostImageTableChip::new(config.post_image_table); let mchip = MemoryTableChip::new(config.mtable, config.max_available_rows); let jchip = JumpTableChip::new(config.jtable, config.max_available_rows); let echip = EventTableChip::new( @@ -327,7 +326,7 @@ impl Circuit for TestCircuit { .len() + self.tables.compilation_tables.elem_table.entries().len() + 1, - compute_maximal_pages(zkwasm_k()), + config.circuit_maximal_pages, ); let pre_image_table_cells = exec_with_profile!( @@ -343,6 +342,7 @@ impl Circuit for TestCircuit { static_frame_entries, instructions: None, br_table: None, + padding: None, init_memory_entries: None, rest_memory_writing_ops: None, } @@ -353,6 +353,7 @@ impl Circuit for TestCircuit { || "Assign Post Image Table", post_image_chip.assign( &mut layouter, + &mut image_table_assigner, self.tables .compilation_tables .encode_compilation_table_values(), @@ -364,6 +365,7 @@ impl Circuit for TestCircuit { static_frame_entries: pre_image_table_cells.static_frame_entries, instructions: pre_image_table_cells.instructions, br_table: pre_image_table_cells.br_table, + padding: pre_image_table_cells.padding, init_memory_entries: pre_image_table_cells.init_memory_entries, rest_memory_writing_ops, } diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index e32bd7cc3..ec00409bf 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -27,7 +27,7 @@ pub(crate) struct Layouter { pub(crate) instructions: Vec, pub(crate) br_table_entires: Vec, // NOTE: padding entries also need constain_equal for other image - pub(crate) _padding_entires: Vec, + pub(crate) padding_entires: Vec, pub(crate) _init_memory_entires: Vec, } @@ -36,7 +36,7 @@ pub(crate) struct ImageTableAssigner< const STACK_CAPABILITY: usize, const GLOBAL_CAPABILITY: usize, > { - _heap_capability: u32, + pub(crate) heap_capability: u32, initialization_state_offset: usize, static_frame_entries_offset: usize, instruction_offset: usize, @@ -64,7 +64,7 @@ impl< assert!(padding_offset <= init_memory_offset); Self { - _heap_capability: pages_capability * PAGE_ENTRIES, + heap_capability: pages_capability * PAGE_ENTRIES, initialization_state_offset, static_frame_entries_offset, instruction_offset, @@ -129,7 +129,7 @@ impl< let static_frame_entries = self.exec_static_frame_entries(static_frame_entries_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)?; + let padding_entires = self.exec_padding_entires(padding_handler)?; let _init_memory_entires = self.exec_init_memory_entires(init_memory_entries_handler)?; Ok(Layouter { @@ -137,7 +137,7 @@ impl< static_frame_entries, instructions, br_table_entires, - _padding_entires, + padding_entires, _init_memory_entires, }) } From 5d79edab771ad60febeef4e01e40fd306f3c612b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 27 Nov 2023 23:02:36 +0800 Subject: [PATCH 04/28] review 1 fixed --- crates/specs/src/encode/image_table.rs | 13 +++---------- crates/specs/src/encode/init_memory_table.rs | 18 +++++++++--------- crates/zkwasm/src/circuits/mtable/allocator.rs | 6 +++--- crates/zkwasm/src/circuits/test_circuit/mod.rs | 4 ++-- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/crates/specs/src/encode/image_table.rs b/crates/specs/src/encode/image_table.rs index 8a8182049..89e6afb3c 100644 --- a/crates/specs/src/encode/image_table.rs +++ b/crates/specs/src/encode/image_table.rs @@ -1,4 +1,3 @@ -use num_bigint::BigUint; use num_bigint::ToBigUint; use crate::encode::br_table::BR_TABLE_ENCODE_BOUNDARY; @@ -22,14 +21,8 @@ impl ImageTableEncoder { assert!(BR_TABLE_ENCODE_BOUNDARY <= CLASS_SHIFT); assert!(INIT_MEMORY_ENCODE_BOUNDARY <= CLASS_SHIFT); - let tag = if cfg!(feature = "continuation") && *self == ImageTableEncoder::InitMemory { - // Memory Initialization Lookup with continuation - T::from_bn(&BigUint::zero()) - } else { - T::from_bn(&(*self as u64).to_biguint().unwrap()) - * T::from_bn(&(1u64.to_biguint().unwrap() << CLASS_SHIFT)) - }; - - tag + data + T::from_bn(&(*self as u64).to_biguint().unwrap()) + * T::from_bn(&(1u64.to_biguint().unwrap() << CLASS_SHIFT)) + + data } } diff --git a/crates/specs/src/encode/init_memory_table.rs b/crates/specs/src/encode/init_memory_table.rs index f3a59e5f2..8b353a748 100644 --- a/crates/specs/src/encode/init_memory_table.rs +++ b/crates/specs/src/encode/init_memory_table.rs @@ -17,24 +17,24 @@ pub fn encode_init_memory_table_entry( eid: T, value: T, ) -> T { - const LTYPE_SHIFT: u32 = OFFSET_SHIFT + 32; + const LTYPE_SHIFT: u32 = OFFSET_SHIFT + u32::BITS; const OFFSET_SHIFT: u32 = IS_MUTABLE_SHIFT + 1; - const IS_MUTABLE_SHIFT: u32 = EID_OFFSET_SHIFT + 32; + const IS_MUTABLE_SHIFT: u32 = EID_OFFSET_SHIFT + u32::BITS; const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + 64; const VALUE_SHIFT: u32 = 0; assert!(LTYPE_SHIFT + 8 <= INIT_MEMORY_ENCODE_BOUNDARY); + let encode = is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) + + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) + + value; + if cfg!(feature = "continuation") { + encode + } else { ltype * T::from_bn(&(1u64.to_biguint().unwrap() << LTYPE_SHIFT)) + offset * T::from_bn(&(1u64.to_biguint().unwrap() << OFFSET_SHIFT)) - + is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) - + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) - + value - } else { - is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) - + eid * T::from_bn(&(1u64.to_biguint().unwrap() << EID_OFFSET_SHIFT)) - + value + + encode } } diff --git a/crates/zkwasm/src/circuits/mtable/allocator.rs b/crates/zkwasm/src/circuits/mtable/allocator.rs index 5440a982b..d643f75e9 100644 --- a/crates/zkwasm/src/circuits/mtable/allocator.rs +++ b/crates/zkwasm/src/circuits/mtable/allocator.rs @@ -83,9 +83,9 @@ pub(super) enum MemoryTableCellType { const BIT_COLUMNS: usize = 3; const U16_COLUMNS: usize = U32_CELLS.next_multiple_of(2) / 2 + U64_CELLS; -const COMMON_RANGE_COLUMNS: usize = 2; -const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 3 }; -const U32_CELLS: usize = if cfg!(feature = "continuation") { 9 } else { 6 }; +const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 1 } else { 2 }; +const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 3 } else { 2 }; +const U32_CELLS: usize = if cfg!(feature = "continuation") { 5 } else { 2 }; const U64_CELLS: usize = 1; #[derive(Debug, Clone)] diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 0a272060a..192640a43 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -56,9 +56,9 @@ use super::image_table::ImageTableConfig; use super::post_image_table::PostImageTableConfig; pub const VAR_COLUMNS: usize = if cfg!(feature = "continuation") { - 63 + 59 } else { - 54 + 51 }; // Reserve a few rows to keep usable rows away from blind rows. From 2da075aaf0de7f1d6f13214791c86c330ed7e74d Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 27 Nov 2023 23:07:12 +0800 Subject: [PATCH 05/28] fix --- crates/specs/src/encode/image_table.rs | 2 +- crates/specs/src/encode/init_memory_table.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/specs/src/encode/image_table.rs b/crates/specs/src/encode/image_table.rs index 89e6afb3c..032bfc0ec 100644 --- a/crates/specs/src/encode/image_table.rs +++ b/crates/specs/src/encode/image_table.rs @@ -6,7 +6,7 @@ use crate::encode::instruction_table::INSTRUCTION_ENCODE_BOUNDARY; use super::FromBn; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy)] pub enum ImageTableEncoder { Instruction = 1, BrTable = 2, diff --git a/crates/specs/src/encode/init_memory_table.rs b/crates/specs/src/encode/init_memory_table.rs index 8b353a748..56a8e8e25 100644 --- a/crates/specs/src/encode/init_memory_table.rs +++ b/crates/specs/src/encode/init_memory_table.rs @@ -20,7 +20,7 @@ pub fn encode_init_memory_table_entry( const LTYPE_SHIFT: u32 = OFFSET_SHIFT + u32::BITS; const OFFSET_SHIFT: u32 = IS_MUTABLE_SHIFT + 1; const IS_MUTABLE_SHIFT: u32 = EID_OFFSET_SHIFT + u32::BITS; - const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + 64; + const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + u64::BITS; const VALUE_SHIFT: u32 = 0; assert!(LTYPE_SHIFT + 8 <= INIT_MEMORY_ENCODE_BOUNDARY); From f2fbe059ac58cacda335b1d91442473d684f3dea Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Dec 2023 07:39:03 +0000 Subject: [PATCH 06/28] update comment --- crates/zkwasm/src/circuits/etable/assign.rs | 46 +++++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index 85ff77263..adda194a6 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -23,26 +23,36 @@ use crate::circuits::utils::Context; * Etable Layouter with Continuation * * Not last slice - * | ---- | ------ | ---------- | --------- | - * | sel | enable | rest_mops | states ... | - * | ---- + ------ | ---------- + --------- | - * | 1 | 1 | | ... | - * | 1 | 1 | | ... | - * | 1 | 1 | | ... | - * | 0 | 0 | constant 0 | ... | permutation row(status should keep consistent with previous row) + * - `self.capability` entries with `enable = 1`. + * - one entry(only including status) with enable = 0, the status of this entry should constrain equality + * with the first entry in the next slice. * + * | -------- | ---- | ------ | ---------- | ---- | ------ | + * | | sel | enable | rest_mops | jops | states | + * | -------- | ---- + ------ | ---------- + ---- | ------ | + * | event | 1 | 1 | | | | permutation with pre image table + * | table | 1 | 1 | | | | + * | entries | 1 | 1 | | | | + * | | 1 | 1 | | | | + * | -------- | ---- | ------ | ---------- | ---- | ------ | + * | | 0 | 0 | constant 0 | | | permutation with post image table * - * Not last slice - * | ---- | ------ | ---------- | ------ | - * | sel | enable | rest_mops | states | - * | ---- + ------ | ---------- + -------| - * | 1 | 1 | | ... | - * | 1 | 1 | | ... | - * | 1 | 0 | | ... | - * | 1 | 0 | | ... | - * | 1 | 0 | | ... | - * | 1 | 0 | | ... | - * | 0 | 0 | constant 0 | ... | permutation row + * + * Last slice + * `` + * | -------- | ---- | ------ | ---------- | ---- | ------ | + * | | sel | enable | rest_mops | jops | states | + * | -------- | ---- + ------ | ---------- + ---- | -------| + * | event | 1 | 1 | | | | permutation with pre image table + * | table | 1 | 1 | | | | + * | entires | 1 | 1 | | | | + * | -------- | ---- | ------ | ---------- | ---- | ------ | + * | padding | 1 | 0 | | | | padding rows are used to copy termination status + * | | 1 | 0 | | | | to permutation row + * | | 1 | 0 | | | | + * | | 1 | 0 | | | | + * | -------- | ---- | ------ | ---------- | ---- | ------ | + * | | 0 | 0 | constant 0 | | | permutation with post image table/jops constrain with jtable */ pub(in crate::circuits) struct EventTablePermutationCells { From 7530eb2658764685940e41b63dda01a041261149 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Dec 2023 08:48:04 +0000 Subject: [PATCH 07/28] fix: use F instead of AssignedCell to avoid unwrap --- crates/zkwasm/src/circuits/mtable/assign.rs | 20 +- .../circuits/post_image_table/continuation.rs | 235 +----------------- .../src/circuits/post_image_table/mod.rs | 1 + .../src/circuits/post_image_table/trivial.rs | 1 + .../zkwasm/src/circuits/test_circuit/mod.rs | 141 +++++------ 5 files changed, 82 insertions(+), 316 deletions(-) diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index 0acb7ea27..437b12284 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -297,7 +297,7 @@ impl MemoryTableChip { etable_rest_mops_cell: &Option>, mtable: &MemoryWritingTable, imtable: &InitMemoryTable, - ) -> Result>, Error> { + ) -> Result<(Option>, F), Error> { debug!("size of memory writing table: {}", mtable.0.len()); assert!(mtable.0.len() * (MEMORY_TABLE_ENTRY_ROWS as usize) < self.maximal_available_rows); @@ -309,11 +309,11 @@ impl MemoryTableChip { self.assign_fixed(ctx)?; ctx.reset(); - let _rest_memory_updating_ops = self.compute_rest_memory_updating_ops(mtable); + let rest_memory_updating_ops = self.compute_rest_memory_updating_ops(mtable); #[cfg(feature = "continuation")] - let rest_memory_updating_ops = - self.constrain_rest_memory_updating_ops(ctx, _rest_memory_updating_ops)?; + let rest_memory_updating_ops_cell = + self.constrain_rest_memory_updating_ops(ctx, rest_memory_updating_ops)?; let rest_mops_cell = self.constrain_rest_mops_permutation(ctx, etable_rest_mops_cell, rest_mops)?; @@ -322,21 +322,15 @@ impl MemoryTableChip { * Skip subsequent advice assignment in the first pass to enhance performance. */ if rest_mops_cell.value().is_some() { - self.assign_entries( - ctx, - mtable, - rest_mops, - imtable, - self.compute_rest_memory_updating_ops(mtable), - )?; + self.assign_entries(ctx, mtable, rest_mops, imtable, rest_memory_updating_ops)?; ctx.reset(); } cfg_if::cfg_if! { if #[cfg(feature="continuation")] { - Ok(Some(rest_memory_updating_ops)) + Ok((Some(rest_memory_updating_ops_cell), F::from(rest_memory_updating_ops as u64))) } else { - Ok(None) + Ok((None, F::from(rest_memory_updating_ops as u64))) } } } diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 2cfaba863..6b9ab9de2 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -114,234 +114,8 @@ impl PostImageTableChipTrait pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, + rest_memory_writing_ops: F, ) -> Result<(), Error> { - // fn init_sel( - // region: &mut Region, - // sel: Column, - // rest_memory_finalized_count: Column, - // circuit_maximal_pages: u32, - // ) -> Result<(), Error> { - // let mut offset = INIT_MEMORY_ENTRIES_OFFSET; - - // region.assign_fixed(|| "post image table: init", sel, offset, || Ok(F::zero()))?; - - // offset += 1; - - // macro_rules! assign_address { - // ($l:expr, $o:expr) => {{ - // region.assign_fixed( - // || "post image table: init", - // sel, - // offset, - // || { - // Ok(bn_to_field(&encode_init_memory_table_address( - // BigUint::from($l as u64), - // BigUint::from($o as u64), - // ))) - // }, - // )?; - - // offset += 1; - - // Ok::<_, Error>(()) - // }}; - // } - - // for i in 0..DEFAULT_VALUE_STACK_LIMIT { - // assign_address!(LocationType::Stack, i)?; - // } - - // for i in 0..DEFAULT_VALUE_STACK_LIMIT { - // assign_address!(LocationType::Global, i)?; - // } - - // for i in 0..(circuit_maximal_pages * PAGE_ENTRIES) { - // assign_address!(LocationType::Heap, i)?; - // } - - // region.assign_advice_from_constant( - // || "post image table: init memory", - // rest_memory_finalized_count, - // offset, - // F::zero(), - // )?; - - // Ok(()) - // } - - // fn assign_static_frame_entries( - // ctx: &mut Context, - // post_image_table_col: Column, - // static_frame_entries: &Vec<(AssignedCell, AssignedCell)>, - // ) -> Result<(), Error> { - // for (enable, entry) in static_frame_entries { - // enable.copy_advice( - // || "image table: static frame entry", - // &mut ctx.region, - // post_image_table_col, - // ctx.offset, - // )?; - // ctx.next(); - - // entry.copy_advice( - // || "image table: static frame entry", - // &mut ctx.region, - // post_image_table_col, - // ctx.offset, - // )?; - // ctx.next(); - // } - - // Ok(()) - // } - - // fn assign_instructions( - // ctx: &mut Context, - // post_image_table_col: Column, - // instructions: &Vec>, - // ) -> Result<(), Error> { - // for cell in instructions { - // cell.copy_advice( - // || "post image table: instruction and br table", - // &mut ctx.region, - // post_image_table_col, - // ctx.offset, - // )?; - - // ctx.next(); - // } - - // Ok(()) - // } - - // fn assign_br_table( - // ctx: &mut Context, - // post_image_table_col: Column, - // br_table: &Vec>, - // ) -> Result<(), Error> { - // for cell in br_table { - // cell.copy_advice( - // || "post image table: instruction and br table", - // &mut ctx.region, - // post_image_table_col, - // ctx.offset, - // )?; - - // ctx.next(); - // } - - // Ok(()) - // } - - // fn assign_padding( - // ctx: &mut Context, - // post_image_table_col: Column, - // padding: &Vec>, - // ) -> Result<(), Error> { - // for cell in padding { - // cell.copy_advice( - // || "post image table: instruction and br table", - // &mut ctx.region, - // post_image_table_col, - // ctx.offset, - // )?; - - // ctx.next(); - // } - - // Ok(()) - // } - - // fn assign_init_memory_entries( - // ctx: &mut Context, - // sel: Column, - // post_image_table_col: Column, - // update_col: Column, - // rest_memory_finalized_ops_col: Column, - // pre_image_table: &ImageTableLayouter, - // post_image_table: &ImageTableLayouter, - // permutation_cells: &ImageTableLayouter>, - // circuit_maximal_pages: u32, - // ) -> Result<(), Error> { - // assert!(ctx.offset < INIT_MEMORY_ENTRIES_OFFSET); - // ctx.offset = INIT_MEMORY_ENTRIES_OFFSET; - - // assert_eq!( - // pre_image_table.init_memory_entries.as_ref().unwrap().len(), - // post_image_table.init_memory_entries.as_ref().unwrap().len() - // ); - - // init_sel( - // &mut ctx.region, - // sel, - // rest_memory_finalized_ops_col, - // circuit_maximal_pages, - // )?; - - // permutation_cells - // .rest_memory_writing_ops - // .as_ref() - // .unwrap() - // .copy_advice( - // || "post image table: init memory", - // &mut ctx.region, - // rest_memory_finalized_ops_col, - // ctx.offset, - // )?; - - // let mut rest_memory_writing_ops = *permutation_cells - // .rest_memory_writing_ops - // .as_ref() - // .unwrap() - // .value() - // .unwrap(); - - // for (pre, post) in pre_image_table - // .init_memory_entries - // .as_ref() - // .unwrap() - // .iter() - // .zip( - // post_image_table - // .init_memory_entries - // .as_ref() - // .unwrap() - // .iter(), - // ) - // { - // ctx.region.assign_advice( - // || "post image table: init memory", - // post_image_table_col, - // ctx.offset, - // || Ok(*post), - // )?; - - // ctx.region.assign_advice( - // || "post image table: init memory", - // rest_memory_finalized_ops_col, - // ctx.offset, - // || Ok(rest_memory_writing_ops), - // )?; - - // if pre != post { - // ctx.region.assign_advice( - // || "post image table: init memory", - // update_col, - // ctx.offset, - // || Ok(F::one()), - // )?; - - // rest_memory_writing_ops = rest_memory_writing_ops - F::one(); - // } - - // ctx.next(); - // } - - // assert_eq!(rest_memory_writing_ops, F::zero()); - - // Ok::<_, Error>(()) - // } - layouter.assign_region( || "post image table", |region| { @@ -560,12 +334,7 @@ impl PostImageTableChipTrait let entries = { let mut offset = base_offset; - let mut rest_memory_writing_ops = *permutation_cells - .rest_memory_writing_ops - .as_ref() - .unwrap() - .value() - .unwrap(); + let mut rest_memory_writing_ops = rest_memory_writing_ops; pre_image_table .init_memory_entries diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs index d84f60fef..7e99f1091 100644 --- a/crates/zkwasm/src/circuits/post_image_table/mod.rs +++ b/crates/zkwasm/src/circuits/post_image_table/mod.rs @@ -42,6 +42,7 @@ pub(in crate::circuits) trait PostImageTableChipTrait< pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, + rest_memory_writing_ops: F, ) -> Result<(), Error>; } diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs index 2ff070cc8..cac7219e9 100644 --- a/crates/zkwasm/src/circuits/post_image_table/trivial.rs +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -56,6 +56,7 @@ impl PostImageTableChipTrait> _pre_image_table: ImageTableLayouter, _post_image_table: ImageTableLayouter, _permutation_cells: ImageTableLayouter>, + _rest_memory_writing_ops: F, ) -> Result<(), Error> { Ok(()) } diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 192640a43..e56c8f0aa 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -229,77 +229,77 @@ impl Circuit for TestCircuit { )? ); - let (etable_permutation_cells, rest_memory_writing_ops, 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, + let ( + etable_permutation_cells, + (rest_memory_writing_ops_cell, rest_memory_writing_ops), + 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, + &self.tables.post_image_table.initialization_state, + self.tables.is_last_slice, + )? + ); + + let rest_memory_writing_ops = { + ctx.reset(); + + exec_with_profile!( + || "Assign mtable", + mchip.assign( + &mut ctx, + &etable_permutation_cells.rest_mops, &memory_writing_table, - ) - ); - - let etable_permutation_cells = exec_with_profile!( - || "Assign etable", - echip.assign( + &self.tables.compilation_tables.imtable + )? + ) + }; + + 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.initialization_state, - &self.tables.post_image_table.initialization_state, - self.tables.is_last_slice, + &self.tables.execution_tables.jtable, + &etable_permutation_cells.rest_jops, + &self.tables.compilation_tables.static_jtable, )? - ); - - let rest_memory_writing_ops = { - 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, - rest_memory_writing_ops, - jtable_info, - )) - }, - )?; + ) + }; + + { + ctx.reset(); + exec_with_profile!(|| "Assign bit table", bit_chip.assign(&mut ctx, &etable)?); + } + + Ok(( + etable_permutation_cells, + rest_memory_writing_ops, + jtable_info, + )) + }, + )?; exec_with_profile!( || "Assign context cont chip", @@ -367,8 +367,9 @@ impl Circuit for TestCircuit { br_table: pre_image_table_cells.br_table, padding: pre_image_table_cells.padding, init_memory_entries: pre_image_table_cells.init_memory_entries, - rest_memory_writing_ops, - } + rest_memory_writing_ops: rest_memory_writing_ops_cell, + }, + rest_memory_writing_ops )? ); From 64fda699684697875a7c80c48af7b07ebbef1a87 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Dec 2023 14:17:45 +0000 Subject: [PATCH 08/28] fix: fix termination state and imtable --- crates/specs/src/lib.rs | 66 +++++++++---------- crates/zkwasm/src/circuits/image_table/mod.rs | 15 +++++ .../zkwasm/src/circuits/test_circuit/mod.rs | 8 ++- crates/zkwasm/src/loader/mod.rs | 17 ++++- crates/zkwasm/src/runtime/state.rs | 8 +-- 5 files changed, 72 insertions(+), 42 deletions(-) diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index 97c65d416..ca6a6b02d 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -17,6 +17,7 @@ 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; @@ -65,17 +66,6 @@ pub struct Tables { pub is_last_slice: bool, } -impl Tables { - pub fn default(last_slice_circuit: bool) -> Self { - Self { - compilation_tables: CompilationTable::default(), - execution_tables: ExecutionTable::default(), - post_image_table: CompilationTable::default(), - is_last_slice: last_slice_circuit, - } - } -} - impl Tables { pub fn create_memory_table( &self, @@ -90,33 +80,37 @@ impl Tables { .collect::>>() .concat(); - let init_value = memory_entries - .par_iter() - .map(|entry| { - self.compilation_tables - .imtable - .try_find(entry.ltype, entry.offset) - }) - .collect::>(); - let mut set = HashSet::::default(); - memory_entries - .iter() - .zip(init_value.into_iter()) - .for_each(|(entry, init_memory_entry)| { - if let Some(init_memory_entry) = init_memory_entry { - set.insert(MemoryTableEntry { - eid: init_memory_entry.eid, - offset: entry.offset, - ltype: entry.ltype, - atype: AccessType::Init, - vtype: entry.vtype, - is_mutable: entry.is_mutable, - value: init_memory_entry.value, - }); - } - }); + memory_entries.iter().for_each(|entry| { + let init_memory_entry = self + .compilation_tables + .imtable + .try_find(entry.ltype, entry.offset); + + if let Some(init_memory_entry) = init_memory_entry { + set.insert(MemoryTableEntry { + eid: init_memory_entry.eid, + offset: entry.offset, + ltype: entry.ltype, + atype: AccessType::Init, + vtype: entry.vtype, + is_mutable: entry.is_mutable, + value: init_memory_entry.value, + }); + } else if entry.ltype == LocationType::Heap { + // Heap value without init memory entry should equal 0 + set.insert(MemoryTableEntry { + eid: 0, + offset: entry.offset, + ltype: entry.ltype, + atype: AccessType::Init, + vtype: entry.vtype, + is_mutable: entry.is_mutable, + value: 0, + }); + } + }); memory_entries.append(&mut set.into_iter().collect()); diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index 2eae9ceee..c26e7452b 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -9,9 +9,11 @@ use specs::brtable::BrTable; use specs::brtable::ElemTable; use specs::encode::image_table::ImageTableEncoder; use specs::imtable::InitMemoryTable; +use specs::imtable::InitMemoryTableEntry; use specs::itable::InstructionTable; use specs::jtable::StaticFrameEntry; use specs::mtable::LocationType; +use specs::mtable::VarType; use specs::state::InitializationState; use specs::CompilationTable; use std::marker::PhantomData; @@ -165,6 +167,19 @@ impl EncodeCompilationTableValues for CompilationTable { layouter.for_each(|(ltype, offset)| { if let Some(entry) = init_memory_table.try_find(ltype, offset) { + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(entry.encode()), + )); + } else if ltype == LocationType::Heap { + let entry = InitMemoryTableEntry { + ltype, + is_mutable: true, + offset, + vtype: VarType::I64, + value: 0, + eid: 0, + }; + cells.push(bn_to_field::( &ImageTableEncoder::InitMemory.encode(entry.encode()), )); diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index e56c8f0aa..77021e913 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -12,6 +12,7 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; use log::debug; use log::info; +use specs::ExecutionTable; use specs::Tables; use wasmi::DEFAULT_VALUE_STACK_LIMIT; @@ -90,7 +91,12 @@ impl Circuit for TestCircuit { fn without_witnesses(&self) -> Self { TestCircuit::new( - Tables::default(self.tables.is_last_slice), + Tables { + compilation_tables: self.tables.compilation_tables.clone(), + execution_tables: ExecutionTable::default(), + post_image_table: self.tables.post_image_table.clone(), + is_last_slice: self.tables.is_last_slice, + }, self.slice_capability, ) } diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index 86778ebbe..4c32ad0bd 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::ExecutionTable; use specs::Tables; use wasmi::tracer::Tracer; use wasmi::ImportsBuilder; @@ -108,8 +109,22 @@ impl ZkWasmLoader { } fn circuit_without_witness(&self, last_slice_circuit: bool) -> Result> { + let (env, _) = 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::default(last_slice_circuit), + tables: Tables { + compilation_tables: compiled_module.tables.clone(), + execution_tables: ExecutionTable::default(), + post_image_table: compiled_module.tables, // FIXME: odd + is_last_slice: last_slice_circuit, + }, }; Ok(builder.build_circuit::(None)) diff --git a/crates/zkwasm/src/runtime/state.rs b/crates/zkwasm/src/runtime/state.rs index d87998f73..c35ada3a0 100644 --- a/crates/zkwasm/src/runtime/state.rs +++ b/crates/zkwasm/src/runtime/state.rs @@ -67,18 +67,18 @@ impl UpdateCompilationTable for CompilationTable { match &entry.step_info { // TODO: fix hard code StepInfo::CallHost { + plugin, function_name, args, - op_index_in_plugin, .. } => { - if *op_index_in_plugin == HostPlugin::HostInput as usize { - if function_name == "wasm_input" && args[0] != 0 + if *plugin == HostPlugin::HostInput { + 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 { + } else if *plugin == HostPlugin::Context { if function_name == "wasm_read_context" { context_in_index += 1; } else if function_name == "wasm_write_context" { From 2517cc242b31ec995e4277ba29833deb6a58134d Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Dec 2023 03:48:22 +0000 Subject: [PATCH 09/28] fix etable assignment --- crates/zkwasm/src/circuits/etable/assign.rs | 24 +++++++------------ .../zkwasm/src/circuits/utils/step_status.rs | 4 ++-- third-party/wasmi | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index adda194a6..1685b1350 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -3,7 +3,6 @@ use halo2_proofs::circuit::AssignedCell; use halo2_proofs::plonk::Error; use log::debug; use specs::configure_table::ConfigureTable; -use specs::itable::Opcode; use specs::itable::OpcodeClassPlain; use specs::state::InitializationState; use std::collections::BTreeMap; @@ -326,6 +325,7 @@ impl EventTableChip { event_table: &EventTableWithMemoryInfo, configure_table: &ConfigureTable, initialization_state: &InitializationState, + post_initialization_state: &InitializationState, mut rest_mops: u32, mut jops: u32, ) -> Result<(), Error> { @@ -394,19 +394,12 @@ impl EventTableChip { .collect::>(); let terminate_status = Status { - eid: status.last().unwrap().eid + 1, - fid: 0, - iid: 0, - sp: status.last().unwrap().sp - + if let Opcode::Return { drop, .. } = - &event_table.0.last().unwrap().eentry.inst.opcode - { - *drop - } else { - 0 - }, - last_jump_eid: 0, - allocated_memory_pages: status.last().unwrap().allocated_memory_pages, + eid: post_initialization_state.eid, + fid: post_initialization_state.fid, + iid: post_initialization_state.iid, + sp: post_initialization_state.sp, + last_jump_eid: post_initialization_state.frame_id, + allocated_memory_pages: post_initialization_state.initial_memory_pages, }; status.push(terminate_status); @@ -419,7 +412,7 @@ impl EventTableChip { current: &status[index], next: &status[index + 1], current_external_host_call_index: external_host_call_call_index, - configure_table: *configure_table, + configure_table, host_public_inputs, context_in_index, context_out_index, @@ -521,6 +514,7 @@ impl EventTableChip { event_table, configure_table, &initialization_state, + post_initialization_state, rest_mops, jops, )?; diff --git a/crates/zkwasm/src/circuits/utils/step_status.rs b/crates/zkwasm/src/circuits/utils/step_status.rs index 9238a9ad9..acc2e2863 100644 --- a/crates/zkwasm/src/circuits/utils/step_status.rs +++ b/crates/zkwasm/src/circuits/utils/step_status.rs @@ -10,12 +10,12 @@ pub struct Status { pub allocated_memory_pages: u32, } -pub struct StepStatus<'a> { +pub struct StepStatus<'a, 'b> { pub current: &'a Status, pub next: &'a Status, pub current_external_host_call_index: u32, pub host_public_inputs: u32, pub context_in_index: u32, pub context_out_index: u32, - pub configure_table: ConfigureTable, + pub configure_table: &'b ConfigureTable, } diff --git a/third-party/wasmi b/third-party/wasmi index 7cc3411de..56696b8f4 160000 --- a/third-party/wasmi +++ b/third-party/wasmi @@ -1 +1 @@ -Subproject commit 7cc3411de4ca5ab800dec894781bd7accf668046 +Subproject commit 56696b8f424c4cd5fc69af0d4446e90a168ccdf0 From dad30584d7686b6d1b51d72c3fd957ac6360794e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Dec 2023 07:27:59 +0000 Subject: [PATCH 10/28] fix: fix constraints of etable --- crates/zkwasm/src/circuits/etable/mod.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/crates/zkwasm/src/circuits/etable/mod.rs b/crates/zkwasm/src/circuits/etable/mod.rs index fb68ba3cc..817d72c1e 100644 --- a/crates/zkwasm/src/circuits/etable/mod.rs +++ b/crates/zkwasm/src/circuits/etable/mod.rs @@ -390,10 +390,10 @@ impl EventTableConfig { .into_iter() .reduce(|acc, x| acc + x) .unwrap() - - constant_from!(1), + - enabled_cell.curr_expr(meta), ] .into_iter() - .map(|expr| expr * enabled_cell.curr_expr(meta) * fixed_curr!(meta, step_sel)) + .map(|expr| expr * fixed_curr!(meta, step_sel)) .collect::>() }); @@ -466,7 +466,6 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.input_index_increase(meta, &common_config) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -479,7 +478,6 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.external_host_call_index_increase(meta, &common_config) }, - //Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -489,7 +487,6 @@ impl EventTableConfig { sp_cell.curr_expr(meta) - sp_cell.next_expr(meta), meta, &|meta, config: &Rc>>| config.sp_diff(meta), - //Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -501,7 +498,6 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.allocated_memory_pages_diff(meta) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -513,7 +509,6 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.context_input_index_increase(meta, &common_config) }, - //Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -526,7 +521,6 @@ impl EventTableConfig { &|meta, config: &Rc>>| { config.context_output_index_increase(meta, &common_config) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -549,7 +543,6 @@ impl EventTableConfig { .next_fid(meta, &common_config) .map(|x| x - fid_cell.curr_expr(meta)) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -563,7 +556,6 @@ impl EventTableConfig { .next_iid(meta, &common_config) .map(|x| iid_cell.curr_expr(meta) + enabled_cell.curr_expr(meta) - x) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -577,7 +569,6 @@ impl EventTableConfig { .next_frame_id(meta, &common_config) .map(|x| x - frame_id_cell.curr_expr(meta)) }, - // Some(&|meta| enabled_cell.curr_expr(meta)), None, )] }); @@ -634,7 +625,6 @@ impl EventTableConfig { vec![ (maximal_memory_pages_cell.next_expr(meta) - maximal_memory_pages_cell.curr_expr(meta)) -// * enabled_cell.expr(meta) * fixed_curr!(meta, step_sel), ] }); From d3d098624ff0dd22dd0ece626ee4b839e6b6f66c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Dec 2023 08:50:23 +0000 Subject: [PATCH 11/28] refine image table --- .../zkwasm/src/circuits/image_table/assign.rs | 15 +++++++++------ crates/zkwasm/src/circuits/image_table/mod.rs | 17 +++++++++++++---- crates/zkwasm/src/circuits/jtable/assign.rs | 3 ++- crates/zkwasm/src/circuits/jtable/mod.rs | 7 +++++++ .../circuits/post_image_table/continuation.rs | 17 +++++++---------- .../zkwasm/src/circuits/post_image_table/mod.rs | 1 + .../src/circuits/post_image_table/trivial.rs | 1 + crates/zkwasm/src/circuits/test_circuit/mod.rs | 3 +-- crates/zkwasm/src/circuits/utils/image_table.rs | 15 +++++++++------ 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 4fb7035c7..70c245076 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -5,22 +5,26 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; use halo2_proofs::circuit::Layouter; use halo2_proofs::plonk::Error; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use super::ImageTableChip; use super::ImageTableLayouter; -use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::Context; -impl ImageTableChip { +impl< + const INIT_MEMORY_ENTRIES_OFFSET: usize, + const STACK_LIMIT: usize, + const GLOBAL_LIMIT: usize, + F: FieldExt, + > ImageTableChip +{ pub(crate) fn assign( self, layouter: &mut impl Layouter, image_table_assigner: &mut ImageTableAssigner< INIT_MEMORY_ENTRIES_OFFSET, - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_VALUE_STACK_LIMIT, + STACK_LIMIT, + GLOBAL_LIMIT, >, image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, @@ -199,7 +203,6 @@ impl ImageTableChip { br_table: Some(result.br_table_entires), padding: Some(result.padding_entires), init_memory_entries: None, - rest_memory_writing_ops: None, }) }, ) diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index c26e7452b..3a40534e8 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -79,7 +79,6 @@ pub struct ImageTableLayouter { pub br_table: Option>, pub padding: Option>, pub init_memory_entries: Option>, - pub rest_memory_writing_ops: Option, } impl ImageTableLayouter { @@ -239,7 +238,6 @@ impl EncodeCompilationTableValues for CompilationTable { br_table, padding: None, init_memory_entries, - rest_memory_writing_ops: None, } } } @@ -258,11 +256,22 @@ impl ImageTableConfig { } #[derive(Clone)] -pub struct ImageTableChip { +pub struct ImageTableChip< + const INIT_MEMORY_ENTRIES_OFFSET: usize, + const STACK_LIMIT: usize, + const GLOBAL_LIMIT: usize, + F: FieldExt, +> { config: ImageTableConfig, } -impl ImageTableChip { +impl< + const INIT_MEMORY_ENTRIES_OFFSET: usize, + const STACK_LIMIT: usize, + const GLOBAL_LIMIT: usize, + F: FieldExt, + > ImageTableChip +{ pub fn new(config: ImageTableConfig) -> Self { ImageTableChip { config } } diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 8f6afd195..8510d52de 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -6,6 +6,7 @@ use specs::jtable::StaticFrameEntry; use super::JtableOffset; use super::JumpTableChip; +use super::STATIC_FRAME_ENTRY_NUMBER; use crate::circuits::utils::bn_to_field; use crate::circuits::utils::Context; @@ -72,7 +73,7 @@ impl JumpTableChip { let mut cells = vec![]; static_entries.resize( - 2, + STATIC_FRAME_ENTRY_NUMBER, StaticFrameEntry { enable: false, frame_id: 0, diff --git a/crates/zkwasm/src/circuits/jtable/mod.rs b/crates/zkwasm/src/circuits/jtable/mod.rs index a4cd595e2..786fb62a4 100644 --- a/crates/zkwasm/src/circuits/jtable/mod.rs +++ b/crates/zkwasm/src/circuits/jtable/mod.rs @@ -10,6 +10,13 @@ mod assign; mod configure; pub(crate) mod expression; +// 1. jumps to zkmain +// 2. jumps to start(if exists) +pub(crate) const STATIC_FRAME_ENTRY_NUMBER: usize = 2; + +// enable and data should encode in image table +pub(crate) const STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY: usize = STATIC_FRAME_ENTRY_NUMBER * 2; + pub enum JtableOffset { JtableOffsetEnable = 0, JtableOffsetRest = 1, diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 6b9ab9de2..d2a78c2cf 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -114,6 +114,7 @@ impl PostImageTableChipTrait pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, + rest_memory_writing_ops_cell: Option>, rest_memory_writing_ops: F, ) -> Result<(), Error> { layouter.assign_region( @@ -319,16 +320,12 @@ impl PostImageTableChipTrait // First line is placeholder for default lookup let offset = base_offset + 1; - permutation_cells - .rest_memory_writing_ops - .as_ref() - .unwrap() - .copy_advice( - || "post image table: init memory", - &mut ctx.borrow_mut().region, - self.config.rest_memory_finalized_count, - offset, - )?; + rest_memory_writing_ops_cell.as_ref().unwrap().copy_advice( + || "post image table: init memory", + &mut ctx.borrow_mut().region, + self.config.rest_memory_finalized_count, + offset, + )?; } let entries = { diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs index 7e99f1091..1f1ca6192 100644 --- a/crates/zkwasm/src/circuits/post_image_table/mod.rs +++ b/crates/zkwasm/src/circuits/post_image_table/mod.rs @@ -42,6 +42,7 @@ pub(in crate::circuits) trait PostImageTableChipTrait< pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, + rest_memory_writing_ops_cell: Option>, rest_memory_writing_ops: F, ) -> Result<(), Error>; } diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs index cac7219e9..a146b0c0e 100644 --- a/crates/zkwasm/src/circuits/post_image_table/trivial.rs +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -56,6 +56,7 @@ impl PostImageTableChipTrait> _pre_image_table: ImageTableLayouter, _post_image_table: ImageTableLayouter, _permutation_cells: ImageTableLayouter>, + _rest_memory_writing_ops_cell: Option>, _rest_memory_writing_ops: F, ) -> Result<(), Error> { Ok(()) diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 77021e913..0ce571025 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -350,7 +350,6 @@ impl Circuit for TestCircuit { br_table: None, padding: None, init_memory_entries: None, - rest_memory_writing_ops: None, } )? ); @@ -373,8 +372,8 @@ impl Circuit for TestCircuit { br_table: pre_image_table_cells.br_table, padding: pre_image_table_cells.padding, init_memory_entries: pre_image_table_cells.init_memory_entries, - rest_memory_writing_ops: rest_memory_writing_ops_cell, }, + rest_memory_writing_ops_cell, rest_memory_writing_ops )? ); diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index ec00409bf..f483c8339 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -1,6 +1,7 @@ use specs::state::InitializationState; use crate::circuits::image_table::PAGE_ENTRIES; +use crate::circuits::jtable::STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; /* * -------------------- @@ -21,14 +22,15 @@ use crate::circuits::image_table::PAGE_ENTRIES; * Heap * -------------------- */ +#[allow(dead_code)] pub(crate) struct Layouter { pub(crate) initialization_state: InitializationState, pub(crate) static_frame_entries: Vec<(T, T)>, pub(crate) instructions: Vec, pub(crate) br_table_entires: Vec, - // NOTE: padding entries also need constain_equal for other image + // NOTE: unused instructions and br_table entries. pub(crate) padding_entires: Vec, - pub(crate) _init_memory_entires: Vec, + pub(crate) init_memory_entires: Vec, } pub(crate) struct ImageTableAssigner< @@ -37,6 +39,7 @@ pub(crate) struct ImageTableAssigner< const GLOBAL_CAPABILITY: usize, > { pub(crate) heap_capability: u32, + initialization_state_offset: usize, static_frame_entries_offset: usize, instruction_offset: usize, @@ -55,8 +58,7 @@ impl< let initialization_state_offset = 0; let static_frame_entries_offset = initialization_state_offset + InitializationState::::field_count(); - // FIXME: magic number - let instruction_offset = static_frame_entries_offset + 4; + let instruction_offset = static_frame_entries_offset + STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; let br_table_offset = instruction_offset + instruction_number; let padding_offset = br_table_offset + br_table_number; let init_memory_offset = INIT_MEMORY_OFFSET; @@ -65,6 +67,7 @@ impl< Self { heap_capability: pages_capability * PAGE_ENTRIES, + initialization_state_offset, static_frame_entries_offset, instruction_offset, @@ -130,7 +133,7 @@ impl< 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)?; - let _init_memory_entires = self.exec_init_memory_entires(init_memory_entries_handler)?; + let init_memory_entires = self.exec_init_memory_entires(init_memory_entries_handler)?; Ok(Layouter { initialization_state, @@ -138,7 +141,7 @@ impl< instructions, br_table_entires, padding_entires, - _init_memory_entires, + init_memory_entires, }) } } From 3e234baec02592600e5ef0e7752f0fe148f3890b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Dec 2023 10:09:17 +0000 Subject: [PATCH 12/28] refine image table --- crates/specs/src/brtable.rs | 2 +- crates/specs/src/lib.rs | 4 +- crates/zkwasm/src/checksum/mod.rs | 2 +- .../zkwasm/src/circuits/image_table/assign.rs | 32 +-- crates/zkwasm/src/circuits/image_table/mod.rs | 223 +----------------- crates/zkwasm/src/circuits/jtable/assign.rs | 8 +- .../circuits/post_image_table/continuation.rs | 29 +-- .../src/circuits/post_image_table/mod.rs | 10 +- .../src/circuits/post_image_table/trivial.rs | 10 +- .../zkwasm/src/circuits/test_circuit/mod.rs | 24 +- .../zkwasm/src/circuits/utils/image_table.rs | 209 ++++++++++++++-- crates/zkwasm/src/continuation/slice.rs | 1 + .../zkwasm/src/runtime/wasmi_interpreter.rs | 28 ++- 13 files changed, 252 insertions(+), 330 deletions(-) diff --git a/crates/specs/src/brtable.rs b/crates/specs/src/brtable.rs index c6c3b3211..b23953c0b 100644 --- a/crates/specs/src/brtable.rs +++ b/crates/specs/src/brtable.rs @@ -12,7 +12,7 @@ pub struct BrTableEntry { pub dst_pc: u32, } -#[derive(Debug)] +#[derive(Default, Serialize, Debug, Clone)] pub struct BrTable(Vec); impl BrTable { diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index ca6a6b02d..149335ff0 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -8,6 +8,7 @@ use std::io::Write; use std::path::PathBuf; use std::sync::Arc; +use brtable::BrTable; use brtable::ElemTable; use configure_table::ConfigureTable; use etable::EventTable; @@ -42,10 +43,11 @@ pub mod state; pub mod step; pub mod types; -#[derive(Default, Serialize, Debug, Clone)] +#[derive(Serialize, Debug, Clone)] pub struct CompilationTable { pub itable: Arc, pub imtable: InitMemoryTable, + pub br_table: Arc, pub elem_table: Arc, pub configure_table: Arc, pub static_jtable: Arc>, diff --git a/crates/zkwasm/src/checksum/mod.rs b/crates/zkwasm/src/checksum/mod.rs index 5d03b8743..3ec68d439 100644 --- a/crates/zkwasm/src/checksum/mod.rs +++ b/crates/zkwasm/src/checksum/mod.rs @@ -3,7 +3,7 @@ use halo2_proofs::arithmetic::CurveAffine; use halo2_proofs::poly::commitment::Params; use specs::CompilationTable; -use crate::circuits::image_table::EncodeCompilationTableValues; +use crate::circuits::utils::image_table::EncodeCompilationTableValues; pub trait ImageCheckSum { fn checksum(&self) -> Output; diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 70c245076..b0eb61b6f 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -7,25 +7,15 @@ use halo2_proofs::circuit::Layouter; use halo2_proofs::plonk::Error; use super::ImageTableChip; -use super::ImageTableLayouter; use crate::circuits::utils::image_table::ImageTableAssigner; +use crate::circuits::utils::image_table::ImageTableLayouter; use crate::circuits::utils::Context; -impl< - const INIT_MEMORY_ENTRIES_OFFSET: usize, - const STACK_LIMIT: usize, - const GLOBAL_LIMIT: usize, - F: FieldExt, - > ImageTableChip -{ +impl ImageTableChip { pub(crate) fn assign( self, layouter: &mut impl Layouter, - image_table_assigner: &mut ImageTableAssigner< - INIT_MEMORY_ENTRIES_OFFSET, - STACK_LIMIT, - GLOBAL_LIMIT, - >, + image_table_assigner: &mut ImageTableAssigner, image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, ) -> Result>, Error> { @@ -97,8 +87,6 @@ impl< image_table .instructions - .as_ref() - .unwrap() .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -123,9 +111,7 @@ impl< ctx.borrow_mut().offset = base_offset; image_table - .br_table - .as_ref() - .unwrap() + .br_table_entires .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -166,8 +152,6 @@ impl< image_table .init_memory_entries - .as_ref() - .unwrap() .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -199,10 +183,10 @@ impl< Ok(ImageTableLayouter { initialization_state: result.initialization_state, static_frame_entries: result.static_frame_entries, - instructions: Some(result.instructions), - br_table: Some(result.br_table_entires), - padding: Some(result.padding_entires), - init_memory_entries: None, + instructions: result.instructions, + br_table_entires: result.br_table_entires, + padding_entires: result.padding_entires, + init_memory_entries: result.init_memory_entries, }) }, ) diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index 3a40534e8..b54234233 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -4,32 +4,18 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; -use num_bigint::BigUint; -use specs::brtable::BrTable; -use specs::brtable::ElemTable; -use specs::encode::image_table::ImageTableEncoder; -use specs::imtable::InitMemoryTable; -use specs::imtable::InitMemoryTableEntry; -use specs::itable::InstructionTable; -use specs::jtable::StaticFrameEntry; -use specs::mtable::LocationType; -use specs::mtable::VarType; -use specs::state::InitializationState; -use specs::CompilationTable; use std::marker::PhantomData; use wasmi::DEFAULT_VALUE_STACK_LIMIT; -use crate::circuits::config::zkwasm_k; -use crate::circuits::utils::bn_to_field; use crate::curr; use super::test_circuit::RESERVE_ROWS; +use super::utils::image_table::INIT_MEMORY_ENTRIES_OFFSET; mod assign; mod configure; pub const IMAGE_COL_NAME: &str = "img_col"; -pub const INIT_MEMORY_ENTRIES_OFFSET: usize = 40960; /* * 8192: 64 * 1024 / 8 * A page is 64KB, an entry is 8B @@ -50,198 +36,6 @@ pub fn compute_maximal_pages(k: u32) -> u32 { pages } -pub(crate) struct InitMemoryLayouter { - pub(crate) stack: u32, - pub(crate) global: u32, - pub(crate) pages: u32, -} - -impl InitMemoryLayouter { - fn for_each(self, mut f: impl FnMut((LocationType, u32))) { - for offset in 0..self.stack { - f((LocationType::Stack, offset)) - } - - for offset in 0..self.global { - f((LocationType::Global, offset)) - } - - for offset in 0..(self.pages * PAGE_ENTRIES) { - f((LocationType::Heap, offset)) - } - } -} - -pub struct ImageTableLayouter { - pub initialization_state: InitializationState, - pub static_frame_entries: Vec<(T, T)>, - pub instructions: Option>, - pub br_table: Option>, - pub padding: Option>, - pub init_memory_entries: Option>, -} - -impl ImageTableLayouter { - pub fn plain(&self) -> Vec { - let mut buf = vec![]; - - buf.append(&mut self.initialization_state.plain()); - buf.append( - &mut self - .static_frame_entries - .clone() - .to_vec() - .into_iter() - .map(|(enable, fid)| vec![enable, fid]) - .collect::>>() - .concat(), - ); - buf.append(&mut self.instructions.clone().unwrap()); - buf.append(&mut self.br_table.clone().unwrap()); - buf.append(&mut vec![F::zero(); INIT_MEMORY_ENTRIES_OFFSET - buf.len()]); - buf.append(&mut self.init_memory_entries.clone().unwrap()); - - buf - } -} - -pub trait EncodeCompilationTableValues { - fn encode_compilation_table_values(&self) -> ImageTableLayouter; -} - -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![]; - - cells.push(bn_to_field( - &ImageTableEncoder::Instruction.encode(BigUint::from(0u64)), - )); - - for e in instruction_table.entries() { - cells.push(bn_to_field( - &ImageTableEncoder::Instruction.encode(e.encode()), - )); - } - - cells - } - - fn msg_of_br_table(br_table: &BrTable, elem_table: &ElemTable) -> Vec { - let mut cells = vec![]; - - cells.push(bn_to_field( - &ImageTableEncoder::BrTable.encode(BigUint::from(0u64)), - )); - - for e in br_table.entries() { - cells.push(bn_to_field(&ImageTableEncoder::BrTable.encode(e.encode()))); - } - - for e in elem_table.entries() { - cells.push(bn_to_field(&ImageTableEncoder::BrTable.encode(e.encode()))); - } - - cells - } - - fn msg_of_init_memory_table(init_memory_table: &InitMemoryTable) -> Vec { - let mut cells = vec![]; - - cells.push(bn_to_field( - &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), - )); - - let layouter = InitMemoryLayouter { - stack: DEFAULT_VALUE_STACK_LIMIT as u32, - global: DEFAULT_VALUE_STACK_LIMIT as u32, - pages: compute_maximal_pages(zkwasm_k()), - }; - - layouter.for_each(|(ltype, offset)| { - if let Some(entry) = init_memory_table.try_find(ltype, offset) { - cells.push(bn_to_field::( - &ImageTableEncoder::InitMemory.encode(entry.encode()), - )); - } else if ltype == LocationType::Heap { - let entry = InitMemoryTableEntry { - ltype, - is_mutable: true, - offset, - vtype: VarType::I64, - value: 0, - eid: 0, - }; - - cells.push(bn_to_field::( - &ImageTableEncoder::InitMemory.encode(entry.encode()), - )); - } else { - cells.push(bn_to_field::( - &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), - )); - } - }); - - cells - } - - fn msg_of_static_frame_table( - static_frame_table: &Vec, - ) -> Vec<(F, F)> { - let mut cells = static_frame_table - .into_iter() - .map(|entry| (F::one(), bn_to_field(&entry.encode()))) - .collect::>(); - - cells.resize( - 2, - ( - F::zero(), - bn_to_field( - &StaticFrameEntry { - enable: false, - frame_id: 0, - next_frame_id: 0, - callee_fid: 0, - fid: 0, - iid: 0, - } - .encode(), - ), - ), - ); - - cells - } - - let initialization_state = msg_of_initialization_state(&self.initialization_state); - let static_frame_entries = msg_of_static_frame_table(&self.static_jtable); - - let instructions = Some(msg_of_instruction_table(&self.itable)); - let br_table = Some(msg_of_br_table( - &self.itable.create_brtable(), - &self.elem_table, - )); - let init_memory_entries = Some(msg_of_init_memory_table(&self.imtable)); - - ImageTableLayouter { - initialization_state, - static_frame_entries, - instructions, - br_table, - padding: None, - init_memory_entries, - } - } -} - #[derive(Clone)] pub struct ImageTableConfig { _memory_addr_sel: Column, @@ -256,22 +50,11 @@ impl ImageTableConfig { } #[derive(Clone)] -pub struct ImageTableChip< - const INIT_MEMORY_ENTRIES_OFFSET: usize, - const STACK_LIMIT: usize, - const GLOBAL_LIMIT: usize, - F: FieldExt, -> { +pub struct ImageTableChip { config: ImageTableConfig, } -impl< - const INIT_MEMORY_ENTRIES_OFFSET: usize, - const STACK_LIMIT: usize, - const GLOBAL_LIMIT: usize, - F: FieldExt, - > ImageTableChip -{ +impl ImageTableChip { pub fn new(config: ImageTableConfig) -> Self { ImageTableChip { config } } diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 8510d52de..07a7d143b 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -206,7 +206,13 @@ impl JumpTableChip { self.init(ctx)?; ctx.reset(); - let mut rest_jops = jtable.entries().len() as u64 * 2 + static_entries.len() as u64; + let mut rest_jops = jtable.entries().len() as u64 * 2; + + for entry in static_entries { + if entry.enable { + rest_jops += 1; + } + } let frame_table_start_jump_cells = self.assign_static_entries(ctx, &mut rest_jops, static_entries)?; diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index d2a78c2cf..7d7b3699c 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -16,11 +16,10 @@ use specs::mtable::LocationType; use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::ImageTableConfig; -use crate::circuits::image_table::ImageTableLayouter; -use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::bn_to_field; use crate::circuits::utils::image_table::ImageTableAssigner; +use crate::circuits::utils::image_table::ImageTableLayouter; use crate::circuits::utils::Context; use crate::constant_from; use crate::curr; @@ -106,11 +105,7 @@ impl PostImageTableChipTrait fn assign( self, layouter: &mut impl Layouter, - image_table_assigner: &mut ImageTableAssigner< - INIT_MEMORY_ENTRIES_OFFSET, - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_VALUE_STACK_LIMIT, - >, + image_table_assigner: &mut ImageTableAssigner, pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, @@ -185,8 +180,6 @@ impl PostImageTableChipTrait permutation_cells .instructions - .as_ref() - .unwrap() .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -211,9 +204,7 @@ impl PostImageTableChipTrait ctx.borrow_mut().offset = base_offset; permutation_cells - .br_table - .as_ref() - .unwrap() + .br_table_entires .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -238,9 +229,7 @@ impl PostImageTableChipTrait ctx.borrow_mut().offset = start_offset; permutation_cells - .padding - .as_ref() - .unwrap() + .padding_entires .iter() .map(|entry| { let offset = ctx.borrow().offset; @@ -335,16 +324,8 @@ impl PostImageTableChipTrait pre_image_table .init_memory_entries - .as_ref() - .unwrap() .iter() - .zip( - post_image_table - .init_memory_entries - .as_ref() - .unwrap() - .iter(), - ) + .zip(post_image_table.init_memory_entries.iter()) .map(|(pre, post)| { let entry = ctx.borrow_mut().region.assign_advice( || "post image table: init memory", diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs index 1f1ca6192..e444451c9 100644 --- a/crates/zkwasm/src/circuits/post_image_table/mod.rs +++ b/crates/zkwasm/src/circuits/post_image_table/mod.rs @@ -5,13 +5,11 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use super::image_table::ImageTableConfig; -use super::image_table::ImageTableLayouter; -use super::image_table::INIT_MEMORY_ENTRIES_OFFSET; use super::mtable::MemoryTableConfig; use super::utils::image_table::ImageTableAssigner; +use super::utils::image_table::ImageTableLayouter; pub(self) mod continuation; pub(self) mod trivial; @@ -34,11 +32,7 @@ pub(in crate::circuits) trait PostImageTableChipTrait< fn assign( self, layouter: &mut impl Layouter, - image_table_assigner: &mut ImageTableAssigner< - INIT_MEMORY_ENTRIES_OFFSET, - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_VALUE_STACK_LIMIT, - >, + image_table_assigner: &mut ImageTableAssigner, pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs index a146b0c0e..d73416d45 100644 --- a/crates/zkwasm/src/circuits/post_image_table/trivial.rs +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -7,13 +7,11 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::ImageTableConfig; -use crate::circuits::image_table::ImageTableLayouter; -use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::image_table::ImageTableAssigner; +use crate::circuits::utils::image_table::ImageTableLayouter; use super::PostImageTableChipTrait; use super::PostImageTableConfigTrait; @@ -48,11 +46,7 @@ impl PostImageTableChipTrait> fn assign( self, _layouter: &mut impl Layouter, - _image_table_assigner: &mut ImageTableAssigner< - INIT_MEMORY_ENTRIES_OFFSET, - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_VALUE_STACK_LIMIT, - >, + _image_table_assigner: &mut ImageTableAssigner, _pre_image_table: ImageTableLayouter, _post_image_table: ImageTableLayouter, _permutation_cells: ImageTableLayouter>, diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 0ce571025..bafe47c6c 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -14,7 +14,6 @@ use log::debug; use log::info; use specs::ExecutionTable; use specs::Tables; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::bit_table::BitTableChip; use crate::circuits::bit_table::BitTableConfig; @@ -23,10 +22,7 @@ use crate::circuits::etable::EventTableConfig; use crate::circuits::external_host_call_table::ExternalHostCallChip; use crate::circuits::external_host_call_table::ExternalHostCallTableConfig; use crate::circuits::image_table::compute_maximal_pages; -use crate::circuits::image_table::EncodeCompilationTableValues; use crate::circuits::image_table::ImageTableChip; -use crate::circuits::image_table::ImageTableLayouter; -use crate::circuits::image_table::INIT_MEMORY_ENTRIES_OFFSET; use crate::circuits::jtable::JumpTableChip; use crate::circuits::jtable::JumpTableConfig; use crate::circuits::mtable::MemoryTableChip; @@ -36,7 +32,9 @@ use crate::circuits::post_image_table::PostImageTableChipTrait; use crate::circuits::post_image_table::PostImageTableConfigTrait; use crate::circuits::rtable::RangeTableChip; use crate::circuits::rtable::RangeTableConfig; +use crate::circuits::utils::image_table::EncodeCompilationTableValues; use crate::circuits::utils::image_table::ImageTableAssigner; +use crate::circuits::utils::image_table::ImageTableLayouter; use crate::circuits::utils::table_entry::EventTableWithMemoryInfo; use crate::circuits::utils::table_entry::MemoryWritingTable; use crate::circuits::utils::Context; @@ -316,11 +314,7 @@ impl Circuit for TestCircuit { )? ); - let mut image_table_assigner = ImageTableAssigner::< - INIT_MEMORY_ENTRIES_OFFSET, - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_VALUE_STACK_LIMIT, - >::new( + let mut image_table_assigner = ImageTableAssigner::new( // Add one for default lookup value self.tables.compilation_tables.itable.entries().len() + 1, // FIXME: avoid compute @@ -346,10 +340,10 @@ impl Circuit for TestCircuit { ImageTableLayouter { initialization_state: etable_permutation_cells.pre_initialization_state, static_frame_entries, - instructions: None, - br_table: None, - padding: None, - init_memory_entries: None, + instructions: vec![], + br_table_entires: vec![], + padding_entires: vec![], + init_memory_entries: vec![], } )? ); @@ -369,8 +363,8 @@ impl Circuit for TestCircuit { initialization_state: etable_permutation_cells.post_initialization_state, static_frame_entries: pre_image_table_cells.static_frame_entries, instructions: pre_image_table_cells.instructions, - br_table: pre_image_table_cells.br_table, - padding: pre_image_table_cells.padding, + br_table_entires: pre_image_table_cells.br_table_entires, + padding_entires: pre_image_table_cells.padding_entires, init_memory_entries: pre_image_table_cells.init_memory_entries, }, rest_memory_writing_ops_cell, diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index f483c8339..5689e01e0 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -1,7 +1,44 @@ +use anyhow::Error; +use halo2_proofs::arithmetic::FieldExt; +use num_bigint::BigUint; +use specs::encode::image_table::ImageTableEncoder; +use specs::imtable::InitMemoryTableEntry; +use specs::mtable::LocationType; +use specs::mtable::VarType; use specs::state::InitializationState; +use specs::CompilationTable; +use wasmi::DEFAULT_VALUE_STACK_LIMIT; +use crate::circuits::config::zkwasm_k; +use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::PAGE_ENTRIES; use crate::circuits::jtable::STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; +use crate::circuits::jtable::STATIC_FRAME_ENTRY_NUMBER; +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(crate) struct InitMemoryLayouter { + pub(crate) pages: u32, +} + +impl InitMemoryLayouter { + fn for_each(self, mut f: impl FnMut((LocationType, u32))) { + for offset in 0..STACK_CAPABILITY { + f((LocationType::Stack, offset as u32)) + } + + for offset in 0..GLOBAL_CAPABILITY { + f((LocationType::Global, offset as u32)) + } + + for offset in 0..(self.pages * PAGE_ENTRIES) { + f((LocationType::Heap, offset)) + } + } +} /* * -------------------- @@ -23,21 +60,17 @@ use crate::circuits::jtable::STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; * -------------------- */ #[allow(dead_code)] -pub(crate) struct Layouter { +pub(crate) struct ImageTableLayouter { pub(crate) initialization_state: InitializationState, pub(crate) static_frame_entries: Vec<(T, T)>, pub(crate) instructions: Vec, pub(crate) br_table_entires: Vec, // NOTE: unused instructions and br_table entries. pub(crate) padding_entires: Vec, - pub(crate) init_memory_entires: Vec, + pub(crate) init_memory_entries: Vec, } -pub(crate) struct ImageTableAssigner< - const INIT_MEMORY_OFFSET: usize, - const STACK_CAPABILITY: usize, - const GLOBAL_CAPABILITY: usize, -> { +pub(crate) struct ImageTableAssigner { pub(crate) heap_capability: u32, initialization_state_offset: usize, @@ -48,12 +81,7 @@ pub(crate) struct ImageTableAssigner< init_memory_offset: usize, } -impl< - const INIT_MEMORY_OFFSET: usize, - const STACK_CAPABILITY: usize, - const GLOBAL_CAPABILITY: usize, - > ImageTableAssigner -{ +impl ImageTableAssigner { pub fn new(instruction_number: usize, br_table_number: usize, pages_capability: u32) -> Self { let initialization_state_offset = 0; let static_frame_entries_offset = @@ -61,7 +89,7 @@ impl< let instruction_offset = static_frame_entries_offset + STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; let br_table_offset = instruction_offset + instruction_number; let padding_offset = br_table_offset + br_table_number; - let init_memory_offset = INIT_MEMORY_OFFSET; + let init_memory_offset = INIT_MEMORY_ENTRIES_OFFSET; assert!(padding_offset <= init_memory_offset); @@ -112,7 +140,7 @@ impl< padding_handler(self.padding_offset, self.padding_offset) } - pub fn exec_init_memory_entires( + pub fn exec_init_memory_entries( &mut self, mut init_memory_entries_handler: impl FnMut(usize) -> Result, Error>, ) -> Result, Error> { @@ -127,21 +155,164 @@ impl< br_table_handler: impl FnMut(usize) -> Result, Error>, padding_handler: impl FnMut(usize, usize) -> Result, Error>, init_memory_entries_handler: impl FnMut(usize) -> Result, Error>, - ) -> Result, Error> { + ) -> Result, Error> { let initialization_state = self.exec_initialization_state(initialization_state_handler)?; let static_frame_entries = self.exec_static_frame_entries(static_frame_entries_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)?; - let init_memory_entires = self.exec_init_memory_entires(init_memory_entries_handler)?; + let init_memory_entries = self.exec_init_memory_entries(init_memory_entries_handler)?; - Ok(Layouter { + Ok(ImageTableLayouter { initialization_state, static_frame_entries, instructions, br_table_entires, padding_entires, - init_memory_entires, + init_memory_entries, }) } } + +pub(crate) trait EncodeCompilationTableValues { + fn encode_compilation_table_values(&self) -> ImageTableLayouter; +} + +impl EncodeCompilationTableValues for CompilationTable { + fn encode_compilation_table_values(&self) -> ImageTableLayouter { + // FIXME: ugly + let pages_capability = compute_maximal_pages(zkwasm_k()); + + let initialization_state_handler = + |_| Ok(self.initialization_state.map(|v| F::from((*v) as u64))); + + let static_frame_entries_handler = |_| { + // Encode disabled static frame entry in image table + assert_eq!(self.static_jtable.len(), STATIC_FRAME_ENTRY_NUMBER); + + Ok(self + .static_jtable + .iter() + .map(|entry| (F::from(entry.enable as u64), bn_to_field(&entry.encode()))) + .collect()) + }; + + let instruction_handler = |_| { + let mut cells = vec![]; + + cells.push(bn_to_field( + &ImageTableEncoder::Instruction.encode(BigUint::from(0u64)), + )); + + for e in self.itable.entries() { + cells.push(bn_to_field( + &ImageTableEncoder::Instruction.encode(e.encode()), + )); + } + + Ok(cells) + }; + + let br_table_handler = |_| { + let mut cells = vec![]; + + cells.push(bn_to_field( + &ImageTableEncoder::BrTable.encode(BigUint::from(0u64)), + )); + + for e in self.br_table.entries() { + cells.push(bn_to_field(&ImageTableEncoder::BrTable.encode(e.encode()))); + } + + for e in self.elem_table.entries() { + cells.push(bn_to_field(&ImageTableEncoder::BrTable.encode(e.encode()))); + } + + Ok(cells) + }; + + let padding_handler = |start, end| Ok(vec![F::zero(); end - start]); + + let init_memory_entries_handler = |_| { + let mut cells = vec![]; + + cells.push(bn_to_field( + &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), + )); + + let layouter = InitMemoryLayouter { + pages: pages_capability, + }; + + layouter.for_each(|(ltype, offset)| { + if let Some(entry) = self.imtable.try_find(ltype, offset) { + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(entry.encode()), + )); + } else if ltype == LocationType::Heap { + let entry = InitMemoryTableEntry { + ltype, + is_mutable: true, + offset, + vtype: VarType::I64, + value: 0, + eid: 0, + }; + + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(entry.encode()), + )); + } else { + cells.push(bn_to_field::( + &ImageTableEncoder::InitMemory.encode(BigUint::from(0u64)), + )); + } + }); + + Ok(cells) + }; + + let mut assigner = ImageTableAssigner::new( + self.itable.entries().len(), + self.br_table.entries().len() + self.elem_table.entries().len(), + pages_capability, + ); + + let layouter = assigner + .exec::<_, Error>( + initialization_state_handler, + static_frame_entries_handler, + instruction_handler, + br_table_handler, + padding_handler, + init_memory_entries_handler, + ) + .unwrap(); + + layouter + } +} + +impl ImageTableLayouter { + pub fn plain(&self) -> Vec { + let mut buf = vec![]; + + buf.append(&mut self.initialization_state.plain()); + buf.append( + &mut self + .static_frame_entries + .clone() + .to_vec() + .into_iter() + .map(|(enable, fid)| vec![enable, fid]) + .collect::>>() + .concat(), + ); + buf.append(&mut self.instructions.clone()); + buf.append(&mut self.br_table_entires.clone()); + buf.append(&mut self.padding_entires.clone()); + buf.append(&mut self.init_memory_entries.clone()); + + buf + } +} diff --git a/crates/zkwasm/src/continuation/slice.rs b/crates/zkwasm/src/continuation/slice.rs index 9ec90bd68..85a6e2117 100644 --- a/crates/zkwasm/src/continuation/slice.rs +++ b/crates/zkwasm/src/continuation/slice.rs @@ -103,6 +103,7 @@ impl Iterator for Slices { let post_image_table = CompilationTable { itable: self.origin_table.compilation_tables.itable.clone(), imtable: updated_init_memory_table, + br_table: self.origin_table.compilation_tables.br_table.clone(), elem_table: self.origin_table.compilation_tables.elem_table.clone(), configure_table: self.origin_table.compilation_tables.configure_table.clone(), static_jtable: self.origin_table.compilation_tables.static_jtable.clone(), diff --git a/crates/zkwasm/src/runtime/wasmi_interpreter.rs b/crates/zkwasm/src/runtime/wasmi_interpreter.rs index 7153f317a..3214b0367 100644 --- a/crates/zkwasm/src/runtime/wasmi_interpreter.rs +++ b/crates/zkwasm/src/runtime/wasmi_interpreter.rs @@ -85,6 +85,7 @@ impl Execution CompilationTable { itable: self.tables.itable.clone(), imtable: updated_init_memory_table, + br_table: self.tables.br_table.clone(), elem_table: self.tables.elem_table.clone(), configure_table: self.tables.configure_table.clone(), static_jtable: self.tables.static_jtable.clone(), @@ -144,20 +145,29 @@ impl WasmiRuntime { iid: 0, }); - if instance.has_start() { - tracer - .clone() - .borrow_mut() - .static_jtable_entries - .push(StaticFrameEntry { + tracer + .clone() + .borrow_mut() + .static_jtable_entries + .push(if instance.has_start() { + StaticFrameEntry { enable: true, frame_id: 0, next_frame_id: 0, callee_fid: 0, // the fid of start function is always 0 fid: idx_of_entry, iid: 0, - }); - } + } + } else { + StaticFrameEntry { + enable: false, + frame_id: 0, + next_frame_id: 0, + callee_fid: 0, + fid: 0, + iid: 0, + } + }); if instance.has_start() { 0 @@ -168,6 +178,7 @@ impl WasmiRuntime { let itable = Arc::new(tracer.borrow().itable.clone()); let imtable = tracer.borrow().imtable.finalized(); + let br_table = Arc::new(itable.create_brtable()); 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()); @@ -195,6 +206,7 @@ impl WasmiRuntime { tables: CompilationTable { itable, imtable, + br_table, elem_table, configure_table, static_jtable, From 29c99b4e6007ae0a91b7263eb2335325fc77b944 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Dec 2023 03:38:11 +0000 Subject: [PATCH 13/28] fix hardcode --- .../zkwasm/src/circuits/post_image_table/continuation.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 7d7b3699c..44af5ef26 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -13,13 +13,14 @@ use halo2_proofs::plonk::Fixed; use num_bigint::BigUint; use specs::encode::init_memory_table::encode_init_memory_table_address; use specs::mtable::LocationType; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::circuits::image_table::ImageTableConfig; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::bn_to_field; use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::image_table::ImageTableLayouter; +use crate::circuits::utils::image_table::GLOBAL_CAPABILITY; +use crate::circuits::utils::image_table::STACK_CAPABILITY; use crate::circuits::utils::Context; use crate::constant_from; use crate::curr; @@ -285,11 +286,11 @@ impl PostImageTableChipTrait }}; } - for i in 0..DEFAULT_VALUE_STACK_LIMIT { + for i in 0..STACK_CAPABILITY { assign_address!(LocationType::Stack, i)?; } - for i in 0..DEFAULT_VALUE_STACK_LIMIT { + for i in 0..GLOBAL_CAPABILITY { assign_address!(LocationType::Global, i)?; } From 06f99e4fc103b29e9213f27b887e3be543383b87 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Dec 2023 04:05:34 +0000 Subject: [PATCH 14/28] add transpose for InitializationState --- crates/specs/src/state.rs | 21 +++++++++++++++++++ .../zkwasm/src/circuits/image_table/assign.rs | 18 +++++++--------- .../circuits/post_image_table/continuation.rs | 18 +++++++--------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/crates/specs/src/state.rs b/crates/specs/src/state.rs index 11712c014..3cc0ba3a1 100644 --- a/crates/specs/src/state.rs +++ b/crates/specs/src/state.rs @@ -102,3 +102,24 @@ impl InitializationState { } } } + +impl InitializationState> { + pub fn transpose(self) -> Result, E> { + Ok(InitializationState { + eid: self.eid?, + fid: self.fid?, + iid: self.iid?, + frame_id: self.frame_id?, + sp: self.sp?, + host_public_inputs: self.host_public_inputs?, + context_in_index: self.context_in_index?, + context_out_index: self.context_out_index?, + external_host_call_call_index: self.external_host_call_call_index?, + initial_memory_pages: self.initial_memory_pages?, + maximal_memory_pages: self.maximal_memory_pages?, + + #[cfg(feature = "continuation")] + jops: self.jops?, + }) + } +} diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index b0eb61b6f..46b7c5a06 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -31,21 +31,19 @@ impl ImageTableChip { permutation_cells.initialization_state.map(|field| { let offset = ctx.borrow().offset; - field - .copy_advice( - || "image table: initialization state", - &mut ctx.borrow_mut().region, - self.config.col, - offset, - ) - .unwrap(); + field.copy_advice( + || "image table: initialization state", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + )?; ctx.borrow_mut().next(); - field.clone() + Ok(field.clone()) }); - Ok::<_, Error>(initialization_state) + initialization_state.transpose() }; let static_frame_entries_handler = |base_offset| { diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 44af5ef26..23840cebf 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -125,21 +125,19 @@ impl PostImageTableChipTrait permutation_cells.initialization_state.map(|field| { let offset = ctx.borrow().offset; - field - .copy_advice( - || "image table: initialization state", - &mut ctx.borrow_mut().region, - self.config.post_image_table, - offset, - ) - .unwrap(); + field.copy_advice( + || "image table: initialization state", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; ctx.borrow_mut().next(); - field.clone() + Ok(field.clone()) }); - Ok::<_, Error>(initialization_state) + initialization_state.transpose() }; let static_frame_entries_handler = |base_offset| { From 9febe1929774756473890c88731a56545f43b7fb Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Dec 2023 09:46:35 +0000 Subject: [PATCH 15/28] chore: refine image table assignment --- .../zkwasm/src/circuits/image_table/assign.rs | 80 ++++++------------- .../circuits/post_image_table/continuation.rs | 12 +-- 2 files changed, 25 insertions(+), 67 deletions(-) diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 46b7c5a06..f451d881e 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -24,6 +24,23 @@ impl ImageTableChip { |region| { let ctx = Rc::new(RefCell::new(Context::new(region))); + macro_rules! assign { + ($v:expr) => {{ + let offset = ctx.borrow().offset; + + let cell = ctx.borrow_mut().region.assign_advice( + || "pre image table", + self.config.col, + offset, + || Ok($v), + ); + + ctx.borrow_mut().next(); + + cell + }}; + } + let initialization_state_handler = |base_offset| { ctx.borrow_mut().offset = base_offset; @@ -73,10 +90,8 @@ impl ImageTableChip { )?; ctx.borrow_mut().next(); - Ok::<_, Error>((enable.clone(), entry.clone())) + Ok((enable.clone(), entry.clone())) }) - .collect::>>() - .into_iter() .collect::, Error>>() }; @@ -86,22 +101,7 @@ impl ImageTableChip { image_table .instructions .iter() - .map(|entry| { - let offset = ctx.borrow().offset; - - let cell = ctx.borrow_mut().region.assign_advice( - || "image table", - self.config.col, - offset, - || Ok(*entry), - ); - - ctx.borrow_mut().next(); - - cell - }) - .collect::>>() - .into_iter() + .map(|entry| assign!(*entry)) .collect::, Error>>() }; @@ -111,37 +111,15 @@ impl ImageTableChip { image_table .br_table_entires .iter() - .map(|entry| { - let offset = ctx.borrow().offset; - - let cell = ctx.borrow_mut().region.assign_advice( - || "image table", - self.config.col, - offset, - || Ok(*entry), - ); - - ctx.borrow_mut().next(); - - cell - }) - .collect::>>() - .into_iter() + .map(|entry| assign!(*entry)) .collect::, Error>>() }; let padding_handler = |start_offset, end_offset| { + ctx.borrow_mut().offset = start_offset; + (start_offset..end_offset) - .map(|offset| { - ctx.borrow_mut().region.assign_advice( - || "image table: padding", - self.config.col, - offset, - || Ok(F::zero()), - ) - }) - .collect::>>() - .into_iter() + .map(|_| assign!(F::zero())) .collect::, Error>>() }; @@ -152,20 +130,10 @@ impl ImageTableChip { .init_memory_entries .iter() .map(|entry| { - let offset = ctx.borrow().offset; - let cell = ctx.borrow_mut().region.assign_advice( - || "image table", - self.config.col, - offset, - || Ok(*entry), - ); - ctx.borrow_mut().next(); + assign!(*entry) - cell }) - .collect::>>() - .into_iter() .collect::, Error>>() }; diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 23840cebf..4c5404589 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -167,10 +167,8 @@ impl PostImageTableChipTrait )?; ctx.borrow_mut().next(); - Ok::<_, Error>((enable.clone(), entry.clone())) + Ok((enable.clone(), entry.clone())) }) - .collect::>>() - .into_iter() .collect::, Error>>() }; @@ -194,8 +192,6 @@ impl PostImageTableChipTrait Ok(entry) }) - .collect::>>() - .into_iter() .collect::, Error>>() }; @@ -219,8 +215,6 @@ impl PostImageTableChipTrait Ok(entry) }) - .collect::>>() - .into_iter() .collect::, Error>>() }; @@ -244,8 +238,6 @@ impl PostImageTableChipTrait Ok(entry) }) - .collect::>>() - .into_iter() .collect::, Error>>() }; @@ -355,8 +347,6 @@ impl PostImageTableChipTrait Ok(entry) }) - .collect::>>() - .into_iter() .collect::, Error>>() }?; From 0a6b45de753d8f5a85348ff45877f3df766e67d7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Dec 2023 09:49:44 +0000 Subject: [PATCH 16/28] fmt code --- crates/zkwasm/src/circuits/image_table/assign.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index f451d881e..194a77d86 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -129,11 +129,7 @@ impl ImageTableChip { image_table .init_memory_entries .iter() - .map(|entry| { - - assign!(*entry) - - }) + .map(|entry| assign!(*entry)) .collect::, Error>>() }; From b54a5060f91483ebb3ea4dea741b6d2bdbb61124 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Dec 2023 06:46:55 +0000 Subject: [PATCH 17/28] set the number of frame table entry always 2 --- crates/specs/src/jtable.rs | 4 ++ crates/specs/src/lib.rs | 3 +- .../zkwasm/src/circuits/image_table/assign.rs | 50 ++++++++++--------- crates/zkwasm/src/circuits/image_table/mod.rs | 30 ++++++----- crates/zkwasm/src/circuits/jtable/assign.rs | 29 ++++------- crates/zkwasm/src/circuits/jtable/mod.rs | 5 +- .../circuits/post_image_table/continuation.rs | 50 ++++++++++--------- .../zkwasm/src/circuits/test_circuit/mod.rs | 8 +-- .../zkwasm/src/circuits/utils/image_table.rs | 33 ++++++++---- .../zkwasm/src/runtime/wasmi_interpreter.rs | 13 ++++- 10 files changed, 123 insertions(+), 102 deletions(-) diff --git a/crates/specs/src/jtable.rs b/crates/specs/src/jtable.rs index f9c9179d7..c64e9f09d 100644 --- a/crates/specs/src/jtable.rs +++ b/crates/specs/src/jtable.rs @@ -1,6 +1,10 @@ use super::itable::InstructionTableEntry; use serde::Serialize; +// 1. jumps to zkmain +// 2. jumps to start(if exists) +pub const STATIC_FRAME_ENTRY_NUMBER: usize = 2; + #[derive(Default, Serialize, Debug, Clone)] pub struct StaticFrameEntry { pub enable: bool, diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index 149335ff0..01f4bbb14 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -17,6 +17,7 @@ use imtable::InitMemoryTable; use itable::InstructionTable; use jtable::JumpTable; use jtable::StaticFrameEntry; +use jtable::STATIC_FRAME_ENTRY_NUMBER; use mtable::AccessType; use mtable::LocationType; use mtable::MTable; @@ -50,7 +51,7 @@ pub struct CompilationTable { pub br_table: Arc, pub elem_table: Arc, pub configure_table: Arc, - pub static_jtable: Arc>, + pub static_jtable: Arc<[StaticFrameEntry; STATIC_FRAME_ENTRY_NUMBER]>, pub initialization_state: InitializationState, } diff --git a/crates/zkwasm/src/circuits/image_table/assign.rs b/crates/zkwasm/src/circuits/image_table/assign.rs index 194a77d86..f8fb5e51e 100644 --- a/crates/zkwasm/src/circuits/image_table/assign.rs +++ b/crates/zkwasm/src/circuits/image_table/assign.rs @@ -5,6 +5,7 @@ use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; use halo2_proofs::circuit::Layouter; use halo2_proofs::plonk::Error; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use super::ImageTableChip; use crate::circuits::utils::image_table::ImageTableAssigner; @@ -66,33 +67,36 @@ impl ImageTableChip { let static_frame_entries_handler = |base_offset| { ctx.borrow_mut().offset = base_offset; - permutation_cells - .static_frame_entries - .iter() - .map(|(enable, entry)| { - let offset = ctx.borrow().offset; + let mut cells = vec![]; - enable.copy_advice( - || "image table: static frame entry", - &mut ctx.borrow_mut().region, - self.config.col, - offset, - )?; - ctx.borrow_mut().next(); + for (enable, entry) in &permutation_cells.static_frame_entries { + let offset = ctx.borrow().offset; - let offset = ctx.borrow().offset; + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + )?; + ctx.borrow_mut().next(); - entry.copy_advice( - || "image table: static frame entry", - &mut ctx.borrow_mut().region, - self.config.col, - offset, - )?; - ctx.borrow_mut().next(); + let offset = ctx.borrow().offset; - Ok((enable.clone(), entry.clone())) - }) - .collect::, Error>>() + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.col, + offset, + )?; + ctx.borrow_mut().next(); + + cells.push((enable.clone(), entry.clone())); + } + + Ok(cells.try_into().expect(&format!( + "The number of static frame entries should be {}", + STATIC_FRAME_ENTRY_NUMBER + ))) }; let instruction_handler = |base_offset| { diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index b54234233..d3c8fdb2d 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -5,35 +5,39 @@ use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; use std::marker::PhantomData; -use wasmi::DEFAULT_VALUE_STACK_LIMIT; use crate::curr; use super::test_circuit::RESERVE_ROWS; +use super::utils::image_table::GLOBAL_CAPABILITY; use super::utils::image_table::INIT_MEMORY_ENTRIES_OFFSET; +use super::utils::image_table::STACK_CAPABILITY; mod assign; mod configure; pub const IMAGE_COL_NAME: &str = "img_col"; -/* - * 8192: 64 * 1024 / 8 - * A page is 64KB, an entry is 8B - */ -pub const PAGE_ENTRIES: u32 = 8192; + +pub const PAGE_SIZE: u32 = 64 * 1024; +// A block is 8 bytes +pub const PAGE_ENTRIES: u32 = PAGE_SIZE / 8; /// Compute maximal number of pages supported by the circuit. -/// circuit size - reserved rows for blind - initialization_state/static frame entries/instructions/br_table +/// circuit size - reserved rows for blind - init memory entries base offset /// - stack entries - global entries pub fn compute_maximal_pages(k: u32) -> u32 { - let bytes: u32 = - ((1usize << k) - RESERVE_ROWS - INIT_MEMORY_ENTRIES_OFFSET - DEFAULT_VALUE_STACK_LIMIT * 2) - .try_into() - .unwrap(); + let rows: u32 = ((1usize << k) + - RESERVE_ROWS + - INIT_MEMORY_ENTRIES_OFFSET + - STACK_CAPABILITY + - GLOBAL_CAPABILITY) + .try_into() + .unwrap(); - let pages = bytes / PAGE_ENTRIES; + // A block is 8 bytes. + let bytes = rows * 8; - pages + bytes / PAGE_SIZE } #[derive(Clone)] diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 07a7d143b..4dfda5e4a 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -3,10 +3,10 @@ use halo2_proofs::circuit::AssignedCell; use halo2_proofs::plonk::Error; use specs::jtable::JumpTable; use specs::jtable::StaticFrameEntry; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use super::JtableOffset; use super::JumpTableChip; -use super::STATIC_FRAME_ENTRY_NUMBER; use crate::circuits::utils::bn_to_field; use crate::circuits::utils::Context; @@ -66,24 +66,10 @@ impl JumpTableChip { &self, ctx: &mut Context<'_, F>, rest_jops: &mut u64, - static_entries: &Vec, - ) -> Result, AssignedCell)>, Error> { - let mut static_entries = static_entries.clone(); - + static_entries: &[StaticFrameEntry; STATIC_FRAME_ENTRY_NUMBER], + ) -> Result<[(AssignedCell, AssignedCell); STATIC_FRAME_ENTRY_NUMBER], Error> { let mut cells = vec![]; - static_entries.resize( - STATIC_FRAME_ENTRY_NUMBER, - StaticFrameEntry { - enable: false, - frame_id: 0, - next_frame_id: 0, - callee_fid: 0, - fid: 0, - iid: 0, - }, - ); - for entry in static_entries { ctx.region.assign_fixed( || "jtable start entries", @@ -123,7 +109,10 @@ impl JumpTableChip { } } - Ok(cells) + Ok(cells.try_into().expect(&format!( + "The number of static frame entries should be {}", + STATIC_FRAME_ENTRY_NUMBER + ))) } fn assign_jtable_entries( @@ -197,8 +186,8 @@ impl JumpTableChip { ctx: &mut Context<'_, F>, jtable: &JumpTable, etable_jops_cell: &Option>, - static_entries: &Vec, - ) -> Result, AssignedCell)>, Error> { + static_entries: &[StaticFrameEntry; STATIC_FRAME_ENTRY_NUMBER], + ) -> Result<[(AssignedCell, AssignedCell); STATIC_FRAME_ENTRY_NUMBER], Error> { if etable_jops_cell.is_some() { self.constraint_to_etable_jops(ctx, etable_jops_cell.as_ref().unwrap())?; } diff --git a/crates/zkwasm/src/circuits/jtable/mod.rs b/crates/zkwasm/src/circuits/jtable/mod.rs index 786fb62a4..34132e87a 100644 --- a/crates/zkwasm/src/circuits/jtable/mod.rs +++ b/crates/zkwasm/src/circuits/jtable/mod.rs @@ -4,16 +4,13 @@ use halo2_proofs::plonk::Advice; use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Fixed; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use std::marker::PhantomData; mod assign; mod configure; pub(crate) mod expression; -// 1. jumps to zkmain -// 2. jumps to start(if exists) -pub(crate) const STATIC_FRAME_ENTRY_NUMBER: usize = 2; - // enable and data should encode in image table pub(crate) const STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY: usize = STATIC_FRAME_ENTRY_NUMBER * 2; diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 4c5404589..e79a2534c 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -12,6 +12,7 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; use num_bigint::BigUint; use specs::encode::init_memory_table::encode_init_memory_table_address; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use specs::mtable::LocationType; use crate::circuits::image_table::ImageTableConfig; @@ -143,33 +144,36 @@ impl PostImageTableChipTrait let static_frame_entries_handler = |base_offset| { ctx.borrow_mut().offset = base_offset; - permutation_cells - .static_frame_entries - .iter() - .map(|(enable, entry)| { - let offset = ctx.borrow().offset; + let mut cells = vec![]; - enable.copy_advice( - || "image table: static frame entry", - &mut ctx.borrow_mut().region, - self.config.post_image_table, - offset, - )?; - ctx.borrow_mut().next(); + for (enable, entry) in &permutation_cells.static_frame_entries { + let offset = ctx.borrow().offset; - let offset = ctx.borrow().offset; + enable.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + ctx.borrow_mut().next(); - entry.copy_advice( - || "image table: static frame entry", - &mut ctx.borrow_mut().region, - self.config.post_image_table, - offset, - )?; - ctx.borrow_mut().next(); + let offset = ctx.borrow().offset; - Ok((enable.clone(), entry.clone())) - }) - .collect::, Error>>() + entry.copy_advice( + || "image table: static frame entry", + &mut ctx.borrow_mut().region, + self.config.post_image_table, + offset, + )?; + ctx.borrow_mut().next(); + + cells.push((enable.clone(), entry.clone())); + } + + Ok(cells.try_into().expect(&format!( + "The number of static frame entries should be {}", + STATIC_FRAME_ENTRY_NUMBER + ))) }; let instruction_handler = |base_offset| { diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index bafe47c6c..9b71ee6ae 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -317,13 +317,7 @@ impl Circuit for TestCircuit { let mut image_table_assigner = ImageTableAssigner::new( // Add one for default lookup value self.tables.compilation_tables.itable.entries().len() + 1, - // FIXME: avoid compute - self.tables - .compilation_tables - .itable - .create_brtable() - .entries() - .len() + self.tables.compilation_tables.br_table.entries().len() + self.tables.compilation_tables.elem_table.entries().len() + 1, config.circuit_maximal_pages, diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index 5689e01e0..f909df3f2 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -3,6 +3,7 @@ use halo2_proofs::arithmetic::FieldExt; use num_bigint::BigUint; use specs::encode::image_table::ImageTableEncoder; use specs::imtable::InitMemoryTableEntry; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use specs::mtable::LocationType; use specs::mtable::VarType; use specs::state::InitializationState; @@ -13,7 +14,6 @@ use crate::circuits::config::zkwasm_k; use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::PAGE_ENTRIES; use crate::circuits::jtable::STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; -use crate::circuits::jtable::STATIC_FRAME_ENTRY_NUMBER; use crate::circuits::utils::bn_to_field; pub const STACK_CAPABILITY: usize = DEFAULT_VALUE_STACK_LIMIT; @@ -62,7 +62,7 @@ impl InitMemoryLayouter { #[allow(dead_code)] pub(crate) struct ImageTableLayouter { pub(crate) initialization_state: InitializationState, - pub(crate) static_frame_entries: Vec<(T, T)>, + pub(crate) static_frame_entries: [(T, T); STATIC_FRAME_ENTRY_NUMBER], pub(crate) instructions: Vec, pub(crate) br_table_entires: Vec, // NOTE: unused instructions and br_table entries. @@ -114,8 +114,13 @@ impl ImageTableAssigner { pub fn exec_static_frame_entries( &mut self, - mut static_frame_entries_handler: impl FnMut(usize) -> Result, Error>, - ) -> Result, Error> { + mut static_frame_entries_handler: impl FnMut( + usize, + ) -> Result< + [(T, T); STATIC_FRAME_ENTRY_NUMBER], + Error, + >, + ) -> Result<[(T, T); STATIC_FRAME_ENTRY_NUMBER], Error> { static_frame_entries_handler(self.static_frame_entries_offset) } @@ -150,7 +155,10 @@ impl ImageTableAssigner { pub fn exec( &mut self, initialization_state_handler: impl FnMut(usize) -> Result, Error>, - static_frame_entries_handler: impl FnMut(usize) -> Result, Error>, + static_frame_entries_handler: impl FnMut( + usize, + ) + -> Result<[(T, T); STATIC_FRAME_ENTRY_NUMBER], Error>, instruction_handler: impl FnMut(usize) -> Result, Error>, br_table_handler: impl FnMut(usize) -> Result, Error>, padding_handler: impl FnMut(usize, usize) -> Result, Error>, @@ -190,11 +198,16 @@ impl EncodeCompilationTableValues for CompilationTable { // Encode disabled static frame entry in image table assert_eq!(self.static_jtable.len(), STATIC_FRAME_ENTRY_NUMBER); - Ok(self - .static_jtable - .iter() - .map(|entry| (F::from(entry.enable as u64), bn_to_field(&entry.encode()))) - .collect()) + let mut cells = vec![]; + + for entry in self.static_jtable.as_ref() { + cells.push((F::from(entry.enable as u64), bn_to_field(&entry.encode()))); + } + + Ok(cells.try_into().expect(&format!( + "The number of static frame entries should be {}", + STATIC_FRAME_ENTRY_NUMBER + ))) }; let instruction_handler = |_| { diff --git a/crates/zkwasm/src/runtime/wasmi_interpreter.rs b/crates/zkwasm/src/runtime/wasmi_interpreter.rs index 3214b0367..a18afeecf 100644 --- a/crates/zkwasm/src/runtime/wasmi_interpreter.rs +++ b/crates/zkwasm/src/runtime/wasmi_interpreter.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use anyhow::Result; use specs::host_function::HostFunctionDesc; use specs::jtable::StaticFrameEntry; +use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use specs::state::InitializationState; use specs::CompilationTable; use specs::ExecutionTable; @@ -181,7 +182,17 @@ impl WasmiRuntime { let br_table = Arc::new(itable.create_brtable()); 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 static_jtable = Arc::new( + tracer + .borrow() + .static_jtable_entries + .clone() + .try_into() + .expect(&format!( + "The number of static frame entries should be {}", + STATIC_FRAME_ENTRY_NUMBER + )), + ); let initialization_state = InitializationState { eid: 1, fid: fid_of_entry, From 09b8638cb82afc9700641cd6151c8bd5028a08e6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Dec 2023 07:22:02 +0000 Subject: [PATCH 18/28] fix code style --- crates/zkwasm/src/circuits/jtable/assign.rs | 3 +- crates/zkwasm/src/circuits/jtable/mod.rs | 2 +- crates/zkwasm/src/circuits/mtable/assign.rs | 38 ++++++++++----------- crates/zkwasm/src/circuits/mtable/mod.rs | 14 +++----- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 4dfda5e4a..49ddb26f1 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -195,8 +195,9 @@ impl JumpTableChip { self.init(ctx)?; ctx.reset(); + // non-static entry includes `call`` and `return`` op let mut rest_jops = jtable.entries().len() as u64 * 2; - + // static entry only includes `return` op for entry in static_entries { if entry.enable { rest_jops += 1; diff --git a/crates/zkwasm/src/circuits/jtable/mod.rs b/crates/zkwasm/src/circuits/jtable/mod.rs index 34132e87a..5450888f1 100644 --- a/crates/zkwasm/src/circuits/jtable/mod.rs +++ b/crates/zkwasm/src/circuits/jtable/mod.rs @@ -11,7 +11,7 @@ mod assign; mod configure; pub(crate) mod expression; -// enable and data should encode in image table +// enable and data should be encoded in image table pub(crate) const STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY: usize = STATIC_FRAME_ENTRY_NUMBER * 2; pub enum JtableOffset { diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index 437b12284..0be113dc0 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -41,9 +41,9 @@ impl MemoryTableChip { #[cfg(feature = "continuation")] ctx.region.assign_advice_from_constant( - || "rest_memory_updating_ops terminate", - self.config.rest_memory_updating_ops.0.col, - ctx.offset + self.config.rest_memory_updating_ops.0.rot as usize, + || "rest_memory_finalize_ops terminate", + self.config.rest_memory_finalize_ops.0.col, + ctx.offset + self.config.rest_memory_finalize_ops.0.rot as usize, F::zero(), )?; } @@ -55,16 +55,16 @@ impl MemoryTableChip { } #[cfg(feature = "continuation")] - fn constrain_rest_memory_updating_ops( + fn constrain_rest_memory_finalize_ops( &self, ctx: &mut Context<'_, F>, - rest_memory_updating_ops: u32, + rest_memory_finalize_ops: u32, ) -> Result, Error> { // Overwrite in assign_entries let cell = self .config - .rest_memory_updating_ops - .assign(ctx, F::from(rest_memory_updating_ops as u64))?; + .rest_memory_finalize_ops + .assign(ctx, F::from(rest_memory_finalize_ops as u64))?; Ok(cell) } @@ -94,7 +94,7 @@ impl MemoryTableChip { mtable: &MemoryWritingTable, init_rest_mops: u64, _imtable: &InitMemoryTable, - mut _rest_memory_updating_ops: u32, + mut _rest_memory_finalize_ops: u32, ) -> Result<(), Error> { macro_rules! assign_advice { ($cell:ident, $value:expr) => { @@ -195,8 +195,8 @@ impl MemoryTableChip { #[cfg(feature = "continuation")] assign_advice!( - rest_memory_updating_ops, - F::from(_rest_memory_updating_ops as u64) + rest_memory_finalize_ops, + F::from(_rest_memory_finalize_ops as u64) ); assign_advice!( @@ -220,13 +220,13 @@ impl MemoryTableChip { if entry.entry.atype == AccessType::Write && !entry.entry.is_same_location(&next_entry.entry) { - _rest_memory_updating_ops -= 1; + _rest_memory_finalize_ops -= 1; } } else { // It's last entry if entry.entry.atype == AccessType::Write { - _rest_memory_updating_ops -= 1; + _rest_memory_finalize_ops -= 1; } } @@ -269,7 +269,7 @@ impl MemoryTableChip { Ok(()) } - fn compute_rest_memory_updating_ops(&self, mtable: &MemoryWritingTable) -> u32 { + fn compute_rest_memory_finalize_ops(&self, mtable: &MemoryWritingTable) -> u32 { let mut ops = 0u32; let mut iter = mtable.0.iter().peekable(); @@ -309,11 +309,11 @@ impl MemoryTableChip { self.assign_fixed(ctx)?; ctx.reset(); - let rest_memory_updating_ops = self.compute_rest_memory_updating_ops(mtable); + let rest_memory_finalize_ops = self.compute_rest_memory_finalize_ops(mtable); #[cfg(feature = "continuation")] - let rest_memory_updating_ops_cell = - self.constrain_rest_memory_updating_ops(ctx, rest_memory_updating_ops)?; + let rest_memory_finalize_ops_cell = + self.constrain_rest_memory_finalize_ops(ctx, rest_memory_finalize_ops)?; let rest_mops_cell = self.constrain_rest_mops_permutation(ctx, etable_rest_mops_cell, rest_mops)?; @@ -322,15 +322,15 @@ impl MemoryTableChip { * Skip subsequent advice assignment in the first pass to enhance performance. */ if rest_mops_cell.value().is_some() { - self.assign_entries(ctx, mtable, rest_mops, imtable, rest_memory_updating_ops)?; + self.assign_entries(ctx, mtable, rest_mops, imtable, rest_memory_finalize_ops)?; ctx.reset(); } cfg_if::cfg_if! { if #[cfg(feature="continuation")] { - Ok((Some(rest_memory_updating_ops_cell), F::from(rest_memory_updating_ops as u64))) + Ok((Some(rest_memory_finalize_ops_cell), F::from(rest_memory_finalize_ops as u64))) } else { - Ok((None, F::from(rest_memory_updating_ops as u64))) + Ok((None, F::from(rest_memory_finalize_ops as u64))) } } } diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index 2eace1f46..59f4b0df9 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -46,10 +46,6 @@ pub struct MemoryTableConfig { end_eid_cell: AllocatedU32StateCell, eid_diff_cell: AllocatedU32StateCell, rest_mops_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, @@ -59,7 +55,7 @@ pub struct MemoryTableConfig { init_encode_cell: AllocatedUnlimitedCell, #[cfg(feature = "continuation")] - rest_memory_updating_ops: AllocatedUnlimitedCell, + rest_memory_finalize_ops: AllocatedUnlimitedCell, value: AllocatedU64Cell, } @@ -103,7 +99,7 @@ impl MemoryTableConfig { let init_encode_cell = allocator.alloc_unlimited_cell(); #[cfg(feature = "continuation")] - let rest_memory_updating_ops = { + let rest_memory_finalize_ops = { let cell = allocator.alloc_unlimited_cell(); // FIXME: try to avoid this? meta.enable_equality(cell.0.col); @@ -347,8 +343,8 @@ impl MemoryTableConfig { { meta.create_gate("mc13. rest memory updating ops", |meta| { vec![ - rest_memory_updating_ops.curr_expr(meta) - - rest_memory_updating_ops.next_expr(meta) + rest_memory_finalize_ops.curr_expr(meta) + - rest_memory_finalize_ops.next_expr(meta) - (constant_from!(1) - is_next_same_offset_cell.curr_expr(meta)) * (constant_from!(1) - is_init_cell.curr_expr(meta)), ] @@ -387,7 +383,7 @@ impl MemoryTableConfig { encode_cell, #[cfg(feature = "continuation")] - rest_memory_updating_ops, + rest_memory_finalize_ops, } } } From 208b804ef5ce762de4e856fd5d642262cbf19721 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Dec 2023 07:46:06 +0000 Subject: [PATCH 19/28] fix comment --- Cargo.lock | 16 ++++----- crates/zkwasm/src/checksum/mod.rs | 9 +++-- crates/zkwasm/src/circuits/mtable/assign.rs | 29 +--------------- crates/zkwasm/src/circuits/mtable/mod.rs | 33 ++----------------- .../zkwasm/src/circuits/test_circuit/mod.rs | 7 ++-- .../zkwasm/src/circuits/utils/image_table.rs | 17 +++------- crates/zkwasm/src/loader/mod.rs | 3 +- 7 files changed, 27 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c389443d7..9cc8621ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1016,9 +1016,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memmap" @@ -1481,9 +1481,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -1493,9 +1493,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1504,9 +1504,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rust-gpu-tools" diff --git a/crates/zkwasm/src/checksum/mod.rs b/crates/zkwasm/src/checksum/mod.rs index 3ec68d439..bf04d7133 100644 --- a/crates/zkwasm/src/checksum/mod.rs +++ b/crates/zkwasm/src/checksum/mod.rs @@ -6,7 +6,7 @@ use specs::CompilationTable; use crate::circuits::utils::image_table::EncodeCompilationTableValues; pub trait ImageCheckSum { - fn checksum(&self) -> Output; + fn checksum(&self, page_capability: u32) -> Output; } pub(crate) struct CompilationTableWithParams<'a, 'b, C: CurveAffine> { @@ -15,8 +15,11 @@ pub(crate) struct CompilationTableWithParams<'a, 'b, C: CurveAffine> { } impl<'a, 'b, C: CurveAffine> ImageCheckSum> for CompilationTableWithParams<'a, 'b, C> { - fn checksum(&self) -> Vec { - let cells = self.table.encode_compilation_table_values().plain(); + fn checksum(&self, page_capability: u32) -> Vec { + let cells = self + .table + .encode_compilation_table_values(page_capability) + .plain(); let c = best_multiexp_gpu_cond(&cells[..], &self.params.get_g_lagrange()[0..cells.len()]); vec![c.into()] diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index 0be113dc0..045e060c0 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -6,7 +6,6 @@ use halo2_proofs::plonk::Error; use log::debug; use specs::encode::init_memory_table::encode_init_memory_table_entry; use specs::encode::memory_table::encode_memory_table_entry; -use specs::imtable::InitMemoryTable; use specs::mtable::AccessType; use specs::mtable::LocationType; use specs::mtable::VarType; @@ -60,7 +59,6 @@ impl MemoryTableChip { ctx: &mut Context<'_, F>, rest_memory_finalize_ops: u32, ) -> Result, Error> { - // Overwrite in assign_entries let cell = self .config .rest_memory_finalize_ops @@ -93,7 +91,6 @@ impl MemoryTableChip { ctx: &mut Context<'_, F>, mtable: &MemoryWritingTable, init_rest_mops: u64, - _imtable: &InitMemoryTable, mut _rest_memory_finalize_ops: u32, ) -> Result<(), Error> { macro_rules! assign_advice { @@ -154,26 +151,6 @@ impl MemoryTableChip { assign_bit_if!(entry.entry.atype.is_init(), is_init_cell); - if ctx.offset == 207328 { - println!("is init: {}", entry.entry.atype.is_init()); - } - - //if entry.entry.atype.is_init() { - // let init_memory_entry = imtable - // .try_find(entry.entry.ltype, entry.entry.offset) - // .unwrap(); - - // assign_advice!(offset_align_left, left_offset); - // assign_advice!(offset_align_right, right_offset); - // assign_advice!( - // offset_align_left_diff_cell, - // entry.entry.offset - left_offset - // ); - // assign_advice!( - // offset_align_right_diff_cell, - // right_offset - entry.entry.offset - // ); - assign_advice!( init_encode_cell, bn_to_field(&encode_init_memory_table_entry( @@ -184,7 +161,6 @@ impl MemoryTableChip { entry.entry.value.into() )) ); - //} assign_u32_state!(start_eid_cell, entry.entry.eid); assign_u32_state!(end_eid_cell, entry.end_eid); @@ -264,8 +240,6 @@ impl MemoryTableChip { ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); } - println!("mtable end: {}", ctx.offset); - Ok(()) } @@ -296,7 +270,6 @@ impl MemoryTableChip { ctx: &mut Context<'_, F>, etable_rest_mops_cell: &Option>, mtable: &MemoryWritingTable, - imtable: &InitMemoryTable, ) -> Result<(Option>, F), Error> { debug!("size of memory writing table: {}", mtable.0.len()); assert!(mtable.0.len() * (MEMORY_TABLE_ENTRY_ROWS as usize) < self.maximal_available_rows); @@ -322,7 +295,7 @@ impl MemoryTableChip { * Skip subsequent advice assignment in the first pass to enhance performance. */ if rest_mops_cell.value().is_some() { - self.assign_entries(ctx, mtable, rest_mops, imtable, rest_memory_finalize_ops)?; + self.assign_entries(ctx, mtable, rest_mops, rest_memory_finalize_ops)?; ctx.reset(); } diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index 59f4b0df9..92d46adeb 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -89,7 +89,6 @@ impl MemoryTableConfig { let eid_diff_cell = allocator.alloc_u32_state_cell(); let rest_mops_cell = allocator.alloc_common_range_cell(); - // TODO: cut allocated u32 cell let offset_cell = allocator.alloc_u32_cell(); let offset_diff_cell = allocator.alloc_u32_cell(); @@ -193,32 +192,8 @@ impl MemoryTableConfig { .collect::>() }); - // meta.create_gate("mc7a. init", |meta| { - // vec![ - // // offset_left_align <= offset && offset <= offset_right_align - // is_init_cell.curr_expr(meta) - // * (offset_align_left.curr_expr(meta) - // + offset_align_left_diff_cell.curr_expr(meta) - // - offset_cell.curr_expr(meta)), - // is_init_cell.curr_expr(meta) - // * (offset_cell.curr_expr(meta) + offset_align_right_diff_cell.curr_expr(meta) - // - offset_align_right.curr_expr(meta)), - // ] - // .into_iter() - // .map(|x| x * fixed_curr!(meta, entry_sel)) - // .collect::>() - // }); - - #[cfg(not(feature = "continuation"))] - meta.create_gate("mc7a. init start_eid equals 0", |meta| { - vec![is_init_cell.curr_expr(meta) * start_eid_cell.curr_expr(meta)] - .into_iter() - .map(|x| x * fixed_curr!(meta, entry_sel)) - .collect::>() - }); - meta.create_gate( - "mc7b. global must has init (because of mutability check).", + "mc7a. global must has init (because of mutability check).", |meta| { vec![ (is_next_same_offset_cell.expr(meta) - constant_from!(1)) @@ -231,7 +206,7 @@ impl MemoryTableConfig { }, ); - meta.create_gate("mc7c. init encode.", |meta| { + meta.create_gate("mc7b. init encode.", |meta| { vec![ encode_init_memory_table_entry( is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) @@ -374,10 +349,6 @@ impl MemoryTableConfig { offset_diff_cell, offset_diff_inv_cell, offset_diff_inv_helper_cell, - // offset_align_left, - // offset_align_right, - // offset_align_left_diff_cell, - // offset_align_right_diff_cell, value, init_encode_cell, encode_cell, diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 9b71ee6ae..87e8ab7de 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -274,7 +274,6 @@ impl Circuit for TestCircuit { &mut ctx, &etable_permutation_cells.rest_mops, &memory_writing_table, - &self.tables.compilation_tables.imtable )? ) }; @@ -330,7 +329,7 @@ impl Circuit for TestCircuit { &mut image_table_assigner, self.tables .compilation_tables - .encode_compilation_table_values(), + .encode_compilation_table_values(config.circuit_maximal_pages), ImageTableLayouter { initialization_state: etable_permutation_cells.pre_initialization_state, static_frame_entries, @@ -349,10 +348,10 @@ impl Circuit for TestCircuit { &mut image_table_assigner, self.tables .compilation_tables - .encode_compilation_table_values(), + .encode_compilation_table_values(config.circuit_maximal_pages), self.tables .post_image_table - .encode_compilation_table_values(), + .encode_compilation_table_values(config.circuit_maximal_pages), ImageTableLayouter { initialization_state: etable_permutation_cells.post_initialization_state, static_frame_entries: pre_image_table_cells.static_frame_entries, diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index f909df3f2..d526cfa2c 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -10,8 +10,6 @@ use specs::state::InitializationState; use specs::CompilationTable; use wasmi::DEFAULT_VALUE_STACK_LIMIT; -use crate::circuits::config::zkwasm_k; -use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::PAGE_ENTRIES; use crate::circuits::jtable::STATIC_FRAME_ENTRY_IMAGE_TABLE_ENTRY; use crate::circuits::utils::bn_to_field; @@ -183,14 +181,11 @@ impl ImageTableAssigner { } pub(crate) trait EncodeCompilationTableValues { - fn encode_compilation_table_values(&self) -> ImageTableLayouter; + fn encode_compilation_table_values(&self, page_capability: u32) -> ImageTableLayouter; } impl EncodeCompilationTableValues for CompilationTable { - fn encode_compilation_table_values(&self) -> ImageTableLayouter { - // FIXME: ugly - let pages_capability = compute_maximal_pages(zkwasm_k()); - + fn encode_compilation_table_values(&self, page_capability: u32) -> ImageTableLayouter { let initialization_state_handler = |_| Ok(self.initialization_state.map(|v| F::from((*v) as u64))); @@ -254,7 +249,7 @@ impl EncodeCompilationTableValues for CompilationTable { )); let layouter = InitMemoryLayouter { - pages: pages_capability, + pages: page_capability, }; layouter.for_each(|(ltype, offset)| { @@ -288,7 +283,7 @@ impl EncodeCompilationTableValues for CompilationTable { let mut assigner = ImageTableAssigner::new( self.itable.entries().len(), self.br_table.entries().len() + self.elem_table.entries().len(), - pages_capability, + page_capability, ); let layouter = assigner @@ -314,10 +309,8 @@ impl ImageTableLayouter { buf.append( &mut self .static_frame_entries - .clone() - .to_vec() - .into_iter() .map(|(enable, fid)| vec![enable, fid]) + .into_iter() .collect::>>() .concat(), ); diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index 4c32ad0bd..e6959f5f7 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -26,6 +26,7 @@ use crate::checksum::CompilationTableWithParams; use crate::checksum::ImageCheckSum; use crate::circuits::config::init_zkwasm_runtime; use crate::circuits::config::set_zkwasm_k; +use crate::circuits::image_table::compute_maximal_pages; use crate::circuits::image_table::IMAGE_COL_NAME; use crate::circuits::TestCircuit; use crate::circuits::ZkWasmCircuitBuilder; @@ -172,7 +173,7 @@ impl ZkWasmLoader { params, }; - Ok(table_with_params.checksum()) + Ok(table_with_params.checksum(compute_maximal_pages(self.k))) } } From 6773632c29091140804a9fd269ee1e9d1f839ad5 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Dec 2023 13:30:05 +0000 Subject: [PATCH 20/28] add name for post image table col --- crates/zkwasm/src/circuits/post_image_table/continuation.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index e79a2534c..3aaeaa4f4 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -31,6 +31,8 @@ use crate::next; use super::PostImageTableChipTrait; use super::PostImageTableConfigTrait; +pub const POST_IMAGE_TABLE: &str = "post_img_col"; + #[derive(Clone)] pub(in crate::circuits) struct ContinuationPostImageTableConfig { memory_addr_sel: Column, @@ -49,7 +51,7 @@ impl PostImageTableConfigTrait for ContinuationPostImageTableCon ) -> Self { let update = meta.advice_column(); let rest_memory_finalized_count = meta.advice_column(); - let post_image_table = meta.advice_column(); + let post_image_table = meta.named_advice_column(POST_IMAGE_TABLE.to_owned()); meta.enable_equality(rest_memory_finalized_count); meta.enable_equality(post_image_table); From d861066e7877b0e2046dc47d138e8cdcd92e3654 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Dec 2023 14:06:05 +0000 Subject: [PATCH 21/28] fix image table assigner --- crates/zkwasm/src/circuits/utils/image_table.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index d526cfa2c..e72fe1221 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -140,7 +140,7 @@ impl ImageTableAssigner { &mut self, mut padding_handler: impl FnMut(usize, usize) -> Result, Error>, ) -> Result, Error> { - padding_handler(self.padding_offset, self.padding_offset) + padding_handler(self.padding_offset, self.init_memory_offset) } pub fn exec_init_memory_entries( @@ -281,8 +281,8 @@ impl EncodeCompilationTableValues for CompilationTable { }; let mut assigner = ImageTableAssigner::new( - self.itable.entries().len(), - self.br_table.entries().len() + self.elem_table.entries().len(), + self.itable.entries().len() + 1, + self.br_table.entries().len() + self.elem_table.entries().len() + 1, page_capability, ); From 1fd206636a8082e0b494c15e7696d517d82dc1a0 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Dec 2023 05:37:43 +0000 Subject: [PATCH 22/28] fix circuit_without_witness --- crates/cli/src/exec.rs | 17 ++++++- crates/zkwasm/src/circuits/mod.rs | 6 +++ crates/zkwasm/src/continuation/loader.rs | 2 +- crates/zkwasm/src/continuation/slice.rs | 8 ---- crates/zkwasm/src/loader/mod.rs | 57 +++++++++++++++--------- crates/zkwasm/src/test/test_rlp.rs | 2 +- crates/zkwasm/src/test/test_rlp_slice.rs | 7 ++- 7 files changed, 65 insertions(+), 34 deletions(-) diff --git a/crates/cli/src/exec.rs b/crates/cli/src/exec.rs index e5d0ec7b3..c67b40e12 100644 --- a/crates/cli/src/exec.rs +++ b/crates/cli/src/exec.rs @@ -2,6 +2,7 @@ use anyhow::Result; use delphinus_zkwasm::circuits::TestCircuit; use delphinus_zkwasm::loader::ExecutionArg; use delphinus_zkwasm::loader::ZkWasmLoader; +use delphinus_zkwasm::runtime::host::host_env::HostEnv; use halo2_proofs::arithmetic::BaseExt; use halo2_proofs::pairing::bn256::Bn256; use halo2_proofs::pairing::bn256::Fr; @@ -96,12 +97,18 @@ pub fn exec_image_checksum( ) -> Result<()> { let loader = ZkWasmLoader::::new(zkwasm_k, wasm_binary, phantom_functions)?; + let image = if cfg!(feature = "continuation") { + todo!("read slice image from file?"); + } else { + loader.compile_without_env()?.tables + }; + let params = load_or_build_unsafe_params::( zkwasm_k, Some(&output_dir.join(format!("K{}.params", zkwasm_k))), ); - let checksum = loader.checksum(¶ms)?; + let checksum = loader.checksum(&image, ¶ms)?; assert_eq!(checksum.len(), 1); let checksum = checksum[0]; @@ -333,7 +340,13 @@ pub fn exec_verify_proof( let proof = load_proof(proof_path); - loader.verify_proof(¶ms, vkey, instances, proof)?; + let image = if cfg!(feature = "continuation") { + todo!("read slice image from file?") + } else { + loader.compile_without_env()?.tables + }; + + loader.verify_proof(&image, ¶ms, vkey, &instances, proof)?; info!("Verifing proof passed"); diff --git a/crates/zkwasm/src/circuits/mod.rs b/crates/zkwasm/src/circuits/mod.rs index 672f3b1c3..dca24ab37 100644 --- a/crates/zkwasm/src/circuits/mod.rs +++ b/crates/zkwasm/src/circuits/mod.rs @@ -64,6 +64,12 @@ pub struct ZkWasmCircuitBuilder { impl ZkWasmCircuitBuilder { pub fn build_circuit(self, slice_capability: Option) -> TestCircuit { + #[cfg(feature = "continuation")] + assert!(slice_capability.is_some()); + + #[cfg(not(feature = "continuation"))] + assert!(slice_capability.is_none()); + TestCircuit::new(self.tables, slice_capability) } } diff --git a/crates/zkwasm/src/continuation/loader.rs b/crates/zkwasm/src/continuation/loader.rs index d98848813..335b8fb05 100644 --- a/crates/zkwasm/src/continuation/loader.rs +++ b/crates/zkwasm/src/continuation/loader.rs @@ -8,7 +8,7 @@ use crate::runtime::ExecutionResult; use super::slice::Slices; impl ZkWasmLoader { - fn compute_slice_capability(&self) -> usize { + pub(crate) fn compute_slice_capability(&self) -> usize { ((1 << self.k) - 200) / EVENT_TABLE_ENTRY_ROWS as usize } diff --git a/crates/zkwasm/src/continuation/slice.rs b/crates/zkwasm/src/continuation/slice.rs index 85a6e2117..7a7c85fd0 100644 --- a/crates/zkwasm/src/continuation/slice.rs +++ b/crates/zkwasm/src/continuation/slice.rs @@ -63,14 +63,6 @@ impl Iterator for Slices { } let mut etable_entries = self.pop_etable_entries(); - // let etable = EventTable::new(etable_entries); - - // let is_last_slice = self.remaining_etable_entries.is_empty(); - - // if !is_last_slice { - // self.remaining_etable_entries - // .insert(0, etable.entries().last().unwrap().clone()); - // } let (updated_init_memory_table, updated_post_initialization_state) = { let updated_init_memory_table = self diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index e6959f5f7..a3b7a8b74 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; @@ -97,7 +98,7 @@ impl ZkWasmLoader { Ok(()) } - fn compile(&self, env: &HostEnv) -> Result, Tracer>> { + pub fn compile(&self, env: &HostEnv) -> Result, Tracer>> { let imports = ImportsBuilder::new().with_resolver("env", env); WasmInterpreter::compile( @@ -109,7 +110,7 @@ impl ZkWasmLoader { ) } - fn circuit_without_witness(&self, last_slice_circuit: bool) -> Result> { + pub fn compile_without_env(&self) -> Result, Tracer>> { let (env, _) = HostEnv::new_with_full_foreign_plugins( vec![], vec![], @@ -117,7 +118,11 @@ impl ZkWasmLoader { Arc::new(Mutex::new(vec![])), ); - let compiled_module = self.compile(&env)?; + self.compile(&env) + } + + fn circuit_without_witness(&self, last_slice_circuit: bool) -> Result> { + let compiled_module = self.compile_without_env()?; let builder = ZkWasmCircuitBuilder { tables: Tables { @@ -128,7 +133,13 @@ impl ZkWasmLoader { }, }; - Ok(builder.build_circuit::(None)) + Ok( + builder.build_circuit::(if cfg!(feature = "continuation") { + Some(self.compute_slice_capability()) + } else { + None + }), + ) } pub fn new(k: u32, image: Vec, phantom_functions: Vec) -> Result { @@ -159,17 +170,13 @@ impl ZkWasmLoader { Ok(keygen_vk(¶ms, &circuit).unwrap()) } - pub fn checksum(&self, params: &Params) -> Result> { - let (env, _) = HostEnv::new_with_full_foreign_plugins( - vec![], - vec![], - vec![], - Arc::new(Mutex::new(vec![])), - ); - let compiled = self.compile(&env)?; - + pub fn checksum<'a, 'b>( + &self, + image: &'b CompilationTable, + params: &'a Params, + ) -> Result> { let table_with_params = CompilationTableWithParams { - table: &compiled.tables, + table: &image, params, }; @@ -269,9 +276,10 @@ impl ZkWasmLoader { pub fn verify_proof( &self, + image: &CompilationTable, params: &Params, vkey: VerifyingKey, - instances: Vec, + instances: &Vec, proof: Vec, ) -> Result<()> { let params_verifier: ParamsVerifier = params.verifier(instances.len()).unwrap(); @@ -300,7 +308,7 @@ impl ZkWasmLoader { &mut PoseidonRead::init(&proof[..]), ) .unwrap(); - let checksum = self.checksum(params)?; + let checksum = self.checksum(image, params)?; assert!(vec![img_col_commitment[img_col_idx as usize]] == checksum) } @@ -327,7 +335,7 @@ mod tests { use super::ZkWasmLoader; impl ZkWasmLoader { - pub(crate) fn bench_test(&self, circuit: TestCircuit, instances: Vec) { + pub(crate) fn bench_test(&self, circuit: TestCircuit, instances: &Vec) { fn prepare_param(k: u32) -> Params { let path = PathBuf::from(format!("test_param.{}.data", k)); @@ -351,12 +359,21 @@ mod tests { } let params = prepare_param(self.k); - let vkey = self.create_vkey(¶ms, true).unwrap(); + let vkey = self + .create_vkey(¶ms, circuit.tables.is_last_slice) + .unwrap(); let proof = self - .create_proof(¶ms, vkey.clone(), circuit, &instances) + .create_proof(¶ms, vkey.clone(), circuit.clone(), &instances) .unwrap(); - self.verify_proof(¶ms, vkey, instances, proof).unwrap(); + self.verify_proof( + &circuit.tables.compilation_tables, + ¶ms, + vkey, + instances, + proof, + ) + .unwrap(); } } } diff --git a/crates/zkwasm/src/test/test_rlp.rs b/crates/zkwasm/src/test/test_rlp.rs index 377a0374f..a22ec23b4 100644 --- a/crates/zkwasm/src/test/test_rlp.rs +++ b/crates/zkwasm/src/test/test_rlp.rs @@ -179,7 +179,7 @@ mod tests { fn test_rlp_bench() { let (loader, circuit, instances) = build_circuit().unwrap(); - loader.bench_test(circuit, instances) + loader.bench_test(circuit, &instances) } } } diff --git a/crates/zkwasm/src/test/test_rlp_slice.rs b/crates/zkwasm/src/test/test_rlp_slice.rs index 89ead8347..0e3edd7ac 100644 --- a/crates/zkwasm/src/test/test_rlp_slice.rs +++ b/crates/zkwasm/src/test/test_rlp_slice.rs @@ -169,9 +169,12 @@ fn test_slices() -> Result<()> { while let Some(slice) = slices.next() { println!("slice {}", index); - let circuit = slice.build_circuit(); + if index != 0 { + let circuit = slice.build_circuit(); - loader.mock_test(&circuit, &instances)?; + loader.mock_test(&circuit, &instances)?; + loader.bench_test(circuit, &instances); + } index += 1; } From ce30af317b7a95910a58db3484293c66034fa5e5 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Dec 2023 05:39:09 +0000 Subject: [PATCH 23/28] fix rlp_slice test --- crates/cli/src/exec.rs | 1 - crates/zkwasm/src/test/test_rlp_slice.rs | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/cli/src/exec.rs b/crates/cli/src/exec.rs index c67b40e12..3c7bc2fe3 100644 --- a/crates/cli/src/exec.rs +++ b/crates/cli/src/exec.rs @@ -2,7 +2,6 @@ use anyhow::Result; use delphinus_zkwasm::circuits::TestCircuit; use delphinus_zkwasm::loader::ExecutionArg; use delphinus_zkwasm::loader::ZkWasmLoader; -use delphinus_zkwasm::runtime::host::host_env::HostEnv; use halo2_proofs::arithmetic::BaseExt; use halo2_proofs::pairing::bn256::Bn256; use halo2_proofs::pairing::bn256::Fr; diff --git a/crates/zkwasm/src/test/test_rlp_slice.rs b/crates/zkwasm/src/test/test_rlp_slice.rs index 0e3edd7ac..a0b657fe7 100644 --- a/crates/zkwasm/src/test/test_rlp_slice.rs +++ b/crates/zkwasm/src/test/test_rlp_slice.rs @@ -169,12 +169,10 @@ fn test_slices() -> Result<()> { while let Some(slice) = slices.next() { println!("slice {}", index); - if index != 0 { - let circuit = slice.build_circuit(); + let circuit = slice.build_circuit(); - loader.mock_test(&circuit, &instances)?; - loader.bench_test(circuit, &instances); - } + loader.mock_test(&circuit, &instances)?; + loader.bench_test(circuit, &instances); index += 1; } From bdfbb8e7a8c167300e23907e3630bb4020d15ca0 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Dec 2023 05:55:39 +0000 Subject: [PATCH 24/28] fix compiling error --- crates/zkwasm/src/loader/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index a3b7a8b74..f5cc77ae9 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -133,13 +133,12 @@ impl ZkWasmLoader { }, }; - Ok( - builder.build_circuit::(if cfg!(feature = "continuation") { - Some(self.compute_slice_capability()) - } else { - None - }), - ) + #[cfg(feature = "continuation")] + let slice_capabitlity = Some(self.compute_slice_capability()); + #[cfg(not(feature = "continuation"))] + let slice_capabitlity = None; + + Ok(builder.build_circuit::(slice_capabitlity)) } pub fn new(k: u32, image: Vec, phantom_functions: Vec) -> Result { From 418274f5c6ded057bfc5c14a94aeb1fb8e864350 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Dec 2023 08:48:44 +0000 Subject: [PATCH 25/28] fix code style --- crates/zkwasm/src/circuits/etable/assign.rs | 4 +- crates/zkwasm/src/circuits/jtable/assign.rs | 11 ++-- crates/zkwasm/src/circuits/mtable/assign.rs | 53 ++++++++----------- crates/zkwasm/src/circuits/mtable/mod.rs | 10 ++-- .../zkwasm/src/circuits/utils/image_table.rs | 2 +- crates/zkwasm/src/loader/mod.rs | 2 +- 6 files changed, 34 insertions(+), 48 deletions(-) diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index 1685b1350..08f7237a8 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -219,7 +219,7 @@ impl EventTableChip { }) } - fn assign_post_initialization_state( + fn assign_padding_and_post_initialization_state( &self, ctx: &mut Context<'_, F>, initialization_state: &InitializationState, @@ -520,7 +520,7 @@ impl EventTableChip { )?; let post_initialization_state_cells = - self.assign_post_initialization_state(ctx, &post_initialization_state)?; + self.assign_padding_and_post_initialization_state(ctx, &post_initialization_state)?; cfg_if::cfg_if! { if #[cfg(feature = "continuation")] { diff --git a/crates/zkwasm/src/circuits/jtable/assign.rs b/crates/zkwasm/src/circuits/jtable/assign.rs index 49ddb26f1..3d007ff60 100644 --- a/crates/zkwasm/src/circuits/jtable/assign.rs +++ b/crates/zkwasm/src/circuits/jtable/assign.rs @@ -195,14 +195,9 @@ impl JumpTableChip { self.init(ctx)?; ctx.reset(); - // non-static entry includes `call`` and `return`` op - let mut rest_jops = jtable.entries().len() as u64 * 2; - // static entry only includes `return` op - for entry in static_entries { - if entry.enable { - rest_jops += 1; - } - } + // non-static entry includes `call`` and `return`` op, static entry only includes `return` op + let mut rest_jops = jtable.entries().len() as u64 * 2 + + static_entries.iter().filter(|entry| entry.enable).count() as u64; let frame_table_start_jump_cells = self.assign_static_entries(ctx, &mut rest_jops, static_entries)?; diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index 045e060c0..dc5e37d3a 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -41,8 +41,8 @@ impl MemoryTableChip { #[cfg(feature = "continuation")] ctx.region.assign_advice_from_constant( || "rest_memory_finalize_ops terminate", - self.config.rest_memory_finalize_ops.0.col, - ctx.offset + self.config.rest_memory_finalize_ops.0.rot as usize, + self.config.rest_memory_finalize_ops_cell.0.col, + ctx.offset + self.config.rest_memory_finalize_ops_cell.0.rot as usize, F::zero(), )?; } @@ -61,7 +61,7 @@ impl MemoryTableChip { ) -> Result, Error> { let cell = self .config - .rest_memory_finalize_ops + .rest_memory_finalize_ops_cell .assign(ctx, F::from(rest_memory_finalize_ops as u64))?; Ok(cell) @@ -171,7 +171,7 @@ impl MemoryTableChip { #[cfg(feature = "continuation")] assign_advice!( - rest_memory_finalize_ops, + rest_memory_finalize_ops_cell, F::from(_rest_memory_finalize_ops as u64) ); @@ -192,18 +192,12 @@ impl MemoryTableChip { rest_mops -= 1; } - if let Some(next_entry) = iter.peek() { - if entry.entry.atype == AccessType::Write - && !entry.entry.is_same_location(&next_entry.entry) - { - _rest_memory_finalize_ops -= 1; - } - } else { - // It's last entry - - if entry.entry.atype == AccessType::Write { - _rest_memory_finalize_ops -= 1; - } + if entry.entry.atype == AccessType::Write + && iter.peek().map_or(true, |next_entry| { + !next_entry.entry.is_same_location(&entry.entry) + }) + { + _rest_memory_finalize_ops -= 1; } ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); @@ -243,26 +237,22 @@ impl MemoryTableChip { Ok(()) } - fn compute_rest_memory_finalize_ops(&self, mtable: &MemoryWritingTable) -> u32 { - let mut ops = 0u32; + fn count_rest_memory_finalize_ops(&self, mtable: &MemoryWritingTable) -> u32 { + let mut count = 0u32; let mut iter = mtable.0.iter().peekable(); while let Some(entry) = iter.next() { - if let Some(next_entry) = iter.peek() { - if entry.entry.atype == AccessType::Write - && !entry.entry.is_same_location(&next_entry.entry) - { - ops += 1; - } - } else { - if entry.entry.atype == AccessType::Write { - ops += 1; - } + if entry.entry.atype == AccessType::Write + && iter.peek().map_or(true, |next_entry| { + !next_entry.entry.is_same_location(&entry.entry) + }) + { + count += 1; } } - ops + count } pub(crate) fn assign( @@ -282,7 +272,7 @@ impl MemoryTableChip { self.assign_fixed(ctx)?; ctx.reset(); - let rest_memory_finalize_ops = self.compute_rest_memory_finalize_ops(mtable); + let rest_memory_finalize_ops = self.count_rest_memory_finalize_ops(mtable); #[cfg(feature = "continuation")] let rest_memory_finalize_ops_cell = @@ -303,7 +293,8 @@ impl MemoryTableChip { if #[cfg(feature="continuation")] { Ok((Some(rest_memory_finalize_ops_cell), F::from(rest_memory_finalize_ops as u64))) } else { - Ok((None, F::from(rest_memory_finalize_ops as u64))) + // Useless rest_memory_finalize_ops if continuation is disabled + Ok((None, F::zero())) } } } diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index 92d46adeb..d3fc02683 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -55,7 +55,7 @@ pub struct MemoryTableConfig { init_encode_cell: AllocatedUnlimitedCell, #[cfg(feature = "continuation")] - rest_memory_finalize_ops: AllocatedUnlimitedCell, + rest_memory_finalize_ops_cell: AllocatedUnlimitedCell, value: AllocatedU64Cell, } @@ -98,7 +98,7 @@ impl MemoryTableConfig { let init_encode_cell = allocator.alloc_unlimited_cell(); #[cfg(feature = "continuation")] - let rest_memory_finalize_ops = { + let rest_memory_finalize_ops_cell = { let cell = allocator.alloc_unlimited_cell(); // FIXME: try to avoid this? meta.enable_equality(cell.0.col); @@ -318,8 +318,8 @@ impl MemoryTableConfig { { meta.create_gate("mc13. rest memory updating ops", |meta| { vec![ - rest_memory_finalize_ops.curr_expr(meta) - - rest_memory_finalize_ops.next_expr(meta) + rest_memory_finalize_ops_cell.curr_expr(meta) + - rest_memory_finalize_ops_cell.next_expr(meta) - (constant_from!(1) - is_next_same_offset_cell.curr_expr(meta)) * (constant_from!(1) - is_init_cell.curr_expr(meta)), ] @@ -354,7 +354,7 @@ impl MemoryTableConfig { encode_cell, #[cfg(feature = "continuation")] - rest_memory_finalize_ops, + rest_memory_finalize_ops_cell, } } } diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index e72fe1221..5f437cdda 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -49,7 +49,7 @@ impl InitMemoryLayouter { * Br Table * -------------------- * Padding - * -------------------- Init Memory Offset + * -------------------- Init Memory Offset(Constant) * Stack * -------------------- * Global diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index f5cc77ae9..ef36862ce 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -128,7 +128,7 @@ impl ZkWasmLoader { tables: Tables { compilation_tables: compiled_module.tables.clone(), execution_tables: ExecutionTable::default(), - post_image_table: compiled_module.tables, // FIXME: odd + post_image_table: compiled_module.tables, is_last_slice: last_slice_circuit, }, }; From e884de6ec78a2cab0cf586fc937a67b45230bedc Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Dec 2023 13:31:31 +0000 Subject: [PATCH 26/28] fix: fix a bug of post image table --- .../src/circuits/image_table/configure.rs | 6 +- crates/zkwasm/src/circuits/image_table/mod.rs | 3 +- crates/zkwasm/src/circuits/mod.rs | 9 ++- crates/zkwasm/src/circuits/mtable/assign.rs | 24 +++++--- crates/zkwasm/src/circuits/mtable/mod.rs | 21 +++++-- .../circuits/post_image_table/continuation.rs | 37 ++++++------ .../src/circuits/post_image_table/mod.rs | 57 ------------------- .../src/circuits/post_image_table/trivial.rs | 25 ++++---- .../zkwasm/src/circuits/test_circuit/mod.rs | 17 +++--- .../zkwasm/src/circuits/utils/image_table.rs | 29 ++++++++-- 10 files changed, 107 insertions(+), 121 deletions(-) delete mode 100644 crates/zkwasm/src/circuits/post_image_table/mod.rs diff --git a/crates/zkwasm/src/circuits/image_table/configure.rs b/crates/zkwasm/src/circuits/image_table/configure.rs index 14d5a880d..e0dcc107f 100644 --- a/crates/zkwasm/src/circuits/image_table/configure.rs +++ b/crates/zkwasm/src/circuits/image_table/configure.rs @@ -15,12 +15,12 @@ use crate::curr; impl ImageTableConfig { pub(in crate::circuits) fn configure( meta: &mut ConstraintSystem, - _memory_addr_sel: Column, + memory_addr_sel: Option>, ) -> Self { let col = meta.named_advice_column(IMAGE_COL_NAME.to_owned()); meta.enable_equality(col); Self { - _memory_addr_sel, + memory_addr_sel, col, _mark: PhantomData, } @@ -53,7 +53,7 @@ impl ImageTableConfig { let (addr, encode) = expr(meta); vec![ - (addr, fixed_curr!(meta, self._memory_addr_sel)), + (addr, fixed_curr!(meta, self.memory_addr_sel.unwrap())), ( ImageTableEncoder::InitMemory.encode(encode), curr!(meta, self.col), diff --git a/crates/zkwasm/src/circuits/image_table/mod.rs b/crates/zkwasm/src/circuits/image_table/mod.rs index d3c8fdb2d..5a793aca3 100644 --- a/crates/zkwasm/src/circuits/image_table/mod.rs +++ b/crates/zkwasm/src/circuits/image_table/mod.rs @@ -40,9 +40,10 @@ pub fn compute_maximal_pages(k: u32) -> u32 { bytes / PAGE_SIZE } +#[allow(dead_code)] #[derive(Clone)] pub struct ImageTableConfig { - _memory_addr_sel: Column, + memory_addr_sel: Option>, col: Column, _mark: PhantomData, } diff --git a/crates/zkwasm/src/circuits/mod.rs b/crates/zkwasm/src/circuits/mod.rs index dca24ab37..4a32f3932 100644 --- a/crates/zkwasm/src/circuits/mod.rs +++ b/crates/zkwasm/src/circuits/mod.rs @@ -16,10 +16,17 @@ mod external_host_call_table; mod mtable; mod traits; +#[cfg(feature = "continuation")] +#[path = "./post_image_table/continuation.rs"] +pub mod post_image_table; + +#[cfg(not(feature = "continuation"))] +#[path = "./post_image_table/trivial.rs"] +pub mod post_image_table; + pub mod config; pub mod image_table; pub mod jtable; -pub mod post_image_table; pub mod rtable; pub mod test_circuit; pub mod utils; diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index dc5e37d3a..c01d9e188 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::collections::HashSet; use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::AssignedCell; @@ -92,7 +93,7 @@ impl MemoryTableChip { mtable: &MemoryWritingTable, init_rest_mops: u64, mut _rest_memory_finalize_ops: u32, - ) -> Result<(), Error> { + ) -> Result, Error> { macro_rules! assign_advice { ($cell:ident, $value:expr) => { self.config.$cell.assign(ctx, $value)? @@ -129,6 +130,7 @@ impl MemoryTableChip { }; } + let mut memory_finalized_table = HashSet::new(); let mut rest_mops = init_rest_mops; let mut iter = mtable.0.iter().peekable(); @@ -198,6 +200,8 @@ impl MemoryTableChip { }) { _rest_memory_finalize_ops -= 1; + + memory_finalized_table.insert((entry.entry.ltype, entry.entry.offset)); } ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); @@ -234,7 +238,7 @@ impl MemoryTableChip { ctx.step(MEMORY_TABLE_ENTRY_ROWS as usize); } - Ok(()) + Ok(memory_finalized_table) } fn count_rest_memory_finalize_ops(&self, mtable: &MemoryWritingTable) -> u32 { @@ -260,7 +264,7 @@ impl MemoryTableChip { ctx: &mut Context<'_, F>, etable_rest_mops_cell: &Option>, mtable: &MemoryWritingTable, - ) -> Result<(Option>, F), Error> { + ) -> Result<(Option>, F, HashSet<(LocationType, u32)>), Error> { debug!("size of memory writing table: {}", mtable.0.len()); assert!(mtable.0.len() * (MEMORY_TABLE_ENTRY_ROWS as usize) < self.maximal_available_rows); @@ -284,17 +288,21 @@ impl MemoryTableChip { /* * Skip subsequent advice assignment in the first pass to enhance performance. */ - if rest_mops_cell.value().is_some() { - self.assign_entries(ctx, mtable, rest_mops, rest_memory_finalize_ops)?; + let _memory_finalized_set = if rest_mops_cell.value().is_some() { + let set = self.assign_entries(ctx, mtable, rest_mops, rest_memory_finalize_ops)?; ctx.reset(); - } + + set + } else { + HashSet::new() + }; cfg_if::cfg_if! { if #[cfg(feature="continuation")] { - Ok((Some(rest_memory_finalize_ops_cell), F::from(rest_memory_finalize_ops as u64))) + Ok((Some(rest_memory_finalize_ops_cell), F::from(rest_memory_finalize_ops as u64), _memory_finalized_set)) } else { // Useless rest_memory_finalize_ops if continuation is disabled - Ok((None, F::zero())) + Ok((None, F::zero(), HashSet::new())) } } } diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index d3fc02683..21ef2783a 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -13,8 +13,6 @@ use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::VirtualCells; -use specs::encode::image_table::ImageTableEncoder; -use specs::encode::init_memory_table::encode_init_memory_table_address; use specs::encode::init_memory_table::encode_init_memory_table_entry; use specs::encode::memory_table::encode_memory_table_entry; use specs::mtable::LocationType; @@ -227,6 +225,8 @@ impl MemoryTableConfig { image_table.init_memory_lookup(meta, "mc7c. imtable init", |meta| { cfg_if::cfg_if! { if #[cfg(feature = "continuation")] { + use specs::encode::init_memory_table::encode_init_memory_table_address; + ( encode_init_memory_table_address( is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) @@ -317,14 +317,21 @@ impl MemoryTableConfig { #[cfg(feature = "continuation")] { meta.create_gate("mc13. rest memory updating ops", |meta| { + let is_write = constant_from!(1) - is_init_cell.curr_expr(meta); + let next_entry_at_different_position = + constant_from!(1) - is_next_same_offset_cell.curr_expr(meta); + + let is_memory_finalized_position_bit = is_write * next_entry_at_different_position; + vec![ + // `* enabled_cell`: If disabled, rest_memory_finalize_ops_cell should keep the same, + // The termination rest_memory_finalize_ops_cell is constant 0 at the last selected(sel=1) step. rest_memory_finalize_ops_cell.curr_expr(meta) - rest_memory_finalize_ops_cell.next_expr(meta) - - (constant_from!(1) - is_next_same_offset_cell.curr_expr(meta)) - * (constant_from!(1) - is_init_cell.curr_expr(meta)), + - is_memory_finalized_position_bit * enabled_cell.curr_expr(meta), ] .into_iter() - .map(|x| x * enabled_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel)) + .map(|x| x * fixed_curr!(meta, entry_sel)) .collect::>() }); } @@ -391,6 +398,7 @@ impl ConfigureLookupTable for MemoryTableConfig { } } +#[cfg(feature = "continuation")] impl MemoryTableConfig { pub(in crate::circuits) fn configure_in_post_init_memory_table( &self, @@ -398,6 +406,9 @@ impl MemoryTableConfig { name: &'static str, expr: impl FnOnce(&mut VirtualCells<'_, F>) -> (Expression, Expression), ) { + use specs::encode::image_table::ImageTableEncoder; + use specs::encode::init_memory_table::encode_init_memory_table_address; + meta.lookup_any(name, |meta| { let (address, encode) = expr(meta); vec![ diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 3aaeaa4f4..2a0ff8df8 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::collections::HashSet; use std::marker::PhantomData; use std::rc::Rc; @@ -18,6 +19,7 @@ use specs::mtable::LocationType; use crate::circuits::image_table::ImageTableConfig; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::bn_to_field; +use crate::circuits::utils::image_table::image_table_offset_to_memory_location; use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::image_table::ImageTableLayouter; use crate::circuits::utils::image_table::GLOBAL_CAPABILITY; @@ -28,13 +30,10 @@ use crate::curr; use crate::fixed_curr; use crate::next; -use super::PostImageTableChipTrait; -use super::PostImageTableConfigTrait; - pub const POST_IMAGE_TABLE: &str = "post_img_col"; #[derive(Clone)] -pub(in crate::circuits) struct ContinuationPostImageTableConfig { +pub(in crate::circuits) struct PostImageTableConfig { memory_addr_sel: Column, post_image_table: Column, update: Column, @@ -42,13 +41,14 @@ pub(in crate::circuits) struct ContinuationPostImageTableConfig { _mark: PhantomData, } -impl PostImageTableConfigTrait for ContinuationPostImageTableConfig { - fn configure( +impl PostImageTableConfig { + pub(in crate::circuits) fn configure( meta: &mut ConstraintSystem, - memory_addr_sel: Column, + memory_addr_sel: Option>, memory_table: &MemoryTableConfig, pre_image_table: &ImageTableConfig, ) -> Self { + let memory_addr_sel = memory_addr_sel.unwrap(); let update = meta.advice_column(); let rest_memory_finalized_count = meta.advice_column(); let post_image_table = meta.named_advice_column(POST_IMAGE_TABLE.to_owned()); @@ -95,26 +95,24 @@ impl PostImageTableConfigTrait for ContinuationPostImageTableCon } } -pub(in crate::circuits) struct ContinuationPostImageTableChip { - config: ContinuationPostImageTableConfig, +pub(in crate::circuits) struct PostImageTableChip { + config: PostImageTableConfig, } -impl PostImageTableChipTrait> - for ContinuationPostImageTableChip -{ - fn new(config: ContinuationPostImageTableConfig) -> Self { +impl PostImageTableChip { + pub(in crate::circuits) fn new(config: PostImageTableConfig) -> Self { Self { config } } - fn assign( + pub(in crate::circuits) fn assign( self, layouter: &mut impl Layouter, image_table_assigner: &mut ImageTableAssigner, - pre_image_table: ImageTableLayouter, post_image_table: ImageTableLayouter, permutation_cells: ImageTableLayouter>, rest_memory_writing_ops_cell: Option>, rest_memory_writing_ops: F, + memory_finalized_set: HashSet<(LocationType, u32)>, ) -> Result<(), Error> { layouter.assign_region( || "post image table", @@ -319,11 +317,10 @@ impl PostImageTableChipTrait let mut rest_memory_writing_ops = rest_memory_writing_ops; - pre_image_table + post_image_table .init_memory_entries .iter() - .zip(post_image_table.init_memory_entries.iter()) - .map(|(pre, post)| { + .map(|post| { let entry = ctx.borrow_mut().region.assign_advice( || "post image table: init memory", self.config.post_image_table, @@ -338,7 +335,9 @@ impl PostImageTableChipTrait || Ok(rest_memory_writing_ops), )?; - if pre != post { + let position = image_table_offset_to_memory_location(offset); + + if memory_finalized_set.contains(&position) { ctx.borrow_mut().region.assign_advice( || "post image table: init memory", self.config.update, diff --git a/crates/zkwasm/src/circuits/post_image_table/mod.rs b/crates/zkwasm/src/circuits/post_image_table/mod.rs deleted file mode 100644 index e444451c9..000000000 --- a/crates/zkwasm/src/circuits/post_image_table/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use halo2_proofs::arithmetic::FieldExt; -use halo2_proofs::circuit::AssignedCell; -use halo2_proofs::circuit::Layouter; -use halo2_proofs::plonk::Column; -use halo2_proofs::plonk::ConstraintSystem; -use halo2_proofs::plonk::Error; -use halo2_proofs::plonk::Fixed; - -use super::image_table::ImageTableConfig; -use super::mtable::MemoryTableConfig; -use super::utils::image_table::ImageTableAssigner; -use super::utils::image_table::ImageTableLayouter; - -pub(self) mod continuation; -pub(self) mod trivial; - -pub(in crate::circuits) trait PostImageTableConfigTrait { - fn configure( - _meta: &mut ConstraintSystem, - _memory_addr_sel: Column, - _memory_table: &MemoryTableConfig, - _pre_image_table: &ImageTableConfig, - ) -> Self; -} - -pub(in crate::circuits) trait PostImageTableChipTrait< - F: FieldExt, - Config: PostImageTableConfigTrait, -> -{ - fn new(config: Config) -> Self; - fn assign( - self, - layouter: &mut impl Layouter, - image_table_assigner: &mut ImageTableAssigner, - pre_image_table: ImageTableLayouter, - post_image_table: ImageTableLayouter, - permutation_cells: ImageTableLayouter>, - rest_memory_writing_ops_cell: Option>, - rest_memory_writing_ops: F, - ) -> Result<(), Error>; -} - -cfg_if::cfg_if! { - if #[cfg(feature = "continuation")] { - use self::continuation::*; - - pub(in crate::circuits) type PostImageTableConfig = ContinuationPostImageTableConfig; - pub(in crate::circuits) type PostImageTableChip = ContinuationPostImageTableChip; - - } else { - use self::trivial::*; - - pub(in crate::circuits) type PostImageTableConfig = TrivialPostImageTableConfig; - pub(in crate::circuits) type PostImageTableChip = TrivialPostImageTableChip; - } -} diff --git a/crates/zkwasm/src/circuits/post_image_table/trivial.rs b/crates/zkwasm/src/circuits/post_image_table/trivial.rs index d73416d45..7be976129 100644 --- a/crates/zkwasm/src/circuits/post_image_table/trivial.rs +++ b/crates/zkwasm/src/circuits/post_image_table/trivial.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::marker::PhantomData; use halo2_proofs::arithmetic::FieldExt; @@ -7,24 +8,22 @@ use halo2_proofs::plonk::Column; use halo2_proofs::plonk::ConstraintSystem; use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; +use specs::mtable::LocationType; use crate::circuits::image_table::ImageTableConfig; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::utils::image_table::ImageTableAssigner; use crate::circuits::utils::image_table::ImageTableLayouter; -use super::PostImageTableChipTrait; -use super::PostImageTableConfigTrait; - #[derive(Clone)] -pub(in crate::circuits) struct TrivialPostImageTableConfig { +pub(in crate::circuits) struct PostImageTableConfig { _mark: PhantomData, } -impl PostImageTableConfigTrait for TrivialPostImageTableConfig { - fn configure( +impl PostImageTableConfig { + pub(in crate::circuits) fn configure( _meta: &mut ConstraintSystem, - _memory_addr_sel: Column, + _memory_addr_sel: Option>, _memory_table: &MemoryTableConfig, _pre_image_table: &ImageTableConfig, ) -> Self { @@ -32,26 +31,24 @@ impl PostImageTableConfigTrait for TrivialPostImageTableConfig { +pub(in crate::circuits) struct PostImageTableChip { _mark: PhantomData, } -impl PostImageTableChipTrait> - for TrivialPostImageTableChip -{ - fn new(_config: TrivialPostImageTableConfig) -> Self { +impl PostImageTableChip { + pub(in crate::circuits) fn new(_config: PostImageTableConfig) -> Self { Self { _mark: PhantomData } } - fn assign( + pub(in crate::circuits) fn assign( self, _layouter: &mut impl Layouter, _image_table_assigner: &mut ImageTableAssigner, - _pre_image_table: ImageTableLayouter, _post_image_table: ImageTableLayouter, _permutation_cells: ImageTableLayouter>, _rest_memory_writing_ops_cell: Option>, _rest_memory_writing_ops: F, + _memory_finalized_set: HashSet<(LocationType, u32)>, ) -> Result<(), Error> { Ok(()) } diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index 87e8ab7de..a1bbd9dda 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -28,8 +28,6 @@ use crate::circuits::jtable::JumpTableConfig; use crate::circuits::mtable::MemoryTableChip; use crate::circuits::mtable::MemoryTableConfig; use crate::circuits::post_image_table::PostImageTableChip; -use crate::circuits::post_image_table::PostImageTableChipTrait; -use crate::circuits::post_image_table::PostImageTableConfigTrait; use crate::circuits::rtable::RangeTableChip; use crate::circuits::rtable::RangeTableConfig; use crate::circuits::utils::image_table::EncodeCompilationTableValues; @@ -108,7 +106,12 @@ impl Circuit for TestCircuit { meta.enable_constant(constants); meta.enable_equality(constants); } - let memory_addr_sel = meta.fixed_column(); + + let memory_addr_sel = if cfg!(feature = "continuation") { + Some(meta.fixed_column()) + } else { + None + }; let foreign_table_from_zero_index = meta.fixed_column(); @@ -235,7 +238,7 @@ impl Circuit for TestCircuit { let ( etable_permutation_cells, - (rest_memory_writing_ops_cell, rest_memory_writing_ops), + (rest_memory_writing_ops_cell, rest_memory_writing_ops, memory_finalized_set), static_frame_entries, ) = layouter.assign_region( || "jtable mtable etable", @@ -346,9 +349,6 @@ impl Circuit for TestCircuit { post_image_chip.assign( &mut layouter, &mut image_table_assigner, - self.tables - .compilation_tables - .encode_compilation_table_values(config.circuit_maximal_pages), self.tables .post_image_table .encode_compilation_table_values(config.circuit_maximal_pages), @@ -361,7 +361,8 @@ impl Circuit for TestCircuit { init_memory_entries: pre_image_table_cells.init_memory_entries, }, rest_memory_writing_ops_cell, - rest_memory_writing_ops + rest_memory_writing_ops, + memory_finalized_set )? ); diff --git a/crates/zkwasm/src/circuits/utils/image_table.rs b/crates/zkwasm/src/circuits/utils/image_table.rs index 5f437cdda..c6f63a97c 100644 --- a/crates/zkwasm/src/circuits/utils/image_table.rs +++ b/crates/zkwasm/src/circuits/utils/image_table.rs @@ -38,6 +38,24 @@ impl InitMemoryLayouter { } } +pub fn image_table_offset_to_memory_location(offset: usize) -> (LocationType, u32) { + // Minus one for default lookup entry. + let mut offset = offset - INIT_MEMORY_ENTRIES_OFFSET - 1; + + if offset < STACK_CAPABILITY { + return (LocationType::Stack, offset as u32); + } + + offset -= STACK_CAPABILITY; + + if offset < GLOBAL_CAPABILITY { + return (LocationType::Global, offset as u32); + } + + offset -= GLOBAL_CAPABILITY; + return (LocationType::Heap, offset as u32); +} + /* * -------------------- * Initialization State @@ -49,7 +67,7 @@ impl InitMemoryLayouter { * Br Table * -------------------- * Padding - * -------------------- Init Memory Offset(Constant) + * -------------------- Init Memory Offset(Constant INIT_MEMORY_ENTRIES_OFFSET) * Stack * -------------------- * Global @@ -57,8 +75,7 @@ impl InitMemoryLayouter { * Heap * -------------------- */ -#[allow(dead_code)] -pub(crate) struct ImageTableLayouter { +pub struct ImageTableLayouter { pub(crate) initialization_state: InitializationState, pub(crate) static_frame_entries: [(T, T); STATIC_FRAME_ENTRY_NUMBER], pub(crate) instructions: Vec, @@ -68,8 +85,8 @@ pub(crate) struct ImageTableLayouter { pub(crate) init_memory_entries: Vec, } -pub(crate) struct ImageTableAssigner { - pub(crate) heap_capability: u32, +pub struct ImageTableAssigner { + pub heap_capability: u32, initialization_state_offset: usize, static_frame_entries_offset: usize, @@ -80,6 +97,8 @@ pub(crate) struct ImageTableAssigner { } impl ImageTableAssigner { + /// `instruction_number` and `br_table_number` came from wasm image. Instructions, br table entries and paddings + /// are compacted within a fixed range. `page_capability` is computed based on K. pub fn new(instruction_number: usize, br_table_number: usize, pages_capability: u32) -> Self { let initialization_state_offset = 0; let static_frame_entries_offset = From 11a01cc027ea9915e75aec7c6d3a52450905e217 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 21 Dec 2023 07:40:41 +0000 Subject: [PATCH 27/28] refine etable assignment --- crates/zkwasm/src/circuits/etable/assign.rs | 317 +++++++------------- 1 file changed, 106 insertions(+), 211 deletions(-) diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index 08f7237a8..2a428bf2a 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -62,6 +62,84 @@ pub(in crate::circuits) struct EventTablePermutationCells { } impl EventTableChip { + fn assign_step_state( + &self, + ctx: &mut Context<'_, F>, + 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)? + }; + } + } else { + macro_rules! assign_u32_state { + ($cell:ident, $value:expr) => { + self.config.common_config.$cell.assign_u32(ctx, $value)? + }; + } + } + } + + macro_rules! assign_common_range_advice { + ($cell:ident, $value:expr) => { + self.config + .common_config + .$cell + .assign(ctx, F::from($value as u64))? + }; + } + + let eid = assign_u32_state!(eid_cell, state.eid); + let fid = assign_common_range_advice!(fid_cell, state.fid); + let iid = assign_common_range_advice!(iid_cell, state.iid); + let sp = assign_common_range_advice!(sp_cell, state.sp); + let frame_id = assign_u32_state!(frame_id_cell, state.frame_id); + + let host_public_inputs = + assign_common_range_advice!(input_index_cell, state.host_public_inputs); + let context_in_index = + assign_common_range_advice!(context_input_index_cell, state.context_in_index); + let context_out_index = + assign_common_range_advice!(context_output_index_cell, state.context_out_index); + let external_host_call_call_index = assign_common_range_advice!( + external_host_call_index_cell, + state.external_host_call_call_index + ); + + let initial_memory_pages = + assign_common_range_advice!(mpages_cell, state.initial_memory_pages); + let maximal_memory_pages = + assign_common_range_advice!(maximal_memory_pages_cell, state.maximal_memory_pages); + + #[cfg(feature = "continuation")] + let jops = assign_common_range_advice!(jops_cell, state.jops); + + // The context will be stepped by EVENT_TABLE_ENTRY_ROWS. + ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); + + 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 compute_rest_mops_and_jops( &self, op_configs: &BTreeMap>>>, @@ -138,184 +216,16 @@ impl EventTableChip { Ok((rest_mops_cell, rest_jops_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)? - } - } - } 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))? - }; - } - - 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_padding_and_post_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)? - }; - } - } else { - macro_rules! assign_u32_state { - ($cell:ident, $value:expr) => { - self.config.common_config.$cell.assign_u32(ctx, $value)? - }; - } - } - } - - macro_rules! assign_common_range_advice { - ($cell:ident, $value:expr) => { - self.config - .common_config - .$cell - .assign(ctx, F::from($value as u64))? - }; - } - - macro_rules! assign_one_step { - () => {{ - 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); - - 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, - } - }}; - } - while ctx.offset < self.capability * EVENT_TABLE_ENTRY_ROWS as usize { - assign_one_step!(); - - ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); + self.assign_step_state(ctx, initialization_state)?; } - let post_initialization_state = assign_one_step!(); - - Ok(post_initialization_state) + self.assign_step_state(ctx, initialization_state) } fn assign_entries( @@ -341,22 +251,6 @@ impl EventTableChip { }; } - 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)) - }; - } - } - ); - 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; @@ -427,34 +321,37 @@ impl EventTableChip { assign_advice!(enabled_cell, F::one()); 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)); - assign_advice!( - external_host_call_index_cell, - F::from(external_host_call_call_index as u64) - ); - assign_advice!(sp_cell, F::from(entry.eentry.sp as u64)); - assign_advice!( - mpages_cell, - F::from(entry.eentry.allocated_memory_pages as u64) - ); - assign_advice!( - maximal_memory_pages_cell, - F::from(configure_table.maximal_memory_pages as u64) - ); - 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())); + assign_advice!(jops_cell, F::from(jops as u64)); let op_config = op_configs .get(&((&entry.eentry.inst.opcode).into())) .unwrap(); op_config.assign(ctx, &step_status, &entry)?; + // Be careful, the function will step context. + self.assign_step_state( + ctx, + &InitializationState { + eid: entry.eentry.eid, + fid: entry.eentry.inst.fid, + iid: entry.eentry.inst.iid, + sp: entry.eentry.sp, + frame_id: entry.eentry.last_jump_eid, + + host_public_inputs, + context_in_index, + context_out_index, + external_host_call_call_index, + + initial_memory_pages: entry.eentry.allocated_memory_pages, + maximal_memory_pages: configure_table.maximal_memory_pages, + + #[cfg(feature = "continuation")] + jops, + }, + )?; + if op_config.is_host_public_input(&entry.eentry) { host_public_inputs += 1; } @@ -474,8 +371,6 @@ impl EventTableChip { } else { jops -= op_config.jops() } - - ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); } Ok(()) @@ -505,8 +400,8 @@ impl EventTableChip { initialization_state, ); - let pre_initialization_state_cells = - self.assign_initialization_state(ctx, &initialization_state)?; + let pre_initialization_state_cells = self.assign_step_state(ctx, &initialization_state)?; + ctx.reset(); self.assign_entries( ctx, From f933ea84001af05e2cb3f477b672f2556b4fe1ff Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 22 Dec 2023 09:10:09 +0000 Subject: [PATCH 28/28] decrease the degree of post init memory lookup --- crates/specs/src/encode/init_memory_table.rs | 2 + .../zkwasm/src/circuits/mtable/allocator.rs | 2 +- crates/zkwasm/src/circuits/mtable/assign.rs | 64 ++++++++-- crates/zkwasm/src/circuits/mtable/mod.rs | 115 ++++++++++-------- .../circuits/post_image_table/continuation.rs | 34 +++++- .../zkwasm/src/circuits/test_circuit/mod.rs | 2 +- 6 files changed, 151 insertions(+), 68 deletions(-) diff --git a/crates/specs/src/encode/init_memory_table.rs b/crates/specs/src/encode/init_memory_table.rs index 56a8e8e25..8430e599e 100644 --- a/crates/specs/src/encode/init_memory_table.rs +++ b/crates/specs/src/encode/init_memory_table.rs @@ -5,6 +5,7 @@ use super::FromBn; use crate::imtable::InitMemoryTableEntry; pub(crate) const INIT_MEMORY_ENCODE_BOUNDARY: u32 = 224; +pub const MEMORY_ADDRESS_OFFSET: u32 = 97; pub fn encode_init_memory_table_address(location_type: T, offset: T) -> T { location_type * T::from_bn(&(1u64.to_biguint().unwrap() << 32)) + offset @@ -23,6 +24,7 @@ pub fn encode_init_memory_table_entry( const EID_OFFSET_SHIFT: u32 = VALUE_SHIFT + u64::BITS; const VALUE_SHIFT: u32 = 0; + assert_eq!(OFFSET_SHIFT, MEMORY_ADDRESS_OFFSET); assert!(LTYPE_SHIFT + 8 <= INIT_MEMORY_ENCODE_BOUNDARY); let encode = is_mutable * T::from_bn(&(1u64.to_biguint().unwrap() << IS_MUTABLE_SHIFT)) diff --git a/crates/zkwasm/src/circuits/mtable/allocator.rs b/crates/zkwasm/src/circuits/mtable/allocator.rs index d643f75e9..c03c47991 100644 --- a/crates/zkwasm/src/circuits/mtable/allocator.rs +++ b/crates/zkwasm/src/circuits/mtable/allocator.rs @@ -84,7 +84,7 @@ pub(super) enum MemoryTableCellType { const BIT_COLUMNS: usize = 3; const U16_COLUMNS: usize = U32_CELLS.next_multiple_of(2) / 2 + U64_CELLS; const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 1 } else { 2 }; -const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 3 } else { 2 }; +const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 2 }; const U32_CELLS: usize = if cfg!(feature = "continuation") { 5 } else { 2 }; const U64_CELLS: usize = 1; diff --git a/crates/zkwasm/src/circuits/mtable/assign.rs b/crates/zkwasm/src/circuits/mtable/assign.rs index c01d9e188..daa6a79a4 100644 --- a/crates/zkwasm/src/circuits/mtable/assign.rs +++ b/crates/zkwasm/src/circuits/mtable/assign.rs @@ -134,6 +134,7 @@ impl MemoryTableChip { let mut rest_mops = init_rest_mops; let mut iter = mtable.0.iter().peekable(); + let mut current_address_init_encode = None; while let Some(entry) = iter.next() { assign_bit!(enabled_cell); @@ -153,17 +154,26 @@ impl MemoryTableChip { assign_bit_if!(entry.entry.atype.is_init(), is_init_cell); - assign_advice!( - init_encode_cell, - bn_to_field(&encode_init_memory_table_entry( + if entry.entry.atype.is_init() { + current_address_init_encode = Some(bn_to_field(&encode_init_memory_table_entry( (entry.entry.ltype as u64).into(), entry.entry.offset.into(), (entry.entry.is_mutable as u64).into(), entry.entry.eid.into(), - entry.entry.value.into() - )) + entry.entry.value.into(), + ))); + } + assign_advice!( + init_encode_cell, + current_address_init_encode.unwrap_or(F::zero()) ); + if let Some(next_entry) = iter.peek() { + if !next_entry.entry.is_same_location(&entry.entry) { + current_address_init_encode = None; + } + } + 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); @@ -172,10 +182,22 @@ impl MemoryTableChip { assign_advice!(value, entry.entry.value); #[cfg(feature = "continuation")] - assign_advice!( - rest_memory_finalize_ops_cell, - F::from(_rest_memory_finalize_ops as u64) - ); + { + use specs::encode::init_memory_table::encode_init_memory_table_address; + + assign_advice!( + rest_memory_finalize_ops_cell, + F::from(_rest_memory_finalize_ops as u64) + ); + + assign_advice!( + address_encode_cell, + bn_to_field(&encode_init_memory_table_address( + (entry.entry.ltype as u64).into(), + entry.entry.offset.into() + )) + ); + } assign_advice!( encode_cell, @@ -202,6 +224,30 @@ impl MemoryTableChip { _rest_memory_finalize_ops -= 1; memory_finalized_table.insert((entry.entry.ltype, entry.entry.offset)); + + #[cfg(feature = "continuation")] + { + use num_bigint::BigUint; + use specs::encode::init_memory_table::encode_init_memory_table_address; + use specs::encode::init_memory_table::MEMORY_ADDRESS_OFFSET; + + assign_advice!( + post_init_encode_cell, + bn_to_field( + &((encode_init_memory_table_address::( + (entry.entry.ltype as u64).into(), + entry.entry.offset.into() + )) * MEMORY_ADDRESS_OFFSET + + (encode_init_memory_table_entry::( + (entry.entry.ltype as u64).into(), + entry.entry.offset.into(), + (entry.entry.is_mutable as u64).into(), + entry.entry.eid.into(), + entry.entry.value.into() + ))) + ) + ); + } } 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 21ef2783a..3509d1541 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -52,6 +52,10 @@ pub struct MemoryTableConfig { encode_cell: AllocatedUnlimitedCell, init_encode_cell: AllocatedUnlimitedCell, + #[cfg(feature = "continuation")] + address_encode_cell: AllocatedUnlimitedCell, + #[cfg(feature = "continuation")] + post_init_encode_cell: AllocatedUnlimitedCell, #[cfg(feature = "continuation")] rest_memory_finalize_ops_cell: AllocatedUnlimitedCell, @@ -95,6 +99,11 @@ impl MemoryTableConfig { let encode_cell = allocator.alloc_unlimited_cell(); let init_encode_cell = allocator.alloc_unlimited_cell(); + #[cfg(feature = "continuation")] + let post_init_encode_cell = allocator.alloc_unlimited_cell(); + #[cfg(feature = "continuation")] + let address_encode_cell = allocator.alloc_unlimited_cell(); + #[cfg(feature = "continuation")] let rest_memory_finalize_ops_cell = { let cell = allocator.alloc_unlimited_cell(); @@ -105,6 +114,13 @@ impl MemoryTableConfig { let value = allocator.alloc_u64_cell(); + macro_rules! location { + ($meta:expr) => { + is_stack_cell.curr_expr($meta) * constant_from!(LocationType::Stack as u64) + + is_global_cell.curr_expr($meta) * constant_from!(LocationType::Global as u64) + + is_heap_cell.curr_expr($meta) * constant_from!(LocationType::Heap) + }; + } meta.create_gate("mc1. enable seq", |meta| { vec![ (enabled_cell.curr_expr(meta) - constant_from!(1)) @@ -206,16 +222,14 @@ impl MemoryTableConfig { meta.create_gate("mc7b. init encode.", |meta| { vec![ - encode_init_memory_table_entry( - is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) - + is_heap_cell.curr_expr(meta) * constant_from!(LocationType::Heap as u64) - + is_global_cell.curr_expr(meta) - * constant_from!(LocationType::Global as u64), + (encode_init_memory_table_entry( + location!(meta), offset_cell.curr_expr(meta), is_mutable.curr_expr(meta), start_eid_cell.curr_expr(meta), value.u64_cell.curr_expr(meta), - ) - init_encode_cell.curr_expr(meta), + ) - init_encode_cell.curr_expr(meta)) + * is_init_cell.curr_expr(meta), ] .into_iter() .map(|x| x * fixed_curr!(meta, entry_sel)) @@ -225,21 +239,12 @@ impl MemoryTableConfig { image_table.init_memory_lookup(meta, "mc7c. imtable init", |meta| { cfg_if::cfg_if! { if #[cfg(feature = "continuation")] { - use specs::encode::init_memory_table::encode_init_memory_table_address; - ( - encode_init_memory_table_address( - is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) - + is_heap_cell.curr_expr(meta) - * constant_from!(LocationType::Heap as u64) - + is_global_cell.curr_expr(meta) - * constant_from!(LocationType::Global as u64), - offset_cell.curr_expr(meta), - ) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta), - init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta), + address_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel), + init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel), ) } else { - init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) * is_init_cell.curr_expr(meta) + init_encode_cell.curr_expr(meta) * fixed_curr!(meta, entry_sel) } } }); @@ -302,10 +307,7 @@ impl MemoryTableConfig { (constant_from!(1) - enabled_cell.curr_expr(meta)) * encode_cell.curr_expr(meta), encode_memory_table_entry( offset_cell.curr_expr(meta), - is_stack_cell.curr_expr(meta) * constant_from!(LocationType::Stack as u64) - + is_global_cell.curr_expr(meta) - * constant_from!(LocationType::Global as u64) - + is_heap_cell.curr_expr(meta) * constant_from!(LocationType::Heap), + location!(meta), is_i32_cell.curr_expr(meta), ) - encode_cell.curr_expr(meta), ] @@ -316,19 +318,44 @@ impl MemoryTableConfig { #[cfg(feature = "continuation")] { - meta.create_gate("mc13. rest memory updating ops", |meta| { - let is_write = constant_from!(1) - is_init_cell.curr_expr(meta); + use specs::encode::init_memory_table::encode_init_memory_table_address; + use specs::encode::init_memory_table::MEMORY_ADDRESS_OFFSET; + + meta.create_gate("mc13. post init memory entry", |meta| { + let is_writing = constant_from!(1) - is_init_cell.curr_expr(meta); let next_entry_at_different_position = constant_from!(1) - is_next_same_offset_cell.curr_expr(meta); - let is_memory_finalized_position_bit = is_write * next_entry_at_different_position; + let is_memory_finalized_position_bit = + is_writing * next_entry_at_different_position; vec![ + // rest_memory_finalize_ops_cell decreases. // `* enabled_cell`: If disabled, rest_memory_finalize_ops_cell should keep the same, // The termination rest_memory_finalize_ops_cell is constant 0 at the last selected(sel=1) step. rest_memory_finalize_ops_cell.curr_expr(meta) - rest_memory_finalize_ops_cell.next_expr(meta) - - is_memory_finalized_position_bit * enabled_cell.curr_expr(meta), + - is_memory_finalized_position_bit.clone() * enabled_cell.curr_expr(meta), + // encode address_encode_cell. + (encode_init_memory_table_address( + location!(meta), + offset_cell.curr_expr(meta), + ) - address_encode_cell.curr_expr(meta)), + // post_init_encode_cell assigned iff at memory finalized position. + post_init_encode_cell.curr_expr(meta) + * (constant_from!(1) - is_memory_finalized_position_bit.clone()), + // encode post_init_encode_cell. + (post_init_encode_cell.curr_expr(meta) + - address_encode_cell.curr_expr(meta) + * constant_from!(MEMORY_ADDRESS_OFFSET) + - encode_init_memory_table_entry( + location!(meta), + offset_cell.curr_expr(meta), + is_mutable.curr_expr(meta), + start_eid_cell.curr_expr(meta), + value.u64_cell.curr_expr(meta), + )) + * is_memory_finalized_position_bit, ] .into_iter() .map(|x| x * fixed_curr!(meta, entry_sel)) @@ -360,6 +387,10 @@ impl MemoryTableConfig { init_encode_cell, encode_cell, + #[cfg(feature = "continuation")] + post_init_encode_cell, + #[cfg(feature = "continuation")] + address_encode_cell, #[cfg(feature = "continuation")] rest_memory_finalize_ops_cell, } @@ -404,35 +435,17 @@ impl MemoryTableConfig { &self, meta: &mut ConstraintSystem, name: &'static str, - expr: impl FnOnce(&mut VirtualCells<'_, F>) -> (Expression, Expression), + expr: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, ) { use specs::encode::image_table::ImageTableEncoder; - use specs::encode::init_memory_table::encode_init_memory_table_address; meta.lookup_any(name, |meta| { - let (address, encode) = expr(meta); - vec![ - ( - address, - // FIXME: Add a bit cell to indicate finalized state - encode_init_memory_table_address( - self.is_stack_cell.expr(meta) - + self.is_heap_cell.expr(meta) * constant_from!(LocationType::Heap) - + self.is_global_cell.expr(meta) * constant_from!(LocationType::Global), - self.offset_cell.expr(meta), - ) * fixed_curr!(meta, self.entry_sel) - * (constant_from!(1) - self.is_init_cell.expr(meta)) - * (constant_from!(1) - self.is_next_same_offset_cell.expr(meta)), - ), - ( - encode, - // FIXME: Add a bit cell to indicate finalized state - ImageTableEncoder::InitMemory.encode(self.init_encode_cell.expr(meta)) - * fixed_curr!(meta, self.entry_sel) - * (constant_from!(1) - self.is_init_cell.expr(meta)) - * (constant_from!(1) - self.is_next_same_offset_cell.expr(meta)), - ), - ] + let encode = expr(meta); + vec![( + encode, + ImageTableEncoder::InitMemory.encode(self.post_init_encode_cell.expr(meta)) + * fixed_curr!(meta, self.entry_sel), + )] }); } } diff --git a/crates/zkwasm/src/circuits/post_image_table/continuation.rs b/crates/zkwasm/src/circuits/post_image_table/continuation.rs index 2a0ff8df8..2ad4dc9b0 100644 --- a/crates/zkwasm/src/circuits/post_image_table/continuation.rs +++ b/crates/zkwasm/src/circuits/post_image_table/continuation.rs @@ -13,6 +13,7 @@ use halo2_proofs::plonk::Error; use halo2_proofs::plonk::Fixed; use num_bigint::BigUint; use specs::encode::init_memory_table::encode_init_memory_table_address; +use specs::encode::init_memory_table::MEMORY_ADDRESS_OFFSET; use specs::jtable::STATIC_FRAME_ENTRY_NUMBER; use specs::mtable::LocationType; @@ -38,6 +39,7 @@ pub(in crate::circuits) struct PostImageTableConfig { post_image_table: Column, update: Column, rest_memory_finalized_count: Column, + memory_finalized_lookup_encode: Column, _mark: PhantomData, } @@ -52,6 +54,7 @@ impl PostImageTableConfig { let update = meta.advice_column(); let rest_memory_finalized_count = meta.advice_column(); let post_image_table = meta.named_advice_column(POST_IMAGE_TABLE.to_owned()); + let memory_finalized_lookup_encode = meta.advice_column(); meta.enable_equality(rest_memory_finalized_count); meta.enable_equality(post_image_table); @@ -74,15 +77,20 @@ impl PostImageTableConfig { ] }); + meta.create_gate("post image table: memory_finalized_lookup_encode", |meta| { + vec![ + fixed_curr!(meta, memory_addr_sel) + * curr!(meta, update) + * (fixed_curr!(meta, memory_addr_sel) * constant_from!(MEMORY_ADDRESS_OFFSET) + + curr!(meta, post_image_table) + - curr!(meta, memory_finalized_lookup_encode)), + ] + }); + memory_table.configure_in_post_init_memory_table( meta, "post image table: lookup updating value", - |meta| { - ( - fixed_curr!(meta, memory_addr_sel) * curr!(meta, update), - curr!(meta, post_image_table) * curr!(meta, update), - ) - }, + |meta| curr!(meta, memory_finalized_lookup_encode), ); Self { @@ -90,6 +98,7 @@ impl PostImageTableConfig { post_image_table, update, rest_memory_finalized_count, + memory_finalized_lookup_encode, _mark: PhantomData, } } @@ -345,6 +354,19 @@ impl PostImageTableChip { || Ok(F::one()), )?; + let address: BigUint = + encode_init_memory_table_address::( + (position.0 as u64).into(), + position.1.into(), + ) * MEMORY_ADDRESS_OFFSET; + + ctx.borrow_mut().region.assign_advice( + || "post image table: init memory lookup", + self.config.memory_finalized_lookup_encode, + offset, + || Ok(bn_to_field::(&address) + *post), + )?; + rest_memory_writing_ops = rest_memory_writing_ops - F::one(); } diff --git a/crates/zkwasm/src/circuits/test_circuit/mod.rs b/crates/zkwasm/src/circuits/test_circuit/mod.rs index a1bbd9dda..54e98fb9a 100644 --- a/crates/zkwasm/src/circuits/test_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/test_circuit/mod.rs @@ -53,7 +53,7 @@ use super::image_table::ImageTableConfig; use super::post_image_table::PostImageTableConfig; pub const VAR_COLUMNS: usize = if cfg!(feature = "continuation") { - 59 + 60 } else { 51 };