Skip to content

Commit 2400506

Browse files
authored
[Upgrade] ZKVMProof Verifier Update (#31)
* Remove index reversal * Add a cycle tracker * Delete a loop * Better casting * Change verifier logic * Finish opcdoe proof verification debugging * Finish debugging table proof verification * Debug verifier * Finish debugging updated verifier * Remove unnecessary table proof fields * Remove unnecessary parsing * Update Plonky3 * Migrate away from temporary build branch
1 parent d7bbb56 commit 2400506

File tree

10 files changed

+892
-1013
lines changed

10 files changed

+892
-1013
lines changed

Cargo.lock

Lines changed: 294 additions & 184 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ openvm-native-circuit = { git = "https://github.com/scroll-tech/openvm.git", bra
1010
openvm-native-compiler = { git = "https://github.com/scroll-tech/openvm.git", branch = "feat/native_multi_observe", default-features = false }
1111
openvm-native-compiler-derive = { git = "https://github.com/scroll-tech/openvm.git", branch = "feat/native_multi_observe", default-features = false }
1212
openvm-native-recursion = { git = "https://github.com/scroll-tech/openvm.git", branch = "feat/native_multi_observe", default-features = false }
13-
1413
openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.0.0", default-features = false }
1514
openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v1.0.0", default-features = false }
1615

1716
rand = { version = "0.8.5", default-features = false }
1817
itertools = { version = "0.13.0", default-features = false }
19-
bincode = "1"
18+
bincode = "1.3.3"
2019
tracing = "0.1.40"
2120

2221
# Plonky3
@@ -38,13 +37,13 @@ ark-poly = "0.5"
3837
ark-serialize = "0.5"
3938

4039
# Ceno
41-
ceno_mle = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "multilinear_extensions" }
42-
ceno_sumcheck = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "sumcheck" }
43-
ceno_transcript = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "transcript" }
44-
ceno_zkvm = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
45-
ceno_emul = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
46-
mpcs = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
47-
ff_ext = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
40+
ceno_mle = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support", package = "multilinear_extensions" }
41+
ceno_sumcheck = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support", package = "sumcheck" }
42+
ceno_transcript = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support", package = "transcript" }
43+
ceno_zkvm = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support" }
44+
ceno_emul = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support" }
45+
mpcs = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support" }
46+
ff_ext = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/smaller_field_support" }
4847
serde = { version = "1.0", features = ["derive"] }
4948
serde_json = "1.0"
5049

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[toolchain]
2-
channel = "nightly-2025-01-06"
2+
channel = "nightly-2025-03-25"
33
targets = ["riscv32im-unknown-none-elf"]
44
components = ["clippy", "rustfmt", "rust-src"]

src/arithmetics/mod.rs

Lines changed: 138 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::tower_verifier::binding::PointAndEvalVariable;
22
use crate::zkvm_verifier::binding::ZKVMOpcodeProofInputVariable;
3-
use ceno_zkvm::expression::{Expression, Fixed, Instance};
3+
use ceno_mle::expression::{Expression, Fixed, Instance};
44
use ceno_zkvm::structs::{ChallengeId, WitnessId};
55
use ff_ext::ExtensionField;
66
use ff_ext::{BabyBearExt4, SmallField};
@@ -10,11 +10,13 @@ use openvm_native_recursion::challenger::ChallengerVariable;
1010
use openvm_native_recursion::challenger::{
1111
duplex::DuplexChallengerVariable, CanObserveVariable, FeltChallenger,
1212
};
13+
use itertools::Either;
1314
use p3_field::{FieldAlgebra, FieldExtensionAlgebra};
1415
type E = BabyBearExt4;
1516
const HASH_RATE: usize = 8;
17+
const MAX_NUM_VARS: usize = 25;
1618

