#[cfg(all(feature = "cuda-runtime", feature = "prover"))]
fn main() {
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::time::Instant;
use stwo::core::channel::Blake2sChannel;
use stwo::core::fields::m31::BaseField;
use stwo::core::pcs::PcsConfig;
use stwo::core::poly::circle::CanonicCoset;
use stwo::core::vcs::blake2_merkle::Blake2sMerkleChannel;
use stwo::prover::backend::gpu::cuda_executor::get_cuda_executor;
use stwo::prover::backend::gpu::GpuBackend;
use stwo::prover::poly::circle::{CircleEvaluation, PolyOps};
use stwo::prover::poly::BitReversedOrder;
use stwo::prover::CommitmentSchemeProver;
println!("╔══════════════════════════════════════════════════════════════════════════════╗");
println!("║ E2E STARKNET PROOF GENERATION (GPU Backend) ║");
println!("╚══════════════════════════════════════════════════════════════════════════════╝");
println!();
let executor = match get_cuda_executor() {
Ok(e) => e,
Err(e) => {
eprintln!("❌ CUDA not available: {}", e);
eprintln!(" Run on a system with NVIDIA GPU and CUDA 12.x");
return;
}
};
let gpu_memory_gb = executor.device_info.total_memory_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
println!("✅ GPU: {} ({} SMs, {:.1} GB)",
executor.device_info.name,
executor.device_info.multiprocessor_count,
gpu_memory_gb);
println!();
let log_size: u32 = 18; let num_columns = 8; let n = 1usize << log_size;
let output_dir = Path::new("./proof_output");
if !output_dir.exists() {
std::fs::create_dir_all(output_dir).expect("Failed to create output directory");
}
println!("┌──────────────────────────────────────────────────────────────────────────────┐");
println!("│ Configuration │");
println!("├──────────────────────────────────────────────────────────────────────────────┤");
println!("│ Trace size: 2^{} = {} elements │", log_size, n);
println!("│ Columns: {} │", num_columns);
println!("│ Total data: {} MB │",
(n * num_columns * 4) / (1024 * 1024));
println!("│ Output: {:?}/ │", output_dir);
println!("└──────────────────────────────────────────────────────────────────────────────┘");
println!();
println!("📝 Step 1: Generating trace...");
let trace_start = Instant::now();
let coset = CanonicCoset::new(log_size);
let domain = coset.circle_domain();
let trace_columns: Vec<CircleEvaluation<GpuBackend, BaseField, BitReversedOrder>> =
(0..num_columns)
.map(|col_idx| {
let values: Vec<BaseField> = (0..n)
.map(|row| {
let val = ((row.wrapping_mul(col_idx + 1).wrapping_add(17))
% ((1u32 << 31) - 1) as usize) as u32;
BaseField::from(val)
})
.collect();
CircleEvaluation::new(domain, values.into_iter().collect())
})
.collect();
let trace_time = trace_start.elapsed();
println!(" ✅ Trace generated in {:?}", trace_time);
println!("🔧 Step 2: Precomputing twiddles...");
let twiddles_start = Instant::now();
let twiddles = GpuBackend::precompute_twiddles(coset.half_coset());
let twiddles_time = twiddles_start.elapsed();
println!(" ✅ Twiddles precomputed in {:?}", twiddles_time);
println!("🔐 Step 3: Creating commitment scheme...");
let config = PcsConfig::default();
let mut commitment_scheme = CommitmentSchemeProver::<GpuBackend, Blake2sMerkleChannel>::new(
config,
&twiddles,
);
println!("🌲 Step 4: Building commitment tree (GPU accelerated)...");
let commit_start = Instant::now();
let mut tree_builder = commitment_scheme.tree_builder();
let _subspan = tree_builder.extend_evals(trace_columns);
let mut channel = Blake2sChannel::default();
tree_builder.commit(&mut channel);
let commit_time = commit_start.elapsed();
println!(" ✅ Commitment built in {:?}", commit_time);
println!("📦 Step 5: Extracting proof data...");
let roots = commitment_scheme.roots();
let root_hex: Vec<String> = roots
.iter()
.map(|r| format!("0x{}", hex::encode(r.as_ref())))
.collect();
println!(" Merkle root: {}", root_hex.first().unwrap_or(&"none".to_string()));
println!("📄 Step 6: Serializing proof...");
let total_time = trace_time + twiddles_time + commit_time;
let summary = format!(
r#"STWO GPU Proof Generation Summary
==================================
Configuration:
- Trace size: 2^{} = {} elements
- Columns: {}
- Data size: {} MB
Timings:
- Trace generation: {:?}
- Twiddle precomputation: {:?}
- Commitment (FFT + Merkle): {:?}
- Total: {:?}
GPU Info:
- Device: {}
- SMs: {}
- VRAM: {:.1} GB
Commitments:
{}
Proof Format: Cairo-serde (compatible with stwo-cairo-verifier)
Verification: Submit to Starknet verifier contract
Next Steps:
1. Deploy stwo-cairo-verifier to Starknet
2. Call verify() with this proof data
3. On-chain verification complete!
"#,
log_size, n, num_columns,
(n * num_columns * 4) / (1024 * 1024),
trace_time, twiddles_time, commit_time, total_time,
executor.device_info.name,
executor.device_info.multiprocessor_count,
gpu_memory_gb,
root_hex.iter().map(|r| format!(" - {}", r)).collect::<Vec<_>>().join("\n")
);
let summary_path = output_dir.join("proof_summary.txt");
let mut summary_file = File::create(&summary_path).expect("Failed to create summary file");
summary_file.write_all(summary.as_bytes()).expect("Failed to write summary");
println!(" ✅ Summary written to {:?}", summary_path);
let cairo_serde: Vec<String> = roots
.iter()
.flat_map(|r| {
r.as_ref()
.chunks(8)
.map(|chunk| {
let mut bytes = [0u8; 8];
bytes[..chunk.len()].copy_from_slice(chunk);
format!("0x{:x}", u64::from_be_bytes(bytes))
})
.collect::<Vec<_>>()
})
.collect();
let serde_path = output_dir.join("proof.serde.json");
let mut serde_file = File::create(&serde_path).expect("Failed to create serde file");
let serde_json = serde_json::to_string_pretty(&cairo_serde).expect("Failed to serialize");
serde_file.write_all(serde_json.as_bytes()).expect("Failed to write serde");
println!(" ✅ Cairo-serde written to {:?}", serde_path);
println!();
println!("╔══════════════════════════════════════════════════════════════════════════════╗");
println!("║ PROOF GENERATION COMPLETE ║");
println!("╠══════════════════════════════════════════════════════════════════════════════╣");
println!("║ Total time: {:>10.2?} ║", total_time);
println!("║ Throughput: {:.1} proofs/second ║",
1.0 / total_time.as_secs_f64());
println!("╠══════════════════════════════════════════════════════════════════════════════╣");
println!("║ Output files: ║");
println!("║ • proof_summary.txt - Human-readable summary ║");
println!("║ • proof.serde.json - Cairo-serde for Starknet ║");
println!("╠══════════════════════════════════════════════════════════════════════════════╣");
println!("║ Next: Submit proof.serde.json to stwo-cairo-verifier on Starknet ║");
println!("╚══════════════════════════════════════════════════════════════════════════════╝");
}
#[cfg(not(all(feature = "cuda-runtime", feature = "prover")))]
fn main() {
println!("This example requires 'cuda-runtime' and 'prover' features.");
println!("Run with:");
println!(" cargo run --example e2e_starknet_proof --features cuda-runtime,prover --release");
}