From 4684ab9309d75e013ffbd2fe6caddb94e25b6597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Wed, 8 Jan 2025 14:56:40 +0800 Subject: [PATCH 1/6] Less spam when running `e2e` (#815) This avoids spam like the following going on for thousands of lines: ``` INFO e2e: Running on platform Ceno Platform { rom: 536870912..538373056, prog_data: {536870912, [...] ``` --- ceno_emul/src/platform.rs | 23 ++++++++++++++++++++++- ceno_zkvm/src/bin/e2e.rs | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ceno_emul/src/platform.rs b/ceno_emul/src/platform.rs index e8b06721c..034340c54 100644 --- a/ceno_emul/src/platform.rs +++ b/ceno_emul/src/platform.rs @@ -1,4 +1,5 @@ -use std::{collections::BTreeSet, ops::Range}; +use core::fmt::{self, Formatter}; +use std::{collections::BTreeSet, fmt::Display, ops::Range}; use crate::addr::{Addr, RegIdx}; @@ -19,6 +20,26 @@ pub struct Platform { pub unsafe_ecall_nop: bool, } +impl Display for Platform { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let prog_data: Option> = match (self.prog_data.first(), self.prog_data.last()) { + (Some(first), Some(last)) => Some(*first..*last), + _ => None, + }; + write!( + f, + "Platform {{ rom: {:?}, prog_data: {:?}, stack: {:?}, heap: {:?}, public_io: {:?}, hints: {:?}, unsafe_ecall_nop: {} }}", + self.rom, + prog_data, + self.stack, + self.heap, + self.public_io, + self.hints, + self.unsafe_ecall_nop + ) + } +} + pub const CENO_PLATFORM: Platform = Platform { rom: 0x2000_0000..0x3000_0000, prog_data: BTreeSet::new(), diff --git a/ceno_zkvm/src/bin/e2e.rs b/ceno_zkvm/src/bin/e2e.rs index 5de9b3fab..f1da01d51 100644 --- a/ceno_zkvm/src/bin/e2e.rs +++ b/ceno_zkvm/src/bin/e2e.rs @@ -113,7 +113,7 @@ fn main() { args.heap_size, pub_io_size, ); - tracing::info!("Running on platform {:?} {:?}", args.platform, platform); + tracing::info!("Running on platform {:?} {}", args.platform, platform); tracing::info!( "Stack: {} bytes. Heap: {} bytes.", args.stack_size, From b60c6fe3dde3d4641630733a9023eb7a085ae047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Wed, 8 Jan 2025 15:06:05 +0800 Subject: [PATCH 2/6] Only complain about threads once (#816) This cuts down on logging spam. --- multilinear_extensions/src/util.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/multilinear_extensions/src/util.rs b/multilinear_extensions/src/util.rs index a0a8e56a2..230f187f4 100644 --- a/multilinear_extensions/src/util.rs +++ b/multilinear_extensions/src/util.rs @@ -40,11 +40,16 @@ pub fn max_usable_threads() -> usize { if cfg!(test) { 1 } else { - let n = rayon::current_num_threads(); - let threads = prev_power_of_two(n); - if n != threads { - tracing::warn!("thread size {n} is not power of 2, using {threads} threads instead."); - } - threads + static MAX_USABLE_THREADS: std::sync::OnceLock = std::sync::OnceLock::new(); + *MAX_USABLE_THREADS.get_or_init(|| { + let n = rayon::current_num_threads(); + let threads = prev_power_of_two(n); + if n != threads { + tracing::warn!( + "thread size {n} is not power of 2, using {threads} threads instead." + ); + } + threads + }) } } From dfce3af72cb043bb4f76ec447813e604680cbc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Thu, 9 Jan 2025 08:41:49 +0800 Subject: [PATCH 3/6] Log unused instructions, too (#817) It's useful to see which Risc-V instructions aren't used at all when running eg sproll-evm. --- ceno_zkvm/src/instructions/riscv/rv32im.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ceno_zkvm/src/instructions/riscv/rv32im.rs b/ceno_zkvm/src/instructions/riscv/rv32im.rs index 5d19255d7..fefb18ba5 100644 --- a/ceno_zkvm/src/instructions/riscv/rv32im.rs +++ b/ceno_zkvm/src/instructions/riscv/rv32im.rs @@ -29,12 +29,15 @@ use ceno_emul::{ }; use ecall::EcallDummy; use ff_ext::ExtensionField; -use itertools::Itertools; +use itertools::{Itertools, izip}; use mul::{MulInstruction, MulhInstruction, MulhsuInstruction}; use shift::SraInstruction; use slt::{SltInstruction, SltuInstruction}; use slti::SltiuInstruction; -use std::collections::{BTreeMap, BTreeSet}; +use std::{ + cmp::Reverse, + collections::{BTreeMap, BTreeSet}, +}; use strum::IntoEnumIterator; use super::{ @@ -337,14 +340,10 @@ impl Rv32imConfig { } }); - for (insn_kind, (_, records)) in InsnKind::iter() - .zip(all_records.iter()) - .sorted_by(|a, b| Ord::cmp(&a.1.1.len(), &b.1.1.len())) - .rev() + for (insn_kind, (_, records)) in + izip!(InsnKind::iter(), &all_records).sorted_by_key(|(_, (_, a))| Reverse(a.len())) { - if !records.is_empty() { - tracing::info!("tracer generated {:?} {} records", insn_kind, records.len()); - } + tracing::info!("tracer generated {:?} {} records", insn_kind, records.len()); } macro_rules! assign_opcode { From 2cf18531999f785dcb95da55bb9935bd5ea0ae0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Thu, 9 Jan 2025 18:51:20 +0800 Subject: [PATCH 4/6] Rename bubble sort to quadratic sort (#820) In preparation for https://github.com/scroll-tech/ceno/pull/813 Also stop hard-coding the examples in the examples-builder. --- Cargo.lock | 3 +++ ceno_host/tests/test_elf.rs | 2 +- examples-builder/Cargo.toml | 3 +++ examples-builder/build.rs | 24 ++++++------------- ...bubble_sorting.rs => quadratic_sorting.rs} | 0 5 files changed, 14 insertions(+), 18 deletions(-) rename examples/examples/{bubble_sorting.rs => quadratic_sorting.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index ef8dbb072..e5fc6dd4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -280,6 +280,9 @@ dependencies = [ [[package]] name = "ceno-examples" version = "0.1.0" +dependencies = [ + "glob", +] [[package]] name = "ceno_emul" diff --git a/ceno_host/tests/test_elf.rs b/ceno_host/tests/test_elf.rs index 6831ac9eb..39d132751 100644 --- a/ceno_host/tests/test_elf.rs +++ b/ceno_host/tests/test_elf.rs @@ -137,7 +137,7 @@ fn test_bubble_sorting() -> Result<()> { let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, - ceno_examples::bubble_sorting, + ceno_examples::quadratic_sorting, &hints, )); for msg in &all_messages { diff --git a/examples-builder/Cargo.toml b/examples-builder/Cargo.toml index 00104ec3c..5e0ae79d0 100644 --- a/examples-builder/Cargo.toml +++ b/examples-builder/Cargo.toml @@ -7,3 +7,6 @@ license.workspace = true name = "ceno-examples" repository.workspace = true version.workspace = true + +[build-dependencies] +glob = "0.3" diff --git a/examples-builder/build.rs b/examples-builder/build.rs index 10d79d4f3..20b49b8d1 100644 --- a/examples-builder/build.rs +++ b/examples-builder/build.rs @@ -1,3 +1,4 @@ +use glob::glob; use std::{ fs::{File, read_dir}, io::{self, Write}, @@ -5,22 +6,6 @@ use std::{ process::Command, }; -/// Add each example to this list. -/// -/// Contact Matthias, if your examples get complicated enough to need their own crates, instead of just being one file. -const EXAMPLES: &[&str] = &[ - "ceno_rt_alloc", - "ceno_rt_io", - "ceno_rt_mem", - "ceno_rt_mini", - "ceno_rt_panic", - "ceno_rt_keccak", - "hints", - "sorting", - "median", - "bubble_sorting", - "hashing", -]; const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); fn rerun_all_but_target(dir: &Path) { @@ -51,7 +36,12 @@ fn build_elfs() { io::stderr().write_all(&output.stderr).unwrap(); panic!("cargo build of examples failed."); } - for example in EXAMPLES { + // Contact Matthias, if your examples get complicated enough to need their own crates, instead of just being one file. + for example in glob("../examples/examples/*.rs") + .unwrap() + .map(Result::unwrap) + { + let example = example.file_stem().unwrap().to_str().unwrap(); writeln!( dest, r#"#[allow(non_upper_case_globals)] diff --git a/examples/examples/bubble_sorting.rs b/examples/examples/quadratic_sorting.rs similarity index 100% rename from examples/examples/bubble_sorting.rs rename to examples/examples/quadratic_sorting.rs From 083b2d47c4192b24572d280b8367cf1eeb5caa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Thu, 9 Jan 2025 19:02:40 +0800 Subject: [PATCH 5/6] Clean up 'hints' for guests (#821) Add the functionality to chain writes to the hints stream. --- ceno_host/src/lib.rs | 5 +-- ceno_host/tests/test_elf.rs | 61 +++++++++++++++---------------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/ceno_host/src/lib.rs b/ceno_host/src/lib.rs index d6cd94ea1..fe6765c27 100644 --- a/ceno_host/src/lib.rs +++ b/ceno_host/src/lib.rs @@ -120,14 +120,15 @@ impl From<&CenoStdin> for Vec { } impl CenoStdin { - pub fn write_slice(&mut self, bytes: AlignedVec) { + pub fn write_slice(&mut self, bytes: AlignedVec) -> &mut Self { self.items.push(bytes); + self } pub fn write( &mut self, item: &impl for<'a> Serialize, Error>>, - ) -> Result<(), Error> { + ) -> Result<&mut Self, Error> { to_bytes::(item).map(|bytes| self.write_slice(bytes)) } } diff --git a/ceno_host/tests/test_elf.rs b/ceno_host/tests/test_elf.rs index 39d132751..97fcd751b 100644 --- a/ceno_host/tests/test_elf.rs +++ b/ceno_host/tests/test_elf.rs @@ -7,6 +7,7 @@ use ceno_emul::{ }; use ceno_host::CenoStdin; use itertools::{Itertools, enumerate, izip}; +use rand::{Rng, thread_rng}; use tiny_keccak::keccakf; #[test] @@ -111,14 +112,15 @@ fn test_ceno_rt_io() -> Result<()> { #[test] fn test_hints() -> Result<()> { - let mut hints = CenoStdin::default(); - hints.write(&true)?; - hints.write(&"This is my hint string.".to_string())?; - hints.write(&1997_u32)?; - hints.write(&1999_u32)?; - - let all_messages = - messages_to_strings(&ceno_host::run(CENO_PLATFORM, ceno_examples::hints, &hints)); + let all_messages = messages_to_strings(&ceno_host::run( + CENO_PLATFORM, + ceno_examples::hints, + CenoStdin::default() + .write(&true)? + .write(&"This is my hint string.".to_string())? + .write(&1997_u32)? + .write(&1999_u32)?, + )); for (i, msg) in enumerate(&all_messages) { println!("{i}: {msg}"); } @@ -128,17 +130,12 @@ fn test_hints() -> Result<()> { #[test] fn test_bubble_sorting() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); - - // Provide some random numbers to sort. - hints.write(&(0..1_000).map(|_| rng.gen::()).collect::>())?; - + let mut rng = thread_rng(); let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, ceno_examples::quadratic_sorting, - &hints, + // Provide some random numbers to sort. + CenoStdin::default().write(&(0..1_000).map(|_| rng.gen::()).collect::>())?, )); for msg in &all_messages { print!("{msg}"); @@ -147,17 +144,12 @@ fn test_bubble_sorting() -> Result<()> { } #[test] fn test_sorting() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); - - // Provide some random numbers to sort. - hints.write(&(0..1000).map(|_| rng.gen::()).collect::>())?; - + let mut rng = thread_rng(); let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, ceno_examples::sorting, - &hints, + // Provide some random numbers to sort. + CenoStdin::default().write(&(0..1000).map(|_| rng.gen::()).collect::>())?, )); for (i, msg) in enumerate(&all_messages) { println!("{i}: {msg}"); @@ -167,9 +159,8 @@ fn test_sorting() -> Result<()> { #[test] fn test_median() -> Result<()> { - use rand::Rng; let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); // Provide some random numbers to find the median of. let mut nums = (0..1000).map(|_| rng.gen::()).collect::>(); @@ -192,23 +183,22 @@ fn test_median() -> Result<()> { #[test] #[should_panic(expected = "Trap IllegalInstruction")] fn test_hashing_fail() { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let mut nums = (0..1_000).map(|_| rng.gen::()).collect::>(); // Add a duplicate number to make uniqueness check fail: nums[211] = nums[907]; - hints.write(&nums).unwrap(); - let _ = ceno_host::run(CENO_PLATFORM, ceno_examples::hashing, &hints); + let _ = ceno_host::run( + CENO_PLATFORM, + ceno_examples::hashing, + CenoStdin::default().write(&nums).unwrap(), + ); } #[test] fn test_hashing() -> Result<()> { - use rand::Rng; - let mut hints = CenoStdin::default(); - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); // Provide some unique random numbers to verify: let uniques: Vec = { @@ -219,11 +209,10 @@ fn test_hashing() -> Result<()> { .collect::>() }; - hints.write(&uniques)?; let all_messages = messages_to_strings(&ceno_host::run( CENO_PLATFORM, ceno_examples::hashing, - &hints, + CenoStdin::default().write(&uniques)?, )); assert!(!all_messages.is_empty()); for (i, msg) in enumerate(&all_messages) { From 7919da29ff5b20d868c8ac4f74dcbab3fcc5739a Mon Sep 17 00:00:00 2001 From: even <35983442+10to4@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:39:23 +0800 Subject: [PATCH 6/6] Feat/skip fixed commit of range table (#797) Work for #789 --------- Co-authored-by: sm.wu --- ceno_zkvm/src/chip_handler/general.rs | 4 +- ceno_zkvm/src/circuit_builder.rs | 13 ++--- ceno_zkvm/src/scheme/mock_prover.rs | 10 ++-- ceno_zkvm/src/scheme/prover.rs | 9 ++-- ceno_zkvm/src/scheme/verifier.rs | 31 ++++++++---- ceno_zkvm/src/stats.rs | 2 +- ceno_zkvm/src/tables/ops/ops_impl.rs | 13 ++++- ceno_zkvm/src/tables/program.rs | 7 ++- ceno_zkvm/src/tables/range/range_circuit.rs | 18 ++++--- ceno_zkvm/src/tables/range/range_impl.rs | 54 ++++++++++----------- 10 files changed, 92 insertions(+), 69 deletions(-) diff --git a/ceno_zkvm/src/chip_handler/general.rs b/ceno_zkvm/src/chip_handler/general.rs index 4fe85f3d9..6692a8cb2 100644 --- a/ceno_zkvm/src/chip_handler/general.rs +++ b/ceno_zkvm/src/chip_handler/general.rs @@ -95,7 +95,7 @@ impl<'a, E: ExtensionField> CircuitBuilder<'a, E> { pub fn lk_table_record( &mut self, name_fn: N, - table_len: usize, + table_spec: SetTableSpec, rom_type: ROMType, record: Vec>, multiplicity: Expression, @@ -105,7 +105,7 @@ impl<'a, E: ExtensionField> CircuitBuilder<'a, E> { N: FnOnce() -> NR, { self.cs - .lk_table_record(name_fn, table_len, rom_type, record, multiplicity) + .lk_table_record(name_fn, table_spec, rom_type, record, multiplicity) } pub fn r_table_record( diff --git a/ceno_zkvm/src/circuit_builder.rs b/ceno_zkvm/src/circuit_builder.rs index 5c3e2dc2c..6fc2b6c43 100644 --- a/ceno_zkvm/src/circuit_builder.rs +++ b/ceno_zkvm/src/circuit_builder.rs @@ -1,4 +1,3 @@ -use ceno_emul::Addr; use itertools::{Itertools, chain}; use std::{collections::HashMap, iter::once, marker::PhantomData}; @@ -56,13 +55,7 @@ impl NameSpace { pub struct LogupTableExpression { pub multiplicity: Expression, pub values: Expression, - pub table_len: usize, -} - -#[derive(Clone, Debug)] -pub struct DynamicAddr { - pub addr_witin_id: usize, - pub offset: Addr, + pub table_spec: SetTableSpec, } #[derive(Clone, Debug)] @@ -297,7 +290,7 @@ impl ConstraintSystem { pub fn lk_table_record( &mut self, name_fn: N, - table_len: usize, + table_spec: SetTableSpec, rom_type: ROMType, record: Vec>, multiplicity: Expression, @@ -321,7 +314,7 @@ impl ConstraintSystem { self.lk_table_expressions.push(LogupTableExpression { values: rlc_record, multiplicity, - table_len, + table_spec, }); let path = self.ns.compute_path(name_fn().into()); self.lk_expressions_namespace_map.push(path); diff --git a/ceno_zkvm/src/scheme/mock_prover.rs b/ceno_zkvm/src/scheme/mock_prover.rs index e63ae4ee7..9ea7791c3 100644 --- a/ceno_zkvm/src/scheme/mock_prover.rs +++ b/ceno_zkvm/src/scheme/mock_prover.rs @@ -791,6 +791,7 @@ Hints: ); let mut wit_mles = HashMap::new(); + let mut structural_wit_mles = HashMap::new(); let mut fixed_mles = HashMap::new(); let mut num_instances = HashMap::new(); @@ -815,15 +816,17 @@ Hints: if witness.num_instances() == 0 { wit_mles.insert(circuit_name.clone(), vec![]); + structural_wit_mles.insert(circuit_name.clone(), vec![]); fixed_mles.insert(circuit_name.clone(), vec![]); num_instances.insert(circuit_name.clone(), num_rows); continue; } - let witness = witness + let mut witness = witness .into_mles() .into_iter() .map(|w| w.into()) .collect_vec(); + let structural_witness = witness.split_off(cs.num_witin as usize); let fixed: Vec<_> = fixed_trace .circuit_fixed_traces .remove(circuit_name) @@ -876,7 +879,7 @@ Hints: let lk_table = wit_infer_by_expr( &fixed, &witness, - &[], + &structural_witness, &pi_mles, &challenges, &expr.values, @@ -887,7 +890,7 @@ Hints: let multiplicity = wit_infer_by_expr( &fixed, &witness, - &[], + &structural_witness, &pi_mles, &challenges, &expr.multiplicity, @@ -905,6 +908,7 @@ Hints: } } wit_mles.insert(circuit_name.clone(), witness); + structural_wit_mles.insert(circuit_name.clone(), structural_witness); fixed_mles.insert(circuit_name.clone(), fixed); num_instances.insert(circuit_name.clone(), num_rows); } diff --git a/ceno_zkvm/src/scheme/prover.rs b/ceno_zkvm/src/scheme/prover.rs index a7042e5ca..06eda546b 100644 --- a/ceno_zkvm/src/scheme/prover.rs +++ b/ceno_zkvm/src/scheme/prover.rs @@ -964,12 +964,9 @@ impl> ZKVMProver { ); exit_span!(tower_span); - // same point sumcheck is optional when all witin + fixed are in same num_vars - let is_skip_same_point_sumcheck = witnesses - .iter() - .chain(fixed.iter()) - .map(|v| v.num_vars()) - .all_equal(); + // In table proof, we always skip same point sumcheck for now + // as tower sumcheck batch product argument/logup in same length + let is_skip_same_point_sumcheck = true; let (input_open_point, same_r_sumcheck_proofs, rw_in_evals, lk_in_evals) = if is_skip_same_point_sumcheck { diff --git a/ceno_zkvm/src/scheme/verifier.rs b/ceno_zkvm/src/scheme/verifier.rs index 03ef32e64..e9cc8fa6e 100644 --- a/ceno_zkvm/src/scheme/verifier.rs +++ b/ceno_zkvm/src/scheme/verifier.rs @@ -522,6 +522,7 @@ impl> ZKVMVerifier let tower_proofs = &proof.tower_proof; let expected_rounds = cs + // only iterate r set, as read/write set round should match .r_table_expressions .iter() .flat_map(|r| { @@ -538,13 +539,24 @@ impl> ZKVMVerifier .max() .unwrap() }); - [num_vars, num_vars] + [num_vars, num_vars] // format: [read_round, write_round] }) - .chain( - cs.lk_table_expressions - .iter() - .map(|l| ceil_log2(l.table_len)), - ) + .chain(cs.lk_table_expressions.iter().map(|l| { + // iterate through structural witins and collect max round. + let num_vars = l.table_spec.len.map(ceil_log2).unwrap_or_else(|| { + l.table_spec + .structural_witins + .iter() + .map(|StructuralWitIn { id, max_len, .. }| { + let hint_num_vars = proof.rw_hints_num_vars[*id as usize]; + assert!((1 << hint_num_vars) <= *max_len); + hint_num_vars + }) + .max() + .unwrap() + }); + num_vars + })) .collect_vec(); for var in proof.rw_hints_num_vars.iter() { @@ -693,9 +705,10 @@ impl> ZKVMVerifier let structural_witnesses = cs .r_table_expressions .iter() - .flat_map(|set_table_expression| { - set_table_expression - .table_spec + .map(|r| &r.table_spec) + .chain(cs.lk_table_expressions.iter().map(|r| &r.table_spec)) + .flat_map(|table_spec| { + table_spec .structural_witins .iter() .map( diff --git a/ceno_zkvm/src/stats.rs b/ceno_zkvm/src/stats.rs index 7643d0c12..89271277a 100644 --- a/ceno_zkvm/src/stats.rs +++ b/ceno_zkvm/src/stats.rs @@ -107,7 +107,7 @@ impl CircuitStats { }) } else { let table_len = if !system.lk_table_expressions.is_empty() { - system.lk_table_expressions[0].table_len + system.lk_table_expressions[0].table_spec.len.unwrap_or(0) } else { 0 }; diff --git a/ceno_zkvm/src/tables/ops/ops_impl.rs b/ceno_zkvm/src/tables/ops/ops_impl.rs index efe7c4de9..8ece6a077 100644 --- a/ceno_zkvm/src/tables/ops/ops_impl.rs +++ b/ceno_zkvm/src/tables/ops/ops_impl.rs @@ -7,7 +7,7 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterato use std::collections::HashMap; use crate::{ - circuit_builder::CircuitBuilder, + circuit_builder::{CircuitBuilder, SetTableSpec}, error::ZKVMError, expression::{Expression, Fixed, ToExpr, WitIn}, instructions::InstancePaddingStrategy, @@ -38,7 +38,16 @@ impl OpTableConfig { let record_exprs = abc.into_iter().map(|f| Expression::Fixed(f)).collect_vec(); - cb.lk_table_record(|| "record", table_len, rom_type, record_exprs, mlt.expr())?; + cb.lk_table_record( + || "record", + SetTableSpec { + len: Some(table_len), + structural_witins: vec![], + }, + rom_type, + record_exprs, + mlt.expr(), + )?; Ok(Self { abc, mlt }) } diff --git a/ceno_zkvm/src/tables/program.rs b/ceno_zkvm/src/tables/program.rs index 5a43af187..5f3773878 100644 --- a/ceno_zkvm/src/tables/program.rs +++ b/ceno_zkvm/src/tables/program.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, marker::PhantomData}; use crate::{ - circuit_builder::CircuitBuilder, + circuit_builder::{CircuitBuilder, SetTableSpec}, error::ZKVMError, expression::{Expression, Fixed, ToExpr, WitIn}, instructions::InstancePaddingStrategy, @@ -115,7 +115,10 @@ impl TableCircuit for ProgramTableCircuit { cb.lk_table_record( || "prog table", - cb.params.program_size.next_power_of_two(), + SetTableSpec { + len: Some(cb.params.program_size.next_power_of_two()), + structural_witins: vec![], + }, ROMType::Instruction, record_exprs, mlt.expr(), diff --git a/ceno_zkvm/src/tables/range/range_circuit.rs b/ceno_zkvm/src/tables/range/range_circuit.rs index 83d8da017..2ecb6c6f3 100644 --- a/ceno_zkvm/src/tables/range/range_circuit.rs +++ b/ceno_zkvm/src/tables/range/range_circuit.rs @@ -5,8 +5,8 @@ use super::range_impl::RangeTableConfig; use std::{collections::HashMap, marker::PhantomData}; use crate::{ - circuit_builder::CircuitBuilder, error::ZKVMError, structs::ROMType, tables::TableCircuit, - witness::RowMajorMatrix, + circuit_builder::CircuitBuilder, error::ZKVMError, instructions::InstancePaddingStrategy, + structs::ROMType, tables::TableCircuit, witness::RowMajorMatrix, }; use ff_ext::ExtensionField; @@ -40,11 +40,11 @@ impl TableCircuit for RangeTableCircuit } fn generate_fixed_traces( - config: &RangeTableConfig, - num_fixed: usize, + _config: &RangeTableConfig, + _num_fixed: usize, _input: &(), ) -> RowMajorMatrix { - config.generate_fixed_traces(num_fixed, RANGE::content()) + RowMajorMatrix::::new(0, 0, InstancePaddingStrategy::Default) } fn assign_instances( @@ -55,6 +55,12 @@ impl TableCircuit for RangeTableCircuit _input: &(), ) -> Result, ZKVMError> { let multiplicity = &multiplicity[RANGE::ROM_TYPE as usize]; - config.assign_instances(num_witin, num_structural_witin, multiplicity, RANGE::len()) + config.assign_instances( + num_witin, + num_structural_witin, + multiplicity, + RANGE::content(), + RANGE::len(), + ) } } diff --git a/ceno_zkvm/src/tables/range/range_impl.rs b/ceno_zkvm/src/tables/range/range_impl.rs index 6e7ebaee4..2832892dd 100644 --- a/ceno_zkvm/src/tables/range/range_impl.rs +++ b/ceno_zkvm/src/tables/range/range_impl.rs @@ -6,19 +6,19 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterato use std::collections::HashMap; use crate::{ - circuit_builder::CircuitBuilder, + circuit_builder::{CircuitBuilder, SetTableSpec}, error::ZKVMError, - expression::{Expression, Fixed, ToExpr, WitIn}, + expression::{StructuralWitIn, ToExpr, WitIn}, instructions::InstancePaddingStrategy, scheme::constants::MIN_PAR_SIZE, - set_fixed_val, set_val, + set_val, structs::ROMType, witness::RowMajorMatrix, }; #[derive(Clone, Debug)] pub struct RangeTableConfig { - fixed: Fixed, + range: StructuralWitIn, mlt: WitIn, } @@ -28,33 +28,23 @@ impl RangeTableConfig { rom_type: ROMType, table_len: usize, ) -> Result { - let fixed = cb.create_fixed(|| "fixed")?; + let range = cb.create_structural_witin(|| "structural range witin", table_len, 0, 1); let mlt = cb.create_witin(|| "mlt"); - let record_exprs = vec![Expression::Fixed(fixed)]; + let record_exprs = vec![range.expr()]; - cb.lk_table_record(|| "record", table_len, rom_type, record_exprs, mlt.expr())?; + cb.lk_table_record( + || "record", + SetTableSpec { + len: Some(table_len), + structural_witins: vec![range], + }, + rom_type, + record_exprs, + mlt.expr(), + )?; - Ok(Self { fixed, mlt }) - } - - pub fn generate_fixed_traces( - &self, - num_fixed: usize, - content: Vec, - ) -> RowMajorMatrix { - let mut fixed = - RowMajorMatrix::::new(content.len(), num_fixed, InstancePaddingStrategy::Default); - - fixed - .par_iter_mut() - .with_min_len(MIN_PAR_SIZE) - .zip(content.into_par_iter()) - .for_each(|(row, i)| { - set_fixed_val!(row, self.fixed, F::from(i)); - }); - - fixed + Ok(Self { range, mlt }) } pub fn assign_instances( @@ -62,6 +52,7 @@ impl RangeTableConfig { num_witin: usize, num_structural_witin: usize, multiplicity: &HashMap, + content: Vec, length: usize, ) -> Result, ZKVMError> { let mut witness = RowMajorMatrix::::new( @@ -75,12 +66,19 @@ impl RangeTableConfig { mlts[*idx as usize] = *mlt; } + let offset_range = StructuralWitIn { + id: self.range.id + (num_witin as u16), + ..self.range + }; + witness .par_iter_mut() .with_min_len(MIN_PAR_SIZE) .zip(mlts.into_par_iter()) - .for_each(|(row, mlt)| { + .zip(content.into_par_iter()) + .for_each(|((row, mlt), i)| { set_val!(row, self.mlt, F::from(mlt as u64)); + set_val!(row, offset_range, F::from(i)); }); Ok(witness)