Skip to content

Commit c1970fa

Browse files
Fix Batch Verify (#1205)
- Debug and complete the batch verify component of recursion verifier program --------- Co-authored-by: kunxian xia <xiakunxian130@gmail.com>
1 parent 6b672b8 commit c1970fa

9 files changed

Lines changed: 181 additions & 98 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ proptest-regressions/
1313

1414
# ceno serialized files
1515
*.bin
16+
*.json

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ version = "0.1.0"
2626
[workspace.dependencies]
2727
ceno_crypto_primitives = { git = "https://github.com/scroll-tech/ceno-patch.git", package = "ceno_crypto_primitives", branch = "main" }
2828
ceno_syscall = { git = "https://github.com/scroll-tech/ceno-patch.git", package = "ceno_syscall", branch = "main" }
29+
2930
ff_ext = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "ff_ext", tag = "v1.0.0-alpha.19" }
3031
mpcs = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "mpcs", tag = "v1.0.0-alpha.19" }
3132
multilinear_extensions = { git = "https://github.com/scroll-tech/gkr-backend.git", package = "multilinear_extensions", tag = "v1.0.0-alpha.19" }

ceno_cli/src/sdk.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,12 @@ where
211211
agg_pk.internal_committed_exe.exe.clone(),
212212
)
213213
.expect("internal prover");
214-
215-
CenoAggregationProver::new(leaf_prover, internal_prover, agg_pk.clone())
214+
assert!(
215+
self.zkvm_vk.is_some(),
216+
"Aggregation must provide existing base layer vk."
217+
);
218+
let base_vk = self.zkvm_vk.as_ref().unwrap().clone();
219+
CenoAggregationProver::new(base_vk, leaf_prover, internal_prover, agg_pk.clone())
216220
} else {
217221
let agg_prover = CenoAggregationProver::from_base_vk(self.zkvm_vk.clone().unwrap());
218222
self.agg_pk = Some(agg_prover.pk.clone());

ceno_recursion/src/aggregation/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ const VM_MAX_TRACE_HEIGHTS: &[u32] = &[
9090
2097152, 8388608, 262144, 2097152, 1048576, 4194304, 1048576, 262144,
9191
];
9292
pub struct CenoAggregationProver {
93+
pub base_vk: ZKVMVerifyingKey<E, Basefold<E, BasefoldRSParams>>,
9394
pub leaf_prover: VmInstance<BabyBearPoseidon2Engine, NativeBuilder>,
9495
pub internal_prover: VmInstance<BabyBearPoseidon2Engine, NativeBuilder>,
9596
pub vk: CenoRecursionVerifierKeys<BabyBearPoseidon2Config>,
@@ -98,11 +99,13 @@ pub struct CenoAggregationProver {
9899

99100
impl CenoAggregationProver {
100101
pub fn new(
102+
base_vk: ZKVMVerifyingKey<E, Basefold<E, BasefoldRSParams>>,
101103
leaf_prover: VmInstance<BabyBearPoseidon2Engine, NativeBuilder>,
102104
internal_prover: VmInstance<BabyBearPoseidon2Engine, NativeBuilder>,
103105
pk: CenoRecursionProvingKeys<BabyBearPoseidon2Config, NativeConfig>,
104106
) -> Self {
105107
Self {
108+
base_vk,
106109
leaf_prover,
107110
internal_prover,
108111
vk: pk.get_vk(),
@@ -150,11 +153,11 @@ impl CenoAggregationProver {
150153

151154
// Leaf layer program
152155
let leaf_engine = BabyBearPoseidon2Engine::new(leaf_fri_params);
153-
let leaf_program = CenoLeafVmVerifierConfig {
156+
let leaf_vm_verifier_config = CenoLeafVmVerifierConfig {
154157
vk,
155158
compiler_options: CompilerOptions::default().with_cycle_tracker(),
156-
}
157-
.build_program();
159+
};
160+
let leaf_program = leaf_vm_verifier_config.build_program();
158161
let leaf_committed_exe = Arc::new(VmCommittedExe::<SC>::commit(
159162
leaf_program.into(),
160163
leaf_engine.config().pcs(),
@@ -239,6 +242,7 @@ impl CenoAggregationProver {
239242
};
240243

241244
Self {
245+
base_vk: leaf_vm_verifier_config.vk,
242246
leaf_prover,
243247
internal_prover,
244248
vk,
@@ -256,7 +260,7 @@ impl CenoAggregationProver {
256260
let zkvm_proof_inputs: Vec<ZKVMProofInput> = base_proofs
257261
.into_iter()
258262
.enumerate()
259-
.map(|(shard_id, p)| ZKVMProofInput::from((shard_id, p)))
263+
.map(|(shard_id, p)| ZKVMProofInput::from_proof(shard_id, p, &self.base_vk))
260264
.collect();
261265
let user_public_values: Vec<F> = zkvm_proof_inputs
262266
.iter()
@@ -673,7 +677,7 @@ pub fn verify_proofs(
673677
) {
674678
let program = build_zkvm_verifier_program(&vk);
675679
if !zkvm_proofs.is_empty() {
676-
let zkvm_proof_input = ZKVMProofInput::from((0usize, zkvm_proofs[0].clone()));
680+
let zkvm_proof_input = ZKVMProofInput::from_proof(0usize, zkvm_proofs[0].clone(), &vk);
677681

678682
// Pass in witness stream
679683
let mut witness_stream: Vec<Vec<F>> = Vec::new();

ceno_recursion/src/basefold_verifier/hash.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ impl Hintable<InnerConfig> for Hash {
4444
}
4545
}
4646

47+
impl<C: Config<F = F>> HashVariable<C> {
48+
pub fn new(builder: &mut Builder<C>, hash: &Hash) -> Self {
49+
let value = builder.dyn_array(DIGEST_ELEMS);
50+
for i in 0..DIGEST_ELEMS {
51+
builder.set(&value, i, hash.value[i]);
52+
}
53+
54+
HashVariable { value }
55+
}
56+
}
57+
4758
#[cfg(test)]
4859
mod tests {
4960
use openvm_circuit::arch::{SystemConfig, VmExecutor};

ceno_recursion/src/basefold_verifier/verifier.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ pub fn batch_verify<C: Config>(
8787
// num_var is always smaller than 32.
8888
builder.range_check_var(diff, 5);
8989
builder.assign(&diff_product_num_var, diff_product_num_var * diff);
90-
9190
let diff: Var<C::N> = builder.eval(max_width - opening.point_and_evals.evals.len());
9291
// width is always smaller than 2^14.
9392
builder.range_check_var(diff, 14);

ceno_recursion/src/zkvm_verifier/binding.rs

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::BTreeMap;
1+
use std::collections::{BTreeMap, HashMap};
22

33
use crate::{
44
arithmetics::{ceil_log2, next_pow2_instance_padding},
@@ -12,7 +12,7 @@ use crate::{
1212
};
1313
use ceno_zkvm::{
1414
scheme::{ZKVMChipProof, ZKVMProof},
15-
structs::{EccQuarkProof, TowerProofs},
15+
structs::{EccQuarkProof, TowerProofs, ZKVMVerifyingKey},
1616
};
1717
use gkr_iop::gkr::{GKRProof, layer::sumcheck_layer::LayerProof};
1818
use itertools::Itertools;
@@ -97,29 +97,62 @@ pub(crate) struct ZKVMProofInput {
9797
pub opening_proof: BasefoldProof,
9898
}
9999

100-
impl From<(usize, ZKVMProof<E, RecPcs>)> for ZKVMProofInput {
101-
fn from(d: (usize, ZKVMProof<E, RecPcs>)) -> Self {
100+
impl ZKVMProofInput {
101+
pub fn from_proof(
102+
shard_id: usize,
103+
zkvm_proof: ZKVMProof<E, RecPcs>,
104+
vk: &ZKVMVerifyingKey<E, RecPcs>,
105+
) -> Self {
106+
let mut chip_witin_num_vars: HashMap<usize, (usize, usize)> = HashMap::new(); // (chip_id, (num_witin, num_fixed))
107+
let mut chip_indices = zkvm_proof
108+
.chip_proofs
109+
.keys()
110+
.copied()
111+
.collect::<Vec<usize>>();
112+
chip_indices.push(0);
113+
114+
let mut chip_idx: usize = 0;
115+
let mut chip_id: usize = chip_indices[chip_idx];
116+
for (i, (_, chip_vk)) in vk.circuit_vks.iter().enumerate() {
117+
if chip_id == i {
118+
let composed_cs = chip_vk.get_cs();
119+
chip_witin_num_vars.insert(
120+
chip_id,
121+
(
122+
composed_cs.zkvm_v1_css.num_witin as usize,
123+
composed_cs.zkvm_v1_css.num_fixed,
124+
),
125+
);
126+
chip_idx += 1;
127+
chip_id = chip_indices[chip_idx];
128+
}
129+
}
130+
102131
ZKVMProofInput {
103-
shard_id: d.0,
104-
raw_pi: d.1.raw_pi,
105-
pi_evals: d.1.pi_evals,
106-
chip_proofs: d
107-
.1
132+
shard_id,
133+
raw_pi: zkvm_proof.raw_pi,
134+
pi_evals: zkvm_proof.pi_evals,
135+
chip_proofs: zkvm_proof
108136
.chip_proofs
109137
.into_iter()
110138
.map(|(chip_idx, proofs)| {
139+
let (num_witin, num_fixed) = *chip_witin_num_vars
140+
.get(&chip_idx)
141+
.expect("num_witin data should exist");
111142
(
112143
chip_idx,
113144
proofs
114145
.into_iter()
115-
.map(|proof| ZKVMChipProofInput::from((chip_idx, proof)))
146+
.map(|proof| {
147+
ZKVMChipProofInput::from((chip_idx, proof, num_witin, num_fixed))
148+
})
116149
.collect::<Vec<ZKVMChipProofInput>>()
117150
.into(),
118151
)
119152
})
120153
.collect::<BTreeMap<usize, ZKVMChipProofs>>(),
121-
witin_commit: d.1.witin_commit.into(),
122-
opening_proof: d.1.opening_proof.into(),
154+
witin_commit: zkvm_proof.witin_commit.into(),
155+
opening_proof: zkvm_proof.opening_proof.into(),
123156
}
124157
}
125158
}
@@ -167,7 +200,8 @@ impl Hintable<InnerConfig> for ZKVMProofInput {
167200
.chip_proofs
168201
.iter()
169202
.flat_map(|(_, proofs)| proofs.iter())
170-
.map(|proof| proof.sum_num_instances)
203+
.filter(|proof| proof.num_witin > 0)
204+
.map(|proof| proof.num_vars)
171205
.collect::<Vec<_>>();
172206
let witin_max_widths = self
173207
.chip_proofs
@@ -180,7 +214,7 @@ impl Hintable<InnerConfig> for ZKVMProofInput {
180214
.iter()
181215
.flat_map(|(_, proofs)| proofs.iter())
182216
.filter(|proof| !proof.fixed_in_evals.is_empty())
183-
.map(|proof| proof.sum_num_instances)
217+
.map(|proof| proof.num_vars)
184218
.collect::<Vec<_>>();
185219
let fixed_max_widths = self
186220
.chip_proofs
@@ -189,7 +223,12 @@ impl Hintable<InnerConfig> for ZKVMProofInput {
189223
.filter(|proof| !proof.fixed_in_evals.is_empty())
190224
.map(|proof| proof.fixed_in_evals.len())
191225
.collect::<Vec<_>>();
192-
let max_num_var = witin_num_vars.iter().copied().max().unwrap_or(0);
226+
let max_num_var = witin_num_vars
227+
.iter()
228+
.chain(fixed_num_vars.iter())
229+
.copied()
230+
.max()
231+
.unwrap_or(0);
193232
let max_width = witin_max_widths
194233
.iter()
195234
.chain(fixed_max_widths.iter())
@@ -319,7 +358,11 @@ impl Hintable<InnerConfig> for TowerProofInput {
319358

320359
pub struct ZKVMChipProofInput {
321360
pub idx: usize,
322-
pub sum_num_instances: usize,
361+
/// number of variables in the chip's multilinear polynomials
362+
pub num_vars: usize,
363+
364+
pub num_witin: usize,
365+
pub num_fixed: usize,
323366

324367
// product constraints
325368
pub r_out_evals_len: usize,
@@ -380,15 +423,30 @@ impl Hintable<InnerConfig> for ZKVMChipProofs {
380423
}
381424
}
382425

383-
impl From<(usize, ZKVMChipProof<E>)> for ZKVMChipProofInput {
384-
fn from(d: (usize, ZKVMChipProof<E>)) -> Self {
426+
impl From<(usize, ZKVMChipProof<E>, usize, usize)> for ZKVMChipProofInput {
427+
fn from(d: (usize, ZKVMChipProof<E>, usize, usize)) -> Self {
385428
let idx = d.0;
386429
let p = d.1;
387-
let sum_num_instances = p.num_instances.iter().sum();
430+
431+
let num_vars = if p.gkr_iop_proof.is_some() {
432+
let vars = p
433+
.gkr_iop_proof
434+
.as_ref()
435+
.unwrap()
436+
.0
437+
.iter()
438+
.map(|l| l.main.proof.proofs.len())
439+
.collect::<Vec<usize>>();
440+
vars[0]
441+
} else {
442+
0
443+
};
388444

389445
Self {
390446
idx,
391-
sum_num_instances,
447+
num_vars,
448+
num_witin: d.2,
449+
num_fixed: d.3,
392450
r_out_evals_len: p.r_out_evals.len(),
393451
w_out_evals_len: p.w_out_evals.len(),
394452
lk_out_evals_len: p.lk_out_evals.len(),

0 commit comments

Comments
 (0)