From 3a4e8c0e4a3d1887cdedb86a5542b94e52408215 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sun, 14 Apr 2024 05:24:02 +0000 Subject: [PATCH] refactor: free some unlimited cells related to u32 cells --- crates/zkwasm/src/circuits/cell.rs | 37 +++++++- .../zkwasm/src/circuits/etable/allocator.rs | 93 ++++++++++++------- crates/zkwasm/src/circuits/etable/assign.rs | 29 ------ crates/zkwasm/src/circuits/etable/mod.rs | 6 +- .../zkwasm/src/circuits/mtable/allocator.rs | 78 +++++++--------- crates/zkwasm/src/circuits/mtable/mod.rs | 6 +- crates/zkwasm/src/circuits/utils/mod.rs | 1 - .../src/circuits/utils/u32_state/mod.rs | 11 --- .../zkwasm/src/circuits/zkwasm_circuit/mod.rs | 4 +- test_cli.sh | 6 +- 10 files changed, 144 insertions(+), 127 deletions(-) delete mode 100644 crates/zkwasm/src/circuits/utils/u32_state/mod.rs diff --git a/crates/zkwasm/src/circuits/cell.rs b/crates/zkwasm/src/circuits/cell.rs index 56a42375b..62a038c0e 100644 --- a/crates/zkwasm/src/circuits/cell.rs +++ b/crates/zkwasm/src/circuits/cell.rs @@ -9,8 +9,10 @@ use halo2_proofs::plonk::Expression; use halo2_proofs::plonk::VirtualCells; use num_bigint::BigUint; +use crate::circuits::etable::EVENT_TABLE_ENTRY_ROWS; use crate::circuits::utils::bn_to_field; use crate::circuits::utils::Context; +use crate::constant_from; use crate::nextn; #[derive(Debug, Clone, Copy)] @@ -79,6 +81,11 @@ impl AllocatedU64Cell { #[derive(Debug, Clone, Copy)] pub(crate) struct AllocatedU32Cell { pub(crate) u16_cells_le: [AllocatedU16Cell; 2], +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct AllocatedU32PermutationCell { + pub(crate) u16_cells_le: [AllocatedU16Cell; 2], pub(crate) u32_cell: AllocatedUnlimitedCell, } @@ -160,13 +167,41 @@ impl CellExpression for AllocatedCommonRangeCell { impl AllocatedU32Cell { pub(crate) fn expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - self.u32_cell.curr_expr(meta) + self.u16_cells_le[0].curr_expr(meta) + + (self.u16_cells_le[1].curr_expr(meta) * constant_from!(1 << 16)) } pub(crate) fn curr_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { self.expr(meta) } + pub(crate) fn assign(&self, ctx: &mut Context<'_, F>, value: u32) -> Result<(), Error> { + for i in 0..2 { + self.u16_cells_le[i].assign(ctx, (((value >> (i * 16)) & 0xffffu32) as u64).into())?; + } + + Ok(()) + } +} + +#[allow(dead_code)] +impl AllocatedU32PermutationCell { + pub(crate) fn expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + self.curr_expr(meta) + } + + pub(crate) fn curr_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + self.u32_cell.expr(meta) + } + + pub(crate) fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { + nextn!( + meta, + self.u32_cell.cell.col, + self.u32_cell.cell.rot + EVENT_TABLE_ENTRY_ROWS + ) + } + pub(crate) fn assign( &self, ctx: &mut Context<'_, F>, diff --git a/crates/zkwasm/src/circuits/etable/allocator.rs b/crates/zkwasm/src/circuits/etable/allocator.rs index b49da2c1d..af43fac64 100644 --- a/crates/zkwasm/src/circuits/etable/allocator.rs +++ b/crates/zkwasm/src/circuits/etable/allocator.rs @@ -1,3 +1,4 @@ +use super::AllocatedU32StateCell; use super::EVENT_TABLE_ENTRY_ROWS; use crate::circuits::bit_table::BitTableOp; use crate::circuits::cell::*; @@ -9,7 +10,6 @@ use crate::circuits::traits::ConfigureLookupTable; use crate::circuits::utils::bit::BitColumn; use crate::circuits::utils::common_range::CommonRangeColumn; use crate::circuits::utils::u16::U16Column; -use crate::circuits::utils::u32_state::AllocatedU32StateCell; use crate::circuits::utils::u8::U8Column; use crate::circuits::Context; use crate::circuits::Lookup; @@ -66,24 +66,6 @@ impl_cell!(AllocatedCommonRangeCell); impl_cell!(AllocatedUnlimitedCell); impl_cell!(AllocatedJumpTableLookupCell); -impl EventTableCellExpression for AllocatedU32Cell { - fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - nextn!( - meta, - self.u32_cell.cell.col, - self.u32_cell.cell.rot + EVENT_TABLE_ENTRY_ROWS as i32 - ) - } - - fn prev_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - nextn!( - meta, - self.u32_cell.cell.col, - self.u32_cell.cell.rot - EVENT_TABLE_ENTRY_ROWS as i32 - ) - } -} - #[derive(Debug, Clone, Copy)] pub(crate) struct AllocatedJumpTableLookupCell { pub(crate) cell: AllocatedCell, @@ -184,18 +166,20 @@ pub(crate) enum EventTableCellType { const BIT_COLUMNS: usize = 12; const U8_COLUMNS: usize = 1; -const U32_CELLS: usize = if cfg!(feature = "continuation") { - 12 +const U32_CELLS: usize = 2; +const U32_PERMUTATION_CELLS: usize = if cfg!(feature = "continuation") { + 10 } else { - 2 + 0 }; const U64_CELLS: usize = 5; -const U16_COLUMNS: usize = U64_CELLS + (U32_CELLS / 2); +const U16_COLUMNS: usize = + U64_CELLS + ((U32_CELLS + U32_PERMUTATION_CELLS).next_multiple_of(2) / 2); const COMMON_RANGE_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 6 }; const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 10 } else { - 8 + 7 }; const MEMORY_TABLE_LOOKUP_COLUMNS: usize = 2; const JUMP_TABLE_LOOKUP_COLUMNS: usize = 1; @@ -229,6 +213,7 @@ impl AllocatedBitTableLookupCells { pub(crate) struct AllocatorFreeCellsProfiler { free_cells: BTreeMap, free_u32_cells: usize, + free_u32_permutation_cells: usize, free_u64_cells: usize, } @@ -237,6 +222,7 @@ impl AllocatorFreeCellsProfiler { Self { free_cells: allocator.free_cells.clone(), free_u32_cells: allocator.free_u32_cells.len(), + free_u32_permutation_cells: allocator.free_u32_permutation_cells.len(), free_u64_cells: allocator.free_u64_cells.len(), } } @@ -254,6 +240,10 @@ impl AllocatorFreeCellsProfiler { } self.free_u32_cells = usize::min(self.free_u32_cells, allocator.free_u32_cells.len()); + self.free_u32_permutation_cells = usize::min( + self.free_u32_permutation_cells, + allocator.free_u32_permutation_cells.len(), + ); self.free_u64_cells = usize::min(self.free_u64_cells, allocator.free_u64_cells.len()); } @@ -261,11 +251,29 @@ impl AllocatorFreeCellsProfiler { for (t, (i, j)) in &self.free_cells { let cols = allocator.all_cols.get(t).unwrap(); - assert!(*i == cols.len() || (*i == cols.len() - 1 && *j > 0)); + assert!( + *i == cols.len() || (*i == cols.len() - 1 && *j > 0), + "unused {:?} col should be removed: {}.", + t, + cols.len() - *i - (*j != 0) as usize + ); } - assert!(self.free_u32_cells == 0); - assert!(self.free_u64_cells == 0); + assert!( + self.free_u32_cells == 0, + "unused u32 cells should be removed: {:?}.", + self.free_u32_cells + ); + assert!( + self.free_u32_permutation_cells == 0, + "unused u32 permutation cells should be removed: {:?}.", + self.free_u32_permutation_cells + ); + assert!( + self.free_u64_cells == 0, + "unused u64 cells should be removed: {:?}.", + self.free_u64_cells + ); } } @@ -275,6 +283,7 @@ pub(crate) struct EventTableCellAllocator { pub(crate) free_cells: BTreeMap, all_cols: BTreeMap>>>, free_u32_cells: Vec>, + free_u32_permutation_cells: Vec>, free_u64_cells: Vec>, _mark: PhantomData, } @@ -293,11 +302,17 @@ impl EventTableCellAllocator { } } - pub(super) fn prepare_alloc_u32_cell( + pub(super) fn prepare_alloc_u32_cell(&mut self) -> AllocatedU32Cell { + let u16_cells_le = [0; 2].map(|_| self.alloc_u16_cell()); + + AllocatedU32Cell { u16_cells_le } + } + + pub(super) fn prepare_alloc_u32_permutation_cell( &mut self, meta: &mut ConstraintSystem, enable: impl Fn(&mut VirtualCells<'_, F>) -> Expression, - ) -> AllocatedU32Cell { + ) -> AllocatedU32PermutationCell { let u16_cells_le = [0; 2].map(|_| self.alloc_u16_cell()); let u32_cell = self.alloc_unlimited_cell(); meta.create_gate("c9. u32 decompose", |meta| { @@ -312,7 +327,7 @@ impl EventTableCellAllocator { }); meta.enable_equality(u32_cell.cell.col); - AllocatedU32Cell { + AllocatedU32PermutationCell { u16_cells_le, u32_cell, } @@ -352,9 +367,14 @@ impl EventTableCellAllocator { ) -> Self { let mut allocator = Self::_new(meta, k, sel, rtable, mtable, jtable, cols); for _ in 0..U32_CELLS { - let cell = allocator.prepare_alloc_u32_cell(meta, |meta| fixed_curr!(meta, sel)); + let cell = allocator.prepare_alloc_u32_cell(); allocator.free_u32_cells.push(cell); } + for _ in 0..U32_PERMUTATION_CELLS { + let cell = + allocator.prepare_alloc_u32_permutation_cell(meta, |meta| fixed_curr!(meta, sel)); + allocator.free_u32_permutation_cells.push(cell); + } for _ in 0..U64_CELLS { let cell = allocator.prepare_alloc_u64_cell(meta, |meta| fixed_curr!(meta, sel)); allocator.free_u64_cells.push(cell); @@ -462,6 +482,7 @@ impl EventTableCellAllocator { .into_iter(), ), free_u32_cells: vec![], + free_u32_permutation_cells: vec![], free_u64_cells: vec![], _mark: PhantomData, } @@ -522,7 +543,7 @@ impl EventTableCellAllocator { pub(crate) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { cfg_if::cfg_if! { if #[cfg(feature = "continuation")] { - self.alloc_u32_cell() + self.alloc_u32_permutation_cell() } else { self.alloc_common_range_cell() } @@ -731,11 +752,17 @@ impl EventTableCellAllocator { cell } - #[allow(dead_code)] pub(crate) fn alloc_u32_cell(&mut self) -> AllocatedU32Cell { self.free_u32_cells.pop().expect("no more free u32 cells") } + #[allow(dead_code)] + pub(crate) fn alloc_u32_permutation_cell(&mut self) -> AllocatedU32PermutationCell { + self.free_u32_permutation_cells + .pop() + .expect("no more free u32 permutation cells") + } + pub(crate) fn alloc_u64_cell(&mut self) -> AllocatedU64Cell { self.free_u64_cells.pop().expect("no more free u64 cells") } diff --git a/crates/zkwasm/src/circuits/etable/assign.rs b/crates/zkwasm/src/circuits/etable/assign.rs index db64f9976..98a382016 100644 --- a/crates/zkwasm/src/circuits/etable/assign.rs +++ b/crates/zkwasm/src/circuits/etable/assign.rs @@ -124,35 +124,6 @@ impl EventTableChip { #[cfg(feature = "continuation")] let jops = assign_common_range_advice!(jops_cell, state.jops); - // if let Some(assigned_pre_initialization_state) = assigned_pre_initialization_state { - // macro_rules! constrain_equal { - // ($field:ident) => { - // ctx.region.constrain_equal( - // $field.cell(), - // assigned_pre_initialization_state.$field.cell(), - // )?; - // }; - // } - - // constrain_equal!(eid); - // constrain_equal!(fid); - // constrain_equal!(iid); - // constrain_equal!(sp); - // constrain_equal!(frame_id); - - // constrain_equal!(host_public_inputs); - // constrain_equal!(context_in_index); - // constrain_equal!(context_out_index); - // constrain_equal!(external_host_call_call_index); - - // constrain_equal!(initial_memory_pages); - // constrain_equal!(maximal_memory_pages); - - // #[cfg(feature = "continuation")] - // constrain_equal!(jops); - // } - - // The context will be stepped by EVENT_TABLE_ENTRY_ROWS. ctx.step(EVENT_TABLE_ENTRY_ROWS as usize); Ok(InitializationState { diff --git a/crates/zkwasm/src/circuits/etable/mod.rs b/crates/zkwasm/src/circuits/etable/mod.rs index 2e7963a17..e521db43a 100644 --- a/crates/zkwasm/src/circuits/etable/mod.rs +++ b/crates/zkwasm/src/circuits/etable/mod.rs @@ -10,7 +10,6 @@ use super::rtable::RangeTableConfig; use super::traits::ConfigureLookupTable; use super::utils::step_status::StepStatus; use super::utils::table_entry::EventTableEntryWithMemoryInfo; -use super::utils::u32_state::AllocatedU32StateCell; use super::utils::Context; use crate::circuits::etable::op_configure::op_bin::BinConfigBuilder; use crate::circuits::etable::op_configure::op_bin_bit::BinBitConfigBuilder; @@ -68,6 +67,11 @@ mod op_configure; pub(crate) mod allocator; pub(crate) mod constraint_builder; +#[cfg(feature = "continuation")] +type AllocatedU32StateCell = AllocatedU32PermutationCell; +#[cfg(not(feature = "continuation"))] +type AllocatedU32StateCell = AllocatedCommonRangeCell; + pub(crate) const EVENT_TABLE_ENTRY_ROWS: i32 = 4; pub(crate) const OP_CAPABILITY: usize = 32; diff --git a/crates/zkwasm/src/circuits/mtable/allocator.rs b/crates/zkwasm/src/circuits/mtable/allocator.rs index 8ae446d37..deb4b723c 100644 --- a/crates/zkwasm/src/circuits/mtable/allocator.rs +++ b/crates/zkwasm/src/circuits/mtable/allocator.rs @@ -15,7 +15,6 @@ use crate::circuits::rtable::RangeTableConfig; use crate::circuits::utils::bit::BitColumn; use crate::circuits::utils::common_range::CommonRangeColumn; use crate::circuits::utils::u16::U16Column; -use crate::circuits::utils::u32_state::AllocatedU32StateCell; use crate::constant_from; use crate::fixed_curr; use crate::nextn; @@ -58,19 +57,12 @@ impl_cell!(AllocatedUnlimitedCell); impl MemoryTableCellExpression for AllocatedU32Cell { fn next_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - nextn!( - meta, - self.u32_cell.cell.col, - self.u32_cell.cell.rot + MEMORY_TABLE_ENTRY_ROWS as i32 - ) + self.u16_cells_le[0].next_expr(meta) + + (self.u16_cells_le[1].next_expr(meta) * constant_from!(1 << 16)) } - fn prev_expr(&self, meta: &mut VirtualCells<'_, F>) -> Expression { - nextn!( - meta, - self.u32_cell.cell.col, - self.u32_cell.cell.rot - MEMORY_TABLE_ENTRY_ROWS as i32 - ) + fn prev_expr(&self, _meta: &mut VirtualCells<'_, F>) -> Expression { + unimplemented!() } } @@ -85,7 +77,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 = 1; -const UNLIMITED_COLUMNS: usize = if cfg!(feature = "continuation") { 4 } else { 2 }; +const UNLIMITED_COLUMNS: usize = 2; const U32_CELLS: usize = if cfg!(feature = "continuation") { 5 } else { 2 }; const U64_CELLS: usize = 1; @@ -104,11 +96,24 @@ impl MemoryTableCellAllocator { for (t, (i, j)) in &self.free_cells { let cols = self.all_cols.get(t).unwrap(); - assert!(*i == cols.len() || (*i == cols.len() - 1 && *j > 0)); + assert!( + *i == cols.len() || (*i == cols.len() - 1 && *j > 0), + "unused {:?} col should be removed: {}.", + t, + cols.len() - *i - (*j != 0) as usize + ); } - assert!(self.free_u32_cells.is_empty()); - assert!(self.free_u64_cells.is_empty()); + assert!( + self.free_u32_cells.is_empty(), + "unused u32 cells should be removed: {:?}.", + self.free_u32_cells.len() + ); + assert!( + self.free_u64_cells.is_empty(), + "unused u64 cells should be removed: {:?}.", + self.free_u64_cells.len() + ); } pub fn enable_equality(&mut self, meta: &mut ConstraintSystem, t: &MemoryTableCellType) { @@ -117,27 +122,10 @@ impl MemoryTableCellAllocator { } } - pub(super) fn prepare_alloc_u32_cell( - &mut self, - meta: &mut ConstraintSystem, - enable: impl Fn(&mut VirtualCells<'_, F>) -> Expression, - ) -> AllocatedU32Cell { + pub(super) fn prepare_alloc_u32_cell(&mut self) -> AllocatedU32Cell { let u16_cells_le = [0; 2].map(|_| self.alloc_u16_cell()); - let u32_cell = self.alloc_unlimited_cell(); - meta.create_gate("mc9. value", |meta| { - let init = u32_cell.curr_expr(meta); - vec![ - (0..2) - .into_iter() - .map(|x| u16_cells_le[x].curr_expr(meta) * constant_from!(1u64 << (16 * x))) - .fold(init, |acc, x| acc - x) - * enable(meta), - ] - }); - AllocatedU32Cell { - u16_cells_le, - u32_cell, - } + + AllocatedU32Cell { u16_cells_le } } pub(super) fn prepare_alloc_u64_cell( @@ -172,7 +160,7 @@ impl MemoryTableCellAllocator { ) -> Self { let mut allocator = Self::_new(meta, k, sel.clone(), rtable, cols); for _ in 0..U32_CELLS { - let cell = allocator.prepare_alloc_u32_cell(meta, |meta| fixed_curr!(meta, sel)); + let cell = allocator.prepare_alloc_u32_cell(); allocator.free_u32_cells.push(cell); } for _ in 0..U64_CELLS { @@ -268,14 +256,14 @@ impl MemoryTableCellAllocator { } } - pub(super) fn alloc_u32_state_cell(&mut self) -> AllocatedU32StateCell { - cfg_if::cfg_if! { - if #[cfg(feature = "continuation")] { - self.alloc_u32_cell() - } else { - self.alloc_common_range_cell() - } - } + #[cfg(feature = "continuation")] + pub(super) fn alloc_u32_state_cell(&mut self) -> AllocatedU32Cell { + self.alloc_u32_cell() + } + + #[cfg(not(feature = "continuation"))] + pub(super) fn alloc_u32_state_cell(&mut self) -> AllocatedCommonRangeCell { + self.alloc_common_range_cell() } pub(super) fn alloc_u16_cell(&mut self) -> AllocatedU16Cell { diff --git a/crates/zkwasm/src/circuits/mtable/mod.rs b/crates/zkwasm/src/circuits/mtable/mod.rs index 2df156e59..9766ff030 100644 --- a/crates/zkwasm/src/circuits/mtable/mod.rs +++ b/crates/zkwasm/src/circuits/mtable/mod.rs @@ -3,7 +3,6 @@ use super::cell::*; use super::image_table::ImageTableConfig; use super::rtable::RangeTableConfig; use super::traits::ConfigureLookupTable; -use super::utils::u32_state::AllocatedU32StateCell; use crate::constant_from; use crate::fixed_curr; use halo2_proofs::arithmetic::FieldExt; @@ -24,6 +23,11 @@ pub(crate) mod utils; pub(crate) const MEMORY_TABLE_ENTRY_ROWS: i32 = 4; +#[cfg(feature = "continuation")] +type AllocatedU32StateCell = AllocatedU32Cell; +#[cfg(not(feature = "continuation"))] +type AllocatedU32StateCell = AllocatedCommonRangeCell; + #[derive(Clone)] pub struct MemoryTableConfig { entry_sel: Column, diff --git a/crates/zkwasm/src/circuits/utils/mod.rs b/crates/zkwasm/src/circuits/utils/mod.rs index 987c664e6..9b5b0899a 100644 --- a/crates/zkwasm/src/circuits/utils/mod.rs +++ b/crates/zkwasm/src/circuits/utils/mod.rs @@ -9,7 +9,6 @@ pub mod image_table; pub mod row_diff; pub mod step_status; pub mod u16; -pub mod u32_state; pub mod u8; pub mod table_entry; diff --git a/crates/zkwasm/src/circuits/utils/u32_state/mod.rs b/crates/zkwasm/src/circuits/utils/u32_state/mod.rs deleted file mode 100644 index 542bc3ead..000000000 --- a/crates/zkwasm/src/circuits/utils/u32_state/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -cfg_if::cfg_if! { - if #[cfg(feature = "continuation")] { - use crate::circuits::cell::AllocatedU32Cell; - - pub(crate) type AllocatedU32StateCell = AllocatedU32Cell; - } else { - use crate::circuits::cell::AllocatedCommonRangeCell; - - pub(crate) type AllocatedU32StateCell = AllocatedCommonRangeCell; - } -} diff --git a/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs b/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs index d222231a9..8f7667e9f 100644 --- a/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs +++ b/crates/zkwasm/src/circuits/zkwasm_circuit/mod.rs @@ -60,9 +60,9 @@ use super::image_table::ImageTableConfig; use super::post_image_table::PostImageTableConfig; pub const VAR_COLUMNS: usize = if cfg!(feature = "continuation") { - 60 + 58 } else { - 51 + 50 }; // Reserve a few rows to keep usable rows away from blind rows. diff --git a/test_cli.sh b/test_cli.sh index 30b0182b8..e2b9c64b4 100755 --- a/test_cli.sh +++ b/test_cli.sh @@ -9,7 +9,7 @@ CUDA="--features cuda" test_default_cli() { cargo build --release $CUDA - rm -rf params output + rm -rf params output/*.data output/*.json $CLI --params ./params wasm_output setup --wasm ./crates/zkwasm/wasm/wasm_output.wasm $CLI --params ./params wasm_output dry-run --wasm crates/zkwasm/wasm/wasm_output.wasm --public 133:i64 --public 2:i64 --output ./output $CLI --params ./params wasm_output prove --wasm crates/zkwasm/wasm/wasm_output.wasm --public 133:i64 --public 2:i64 --output ./output @@ -18,7 +18,7 @@ test_default_cli() { test_uniform_circuit_cli() { cargo build --release --features uniform-circuit $CUDA - rm -rf params output + rm -rf params output/*.data output/*.json $CLI --params ./params wasm_output setup $CLI --params ./params wasm_output dry-run --wasm crates/zkwasm/wasm/wasm_output.wasm --public 133:i64 --public 2:i64 --output ./output $CLI --params ./params wasm_output prove --wasm crates/zkwasm/wasm/wasm_output.wasm --public 133:i64 --public 2:i64 --output ./output @@ -27,7 +27,7 @@ test_uniform_circuit_cli() { test_continuation_cli() { cargo build --release --features continuation $CUDA - rm -rf params output + rm -rf params output/*.data output/*.json $CLI --params ./params fibonacci setup -k 22 $CLI --params ./params fibonacci dry-run --wasm crates/zkwasm/wasm/fibonacci.wasm --public 25:i64 --output ./output $CLI --params ./params fibonacci prove --wasm crates/zkwasm/wasm/fibonacci.wasm --public 25:i64 --output ./output