1use std::{iter::zip, sync::Arc};
2
3use itertools::Itertools;
4use openvm_cuda_common::{
5 copy::{MemCopyD2H, MemCopyH2D},
6 d_buffer::DeviceBuffer,
7 memory_manager::MemTracker,
8 stream::GpuDeviceCtx,
9};
10use openvm_stark_backend::{
11 proof::{MerkleProof, WhirProof},
12 prover::MatrixDimensions,
13 SystemParams,
14};
15use p3_field::{BasedVectorSpace, PrimeCharacteristicRing, TwoAdicField};
16use p3_util::log2_strict_usize;
17use tracing::instrument;
18
19use crate::{
20 base::DeviceMatrix,
21 cuda::{
22 batch_ntt_small::batch_ntt_small,
23 matrix::{batch_expand_pad, split_ext_to_base_col_major_matrix},
24 mle_interpolate::mle_interpolate_stage_ext,
25 poly::{eval_poly_ext_at_point_from_base, transpose_fp_to_fpext_vec},
26 whir::{
27 _whir_sumcheck_coeff_moments_required_temp_buffer_size, w_moments_accumulate,
28 whir_algebraic_batch_traces, whir_fold_coeffs_and_moments,
29 whir_sumcheck_coeff_moments_round,
30 },
31 },
32 hash_scheme::GpuHashScheme,
33 merkle_tree::{MerkleProofQueryDigest, MerkleTreeConstructor, MerkleTreeGpu},
34 ntt::batch_ntt,
35 poly::evals_eq_hypercube,
36 prelude::{D_EF, EF, F},
37 sponge::GpuFiatShamirTranscript,
38 stacked_pcs::rs_code_matrix,
39 stacked_reduction::StackedPcsData2,
40 WhirProverError,
41};
42
43#[repr(C)]
44pub(crate) struct BatchingTracePacket {
45 ptr: *const F,
47 height: u32,
49 width: u32,
51 stacked_row_start: u32,
53 mu_idx: u32,
55}
56
57#[instrument(
58 name = "prover.openings.whir",
59 level = "info",
60 skip_all,
61 fields(phase = "prover")
62)]
63pub fn prove_whir_opening_gpu<HS, TS>(
64 params: &SystemParams,
65 transcript: &mut TS,
66 mut stacked_per_commit: Vec<StackedPcsData2<HS::Digest>>,
67 u: &[EF],
68 device_ctx: &GpuDeviceCtx,
69) -> Result<WhirProof<HS::SC>, WhirProverError>
70where
71 HS: GpuHashScheme,
72 TS: GpuFiatShamirTranscript<HS::SC>,
73 HS::MerkleHash: MerkleTreeConstructor,
74 HS::Digest: MerkleProofQueryDigest,
75{
76 let mem = MemTracker::start("prover.prove_whir_opening");
77 let l_skip = params.l_skip;
78 let log_blowup = params.log_blowup;
79 let k_whir = params.k_whir();
80 let whir_params = params.whir();
81 let log_final_poly_len = params.log_final_poly_len();
82
83 let height = stacked_per_commit[0].layout().height();
84 debug_assert!(stacked_per_commit
85 .iter()
86 .all(|d| d.layout().height() == height));
87 let mut m = log2_strict_usize(height);
88 assert_eq!(m, u.len());
89 debug_assert!(m >= l_skip);
90
91 let mu_pow_witness = transcript
94 .grind_gpu(whir_params.mu_pow_bits, device_ctx)
95 .map_err(WhirProverError::MuGrind)?;
96 let mu = transcript.sample_ext();
99 let num_commits = stacked_per_commit.len();
100
101 let mut f_ple_evals = DeviceBuffer::<F>::with_capacity_on(height * D_EF, device_ctx);
103 {
105 let mut packets = Vec::new();
106 let mut total_stacked_width = 0u32;
107 for stacked in &stacked_per_commit {
108 let layout = stacked.layout();
109 for (trace, &idx) in zip(&stacked.traces, &layout.mat_starts) {
110 let (_, _, s) = layout.sorted_cols[idx];
111 let packet = BatchingTracePacket {
112 ptr: trace.buffer().as_ptr(),
113 height: trace.height() as u32,
114 width: trace.width() as u32,
115 stacked_row_start: s.row_idx as u32,
116 mu_idx: total_stacked_width + s.col_idx as u32,
117 };
118 packets.push(packet);
119 }
120 total_stacked_width += layout.width() as u32;
121 }
122 let mu_powers = mu.powers().take(total_stacked_width as usize).collect_vec();
123 let d_mu_powers = mu_powers.to_device_on(device_ctx)?;
124 let d_packets = packets.to_device_on(device_ctx)?;
125 unsafe {
130 whir_algebraic_batch_traces(
131 &mut f_ple_evals,
132 &d_packets,
133 &d_mu_powers,
134 1 << l_skip,
135 device_ctx.stream.as_raw(),
136 )
137 .map_err(WhirProverError::AlgebraicBatch)?;
138 }
139 for stacked in &mut stacked_per_commit {
140 if stacked.inner.tree.backing_matrix.is_some() {
142 stacked.traces.clear();
143 }
144 }
145 } unsafe {
152 let num_poly = f_ple_evals.len() >> l_skip;
153 batch_ntt_small(
154 &mut f_ple_evals,
155 l_skip,
156 num_poly,
157 true,
158 device_ctx.stream.as_raw(),
159 )
160 .map_err(WhirProverError::CustomBatchIntt)?;
161 }
162 let mut f_coeffs = DeviceBuffer::<EF>::with_capacity_on(height, device_ctx);
163 unsafe {
165 transpose_fp_to_fpext_vec(&mut f_coeffs, &f_ple_evals, device_ctx.stream.as_raw())
166 .map_err(WhirProverError::Transpose)?;
167 }
168 drop(f_ple_evals);
169 for i in 0..l_skip {
174 let step = 1u32 << i;
175 unsafe {
177 mle_interpolate_stage_ext(&mut f_coeffs, step, false, device_ctx.stream.as_raw())
178 .map_err(|error| WhirProverError::MleInterpolate { error, step })?;
179 }
180 }
181
182 debug_assert_eq!((m - log_final_poly_len) % k_whir, 0);
183 let num_whir_rounds = (m - log_final_poly_len) / k_whir;
184 assert!(num_whir_rounds > 0);
185
186 let mut w_moments = DeviceBuffer::<EF>::with_capacity_on(1 << m, device_ctx);
190 unsafe {
191 evals_eq_hypercube(&mut w_moments, u, device_ctx).map_err(WhirProverError::EvalEq)?;
192 }
193
194 let mut whir_sumcheck_polys: Vec<[EF; 2]> = vec![];
195 let mut codeword_commits = vec![];
196 let mut ood_values = vec![];
197 let mut initial_round_opened_rows: Vec<Vec<Vec<Vec<F>>>> = vec![vec![]; num_commits];
199 let mut initial_round_merkle_proofs: Vec<Vec<MerkleProof<HS::Digest>>> = vec![];
200 let mut codeword_opened_values: Vec<Vec<Vec<EF>>> = vec![];
201 let mut codeword_merkle_proofs: Vec<Vec<MerkleProof<HS::Digest>>> = vec![];
202 let mut folding_pow_witnesses = vec![];
203 let mut query_phase_pow_witnesses = vec![];
204 let mut rs_tree = None;
205 let mut log_rs_domain_size = m + log_blowup;
206 let mut final_poly = None;
207
208 let mut d_s_evals = DeviceBuffer::<EF>::with_capacity_on(2, device_ctx);
209 let mut d_sumcheck_tmp = DeviceBuffer::<EF>::new();
210
211 mem.tracing_info("before_whir_rounds");
212 for (whir_round, round_params) in whir_params.rounds.iter().enumerate() {
214 let is_last_round = whir_round == num_whir_rounds - 1;
215 for round in 0..k_whir {
217 let f_height = 1 << (m - round);
219 debug_assert!(
220 f_coeffs.len() >= f_height,
221 "f_coeffs has length {}, expected 2^{} for m={m}, round={round}",
222 f_coeffs.len(),
223 m - round
224 );
225 debug_assert!(w_moments.len() >= f_height);
226 let output_height = f_height / 2;
227 let tmp_buffer_capacity =
228 unsafe { _whir_sumcheck_coeff_moments_required_temp_buffer_size(f_height as u32) };
229 if d_sumcheck_tmp.len() < tmp_buffer_capacity as usize {
230 d_sumcheck_tmp =
231 DeviceBuffer::<EF>::with_capacity_on(tmp_buffer_capacity as usize, device_ctx);
232 }
233 let mut new_f_coeffs = DeviceBuffer::<EF>::with_capacity_on(output_height, device_ctx);
234 let mut new_w_moments = DeviceBuffer::<EF>::with_capacity_on(output_height, device_ctx);
235 unsafe {
239 whir_sumcheck_coeff_moments_round(
240 &f_coeffs,
241 &w_moments,
242 &mut d_s_evals,
243 &mut d_sumcheck_tmp,
244 f_height as u32,
245 device_ctx.stream.as_raw(),
246 )
247 .map_err(|error| WhirProverError::SumcheckMleRound {
248 error,
249 whir_round,
250 round,
251 })?;
252 }
253 let s_evals = d_s_evals.to_host_on(device_ctx)?;
254 for &eval in &s_evals {
255 transcript.observe_ext(eval);
256 }
257 whir_sumcheck_polys.push(s_evals.try_into().unwrap());
258
259 folding_pow_witnesses.push(
260 transcript
261 .grind_gpu(whir_params.folding_pow_bits, device_ctx)
262 .map_err(WhirProverError::FoldingGrind)?,
263 );
264 let alpha = transcript.sample_ext();
265
266 unsafe {
271 whir_fold_coeffs_and_moments(
272 &f_coeffs,
273 &w_moments,
274 &mut new_f_coeffs,
275 &mut new_w_moments,
276 alpha,
277 f_height as u32,
278 device_ctx.stream.as_raw(),
279 )
280 .map_err(|error| WhirProverError::FoldMle {
281 error,
282 whir_round,
283 round,
284 })?;
285 }
286 f_coeffs = new_f_coeffs;
287 w_moments = new_w_moments;
288 }
289 let f_height = 1 << (m - k_whir);
292 debug_assert!(f_coeffs.len() >= f_height);
293 debug_assert_eq!(size_of::<EF>() / size_of::<F>(), D_EF);
294 let mut g_coeffs = DeviceBuffer::<F>::with_capacity_on(f_height * D_EF, device_ctx);
295 unsafe {
298 split_ext_to_base_col_major_matrix(
299 &mut g_coeffs,
300 &f_coeffs,
301 f_height as u64,
302 f_height as u32,
303 device_ctx.stream.as_raw(),
304 )
305 .map_err(|error| WhirProverError::SplitExtPoly { error, whir_round })?;
306 }
307 let (g_tree, z_0) = if !is_last_round {
308 let codeword_height = 1 << (log_rs_domain_size - 1);
309 let g_rs = DeviceBuffer::<F>::with_capacity_on(D_EF * codeword_height, device_ctx);
311 unsafe {
317 batch_expand_pad(
318 g_rs.as_mut_ptr(),
319 g_coeffs.as_ptr(),
320 D_EF as u32,
321 codeword_height as u32,
322 f_height as u32,
323 device_ctx.stream.as_raw(),
324 )
325 .map_err(|error| WhirProverError::BatchExpandPad { error, whir_round })?;
326
327 batch_ntt(
328 &g_rs,
329 (log_rs_domain_size - 1) as u32,
330 0u32,
331 D_EF as u32,
332 true,
333 false,
334 device_ctx,
335 );
336 }
337
338 let g_tree = MerkleTreeGpu::<F, HS::Digest>::new_with_hash::<HS::MerkleHash>(
339 DeviceMatrix::new(Arc::new(g_rs), codeword_height, D_EF),
340 1 << k_whir,
341 true,
342 device_ctx,
343 )
344 .map_err(WhirProverError::MerkleTree)?;
345 let g_commit = g_tree.root();
346 transcript.observe_commit(g_commit);
347 codeword_commits.push(g_commit);
348
349 let z_0 = transcript.sample_ext();
350 let g_opened_value = unsafe {
354 eval_poly_ext_at_point_from_base(&g_coeffs, 1 << (m - k_whir), z_0, device_ctx)
355 .map_err(|error| WhirProverError::EvalPolyAtPoint { error, whir_round })?
356 };
357 transcript.observe_ext(g_opened_value);
358 ood_values.push(g_opened_value);
359
360 (Some(g_tree), Some(z_0))
361 } else {
362 debug_assert_eq!(log_final_poly_len, m - k_whir);
364 let final_poly_len = 1 << log_final_poly_len;
365 let base_coeffs = g_coeffs.to_host_on(device_ctx)?;
366 debug_assert_eq!(base_coeffs.len(), D_EF * final_poly_len);
367 let mut coeffs = Vec::with_capacity(final_poly_len);
368 for i in 0..final_poly_len {
369 let coeff = EF::from_basis_coefficients_fn(|j| base_coeffs[j * final_poly_len + i]);
370 transcript.observe_ext(coeff);
371 coeffs.push(coeff);
372 }
373 final_poly = Some(coeffs);
374 (None, None)
375 };
376
377 let omega = F::two_adic_generator(log_rs_domain_size - k_whir);
379 let num_queries = round_params.num_queries;
380 let mut query_indices = Vec::with_capacity(num_queries);
381 query_phase_pow_witnesses.push(
382 transcript
383 .grind_gpu(whir_params.query_phase_pow_bits, device_ctx)
384 .map_err(WhirProverError::QueryPhaseGrind)?,
385 );
386 for _ in 0..num_queries {
388 let index = transcript.sample_bits(log_rs_domain_size - k_whir);
390 query_indices.push(index as usize);
391 }
392 if !is_last_round {
393 codeword_opened_values.push(vec![]);
394 codeword_merkle_proofs.push(vec![]);
395 }
396 if whir_round == 0 {
397 let mut backing_mats_owned = vec![None; stacked_per_commit.len()];
400 let mut backing_matrices = Vec::with_capacity(stacked_per_commit.len());
401 let mut trees = Vec::with_capacity(stacked_per_commit.len());
402 for (d, backing_mat_owned) in zip(&mut stacked_per_commit, &mut backing_mats_owned) {
403 trees.push(&d.inner.tree);
404 if let Some(matrix) = d.inner.tree.backing_matrix.as_ref() {
405 backing_matrices.push(matrix);
406 } else {
407 let layout = d.layout();
408 let traces = d.traces.iter().collect_vec();
409 debug_assert!(!traces.is_empty());
410 let backing_matrix =
411 rs_code_matrix(log_blowup, layout, &traces, &d.inner.matrix, device_ctx)
412 .map_err(WhirProverError::RsCodeMatrix)?;
413 d.traces.clear();
414 *backing_mat_owned = Some(backing_matrix);
415 backing_matrices.push(backing_mat_owned.as_ref().unwrap());
416 }
417 }
418 initial_round_merkle_proofs =
421 <MerkleTreeGpu<F, HS::Digest>>::batch_query_merkle_proofs(
422 trees.as_slice(),
423 &query_indices,
424 device_ctx,
425 )
426 .map_err(WhirProverError::MerkleTree)?;
427
428 let query_stride = trees[0].query_stride();
429 debug_assert!(
430 trees.iter().all(|tree| tree.query_stride() == query_stride),
431 "Merkle trees don't have same layer size"
432 );
433 let num_rows_per_query = trees[0].rows_per_query;
434 debug_assert!(
435 trees
436 .iter()
437 .all(|tree| tree.rows_per_query == num_rows_per_query),
438 "Merkle trees don't have same rows_per_query"
439 );
440
441 initial_round_opened_rows = MerkleTreeGpu::<F, HS::Digest>::batch_open_rows(
442 &backing_matrices,
443 &query_indices,
444 query_stride,
445 num_rows_per_query,
446 device_ctx,
447 )
448 .map_err(WhirProverError::MerkleTree)?
449 .into_iter()
450 .map(|rows_per_commit| {
451 rows_per_commit
452 .into_iter()
453 .map(|rows| {
454 let width = rows.len() / num_rows_per_query;
455 rows.chunks_exact(width).map(|row| row.to_vec()).collect()
456 })
457 .collect()
458 })
459 .collect();
460 debug_assert_eq!(
461 Arc::strong_count(&stacked_per_commit[0].inner),
462 1,
463 "common_main_pcs_data should be owned"
464 );
465 stacked_per_commit.clear(); mem.tracing_info("after_initial_whir_round");
467 } else {
468 let tree: &MerkleTreeGpu<F, HS::Digest> = rs_tree.as_ref().unwrap();
469 codeword_merkle_proofs[whir_round - 1] =
470 <MerkleTreeGpu<F, HS::Digest>>::batch_query_merkle_proofs(
471 &[tree],
472 &query_indices,
473 device_ctx,
474 )
475 .map_err(WhirProverError::MerkleTree)?
476 .pop()
477 .expect("exactly 1 tree");
478 codeword_opened_values[whir_round - 1] =
479 MerkleTreeGpu::<F, HS::Digest>::batch_open_rows(
480 &[tree.backing_matrix.as_ref().unwrap()],
481 &query_indices,
482 tree.query_stride(),
483 tree.rows_per_query,
484 device_ctx,
485 )
486 .map_err(WhirProverError::MerkleTree)?
487 .pop()
488 .unwrap()
489 .into_iter()
490 .map(EF::reconstitute_from_base)
491 .collect();
492 }
493 rs_tree = g_tree;
494
495 let gamma = transcript.sample_ext();
499
500 if !is_last_round {
501 let log_height = (m - k_whir) as u32;
504 let z0 = z_0.unwrap();
505 let z_points = query_indices
506 .iter()
507 .map(|&index| omega.exp_u64(index as u64))
508 .collect_vec();
509
510 let mut z0_pows2 = Vec::with_capacity(log_height as usize);
511 let mut z0_pow = z0;
512 for _ in 0..log_height {
513 z0_pows2.push(z0_pow);
514 z0_pow = z0_pow.square();
515 }
516
517 let mut z_pows2 = Vec::with_capacity(num_queries * log_height as usize);
518 for z in &z_points {
519 let mut z_pow = *z;
520 for _ in 0..log_height {
521 z_pows2.push(z_pow);
522 z_pow = z_pow.square();
523 }
524 }
525
526 let d_z0_pows2 = z0_pows2.to_device_on(device_ctx)?;
527 let d_z_pows2 = z_pows2.to_device_on(device_ctx)?;
528 unsafe {
529 w_moments_accumulate(
530 &mut w_moments,
531 &d_z0_pows2,
532 &d_z_pows2,
533 gamma,
534 num_queries as u32,
535 log_height,
536 device_ctx.stream.as_raw(),
537 )
538 .map_err(|error| WhirProverError::WMomentsAccumulate { error, whir_round })?;
539 }
540 }
541
542 m -= k_whir;
543 log_rs_domain_size -= 1;
544 }
545
546 mem.emit_metrics();
547 Ok(WhirProof {
548 mu_pow_witness,
549 whir_sumcheck_polys,
550 codeword_commits,
551 ood_values,
552 folding_pow_witnesses,
553 query_phase_pow_witnesses,
554 initial_round_opened_rows,
555 initial_round_merkle_proofs,
556 codeword_opened_values,
557 codeword_merkle_proofs,
558 final_poly: final_poly.unwrap(),
559 })
560}
561
562#[cfg(test)]
563mod tests {
564 use std::sync::Arc;
565
566 use itertools::Itertools;
567 use openvm_stark_backend::{
568 keygen::types::MultiStarkProvingKey,
569 prover::{
570 stacked_pcs::stacked_commit, CpuColMajorBackend, DeviceDataTransporter, ProvingContext,
571 },
572 test_utils::{CachedFixture11, FibFixture, TestFixture},
573 verifier::whir::{verify_whir, VerifyWhirError},
574 StarkEngine, StarkProtocolConfig, SystemParams, WhirConfig, WhirParams,
575 WhirProximityStrategy,
576 };
577 use openvm_stark_sdk::{
578 config::{
579 baby_bear_poseidon2::{
580 default_duplex_sponge, BabyBearPoseidon2RefEngine, DuplexSponge,
581 },
582 log_up_params::log_up_security_params_baby_bear_100_bits,
583 },
584 utils::setup_tracing_with_log_level,
585 };
586 use rand::{rngs::StdRng, SeedableRng};
587 use test_case::test_case;
588 use tracing::Level;
589
590 use crate::{
591 prelude::SC, sponge::DuplexSpongeGpu, stacked_reduction::StackedPcsData2,
592 whir::prove_whir_opening_gpu, BabyBearPoseidon2GpuEngine, GpuBackend,
593 };
594
595 fn run_whir_test_gpu(
598 params: SystemParams,
599 pk: MultiStarkProvingKey<SC>,
600 ctx: ProvingContext<CpuColMajorBackend<SC>>,
601 ) -> Result<(), VerifyWhirError> {
602 let engine = BabyBearPoseidon2GpuEngine::new(params.clone());
603 let device = engine.device();
604 let mut rng = StdRng::seed_from_u64(0);
605 let (z_prism, z_cube) = openvm_backend_tests::generate_random_z(¶ms, &mut rng);
606
607 let common_main_traces = ctx
608 .common_main_traces()
609 .map(|(_, trace)| trace)
610 .collect_vec();
611 let (common_main_commit, common_main_pcs_data) = stacked_commit(
613 engine.config().hasher(),
614 params.l_skip,
615 params.n_stack,
616 params.log_blowup,
617 params.k_whir(),
618 &common_main_traces,
619 )
620 .unwrap();
621 let d_common_main_traces = common_main_traces
622 .iter()
623 .map(|t| {
624 <_ as DeviceDataTransporter<SC, GpuBackend>>::transport_matrix_to_device(device, t)
625 })
626 .collect_vec();
627 let d_common_main_pcs_data =
628 <_ as DeviceDataTransporter<SC, GpuBackend>>::transport_pcs_data_to_device(
629 device,
630 &common_main_pcs_data,
631 );
632
633 let mut stacking_openings = vec![openvm_backend_tests::stacking_openings_for_matrix(
634 ¶ms,
635 &z_prism,
636 &common_main_pcs_data.matrix,
637 )];
638 let mut commits = vec![common_main_commit];
639 let mut stacked_per_commit = vec![StackedPcsData2 {
640 inner: Arc::new(d_common_main_pcs_data),
641 traces: d_common_main_traces,
642 }];
643 for (air_id, air_ctx) in ctx.per_trace {
644 for data in pk.per_air[air_id]
645 .preprocessed_data
646 .iter()
647 .chain(air_ctx.cached_mains.iter().map(|cd| &cd.data))
648 {
649 let trace =
650 <_ as DeviceDataTransporter<SC, GpuBackend>>::transport_matrix_to_device(
651 device,
652 &data.mat_view(0).to_matrix(),
653 );
654 commits.push(data.commit().unwrap());
655 stacking_openings.push(openvm_backend_tests::stacking_openings_for_matrix(
656 ¶ms,
657 &z_prism,
658 &data.matrix,
659 ));
660 let d_data =
661 <_ as DeviceDataTransporter<SC, GpuBackend>>::transport_pcs_data_to_device(
662 device, data,
663 );
664 stacked_per_commit.push(StackedPcsData2 {
665 inner: Arc::new(d_data),
666 traces: vec![trace],
667 });
668 }
669 }
670
671 let mut prover_sponge = DuplexSpongeGpu::default();
672
673 let proof = prove_whir_opening_gpu::<crate::DefaultHashScheme, _>(
674 ¶ms,
675 &mut prover_sponge,
676 stacked_per_commit,
677 &z_cube,
678 &device.device_ctx,
679 )
680 .unwrap();
681
682 let mut verifier_sponge = default_duplex_sponge();
683 verify_whir(
684 &mut verifier_sponge,
685 engine.config(),
686 &proof,
687 &stacking_openings,
688 &commits,
689 &z_cube,
690 )
691 }
692
693 fn run_whir_fixture_test_gpu<F>(
694 params: SystemParams,
695 engine: &BabyBearPoseidon2RefEngine<DuplexSponge>,
696 fx: F,
697 ) -> Result<(), VerifyWhirError>
698 where
699 F: TestFixture<SC>,
700 {
701 let (pk, _vk) = fx.keygen(engine);
702 let ctx = fx.generate_proving_ctx().into_sorted();
703 run_whir_test_gpu(params, pk, ctx)
704 }
705
706 fn whir_test_params(k_whir: usize, log_final_poly_len: usize) -> WhirParams {
707 WhirParams {
708 k: k_whir,
709 log_final_poly_len,
710 query_phase_pow_bits: 2,
711 folding_pow_bits: 1,
712 mu_pow_bits: 3,
713 proximity: WhirProximityStrategy::UniqueDecoding,
714 }
715 }
716
717 fn whir_test_system_params(
718 n_stack: usize,
719 log_blowup: usize,
720 k_whir: usize,
721 log_final_poly_len: usize,
722 ) -> SystemParams {
723 let l_skip = 2;
724 let w_stack = 8;
725 let whir = WhirConfig::new(
726 log_blowup,
727 l_skip + n_stack,
728 whir_test_params(k_whir, log_final_poly_len),
729 10,
730 );
731 SystemParams {
732 l_skip: 2,
733 n_stack,
734 w_stack,
735 log_blowup,
736 whir,
737 logup: log_up_security_params_baby_bear_100_bits(0.0),
738 max_constraint_degree: 3,
739 }
740 }
741
742 #[test_case(0, 1, 1, 0)]
743 #[test_case(2, 1, 1, 2)]
744 #[test_case(2, 1, 2, 0)]
745 #[test_case(2, 1, 3, 1)]
746 #[test_case(2, 1, 4, 0)]
747 #[test_case(2, 2, 4, 0)]
748 fn test_whir_single_fib_gpu(
749 n_stack: usize,
750 log_blowup: usize,
751 k_whir: usize,
752 log_final_poly_len: usize,
753 ) -> Result<(), VerifyWhirError> {
754 setup_tracing_with_log_level(Level::DEBUG);
755
756 let params = whir_test_system_params(n_stack, log_blowup, k_whir, log_final_poly_len);
757 let engine = BabyBearPoseidon2RefEngine::<DuplexSponge>::new(params.clone());
758 let height = 1 << params.log_stacked_height();
759
760 run_whir_fixture_test_gpu(params, &engine, FibFixture::new(0, 1, height))
761 }
762
763 #[test_case(2, 1, 1, 2)]
764 #[test_case(2, 1, 2, 0)]
765 #[test_case(2, 1, 3, 1)]
766 #[test_case(2, 1, 4, 0)]
767 #[test_case(2, 2, 4, 0)]
768 fn test_whir_cached_gpu(
769 n_stack: usize,
770 log_blowup: usize,
771 k_whir: usize,
772 log_final_poly_len: usize,
773 ) -> Result<(), VerifyWhirError> {
774 setup_tracing_with_log_level(Level::DEBUG);
775
776 let params = whir_test_system_params(n_stack, log_blowup, k_whir, log_final_poly_len);
777 let engine = BabyBearPoseidon2RefEngine::<DuplexSponge>::new(params.clone());
778
779 run_whir_fixture_test_gpu(
780 params,
781 &engine,
782 CachedFixture11::new(engine.config().clone()),
783 )
784 }
785}