17-
pub fn _print_ext_arr<C: Config>(builder: &mut Builder<C>, arr: &Array<C, Ext<C::F, C::EF>>) {
19+
pub fn print_ext_arr<C: Config>(builder: &mut Builder<C>, arr: &Array<C, Ext<C::F, C::EF>>) {
1820
iter_zip!(builder, arr).for_each(|ptr_vec, builder| {
1921
let e = builder.iter_ptr_get(arr, ptr_vec[0]);
2022
builder.print_e(e);
@@ -28,7 +30,7 @@ pub fn print_felt_arr<C: Config>(builder: &mut Builder<C>, arr: &Array<C, Felt<C
2830
});
2931
}
3032

31-
pub fn _print_usize_arr<C: Config>(builder: &mut Builder<C>, arr: &Array<C, Usize<C::N>>) {
33+
pub fn print_usize_arr<C: Config>(builder: &mut Builder<C>, arr: &Array<C, Usize<C::N>>) {
3234
iter_zip!(builder, arr).for_each(|ptr_vec, builder| {
3335
let n = builder.iter_ptr_get(arr, ptr_vec[0]);
3436
builder.print_v(n.get_var());
@@ -87,20 +89,91 @@ pub fn is_smaller_than<C: Config>(
8789
RVar::from(v)
8890
}
8991

90-
pub fn evaluate_at_point<C: Config>(
92+
pub fn evaluate_at_point_degree_1<C: Config>(
9193
builder: &mut Builder<C>,
9294
evals: &Array<C, Ext<C::F, C::EF>>,
9395
point: &Array<C, Ext<C::F, C::EF>>,
9496
) -> Ext<C::F, C::EF> {
95-
// TODO: Dynamic length
96-
// TODO: Sanity checks
9797
let left = builder.get(&evals, 0);
9898
let right = builder.get(&evals, 1);
9999
let r = builder.get(point, 0);
100100

101101
builder.eval(r * (right - left) + left)
102102
}
103103

104+
pub struct PolyEvaluator<C: Config> {
105+
powers_of_2: Array<C, Usize<C::N>>,
106+
}
107+
108+
impl<C: Config> PolyEvaluator<C> {
109+
pub fn new(builder: &mut Builder<C>) -> Self {
110+
let powers_of_2: Array<C, Usize<C::N>> = builder.dyn_array(MAX_NUM_VARS);
111+
builder.set(&powers_of_2, 0, Usize::from(16777216));
112+
builder.set(&powers_of_2, 1, Usize::from(8388608));
113+
builder.set(&powers_of_2, 2, Usize::from(4194304));
114+
builder.set(&powers_of_2, 3, Usize::from(1048576));
115+
builder.set(&powers_of_2, 4, Usize::from(2097152));
116+
builder.set(&powers_of_2, 5, Usize::from(524288));
117+
builder.set(&powers_of_2, 6, Usize::from(262144));
118+
builder.set(&powers_of_2, 7, Usize::from(131072));
119+
builder.set(&powers_of_2, 8, Usize::from(65536));
120+
builder.set(&powers_of_2, 9, Usize::from(32768));
121+
builder.set(&powers_of_2, 10, Usize::from(16384));
122+
builder.set(&powers_of_2, 11, Usize::from(8192));
123+
builder.set(&powers_of_2, 12, Usize::from(4096));
124+
builder.set(&powers_of_2, 13, Usize::from(2048));
125+
builder.set(&powers_of_2, 14, Usize::from(1024));
126+
builder.set(&powers_of_2, 15, Usize::from(512));
127+
builder.set(&powers_of_2, 16, Usize::from(256));
128+
builder.set(&powers_of_2, 17, Usize::from(128));
129+
builder.set(&powers_of_2, 18, Usize::from(64));
130+
builder.set(&powers_of_2, 19, Usize::from(32));
131+
builder.set(&powers_of_2, 20, Usize::from(16));
132+
builder.set(&powers_of_2, 21, Usize::from(8));
133+
builder.set(&powers_of_2, 22, Usize::from(4));
134+
builder.set(&powers_of_2, 23, Usize::from(2));
135+
builder.set(&powers_of_2, 24, Usize::from(1));
136+
137+
Self { powers_of_2 }
138+
}
139+
140+
pub fn evaluate_base_poly_at_point(
141+
&self,
142+
builder: &mut Builder<C>,
143+
evals: &Array<C, Felt<C::F>>,
144+
point: &Array<C, Ext<C::F, C::EF>>,
145+
) -> Ext<C::F, C::EF> {
146+
let num_var = point.len();
147+
148+
let evals_ext: Array<C, Ext<C::F, C::EF>> = builder.dyn_array(evals.len());
149+
iter_zip!(builder, evals, evals_ext).for_each(|ptr_vec, builder| {
150+
let f = builder.iter_ptr_get(&evals, ptr_vec[0]);
151+
let e = builder.ext_from_base_slice(&[f]);
152+
builder.iter_ptr_set(&evals_ext, ptr_vec[1], e);
153+
});
154+
155+
let pwr_slice_idx: Usize<C::N> = builder.eval(Usize::from(25) - num_var);
156+
let pwrs = self.powers_of_2.slice(builder, pwr_slice_idx, MAX_NUM_VARS);
157+
158+
iter_zip!(builder, point, pwrs).for_each(|ptr_vec, builder| {
159+
let pt = builder.iter_ptr_get(&point, ptr_vec[0]);
160+
let idx_bound = builder.iter_ptr_get(&pwrs, ptr_vec[1]);
161+
162+
builder.range(0, idx_bound).for_each(|idx_vec, builder| {
163+
let left_idx: Usize<C::N> = builder.eval(idx_vec[0] * Usize::from(2));
164+
let right_idx: Usize<C::N> = builder.eval(idx_vec[0] * Usize::from(2) + Usize::from(1));
165+
let left = builder.get(&evals_ext, left_idx);
166+
let right = builder.get(&evals_ext, right_idx);
167+
168+
let e: Ext<C::F, C::EF> = builder.eval(pt * (right - left) + left);
169+
builder.set(&evals_ext, idx_vec[0], e);
170+
});
171+
});
172+
173+
builder.get(&evals_ext, 0)
174+
}
175+
}
176+
104177
pub fn dot_product<C: Config>(
105178
builder: &mut Builder<C>,
106179
a: &Array<C, Ext<C::F, C::EF>>,
@@ -221,6 +294,24 @@ pub fn product<C: Config>(
221294
acc
222295
}
223296

297+
// Multiply all elements in a nested Array
298+
pub fn nested_product<C: Config>(
299+
builder: &mut Builder<C>,
300+
arr: &Array<C, Array<C, Ext<C::F, C::EF>>>,
301+
) -> Ext<C::F, C::EF> {
302+
let acc = builder.constant(C::EF::ONE);
303+
iter_zip!(builder, arr).for_each(|ptr_vec, builder| {
304+
let inner_arr = builder.iter_ptr_get(arr, ptr_vec[0]);
305+
306+
iter_zip!(builder, inner_arr).for_each(|ptr_vec, builder| {
307+
let el = builder.iter_ptr_get(&inner_arr, ptr_vec[0]);
308+
builder.assign(&acc, acc * el);
309+
});
310+
});
311+
312+
acc
313+
}
314+
224315
// Add all elements in the Array
225316
pub fn sum<C: Config>(
226317
builder: &mut Builder<C>,
@@ -286,12 +377,13 @@ pub fn eq_eval_less_or_equal_than<C: Config>(
286377
a: &Array<C, Ext<C::F, C::EF>>,
287378
b: &Array<C, Ext<C::F, C::EF>>,
288379
) -> Ext<C::F, C::EF> {
380+
builder.cycle_tracker_start("Compute eq_eval_less_or_equal_than");
289381
let eq_bit_decomp: Array<C, Felt<C::F>> = opcode_proof
290382
.num_instances_minus_one_bit_decomposition
291383
.slice(builder, 0, b.len());
292384

293385
let one_ext: Ext<C::F, C::EF> = builder.constant(C::EF::ONE);
294-
let rp_len = builder.eval_expr(RVar::from(b.len()) + RVar::from(1));
386+
let rp_len = builder.eval_expr(b.len() + C::N::ONE);
295387
let running_product: Array<C, Ext<C::F, C::EF>> = builder.dyn_array(rp_len);
296388
builder.set(&running_product, 0, one_ext);
297389

@@ -305,49 +397,29 @@ pub fn eq_eval_less_or_equal_than<C: Config>(
305397
builder.set(&running_product, next_idx, next_v);
306398
});
307399

308-
let running_product2: Array<C, Ext<C::F, C::EF>> = builder.dyn_array(rp_len);
309-
builder.set(&running_product2, b.len(), one_ext);
310-
311-
let eq_bit_decomp_rev = reverse(builder, &eq_bit_decomp);
312-
let idx_arr = gen_idx_arr(builder, b.len());
313-
let idx_arr_rev = reverse(builder, &idx_arr);
314-
builder.assert_usize_eq(eq_bit_decomp_rev.len(), idx_arr_rev.len());
315-
316-
iter_zip!(builder, idx_arr_rev, eq_bit_decomp_rev).for_each(|ptr_vec, builder| {
317-
let i = builder.iter_ptr_get(&idx_arr_rev, ptr_vec[0]);
318-
let bit = builder.iter_ptr_get(&eq_bit_decomp_rev, ptr_vec[1]);
319-
let bit_ext = builder.ext_from_base_slice(&[bit]);
320-
let last_idx = builder.eval_expr(i.clone() + RVar::from(1));
321-
322-
let v = builder.get(&running_product2, last_idx);
323-
let a_i = builder.get(a, i.clone());
324-
let b_i = builder.get(b, i.clone());
325-
326-
let next_v: Ext<C::F, C::EF> = builder.eval(
327-
v * (a_i * b_i * bit_ext + (one_ext - a_i) * (one_ext - b_i) * (one_ext - bit_ext)),
328-
);
329-
builder.set(&running_product2, i, next_v);
330-
});
331-
332-
// Here is an example of how this works:
333-
// Suppose max_idx = (110101)_2
334-
// Then ans = eq(a, b)
335-
// - eq(11011, a[1..6], b[1..6])eq(a[0..1], b[0..1])
336-
// - eq(111, a[3..6], b[3..6])eq(a[0..3], b[0..3])
337400
let ans = builder.get(&running_product, b.len());
338-
builder.range(0, b.len()).for_each(|idx_vec, builder| {
339-
let bit = builder.get(&eq_bit_decomp, idx_vec[0]);
401+
let running_product2: Ext<C::F, C::EF> = builder.constant(C::EF::ONE);
402+
let idx: Var<C::N> = builder.uninit();
403+
builder.assign(&idx, b.len() - C::N::ONE);
404+
builder.range(0, b.len()).for_each(|_, builder| {
405+
let bit = builder.get(&eq_bit_decomp, idx);
340406
let bit_rvar = RVar::from(builder.cast_felt_to_var(bit));
407+
let bit_ext: Ext<C::F, C::EF> = builder.eval(bit * SymbolicExt::from_f(C::EF::ONE));
341408

342-
builder.if_ne(bit_rvar, RVar::from(1)).then(|builder| {
343-
let next_idx = builder.eval_expr(idx_vec[0] + RVar::from(1));
344-
let v1 = builder.get(&running_product, idx_vec[0]);
345-
let v2 = builder.get(&running_product2, next_idx);
346-
let a_i = builder.get(a, idx_vec[0]);
347-
let b_i = builder.get(b, idx_vec[0]);
409+
let a_i = builder.get(a, idx);
410+
let b_i = builder.get(b, idx);
348411

349-
builder.assign(&ans, ans - v1 * v2 * a_i * b_i);
412+
// Suppose max_idx = (110101)_2
413+
// Then ans = eq(a, b)
414+
// - eq(11011, a[1..6], b[1..6])eq(a[0..1], b[0..1])
415+
// - eq(111, a[3..6], b[3..6])eq(a[0..3], b[0..3])
416+
builder.if_ne(bit_rvar, RVar::from(1)).then(|builder| {
417+
let v1 = builder.get(&running_product, idx);
418+
builder.assign(&ans, ans - v1 * running_product2 * a_i * b_i);
350419
});
420+
421+
builder.assign(&running_product2, running_product2 * (a_i * b_i * bit_ext + (one_ext - a_i) * (one_ext - b_i) * (one_ext - bit_ext)));
422+
builder.assign(&idx, idx - C::N::ONE);
351423
});
352424

353425
let a_remainder_arr: Array<C, Ext<C::F, C::EF>> = a.slice(builder, b.len(), a.len());
@@ -356,6 +428,8 @@ pub fn eq_eval_less_or_equal_than<C: Config>(
356428
builder.assign(&ans, ans * (one_ext - a));
357429
});
358430

431+
builder.cycle_tracker_end("Compute eq_eval_less_or_equal_than");
432+
359433
ans
360434
}
361435

@@ -460,9 +534,14 @@ pub fn eval_ceno_expr_with_instance<C: Config>(
460534
res
461535
},
462536
&|builder, scalar| {
463-
let res: Ext<C::F, C::EF> =
464-
builder.constant(C::EF::from_canonical_u32(scalar.to_canonical_u64() as u32));
465-
res
537+
let scalar_base_slice = scalar
538+
.as_bases()
539+
.iter()
540+
.map(|b| C::F::from_canonical_u64(b.to_canonical_u64()))
541+
.collect::<Vec<C::F>>();
542+
let scalar_ext: Ext<C::F, C::EF> =
543+
builder.constant(C::EF::from_base_slice(&scalar_base_slice));
544+
scalar_ext
466545
},
467546
&|builder, challenge_id, pow, scalar, offset| {
468547
let challenge = builder.get(&challenges, challenge_id as usize);
@@ -510,7 +589,7 @@ pub fn evaluate_ceno_expr<C: Config, T>(
510589
wit_in: &impl Fn(&mut Builder<C>, WitnessId) -> T, // witin id
511590
structural_wit_in: &impl Fn(&mut Builder<C>, WitnessId, usize, u32, usize) -> T,
512591
instance: &impl Fn(&mut Builder<C>, Instance) -> T,
513-
constant: &impl Fn(&mut Builder<C>, <E as ExtensionField>::BaseField) -> T,
592+
constant: &impl Fn(&mut Builder<C>, E) -> T,
514593
challenge: &impl Fn(&mut Builder<C>, ChallengeId, usize, E, E) -> T,
515594
sum: &impl Fn(&mut Builder<C>, T, T) -> T,
516595
product: &impl Fn(&mut Builder<C>, T, T) -> T,
@@ -523,7 +602,16 @@ pub fn evaluate_ceno_expr<C: Config, T>(
523602
structural_wit_in(builder, *witness_id, *max_len, *offset, *multi_factor)
524603
}
525604
Expression::Instance(i) => instance(builder, *i),
526-
Expression::Constant(scalar) => constant(builder, *scalar),
605+
Expression::Constant(scalar) => {
606+
match scalar {
607+
Either::Left(s) => {
608+
constant(builder, E::from_base(*s))
609+
},
610+
Either::Right(s) => {
611+
constant(builder, *s)
612+
},
613+
}
614+
},
527615
Expression::Sum(a, b) => {
528616
let a = evaluate_ceno_expr(
529617
builder,

0 commit comments

Comments
 (0)