diff --git a/Cargo.lock b/Cargo.lock index d15f61c316..88294e9f64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3069,6 +3069,23 @@ dependencies = [ "tracer", ] +[[package]] +name = "jolt-kernels" +version = "0.1.0" +dependencies = [ + "jolt-field", + "jolt-lookup-tables", + "jolt-poly", + "jolt-program", + "jolt-r1cs", + "jolt-riscv", + "jolt-sumcheck", + "jolt-transcript", + "jolt-witness", + "rayon", + "tracing", +] + [[package]] name = "jolt-lookup-tables" version = "0.1.0" @@ -3171,6 +3188,22 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "jolt-prover" +version = "0.0.0" +dependencies = [ + "jolt-dory", + "jolt-field", + "jolt-kernels", + "jolt-openings", + "jolt-poly", + "jolt-transcript", + "jolt-verifier", + "jolt-witness", + "rayon", + "tracing", +] + [[package]] name = "jolt-r1cs" version = "0.1.0" @@ -3253,6 +3286,21 @@ dependencies = [ "sha3 0.11.0", ] +[[package]] +name = "jolt-verifier" +version = "0.0.0" +dependencies = [ + "jolt-dory", + "jolt-field", + "jolt-lookup-tables", + "jolt-openings", + "jolt-poly", + "jolt-sumcheck", + "jolt-transcript", + "serde", + "tracing", +] + [[package]] name = "jolt-witness" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 81b7728ae6..66a592b68e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ members = [ "crates/jolt-transcript", "crates/jolt-witness", "crates/bolt", + "crates/jolt-kernels", + "crates/jolt-prover", + "crates/jolt-verifier", "crates/jolt-profiling", "crates/jolt-field", "jolt-core", @@ -379,6 +382,8 @@ common = { path = "./common", default-features = false } tracer = { path = "./tracer", default-features = false } jolt-core = { path = "./jolt-core", default-features = false } jolt-crypto = { path = "./crates/jolt-crypto" } +jolt-dory = { path = "./crates/jolt-dory" } +jolt-hyperkzg = { path = "./crates/jolt-hyperkzg" } jolt-field = { path = "./crates/jolt-field" } jolt-openings = { path = "./crates/jolt-openings" } jolt-poly = { path = "./crates/jolt-poly" } @@ -387,6 +392,9 @@ jolt-sumcheck = { path = "./crates/jolt-sumcheck" } jolt-r1cs = { path = "./crates/jolt-r1cs" } jolt-witness = { path = "./crates/jolt-witness" } bolt = { path = "./crates/bolt" } +jolt-kernels = { path = "./crates/jolt-kernels" } +jolt-prover = { path = "./crates/jolt-prover" } +jolt-verifier = { path = "./crates/jolt-verifier" } jolt-riscv = { path = "./crates/jolt-riscv", default-features = false } jolt-program = { path = "./crates/jolt-program", default-features = false } jolt-lookup-tables = { path = "./crates/jolt-lookup-tables" } diff --git a/crates/bolt/src/emit/rust/artifacts.rs b/crates/bolt/src/emit/rust/artifacts.rs index ec2d2a6c7f..1b9936fa77 100644 --- a/crates/bolt/src/emit/rust/artifacts.rs +++ b/crates/bolt/src/emit/rust/artifacts.rs @@ -426,9 +426,18 @@ fn generated_crate( path: format!("src/stages/{}.rs", artifact.stage.module_name()), source: artifact.source.source, })); + for file in &mut files { + file.source = normalized_generated_source(&file.source); + } GeneratedCrate { crate_name, files } } +fn normalized_generated_source(source: &str) -> String { + let mut normalized = source.trim_end_matches(char::is_whitespace).to_owned(); + normalized.push('\n'); + normalized +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum ManifestMode<'a> { Standalone { dependency_root: &'a str }, diff --git a/crates/bolt/src/protocols/jolt/artifacts.rs b/crates/bolt/src/protocols/jolt/artifacts.rs index 0a13379d7d..7f1fae8c5c 100644 --- a/crates/bolt/src/protocols/jolt/artifacts.rs +++ b/crates/bolt/src/protocols/jolt/artifacts.rs @@ -322,8 +322,8 @@ pub use verifier::{ verify_jolt_through_stage6_with_programs, verify_jolt_through_stage7, verify_jolt_through_stage7_with_programs, verify_jolt_with_programs, JoltEvaluationProof, JoltEvaluationProofError, JoltNamedEval, JoltProof, JoltStage2RamAccess, JoltStage2RamData, - JoltStage2RamOutputLayout, JoltStageChallengeVector, JoltStageExecutionArtifacts, - JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, JoltStage6VerifierData, + JoltStage2RamOutputLayout, JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, + JoltStage6VerifierData, JoltStageChallengeVector, JoltStageExecutionArtifacts, JoltStageOpeningInputValue, JoltStageProof, JoltSumcheckOutput, JoltVerificationArtifacts, JoltVerifierInputs, JoltVerifierPrograms, JoltVerifierTarget, JoltVerifyError, };" @@ -337,7 +337,7 @@ fn jolt_evaluation_role_api_extension() -> ProtocolArtifactExtension { required_artifact_stages: vec!["stage8".to_owned()], prover: ProtocolProverApiExtension { lib_module: jolt_prover_lib_module(), - imports: "#![expect(\n clippy::too_many_arguments,\n reason = \"generated prover helpers mirror staged protocol ABIs\"\n)]\n\nuse jolt_dory::{DoryCommitment, DoryHint, DoryProverSetup, DoryScheme};\nuse jolt_field::{Field, Fr};\nuse jolt_kernels::{stage1, stage2, stage3, stage4, stage5, stage6, stage7};\nuse jolt_openings::{AdditivelyHomomorphic, CommitmentScheme};\nuse jolt_poly::{EqPolynomial, Polynomial};\nuse jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript};\nuse jolt_verifier::{JoltEvaluationProof, JoltNamedEval, JoltProof, JoltStage2RamAccess, JoltStage2RamData, JoltStage2RamOutputLayout, JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, JoltStage6VerifierData, JoltStageChallengeVector, JoltStageExecutionArtifacts, JoltStageOpeningInputValue, JoltStageProof, JoltSumcheckOutput};\nuse jolt_witness::{stage4_ram_val_init_opening, CycleInput, Stage45SparseTraceWitness, Stage6BytecodeEntry as WitnessStage6BytecodeEntry, Stage6WitnessParams, Stage6WitnessPolynomials, Stage6WitnessSlices};\nuse rayon::prelude::*;\n\n".to_owned(), + imports: "#![expect(\n clippy::too_many_arguments,\n reason = \"generated prover helpers mirror staged protocol ABIs\"\n)]\n\nuse jolt_dory::{DoryCommitment, DoryHint, DoryProverSetup, DoryScheme};\nuse jolt_field::Fr;\nuse jolt_kernels::{stage1, stage2, stage3, stage4, stage5, stage6, stage7};\nuse jolt_openings::{AdditivelyHomomorphic, CommitmentScheme};\nuse jolt_poly::{EqPolynomial, Polynomial};\nuse jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript};\nuse jolt_verifier::{JoltEvaluationProof, JoltNamedEval, JoltProof, JoltStage2RamAccess, JoltStage2RamData, JoltStage2RamOutputLayout, JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, JoltStage6VerifierData, JoltStageChallengeVector, JoltStageExecutionArtifacts, JoltStageOpeningInputValue, JoltStageProof, JoltSumcheckOutput};\nuse jolt_witness::{stage4_ram_val_init_opening, CycleInput, Stage45SparseTraceWitness, Stage6BytecodeEntry as WitnessStage6BytecodeEntry, Stage6WitnessParams, Stage6WitnessPolynomials, Stage6WitnessSlices};\nuse rayon::prelude::*;\n\n".to_owned(), input_fields: " pub stage7_openings: Option<&'a [stage7::Stage7OpeningInputValue]>,\n" .to_owned(), @@ -357,7 +357,7 @@ fn jolt_evaluation_role_api_extension() -> ProtocolArtifactExtension { }, verifier: ProtocolVerifierApiExtension { lib_module: jolt_verifier_lib_module(), - imports: "use std::collections::BTreeMap;\n\nuse jolt_dory::{DoryCommitment, DoryProof, DoryScheme, DoryVerifierSetup};\nuse jolt_field::{Field, Fr};\nuse jolt_openings::{AdditivelyHomomorphic, CommitmentScheme, OpeningsError};\nuse jolt_poly::EqPolynomial;\nuse jolt_transcript::{AppendToTranscript, LabelWithCount, Transcript};\n".to_owned(), + imports: "use std::collections::BTreeMap;\n\nuse jolt_dory::{DoryCommitment, DoryProof, DoryScheme, DoryVerifierSetup};\nuse jolt_field::Fr;\nuse jolt_openings::{AdditivelyHomomorphic, CommitmentScheme, OpeningsError};\nuse jolt_poly::EqPolynomial;\nuse jolt_transcript::{AppendToTranscript, LabelWithCount, Transcript};\n".to_owned(), proof_fields: " pub evaluation: Option,\n".to_owned(), proof_items: "pub type JoltStage2RamAccess = crate::stages::stage2::Stage2RamAccess;\npub type JoltStage2RamOutputLayout = crate::stages::stage2::Stage2RamOutputLayout;\npub type JoltStage2RamData<'a> = crate::stages::stage2::Stage2RamData<'a>;\npub type JoltStageChallengeVector = crate::stages::common::StageChallengeVector;\npub type JoltStageExecutionArtifacts = crate::stages::common::StageExecutionArtifacts;\npub type JoltStageOpeningInputValue = crate::stages::common::StageOpeningInputValue;\n\n#[derive(Clone, Debug)]\npub struct JoltEvaluationProof {\n pub joint_opening_proof: DoryProof,\n}\n\n".to_owned(), inputs_derive: Some("#[derive(Clone, Copy)]".to_owned()), diff --git a/crates/bolt/src/protocols/jolt/emit/rust/commitment.rs b/crates/bolt/src/protocols/jolt/emit/rust/commitment.rs index 66186d2419..e5460c75c6 100644 --- a/crates/bolt/src/protocols/jolt/emit/rust/commitment.rs +++ b/crates/bolt/src/protocols/jolt/emit/rust/commitment.rs @@ -256,7 +256,7 @@ impl CommitmentCpuProgram { "use std::borrow::Cow;\n\ \n\ use jolt_dory::{DoryCommitment, DoryHint, DoryProverSetup, DoryScheme};\n\ - use jolt_field::{Field, Fr};\n\ + use jolt_field::Fr;\n\ use jolt_openings::CommitmentScheme as _;\n\ use jolt_poly::{EqPolynomial, MultilinearPoly};\n\ use jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript};\n\ @@ -540,13 +540,13 @@ impl MultilinearPoly for AddressMajorOneHotPolynomial { result } - fn is_sparse(&self) -> bool { + fn is_one_hot(&self) -> bool { true } - fn for_each_nonzero(&self, f: &mut dyn FnMut(usize, Fr)) { + fn for_each_one(&self, f: &mut dyn FnMut(usize)) { for flat in self.nonzero_flat_indices() { - f(flat, Fr::from_u64(1)); + f(flat); } } } @@ -908,6 +908,14 @@ impl Default for OneHotChunkCounts { } } } + let input_binding = if initializers + .iter() + .any(|initializer| initializer.contains("inputs.")) + { + "inputs" + } else { + "_inputs" + }; let fields = fields.join("\n"); let provider_arms = provider_arms.join("\n"); let initializers = initializers.join("\n"); @@ -930,7 +938,7 @@ impl CommitmentInputProvider for CommitmentOracles {{ }} pub fn build_commitment_oracles( - inputs: &CommitmentOracleInputs<'_>, + {input_binding}: &CommitmentOracleInputs<'_>, ) -> Result {{ Ok(CommitmentOracles {{ {initializers} diff --git a/crates/bolt/src/protocols/jolt/emit/rust/stage1.rs b/crates/bolt/src/protocols/jolt/emit/rust/stage1.rs index 0755beb79d..7ad20c4197 100644 --- a/crates/bolt/src/protocols/jolt/emit/rust/stage1.rs +++ b/crates/bolt/src/protocols/jolt/emit/rust/stage1.rs @@ -1067,7 +1067,7 @@ impl Stage1CpuProgram { fn emit_verifier_imports() -> &'static str { "use super::common::append_labeled_scalar;\n\ - use jolt_field::{Field, Fr};\n\ + use jolt_field::Fr;\n\ use jolt_sumcheck::{CompressedLabeledRoundPoly, LabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckVerifier};\n\ use jolt_transcript::{Blake2bTranscript, Transcript};" } diff --git a/crates/bolt/src/protocols/jolt/emit/rust/stage2.rs b/crates/bolt/src/protocols/jolt/emit/rust/stage2.rs index eb8eceadb7..ba5f5e9ed5 100644 --- a/crates/bolt/src/protocols/jolt/emit/rust/stage2.rs +++ b/crates/bolt/src/protocols/jolt/emit/rust/stage2.rs @@ -927,7 +927,7 @@ impl Stage2CpuProgram { fn emit_verifier_imports() -> &'static str { "use super::common::{append_labeled_scalar, batch_claims, eval_by_name, find_batch, find_plan, pow_field, require_operand_count, reverse_slice, single_operand};\n\ - use jolt_field::{Field, Fr};\n\ + use jolt_field::{Field, Fr, MulPow2, MulPrimitiveInt, RingCore};\n\ use jolt_poly::lagrange::{lagrange_evals, lagrange_kernel_eval};\n\ use jolt_poly::{EqPolynomial, UnivariatePoly};\n\ use jolt_sumcheck::{CompressedLabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckVerifier};\n\ diff --git a/crates/bolt/src/protocols/jolt/emit/rust/stage5.rs b/crates/bolt/src/protocols/jolt/emit/rust/stage5.rs index 30ab3d7edc..1c0db977b0 100644 --- a/crates/bolt/src/protocols/jolt/emit/rust/stage5.rs +++ b/crates/bolt/src/protocols/jolt/emit/rust/stage5.rs @@ -964,7 +964,7 @@ impl Stage5CpuProgram { fn emit_verifier_imports() -> &'static str { "use super::common::{batch_claims, eval_by_name, find_batch, find_plan, identity_polynomial_eval, indexed_evals_by_prefix, indexed_evals_by_prefix_any, lt_polynomial_eval, normalize_instruction_read_raf_point, operand_polynomial_eval, reverse_slice, suffix_point};\n\ - use jolt_field::{Field, Fr};\n\ + use jolt_field::{Field, Fr, RingCore};\n\ use jolt_lookup_tables::LookupTableKind;\n\ use jolt_poly::EqPolynomial;\n\ use jolt_sumcheck::SumcheckError;\n\ diff --git a/crates/bolt/src/protocols/jolt/emit/rust/stage7.rs b/crates/bolt/src/protocols/jolt/emit/rust/stage7.rs index afc274ff7f..764a0d8ec4 100644 --- a/crates/bolt/src/protocols/jolt/emit/rust/stage7.rs +++ b/crates/bolt/src/protocols/jolt/emit/rust/stage7.rs @@ -985,7 +985,7 @@ impl Stage7CpuProgram { fn emit_verifier_imports() -> &'static str { "use super::common::{batch_claims, eval_by_name, find_batch, find_plan, normalize_bytecode_read_raf_point, normalize_instruction_read_raf_point, reverse_slice};\n\ - use jolt_field::{Field, Fr};\n\ + use jolt_field::{Field, Fr, RingCore};\n\ use jolt_poly::EqPolynomial;\n\ use jolt_sumcheck::SumcheckError;\n\ use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript};" diff --git a/crates/bolt/src/protocols/jolt/params.rs b/crates/bolt/src/protocols/jolt/params.rs index 5dd94687dd..9229977949 100644 --- a/crates/bolt/src/protocols/jolt/params.rs +++ b/crates/bolt/src/protocols/jolt/params.rs @@ -61,7 +61,7 @@ impl JoltProtocolParams { lookups_ra_virtual_log_k_chunk, instruction_log_k, register_log_k: 7, - lookup_table_count: 40, + lookup_table_count: 41, instruction_d, instruction_ra_virtual_d, bytecode_d, diff --git a/crates/bolt/src/protocols/jolt/verifier_common.rs.template b/crates/bolt/src/protocols/jolt/verifier_common.rs.template index 5c31bfa6ef..340d4f9d52 100644 --- a/crates/bolt/src/protocols/jolt/verifier_common.rs.template +++ b/crates/bolt/src/protocols/jolt/verifier_common.rs.template @@ -3,7 +3,7 @@ reason = "generated verifier helpers mirror staged protocol ABIs" )] -use jolt_field::{Field, Fr}; +use jolt_field::{Field, Fr, MulPow2, RingCore}; use jolt_poly::EqPolynomial; use jolt_sumcheck::{ CompressedLabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckProof, SumcheckVerifier, diff --git a/crates/bolt/tests/commitment_ir.rs b/crates/bolt/tests/commitment_ir.rs index 63817bba72..4262d21aa5 100644 --- a/crates/bolt/tests/commitment_ir.rs +++ b/crates/bolt/tests/commitment_ir.rs @@ -1417,8 +1417,8 @@ fn stage5_rust_targets_extract_and_compile() { assert!(verifier_source .source .contains("jolt.stage5.registers_val_evaluation")); - assert!(verifier_source.source.contains("LookupTableFlag_39")); - assert!(!verifier_source.source.contains("LookupTableFlag_40")); + assert!(verifier_source.source.contains("LookupTableFlag_40")); + assert!(!verifier_source.source.contains("LookupTableFlag_41")); assert!(verifier_source .source .contains("stage5.instruction_read_raf.eval.InstructionRa_7")); @@ -1453,7 +1453,7 @@ fn stage6_rust_targets_extract_and_compile() { assert_eq!(prover_program.steps.len(), 10); assert_eq!(prover_program.transcript_squeezes.len(), 9); assert!(prover_program.transcript_absorb_bytes.is_empty()); - assert_eq!(prover_program.opening_inputs.len(), 90); + assert_eq!(prover_program.opening_inputs.len(), 91); assert!(prover_program.field_exprs.len() > 150); assert_eq!(prover_program.field_constants.len(), 1); assert!(prover_program.opening_equalities.is_empty()); @@ -3169,11 +3169,11 @@ fn assert_rust_source_compiles(_filename: &str, source: &str) { .expect("write generated cargo manifest"); std::fs::create_dir_all(dir.join("src")).expect("create generated src dir"); if source.contains("super::common") { - let common = std::fs::read_to_string( - workspace_root.join("crates/jolt-verifier/src/stages/common.rs"), + std::fs::write( + dir.join("src/common.rs"), + generated_verifier_common_source(&workspace_root), ) - .expect("read generated verifier common stage source"); - std::fs::write(dir.join("src/common.rs"), common).expect("write generated common source"); + .expect("write generated common source"); std::fs::write(dir.join("src/generated.rs"), source).expect("write generated source"); std::fs::write( dir.join("src/lib.rs"), @@ -3445,10 +3445,20 @@ fn assert_generated_jolt_chain_self_parity_runs(files: &[&RustSourceFile], main_ } fn write_verifier_common_module(src_dir: &Path, workspace_root: &Path) { + std::fs::write( + src_dir.join("common.rs"), + generated_verifier_common_source(workspace_root), + ) + .expect("write generated common source"); +} + +fn generated_verifier_common_source(workspace_root: &Path) -> String { let common = std::fs::read_to_string(workspace_root.join("crates/jolt-verifier/src/stages/common.rs")) .expect("read generated verifier common stage source"); - std::fs::write(src_dir.join("common.rs"), common).expect("write generated common source"); + format!( + "#![allow(dead_code, unused_imports, unused_macros, reason = \"generated verifier helpers are shared across generated stage subsets\")]\n{common}" + ) } fn workspace_root() -> std::path::PathBuf { @@ -3538,7 +3548,7 @@ mod verify_commitment_phase; use std::borrow::Cow; use jolt_dory::DoryScheme; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_transcript::{Blake2bTranscript, Transcript}; struct Inputs; @@ -3600,7 +3610,7 @@ fn generated_pipeline_self_parity_main() -> String { mod verify_commitment_phase; use jolt_dory::DoryScheme; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_transcript::{Blake2bTranscript, Transcript}; " @@ -3663,7 +3673,7 @@ fn generated_stage1_shape_self_parity_main() -> String { let mut source = r"mod prove_stage1_outer; mod verify_stage1_outer; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_kernels::stage1::Stage1ShapeKernelExecutor; use jolt_transcript::{Blake2bTranscript, Transcript}; @@ -3768,7 +3778,7 @@ fn generated_stage1_real_dispatch_main() -> &'static str { r#"mod prove_stage1_outer; mod verify_stage1_outer; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_kernels::stage1::{ Stage1KernelError, Stage1ProverInputs, Stage1ProverKernelExecutor, }; @@ -3829,7 +3839,7 @@ fn generated_stage1_synthetic_remaining_main() -> String { let mut source = r"mod prove_stage1_outer; mod verify_stage1_outer; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_kernels::stage1::{ Stage1OuterRemainingContext, Stage1OuterRemainingEvaluator, Stage1ProverInputs, Stage1ProverKernelExecutor, @@ -3969,7 +3979,7 @@ fn generated_stage1_r1cs_data_main() -> String { let mut source = r"mod prove_stage1_outer; mod verify_stage1_outer; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_kernels::stage1::{ Stage1OuterR1csData, Stage1ProverInputs, Stage1ProverKernelExecutor, }; @@ -4039,7 +4049,7 @@ mod verify_commitment_phase; mod verify_stage1_outer; use jolt_dory::DoryScheme; -use jolt_field::{Field, Fr}; +use jolt_field::Fr; use jolt_kernels::stage1::{ Stage1OuterRemainingContext, Stage1OuterRemainingEvaluator, Stage1ProverInputs, Stage1ProverKernelExecutor, @@ -4178,6 +4188,7 @@ impl Transcript for TracingTranscript { } } +#[allow(dead_code)] fn assert_transcript_step_parity(prover: &TracingTranscript, verifier: &TracingTranscript) { assert_eq!(prover.events, verifier.events); assert_eq!(prover.state(), verifier.state()); diff --git a/crates/jolt-crypto/benches/crypto.rs b/crates/jolt-crypto/benches/crypto.rs index d41511ccb3..1e267657a4 100644 --- a/crates/jolt-crypto/benches/crypto.rs +++ b/crates/jolt-crypto/benches/crypto.rs @@ -5,7 +5,7 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use jolt_crypto::{ Bn254, Bn254G1, Bn254G2, JoltGroup, PairingGroup, Pedersen, PedersenSetup, VectorCommitment, }; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-crypto/src/ec/bn254/gt.rs b/crates/jolt-crypto/src/ec/bn254/gt.rs index befa42df4c..62a71712fa 100644 --- a/crates/jolt-crypto/src/ec/bn254/gt.rs +++ b/crates/jolt-crypto/src/ec/bn254/gt.rs @@ -44,6 +44,14 @@ impl From for Fq12 { } } +impl Bn254GT { + #[inline] + pub fn serialized_len(&self) -> usize { + use ark_serialize::CanonicalSerialize; + self.0.uncompressed_size() + } +} + impl Default for Bn254GT { #[inline(always)] fn default() -> Self { diff --git a/crates/jolt-crypto/tests/coverage.rs b/crates/jolt-crypto/tests/coverage.rs index 3dca4b1230..0cfbe02b8c 100644 --- a/crates/jolt-crypto/tests/coverage.rs +++ b/crates/jolt-crypto/tests/coverage.rs @@ -7,7 +7,7 @@ use jolt_crypto::ec::bn254::glv; use jolt_crypto::{ Bn254, Bn254G1, Bn254G2, Bn254GT, HomomorphicCommitment, JoltGroup, PairingGroup, }; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-crypto/tests/group_laws.rs b/crates/jolt-crypto/tests/group_laws.rs index 4477227487..db65396710 100644 --- a/crates/jolt-crypto/tests/group_laws.rs +++ b/crates/jolt-crypto/tests/group_laws.rs @@ -1,7 +1,7 @@ //! Algebraic group law tests for BN254 G1 and G2. use jolt_crypto::{Bn254, Bn254G1, Bn254G2, JoltGroup}; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-crypto/tests/pairing.rs b/crates/jolt-crypto/tests/pairing.rs index a50c75dd4d..d50cbf959d 100644 --- a/crates/jolt-crypto/tests/pairing.rs +++ b/crates/jolt-crypto/tests/pairing.rs @@ -1,7 +1,7 @@ //! Pairing bilinearity and consistency tests for BN254. use jolt_crypto::{Bn254, Bn254G2, Bn254GT, JoltGroup, PairingGroup}; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-crypto/tests/pedersen.rs b/crates/jolt-crypto/tests/pedersen.rs index b1d3201b43..b1d0a018e1 100644 --- a/crates/jolt-crypto/tests/pedersen.rs +++ b/crates/jolt-crypto/tests/pedersen.rs @@ -1,7 +1,7 @@ //! Pedersen commitment scheme tests over BN254 G1. use jolt_crypto::{Bn254, Bn254G1, JoltGroup, Pedersen, PedersenSetup, VectorCommitment}; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-crypto/tests/serialization.rs b/crates/jolt-crypto/tests/serialization.rs index d543789d24..9206fb70df 100644 --- a/crates/jolt-crypto/tests/serialization.rs +++ b/crates/jolt-crypto/tests/serialization.rs @@ -2,7 +2,7 @@ //! Serialization round-trip tests for all BN254 types. use jolt_crypto::{Bn254, Bn254G1, Bn254G2, Bn254GT, JoltGroup, PairingGroup, PedersenSetup}; -use jolt_field::{Fr, FromPrimitiveInt}; +use jolt_field::Fr; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-dory/src/scheme.rs b/crates/jolt-dory/src/scheme.rs index dc6491b36a..6e1eaa2cd7 100644 --- a/crates/jolt-dory/src/scheme.rs +++ b/crates/jolt-dory/src/scheme.rs @@ -110,6 +110,55 @@ impl DoryScheme { ), ) } + + #[tracing::instrument(skip_all, name = "DoryScheme::commit_evaluations_with_row_len")] + pub fn commit_evaluations_with_row_len( + evaluations: &[Fr], + row_len: usize, + setup: &DoryProverSetup, + ) -> (DoryCommitment, DoryHint) { + assert!( + row_len.is_power_of_two(), + "Dory row length ({row_len}) must be a power of two", + ); + assert!( + row_len <= setup.0.g1_vec.len(), + "Dory row length ({}) exceeds G1 SRS size ({})", + row_len, + setup.0.g1_vec.len(), + ); + let num_rows = evaluations + .len() + .div_ceil(row_len) + .max(1) + .next_power_of_two(); + assert!( + num_rows <= setup.0.g2_vec.len(), + "Dory row count ({}) exceeds G2 SRS size ({})", + num_rows, + setup.0.g2_vec.len(), + ); + + let g1_bases = &setup.0.g1_vec[..row_len]; + let row_commitments: Vec = (0..num_rows) + .into_par_iter() + .map(|row_index| { + let start = row_index * row_len; + let end = (start + row_len).min(evaluations.len()); + let row = evaluations.get(start..end).unwrap_or_default(); + let scalars: Vec = row.iter().map(jolt_fr_to_ark).collect(); + G1Routines::msm(&g1_bases[..scalars.len()], &scalars) + }) + .collect(); + let (tier_2, _) = commit_rows_tier_2::(&row_commitments, setup); + ( + DoryCommitment(ark_to_jolt_gt(&tier_2)), + DoryHint::new( + ark_to_jolt_g1_vec(row_commitments), + ark_to_jolt_fr(&::zero()), + ), + ) + } } impl DeriveSetup for PedersenSetup { diff --git a/crates/jolt-dory/src/types.rs b/crates/jolt-dory/src/types.rs index c0e720f8cb..0df10a3673 100644 --- a/crates/jolt-dory/src/types.rs +++ b/crates/jolt-dory/src/types.rs @@ -20,6 +20,13 @@ pub const MAX_SERIALIZED_PROOF_ROUNDS: usize = 64; #[derive(Clone, Debug, PartialEq, Eq)] pub struct DoryCommitment(pub Bn254GT); +impl DoryCommitment { + #[inline] + pub fn serialized_len(&self) -> u64 { + self.0.serialized_len() as u64 + } +} + impl Serialize for DoryCommitment { fn serialize(&self, serializer: S) -> Result { self.0.serialize(serializer) diff --git a/crates/jolt-dory/tests/commit_open_verify.rs b/crates/jolt-dory/tests/commit_open_verify.rs index 1b14dae377..0f2da3b123 100644 --- a/crates/jolt-dory/tests/commit_open_verify.rs +++ b/crates/jolt-dory/tests/commit_open_verify.rs @@ -7,7 +7,7 @@ use dory::backends::arkworks::ArkG1; use jolt_dory::DoryScheme; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use jolt_openings::{ AdditivelyHomomorphic, CommitmentScheme, StreamingCommitment, ZkOpeningScheme, }; diff --git a/crates/jolt-field/src/arkworks/bn254.rs b/crates/jolt-field/src/arkworks/bn254.rs index df579d70ad..a6bb11f969 100644 --- a/crates/jolt-field/src/arkworks/bn254.rs +++ b/crates/jolt-field/src/arkworks/bn254.rs @@ -285,6 +285,31 @@ impl allocative::Allocative for Fr { } impl Fr { + #[inline(always)] + pub fn from_bool(value: bool) -> Self { + ::from_bool(value) + } + + #[inline(always)] + pub fn from_u64(value: u64) -> Self { + ::from_u64(value) + } + + #[inline(always)] + pub fn from_i64(value: i64) -> Self { + ::from_i64(value) + } + + #[inline(always)] + pub fn from_u128(value: u128) -> Self { + ::from_u128(value) + } + + #[inline(always)] + pub fn from_i128(value: i128) -> Self { + ::from_i128(value) + } + /// Deserializes from little-endian bytes, reducing modulo the field prime. #[inline] pub fn from_le_bytes_mod_order(bytes: &[u8]) -> Self { @@ -298,6 +323,13 @@ impl Fr { Fr(bn254_ops::from_bigint_unchecked(limbs.into())) } + /// Reduces raw little-endian limbs modulo the field prime and wraps the + /// result as a field element. + #[inline] + pub fn from_barrett_reduced_limbs(limbs: Limbs) -> Self { + Fr(bn254_ops::from_barrett_reduced_limbs(limbs.into())) + } + /// Access the internal Montgomery-form limbs. /// /// Used by [`WideAccumulator`](super::wide_accumulator::WideAccumulator) diff --git a/crates/jolt-field/src/arkworks/bn254_ops.rs b/crates/jolt-field/src/arkworks/bn254_ops.rs index 3a1d061791..ee8f081a8b 100644 --- a/crates/jolt-field/src/arkworks/bn254_ops.rs +++ b/crates/jolt-field/src/arkworks/bn254_ops.rs @@ -385,6 +385,18 @@ fn from_unchecked_nplus2(element: BigInt<6>) -> Fr { Fp::new_unchecked(r2) } +/// Barrett reduce raw little-endian limbs to a field element. +#[inline(always)] +pub(crate) fn from_barrett_reduced_limbs(element: BigInt) -> Fr { + let mut acc = BigInt::([0u64; N]); + let mut i = L; + while i > 0 { + i -= 1; + acc = barrett_reduce_5_to_4(nplus1_from_low_and_high(element.0[i], acc.0)); + } + Fp::new_unchecked(acc) +} + /// Multiply a field element by u64. #[inline(always)] pub(crate) fn mul_u64(a: Fr, b: u64) -> Fr { diff --git a/crates/jolt-field/src/arkworks/wide_accumulator.rs b/crates/jolt-field/src/arkworks/wide_accumulator.rs index ab76c66ab4..865cfb058a 100644 --- a/crates/jolt-field/src/arkworks/wide_accumulator.rs +++ b/crates/jolt-field/src/arkworks/wide_accumulator.rs @@ -67,7 +67,7 @@ impl RingAccumulator for WideAccumulator { #[cfg(test)] mod tests { use super::*; - use crate::{AdditiveAccumulator, FromPrimitiveInt}; + use crate::AdditiveAccumulator; #[test] fn single_fmadd() { diff --git a/crates/jolt-field/src/field.rs b/crates/jolt-field/src/field.rs index 80c1da6778..b09e8e889c 100644 --- a/crates/jolt-field/src/field.rs +++ b/crates/jolt-field/src/field.rs @@ -3,7 +3,7 @@ use allocative::Allocative; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::{Debug, Display}; use std::hash::Hash; -use std::ops::Mul; +use std::ops::{Div, Mul}; use crate::{ CanonicalBitLength, CanonicalBytes, CanonicalU64, FieldCore, FixedByteSize, FixedBytes, @@ -43,6 +43,8 @@ pub trait Field: + WithAccumulator + MulPow2 + MulPrimitiveInt + + Div + + for<'a> Div<&'a Self, Output = Self> + Serialize + DeserializeOwned + MaybeAllocative diff --git a/crates/jolt-field/src/with_accumulator.rs b/crates/jolt-field/src/with_accumulator.rs index 65c50cc90d..081729441c 100644 --- a/crates/jolt-field/src/with_accumulator.rs +++ b/crates/jolt-field/src/with_accumulator.rs @@ -1,7 +1,7 @@ -use crate::{AdditiveAccumulator, AdditiveGroup}; +use crate::{AdditiveGroup, FromPrimitiveInt, RingAccumulator, RingCore}; /// Associates an additive redundant accumulator with an element type. -pub trait WithAccumulator: AdditiveGroup { +pub trait WithAccumulator: AdditiveGroup + RingCore + FromPrimitiveInt { /// Accumulator type. - type Accumulator: AdditiveAccumulator; + type Accumulator: RingAccumulator; } diff --git a/crates/jolt-hyperkzg/src/kzg.rs b/crates/jolt-hyperkzg/src/kzg.rs index 00dcff0ea1..c8f930186b 100644 --- a/crates/jolt-hyperkzg/src/kzg.rs +++ b/crates/jolt-hyperkzg/src/kzg.rs @@ -215,7 +215,7 @@ pub(crate) fn challenge_powers(c: F, n: usize) -> Vec { #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; use num_traits::Zero; #[test] diff --git a/crates/jolt-hyperkzg/tests/commit_open_verify.rs b/crates/jolt-hyperkzg/tests/commit_open_verify.rs index 52a8376880..1687d0d1e7 100644 --- a/crates/jolt-hyperkzg/tests/commit_open_verify.rs +++ b/crates/jolt-hyperkzg/tests/commit_open_verify.rs @@ -3,7 +3,7 @@ #![expect(clippy::expect_used, reason = "tests may panic on assertion failures")] use jolt_crypto::Bn254; -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use jolt_hyperkzg::{HyperKZGProverSetup, HyperKZGScheme, HyperKZGVerifierSetup}; use jolt_openings::{AdditivelyHomomorphic, CommitmentScheme}; use jolt_poly::Polynomial; diff --git a/crates/jolt-kernels/Cargo.toml b/crates/jolt-kernels/Cargo.toml new file mode 100644 index 0000000000..cce68df36e --- /dev/null +++ b/crates/jolt-kernels/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "jolt-kernels" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" +authors = ["Jolt Contributors"] +repository = "https://github.com/a16z/jolt" +description = "Coarse CPU kernels targeted by the Bolt-shaped Jolt compiler" +keywords = ["SNARK", "compiler", "sumcheck", "zkvm"] +categories = ["cryptography"] + +[lints] +workspace = true + +[dependencies] +jolt-field = { path = "../jolt-field" } +jolt-lookup-tables = { path = "../jolt-lookup-tables" } +jolt-poly = { path = "../jolt-poly" } +jolt-program = { path = "../jolt-program" } +jolt-r1cs = { path = "../jolt-r1cs" } +jolt-riscv = { path = "../jolt-riscv", default-features = false } +jolt-sumcheck = { path = "../jolt-sumcheck" } +jolt-transcript = { path = "../jolt-transcript" } +jolt-witness = { path = "../jolt-witness" } +rayon = { workspace = true } +tracing = { workspace = true } diff --git a/crates/jolt-kernels/src/dense.rs b/crates/jolt-kernels/src/dense.rs new file mode 100644 index 0000000000..c964703db0 --- /dev/null +++ b/crates/jolt-kernels/src/dense.rs @@ -0,0 +1,32 @@ +use jolt_field::Field; +use rayon::prelude::*; + +pub(crate) const DENSE_BIND_PAR_THRESHOLD: usize = 1024; + +#[inline] +pub(crate) fn bind_dense_evals_reuse( + values: &mut Vec, + scratch: &mut Vec, + challenge: F, +) { + let half = values.len() / 2; + scratch.resize(half, F::zero()); + if half >= DENSE_BIND_PAR_THRESHOLD { + scratch + .par_iter_mut() + .enumerate() + .for_each(|(index, output)| { + let low = values[index << 1]; + let high = values[(index << 1) + 1]; + *output = low + challenge * (high - low); + }); + } else { + for (index, output) in scratch.iter_mut().enumerate() { + let low = values[index << 1]; + let high = values[(index << 1) + 1]; + *output = low + challenge * (high - low); + } + } + std::mem::swap(values, scratch); + scratch.clear(); +} diff --git a/crates/jolt-kernels/src/lib.rs b/crates/jolt-kernels/src/lib.rs new file mode 100644 index 0000000000..882e8b132c --- /dev/null +++ b/crates/jolt-kernels/src/lib.rs @@ -0,0 +1,17 @@ +//! Coarse CPU kernels used by generated Bolt/Jolt Rust. +//! +//! This crate is intentionally above the primitive protocol crates and below +//! generated code. It owns the temporary coarse CPU ABI while the compiler +//! grows finer compute lowerings. + +mod dense; +mod split_eq; + +pub mod stage1; +pub mod stage2; +pub mod stage3; +pub mod stage4; +pub mod stage5; +pub mod stage6; +pub mod stage7; +pub mod trace; diff --git a/crates/jolt-kernels/src/split_eq.rs b/crates/jolt-kernels/src/split_eq.rs new file mode 100644 index 0000000000..debd0251e4 --- /dev/null +++ b/crates/jolt-kernels/src/split_eq.rs @@ -0,0 +1,65 @@ +use jolt_field::Field; +use jolt_poly::EqPolynomial; + +use crate::dense::bind_dense_evals_reuse; + +#[derive(Clone)] +pub(crate) struct SplitEqState { + low_point: Vec, + high_point: Vec, + e_in: Vec, + e_out: Vec, + e_in_scratch: Vec, + e_out_scratch: Vec, +} + +impl SplitEqState { + #[inline] + pub(crate) fn new_low_to_high(point: &[F], scaling: Option) -> Self { + let (high_point, low_point) = point.split_at(point.len() / 2); + Self { + low_point: low_point.to_vec(), + high_point: high_point.to_vec(), + e_in: EqPolynomial::::evals(low_point, scaling), + e_out: EqPolynomial::::evals(high_point, None), + e_in_scratch: Vec::new(), + e_out_scratch: Vec::new(), + } + } + + #[inline] + pub(crate) fn e_in(&self) -> &[F] { + &self.e_in + } + + #[inline] + pub(crate) fn e_out(&self) -> &[F] { + &self.e_out + } + + #[inline] + pub(crate) fn current_target(&self) -> F { + debug_assert!(self.e_in.len() > 1 || self.e_out.len() > 1); + if self.e_in.len() > 1 { + let remaining = self.e_in.len().trailing_zeros() as usize; + self.low_point[remaining - 1] + } else { + let remaining = self.e_out.len().trailing_zeros() as usize; + self.high_point[remaining - 1] + } + } + + #[inline] + pub(crate) fn eval(&self) -> F { + self.e_in[0] * self.e_out[0] + } + + #[inline] + pub(crate) fn bind(&mut self, challenge: F) { + if self.e_in.len() > 1 { + bind_dense_evals_reuse(&mut self.e_in, &mut self.e_in_scratch, challenge); + } else { + bind_dense_evals_reuse(&mut self.e_out, &mut self.e_out_scratch, challenge); + } + } +} diff --git a/crates/jolt-kernels/src/stage1.rs b/crates/jolt-kernels/src/stage1.rs new file mode 100644 index 0000000000..650c13345a --- /dev/null +++ b/crates/jolt-kernels/src/stage1.rs @@ -0,0 +1,2948 @@ +//! Stage 1 outer-sumcheck kernel ABI. + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +use jolt_field::{AdditiveAccumulator, Field, RingAccumulator}; +use jolt_poly::lagrange::{interpolate_to_coeffs, lagrange_evals, lagrange_kernel_eval}; +use jolt_poly::{EqPolynomial, UnivariatePoly}; +use jolt_r1cs::{constraints::rv64, R1csKey, R1csRowDotSlice, R1csRowDotTable}; +use jolt_sumcheck::SumcheckProof; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use rayon::prelude::*; + +mod rv64_typed; +pub use rv64_typed::{Stage1OuterRv64Data, Stage1Rv64Cycle}; + +const OUTER_UNISKIP_DOMAIN_SIZE: usize = 10; +const OUTER_UNISKIP_DEGREE: usize = 9; +const OUTER_UNISKIP_EXTENDED_SIZE: usize = 19; +const OUTER_UNISKIP_NUM_COEFFS: usize = 28; +const OUTER_UNISKIP_DEGREE_BOUND: usize = OUTER_UNISKIP_NUM_COEFFS - 1; +const OUTER_UNISKIP_EXTENDED_START: i64 = -(OUTER_UNISKIP_DEGREE as i64); +const OUTER_UNISKIP_BASE_START: i64 = -((OUTER_UNISKIP_DOMAIN_SIZE as i64 - 1) / 2); +const OUTER_REMAINING_DEGREE_BOUND: usize = 3; +const DENSE_BIND_PAR_THRESHOLD: usize = 1024; +const OUTER_FIRST_GROUP_ROWS: [usize; 10] = [1, 2, 3, 4, 5, 6, 11, 14, 17, 18]; +const OUTER_SECOND_GROUP_ROWS: [usize; 9] = [0, 7, 8, 9, 10, 12, 13, 15, 16]; +const OUTER_EQ_CONSTRAINT_ROWS: usize = + OUTER_FIRST_GROUP_ROWS.len() + OUTER_SECOND_GROUP_ROWS.len(); +const OUTER_UNISKIP_TARGET_COEFFS: [[i64; OUTER_UNISKIP_DOMAIN_SIZE]; OUTER_UNISKIP_DEGREE] = [ + [10, -45, 120, -210, 252, -210, 120, -45, 10, -1], + [-1, 10, -45, 120, -210, 252, -210, 120, -45, 10], + [55, -330, 990, -1848, 2310, -1980, 1155, -440, 99, -10], + [-10, 99, -440, 1155, -1980, 2310, -1848, 990, -330, 55], + [ + 220, -1485, 4752, -9240, 11880, -10395, 6160, -2376, 540, -55, + ], + [ + -55, 540, -2376, 6160, -10395, 11880, -9240, 4752, -1485, 220, + ], + [ + 715, -5148, 17160, -34320, 45045, -40040, 24024, -9360, 2145, -220, + ], + [ + -220, 2145, -9360, 24024, -40040, 45045, -34320, 17160, -5148, 715, + ], + [ + 2002, -15015, 51480, -105_105, 140_140, -126_126, 76440, -30030, 6930, -715, + ], +]; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage1ExecutionMode { + Prover, + Verifier, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1SumcheckClaimPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub domain: &'static str, + pub num_rounds: usize, + pub degree: usize, + pub claim: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub claim_value: &'static str, + pub input_openings: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1SumcheckBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], + pub claim_label: &'static str, + pub round_label: &'static str, + pub round_schedule: &'static [usize], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1SumcheckDriverPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub batch: &'static str, + pub policy: &'static str, + pub round_schedule: &'static [usize], + pub claim_label: &'static str, + pub round_label: &'static str, + pub num_rounds: usize, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1SumcheckInstanceResultPlan { + pub symbol: &'static str, + pub source: &'static str, + pub claim: &'static str, + pub relation: &'static str, + pub index: usize, + pub point_arity: usize, + pub num_rounds: usize, + pub round_offset: usize, + pub point_order: &'static str, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1SumcheckEvalPlan { + pub symbol: &'static str, + pub source: &'static str, + pub name: &'static str, + pub index: usize, + pub oracle: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, + pub point_source: &'static str, + pub eval_source: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1OpeningBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1TranscriptSqueezePlan { + pub symbol: &'static str, + pub label: &'static str, + pub kind: &'static str, + pub count: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage1CpuProgramPlan { + pub params: Stage1Params, + pub transcript_squeezes: &'static [Stage1TranscriptSqueezePlan], + pub kernels: &'static [Stage1KernelPlan], + pub claims: &'static [Stage1SumcheckClaimPlan], + pub batches: &'static [Stage1SumcheckBatchPlan], + pub drivers: &'static [Stage1SumcheckDriverPlan], + pub instance_results: &'static [Stage1SumcheckInstanceResultPlan], + pub evals: &'static [Stage1SumcheckEvalPlan], + pub opening_claims: &'static [Stage1OpeningClaimPlan], + pub opening_batches: &'static [Stage1OpeningBatchPlan], +} + +impl Stage1CpuProgramPlan { + pub fn evals_for_driver<'a>( + &'a self, + driver: &'a str, + ) -> impl Iterator + 'a { + self.evals.iter().filter(move |eval| eval.source == driver) + } + + pub fn instance_results_for_driver<'a>( + &'a self, + driver: &'a str, + ) -> impl Iterator + 'a { + self.instance_results + .iter() + .filter(move |instance| instance.source == driver) + } +} + +#[derive(Clone, Debug)] +pub struct Stage1NamedEval { + pub name: &'static str, + pub oracle: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage1SumcheckOutput { + pub driver: &'static str, + pub point: Vec, + pub evals: Vec>, + pub proof: SumcheckProof, +} + +#[derive(Clone, Debug)] +pub struct Stage1ChallengeVector { + pub symbol: &'static str, + pub values: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage1OpeningValue { + pub symbol: &'static str, + pub oracle: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Debug)] +pub struct Stage1ExecutionArtifacts { + pub challenge_vectors: Vec>, + pub sumchecks: Vec>, + pub opening_values: Vec>, + pub opening_batches: Vec<&'static Stage1OpeningBatchPlan>, +} + +impl Default for Stage1ExecutionArtifacts { + fn default() -> Self { + Self { + challenge_vectors: Vec::new(), + sumchecks: Vec::new(), + opening_values: Vec::new(), + opening_batches: Vec::new(), + } + } +} + +impl Stage1ExecutionArtifacts { + pub fn opening_value(&self, symbol: &str) -> Option<&Stage1OpeningValue> { + self.opening_values + .iter() + .find(|opening| opening.symbol == symbol) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage1OracleData<'a, F: Field> { + pub name: &'static str, + pub evaluations: &'a [F], +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage1OuterRemainingContext<'a, F: Field> { + pub tau: &'a [F], + pub r0: F, +} + +pub type Stage1RemainingRoundProof = Result<(Vec, Vec>), Stage1KernelError>; + +pub trait Stage1OuterRemainingEvaluator: Sync { + fn evaluate(&self, context: Stage1OuterRemainingContext<'_, F>, point: &[F]) -> F; + + fn uniskip_extended_evals(&self, _tau: &[F]) -> Option> { + None + } + + fn evaluate_virtual_oracle( + &self, + _context: Stage1OuterRemainingContext<'_, F>, + _oracle: &str, + _point: &[F], + ) -> Option { + None + } + + fn evaluate_virtual_oracles( + &self, + context: Stage1OuterRemainingContext<'_, F>, + oracles: &[&str], + point: &[F], + ) -> Option> { + oracles + .iter() + .map(|oracle| self.evaluate_virtual_oracle(context, oracle, point)) + .collect() + } + + fn prove_remaining_rounds( + &self, + _context: Stage1OuterRemainingContext<'_, F>, + _num_rounds: usize, + _batching_coeff: F, + _initial_claim: F, + _observe_round: &mut dyn FnMut(&UnivariatePoly) -> F, + ) -> Option> { + None + } +} + +#[derive(Clone, Copy)] +pub struct Stage1ProverInputs<'a, F: Field> { + pub trace_num_vars: usize, + pub virtual_oracles: &'a [Stage1OracleData<'a, F>], + pub uniskip_extended_evals: Option<&'a [F]>, + pub outer_remaining_evaluator: Option<&'a dyn Stage1OuterRemainingEvaluator>, +} + +impl<'a, F: Field> Stage1ProverInputs<'a, F> { + pub fn new(trace_num_vars: usize, virtual_oracles: &'a [Stage1OracleData<'a, F>]) -> Self { + Self { + trace_num_vars, + virtual_oracles, + uniskip_extended_evals: None, + outer_remaining_evaluator: None, + } + } + + pub fn empty(trace_num_vars: usize) -> Self { + Self { + trace_num_vars, + virtual_oracles: &[], + uniskip_extended_evals: None, + outer_remaining_evaluator: None, + } + } + + pub fn with_uniskip_extended_evals(mut self, evaluations: &'a [F]) -> Self { + self.uniskip_extended_evals = Some(evaluations); + self + } + + pub fn with_outer_remaining_evaluator( + mut self, + evaluator: &'a dyn Stage1OuterRemainingEvaluator, + ) -> Self { + self.outer_remaining_evaluator = Some(evaluator); + self + } + + pub fn oracle(&self, name: &str) -> Option<&'a [F]> { + self.virtual_oracles + .iter() + .find(|oracle| oracle.name == name) + .map(|oracle| oracle.evaluations) + } +} + +#[derive(Debug)] +pub struct Stage1OuterR1csData<'a, F: Field> { + pub key: &'a R1csKey, + pub witness: &'a [F], + row_dots: R1csRowDotTable, +} + +impl<'a, F: Field> Stage1OuterR1csData<'a, F> { + #[tracing::instrument(skip_all, name = "Stage1OuterR1csData::new")] + pub fn new(key: &'a R1csKey, witness: &'a [F]) -> Result { + let expected = key.num_cycles * key.num_vars_padded; + if witness.len() != expected { + return Err(Stage1KernelError::InvalidInputLength { + input: "r1cs_witness", + expected, + actual: witness.len(), + }); + } + Ok(Self { + key, + witness, + row_dots: R1csRowDotTable::compute_ab_prefix(key, witness, OUTER_EQ_CONSTRAINT_ROWS), + }) + } + + fn witness_evals(&self, cycle_point: &[F]) -> Vec { + assert_eq!( + cycle_point.len(), + self.key.num_cycle_vars(), + "stage1 cycle point dimension mismatch" + ); + if let Some(cycle) = boolean_index(cycle_point) { + let base = cycle * self.key.num_vars_padded; + return self.witness[base..base + self.key.matrices.num_vars].to_vec(); + } + (0..self.key.matrices.num_vars) + .map(|variable| self.witness_eval(variable, cycle_point)) + .collect() + } + + fn witness_eval(&self, variable: usize, cycle_point: &[F]) -> F { + if let Some(cycle) = boolean_index(cycle_point) { + return self.witness[cycle * self.key.num_vars_padded + variable]; + } + let eq = EqPolynomial::new(cycle_point.to_vec()).evaluations(); + eq.iter() + .take(self.key.num_cycles) + .enumerate() + .fold(F::zero(), |acc, (cycle, &weight)| { + acc + weight * self.witness[cycle * self.key.num_vars_padded + variable] + }) + } + + fn witness_evals_for_variables(&self, variables: &[usize], cycle_point: &[F]) -> Vec { + if let Some(cycle) = boolean_index(cycle_point) { + let base = cycle * self.key.num_vars_padded; + return variables + .iter() + .map(|&variable| self.witness[base + variable]) + .collect(); + } + + let eq = EqPolynomial::new(cycle_point.to_vec()).evaluations(); + let accumulators = eq + .par_iter() + .take(self.key.num_cycles) + .enumerate() + .fold( + || vec![F::Accumulator::default(); variables.len()], + |mut local, (cycle, &weight)| { + let base = cycle * self.key.num_vars_padded; + for (accumulator, &variable) in local.iter_mut().zip(variables) { + accumulator.fmadd(weight, self.witness[base + variable]); + } + local + }, + ) + .reduce( + || vec![F::Accumulator::default(); variables.len()], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + accumulators + .into_iter() + .map(AdditiveAccumulator::reduce) + .collect() + } + + fn inner_sum_product(&self, r_stream: F, r0: F, witness_evals: &[F]) -> F { + let weights = lagrange_evals(OUTER_UNISKIP_BASE_START, OUTER_UNISKIP_DOMAIN_SIZE, r0); + let (az_g0, bz_g0) = self.group_matvecs(&OUTER_FIRST_GROUP_ROWS, &weights, witness_evals); + let (az_g1, bz_g1) = self.group_matvecs(&OUTER_SECOND_GROUP_ROWS, &weights, witness_evals); + let az = az_g0 + r_stream * (az_g1 - az_g0); + let bz = bz_g0 + r_stream * (bz_g1 - bz_g0); + az * bz + } + + fn group_matvecs(&self, rows: &[usize], weights: &[F], witness_evals: &[F]) -> (F, F) { + let mut az = F::zero(); + let mut bz = F::zero(); + for (&row, &weight) in rows.iter().zip(weights.iter()) { + az += weight * Self::row_dot(&self.key.matrices.a[row], witness_evals); + bz += weight * Self::row_dot(&self.key.matrices.b[row], witness_evals); + } + (az, bz) + } + + fn group_matvecs_from_dots( + rows: &[usize], + weights: &[F], + dots: R1csRowDotSlice<'_, F>, + ) -> (F, F) { + let mut az = F::zero(); + let mut bz = F::zero(); + for (&row, &weight) in rows.iter().zip(weights.iter()) { + az += weight * dots.a[row]; + bz += weight * dots.b[row]; + } + (az, bz) + } + + #[cfg(test)] + fn group_matvecs_from_integer_coeffs( + rows: &[usize], + coefficients: &[i64], + coefficient_fields: &[F], + dots: R1csRowDotSlice<'_, F>, + ) -> (F, F) { + let mut az = F::zero(); + let mut bz = F::zero(); + for ((&row, &coefficient), &coefficient_field) in rows + .iter() + .zip(coefficients.iter()) + .zip(coefficient_fields.iter()) + { + if coefficient == 0 { + continue; + } + let a = dots.a[row]; + if a == F::one() { + az += coefficient_field; + } else if a != F::zero() { + az += a.mul_i64(coefficient); + } + + let b = dots.b[row]; + if b != F::zero() { + bz += b.mul_i64(coefficient); + } + } + (az, bz) + } + + fn group_matvecs_all_uniskip_targets( + rows: &[usize], + target_coeff_fields: &[[F; OUTER_UNISKIP_DOMAIN_SIZE]; OUTER_UNISKIP_DEGREE], + dots: R1csRowDotSlice<'_, F>, + ) -> [(F, F); OUTER_UNISKIP_DEGREE] { + let mut az = [F::zero(); OUTER_UNISKIP_DEGREE]; + let mut bz = [F::zero(); OUTER_UNISKIP_DEGREE]; + for (position, &row) in rows.iter().enumerate() { + let a = dots.a[row]; + let b = dots.b[row]; + if a == F::one() { + for target in 0..OUTER_UNISKIP_DEGREE { + az[target] += target_coeff_fields[target][position]; + } + } else if a != F::zero() { + for target in 0..OUTER_UNISKIP_DEGREE { + az[target] += a.mul_i64(OUTER_UNISKIP_TARGET_COEFFS[target][position]); + } + } + if b != F::zero() { + for target in 0..OUTER_UNISKIP_DEGREE { + bz[target] += b.mul_i64(OUTER_UNISKIP_TARGET_COEFFS[target][position]); + } + } + } + core::array::from_fn(|target| (az[target], bz[target])) + } + + fn row_dot(row: &[(usize, F)], witness_evals: &[F]) -> F { + let mut acc = F::zero(); + for &(variable, coefficient) in row { + acc += coefficient * witness_evals[variable]; + } + acc + } + + fn remaining_cycle_point(point: &[F]) -> Vec { + point[1..].iter().rev().copied().collect() + } + + #[tracing::instrument(skip_all, name = "Stage1OuterR1csData::dense_outer_state")] + fn dense_outer_state( + &self, + context: Stage1OuterRemainingContext<'_, F>, + num_rounds: usize, + batching_coeff: F, + ) -> DenseOuterState { + let tau_high = context.tau[context.tau.len() - 1]; + let tau_low = &context.tau[..context.tau.len() - 1]; + let lagrange_tau_r0 = lagrange_kernel_eval( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + tau_high, + context.r0, + ); + let weights = lagrange_evals( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + context.r0, + ); + let len = 1usize << num_rounds; + let scale = lagrange_tau_r0 * batching_coeff; + let eq_evals = EqPolynomial::new(tau_low.to_vec()).evaluations(); + let mut eq = vec![F::zero(); len]; + let mut az = vec![F::zero(); len]; + let mut bz = vec![F::zero(); len]; + eq.par_chunks_mut(2) + .zip(az.par_chunks_mut(2)) + .zip(bz.par_chunks_mut(2)) + .enumerate() + .for_each(|(cycle, ((eq_pair, az_pair), bz_pair))| { + let index = cycle << 1; + let dots = self.row_dots.cycle(cycle); + let (az_g0, bz_g0) = + Self::group_matvecs_from_dots(&OUTER_FIRST_GROUP_ROWS, &weights, dots); + let (az_g1, bz_g1) = + Self::group_matvecs_from_dots(&OUTER_SECOND_GROUP_ROWS, &weights, dots); + eq_pair[0] = eq_evals[index] * scale; + az_pair[0] = az_g0; + bz_pair[0] = bz_g0; + eq_pair[1] = eq_evals[index + 1] * scale; + az_pair[1] = az_g1; + bz_pair[1] = bz_g1; + }); + DenseOuterState { + eq, + az, + bz, + eq_scratch: Vec::with_capacity(len / 2), + az_scratch: Vec::with_capacity(len / 2), + bz_scratch: Vec::with_capacity(len / 2), + } + } +} + +impl Stage1OuterRemainingEvaluator for Stage1OuterR1csData<'_, F> { + fn evaluate(&self, context: Stage1OuterRemainingContext<'_, F>, point: &[F]) -> F { + assert_eq!( + point.len(), + self.key.num_cycle_vars() + 1, + "stage1 outer remaining point dimension mismatch" + ); + assert_eq!( + context.tau.len(), + self.key.num_cycle_vars() + 2, + "stage1 tau dimension mismatch" + ); + let tau_high = context.tau[context.tau.len() - 1]; + let tau_low = &context.tau[..context.tau.len() - 1]; + let mut point_reversed = point.to_vec(); + point_reversed.reverse(); + let tau_weight = EqPolynomial::::mle(tau_low, &point_reversed); + let lagrange_tau_r0 = lagrange_kernel_eval( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + tau_high, + context.r0, + ); + let cycle_point = Self::remaining_cycle_point(point); + let witness_evals = self.witness_evals(&cycle_point); + lagrange_tau_r0 * tau_weight * self.inner_sum_product(point[0], context.r0, &witness_evals) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterR1csData::uniskip_extended_evals")] + fn uniskip_extended_evals(&self, tau: &[F]) -> Option> { + if tau.len() != self.key.num_cycle_vars() + 2 { + return None; + } + let tau_low = &tau[..tau.len() - 1]; + let num_rounds = self.key.num_cycle_vars() + 1; + let eq_evals = EqPolynomial::new(tau_low.to_vec()).evaluations(); + let num_cycles = 1usize << (num_rounds - 1); + assert_eq!(self.row_dots.cycle_count(), num_cycles); + let target_coeff_fields = + OUTER_UNISKIP_TARGET_COEFFS.map(|coefficients| coefficients.map(F::from_i64)); + let accumulators = (0..num_cycles) + .into_par_iter() + .fold( + || [F::Accumulator::default(); OUTER_UNISKIP_DEGREE], + |mut local, cycle| { + let dots = self.row_dots.cycle(cycle); + let index = cycle << 1; + let first_group = Self::group_matvecs_all_uniskip_targets( + &OUTER_FIRST_GROUP_ROWS, + &target_coeff_fields, + dots, + ); + let second_group = Self::group_matvecs_all_uniskip_targets( + &OUTER_SECOND_GROUP_ROWS, + &target_coeff_fields, + dots, + ); + for target in 0..OUTER_UNISKIP_DEGREE { + let (az_g0, bz_g0) = first_group[target]; + let (az_g1, bz_g1) = second_group[target]; + local[target].fmadd(eq_evals[index], az_g0 * bz_g0); + local[target].fmadd(eq_evals[index + 1], az_g1 * bz_g1); + } + local + }, + ) + .reduce( + || [F::Accumulator::default(); OUTER_UNISKIP_DEGREE], + |mut left, right| { + for target in 0..OUTER_UNISKIP_DEGREE { + left[target].merge(right[target]); + } + left + }, + ); + let extended_evals = accumulators.map(AdditiveAccumulator::reduce).to_vec(); + Some(extended_evals) + } + + fn evaluate_virtual_oracle( + &self, + _context: Stage1OuterRemainingContext<'_, F>, + oracle: &str, + point: &[F], + ) -> Option { + let variable = r1cs_oracle_variable(oracle)?; + let cycle_point = Self::remaining_cycle_point(point); + Some(self.witness_eval(variable, &cycle_point)) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterR1csData::evaluate_virtual_oracles")] + fn evaluate_virtual_oracles( + &self, + _context: Stage1OuterRemainingContext<'_, F>, + oracles: &[&str], + point: &[F], + ) -> Option> { + let variables = oracles + .iter() + .map(|oracle| r1cs_oracle_variable(oracle)) + .collect::>>()?; + let cycle_point = Self::remaining_cycle_point(point); + Some(self.witness_evals_for_variables(&variables, &cycle_point)) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterR1csData::prove_remaining_rounds")] + fn prove_remaining_rounds( + &self, + context: Stage1OuterRemainingContext<'_, F>, + num_rounds: usize, + batching_coeff: F, + initial_claim: F, + observe_round: &mut dyn FnMut(&UnivariatePoly) -> F, + ) -> Option> { + let mut state = self.dense_outer_state(context, num_rounds, batching_coeff); + let mut running_sum = initial_claim * batching_coeff; + let mut point = Vec::with_capacity(num_rounds); + let mut round_polynomials = Vec::with_capacity(num_rounds); + + for _round in 0..num_rounds { + let poly = state.round_poly(); + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_sum { + return Some(Err(Stage1KernelError::InvalidProof { + driver: "stage1.outer.remaining", + reason: "dense outer remaining claim mismatch", + })); + } + let challenge = observe_round(&poly); + running_sum = poly.evaluate(challenge); + state.bind(challenge); + point.push(challenge); + round_polynomials.push(poly); + } + Some(Ok((point, round_polynomials))) + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage1Proof { + pub sumchecks: Vec>, +} + +impl From> for Stage1Proof { + fn from(artifacts: Stage1ExecutionArtifacts) -> Self { + Self { + sumchecks: artifacts.sumchecks, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage1KernelContext<'a> { + pub mode: Stage1ExecutionMode, + pub program: &'a Stage1CpuProgramPlan, + pub kernel: &'a Stage1KernelPlan, + pub batch: &'a Stage1SumcheckBatchPlan, + pub driver: &'a Stage1SumcheckDriverPlan, +} + +pub trait Stage1KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage1TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage1KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage1SumcheckOutput, + ) -> Result<(), Stage1KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage1KernelExecutor; + +impl Stage1KernelExecutor for UnsupportedStage1KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Err(Stage1KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Err(Stage1KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage1ShapeKernelExecutor; + +impl Stage1KernelExecutor for Stage1ShapeKernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + run_shape_kernel(context, transcript) + } + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + run_shape_kernel(context, transcript) + } +} + +#[derive(Clone)] +pub struct Stage1ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage1ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage1ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage1ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } +} + +impl Stage1KernelExecutor for Stage1ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage1TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage1KernelError> { + self.challenge_vectors.push(Stage1ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage1SumcheckOutput, + ) -> Result<(), Stage1KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + prove_stage1_kernel( + context, + &self.inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Err(Stage1KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage1ExecutionMode::Prover, + actual: Stage1ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone, Debug)] +pub struct Stage1VerifierKernelExecutor<'a, F: Field> { + pub proof: &'a Stage1Proof, + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage1VerifierKernelExecutor<'a, F> { + pub fn new(proof: &'a Stage1Proof) -> Self { + Self { + proof, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } +} + +impl Stage1KernelExecutor for Stage1VerifierKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage1TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage1KernelError> { + self.challenge_vectors.push(Stage1ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage1SumcheckOutput, + ) -> Result<(), Stage1KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Err(Stage1KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage1ExecutionMode::Verifier, + actual: Stage1ExecutionMode::Prover, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + let proof = self.proof.sumchecks.get(self.cursor); + self.cursor += usize::from(proof.is_some()); + verify_stage1_kernel( + context, + proof, + &self.challenge_vectors, + &self.completed_sumchecks, + transcript, + ) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage1KernelError { + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage1ExecutionMode, + actual: Stage1ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedPointOrder { + symbol: &'static str, + point_order: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage1KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage1 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage1 driver @{driver} references missing batch @{batch}" + ) + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => write!( + formatter, + "stage1 plan @{artifact} count mismatch: expected {expected}, got {actual}" + ), + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage1 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => write!( + formatter, + "stage1 driver @{driver} ran with {actual:?} executor path, expected {expected:?}" + ), + Self::MissingProof { driver } => { + write!( + formatter, + "stage1 verifier missing proof for driver @{driver}" + ) + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage1 kernel `{kernel}` missing input `{input}`" + ) + } + Self::InvalidInputLength { + input, + expected, + actual, + } => write!( + formatter, + "stage1 input `{input}` length mismatch: expected {expected}, got {actual}" + ), + Self::UnsupportedPointOrder { + symbol, + point_order, + } => write!( + formatter, + "stage1 instance @{symbol} uses unsupported point order `{point_order}`" + ), + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage1 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage1KernelError {} + +pub fn execute_stage1_program( + program: &'static Stage1CpuProgramPlan, + mode: Stage1ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + E: Stage1KernelExecutor, + T: Transcript, +{ + verify_static_program_shape(program)?; + let mut artifacts = Stage1ExecutionArtifacts::default(); + for squeeze in program.transcript_squeezes { + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage1ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + for driver in program.drivers { + let kernel_symbol = driver.kernel.ok_or(Stage1KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = + find_kernel(program, kernel_symbol).ok_or(Stage1KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + })?; + let batch = find_batch(program, driver.batch).ok_or(Stage1KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage1KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage1ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage1ExecutionMode::Verifier => executor.verify_sumcheck(context, transcript)?, + }; + executor.observe_sumcheck_output(&output)?; + artifacts.sumchecks.push(output); + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + artifacts.opening_values = stage1_opening_values(program, &artifacts.sumchecks)?; + Ok(artifacts) +} + +fn stage1_opening_values( + program: &'static Stage1CpuProgramPlan, + sumchecks: &[Stage1SumcheckOutput], +) -> Result>, Stage1KernelError> { + let mut points = Vec::>::new(); + let mut scalars = Vec::>::new(); + for output in sumchecks { + points.push(Stage1PointValue { + symbol: output.driver, + point: output.point.clone(), + }); + for instance in program.instance_results_for_driver(output.driver) { + points.push(Stage1PointValue { + symbol: instance.symbol, + point: stage1_instance_point(instance, &output.point)?, + }); + } + for eval in program.evals_for_driver(output.driver) { + let value = output + .evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| output.evals.get(eval.index)) + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: output.driver, + input: eval.symbol, + })? + .value; + scalars.push(Stage1ScalarValue { + symbol: eval.symbol, + value, + }); + scalars.push(Stage1ScalarValue { + symbol: eval.name, + value, + }); + } + } + program + .opening_claims + .iter() + .map(|claim| { + let point = points + .iter() + .find(|point| point.symbol == claim.point_source) + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: claim.symbol, + input: claim.point_source, + })? + .point + .clone(); + let eval = scalars + .iter() + .find(|scalar| scalar.symbol == claim.eval_source) + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: claim.symbol, + input: claim.eval_source, + })? + .value; + Ok(Stage1OpeningValue { + symbol: claim.symbol, + oracle: claim.oracle, + point, + eval, + }) + }) + .collect() +} + +fn stage1_instance_point( + instance: &Stage1SumcheckInstanceResultPlan, + point: &[F], +) -> Result, Stage1KernelError> { + let end = instance.round_offset + instance.point_arity; + let mut point = point + .get(instance.round_offset..end) + .ok_or(Stage1KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => Ok(point), + "reverse" => { + point.reverse(); + Ok(point) + } + point_order => Err(Stage1KernelError::UnsupportedPointOrder { + symbol: instance.symbol, + point_order, + }), + } +} + +#[derive(Clone, Debug)] +struct Stage1PointValue { + symbol: &'static str, + point: Vec, +} + +#[derive(Clone, Copy, Debug)] +struct Stage1ScalarValue { + symbol: &'static str, + value: F, +} + +fn verify_static_program_shape( + program: &'static Stage1CpuProgramPlan, +) -> Result<(), Stage1KernelError> { + for batch in program.batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + for batch in program.opening_batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + Ok(()) +} + +fn verify_count( + artifact: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage1KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage1KernelError::PlanCountMismatch { + artifact, + expected, + actual, + }) + } +} + +fn find_kernel( + program: &'static Stage1CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage1KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch( + program: &'static Stage1CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage1SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +fn prove_stage1_kernel( + context: Stage1KernelContext<'_>, + inputs: &Stage1ProverInputs<'_, F>, + challenge_vectors: &[Stage1ChallengeVector], + completed_sumchecks: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + match context.kernel.abi { + "jolt_stage1_outer_uniskip" => { + prove_outer_uniskip(context, inputs, challenge_vectors, transcript) + } + "jolt_stage1_outer_remaining" => prove_outer_remaining( + context, + inputs, + challenge_vectors, + completed_sumchecks, + transcript, + ), + abi => Err(Stage1KernelError::KernelNotImplemented { abi }), + } +} + +fn verify_stage1_kernel( + context: Stage1KernelContext<'_>, + proof: Option<&Stage1SumcheckOutput>, + challenge_vectors: &[Stage1ChallengeVector], + completed_sumchecks: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + match context.kernel.abi { + "jolt_stage1_outer_uniskip" => { + verify_outer_uniskip(context, proof, challenge_vectors, transcript) + } + "jolt_stage1_outer_remaining" => { + verify_outer_remaining(context, proof, completed_sumchecks, transcript) + } + abi => Err(Stage1KernelError::KernelNotImplemented { abi }), + } +} + +#[tracing::instrument(skip_all, name = "prove_outer_uniskip")] +fn prove_outer_uniskip( + context: Stage1KernelContext<'_>, + inputs: &Stage1ProverInputs<'_, F>, + challenge_vectors: &[Stage1ChallengeVector], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + let tau = find_challenge_vector(challenge_vectors, "stage1.tau").ok_or( + Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "stage1.tau", + }, + )?; + let tau_high = tau + .last() + .copied() + .ok_or(Stage1KernelError::InvalidInputLength { + input: "stage1.tau", + expected: 1, + actual: 0, + })?; + let owned_extended_evals; + let extended_evals = if let Some(extended_evals) = inputs.uniskip_extended_evals { + extended_evals + } else { + let evaluator = + inputs + .outer_remaining_evaluator + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "uniskip_extended_evals", + })?; + owned_extended_evals = + evaluator + .uniskip_extended_evals(tau) + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "uniskip_extended_evals", + })?; + owned_extended_evals.as_slice() + }; + let poly = build_outer_uniskip_poly(extended_evals, tau_high)?; + append_univariate_poly(transcript, context.driver.round_label, &poly); + let r0 = transcript.challenge(); + let eval = poly.evaluate(r0); + append_labeled_scalar(transcript, "opening_claim", &eval); + Ok(Stage1SumcheckOutput { + driver: context.driver.symbol, + point: vec![r0], + evals: driver_evals(context, eval), + proof: SumcheckProof { + round_polynomials: vec![poly], + }, + }) +} + +#[tracing::instrument(skip_all, name = "prove_outer_remaining")] +fn prove_outer_remaining( + context: Stage1KernelContext<'_>, + inputs: &Stage1ProverInputs<'_, F>, + challenge_vectors: &[Stage1ChallengeVector], + completed_sumchecks: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + let evaluator = + inputs + .outer_remaining_evaluator + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "outer_remaining_evaluator", + })?; + let tau = find_challenge_vector(challenge_vectors, "stage1.tau").ok_or( + Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "stage1.tau", + }, + )?; + let (r0, input_claim) = uniskip_point_and_claim(completed_sumchecks).ok_or( + Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "stage1.uniskip.eval", + }, + )?; + let remaining_context = Stage1OuterRemainingContext { tau, r0 }; + append_labeled_scalar(transcript, context.driver.claim_label, &input_claim); + let batching_coeff = transcript.challenge(); + let fast_path = evaluator.prove_remaining_rounds( + remaining_context, + context.driver.num_rounds, + batching_coeff, + input_claim, + &mut |poly| { + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + transcript.challenge() + }, + ); + let (point, round_polynomials) = if let Some(result) = fast_path { + result? + } else { + prove_outer_remaining_fallback( + context, + evaluator, + remaining_context, + batching_coeff, + input_claim, + transcript, + )? + }; + + let evals = remaining_driver_evals(context, evaluator, remaining_context, &point)?; + append_opening_claims(transcript, &evals); + Ok(Stage1SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + proof: SumcheckProof { round_polynomials }, + }) +} + +fn verify_outer_uniskip( + context: Stage1KernelContext<'_>, + proof: Option<&Stage1SumcheckOutput>, + _challenge_vectors: &[Stage1ChallengeVector], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + let Some(proof) = proof else { + return Err(Stage1KernelError::MissingProof { + driver: context.driver.symbol, + }); + }; + if proof.driver != context.driver.symbol { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + let Some(poly) = proof.proof.round_polynomials.first() else { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "missing uniskip round polynomial", + }); + }; + if proof.proof.round_polynomials.len() != 1 { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected uniskip round count", + }); + } + if polynomial_degree(poly) > OUTER_UNISKIP_DEGREE_BOUND { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "uniskip polynomial exceeds degree bound", + }); + } + append_univariate_poly(transcript, context.driver.round_label, poly); + let r0 = transcript.challenge(); + if !uniskip_sum_matches(poly, F::zero()) { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "uniskip polynomial sum check failed", + }); + } + let eval = poly.evaluate(r0); + if !proof.point.is_empty() && (proof.point.len() != 1 || proof.point[0] != r0) { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "uniskip point mismatch", + }); + } + validate_eval_shape(context, &proof.evals, Some(eval))?; + append_labeled_scalar(transcript, "opening_claim", &eval); + Ok(Stage1SumcheckOutput { + driver: context.driver.symbol, + point: vec![r0], + evals: driver_evals(context, eval), + proof: proof.proof.clone(), + }) +} + +fn verify_outer_remaining( + context: Stage1KernelContext<'_>, + proof: Option<&Stage1SumcheckOutput>, + completed_sumchecks: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + let Some(proof) = proof else { + return Err(Stage1KernelError::MissingProof { + driver: context.driver.symbol, + }); + }; + if proof.driver != context.driver.symbol { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected outer remaining round count", + }); + } + let input_claim = + uniskip_output_claim(completed_sumchecks).ok_or(Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "stage1.uniskip.eval", + })?; + append_labeled_scalar(transcript, context.driver.claim_label, &input_claim); + let batching_coeff = transcript.challenge(); + let mut running_sum = input_claim * batching_coeff; + let mut point = Vec::with_capacity(context.driver.num_rounds); + + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > OUTER_REMAINING_DEGREE_BOUND { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "outer remaining polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_sum { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "outer remaining round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_sum = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "outer remaining point mismatch", + }); + } + validate_eval_shape(context, &proof.evals, None)?; + append_opening_claims(transcript, &proof.evals); + Ok(Stage1SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + proof: proof.proof.clone(), + }) +} + +fn prove_outer_remaining_fallback( + context: Stage1KernelContext<'_>, + evaluator: &dyn Stage1OuterRemainingEvaluator, + remaining_context: Stage1OuterRemainingContext<'_, F>, + batching_coeff: F, + input_claim: F, + transcript: &mut T, +) -> Result<(Vec, Vec>), Stage1KernelError> +where + F: Field, + T: Transcript, +{ + let mut running_sum = input_claim * batching_coeff; + let mut point = Vec::with_capacity(context.driver.num_rounds); + let mut round_polynomials = Vec::with_capacity(context.driver.num_rounds); + for _round in 0..context.driver.num_rounds { + let poly = outer_remaining_round_poly( + evaluator, + remaining_context, + context.driver.num_rounds, + &point, + ); + let scaled_poly = scale_poly(&poly, batching_coeff); + if scaled_poly.evaluate(F::zero()) + scaled_poly.evaluate(F::one()) != running_sum { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "outer remaining prover claim mismatch", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &scaled_poly); + let challenge = transcript.challenge(); + running_sum = scaled_poly.evaluate(challenge); + point.push(challenge); + round_polynomials.push(scaled_poly); + } + Ok((point, round_polynomials)) +} + +fn find_challenge_vector<'a, F: Field>( + challenges: &'a [Stage1ChallengeVector], + symbol: &str, +) -> Option<&'a [F]> { + challenges + .iter() + .find(|challenge| challenge.symbol == symbol) + .map(|challenge| challenge.values.as_slice()) +} + +fn build_outer_uniskip_poly( + extended_evals: &[F], + tau_high: F, +) -> Result, Stage1KernelError> { + if extended_evals.len() != OUTER_UNISKIP_DEGREE { + return Err(Stage1KernelError::InvalidInputLength { + input: "uniskip_extended_evals", + expected: OUTER_UNISKIP_DEGREE, + actual: extended_evals.len(), + }); + } + + let mut t1_values = vec![F::zero(); OUTER_UNISKIP_EXTENDED_SIZE]; + for (value, target) in extended_evals.iter().zip(outer_uniskip_targets()) { + let index = (target - OUTER_UNISKIP_EXTENDED_START) as usize; + t1_values[index] = *value; + } + + let t1_coeffs = interpolate_to_coeffs(OUTER_UNISKIP_EXTENDED_START, &t1_values); + let lagrange_values = lagrange_evals( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + tau_high, + ); + let lagrange_coeffs = interpolate_to_coeffs(OUTER_UNISKIP_BASE_START, &lagrange_values); + + let mut coefficients = vec![F::zero(); OUTER_UNISKIP_NUM_COEFFS]; + for (i, &lagrange_coeff) in lagrange_coeffs.iter().enumerate() { + for (j, &t1_coeff) in t1_coeffs.iter().enumerate() { + coefficients[i + j] += lagrange_coeff * t1_coeff; + } + } + Ok(UnivariatePoly::new(coefficients)) +} + +/// Returns the off-domain targets used by the Stage 1 outer univariate-skip +/// round polynomial. +pub fn outer_uniskip_targets() -> [i64; OUTER_UNISKIP_DEGREE] { + let ext_left = OUTER_UNISKIP_EXTENDED_START; + let ext_right = OUTER_UNISKIP_DEGREE as i64; + let base_left = OUTER_UNISKIP_BASE_START; + let base_right = base_left + OUTER_UNISKIP_DOMAIN_SIZE as i64 - 1; + let mut targets = [0i64; OUTER_UNISKIP_DEGREE]; + let mut index = 0; + let mut negative = base_left - 1; + let mut positive = base_right + 1; + while negative >= ext_left && positive <= ext_right && index < OUTER_UNISKIP_DEGREE { + targets[index] = negative; + index += 1; + if index >= OUTER_UNISKIP_DEGREE { + break; + } + targets[index] = positive; + index += 1; + negative -= 1; + positive += 1; + } + while index < OUTER_UNISKIP_DEGREE && negative >= ext_left { + targets[index] = negative; + index += 1; + negative -= 1; + } + while index < OUTER_UNISKIP_DEGREE && positive <= ext_right { + targets[index] = positive; + index += 1; + positive += 1; + } + targets +} + +/// Recovers the Stage 1 outer univariate-skip extended evaluations from a +/// first-round proof polynomial. +pub fn outer_uniskip_extended_evals_from_round_poly( + round_poly: &UnivariatePoly, + tau_high: F, +) -> Vec { + outer_uniskip_targets() + .into_iter() + .map(|target| { + let y = F::from_i64(target); + let kernel = lagrange_kernel_eval( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + tau_high, + y, + ); + round_poly.evaluate(y) / kernel + }) + .collect() +} + +fn boolean_index(point: &[F]) -> Option { + let mut index = 0usize; + for value in point { + index <<= 1; + if *value == F::one() { + index |= 1; + } else if *value != F::zero() { + return None; + } + } + Some(index) +} + +fn r1cs_oracle_variable(oracle: &str) -> Option { + match oracle { + "LeftInstructionInput" => Some(rv64::V_LEFT_INSTRUCTION_INPUT), + "RightInstructionInput" => Some(rv64::V_RIGHT_INSTRUCTION_INPUT), + "Product" => Some(rv64::V_PRODUCT), + "ShouldBranch" => Some(rv64::V_SHOULD_BRANCH), + "PC" => Some(rv64::V_PC), + "UnexpandedPC" => Some(rv64::V_UNEXPANDED_PC), + "Imm" => Some(rv64::V_IMM), + "RamAddress" => Some(rv64::V_RAM_ADDRESS), + "Rs1Value" => Some(rv64::V_RS1_VALUE), + "Rs2Value" => Some(rv64::V_RS2_VALUE), + "RdWriteValue" => Some(rv64::V_RD_WRITE_VALUE), + "RamReadValue" => Some(rv64::V_RAM_READ_VALUE), + "RamWriteValue" => Some(rv64::V_RAM_WRITE_VALUE), + "LeftLookupOperand" => Some(rv64::V_LEFT_LOOKUP_OPERAND), + "RightLookupOperand" => Some(rv64::V_RIGHT_LOOKUP_OPERAND), + "NextUnexpandedPC" => Some(rv64::V_NEXT_UNEXPANDED_PC), + "NextPC" => Some(rv64::V_NEXT_PC), + "NextIsVirtual" => Some(rv64::V_NEXT_IS_VIRTUAL), + "NextIsFirstInSequence" => Some(rv64::V_NEXT_IS_FIRST_IN_SEQUENCE), + "LookupOutput" => Some(rv64::V_LOOKUP_OUTPUT), + "ShouldJump" => Some(rv64::V_SHOULD_JUMP), + "OpFlagAddOperands" => Some(rv64::V_FLAG_ADD_OPERANDS), + "OpFlagSubtractOperands" => Some(rv64::V_FLAG_SUBTRACT_OPERANDS), + "OpFlagMultiplyOperands" => Some(rv64::V_FLAG_MULTIPLY_OPERANDS), + "OpFlagLoad" => Some(rv64::V_FLAG_LOAD), + "OpFlagStore" => Some(rv64::V_FLAG_STORE), + "OpFlagJump" => Some(rv64::V_FLAG_JUMP), + "OpFlagWriteLookupOutputToRD" => Some(rv64::V_FLAG_WRITE_LOOKUP_OUTPUT_TO_RD), + "OpFlagVirtualInstruction" => Some(rv64::V_FLAG_VIRTUAL_INSTRUCTION), + "OpFlagAssert" => Some(rv64::V_FLAG_ASSERT), + "OpFlagDoNotUpdateUnexpandedPC" => Some(rv64::V_FLAG_DO_NOT_UPDATE_UNEXPANDED_PC), + "OpFlagAdvice" => Some(rv64::V_FLAG_ADVICE), + "OpFlagIsCompressed" => Some(rv64::V_FLAG_IS_COMPRESSED), + "OpFlagIsFirstInSequence" => Some(rv64::V_FLAG_IS_FIRST_IN_SEQUENCE), + "OpFlagIsLastInSequence" => Some(rv64::V_FLAG_IS_LAST_IN_SEQUENCE), + _ => None, + } +} + +fn append_univariate_poly(transcript: &mut T, label: &'static str, poly: &UnivariatePoly) +where + F: Field, + T: Transcript, +{ + transcript.append(&LabelWithCount( + label.as_bytes(), + poly.coefficients().len() as u64, + )); + for coefficient in poly.coefficients() { + transcript.append(coefficient); + } +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims(transcript: &mut T, evals: &[Stage1NamedEval]) +where + F: Field, + T: Transcript, +{ + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } +} + +struct DenseOuterState { + eq: Vec, + az: Vec, + bz: Vec, + eq_scratch: Vec, + az_scratch: Vec, + bz_scratch: Vec, +} + +impl DenseOuterState { + #[tracing::instrument(skip_all, name = "DenseOuterState::round_poly")] + fn round_poly(&self) -> UnivariatePoly { + let pair_count = self.eq.len() / 2; + let accumulators = if pair_count >= DENSE_BIND_PAR_THRESHOLD { + self.eq + .par_chunks_exact(2) + .zip(self.az.par_chunks_exact(2)) + .zip(self.bz.par_chunks_exact(2)) + .map(|((eq_pair, az_pair), bz_pair)| { + let mut local = [F::Accumulator::default(); OUTER_REMAINING_DEGREE_BOUND + 1]; + let eq0 = eq_pair[0]; + let eq_delta = eq_pair[1] - eq_pair[0]; + let az0 = az_pair[0]; + let az_delta = az_pair[1] - az_pair[0]; + let bz0 = bz_pair[0]; + let bz_delta = bz_pair[1] - bz_pair[0]; + accumulate_cubic_product_coefficients( + &mut local, eq0, eq_delta, az0, az_delta, bz0, bz_delta, + ); + local + }) + .reduce( + || [F::Accumulator::default(); OUTER_REMAINING_DEGREE_BOUND + 1], + |mut left, right| { + for i in 0..left.len() { + left[i].merge(right[i]); + } + left + }, + ) + } else { + self.eq + .chunks_exact(2) + .zip(self.az.chunks_exact(2)) + .zip(self.bz.chunks_exact(2)) + .fold( + [F::Accumulator::default(); OUTER_REMAINING_DEGREE_BOUND + 1], + |mut local, ((eq_pair, az_pair), bz_pair)| { + let eq0 = eq_pair[0]; + let eq_delta = eq_pair[1] - eq_pair[0]; + let az0 = az_pair[0]; + let az_delta = az_pair[1] - az_pair[0]; + let bz0 = bz_pair[0]; + let bz_delta = bz_pair[1] - bz_pair[0]; + accumulate_cubic_product_coefficients( + &mut local, eq0, eq_delta, az0, az_delta, bz0, bz_delta, + ); + local + }, + ) + }; + UnivariatePoly::new(accumulators.map(AdditiveAccumulator::reduce).to_vec()) + } + + #[tracing::instrument(skip_all, name = "DenseOuterState::bind")] + fn bind(&mut self, challenge: F) { + bind_dense_evals_reuse(&mut self.eq, &mut self.eq_scratch, challenge); + bind_dense_evals_reuse(&mut self.az, &mut self.az_scratch, challenge); + bind_dense_evals_reuse(&mut self.bz, &mut self.bz_scratch, challenge); + } +} + +#[inline] +fn accumulate_cubic_product_coefficients( + coefficients: &mut [F::Accumulator; OUTER_REMAINING_DEGREE_BOUND + 1], + eq0: F, + eq_delta: F, + az0: F, + az_delta: F, + bz0: F, + bz_delta: F, +) { + let az0_bz0 = az0 * bz0; + let az_delta_bz0 = az_delta * bz0; + let az0_bz_delta = az0 * bz_delta; + let az_delta_bz_delta = az_delta * bz_delta; + + coefficients[0].fmadd(eq0, az0_bz0); + coefficients[1].fmadd(eq_delta, az0_bz0); + coefficients[1].fmadd(eq0, az_delta_bz0); + coefficients[1].fmadd(eq0, az0_bz_delta); + coefficients[2].fmadd(eq_delta, az_delta_bz0); + coefficients[2].fmadd(eq_delta, az0_bz_delta); + coefficients[2].fmadd(eq0, az_delta_bz_delta); + coefficients[3].fmadd(eq_delta, az_delta_bz_delta); +} + +fn bind_dense_evals_reuse(values: &mut Vec, scratch: &mut Vec, challenge: F) { + let half = values.len() / 2; + scratch.resize(half, F::zero()); + if half >= DENSE_BIND_PAR_THRESHOLD { + scratch + .par_iter_mut() + .enumerate() + .for_each(|(index, output)| { + let low = values[index << 1]; + let high = values[(index << 1) + 1]; + *output = low + (high - low) * challenge; + }); + } else { + for (index, output) in scratch.iter_mut().enumerate() { + let low = values[index << 1]; + let high = values[(index << 1) + 1]; + *output = low + (high - low) * challenge; + } + } + std::mem::swap(values, scratch); + scratch.clear(); +} + +fn outer_remaining_round_poly( + evaluator: &dyn Stage1OuterRemainingEvaluator, + context: Stage1OuterRemainingContext<'_, F>, + num_rounds: usize, + prefix: &[F], +) -> UnivariatePoly { + let suffix_rounds = num_rounds - prefix.len() - 1; + let mut evals = Vec::with_capacity(OUTER_REMAINING_DEGREE_BOUND + 1); + for x in 0..=OUTER_REMAINING_DEGREE_BOUND { + let mut sum = F::zero(); + for suffix in 0..(1usize << suffix_rounds) { + let mut point = Vec::with_capacity(num_rounds); + point.extend_from_slice(prefix); + point.push(F::from_u64(x as u64)); + for bit in 0..suffix_rounds { + point.push(F::from_u64(((suffix >> bit) & 1) as u64)); + } + sum += evaluator.evaluate(context, &point); + } + evals.push(sum); + } + UnivariatePoly::new(interpolate_to_coeffs(0, &evals)) +} + +fn scale_poly(poly: &UnivariatePoly, scalar: F) -> UnivariatePoly { + UnivariatePoly::new( + poly.coefficients() + .iter() + .map(|coefficient| *coefficient * scalar) + .collect(), + ) +} + +fn remaining_driver_evals( + context: Stage1KernelContext<'_>, + evaluator: &dyn Stage1OuterRemainingEvaluator, + remaining_context: Stage1OuterRemainingContext<'_, F>, + point: &[F], +) -> Result>, Stage1KernelError> { + let plans = context + .program + .evals + .iter() + .filter(|eval| eval.source == context.driver.symbol) + .collect::>(); + let oracles = plans.iter().map(|eval| eval.oracle).collect::>(); + let values = evaluator + .evaluate_virtual_oracles(remaining_context, &oracles, point) + .ok_or(Stage1KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "remaining_driver_evals", + })?; + if values.len() != plans.len() { + return Err(Stage1KernelError::InvalidInputLength { + input: "remaining_driver_evals", + expected: plans.len(), + actual: values.len(), + }); + } + Ok(plans + .into_iter() + .zip(values) + .map(|(eval, value)| Stage1NamedEval { + name: eval.name, + oracle: eval.oracle, + value, + }) + .collect()) +} + +fn uniskip_output_claim(sumchecks: &[Stage1SumcheckOutput]) -> Option { + uniskip_point_and_claim(sumchecks).map(|(_, claim)| claim) +} + +fn uniskip_point_and_claim(sumchecks: &[Stage1SumcheckOutput]) -> Option<(F, F)> { + sumchecks.iter().find_map(|sumcheck| { + let point = *sumcheck.point.first()?; + let claim = sumcheck + .evals + .iter() + .find(|eval| eval.oracle == "UnivariateSkip") + .map(|eval| eval.value)?; + Some((point, claim)) + }) +} + +fn uniskip_sum_matches(poly: &UnivariatePoly, claim: F) -> bool { + let power_sums = integer_domain_power_sums( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + poly.coefficients().len(), + ); + let sum = poly + .coefficients() + .iter() + .zip(power_sums) + .fold(F::zero(), |acc, (coefficient, power_sum)| { + acc + coefficient.mul_i128(power_sum) + }); + sum == claim +} + +fn integer_domain_power_sums(domain_start: i64, domain_size: usize, count: usize) -> Vec { + let mut sums = vec![0i128; count]; + for offset in 0..domain_size { + let point = i128::from(domain_start + offset as i64); + let mut power = 1i128; + for sum in &mut sums { + *sum += power; + power *= point; + } + } + sums +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients().len().saturating_sub(1) +} + +fn driver_evals(context: Stage1KernelContext<'_>, value: F) -> Vec> { + context + .program + .evals + .iter() + .filter(|eval| eval.source == context.driver.symbol) + .map(|eval| Stage1NamedEval { + name: eval.name, + oracle: eval.oracle, + value, + }) + .collect() +} + +fn validate_eval_shape( + context: Stage1KernelContext<'_>, + actual: &[Stage1NamedEval], + expected_value: Option, +) -> Result<(), Stage1KernelError> { + let expected = context + .program + .evals + .iter() + .filter(|eval| eval.source == context.driver.symbol) + .collect::>(); + if actual.len() != expected.len() { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "eval count mismatch", + }); + } + for (actual, expected) in actual.iter().zip(expected) { + if actual.name != expected.name { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "eval name mismatch", + }); + } + if actual.oracle != expected.oracle { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "eval oracle mismatch", + }); + } + if expected_value + .as_ref() + .is_some_and(|expected_value| actual.value != *expected_value) + { + return Err(Stage1KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "eval value mismatch", + }); + } + } + Ok(()) +} + +fn run_shape_kernel( + context: Stage1KernelContext<'_>, + transcript: &mut T, +) -> Result, Stage1KernelError> +where + F: Field, + T: Transcript, +{ + match context.kernel.abi { + "jolt_stage1_outer_uniskip" | "jolt_stage1_outer_remaining" => { + Ok(shape_sumcheck_output(context, transcript)) + } + abi => Err(Stage1KernelError::KernelNotImplemented { abi }), + } +} + +fn shape_sumcheck_output( + context: Stage1KernelContext<'_>, + transcript: &mut T, +) -> Stage1SumcheckOutput +where + F: Field, + T: Transcript, +{ + let point = (0..context.driver.num_rounds) + .map(|_| transcript.challenge()) + .collect(); + let evals = context + .program + .evals + .iter() + .filter(|eval| eval.source == context.driver.symbol) + .map(|eval| Stage1NamedEval { + name: eval.name, + oracle: eval.oracle, + value: F::from_u64(eval.index as u64), + }) + .collect(); + Stage1SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + proof: shape_sumcheck_proof(context.driver), + } +} + +fn shape_sumcheck_proof(driver: &Stage1SumcheckDriverPlan) -> SumcheckProof { + let coefficients = vec![F::zero(); driver.degree + 1]; + SumcheckProof { + round_polynomials: (0..driver.num_rounds) + .map(|_| UnivariatePoly::new(coefficients.clone())) + .collect(), + } +} + +#[cfg(test)] +#[expect(clippy::expect_used, reason = "tests use explicit panic messages")] +mod tests { + use jolt_field::{Fr, WithAccumulator}; + use jolt_transcript::{MockTranscript, Transcript}; + + use super::*; + + static KERNELS: &[Stage1KernelPlan] = &[Stage1KernelPlan { + symbol: "kernel", + relation: "relation", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage1_outer_uniskip", + }]; + static FULL_KERNELS: &[Stage1KernelPlan] = &[ + Stage1KernelPlan { + symbol: "uniskip_kernel", + relation: "jolt.stage1.outer.uniskip", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage1_outer_uniskip", + }, + Stage1KernelPlan { + symbol: "remaining_kernel", + relation: "jolt.stage1.outer.remaining", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage1_outer_remaining", + }, + ]; + static CLAIMS: &[Stage1SumcheckClaimPlan] = &[Stage1SumcheckClaimPlan { + symbol: "claim", + stage: "stage", + domain: "domain", + num_rounds: 1, + degree: OUTER_UNISKIP_DEGREE_BOUND, + claim: "zero", + kernel: Some("kernel"), + relation: None, + claim_value: "zero", + input_openings: &[], + }]; + static BATCHES: &[Stage1SumcheckBatchPlan] = &[Stage1SumcheckBatchPlan { + symbol: "batch", + stage: "stage", + proof_slot: "proof", + policy: "single", + count: 1, + ordered_claims: &["claim"], + claim_operands: &["claim"], + claim_label: "claim_label", + round_label: "round_label", + round_schedule: &[1], + }]; + static BAD_BATCHES: &[Stage1SumcheckBatchPlan] = &[Stage1SumcheckBatchPlan { + symbol: "batch", + stage: "stage", + proof_slot: "proof", + policy: "single", + count: 2, + ordered_claims: &["claim"], + claim_operands: &["claim"], + claim_label: "claim_label", + round_label: "round_label", + round_schedule: &[1], + }]; + + #[test] + fn cubic_product_coefficients_match_interpolation() { + let eq0 = Fr::from_u64(3); + let eq_delta = Fr::from_u64(5); + let az0 = Fr::from_u64(7); + let az_delta = Fr::from_u64(11); + let bz0 = Fr::from_u64(13); + let bz_delta = Fr::from_u64(17); + + let mut accumulators = + [::Accumulator::default(); OUTER_REMAINING_DEGREE_BOUND + 1]; + accumulate_cubic_product_coefficients( + &mut accumulators, + eq0, + eq_delta, + az0, + az_delta, + bz0, + bz_delta, + ); + let direct = accumulators.map(AdditiveAccumulator::reduce).to_vec(); + + let evals = (0..=OUTER_REMAINING_DEGREE_BOUND) + .map(|x| { + let point = Fr::from_u64(x as u64); + (eq0 + eq_delta * point) * (az0 + az_delta * point) * (bz0 + bz_delta * point) + }) + .collect::>(); + assert_eq!(direct, interpolate_to_coeffs(0, &evals)); + } + + #[test] + fn uniskip_integer_coefficients_match_lagrange_weights() { + for (target, coefficients) in outer_uniskip_targets() + .into_iter() + .zip(OUTER_UNISKIP_TARGET_COEFFS) + { + let weights = lagrange_evals( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + Fr::from_i64(target), + ); + let expected = coefficients.map(Fr::from_i64).to_vec(); + assert_eq!(weights, expected); + } + } + + #[test] + fn integer_coeff_group_matvec_matches_field_weights() { + let mut a_values = [Fr::from_u64(0); OUTER_EQ_CONSTRAINT_ROWS]; + let mut b_values = [Fr::from_u64(0); OUTER_EQ_CONSTRAINT_ROWS]; + for i in 0..OUTER_EQ_CONSTRAINT_ROWS { + a_values[i] = match i % 3 { + 0 => Fr::from_u64(0), + 1 => Fr::from_u64(1), + _ => Fr::from_u64((i + 2) as u64), + }; + b_values[i] = Fr::from_i64(i as i64 - 7); + } + let dots = R1csRowDotSlice { + a: &a_values, + b: &b_values, + }; + let coefficients = &OUTER_UNISKIP_TARGET_COEFFS[3]; + let coefficient_fields = coefficients.map(Fr::from_i64); + let weights = coefficient_fields.to_vec(); + + let integer = Stage1OuterR1csData::group_matvecs_from_integer_coeffs( + &OUTER_FIRST_GROUP_ROWS, + coefficients, + &coefficient_fields, + dots, + ); + let field = + Stage1OuterR1csData::group_matvecs_from_dots(&OUTER_FIRST_GROUP_ROWS, &weights, dots); + assert_eq!(integer, field); + } + + static FULL_CLAIMS: &[Stage1SumcheckClaimPlan] = &[ + Stage1SumcheckClaimPlan { + symbol: "uniskip_claim", + stage: "stage", + domain: "uniskip_domain", + num_rounds: 1, + degree: OUTER_UNISKIP_DEGREE_BOUND, + claim: "zero", + kernel: Some("uniskip_kernel"), + relation: None, + claim_value: "zero", + input_openings: &[], + }, + Stage1SumcheckClaimPlan { + symbol: "remaining_claim", + stage: "stage", + domain: "trace_domain", + num_rounds: 2, + degree: OUTER_REMAINING_DEGREE_BOUND, + claim: "stage1.uniskip.opening", + kernel: Some("remaining_kernel"), + relation: None, + claim_value: "stage1.uniskip.eval", + input_openings: &["stage1.uniskip.opening"], + }, + ]; + static FULL_BATCHES: &[Stage1SumcheckBatchPlan] = &[ + Stage1SumcheckBatchPlan { + symbol: "uniskip_batch", + stage: "stage", + proof_slot: "uniskip_proof", + policy: "single", + count: 1, + ordered_claims: &["uniskip_claim"], + claim_operands: &["uniskip_claim"], + claim_label: "uniskip_claim", + round_label: "uniskip_poly", + round_schedule: &[1], + }, + Stage1SumcheckBatchPlan { + symbol: "remaining_batch", + stage: "stage", + proof_slot: "remaining_proof", + policy: "jolt_core_front_loaded", + count: 1, + ordered_claims: &["remaining_claim"], + claim_operands: &["remaining_claim"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[2], + }, + ]; + static DRIVERS: &[Stage1SumcheckDriverPlan] = &[Stage1SumcheckDriverPlan { + symbol: "driver", + stage: "stage", + proof_slot: "proof", + kernel: Some("kernel"), + relation: None, + batch: "batch", + policy: "single", + round_schedule: &[1], + claim_label: "claim_label", + round_label: "round_label", + num_rounds: 1, + degree: OUTER_UNISKIP_DEGREE_BOUND, + }]; + static FULL_DRIVERS: &[Stage1SumcheckDriverPlan] = &[ + Stage1SumcheckDriverPlan { + symbol: "stage1.uniskip.sumcheck", + stage: "stage", + proof_slot: "uniskip_proof", + kernel: Some("uniskip_kernel"), + relation: None, + batch: "uniskip_batch", + policy: "univariate_skip", + round_schedule: &[1], + claim_label: "uniskip_claim", + round_label: "uniskip_poly", + num_rounds: 1, + degree: OUTER_UNISKIP_DEGREE_BOUND, + }, + Stage1SumcheckDriverPlan { + symbol: "stage1.outer_remaining.sumcheck", + stage: "stage", + proof_slot: "remaining_proof", + kernel: Some("remaining_kernel"), + relation: None, + batch: "remaining_batch", + policy: "jolt_core_front_loaded", + round_schedule: &[2], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: OUTER_REMAINING_DEGREE_BOUND, + }, + ]; + static FULL_EVALS: &[Stage1SumcheckEvalPlan] = &[ + Stage1SumcheckEvalPlan { + symbol: "uniskip_eval", + source: "stage1.uniskip.sumcheck", + name: "stage1.uniskip.eval", + index: 0, + oracle: "UnivariateSkip", + }, + Stage1SumcheckEvalPlan { + symbol: "remaining_eval", + source: "stage1.outer_remaining.sumcheck", + name: "stage1.outer_remaining.eval.Synthetic", + index: 0, + oracle: "Synthetic", + }, + ]; + static SQUEEZES: &[Stage1TranscriptSqueezePlan] = &[Stage1TranscriptSqueezePlan { + symbol: "stage1.tau", + label: "outer_tau", + kind: "challenge_vector", + count: 2, + }]; + static REAL_SQUEEZES: &[Stage1TranscriptSqueezePlan] = &[Stage1TranscriptSqueezePlan { + symbol: "stage1.tau", + label: "outer_tau", + kind: "challenge_vector", + count: 3, + }]; + static PROGRAM: Stage1CpuProgramPlan = Stage1CpuProgramPlan { + params: Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + transcript_squeezes: SQUEEZES, + kernels: KERNELS, + claims: CLAIMS, + batches: BATCHES, + drivers: DRIVERS, + instance_results: &[], + evals: &[], + opening_claims: &[], + opening_batches: &[], + }; + static BAD_PROGRAM: Stage1CpuProgramPlan = Stage1CpuProgramPlan { + params: Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + transcript_squeezes: SQUEEZES, + kernels: KERNELS, + claims: CLAIMS, + batches: BAD_BATCHES, + drivers: DRIVERS, + instance_results: &[], + evals: &[], + opening_claims: &[], + opening_batches: &[], + }; + static FULL_PROGRAM: Stage1CpuProgramPlan = Stage1CpuProgramPlan { + params: Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + transcript_squeezes: SQUEEZES, + kernels: FULL_KERNELS, + claims: FULL_CLAIMS, + batches: FULL_BATCHES, + drivers: FULL_DRIVERS, + instance_results: &[], + evals: FULL_EVALS, + opening_claims: &[], + opening_batches: &[], + }; + static REAL_EVALS: &[Stage1SumcheckEvalPlan] = &[ + Stage1SumcheckEvalPlan { + symbol: "uniskip_eval", + source: "stage1.uniskip.sumcheck", + name: "stage1.uniskip.eval", + index: 0, + oracle: "UnivariateSkip", + }, + Stage1SumcheckEvalPlan { + symbol: "remaining_eval", + source: "stage1.outer_remaining.sumcheck", + name: "stage1.outer_remaining.eval.PC", + index: 0, + oracle: "PC", + }, + ]; + static REAL_PROGRAM: Stage1CpuProgramPlan = Stage1CpuProgramPlan { + params: Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + transcript_squeezes: REAL_SQUEEZES, + kernels: FULL_KERNELS, + claims: FULL_CLAIMS, + batches: FULL_BATCHES, + drivers: FULL_DRIVERS, + instance_results: &[], + evals: REAL_EVALS, + opening_claims: &[], + opening_batches: &[], + }; + + struct SumZeroRemainingEvaluator; + + impl Stage1OuterRemainingEvaluator for SumZeroRemainingEvaluator { + fn evaluate(&self, _context: Stage1OuterRemainingContext<'_, Fr>, point: &[Fr]) -> Fr { + point[0] + point[0] - Fr::from_u64(1) + } + + fn evaluate_virtual_oracle( + &self, + _context: Stage1OuterRemainingContext<'_, Fr>, + oracle: &str, + point: &[Fr], + ) -> Option { + (oracle == "Synthetic").then(|| point.iter().copied().sum()) + } + } + + #[derive(Default)] + struct RecordingExecutor { + modes: Vec, + drivers: Vec<&'static str>, + } + + impl RecordingExecutor { + fn output( + &mut self, + context: Stage1KernelContext<'_>, + point: F, + ) -> Stage1SumcheckOutput { + self.modes.push(context.mode); + self.drivers.push(context.driver.symbol); + Stage1SumcheckOutput { + driver: context.driver.symbol, + point: vec![point], + evals: Vec::new(), + proof: SumcheckProof::default(), + } + } + } + + impl Stage1KernelExecutor for RecordingExecutor { + fn prove_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Ok(self.output(context, transcript.challenge())) + } + + fn verify_sumcheck( + &mut self, + context: Stage1KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage1KernelError> + where + T: Transcript, + { + Ok(self.output(context, transcript.challenge())) + } + } + + fn noop_r1cs_key_and_witness(num_cycles: usize) -> (R1csKey, Vec) { + let matrices = rv64::rv64_constraints::(); + let key = R1csKey::new(matrices, num_cycles); + let mut witness = vec![Fr::from_u64(0); key.num_cycles * key.num_vars_padded]; + for cycle in 0..key.num_cycles { + let base = cycle * key.num_vars_padded; + witness[base + rv64::V_CONST] = Fr::from_u64(1); + witness[base + rv64::V_FLAG_DO_NOT_UPDATE_UNEXPANDED_PC] = Fr::from_u64(1); + key.matrices + .check_witness(&witness[base..base + rv64::NUM_VARS_PER_CYCLE]) + .expect("noop cycle satisfies RV64 constraints"); + } + (key, witness) + } + + #[test] + fn execute_stage1_program_dispatches_driver_to_executor() { + let mut executor = RecordingExecutor::default(); + let mut transcript = MockTranscript::::new(b"stage1"); + let artifacts = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect("dispatch succeeds"); + + assert_eq!(executor.modes, vec![Stage1ExecutionMode::Prover]); + assert_eq!(executor.drivers, vec!["driver"]); + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.challenge_vectors.len(), 1); + assert_eq!(artifacts.sumchecks[0].driver, "driver"); + assert_eq!(artifacts.sumchecks[0].point.len(), 1); + } + + #[test] + fn execute_stage1_program_rejects_static_count_mismatch() { + let mut executor = RecordingExecutor::default(); + let mut transcript = MockTranscript::::new(b"stage1"); + let error = execute_stage1_program( + &BAD_PROGRAM, + Stage1ExecutionMode::Verifier, + &mut executor, + &mut transcript, + ) + .expect_err("bad static plan rejected"); + + assert_eq!( + error, + Stage1KernelError::PlanCountMismatch { + artifact: "batch", + expected: 2, + actual: 1, + } + ); + assert!(executor.drivers.is_empty()); + } + + #[test] + fn shape_kernel_executor_runs_known_stage1_kernel_abis() { + let mut executor = Stage1ShapeKernelExecutor; + let mut transcript = MockTranscript::::new(b"stage1"); + let artifacts = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Verifier, + &mut executor, + &mut transcript, + ) + .expect("shape kernel dispatch succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].driver, "driver"); + assert_eq!(artifacts.sumchecks[0].point.len(), 1); + assert_eq!(artifacts.sumchecks[0].proof.round_polynomials.len(), 1); + assert_eq!( + artifacts.sumchecks[0].proof.round_polynomials[0] + .coefficients() + .len(), + OUTER_UNISKIP_DEGREE_BOUND + 1 + ); + } + + #[test] + fn prover_kernel_executor_requires_uniskip_extended_evals() { + let inputs = Stage1ProverInputs::::empty(1); + let mut executor = Stage1ProverKernelExecutor::new(inputs); + let mut transcript = MockTranscript::::new(b"stage1"); + let error = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect_err("real prover requires extended evaluations"); + + assert_eq!( + error, + Stage1KernelError::MissingKernelInput { + kernel: "jolt_stage1_outer_uniskip", + input: "uniskip_extended_evals", + } + ); + } + + #[test] + fn uniskip_kernel_prover_verifier_self_parity() { + let extended_evals = (1..=OUTER_UNISKIP_DEGREE) + .map(|index| Fr::from_u64(index as u64)) + .collect::>(); + let inputs = Stage1ProverInputs::empty(1).with_uniskip_extended_evals(&extended_evals); + let mut prover_executor = Stage1ProverKernelExecutor::new(inputs); + let mut prover_transcript = MockTranscript::::new(b"stage1"); + let prover_artifacts = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Prover, + &mut prover_executor, + &mut prover_transcript, + ) + .expect("uniskip prover succeeds"); + + let proof = Stage1Proof::from(prover_artifacts.clone()); + let mut verifier_executor = Stage1VerifierKernelExecutor::new(&proof); + let mut verifier_transcript = MockTranscript::::new(b"stage1"); + let verifier_artifacts = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Verifier, + &mut verifier_executor, + &mut verifier_transcript, + ) + .expect("uniskip verifier accepts prover proof"); + + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + assert_eq!(prover_artifacts.sumchecks.len(), 1); + assert_eq!(verifier_artifacts.sumchecks.len(), 1); + assert_eq!( + prover_artifacts.sumchecks[0].point, + verifier_artifacts.sumchecks[0].point + ); + assert_eq!( + prover_artifacts.sumchecks[0].proof.round_polynomials[0].coefficients(), + verifier_artifacts.sumchecks[0].proof.round_polynomials[0].coefficients() + ); + } + + #[test] + fn full_stage1_uniskip_and_remaining_self_parity() { + let extended_evals = vec![Fr::from_u64(0); OUTER_UNISKIP_DEGREE]; + let evaluator = SumZeroRemainingEvaluator; + let inputs = Stage1ProverInputs::empty(1) + .with_uniskip_extended_evals(&extended_evals) + .with_outer_remaining_evaluator(&evaluator); + let mut prover_executor = Stage1ProverKernelExecutor::new(inputs); + let mut prover_transcript = MockTranscript::::new(b"stage1"); + let prover_artifacts = execute_stage1_program( + &FULL_PROGRAM, + Stage1ExecutionMode::Prover, + &mut prover_executor, + &mut prover_transcript, + ) + .expect("full stage1 prover succeeds"); + + let proof = Stage1Proof::from(prover_artifacts.clone()); + let mut verifier_executor = Stage1VerifierKernelExecutor::new(&proof); + let mut verifier_transcript = MockTranscript::::new(b"stage1"); + let verifier_artifacts = execute_stage1_program( + &FULL_PROGRAM, + Stage1ExecutionMode::Verifier, + &mut verifier_executor, + &mut verifier_transcript, + ) + .expect("full stage1 verifier accepts prover proof"); + + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + assert_eq!(prover_artifacts.sumchecks.len(), 2); + assert_eq!(verifier_artifacts.sumchecks.len(), 2); + assert_eq!( + prover_artifacts.sumchecks[1].point, + verifier_artifacts.sumchecks[1].point + ); + assert_eq!(prover_artifacts.sumchecks[1].evals.len(), 1); + assert_eq!( + prover_artifacts.sumchecks[1].evals[0].value, + verifier_artifacts.sumchecks[1].evals[0].value + ); + } + + #[test] + fn full_stage1_r1cs_data_self_parity() { + let (key, witness) = noop_r1cs_key_and_witness(2); + let data = Stage1OuterR1csData::new(&key, &witness).expect("valid R1CS witness shape"); + let inputs = + Stage1ProverInputs::empty(key.num_cycle_vars()).with_outer_remaining_evaluator(&data); + let mut prover_executor = Stage1ProverKernelExecutor::new(inputs); + let mut prover_transcript = MockTranscript::::new(b"stage1"); + let prover_artifacts = execute_stage1_program( + &REAL_PROGRAM, + Stage1ExecutionMode::Prover, + &mut prover_executor, + &mut prover_transcript, + ) + .expect("real R1CS-backed stage1 prover succeeds"); + + let proof = Stage1Proof::from(prover_artifacts.clone()); + let mut verifier_executor = Stage1VerifierKernelExecutor::new(&proof); + let mut verifier_transcript = MockTranscript::::new(b"stage1"); + let verifier_artifacts = execute_stage1_program( + &REAL_PROGRAM, + Stage1ExecutionMode::Verifier, + &mut verifier_executor, + &mut verifier_transcript, + ) + .expect("real R1CS-backed stage1 verifier accepts prover proof"); + + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + assert_eq!(prover_artifacts.sumchecks.len(), 2); + assert_eq!(verifier_artifacts.sumchecks.len(), 2); + assert_eq!( + prover_artifacts.sumchecks[1].evals[0].value, + verifier_artifacts.sumchecks[1].evals[0].value + ); + } + + #[test] + fn full_stage1_r1cs_data_verifier_rejects_tampered_remaining_round() { + let (key, witness) = noop_r1cs_key_and_witness(2); + let data = Stage1OuterR1csData::new(&key, &witness).expect("valid R1CS witness shape"); + let inputs = + Stage1ProverInputs::empty(key.num_cycle_vars()).with_outer_remaining_evaluator(&data); + let mut prover_executor = Stage1ProverKernelExecutor::new(inputs); + let mut prover_transcript = MockTranscript::::new(b"stage1"); + let prover_artifacts = execute_stage1_program( + &REAL_PROGRAM, + Stage1ExecutionMode::Prover, + &mut prover_executor, + &mut prover_transcript, + ) + .expect("real R1CS-backed stage1 prover succeeds"); + + let mut proof = Stage1Proof::from(prover_artifacts); + let remaining = &mut proof.sumchecks[1].proof.round_polynomials[0]; + let mut coefficients = remaining.clone().into_coefficients(); + coefficients[0] += Fr::from_u64(1); + *remaining = UnivariatePoly::new(coefficients); + + let mut verifier_executor = Stage1VerifierKernelExecutor::new(&proof); + let mut verifier_transcript = MockTranscript::::new(b"stage1"); + let error = execute_stage1_program( + &REAL_PROGRAM, + Stage1ExecutionMode::Verifier, + &mut verifier_executor, + &mut verifier_transcript, + ) + .expect_err("tampered remaining round is rejected"); + + assert_eq!( + error, + Stage1KernelError::InvalidProof { + driver: "stage1.outer_remaining.sumcheck", + reason: "outer remaining round check failed", + } + ); + } + + #[test] + fn verifier_kernel_executor_rejects_invalid_uniskip_proof() { + let proof = Stage1Proof { + sumchecks: vec![Stage1SumcheckOutput { + driver: "driver", + point: Vec::new(), + evals: Vec::new(), + proof: SumcheckProof::default(), + }], + }; + let mut executor = Stage1VerifierKernelExecutor::new(&proof); + let mut transcript = MockTranscript::::new(b"stage1"); + let error = execute_stage1_program( + &PROGRAM, + Stage1ExecutionMode::Verifier, + &mut executor, + &mut transcript, + ) + .expect_err("empty verifier proof is invalid"); + + assert_eq!( + error, + Stage1KernelError::InvalidProof { + driver: "driver", + reason: "missing uniskip round polynomial", + } + ); + } +} diff --git a/crates/jolt-kernels/src/stage1/README.md b/crates/jolt-kernels/src/stage1/README.md new file mode 100644 index 0000000000..1e9fa3a517 --- /dev/null +++ b/crates/jolt-kernels/src/stage1/README.md @@ -0,0 +1,17 @@ +Stage 1 kernel modules +====================== + +`stage1.rs` owns the generated-code ABI: static plans, sumcheck execution, +proof verification, and the generic R1CS-backed fallback evaluator. + +`rv64_typed.rs` owns the RV64 coarse CPU specialization. It must remain a +semantic refinement of the generic R1CS evaluator: typed oracle evaluations and +sumcheck products are tested against the R1CS column path before equivalence +tests compare Bolt against jolt-core. + +Future Stage 1 kernels should follow the same shape: + +- Keep protocol scheduling in `stage1.rs`. +- Put workload-specific arithmetic in a focused typed module. +- Preserve a generic fallback or parity oracle for new specializations. +- Add a local typed-vs-generic test before wiring core equivalence. diff --git a/crates/jolt-kernels/src/stage1/rv64_typed.rs b/crates/jolt-kernels/src/stage1/rv64_typed.rs new file mode 100644 index 0000000000..579a8df3da --- /dev/null +++ b/crates/jolt-kernels/src/stage1/rv64_typed.rs @@ -0,0 +1,1207 @@ +use std::cmp::Ordering; + +use jolt_field::signed::{S128, S160, S192, S64}; +use jolt_field::{Fr, Limbs}; +use jolt_poly::lagrange::{lagrange_evals, lagrange_kernel_eval}; +use jolt_poly::{EqPolynomial, UnivariatePoly}; +use jolt_r1cs::R1csKey; +use rayon::prelude::*; + +use super::{ + boolean_index, DenseOuterState, Stage1KernelError, Stage1OuterR1csData, + Stage1OuterRemainingContext, Stage1OuterRemainingEvaluator, Stage1RemainingRoundProof, + OUTER_SECOND_GROUP_ROWS, OUTER_UNISKIP_BASE_START, OUTER_UNISKIP_DEGREE, + OUTER_UNISKIP_DOMAIN_SIZE, OUTER_UNISKIP_TARGET_COEFFS, +}; + +const RV64_NUM_CIRCUIT_FLAGS: usize = 14; +const FLAG_ADD_OPERANDS: usize = 0; +const FLAG_SUBTRACT_OPERANDS: usize = 1; +const FLAG_MULTIPLY_OPERANDS: usize = 2; +const FLAG_LOAD: usize = 3; +const FLAG_STORE: usize = 4; +const FLAG_JUMP: usize = 5; +const FLAG_WRITE_LOOKUP_OUTPUT_TO_RD: usize = 6; +const FLAG_VIRTUAL_INSTRUCTION: usize = 7; +const FLAG_ASSERT: usize = 8; +const FLAG_DO_NOT_UPDATE_UNEXPANDED_PC: usize = 9; +const FLAG_ADVICE: usize = 10; +const FLAG_IS_COMPRESSED: usize = 11; +const FLAG_IS_FIRST_IN_SEQUENCE: usize = 12; +const FLAG_IS_LAST_IN_SEQUENCE: usize = 13; + +#[derive(Clone, Copy, Debug)] +pub struct Stage1Rv64Cycle { + pub left_input: u64, + pub right_input: S64, + pub product: S128, + pub left_lookup: u64, + pub right_lookup: u128, + pub lookup_output: u64, + pub rs1_read_value: u64, + pub rs2_read_value: u64, + pub rd_write_value: u64, + pub ram_addr: u64, + pub ram_read_value: u64, + pub ram_write_value: u64, + pub pc: u64, + pub next_pc: u64, + pub unexpanded_pc: u64, + pub next_unexpanded_pc: u64, + pub imm: S64, + pub flags: [bool; RV64_NUM_CIRCUIT_FLAGS], + pub should_jump: bool, + pub should_branch: bool, + pub next_is_virtual: bool, + pub next_is_first_in_sequence: bool, +} + +impl Stage1Rv64Cycle { + pub fn padding() -> Self { + let mut flags = [false; RV64_NUM_CIRCUIT_FLAGS]; + flags[FLAG_DO_NOT_UPDATE_UNEXPANDED_PC] = true; + Self { + left_input: 0, + right_input: S64::from_u64(0), + product: S128::from_u64(0), + left_lookup: 0, + right_lookup: 0, + lookup_output: 0, + rs1_read_value: 0, + rs2_read_value: 0, + rd_write_value: 0, + ram_addr: 0, + ram_read_value: 0, + ram_write_value: 0, + pc: 0, + next_pc: 0, + unexpanded_pc: 0, + next_unexpanded_pc: 0, + imm: S64::from_u64(0), + flags, + should_jump: false, + should_branch: false, + next_is_virtual: false, + next_is_first_in_sequence: false, + } + } +} + +#[derive(Debug)] +pub struct Stage1OuterRv64Data<'a> { + field_data: Stage1OuterR1csData<'a, Fr>, + cycles: &'a [Stage1Rv64Cycle], +} + +impl<'a> Stage1OuterRv64Data<'a> { + pub fn new( + key: &'a R1csKey, + witness: &'a [Fr], + cycles: &'a [Stage1Rv64Cycle], + ) -> Result { + if cycles.len() != key.num_cycles { + return Err(Stage1KernelError::InvalidInputLength { + input: "rv64_cycles", + expected: key.num_cycles, + actual: cycles.len(), + }); + } + Ok(Self { + field_data: Stage1OuterR1csData::new(key, witness)?, + cycles, + }) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterRv64Data::dense_outer_state")] + fn dense_outer_state( + &self, + context: Stage1OuterRemainingContext<'_, Fr>, + num_rounds: usize, + batching_coeff: Fr, + ) -> DenseOuterState { + let tau_high = context.tau[context.tau.len() - 1]; + let tau_low = &context.tau[..context.tau.len() - 1]; + let lagrange_tau_r0 = lagrange_kernel_eval( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + tau_high, + context.r0, + ); + let weights = lagrange_evals( + OUTER_UNISKIP_BASE_START, + OUTER_UNISKIP_DOMAIN_SIZE, + context.r0, + ); + let len = 1usize << num_rounds; + let scale = lagrange_tau_r0 * batching_coeff; + let eq_evals = EqPolynomial::new(tau_low.to_vec()).evaluations(); + let mut eq = vec![Fr::from_u64(0); len]; + let mut az = vec![Fr::from_u64(0); len]; + let mut bz = vec![Fr::from_u64(0); len]; + eq.par_chunks_mut(2) + .zip(az.par_chunks_mut(2)) + .zip(bz.par_chunks_mut(2)) + .enumerate() + .for_each(|(cycle, ((eq_pair, az_pair), bz_pair))| { + let index = cycle << 1; + let eval = Stage1Rv64Eval::new(&self.cycles[cycle]); + let (az_g0, bz_g0) = eval.first_group_linear(&weights); + let (az_g1, bz_g1) = eval.second_group_linear(&weights); + eq_pair[0] = eq_evals[index] * scale; + az_pair[0] = az_g0; + bz_pair[0] = bz_g0; + eq_pair[1] = eq_evals[index + 1] * scale; + az_pair[1] = az_g1; + bz_pair[1] = bz_g1; + }); + DenseOuterState { + eq, + az, + bz, + eq_scratch: Vec::with_capacity(len / 2), + az_scratch: Vec::with_capacity(len / 2), + bz_scratch: Vec::with_capacity(len / 2), + } + } +} + +impl Stage1OuterRemainingEvaluator for Stage1OuterRv64Data<'_> { + fn evaluate(&self, context: Stage1OuterRemainingContext<'_, Fr>, point: &[Fr]) -> Fr { + self.field_data.evaluate(context, point) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterRv64Data::uniskip_extended_evals")] + fn uniskip_extended_evals(&self, tau: &[Fr]) -> Option> { + if tau.len() != self.field_data.key.num_cycle_vars() + 2 { + return None; + } + let tau_low = &tau[..tau.len() - 1]; + let num_rounds = self.field_data.key.num_cycle_vars() + 1; + let eq_evals = EqPolynomial::new(tau_low.to_vec()).evaluations(); + let num_cycles = 1usize << (num_rounds - 1); + if self.cycles.len() != num_cycles { + return None; + } + let accumulators = (0..num_cycles) + .into_par_iter() + .fold( + || [FrSignedProductAccumulator::zero(); OUTER_UNISKIP_DEGREE], + |mut local, cycle| { + let eval = Stage1Rv64Eval::new(&self.cycles[cycle]); + let (first_products, second_products) = eval.uniskip_products(); + let index = cycle << 1; + for (target, accumulator) in local.iter_mut().enumerate() { + accumulator.fmadd_s192(eq_evals[index], first_products[target]); + accumulator.fmadd_s192(eq_evals[index + 1], second_products[target]); + } + local + }, + ) + .reduce( + || [FrSignedProductAccumulator::zero(); OUTER_UNISKIP_DEGREE], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + Some( + accumulators + .into_iter() + .map(FrSignedProductAccumulator::reduce) + .collect(), + ) + } + + fn evaluate_virtual_oracle( + &self, + context: Stage1OuterRemainingContext<'_, Fr>, + oracle: &str, + point: &[Fr], + ) -> Option { + self.evaluate_virtual_oracles(context, &[oracle], point) + .and_then(|values| values.into_iter().next()) + } + + #[tracing::instrument(skip_all, name = "Stage1OuterRv64Data::evaluate_virtual_oracles")] + fn evaluate_virtual_oracles( + &self, + _context: Stage1OuterRemainingContext<'_, Fr>, + oracles: &[&str], + point: &[Fr], + ) -> Option> { + if point.len() != self.field_data.key.num_cycle_vars() + 1 { + return None; + } + let rv64_oracles = oracles + .iter() + .map(|oracle| Stage1Rv64Oracle::from_name(oracle)) + .collect::>>()?; + let cycle_point = Stage1OuterR1csData::::remaining_cycle_point(point); + if let Some(cycle) = boolean_index(&cycle_point) { + let row = self.cycles.get(cycle)?; + return Some( + rv64_oracles + .iter() + .map(|oracle| oracle.field_value(row)) + .collect(), + ); + } + + let eq = EqPolynomial::new(cycle_point).evaluations(); + let accumulators = eq + .par_iter() + .take(self.cycles.len()) + .enumerate() + .fold( + || vec![FrSignedProductAccumulator::zero(); rv64_oracles.len()], + |mut local, (cycle, &weight)| { + let row = &self.cycles[cycle]; + for (accumulator, oracle) in local.iter_mut().zip(&rv64_oracles) { + accumulator.fmadd_rv64_scalar(weight, oracle.scalar(row)); + } + local + }, + ) + .reduce( + || vec![FrSignedProductAccumulator::zero(); rv64_oracles.len()], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + Some( + accumulators + .into_iter() + .map(FrSignedProductAccumulator::reduce) + .collect(), + ) + } + + fn prove_remaining_rounds( + &self, + context: Stage1OuterRemainingContext<'_, Fr>, + num_rounds: usize, + batching_coeff: Fr, + initial_claim: Fr, + observe_round: &mut dyn FnMut(&UnivariatePoly) -> Fr, + ) -> Option> { + let mut state = self.dense_outer_state(context, num_rounds, batching_coeff); + let mut running_sum = initial_claim * batching_coeff; + let mut point = Vec::with_capacity(num_rounds); + let mut round_polynomials = Vec::with_capacity(num_rounds); + + for _round in 0..num_rounds { + let poly = state.round_poly(); + if poly.evaluate(Fr::from_u64(0)) + poly.evaluate(Fr::from_u64(1)) != running_sum { + return Some(Err(Stage1KernelError::InvalidProof { + driver: "stage1.outer.remaining", + reason: "dense outer remaining claim mismatch", + })); + } + let challenge = observe_round(&poly); + running_sum = poly.evaluate(challenge); + state.bind(challenge); + point.push(challenge); + round_polynomials.push(poly); + } + Some(Ok((point, round_polynomials))) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Stage1Rv64Oracle { + LeftInstructionInput, + RightInstructionInput, + Product, + ShouldBranch, + Pc, + UnexpandedPc, + Imm, + RamAddress, + Rs1Value, + Rs2Value, + RdWriteValue, + RamReadValue, + RamWriteValue, + LeftLookupOperand, + RightLookupOperand, + NextUnexpandedPc, + NextPc, + NextIsVirtual, + NextIsFirstInSequence, + LookupOutput, + ShouldJump, + OpFlagAddOperands, + OpFlagSubtractOperands, + OpFlagMultiplyOperands, + OpFlagLoad, + OpFlagStore, + OpFlagJump, + OpFlagWriteLookupOutputToRd, + OpFlagVirtualInstruction, + OpFlagAssert, + OpFlagDoNotUpdateUnexpandedPc, + OpFlagAdvice, + OpFlagIsCompressed, + OpFlagIsFirstInSequence, + OpFlagIsLastInSequence, +} + +impl Stage1Rv64Oracle { + fn from_name(name: &str) -> Option { + match name { + "LeftInstructionInput" => Some(Self::LeftInstructionInput), + "RightInstructionInput" => Some(Self::RightInstructionInput), + "Product" => Some(Self::Product), + "ShouldBranch" => Some(Self::ShouldBranch), + "PC" => Some(Self::Pc), + "UnexpandedPC" => Some(Self::UnexpandedPc), + "Imm" => Some(Self::Imm), + "RamAddress" => Some(Self::RamAddress), + "Rs1Value" => Some(Self::Rs1Value), + "Rs2Value" => Some(Self::Rs2Value), + "RdWriteValue" => Some(Self::RdWriteValue), + "RamReadValue" => Some(Self::RamReadValue), + "RamWriteValue" => Some(Self::RamWriteValue), + "LeftLookupOperand" => Some(Self::LeftLookupOperand), + "RightLookupOperand" => Some(Self::RightLookupOperand), + "NextUnexpandedPC" => Some(Self::NextUnexpandedPc), + "NextPC" => Some(Self::NextPc), + "NextIsVirtual" => Some(Self::NextIsVirtual), + "NextIsFirstInSequence" => Some(Self::NextIsFirstInSequence), + "LookupOutput" => Some(Self::LookupOutput), + "ShouldJump" => Some(Self::ShouldJump), + "OpFlagAddOperands" => Some(Self::OpFlagAddOperands), + "OpFlagSubtractOperands" => Some(Self::OpFlagSubtractOperands), + "OpFlagMultiplyOperands" => Some(Self::OpFlagMultiplyOperands), + "OpFlagLoad" => Some(Self::OpFlagLoad), + "OpFlagStore" => Some(Self::OpFlagStore), + "OpFlagJump" => Some(Self::OpFlagJump), + "OpFlagWriteLookupOutputToRD" => Some(Self::OpFlagWriteLookupOutputToRd), + "OpFlagVirtualInstruction" => Some(Self::OpFlagVirtualInstruction), + "OpFlagAssert" => Some(Self::OpFlagAssert), + "OpFlagDoNotUpdateUnexpandedPC" => Some(Self::OpFlagDoNotUpdateUnexpandedPc), + "OpFlagAdvice" => Some(Self::OpFlagAdvice), + "OpFlagIsCompressed" => Some(Self::OpFlagIsCompressed), + "OpFlagIsFirstInSequence" => Some(Self::OpFlagIsFirstInSequence), + "OpFlagIsLastInSequence" => Some(Self::OpFlagIsLastInSequence), + _ => None, + } + } + + #[inline] + fn scalar(self, row: &Stage1Rv64Cycle) -> Stage1Rv64Scalar { + match self { + Self::LeftInstructionInput => Stage1Rv64Scalar::U64(row.left_input), + Self::RightInstructionInput => Stage1Rv64Scalar::S64(row.right_input), + Self::Product => Stage1Rv64Scalar::S128(row.product), + Self::ShouldBranch => Stage1Rv64Scalar::Bool(row.should_branch), + Self::Pc => Stage1Rv64Scalar::U64(row.pc), + Self::UnexpandedPc => Stage1Rv64Scalar::U64(row.unexpanded_pc), + Self::Imm => Stage1Rv64Scalar::S64(row.imm), + Self::RamAddress => Stage1Rv64Scalar::U64(row.ram_addr), + Self::Rs1Value => Stage1Rv64Scalar::U64(row.rs1_read_value), + Self::Rs2Value => Stage1Rv64Scalar::U64(row.rs2_read_value), + Self::RdWriteValue => Stage1Rv64Scalar::U64(row.rd_write_value), + Self::RamReadValue => Stage1Rv64Scalar::U64(row.ram_read_value), + Self::RamWriteValue => Stage1Rv64Scalar::U64(row.ram_write_value), + Self::LeftLookupOperand => Stage1Rv64Scalar::U64(row.left_lookup), + Self::RightLookupOperand => Stage1Rv64Scalar::U128(row.right_lookup), + Self::NextUnexpandedPc => Stage1Rv64Scalar::U64(row.next_unexpanded_pc), + Self::NextPc => Stage1Rv64Scalar::U64(row.next_pc), + Self::NextIsVirtual => Stage1Rv64Scalar::Bool(row.next_is_virtual), + Self::NextIsFirstInSequence => Stage1Rv64Scalar::Bool(row.next_is_first_in_sequence), + Self::LookupOutput => Stage1Rv64Scalar::U64(row.lookup_output), + Self::ShouldJump => Stage1Rv64Scalar::Bool(row.should_jump), + Self::OpFlagAddOperands => Stage1Rv64Scalar::Bool(row.flags[FLAG_ADD_OPERANDS]), + Self::OpFlagSubtractOperands => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_SUBTRACT_OPERANDS]) + } + Self::OpFlagMultiplyOperands => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_MULTIPLY_OPERANDS]) + } + Self::OpFlagLoad => Stage1Rv64Scalar::Bool(row.flags[FLAG_LOAD]), + Self::OpFlagStore => Stage1Rv64Scalar::Bool(row.flags[FLAG_STORE]), + Self::OpFlagJump => Stage1Rv64Scalar::Bool(row.flags[FLAG_JUMP]), + Self::OpFlagWriteLookupOutputToRd => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_WRITE_LOOKUP_OUTPUT_TO_RD]) + } + Self::OpFlagVirtualInstruction => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_VIRTUAL_INSTRUCTION]) + } + Self::OpFlagAssert => Stage1Rv64Scalar::Bool(row.flags[FLAG_ASSERT]), + Self::OpFlagDoNotUpdateUnexpandedPc => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_DO_NOT_UPDATE_UNEXPANDED_PC]) + } + Self::OpFlagAdvice => Stage1Rv64Scalar::Bool(row.flags[FLAG_ADVICE]), + Self::OpFlagIsCompressed => Stage1Rv64Scalar::Bool(row.flags[FLAG_IS_COMPRESSED]), + Self::OpFlagIsFirstInSequence => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_IS_FIRST_IN_SEQUENCE]) + } + Self::OpFlagIsLastInSequence => { + Stage1Rv64Scalar::Bool(row.flags[FLAG_IS_LAST_IN_SEQUENCE]) + } + } + } + + #[inline] + fn field_value(self, row: &Stage1Rv64Cycle) -> Fr { + let mut accumulator = FrSignedProductAccumulator::zero(); + accumulator.fmadd_rv64_scalar(Fr::from_u64(1), self.scalar(row)); + accumulator.reduce() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Stage1Rv64Scalar { + Bool(bool), + U64(u64), + U128(u128), + S64(S64), + S128(S128), +} + +struct Stage1Rv64Eval<'a> { + row: &'a Stage1Rv64Cycle, +} + +impl<'a> Stage1Rv64Eval<'a> { + fn new(row: &'a Stage1Rv64Cycle) -> Self { + Self { row } + } + + #[inline] + fn first_group_linear(&self, weights: &[Fr]) -> (Fr, Fr) { + let mut az = Fr::from_u64(0); + let mut bz = FrSignedProductAccumulator::zero(); + + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[0], + self.not_load_store(), + S128::from_u64(self.row.ram_addr), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[1], + self.row.flags[FLAG_LOAD], + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.ram_read_value, + self.row.ram_write_value, + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[2], + self.row.flags[FLAG_LOAD], + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.ram_read_value, + self.row.rd_write_value, + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[3], + self.row.flags[FLAG_STORE], + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.rs2_read_value, + self.row.ram_write_value, + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[4], + self.add_sub_mul(), + S128::from_u64(self.row.left_lookup), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[5], + !self.add_sub_mul(), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.left_lookup, + self.row.left_input, + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[6], + self.row.flags[FLAG_ASSERT], + S128::zero_extend_from(&S64::from_diff_u64s(self.row.lookup_output, 1)), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[7], + self.row.should_jump, + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.next_unexpanded_pc, + self.row.lookup_output, + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[8], + self.row.flags[FLAG_VIRTUAL_INSTRUCTION] && !self.row.flags[FLAG_IS_LAST_IN_SEQUENCE], + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.next_pc, + self.row.pc.wrapping_add(1), + )), + ); + Self::accumulate_first_linear( + &mut az, + &mut bz, + weights[9], + self.row.next_is_virtual && !self.row.next_is_first_in_sequence, + S128::from_u64(u64::from(!self.row.flags[FLAG_DO_NOT_UPDATE_UNEXPANDED_PC])), + ); + + (az, bz.reduce()) + } + + #[inline] + fn second_group_linear(&self, weights: &[Fr]) -> (Fr, Fr) { + let mut az = Fr::from_u64(0); + let mut bz = FrSignedProductAccumulator::zero(); + + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[0], + self.load_or_store(), + S192::from_i128(self.ram_addr_minus_rs1_plus_imm()), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[1], + self.row.flags[FLAG_ADD_OPERANDS], + (S160::from(self.row.right_lookup) - S160::from(self.right_add_expected())) + .to_signed_bigint_nplus1::<3>(), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[2], + self.row.flags[FLAG_SUBTRACT_OPERANDS], + (S160::from(self.row.right_lookup) - S160::from(self.right_sub_expected())) + .to_signed_bigint_nplus1::<3>(), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[3], + self.row.flags[FLAG_MULTIPLY_OPERANDS], + (S160::from(self.row.right_lookup) - S160::from(self.row.product)) + .to_signed_bigint_nplus1::<3>(), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[4], + !self.add_sub_mul_advice(), + (S160::from(self.row.right_lookup) + - S160::from(S128::zero_extend_from(&self.row.right_input))) + .to_signed_bigint_nplus1::<3>(), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[5], + self.row.flags[FLAG_WRITE_LOOKUP_OUTPUT_TO_RD], + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.rd_write_value, + self.row.lookup_output, + )), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[6], + self.row.flags[FLAG_JUMP], + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.rd_write_value, + self.expected_pc_plus_const(), + )), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[7], + self.row.should_branch, + S192::from_i128(self.next_unexpanded_pc_minus_pc_plus_imm()), + ); + Self::accumulate_second_linear( + &mut az, + &mut bz, + weights[8], + !self.row.flags[FLAG_JUMP] && !self.row.should_branch, + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.next_unexpanded_pc, + self.expected_next_unexpanded_pc(), + )), + ); + + (az, bz.reduce()) + } + + #[inline] + fn uniskip_products(&self) -> ([S192; OUTER_UNISKIP_DEGREE], [S192; OUTER_UNISKIP_DEGREE]) { + let (first_guards, first_terms) = self.first_group_terms(); + let (second_guards, second_terms) = self.second_group_terms(); + ( + core::array::from_fn(|target| { + Self::first_group_product_from_terms(target, &first_guards, &first_terms) + }), + core::array::from_fn(|target| { + Self::second_group_product_from_terms(target, &second_guards, &second_terms) + }), + ) + } + + #[inline] + fn first_group_terms( + &self, + ) -> ( + [bool; OUTER_UNISKIP_DOMAIN_SIZE], + [S128; OUTER_UNISKIP_DOMAIN_SIZE], + ) { + ( + [ + self.not_load_store(), + self.row.flags[FLAG_LOAD], + self.row.flags[FLAG_LOAD], + self.row.flags[FLAG_STORE], + self.add_sub_mul(), + !self.add_sub_mul(), + self.row.flags[FLAG_ASSERT], + self.row.should_jump, + self.row.flags[FLAG_VIRTUAL_INSTRUCTION] + && !self.row.flags[FLAG_IS_LAST_IN_SEQUENCE], + self.row.next_is_virtual && !self.row.next_is_first_in_sequence, + ], + [ + S128::from_u64(self.row.ram_addr), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.ram_read_value, + self.row.ram_write_value, + )), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.ram_read_value, + self.row.rd_write_value, + )), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.rs2_read_value, + self.row.ram_write_value, + )), + S128::from_u64(self.row.left_lookup), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.left_lookup, + self.row.left_input, + )), + S128::zero_extend_from(&S64::from_diff_u64s(self.row.lookup_output, 1)), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.next_unexpanded_pc, + self.row.lookup_output, + )), + S128::zero_extend_from(&S64::from_diff_u64s( + self.row.next_pc, + self.row.pc.wrapping_add(1), + )), + S128::from_u64(u64::from(!self.row.flags[FLAG_DO_NOT_UPDATE_UNEXPANDED_PC])), + ], + ) + } + + #[inline] + fn second_group_terms( + &self, + ) -> ( + [bool; OUTER_SECOND_GROUP_ROWS.len()], + [S192; OUTER_SECOND_GROUP_ROWS.len()], + ) { + ( + [ + self.load_or_store(), + self.row.flags[FLAG_ADD_OPERANDS], + self.row.flags[FLAG_SUBTRACT_OPERANDS], + self.row.flags[FLAG_MULTIPLY_OPERANDS], + !self.add_sub_mul_advice(), + self.row.flags[FLAG_WRITE_LOOKUP_OUTPUT_TO_RD], + self.row.flags[FLAG_JUMP], + self.row.should_branch, + !self.row.flags[FLAG_JUMP] && !self.row.should_branch, + ], + [ + S192::from_i128(self.ram_addr_minus_rs1_plus_imm()), + (S160::from(self.row.right_lookup) - S160::from(self.right_add_expected())) + .to_signed_bigint_nplus1::<3>(), + (S160::from(self.row.right_lookup) - S160::from(self.right_sub_expected())) + .to_signed_bigint_nplus1::<3>(), + (S160::from(self.row.right_lookup) - S160::from(self.row.product)) + .to_signed_bigint_nplus1::<3>(), + (S160::from(self.row.right_lookup) + - S160::from(S128::zero_extend_from(&self.row.right_input))) + .to_signed_bigint_nplus1::<3>(), + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.rd_write_value, + self.row.lookup_output, + )), + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.rd_write_value, + self.expected_pc_plus_const(), + )), + S192::from_i128(self.next_unexpanded_pc_minus_pc_plus_imm()), + S192::zero_extend_from(&S64::from_diff_u64s( + self.row.next_unexpanded_pc, + self.expected_next_unexpanded_pc(), + )), + ], + ) + } + + #[inline] + fn first_group_product_from_terms( + target: usize, + guards: &[bool; OUTER_UNISKIP_DOMAIN_SIZE], + terms: &[S128; OUTER_UNISKIP_DOMAIN_SIZE], + ) -> S192 { + let coefficients = OUTER_UNISKIP_TARGET_COEFFS[target]; + let mut az = 0i32; + let mut bz = S128::zero(); + for ((&guard, &term), &coefficient) in guards.iter().zip(terms).zip(&coefficients) { + Self::accumulate_first(&mut az, &mut bz, coefficient as i32, guard, term); + } + S64::from_i64(az as i64).mul_trunc::<2, 3>(&bz) + } + + #[inline] + fn second_group_product_from_terms( + target: usize, + guards: &[bool; OUTER_SECOND_GROUP_ROWS.len()], + terms: &[S192; OUTER_SECOND_GROUP_ROWS.len()], + ) -> S192 { + let coefficients = OUTER_UNISKIP_TARGET_COEFFS[target]; + let mut az = 0i32; + let mut bz = S192::zero(); + for ((&guard, &term), &coefficient) in guards.iter().zip(terms).zip(&coefficients) { + Self::accumulate_second(&mut az, &mut bz, coefficient as i32, guard, term); + } + S64::from_i64(az as i64).mul_trunc::<3, 3>(&bz) + } + + #[inline] + fn accumulate_first_linear( + az: &mut Fr, + bz: &mut FrSignedProductAccumulator, + weight: Fr, + guard: bool, + term: S128, + ) { + if guard { + *az += weight; + } else { + bz.fmadd_s128(weight, term); + } + } + + #[inline] + fn accumulate_second_linear( + az: &mut Fr, + bz: &mut FrSignedProductAccumulator, + weight: Fr, + guard: bool, + term: S192, + ) { + if guard { + *az += weight; + } else { + bz.fmadd_s192(weight, term); + } + } + + #[inline] + fn accumulate_first(az: &mut i32, bz: &mut S128, coefficient: i32, guard: bool, term: S128) { + if guard { + *az += coefficient; + } else { + fmadd_i32_s128(bz, coefficient, term); + } + } + + #[inline] + fn accumulate_second(az: &mut i32, bz: &mut S192, coefficient: i32, guard: bool, term: S192) { + if guard { + *az += coefficient; + } else { + fmadd_i32_s192(bz, coefficient, term); + } + } + + #[inline] + fn not_load_store(&self) -> bool { + !self.load_or_store() + } + + #[inline] + fn load_or_store(&self) -> bool { + self.row.flags[FLAG_LOAD] || self.row.flags[FLAG_STORE] + } + + #[inline] + fn add_sub_mul(&self) -> bool { + self.row.flags[FLAG_ADD_OPERANDS] + || self.row.flags[FLAG_SUBTRACT_OPERANDS] + || self.row.flags[FLAG_MULTIPLY_OPERANDS] + } + + #[inline] + fn add_sub_mul_advice(&self) -> bool { + self.add_sub_mul() || self.row.flags[FLAG_ADVICE] + } + + #[inline] + fn ram_addr_minus_rs1_plus_imm(&self) -> i128 { + let expected = if self.row.imm.is_positive { + self.row.rs1_read_value as i128 + self.row.imm.magnitude_as_u64() as i128 + } else { + self.row.rs1_read_value as i128 - self.row.imm.magnitude_as_u64() as i128 + }; + self.row.ram_addr as i128 - expected + } + + #[inline] + fn right_add_expected(&self) -> i128 { + self.row.left_input as i128 + self.row.right_input.to_i128() + } + + #[inline] + fn right_sub_expected(&self) -> i128 { + self.row.left_input as i128 - self.row.right_input.to_i128() + (1i128 << 64) + } + + #[inline] + fn expected_pc_plus_const(&self) -> u64 { + let const_term = 4 - if self.row.flags[FLAG_IS_COMPRESSED] { + 2 + } else { + 0 + }; + self.row.unexpanded_pc.wrapping_add(const_term) + } + + #[inline] + fn next_unexpanded_pc_minus_pc_plus_imm(&self) -> i128 { + self.row.next_unexpanded_pc as i128 + - (self.row.unexpanded_pc as i128 + self.row.imm.to_i128()) + } + + #[inline] + fn expected_next_unexpanded_pc(&self) -> u64 { + let const_term = + 4 - if self.row.flags[FLAG_DO_NOT_UPDATE_UNEXPANDED_PC] { + 4 + } else { + 0 + } - if self.row.flags[FLAG_IS_COMPRESSED] { + 2 + } else { + 0 + }; + self.row.unexpanded_pc.wrapping_add(const_term) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct FrSignedProductAccumulator { + positive: Limbs<9>, + negative: Limbs<9>, +} + +impl FrSignedProductAccumulator { + #[inline] + fn zero() -> Self { + Self { + positive: Limbs::zero(), + negative: Limbs::zero(), + } + } + + #[inline] + fn fmadd_s192(&mut self, field: Fr, scalar: S192) { + if scalar.magnitude_limbs() == [0u64; 3] { + return; + } + self.fmadd_limbs(field, &scalar.magnitude, scalar.is_positive); + } + + #[inline] + fn fmadd_rv64_scalar(&mut self, field: Fr, scalar: Stage1Rv64Scalar) { + match scalar { + Stage1Rv64Scalar::Bool(value) => { + if value { + self.add_positive_field(field); + } + } + Stage1Rv64Scalar::U64(value) => self.fmadd_u64(field, value), + Stage1Rv64Scalar::U128(value) => self.fmadd_u128(field, value), + Stage1Rv64Scalar::S64(value) => self.fmadd_s64(field, value), + Stage1Rv64Scalar::S128(value) => self.fmadd_s128(field, value), + } + } + + #[inline] + fn fmadd_u64(&mut self, field: Fr, scalar: u64) { + if scalar == 0 { + return; + } + if scalar == 1 { + self.add_positive_field(field); + return; + } + self.fmadd_limbs(field, &Limbs::<1>::from_u64(scalar), true); + } + + #[inline] + fn fmadd_u128(&mut self, field: Fr, scalar: u128) { + if scalar == 0 { + return; + } + if scalar <= u64::MAX as u128 { + self.fmadd_u64(field, scalar as u64); + return; + } + self.fmadd_limbs( + field, + &Limbs::<2>::new([scalar as u64, (scalar >> 64) as u64]), + true, + ); + } + + #[inline] + fn fmadd_s64(&mut self, field: Fr, scalar: S64) { + if scalar.magnitude_limbs() == [0u64; 1] { + return; + } + if scalar.is_positive { + self.fmadd_u64(field, scalar.magnitude_as_u64()); + return; + } + self.fmadd_limbs(field, scalar.as_magnitude(), false); + } + + #[inline] + fn fmadd_s128(&mut self, field: Fr, scalar: S128) { + if scalar.magnitude_limbs() == [0u64; 2] { + return; + } + self.fmadd_limbs(field, scalar.as_magnitude(), scalar.is_positive); + } + + #[inline] + fn add_positive_field(&mut self, field: Fr) { + self.positive + .add_assign_trunc::<9>(&Limbs::<9>::zero_extend_from::<4>(&field.inner_limbs())); + } + + #[inline] + fn fmadd_limbs(&mut self, field: Fr, scalar: &Limbs, is_positive: bool) { + let mut product = Limbs::<9>::zero(); + product.fmadd::<4, L>(&field.inner_limbs(), scalar); + if is_positive { + self.positive.add_assign_trunc::<9>(&product); + } else { + self.negative.add_assign_trunc::<9>(&product); + } + } + + #[inline] + fn merge(&mut self, other: Self) { + self.positive.add_assign_trunc::<9>(&other.positive); + self.negative.add_assign_trunc::<9>(&other.negative); + } + + #[inline] + fn reduce(self) -> Fr { + match self.positive.cmp(&self.negative) { + Ordering::Greater | Ordering::Equal => { + let difference = self.positive.sub_trunc::<9, 9>(&self.negative); + Fr::from_barrett_reduced_limbs(difference) + } + Ordering::Less => { + let difference = self.negative.sub_trunc::<9, 9>(&self.positive); + -Fr::from_barrett_reduced_limbs(difference) + } + } + } +} + +#[inline] +fn fmadd_i32_s128(sum: &mut S128, coefficient: i32, term: S128) { + if coefficient == 0 || term.magnitude_as_u128() == 0 { + return; + } + let coefficient_s64 = S64::from_i64(coefficient as i64); + *sum += coefficient_s64.mul_trunc::<2, 2>(&term); +} + +#[inline] +fn fmadd_i32_s192(sum: &mut S192, coefficient: i32, term: S192) { + if coefficient == 0 || term.magnitude_limbs() == [0u64; 3] { + return; + } + let coefficient_s64 = S64::from_i64(coefficient as i64); + *sum += coefficient_s64.mul_trunc::<3, 3>(&term); +} + +#[cfg(test)] +#[expect(clippy::expect_used, reason = "tests use explicit panic messages")] +mod tests { + use jolt_field::Fr; + use jolt_r1cs::{constraints::rv64, R1csKey}; + + use super::*; + + static RV64_ORACLE_NAMES: &[&str] = &[ + "LeftInstructionInput", + "RightInstructionInput", + "Product", + "ShouldBranch", + "PC", + "UnexpandedPC", + "Imm", + "RamAddress", + "Rs1Value", + "Rs2Value", + "RdWriteValue", + "RamReadValue", + "RamWriteValue", + "LeftLookupOperand", + "RightLookupOperand", + "NextUnexpandedPC", + "NextPC", + "NextIsVirtual", + "NextIsFirstInSequence", + "LookupOutput", + "ShouldJump", + "OpFlagAddOperands", + "OpFlagSubtractOperands", + "OpFlagMultiplyOperands", + "OpFlagLoad", + "OpFlagStore", + "OpFlagJump", + "OpFlagWriteLookupOutputToRD", + "OpFlagVirtualInstruction", + "OpFlagAssert", + "OpFlagDoNotUpdateUnexpandedPC", + "OpFlagAdvice", + "OpFlagIsCompressed", + "OpFlagIsFirstInSequence", + "OpFlagIsLastInSequence", + ]; + + fn rv64_eval_test_cycles() -> Vec { + let mut first = Stage1Rv64Cycle::padding(); + first.left_input = 7; + first.right_input = S64::from_i64(-5); + first.product = S128::from_i128(-35); + first.left_lookup = 11; + first.right_lookup = u128::MAX - 4; + first.lookup_output = 1; + first.rs1_read_value = 13; + first.rs2_read_value = 17; + first.rd_write_value = 19; + first.ram_addr = 23; + first.ram_read_value = 29; + first.ram_write_value = 31; + first.pc = 37; + first.next_pc = 41; + first.unexpanded_pc = 43; + first.next_unexpanded_pc = 47; + first.imm = S64::from_i64(-53); + first.flags[FLAG_ADD_OPERANDS] = true; + first.flags[FLAG_LOAD] = true; + first.flags[FLAG_IS_FIRST_IN_SEQUENCE] = true; + first.should_branch = true; + first.next_is_virtual = true; + + let mut second = Stage1Rv64Cycle::padding(); + second.left_input = 59; + second.right_input = S64::from_u64(61); + second.product = S128::from_u128(3599); + second.left_lookup = 67; + second.right_lookup = 71; + second.lookup_output = 73; + second.rs1_read_value = 79; + second.rs2_read_value = 83; + second.rd_write_value = 89; + second.ram_addr = 97; + second.ram_read_value = 101; + second.ram_write_value = 103; + second.pc = 107; + second.next_pc = 109; + second.unexpanded_pc = 113; + second.next_unexpanded_pc = 127; + second.imm = S64::from_u64(131); + second.flags[FLAG_MULTIPLY_OPERANDS] = true; + second.flags[FLAG_STORE] = true; + second.flags[FLAG_JUMP] = true; + second.flags[FLAG_IS_LAST_IN_SEQUENCE] = true; + second.should_jump = true; + second.next_is_first_in_sequence = true; + + vec![first, second] + } + + fn rv64_eval_test_witness(key: &R1csKey, cycles: &[Stage1Rv64Cycle]) -> Vec { + let mut witness = vec![Fr::from_u64(0); key.num_cycles * key.num_vars_padded]; + for (cycle, row) in cycles.iter().enumerate() { + let base = cycle * key.num_vars_padded; + witness[base + rv64::V_CONST] = Fr::from_u64(1); + for name in RV64_ORACLE_NAMES { + let oracle = Stage1Rv64Oracle::from_name(name).expect("known RV64 oracle"); + let variable = + super::super::r1cs_oracle_variable(name).expect("known R1CS variable"); + witness[base + variable] = oracle.field_value(row); + } + } + witness + } + + #[test] + fn typed_virtual_oracle_evals_match_r1cs_columns() { + let cycles = rv64_eval_test_cycles(); + let key = R1csKey::new(rv64::rv64_constraints::(), cycles.len()); + let witness = rv64_eval_test_witness(&key, &cycles); + let r1cs_data = Stage1OuterR1csData::new(&key, &witness).expect("valid witness shape"); + let rv64_data = + Stage1OuterRv64Data::new(&key, &witness, &cycles).expect("valid RV64 shape"); + let tau = [Fr::from_u64(0); 3]; + let context = Stage1OuterRemainingContext { + tau: &tau, + r0: Fr::from_u64(0), + }; + + for point in [ + vec![Fr::from_u64(3), Fr::from_u64(5)], + vec![Fr::from_u64(3), Fr::from_u64(1)], + ] { + assert_eq!( + rv64_data.evaluate_virtual_oracles(context, RV64_ORACLE_NAMES, &point), + r1cs_data.evaluate_virtual_oracles(context, RV64_ORACLE_NAMES, &point) + ); + } + } +} diff --git a/crates/jolt-kernels/src/stage2.rs b/crates/jolt-kernels/src/stage2.rs new file mode 100644 index 0000000000..cacdd27cd9 --- /dev/null +++ b/crates/jolt-kernels/src/stage2.rs @@ -0,0 +1,5201 @@ +use std::borrow::Cow; +use std::cmp::Ordering; +use std::error::Error; +use std::fmt::{self, Display, Formatter}; +use std::mem::MaybeUninit; + +use crate::dense::{bind_dense_evals_reuse, DENSE_BIND_PAR_THRESHOLD}; +use crate::split_eq::SplitEqState; +use jolt_field::signed::{S128, S256}; +use jolt_field::{AdditiveAccumulator, Field, Fr, Limbs, RingAccumulator}; +use jolt_poly::lagrange::{interpolate_to_coeffs, lagrange_evals, lagrange_kernel_eval}; +use jolt_poly::EqPolynomial; +use jolt_poly::UnivariatePoly; +use jolt_sumcheck::SumcheckProof; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use rayon::prelude::*; + +const PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START: i64 = -1; +const PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE: usize = 3; +const PRODUCT_VIRTUAL_UNISKIP_DEGREE: usize = 2; +const PRODUCT_VIRTUAL_UNISKIP_EXTENDED_START: i64 = -(PRODUCT_VIRTUAL_UNISKIP_DEGREE as i64); +const PRODUCT_VIRTUAL_UNISKIP_EXTENDED_SIZE: usize = 2 * PRODUCT_VIRTUAL_UNISKIP_DEGREE + 1; +const PRODUCT_VIRTUAL_UNISKIP_NUM_COEFFS: usize = 3 * PRODUCT_VIRTUAL_UNISKIP_DEGREE + 1; +const PRODUCT_VIRTUAL_UNISKIP_TARGET_COEFFS: [[i32; PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE]; + PRODUCT_VIRTUAL_UNISKIP_DEGREE] = [[3, -3, 1], [1, -3, 3]]; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage2ExecutionMode { + Prover, + Verifier, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage2Relation { + ProductVirtualUniskip, + RamReadWrite, + ProductVirtualRemainder, + InstructionLookupClaimReduction, + RamRafEvaluation, + RamOutputCheck, + Batched, +} + +impl Stage2Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage2.product_virtual.uniskip" => Some(Self::ProductVirtualUniskip), + "jolt.stage2.ram.read_write" => Some(Self::RamReadWrite), + "jolt.stage2.product_virtual.remainder" => Some(Self::ProductVirtualRemainder), + "jolt.stage2.instruction_lookup.claim_reduction" => { + Some(Self::InstructionLookupClaimReduction) + } + "jolt.stage2.ram.raf_evaluation" => Some(Self::RamRafEvaluation), + "jolt.stage2.ram.output_check" => Some(Self::RamOutputCheck), + "jolt.stage2.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::ProductVirtualUniskip => "jolt.stage2.product_virtual.uniskip", + Self::RamReadWrite => "jolt.stage2.ram.read_write", + Self::ProductVirtualRemainder => "jolt.stage2.product_virtual.remainder", + Self::InstructionLookupClaimReduction => { + "jolt.stage2.instruction_lookup.claim_reduction" + } + Self::RamRafEvaluation => "jolt.stage2.ram.raf_evaluation", + Self::RamOutputCheck => "jolt.stage2.ram.output_check", + Self::Batched => "jolt.stage2.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage2KernelAbi { + ProductVirtualUniskip, + RamReadWrite, + ProductVirtualRemainder, + InstructionLookupClaimReduction, + RamRafEvaluation, + RamOutputCheck, + Batched, +} + +impl Stage2KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage2_product_virtual_uniskip" => Some(Self::ProductVirtualUniskip), + "jolt_stage2_ram_read_write" => Some(Self::RamReadWrite), + "jolt_stage2_product_virtual_remainder" => Some(Self::ProductVirtualRemainder), + "jolt_stage2_instruction_lookup_claim_reduction" => { + Some(Self::InstructionLookupClaimReduction) + } + "jolt_stage2_ram_raf_evaluation" => Some(Self::RamRafEvaluation), + "jolt_stage2_ram_output_check" => Some(Self::RamOutputCheck), + "jolt_stage2_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::ProductVirtualUniskip => "jolt_stage2_product_virtual_uniskip", + Self::RamReadWrite => "jolt_stage2_ram_read_write", + Self::ProductVirtualRemainder => "jolt_stage2_product_virtual_remainder", + Self::InstructionLookupClaimReduction => { + "jolt_stage2_instruction_lookup_claim_reduction" + } + Self::RamRafEvaluation => "jolt_stage2_ram_raf_evaluation", + Self::RamOutputCheck => "jolt_stage2_ram_output_check", + Self::Batched => "jolt_stage2_batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +impl Stage2KernelPlan { + pub fn relation_kind(&self) -> Result { + Stage2Relation::from_symbol(self.relation).ok_or(Stage2KernelError::UnknownRelation { + relation: self.relation, + }) + } + + pub fn abi_kind(&self) -> Result { + Stage2KernelAbi::from_name(self.abi) + .ok_or(Stage2KernelError::UnknownKernelAbi { abi: self.abi }) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2TranscriptSqueezePlan { + pub symbol: &'static str, + pub label: &'static str, + pub kind: &'static str, + pub count: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2FieldConstantPlan { + pub symbol: &'static str, + pub field: &'static str, + pub value: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2FieldExprPlan { + pub symbol: &'static str, + pub kind: &'static str, + pub formula: &'static str, + pub operand_names: &'static [&'static str], + pub operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2SumcheckClaimPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub domain: &'static str, + pub num_rounds: usize, + pub degree: usize, + pub claim: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub claim_value: &'static str, + pub input_openings: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2SumcheckBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], + pub claim_label: &'static str, + pub round_label: &'static str, + pub round_schedule: &'static [usize], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2SumcheckDriverPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub batch: &'static str, + pub policy: &'static str, + pub round_schedule: &'static [usize], + pub claim_label: &'static str, + pub round_label: &'static str, + pub num_rounds: usize, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2SumcheckInstanceResultPlan { + pub symbol: &'static str, + pub source: &'static str, + pub claim: &'static str, + pub relation: &'static str, + pub index: usize, + pub point_arity: usize, + pub num_rounds: usize, + pub round_offset: usize, + pub point_order: &'static str, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2SumcheckEvalPlan { + pub symbol: &'static str, + pub source: &'static str, + pub name: &'static str, + pub index: usize, + pub oracle: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2PointSlicePlan { + pub symbol: &'static str, + pub source: &'static str, + pub offset: usize, + pub length: usize, + pub input: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2PointConcatPlan { + pub symbol: &'static str, + pub layout: &'static str, + pub arity: usize, + pub inputs: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, + pub point_source: &'static str, + pub eval_source: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2OpeningBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2ProgramStepPlan { + pub kind: &'static str, + pub symbol: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2CpuProgramPlan { + pub params: Stage2Params, + pub steps: &'static [Stage2ProgramStepPlan], + pub transcript_squeezes: &'static [Stage2TranscriptSqueezePlan], + pub opening_inputs: &'static [Stage2OpeningInputPlan], + pub field_constants: &'static [Stage2FieldConstantPlan], + pub field_exprs: &'static [Stage2FieldExprPlan], + pub kernels: &'static [Stage2KernelPlan], + pub claims: &'static [Stage2SumcheckClaimPlan], + pub batches: &'static [Stage2SumcheckBatchPlan], + pub drivers: &'static [Stage2SumcheckDriverPlan], + pub instance_results: &'static [Stage2SumcheckInstanceResultPlan], + pub evals: &'static [Stage2SumcheckEvalPlan], + pub point_slices: &'static [Stage2PointSlicePlan], + pub point_concats: &'static [Stage2PointConcatPlan], + pub opening_claims: &'static [Stage2OpeningClaimPlan], + pub opening_batches: &'static [Stage2OpeningBatchPlan], +} + +impl Stage2CpuProgramPlan { + pub fn kernel(&self, symbol: &str) -> Option<&Stage2KernelPlan> { + find_kernel(self, symbol) + } + + pub fn batch(&self, symbol: &str) -> Option<&Stage2SumcheckBatchPlan> { + find_batch(self, symbol) + } + + pub fn claim(&self, symbol: &str) -> Option<&Stage2SumcheckClaimPlan> { + self.claims.iter().find(|claim| claim.symbol == symbol) + } + + pub fn evals_for_driver<'a>( + &'a self, + driver: &'a str, + ) -> impl Iterator + 'a { + self.evals.iter().filter(move |eval| eval.source == driver) + } + + pub fn instance_results_for_driver<'a>( + &'a self, + driver: &'a str, + ) -> impl Iterator + 'a { + self.instance_results + .iter() + .filter(move |instance| instance.source == driver) + } +} + +#[derive(Clone, Debug)] +pub struct Stage2NamedEval { + pub name: &'static str, + pub oracle: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage2SumcheckOutput { + pub driver: &'static str, + pub point: Vec, + pub evals: Vec>, + pub opening_claims: Vec>, + pub proof: SumcheckProof, +} + +#[derive(Clone, Debug)] +pub struct Stage2ChallengeVector { + pub symbol: &'static str, + pub values: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage2OpeningClaimValue { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub claim_kind: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Debug)] +pub struct Stage2ExecutionArtifacts { + pub challenge_vectors: Vec>, + pub sumchecks: Vec>, + pub opening_claims: Vec>, + pub opening_batches: Vec<&'static Stage2OpeningBatchPlan>, +} + +impl Default for Stage2ExecutionArtifacts { + fn default() -> Self { + Self { + challenge_vectors: Vec::new(), + sumchecks: Vec::new(), + opening_claims: Vec::new(), + opening_batches: Vec::new(), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage2Proof { + pub sumchecks: Vec>, +} + +impl From> for Stage2Proof { + fn from(artifacts: Stage2ExecutionArtifacts) -> Self { + Self { + sumchecks: artifacts.sumchecks, + } + } +} + +#[derive(Clone, Debug)] +pub struct Stage2ScalarValue { + pub symbol: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage2PointValue { + pub symbol: &'static str, + pub point: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage2OpeningInputValue { + pub symbol: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2ProductVirtualCycle { + pub instruction_left_input: u64, + pub instruction_right_input: i128, + pub should_branch_lookup_output: u64, + pub write_lookup_output_to_rd_flag: bool, + pub jump_flag: bool, + pub should_branch_flag: bool, + pub not_next_noop: bool, + pub virtual_instruction_flag: bool, +} + +impl Stage2ProductVirtualCycle { + pub fn padding() -> Self { + Self { + instruction_left_input: 0, + instruction_right_input: 0, + should_branch_lookup_output: 0, + write_lookup_output_to_rd_flag: false, + jump_flag: false, + should_branch_flag: false, + not_next_noop: false, + virtual_instruction_flag: false, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2InstructionLookupCycle { + pub lookup_output: u64, + pub left_lookup_operand: u64, + pub right_lookup_operand: u128, + pub left_instruction_input: u64, + pub right_instruction_input: i128, +} + +impl Stage2InstructionLookupCycle { + pub fn padding() -> Self { + Self { + lookup_output: 0, + left_lookup_operand: 0, + right_lookup_operand: 0, + left_instruction_input: 0, + right_instruction_input: 0, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage2RamAccess { + pub remapped_address: Option, + pub read_value: u64, + pub write_value: u64, +} + +impl Stage2RamAccess { + pub fn noop() -> Self { + Self { + remapped_address: None, + read_value: 0, + write_value: 0, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage2RamOutputLayout { + pub io_start: usize, + pub io_end: usize, +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage2RamData<'a> { + pub log_k: usize, + pub start_address: u64, + pub initial_ram: &'a [u64], + pub final_ram: &'a [u64], + pub accesses: &'a [Stage2RamAccess], + pub output_layout: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct Stage2ValueStore { + scalars: Vec>, + points: Vec>, +} + +impl Stage2ValueStore { + pub fn new() -> Self { + Self::default() + } + + pub fn with_opening_inputs(inputs: &[Stage2OpeningInputValue]) -> Self { + let mut store = Self::new(); + store.insert_opening_inputs(inputs); + store + } + + pub fn insert_opening_inputs(&mut self, inputs: &[Stage2OpeningInputValue]) { + for input in inputs { + self.insert_scalar(input.symbol, input.eval); + self.insert_point(input.symbol, input.point.clone()); + } + } + + pub fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some(existing) = self + .scalars + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.value = value; + } else { + self.scalars.push(Stage2ScalarValue { symbol, value }); + } + } + + pub fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some(existing) = self + .points + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.point = point; + } else { + self.points.push(Stage2PointValue { symbol, point }); + } + } + + pub fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.value) + } + + pub fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage2KernelError::MissingValue { symbol }) + } + + pub fn point(&self, symbol: &'static str) -> Result<&[F], Stage2KernelError> { + self.try_point(symbol) + .ok_or(Stage2KernelError::MissingValue { symbol }) + } + + pub fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.point.as_slice()) + } + + pub fn seed_constants( + &mut self, + program: &'static Stage2CpuProgramPlan, + ) -> Result<(), Stage2KernelError> { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + Ok(()) + } + + pub fn observe_challenge_vector( + &mut self, + _program: &'static Stage2CpuProgramPlan, + plan: &'static Stage2TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage2KernelError> { + if matches!(plan.kind, "challenge_scalar" | "scalar") { + if values.len() != 1 { + return Err(Stage2KernelError::InvalidInputLength { + input: plan.symbol, + expected: 1, + actual: values.len(), + }); + } + self.insert_scalar(plan.symbol, values[0]); + } + Ok(()) + } + + pub fn observe_sumcheck_output( + &mut self, + program: &'static Stage2CpuProgramPlan, + output: &Stage2SumcheckOutput, + ) -> Result<(), Stage2KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + pub fn observe_sumcheck_values( + &mut self, + program: &'static Stage2CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage2NamedEval], + ) -> Result<(), Stage2KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program.instance_results_for_driver(driver) { + let end = instance.round_offset + instance.point_arity; + let mut point = point + .get(instance.round_offset..end) + .ok_or(Stage2KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + _ => { + return Err(Stage2KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, point); + } + for eval in program.evals_for_driver(driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage2KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + Ok(()) + } + + pub fn evaluate_available_points( + &mut self, + program: &'static Stage2CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage2KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + verify_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage2CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + let value = evaluate_stage2_field_expr(expr, &operands)?; + self.insert_scalar(expr.symbol, value); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn claim_value( + &mut self, + program: &'static Stage2CpuProgramPlan, + claim: &Stage2SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + pub fn batch_claim_values( + &mut self, + program: &'static Stage2CpuProgramPlan, + batch: &Stage2SumcheckBatchPlan, + ) -> Result, Stage2KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage2KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn try_expr_operands(&self, expr: &Stage2FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage2PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +pub fn evaluate_stage2_field_expr( + expr: &Stage2FieldExprPlan, + operands: &[F], +) -> Result { + if let Some(value) = evaluate_stage2_field_op(expr, operands)? { + return Ok(value); + } + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "jolt_stage2_product_virtual_uniskip_input" => { + require_operand_count(expr.symbol, 4, operands.len())?; + let weights = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + operands[0], + ); + Ok(weights[0] * operands[1] + weights[1] * operands[2] + weights[2] * operands[3]) + } + "jolt_stage2_ram_read_write_input" => { + require_operand_count(expr.symbol, 3, operands.len())?; + Ok(operands[1] + operands[0] * operands[2]) + } + "jolt_stage2_instruction_lookup_input" => { + require_operand_count(expr.symbol, 6, operands.len())?; + let gamma = operands[0]; + let gamma_sqr = gamma.square(); + let gamma_cub = gamma_sqr * gamma; + let gamma_quart = gamma_sqr.square(); + Ok(operands[1] + + gamma * operands[2] + + gamma_sqr * operands[3] + + gamma_cub * operands[4] + + gamma_quart * operands[5]) + } + formula => Err(Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }), + } +} + +fn evaluate_stage2_field_op( + expr: &Stage2FieldExprPlan, + operands: &[F], +) -> Result, Stage2KernelError> { + match expr.formula { + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(Some(operands[0] + operands[1])) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(Some(operands[0] - operands[1])) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(Some(operands[0] * operands[1])) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(Some(-operands[0])) + } + _ => { + if let Some(exponent) = expr.formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + } + })?; + return Ok(Some(pow_field(operands[0], exponent))); + } + if let Some(spec) = expr.formula.strip_prefix("poly.lagrange_basis_eval:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let (domain_start, domain_size, index) = parse_lagrange_basis_spec(expr, spec)?; + let weights = lagrange_evals(domain_start, domain_size, operands[0]); + let value = + weights + .get(index) + .copied() + .ok_or(Stage2KernelError::InvalidInputLength { + input: expr.symbol, + expected: index + 1, + actual: weights.len(), + })?; + return Ok(Some(value)); + } + Ok(None) + } + } +} + +fn parse_lagrange_basis_spec( + expr: &Stage2FieldExprPlan, + spec: &str, +) -> Result<(i64, usize, usize), Stage2KernelError> { + let parts = spec.split(':').collect::>(); + if parts.len() != 3 { + return Err(Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + }); + } + let domain_start = + parts[0] + .parse::() + .map_err(|_| Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + })?; + let domain_size = + parts[1] + .parse::() + .map_err(|_| Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + })?; + let index = parts[2] + .parse::() + .map_err(|_| Stage2KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + })?; + Ok((domain_start, domain_size, index)) +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage2KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage2KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage2KernelContext<'a> { + pub mode: Stage2ExecutionMode, + pub program: &'static Stage2CpuProgramPlan, + pub kernel: &'a Stage2KernelPlan, + pub batch: &'a Stage2SumcheckBatchPlan, + pub driver: &'a Stage2SumcheckDriverPlan, +} + +impl Stage2KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + self.kernel.relation_kind() + } + + pub fn abi_kind(&self) -> Result { + self.kernel.abi_kind() + } + + pub fn batch_claims(&self) -> Result, Stage2KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage2KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage2KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage2TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage2KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage2SumcheckOutput, + ) -> Result<(), Stage2KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage2KernelExecutor; + +impl Stage2KernelExecutor for UnsupportedStage2KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + Err(Stage2KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + Err(Stage2KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } +} + +#[derive(Clone)] +pub struct Stage2ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage2OpeningInputValue], + pub product_uniskip_extended_evals: Option>, + pub product_virtual_cycles: Option<&'a [Stage2ProductVirtualCycle]>, + pub instruction_lookup_cycles: Option<&'a [Stage2InstructionLookupCycle]>, + pub ram: Option<&'a Stage2RamData<'a>>, +} + +impl<'a, F: Field> Stage2ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage2OpeningInputValue]) -> Self { + Self { + opening_inputs, + product_uniskip_extended_evals: None, + product_virtual_cycles: None, + instruction_lookup_cycles: None, + ram: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + product_uniskip_extended_evals: None, + product_virtual_cycles: None, + instruction_lookup_cycles: None, + ram: None, + } + } + + pub fn with_product_uniskip_extended_evals(mut self, evaluations: &'a [F]) -> Self { + self.product_uniskip_extended_evals = Some(Cow::Borrowed(evaluations)); + self + } + + pub fn with_product_virtual_cycles(mut self, cycles: &'a [Stage2ProductVirtualCycle]) -> Self { + self.product_virtual_cycles = Some(cycles); + self + } + + pub fn with_instruction_lookup_cycles( + mut self, + cycles: &'a [Stage2InstructionLookupCycle], + ) -> Self { + self.instruction_lookup_cycles = Some(cycles); + self + } + + pub fn with_ram_data(mut self, ram: &'a Stage2RamData<'a>) -> Self { + self.ram = Some(ram); + self + } +} + +impl<'a> Stage2ProverInputs<'a, Fr> { + pub fn with_product_virtual_witness( + mut self, + cycles: &'a [Stage2ProductVirtualCycle], + ) -> Result { + let tau_low = self + .opening_inputs + .iter() + .find(|input| input.symbol == "stage2.input.stage1.Product") + .map(|input| input.point.as_slice()) + .ok_or(Stage2KernelError::MissingValue { + symbol: "stage2.input.stage1.Product", + })?; + let extended_evals = product_virtual_uniskip_extended_evals(cycles, tau_low)?; + self.product_uniskip_extended_evals = Some(Cow::Owned(extended_evals.to_vec())); + self.product_virtual_cycles = Some(cycles); + Ok(self) + } +} + +#[derive(Clone)] +pub struct Stage2ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage2ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage2ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage2ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage2CpuProgramPlan, + ) -> Result, Stage2KernelError> { + let mut store = Stage2ValueStore::with_opening_inputs(self.inputs.opening_inputs); + store.seed_constants(program)?; + for challenge in &self.challenge_vectors { + store.insert_point(challenge.symbol, challenge.values.clone()); + if let Some(plan) = program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == challenge.symbol) + .filter(|plan| matches!(plan.kind, "challenge_scalar" | "scalar")) + { + if challenge.values.len() != 1 { + return Err(Stage2KernelError::InvalidInputLength { + input: plan.symbol, + expected: 1, + actual: challenge.values.len(), + }); + } + store.insert_scalar(plan.symbol, challenge.values[0]); + } + } + for output in &self.completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + Ok(store) + } +} + +impl Stage2KernelExecutor for Stage2ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage2TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage2KernelError> { + self.challenge_vectors.push(Stage2ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage2SumcheckOutput, + ) -> Result<(), Stage2KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + prove_stage2_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + Err(Stage2KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage2ExecutionMode::Prover, + actual: Stage2ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage2VerifierKernelExecutor<'a, F: Field> { + pub proof: &'a Stage2Proof, + pub opening_inputs: &'a [Stage2OpeningInputValue], + pub ram: Option<&'a Stage2RamData<'a>>, + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage2VerifierKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage2Proof, + opening_inputs: &'a [Stage2OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + ram: None, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + pub fn with_ram_data(mut self, ram: &'a Stage2RamData<'a>) -> Self { + self.ram = Some(ram); + self + } + + fn value_store( + &self, + program: &'static Stage2CpuProgramPlan, + ) -> Result, Stage2KernelError> { + let mut store = Stage2ValueStore::with_opening_inputs(self.opening_inputs); + store.seed_constants(program)?; + for challenge in &self.challenge_vectors { + store.insert_point(challenge.symbol, challenge.values.clone()); + if let Some(plan) = program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == challenge.symbol) + .filter(|plan| matches!(plan.kind, "challenge_scalar" | "scalar")) + { + if challenge.values.len() != 1 { + return Err(Stage2KernelError::InvalidInputLength { + input: plan.symbol, + expected: 1, + actual: challenge.values.len(), + }); + } + store.insert_scalar(plan.symbol, challenge.values[0]); + } + } + for output in &self.completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + Ok(store) + } +} + +impl Stage2KernelExecutor for Stage2VerifierKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage2TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage2KernelError> { + self.challenge_vectors.push(Stage2ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage2SumcheckOutput, + ) -> Result<(), Stage2KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + Err(Stage2KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage2ExecutionMode::Verifier, + actual: Stage2ExecutionMode::Prover, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage2KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage2KernelError> + where + T: Transcript, + { + let proof = + self.proof + .sumchecks + .get(self.cursor) + .ok_or(Stage2KernelError::MissingProof { + driver: context.driver.symbol, + })?; + self.cursor += 1; + verify_stage2_kernel( + context, + self.value_store(context.program)?, + proof, + self.ram, + transcript, + ) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage2KernelError { + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage2ExecutionMode, + actual: Stage2ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage2KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage2 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage2 driver @{driver} references missing batch @{batch}" + ) + } + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage2 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage2 value @{symbol} is not available") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => write!( + formatter, + "stage2 plan @{artifact} count mismatch: expected {expected}, got {actual}" + ), + Self::InvalidInputLength { + input, + expected, + actual, + } => write!( + formatter, + "stage2 input `{input}` length mismatch: expected {expected}, got {actual}" + ), + Self::UnsupportedFieldExpr { symbol, formula } => write!( + formatter, + "stage2 field expr @{symbol} uses unsupported formula `{formula}`" + ), + Self::UnknownRelation { relation } => { + write!(formatter, "stage2 relation @{relation} is not registered") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "stage2 kernel ABI `{abi}` is not registered") + } + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage2 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => write!( + formatter, + "stage2 driver @{driver} ran with {actual:?} executor path, expected {expected:?}" + ), + Self::MissingProof { driver } => { + write!( + formatter, + "stage2 verifier missing proof for driver @{driver}" + ) + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage2 kernel `{kernel}` missing input `{input}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage2 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage2KernelError {} + +fn prove_stage2_kernel( + context: Stage2KernelContext<'_>, + inputs: &Stage2ProverInputs<'_, F>, + store: Stage2ValueStore, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage2KernelAbi::ProductVirtualUniskip => { + prove_product_virtual_uniskip(context, inputs, store, transcript) + } + Stage2KernelAbi::Batched => prove_batched_stage2(context, inputs, store, transcript), + abi => Err(Stage2KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +fn verify_stage2_kernel( + context: Stage2KernelContext<'_>, + store: Stage2ValueStore, + proof: &Stage2SumcheckOutput, + ram: Option<&Stage2RamData<'_>>, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage2KernelAbi::ProductVirtualUniskip => { + verify_product_virtual_uniskip(context, store, proof, transcript) + } + Stage2KernelAbi::Batched => verify_batched_stage2(context, store, proof, ram, transcript), + abi => Err(Stage2KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +#[tracing::instrument(skip_all, name = "Stage2::prove_product_virtual_uniskip")] +fn prove_product_virtual_uniskip( + context: Stage2KernelContext<'_>, + inputs: &Stage2ProverInputs<'_, F>, + mut store: Stage2ValueStore, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + let claim = + context + .batch_claims()? + .into_iter() + .next() + .ok_or(Stage2KernelError::MissingClaim { + batch: context.batch.symbol, + claim: "stage2.product_virtual.uniskip.input", + })?; + let input_claim = store.claim_value(context.program, claim)?; + let base_evals = product_uniskip_base_evals(&store)?; + let extended_evals = inputs.product_uniskip_extended_evals.as_deref().ok_or( + Stage2KernelError::MissingKernelInput { + kernel: context.kernel.abi, + input: "product_uniskip_extended_evals", + }, + )?; + let poly = build_product_uniskip_poly( + &base_evals, + extended_evals, + store.scalar("stage2.product_virtual.tau_high")?, + )?; + if !product_uniskip_sum_matches(&poly, input_claim) { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "product uniskip input claim mismatch", + }); + } + append_univariate_poly(transcript, context.driver.round_label, &poly); + let r0 = transcript.challenge(); + let eval = poly.evaluate(r0); + append_labeled_scalar(transcript, "opening_claim", &eval); + Ok(Stage2SumcheckOutput { + driver: context.driver.symbol, + point: vec![r0], + evals: driver_evals(context, eval), + opening_claims: Vec::new(), + proof: SumcheckProof { + round_polynomials: vec![poly], + }, + }) +} + +fn verify_product_virtual_uniskip( + context: Stage2KernelContext<'_>, + mut store: Stage2ValueStore, + proof: &Stage2SumcheckOutput, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + let [poly] = proof.proof.round_polynomials.as_slice() else { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected product uniskip round count", + }); + }; + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "product uniskip polynomial exceeds degree bound", + }); + } + let claim = + context + .batch_claims()? + .into_iter() + .next() + .ok_or(Stage2KernelError::MissingClaim { + batch: context.batch.symbol, + claim: "stage2.product_virtual.uniskip.input", + })?; + let input_claim = store.claim_value(context.program, claim)?; + if !product_uniskip_sum_matches(poly, input_claim) { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "product uniskip input claim mismatch", + }); + } + append_univariate_poly(transcript, context.driver.round_label, poly); + let r0 = transcript.challenge(); + if !proof.point.is_empty() && proof.point != [r0] { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "product uniskip point mismatch", + }); + } + let eval = poly.evaluate(r0); + append_labeled_scalar(transcript, "opening_claim", &eval); + let evals = driver_evals(context, eval); + verify_driver_evals(context.driver.symbol, &evals, &proof.evals)?; + Ok(Stage2SumcheckOutput { + driver: context.driver.symbol, + point: vec![r0], + evals, + opening_claims: Vec::new(), + proof: proof.proof.clone(), + }) +} + +#[tracing::instrument(skip_all, name = "Stage2::prove_batched")] +fn prove_batched_stage2( + context: Stage2KernelContext<'_>, + inputs: &Stage2ProverInputs<'_, F>, + mut store: Stage2ValueStore, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut instances = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + instances.push(Stage2BatchedInstance { + claim, + relation: claim_relation(context.program, claim)?, + offset: instance_round_offset(context.program, context.driver.symbol, claim.symbol)?, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state: Stage2ProverInstanceState::new(context.program, claim, inputs, &store)?, + }); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for instance in &mut instances { + let poly = if instance.is_active(round) { + instance + .state + .round_poly(round - instance.offset, instance.previous_claim)? + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + #[cfg(debug_assertions)] + { + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != instance.previous_claim { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched instance round claim mismatch", + }); + } + } + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + #[cfg(debug_assertions)] + { + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + + for (instance, poly) in instances.iter_mut().zip(individual_polys) { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + instance.state.ingest_challenge(challenge)?; + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + for instance in &instances { + evals.extend(instance.state.final_evals(instance.relation)?); + } + let expected = expected_batched_output_claim( + context, + &store, + &evals, + &point, + &batching_coeffs, + inputs.ram, + )?; + if batched_claim != expected { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + Ok(Stage2SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage2( + context: Stage2KernelContext<'_>, + mut store: Stage2ValueStore, + proof: &Stage2SumcheckOutput, + ram: Option<&Stage2RamData<'_>>, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = expected_batched_output_claim( + context, + &store, + &proof.evals, + &point, + &batching_coeffs, + ram, + )?; + if running_claim != expected { + return Err(Stage2KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &proof.evals)?; + let opening_claims = + append_opening_claims(context.program, &mut store, transcript, &proof.evals)?; + Ok(Stage2SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims, + proof: proof.proof.clone(), + }) +} + +struct Stage2BatchedInstance<'a, F: Field> { + claim: &'a Stage2SumcheckClaimPlan, + relation: Stage2Relation, + offset: usize, + previous_claim: F, + state: Stage2ProverInstanceState<'a, F>, +} + +impl Stage2BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage2ProverInstanceState<'a, F: Field> { + RamReadWrite(RamReadWriteState), + ProductVirtualRemainder(ProductRemainderState<'a, F>), + InstructionLookupClaimReduction(InstructionLookupState<'a, F>), + RamRafEvaluation(DenseInstanceState), + RamOutputCheck(RamOutputState<'a, F>), +} + +impl<'a, F: Field> Stage2ProverInstanceState<'a, F> { + fn new( + program: &'static Stage2CpuProgramPlan, + claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'a, F>, + store: &Stage2ValueStore, + ) -> Result { + match claim_relation(program, claim)? { + Stage2Relation::RamReadWrite => Ok(Self::RamReadWrite(RamReadWriteState::new( + claim, inputs, store, + )?)), + Stage2Relation::ProductVirtualRemainder => Ok(Self::ProductVirtualRemainder( + product_remainder_state(claim, inputs, store)?, + )), + Stage2Relation::InstructionLookupClaimReduction => { + Ok(Self::InstructionLookupClaimReduction( + instruction_lookup_state(claim, inputs, store)?, + )) + } + Stage2Relation::RamRafEvaluation => { + Ok(Self::RamRafEvaluation(ram_raf_state(claim, inputs, store)?)) + } + Stage2Relation::RamOutputCheck => Ok(Self::RamOutputCheck(ram_output_state( + claim, inputs, store, + )?)), + relation => Err(Stage2KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + } + + fn round_poly( + &mut self, + round: usize, + previous_claim: F, + ) -> Result, Stage2KernelError> { + match self { + Self::RamReadWrite(state) => state.round_poly(round, previous_claim), + Self::ProductVirtualRemainder(state) => Ok(state.round_poly(previous_claim)), + Self::InstructionLookupClaimReduction(state) => Ok(state.round_poly(previous_claim)), + Self::RamRafEvaluation(state) => Ok(state.round_poly(previous_claim)), + Self::RamOutputCheck(state) => Ok(state.round_poly(previous_claim)), + } + } + + fn ingest_challenge(&mut self, challenge: F) -> Result<(), Stage2KernelError> { + match self { + Self::RamReadWrite(state) => state.ingest_challenge(challenge), + Self::ProductVirtualRemainder(state) => { + state.bind(challenge); + Ok(()) + } + Self::InstructionLookupClaimReduction(state) => { + state.bind(challenge); + Ok(()) + } + Self::RamRafEvaluation(state) => { + state.bind(challenge); + Ok(()) + } + Self::RamOutputCheck(state) => { + state.bind(challenge); + Ok(()) + } + } + } + + fn final_evals( + &self, + relation: Stage2Relation, + ) -> Result>, Stage2KernelError> { + match self { + Self::RamReadWrite(state) => Ok(vec![ + named_eval( + "stage2.ram_read_write.eval.RamVal", + "RamVal", + state.val_eval()?, + ), + named_eval( + "stage2.ram_read_write.eval.RamRa", + "RamRa", + state.ra_eval()?, + ), + named_eval( + "stage2.ram_read_write.eval.RamInc", + "RamInc", + state.inc_eval()?, + ), + ]), + Self::ProductVirtualRemainder(state) => state.final_evals(relation), + Self::InstructionLookupClaimReduction(state) => state.final_evals(relation), + Self::RamOutputCheck(state) => state.final_evals(relation), + Self::RamRafEvaluation(state) => Ok(vec![named_eval( + "stage2.ram_raf.eval.RamRa", + "RamRa", + state.factor_eval(0, relation)?, + )]), + } + } +} + +struct ProductRemainderState<'a, F: Field> { + cycles: &'a [Stage2ProductVirtualCycle], + left: Vec, + right: Vec, + left_scratch: Vec, + right_scratch: Vec, + split_eq: SplitEqState, + point: Vec, +} + +impl ProductRemainderState<'_, F> { + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + product_remainder_split_round_poly(&self.left, &self.right, &self.split_eq, previous_claim) + } + + #[tracing::instrument(skip_all, name = "ProductRemainderState::bind")] + fn bind(&mut self, challenge: F) { + let left = &mut self.left; + let left_scratch = &mut self.left_scratch; + let right = &mut self.right; + let right_scratch = &mut self.right_scratch; + rayon::join( + || bind_dense_evals_reuse(left, left_scratch, challenge), + || bind_dense_evals_reuse(right, right_scratch, challenge), + ); + self.split_eq.bind(challenge); + self.point.push(challenge); + } + + fn final_evals( + &self, + relation: Stage2Relation, + ) -> Result>, Stage2KernelError> { + product_remainder_final_evals(self.cycles, &self.point, relation) + } +} + +#[tracing::instrument(skip_all, name = "ProductRemainderState::round_poly")] +fn product_remainder_split_round_poly( + left: &[F], + right: &[F], + split_eq: &SplitEqState, + previous_claim: F, +) -> UnivariatePoly { + let e_in = split_eq.e_in(); + let e_out = split_eq.e_out(); + let (q_constant, q_quadratic) = if e_in.len() > 1 { + product_remainder_low_round_coefficients(left, right, e_in, e_out) + } else { + product_remainder_high_round_coefficients(left, right, e_in[0], e_out) + }; + gruen_cubic_poly( + split_eq.current_target(), + q_constant, + q_quadratic, + previous_claim, + ) +} + +fn product_remainder_low_round_coefficients( + left: &[F], + right: &[F], + e_in: &[F], + e_out: &[F], +) -> (F, F) { + let in_len = e_in.len(); + let in_pairs = in_len / 2; + if left.len() / 2 >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = (0..e_out.len()) + .into_par_iter() + .map(|x_out| { + let mut local = [F::Accumulator::default(); 2]; + let base = x_out * in_len; + let out_weight = e_out[x_out]; + for pair in 0..in_pairs { + accumulate_product_remainder_quadratic_pair( + &mut local, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + left[base + 2 * pair], + left[base + 2 * pair + 1], + right[base + 2 * pair], + right[base + 2 * pair + 1], + ); + } + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + (accumulators[0].reduce(), accumulators[1].reduce()) + } else { + let mut total = [F::Accumulator::default(); 2]; + for (x_out, &out_weight) in e_out.iter().enumerate() { + let base = x_out * in_len; + for pair in 0..in_pairs { + accumulate_product_remainder_quadratic_pair( + &mut total, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + left[base + 2 * pair], + left[base + 2 * pair + 1], + right[base + 2 * pair], + right[base + 2 * pair + 1], + ); + } + } + (total[0].reduce(), total[1].reduce()) + } +} + +fn product_remainder_high_round_coefficients( + left: &[F], + right: &[F], + in_weight: F, + e_out: &[F], +) -> (F, F) { + let pairs = e_out.len() / 2; + if pairs >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = (0..pairs) + .into_par_iter() + .map(|pair| { + let mut local = [F::Accumulator::default(); 2]; + accumulate_product_remainder_quadratic_pair( + &mut local, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + left[2 * pair], + left[2 * pair + 1], + right[2 * pair], + right[2 * pair + 1], + ); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + (accumulators[0].reduce(), accumulators[1].reduce()) + } else { + let mut total = [F::Accumulator::default(); 2]; + for pair in 0..pairs { + accumulate_product_remainder_quadratic_pair( + &mut total, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + left[2 * pair], + left[2 * pair + 1], + right[2 * pair], + right[2 * pair + 1], + ); + } + (total[0].reduce(), total[1].reduce()) + } +} + +fn accumulate_product_remainder_quadratic_pair( + accumulators: &mut [F::Accumulator; 2], + weight: F, + left0: F, + left1: F, + right0: F, + right1: F, +) { + accumulators[0].fmadd(weight * left0, right0); + accumulators[1].fmadd(weight * (left1 - left0), right1 - right0); +} + +fn gruen_cubic_poly( + target: F, + q_constant: F, + q_quadratic_coeff: F, + previous_claim: F, +) -> UnivariatePoly { + let eq_eval_1 = target; + let eq_eval_0 = F::one() - target; + let eq_delta = eq_eval_1 - eq_eval_0; + let eq_eval_2 = eq_eval_1 + eq_delta; + let eq_eval_3 = eq_eval_2 + eq_delta; + let cubic_eval_0 = eq_eval_0 * q_constant; + let cubic_eval_1 = previous_claim - cubic_eval_0; + let quadratic_eval_1 = cubic_eval_1 / eq_eval_1; + let e_times_2 = q_quadratic_coeff + q_quadratic_coeff; + let quadratic_eval_2 = quadratic_eval_1 + quadratic_eval_1 - q_constant + e_times_2; + let quadratic_eval_3 = quadratic_eval_2 + quadratic_eval_1 - q_constant + e_times_2 + e_times_2; + UnivariatePoly::from_evals(&[ + cubic_eval_0, + cubic_eval_1, + eq_eval_2 * quadratic_eval_2, + eq_eval_3 * quadratic_eval_3, + ]) +} + +struct InstructionLookupState<'a, F: Field> { + cycles: &'a [Stage2InstructionLookupCycle], + r_spartan: Vec, + gamma: F, + gamma_sqr: F, + gamma_cub: F, + gamma_quart: F, + phase: InstructionLookupPhase, +} + +impl InstructionLookupState<'_, F> { + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + self.phase.round_poly(previous_claim) + } + + fn bind(&mut self, challenge: F) { + if let InstructionLookupPhase::Phase1(phase1) = &self.phase { + if phase1.should_transition_to_phase2() { + let mut challenges = phase1.challenges.clone(); + challenges.push(challenge); + self.phase = InstructionLookupPhase::Phase2(InstructionLookupPhase2::new( + self.cycles, + &self.r_spartan, + &challenges, + [self.gamma, self.gamma_sqr, self.gamma_cub, self.gamma_quart], + )); + return; + } + } + self.phase.bind(challenge); + } + + fn final_evals( + &self, + _relation: Stage2Relation, + ) -> Result>, Stage2KernelError> { + let InstructionLookupPhase::Phase2(phase2) = &self.phase else { + return Err(Stage2KernelError::InvalidProof { + driver: Stage2Relation::InstructionLookupClaimReduction.symbol(), + reason: "instruction lookup did not reach phase 2", + }); + }; + phase2.final_evals() + } +} + +enum InstructionLookupPhase { + Phase1(InstructionLookupPhase1), + Phase2(InstructionLookupPhase2), +} + +impl InstructionLookupPhase { + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + match self { + Self::Phase1(state) => state.round_poly(previous_claim), + Self::Phase2(state) => state.round_poly(previous_claim), + } + } + + fn bind(&mut self, challenge: F) { + match self { + Self::Phase1(state) => state.bind(challenge), + Self::Phase2(state) => state.bind(challenge), + } + } +} + +struct InstructionLookupPhase1 { + p: Vec, + q: Vec, + challenges: Vec, +} + +impl InstructionLookupPhase1 { + fn new(cycles: &[Stage2InstructionLookupCycle], r_spartan: &[F], gamma_powers: [F; 4]) -> Self { + let (r_hi, r_lo) = r_spartan.split_at(r_spartan.len() / 2); + let p = EqPolynomial::::evals(r_lo, None); + let eq_suffix = EqPolynomial::::evals(r_hi, None); + let prefix_len = p.len(); + let q = (0..prefix_len) + .into_par_iter() + .map(|x_lo| { + let mut accumulators = [F::Accumulator::default(); 5]; + for (x_hi, &weight) in eq_suffix.iter().enumerate() { + let index = x_lo + (x_hi * prefix_len); + accumulate_instruction_lookup_outputs( + &mut accumulators, + &cycles[index], + weight, + ); + } + combine_instruction_lookup_values( + accumulators.map(AdditiveAccumulator::reduce), + gamma_powers, + ) + }) + .collect(); + Self { + p, + q, + challenges: Vec::new(), + } + } + + #[tracing::instrument(skip_all, name = "InstructionLookupPhase1::round_poly")] + fn round_poly(&self, _previous_claim: F) -> UnivariatePoly { + round_poly_from_factor_slices(&[&self.p, &self.q], 2) + } + + #[tracing::instrument(skip_all, name = "InstructionLookupPhase1::bind")] + fn bind(&mut self, challenge: F) { + self.challenges.push(challenge); + let mut scratch = Vec::new(); + bind_dense_evals_reuse(&mut self.p, &mut scratch, challenge); + bind_dense_evals_reuse(&mut self.q, &mut scratch, challenge); + } + + fn should_transition_to_phase2(&self) -> bool { + self.p.len() == 2 + } +} + +struct InstructionLookupPhase2 { + eq: Vec, + combined: Vec, + outputs: [Vec; 5], +} + +impl InstructionLookupPhase2 { + #[tracing::instrument(skip_all, name = "InstructionLookupPhase2::new")] + fn new( + cycles: &[Stage2InstructionLookupCycle], + r_spartan: &[F], + challenges: &[F], + gamma_powers: [F; 4], + ) -> Self { + let n_remaining_rounds = r_spartan.len() - challenges.len(); + let remaining_len = 1usize << n_remaining_rounds; + let prefix_point = reverse_slice(challenges); + let (r_hi, r_lo) = r_spartan.split_at(r_spartan.len() / 2); + let eq_prefix = EqPolynomial::::mle(&prefix_point, r_lo); + let prefix_eq_evals = EqPolynomial::::evals(&prefix_point, None); + let rows = (0..remaining_len) + .into_par_iter() + .map(|x_hi| { + let start = x_hi * prefix_eq_evals.len(); + let mut accumulators = [F::Accumulator::default(); 5]; + for (x_lo, &weight) in prefix_eq_evals.iter().enumerate() { + accumulate_instruction_lookup_outputs( + &mut accumulators, + &cycles[start + x_lo], + weight, + ); + } + let outputs = accumulators.map(AdditiveAccumulator::reduce); + let combined = combine_instruction_lookup_values(outputs, gamma_powers); + (outputs, combined) + }) + .collect::>(); + let mut outputs = core::array::from_fn(|_| Vec::with_capacity(remaining_len)); + let mut combined = Vec::with_capacity(remaining_len); + for (row_outputs, row_combined) in rows { + for (output, value) in outputs.iter_mut().zip(row_outputs) { + output.push(value); + } + combined.push(row_combined); + } + Self { + eq: EqPolynomial::::evals(r_hi, Some(eq_prefix)), + combined, + outputs, + } + } + + #[tracing::instrument(skip_all, name = "InstructionLookupPhase2::round_poly")] + fn round_poly(&self, _previous_claim: F) -> UnivariatePoly { + round_poly_from_factor_slices(&[&self.eq, &self.combined], 2) + } + + #[tracing::instrument(skip_all, name = "InstructionLookupPhase2::bind")] + fn bind(&mut self, challenge: F) { + let mut scratch = Vec::new(); + bind_dense_evals_reuse(&mut self.eq, &mut scratch, challenge); + bind_dense_evals_reuse(&mut self.combined, &mut scratch, challenge); + for output in &mut self.outputs { + bind_dense_evals_reuse(output, &mut scratch, challenge); + } + } + + fn final_evals(&self) -> Result>, Stage2KernelError> { + INSTRUCTION_LOOKUP_EVAL_NAMES + .iter() + .zip(&self.outputs) + .map(|(&(name, oracle), output)| { + output + .first() + .copied() + .map(|value| named_eval(name, oracle, value)) + .ok_or(Stage2KernelError::InvalidProof { + driver: Stage2Relation::InstructionLookupClaimReduction.symbol(), + reason: "empty instruction lookup output", + }) + }) + .collect() + } +} + +fn combine_instruction_lookup_values(values: [F; 5], gamma_powers: [F; 4]) -> F { + values[0] + + gamma_powers[0] * values[1] + + gamma_powers[1] * values[2] + + gamma_powers[2] * values[3] + + gamma_powers[3] * values[4] +} + +#[derive(Clone)] +struct DenseInstanceState { + factors: Vec>, + factor_scratch: Vec>, + point: Vec, +} + +impl DenseInstanceState { + fn new(factors: Vec>) -> Self { + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Self { + factors, + factor_scratch, + point: Vec::new(), + } + } + + #[tracing::instrument(skip_all, name = "Stage2DenseState::round_poly")] + fn round_poly(&self, _previous_claim: F) -> UnivariatePoly { + round_poly_from_factors(&self.factors, self.degree()) + } + + fn degree(&self) -> usize { + self.factors.len() + } + + #[tracing::instrument(skip_all, name = "Stage2DenseState::bind")] + fn bind(&mut self, challenge: F) { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse(factor, scratch, challenge); + } + self.point.push(challenge); + } + + fn factor_eval(&self, index: usize, relation: Stage2Relation) -> Result { + self.factors + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage2KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty dense factor", + }) + } +} + +#[derive(Clone)] +struct RamOutputState<'a, F: Field> { + dense: DenseInstanceState, + final_ram: &'a [u64], + nonzero_final_ram: Vec<(usize, u64)>, +} + +impl RamOutputState<'_, F> { + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + self.dense.round_poly(previous_claim) + } + + fn bind(&mut self, challenge: F) { + self.dense.bind(challenge); + } + + fn final_evals( + &self, + _relation: Stage2Relation, + ) -> Result>, Stage2KernelError> { + Ok(vec![named_eval( + "stage2.ram_output.eval.RamValFinal", + "RamValFinal", + ram_eval_reversed(self.final_ram, &self.nonzero_final_ram, &self.dense.point), + )]) + } +} + +#[tracing::instrument(skip_all, name = "Stage2::product_remainder_state")] +fn product_remainder_state<'a, F: Field>( + _claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'a, F>, + store: &Stage2ValueStore, +) -> Result, Stage2KernelError> { + let cycles = inputs + .product_virtual_cycles + .ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_product_virtual_remainder", + input: "product_virtual_cycles", + })?; + let tau_low = store.point("stage2.input.stage1.Product")?; + let expected = + 1usize + .checked_shl(tau_low.len() as u32) + .ok_or(Stage2KernelError::InvalidInputLength { + input: "stage2.product_virtual.cycles", + expected: usize::BITS as usize, + actual: tau_low.len(), + })?; + if cycles.len() != expected { + return Err(Stage2KernelError::InvalidInputLength { + input: "stage2.product_virtual.cycles", + expected, + actual: cycles.len(), + }); + } + let tau_high = store.scalar("stage2.product_virtual.tau_high")?; + let r0 = *store + .point("stage2.product_virtual.uniskip.sumcheck")? + .first() + .ok_or(Stage2KernelError::MissingValue { + symbol: "stage2.product_virtual.uniskip.sumcheck", + })?; + let lagrange_tau_r0 = lagrange_kernel_eval( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + tau_high, + r0, + ); + let weights = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + r0, + ); + let mut left = vec![F::zero(); cycles.len()]; + let mut right = vec![F::zero(); cycles.len()]; + left.par_iter_mut() + .zip(right.par_iter_mut()) + .zip(cycles.par_iter()) + .for_each(|((left, right), cycle)| { + *left = weights[0].mul_u64(cycle.instruction_left_input) + + weights[1].mul_u64(cycle.should_branch_lookup_output) + + if cycle.jump_flag { + weights[2] + } else { + F::zero() + }; + *right = weights[0].mul_i128(cycle.instruction_right_input) + + if cycle.should_branch_flag { + weights[1] + } else { + F::zero() + } + + if cycle.not_next_noop { + weights[2] + } else { + F::zero() + }; + }); + Ok(ProductRemainderState { + cycles, + left, + right, + left_scratch: Vec::new(), + right_scratch: Vec::new(), + split_eq: SplitEqState::new_low_to_high(tau_low, Some(lagrange_tau_r0)), + point: Vec::new(), + }) +} + +#[tracing::instrument(skip_all, name = "Stage2::instruction_lookup_state")] +fn instruction_lookup_state<'a, F: Field>( + _claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'a, F>, + store: &Stage2ValueStore, +) -> Result, Stage2KernelError> { + let cycles = inputs + .instruction_lookup_cycles + .ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_instruction_lookup_claim_reduction", + input: "instruction_lookup_cycles", + })?; + let r_spartan = store.point("stage2.input.stage1.LookupOutput")?; + let expected = 1usize.checked_shl(r_spartan.len() as u32).ok_or( + Stage2KernelError::InvalidInputLength { + input: "stage2.instruction_lookup.cycles", + expected: usize::BITS as usize, + actual: r_spartan.len(), + }, + )?; + if cycles.len() != expected { + return Err(Stage2KernelError::InvalidInputLength { + input: "stage2.instruction_lookup.cycles", + expected, + actual: cycles.len(), + }); + } + let gamma = store.scalar("stage2.instruction_lookup.gamma")?; + let gamma_sqr = gamma.square(); + let gamma_cub = gamma_sqr * gamma; + let gamma_quart = gamma_sqr.square(); + Ok(InstructionLookupState { + cycles, + r_spartan: r_spartan.to_vec(), + gamma, + gamma_sqr, + gamma_cub, + gamma_quart, + phase: InstructionLookupPhase::Phase1(InstructionLookupPhase1::new( + cycles, + r_spartan, + [gamma, gamma_sqr, gamma_cub, gamma_quart], + )), + }) +} + +#[tracing::instrument(skip_all, name = "Stage2::ram_raf_state")] +fn ram_raf_state( + claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'_, F>, + store: &Stage2ValueStore, +) -> Result, Stage2KernelError> { + let ram = inputs.ram.ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_raf_evaluation", + input: "ram", + })?; + require_operand_count("stage2.ram_raf.num_rounds", ram.log_k, claim.num_rounds)?; + let r_cycle = store.point("stage2.input.stage1.RamAddress")?; + let eq_cycle = EqPolynomial::::evals(r_cycle, None); + if ram.accesses.len() != eq_cycle.len() { + return Err(Stage2KernelError::InvalidInputLength { + input: "stage2.ram.accesses", + expected: eq_cycle.len(), + actual: ram.accesses.len(), + }); + } + let k = 1usize << ram.log_k; + let mut ra = vec![F::zero(); k]; + for (access, weight) in ram.accesses.iter().zip(eq_cycle) { + if let Some(address) = access.remapped_address { + ra[address] += weight; + } + } + let mut next_address = F::from_u64(ram.start_address); + let address_step = F::from_u64(8); + let mut unmap = Vec::with_capacity(k); + for _ in 0..k { + unmap.push(next_address); + next_address += address_step; + } + Ok(DenseInstanceState::new(vec![ra, unmap])) +} + +#[tracing::instrument(skip_all, name = "Stage2::ram_output_state")] +fn ram_output_state<'a, F: Field>( + claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'a, F>, + store: &Stage2ValueStore, +) -> Result, Stage2KernelError> { + let ram = inputs.ram.ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_output_check", + input: "ram", + })?; + require_operand_count("stage2.ram_output.num_rounds", ram.log_k, claim.num_rounds)?; + let layout = ram + .output_layout + .ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_output_check", + input: "ram.output_layout", + })?; + let k = 1usize << ram.log_k; + require_operand_count("stage2.ram.final_ram", k, ram.final_ram.len())?; + let r_address = store.point("stage2.ram_output.r_address")?; + let eq = EqPolynomial::::evals(r_address, None); + let mut io_mask = vec![F::zero(); k]; + let mut diff = vec![F::zero(); k]; + let mut nonzero_final_ram = Vec::new(); + for index in 0..k { + let final_value = ram.final_ram[index]; + if final_value != 0 { + nonzero_final_ram.push((index, final_value)); + } + if index >= layout.io_start && index < layout.io_end { + io_mask[index] = F::one(); + } else if final_value != 0 { + diff[index] = F::from_u64(final_value); + } + } + Ok(RamOutputState { + dense: DenseInstanceState::new(vec![eq, io_mask, diff]), + final_ram: ram.final_ram, + nonzero_final_ram, + }) +} + +#[derive(Clone, Debug)] +struct RamCycleEntry { + row: usize, + col: usize, + prev_val: u64, + next_val: u64, + val_coeff: F, + ra_coeff: F, +} + +#[derive(Clone, Debug)] +struct RamAddressEntry { + row: usize, + col: usize, + prev_val: F, + next_val: F, + val_coeff: F, + ra_coeff: F, +} + +#[derive(Clone)] +struct RamReadWriteState { + gamma: F, + log_t: usize, + round: usize, + cycle_eq: SplitEqState, + cycle_entries: Vec>, + address_entries: Vec>, + address_scratch: Vec>, + inc: Vec, + inc_scratch: Vec, + val_init: Vec, + val_init_scratch: Vec, +} + +impl RamReadWriteState { + #[tracing::instrument(skip_all, name = "RamReadWriteState::new")] + fn new( + _claim: &Stage2SumcheckClaimPlan, + inputs: &Stage2ProverInputs<'_, F>, + store: &Stage2ValueStore, + ) -> Result { + let ram = inputs.ram.ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_read_write", + input: "ram", + })?; + let r_cycle = store.point("stage2.input.stage1.RamReadValue")?; + let log_t = r_cycle.len(); + let t = 1usize << log_t; + let k = 1usize << ram.log_k; + require_operand_count("stage2.ram.accesses", t, ram.accesses.len())?; + require_operand_count("stage2.ram.initial_ram", k, ram.initial_ram.len())?; + let gamma = store.scalar("stage2.ram_read_write.gamma")?; + let mut cycle_entries = Vec::with_capacity(ram.accesses.len()); + let mut inc = Vec::with_capacity(t); + for (row, access) in ram.accesses.iter().enumerate() { + inc.push(if access.write_value == access.read_value { + F::zero() + } else { + F::from_u64(access.write_value) - F::from_u64(access.read_value) + }); + if let Some(col) = access.remapped_address { + cycle_entries.push(RamCycleEntry { + row, + col, + prev_val: access.read_value, + next_val: access.write_value, + val_coeff: F::from_u64(access.read_value), + ra_coeff: F::one(), + }); + } + } + Ok(Self { + gamma, + log_t, + round: 0, + cycle_eq: SplitEqState::new_low_to_high(r_cycle, None), + cycle_entries, + address_entries: Vec::new(), + address_scratch: Vec::new(), + inc, + inc_scratch: Vec::new(), + val_init: ram + .initial_ram + .iter() + .map(|&value| { + if value == 0 { + F::zero() + } else { + F::from_u64(value) + } + }) + .collect(), + val_init_scratch: Vec::new(), + }) + } + + fn round_poly( + &mut self, + _round: usize, + previous_claim: F, + ) -> Result, Stage2KernelError> { + if self.round < self.log_t { + Ok(self.cycle_round_poly(previous_claim)) + } else { + Ok(self.address_round_poly(previous_claim)) + } + } + + fn ingest_challenge(&mut self, challenge: F) -> Result<(), Stage2KernelError> { + if self.round < self.log_t { + self.bind_cycle(challenge); + if self.round + 1 == self.log_t { + self.address_entries = self + .cycle_entries + .drain(..) + .map(|entry| RamAddressEntry { + row: entry.row, + col: entry.col, + prev_val: F::from_u64(entry.prev_val), + next_val: F::from_u64(entry.next_val), + val_coeff: entry.val_coeff, + ra_coeff: entry.ra_coeff, + }) + .collect(); + self.address_entries + .sort_by_key(|entry| (entry.col, entry.row)); + } + } else { + self.bind_address(challenge); + } + self.round += 1; + Ok(()) + } + + #[tracing::instrument(skip_all, name = "RamReadWriteState::cycle_round_poly")] + fn cycle_round_poly(&self, previous_claim: F) -> UnivariatePoly { + let e_in = self.cycle_eq.e_in(); + let e_out = self.cycle_eq.e_out(); + let (q_constant, q_quadratic) = if e_in.len() > 1 { + cycle_low_round_coefficients(&self.cycle_entries, &self.inc, e_in, e_out, self.gamma) + } else { + cycle_high_round_coefficients( + &self.cycle_entries, + &self.inc, + e_in[0], + e_out, + self.gamma, + ) + }; + gruen_cubic_poly( + self.cycle_eq.current_target(), + q_constant, + q_quadratic, + previous_claim, + ) + } + + #[tracing::instrument(skip_all, name = "RamReadWriteState::address_round_poly")] + fn address_round_poly(&self, previous_claim: F) -> UnivariatePoly { + let mut evals = [F::zero(); 2]; + let cycle_eq = self.cycle_eq_eval(); + let mut cursor = 0; + while cursor < self.address_entries.len() { + let pair = self.address_entries[cursor].col / 2; + let start = cursor; + while cursor < self.address_entries.len() + && self.address_entries[cursor].col / 2 == pair + { + cursor += 1; + } + let entries = &self.address_entries[start..cursor]; + let odd_start = entries.partition_point(|entry| entry.col % 2 == 0); + let even = &entries[..odd_start]; + let odd = &entries[odd_start..]; + let even_checkpoint = self.val_init[2 * pair]; + let odd_checkpoint = self.val_init[2 * pair + 1]; + for (x, eval_index) in [(0usize, 0usize), (2usize, 1usize)] { + evals[eval_index] += address_pair_eval( + even, + odd, + even_checkpoint, + odd_checkpoint, + RamEvalWeights { + inc: self.inc[0], + eq: cycle_eq, + gamma: self.gamma, + x: F::from_u64(x as u64), + }, + ); + } + } + UnivariatePoly::from_evals_and_hint(previous_claim, &evals) + } + + #[tracing::instrument(skip_all, name = "RamReadWriteState::bind_cycle")] + fn bind_cycle(&mut self, challenge: F) { + self.cycle_entries = bind_cycle_entries_parallel(&self.cycle_entries, challenge); + let inc = &mut self.inc; + let inc_scratch = &mut self.inc_scratch; + bind_dense_evals_reuse(inc, inc_scratch, challenge); + self.cycle_eq.bind(challenge); + } + + #[tracing::instrument(skip_all, name = "RamReadWriteState::bind_address")] + fn bind_address(&mut self, challenge: F) { + let mut bound = std::mem::take(&mut self.address_scratch); + bound.clear(); + bound.reserve(self.address_entries.len()); + let mut cursor = 0; + while cursor < self.address_entries.len() { + let pair = self.address_entries[cursor].col / 2; + let start = cursor; + while cursor < self.address_entries.len() + && self.address_entries[cursor].col / 2 == pair + { + cursor += 1; + } + let entries = &self.address_entries[start..cursor]; + let odd_start = entries.partition_point(|entry| entry.col % 2 == 0); + bind_address_cols( + &entries[..odd_start], + &entries[odd_start..], + self.val_init[2 * pair], + self.val_init[2 * pair + 1], + challenge, + &mut bound, + ); + } + std::mem::swap(&mut self.address_entries, &mut bound); + self.address_scratch = bound; + bind_dense_evals_reuse(&mut self.val_init, &mut self.val_init_scratch, challenge); + } + + fn ra_eval(&self) -> Result { + Ok(self + .address_entries + .first() + .filter(|entry| entry.col == 0 && entry.row == 0) + .map_or(F::zero(), |entry| entry.ra_coeff)) + } + + fn val_eval(&self) -> Result { + Ok(self + .address_entries + .first() + .filter(|entry| entry.col == 0 && entry.row == 0) + .map_or(self.val_init[0], |entry| entry.val_coeff)) + } + + fn inc_eval(&self) -> Result { + Ok(self.inc[0]) + } + + fn cycle_eq_eval(&self) -> F { + self.cycle_eq.eval() + } +} + +fn cycle_low_round_coefficients( + entries: &[RamCycleEntry], + inc: &[F], + e_in: &[F], + e_out: &[F], + gamma: F, +) -> (F, F) { + let in_pairs = e_in.len() / 2; + let accumulators = if entries.len() >= DENSE_BIND_PAR_THRESHOLD { + entries + .par_chunk_by(|left, right| (left.row / 2) / in_pairs == (right.row / 2) / in_pairs) + .map(|entries| { + let mut local = [F::Accumulator::default(); 2]; + accumulate_cycle_outer_chunk( + &mut local, entries, inc, e_in, e_out, in_pairs, gamma, + ); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + entries + .chunk_by(|left, right| (left.row / 2) / in_pairs == (right.row / 2) / in_pairs) + .fold([F::Accumulator::default(); 2], |mut local, entries| { + accumulate_cycle_outer_chunk( + &mut local, entries, inc, e_in, e_out, in_pairs, gamma, + ); + local + }) + }; + (accumulators[0].reduce(), accumulators[1].reduce()) +} + +fn cycle_high_round_coefficients( + entries: &[RamCycleEntry], + inc: &[F], + in_weight: F, + e_out: &[F], + gamma: F, +) -> (F, F) { + let accumulators = if entries.len() >= DENSE_BIND_PAR_THRESHOLD { + entries + .par_chunk_by(|left, right| left.row / 2 == right.row / 2) + .map(|entries| { + let mut local = [F::Accumulator::default(); 2]; + let pair = entries[0].row / 2; + let weight = in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]); + accumulate_cycle_row_pair(&mut local, entries, inc, weight, gamma); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + entries + .chunk_by(|left, right| left.row / 2 == right.row / 2) + .fold([F::Accumulator::default(); 2], |mut local, entries| { + let pair = entries[0].row / 2; + let weight = in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]); + accumulate_cycle_row_pair(&mut local, entries, inc, weight, gamma); + local + }) + }; + (accumulators[0].reduce(), accumulators[1].reduce()) +} + +fn accumulate_cycle_outer_chunk( + accumulators: &mut [F::Accumulator; 2], + entries: &[RamCycleEntry], + inc: &[F], + e_in: &[F], + e_out: &[F], + in_pairs: usize, + gamma: F, +) { + let x_out = (entries[0].row / 2) / in_pairs; + let out_weight = e_out[x_out]; + for entries in entries.chunk_by(|left, right| left.row / 2 == right.row / 2) { + let pair = entries[0].row / 2; + let x_in = pair % in_pairs; + let weight = out_weight * (e_in[2 * x_in] + e_in[2 * x_in + 1]); + accumulate_cycle_row_pair(accumulators, entries, inc, weight, gamma); + } +} + +fn accumulate_cycle_row_pair( + accumulators: &mut [F::Accumulator; 2], + entries: &[RamCycleEntry], + inc: &[F], + weight: F, + gamma: F, +) { + let pair = entries[0].row / 2; + let odd_start = entries.partition_point(|entry| entry.row % 2 == 0); + let even = &entries[..odd_start]; + let odd = &entries[odd_start..]; + let row = pair * 2; + let inc_pair = [inc[row], inc[row + 1]]; + accumulate_cycle_pair_body(accumulators, even, odd, inc_pair, weight, gamma); +} + +fn accumulate_cycle_pair_body( + accumulators: &mut [F::Accumulator; 2], + even: &[RamCycleEntry], + odd: &[RamCycleEntry], + inc_pair: [F; 2], + weight: F, + gamma: F, +) { + let mut i = 0; + let mut j = 0; + while i < even.len() && j < odd.len() { + match even[i].col.cmp(&odd[j].col) { + Ordering::Equal => { + accumulate_cycle_entry_quadratic( + accumulators, + Some(&even[i]), + Some(&odd[j]), + inc_pair, + weight, + gamma, + ); + i += 1; + j += 1; + } + Ordering::Less => { + accumulate_cycle_entry_quadratic( + accumulators, + Some(&even[i]), + None, + inc_pair, + weight, + gamma, + ); + i += 1; + } + Ordering::Greater => { + accumulate_cycle_entry_quadratic( + accumulators, + None, + Some(&odd[j]), + inc_pair, + weight, + gamma, + ); + j += 1; + } + } + } + for entry in &even[i..] { + accumulate_cycle_entry_quadratic(accumulators, Some(entry), None, inc_pair, weight, gamma); + } + for entry in &odd[j..] { + accumulate_cycle_entry_quadratic(accumulators, None, Some(entry), inc_pair, weight, gamma); + } +} + +fn accumulate_cycle_entry_quadratic( + accumulators: &mut [F::Accumulator; 2], + even: Option<&RamCycleEntry>, + odd: Option<&RamCycleEntry>, + inc_pair: [F; 2], + weight: F, + gamma: F, +) { + let (ra0, ra1, val0, val1) = match (even, odd) { + (Some(even), Some(odd)) => (even.ra_coeff, odd.ra_coeff, even.val_coeff, odd.val_coeff), + (Some(even), None) => ( + even.ra_coeff, + F::zero(), + even.val_coeff, + F::from_u64(even.next_val), + ), + (None, Some(odd)) => ( + F::zero(), + odd.ra_coeff, + F::from_u64(odd.prev_val), + odd.val_coeff, + ), + (None, None) => unreachable!(), + }; + let one_plus_gamma = F::one() + gamma; + let inc_delta = inc_pair[1] - inc_pair[0]; + let body0 = one_plus_gamma * val0 + gamma * inc_pair[0]; + let body_delta = one_plus_gamma * (val1 - val0) + gamma * inc_delta; + accumulators[0].fmadd(weight * ra0, body0); + accumulators[1].fmadd(weight * (ra1 - ra0), body_delta); +} + +fn address_pair_eval( + even: &[RamAddressEntry], + odd: &[RamAddressEntry], + mut even_checkpoint: F, + mut odd_checkpoint: F, + weights: RamEvalWeights, +) -> F { + let mut total = F::zero(); + let mut i = 0; + let mut j = 0; + while i < even.len() && j < odd.len() { + match even[i].row.cmp(&odd[j].row) { + Ordering::Equal => { + total += address_entry_eval( + Some(&even[i]), + Some(&odd[j]), + even_checkpoint, + odd_checkpoint, + weights, + ); + even_checkpoint = even[i].next_val; + odd_checkpoint = odd[j].next_val; + i += 1; + j += 1; + } + Ordering::Less => { + total += address_entry_eval( + Some(&even[i]), + None, + even_checkpoint, + odd_checkpoint, + weights, + ); + even_checkpoint = even[i].next_val; + i += 1; + } + Ordering::Greater => { + total += address_entry_eval( + None, + Some(&odd[j]), + even_checkpoint, + odd_checkpoint, + weights, + ); + odd_checkpoint = odd[j].next_val; + j += 1; + } + } + } + for entry in &even[i..] { + total += address_entry_eval(Some(entry), None, even_checkpoint, odd_checkpoint, weights); + even_checkpoint = entry.next_val; + } + for entry in &odd[j..] { + total += address_entry_eval(None, Some(entry), even_checkpoint, odd_checkpoint, weights); + odd_checkpoint = entry.next_val; + } + total +} + +#[derive(Clone, Copy)] +struct RamEvalWeights { + inc: F, + eq: F, + gamma: F, + x: F, +} + +fn address_entry_eval( + even: Option<&RamAddressEntry>, + odd: Option<&RamAddressEntry>, + even_checkpoint: F, + odd_checkpoint: F, + weights: RamEvalWeights, +) -> F { + let (ra0, ra1, val0, val1) = match (even, odd) { + (Some(even), Some(odd)) => (even.ra_coeff, odd.ra_coeff, even.val_coeff, odd.val_coeff), + (Some(even), None) => (even.ra_coeff, F::zero(), even.val_coeff, odd_checkpoint), + (None, Some(odd)) => (F::zero(), odd.ra_coeff, even_checkpoint, odd.val_coeff), + (None, None) => unreachable!(), + }; + let ra = line(ra0, ra1, weights.x); + let val = line(val0, val1, weights.x); + weights.eq * ra * (val + weights.gamma * (val + weights.inc)) +} + +fn bind_cycle_entries_parallel( + entries: &[RamCycleEntry], + challenge: F, +) -> Vec> { + let row_lengths = entries + .par_chunk_by(|left, right| left.row / 2 == right.row / 2) + .map(|entries| { + let odd_start = entries.partition_point(|entry| entry.row % 2 == 0); + let bound_len = bind_cycle_rows_len(&entries[..odd_start], &entries[odd_start..]); + (entries.len(), bound_len) + }) + .collect::>(); + let bound_len = row_lengths.iter().map(|(_, bound_len)| *bound_len).sum(); + let mut bound = Vec::with_capacity(bound_len); + let mut output_remainder = bound.spare_capacity_mut(); + let mut input_remainder = entries; + let mut input_slices = Vec::with_capacity(row_lengths.len()); + let mut output_slices = Vec::with_capacity(row_lengths.len()); + for (input_len, output_len) in row_lengths { + let (output, rest_output) = output_remainder.split_at_mut(output_len); + output_remainder = rest_output; + output_slices.push(output); + let (input, rest_input) = input_remainder.split_at(input_len); + input_remainder = rest_input; + input_slices.push(input); + } + input_slices + .par_iter() + .zip(output_slices.into_par_iter()) + .for_each(|(input, output)| { + let odd_start = input.partition_point(|entry| entry.row % 2 == 0); + let written = + bind_cycle_rows(&input[..odd_start], &input[odd_start..], challenge, output); + debug_assert_eq!(written, output.len()); + }); + // SAFETY: every output slice is disjoint, and `bind_cycle_rows` writes exactly the + // precomputed number of initialized entries into each slice before `set_len`. + unsafe { + bound.set_len(bound_len); + } + bound +} + +fn bind_cycle_rows_len(even: &[RamCycleEntry], odd: &[RamCycleEntry]) -> usize { + let mut i = 0; + let mut j = 0; + let mut len = 0; + while i < even.len() && j < odd.len() { + len += 1; + match even[i].col.cmp(&odd[j].col) { + Ordering::Equal => { + i += 1; + j += 1; + } + Ordering::Less => i += 1, + Ordering::Greater => j += 1, + } + } + len + even.len() - i + odd.len() - j +} + +fn bind_cycle_rows( + even: &[RamCycleEntry], + odd: &[RamCycleEntry], + challenge: F, + out: &mut [MaybeUninit>], +) -> usize { + let mut i = 0; + let mut j = 0; + let mut written = 0; + while i < even.len() && j < odd.len() { + match even[i].col.cmp(&odd[j].col) { + Ordering::Equal => { + let _ = + out[written].write(bind_cycle_entry(Some(&even[i]), Some(&odd[j]), challenge)); + written += 1; + i += 1; + j += 1; + } + Ordering::Less => { + let _ = out[written].write(bind_cycle_entry(Some(&even[i]), None, challenge)); + written += 1; + i += 1; + } + Ordering::Greater => { + let _ = out[written].write(bind_cycle_entry(None, Some(&odd[j]), challenge)); + written += 1; + j += 1; + } + } + } + for entry in &even[i..] { + let _ = out[written].write(bind_cycle_entry(Some(entry), None, challenge)); + written += 1; + } + for entry in &odd[j..] { + let _ = out[written].write(bind_cycle_entry(None, Some(entry), challenge)); + written += 1; + } + written +} + +fn bind_cycle_entry( + even: Option<&RamCycleEntry>, + odd: Option<&RamCycleEntry>, + r: F, +) -> RamCycleEntry { + match (even, odd) { + (Some(even), Some(odd)) => RamCycleEntry { + row: even.row / 2, + col: even.col, + ra_coeff: line(even.ra_coeff, odd.ra_coeff, r), + val_coeff: line(even.val_coeff, odd.val_coeff, r), + prev_val: even.prev_val, + next_val: odd.next_val, + }, + (Some(even), None) => RamCycleEntry { + row: even.row / 2, + col: even.col, + ra_coeff: line(even.ra_coeff, F::zero(), r), + val_coeff: line(even.val_coeff, F::from_u64(even.next_val), r), + prev_val: even.prev_val, + next_val: even.next_val, + }, + (None, Some(odd)) => RamCycleEntry { + row: odd.row / 2, + col: odd.col, + ra_coeff: line(F::zero(), odd.ra_coeff, r), + val_coeff: line(F::from_u64(odd.prev_val), odd.val_coeff, r), + prev_val: odd.prev_val, + next_val: odd.next_val, + }, + (None, None) => unreachable!(), + } +} + +fn bind_address_cols( + even: &[RamAddressEntry], + odd: &[RamAddressEntry], + mut even_checkpoint: F, + mut odd_checkpoint: F, + challenge: F, + out: &mut Vec>, +) { + let mut i = 0; + let mut j = 0; + while i < even.len() && j < odd.len() { + match even[i].row.cmp(&odd[j].row) { + Ordering::Equal => { + out.push(bind_address_entry( + Some(&even[i]), + Some(&odd[j]), + even_checkpoint, + odd_checkpoint, + challenge, + )); + even_checkpoint = even[i].next_val; + odd_checkpoint = odd[j].next_val; + i += 1; + j += 1; + } + Ordering::Less => { + out.push(bind_address_entry( + Some(&even[i]), + None, + even_checkpoint, + odd_checkpoint, + challenge, + )); + even_checkpoint = even[i].next_val; + i += 1; + } + Ordering::Greater => { + out.push(bind_address_entry( + None, + Some(&odd[j]), + even_checkpoint, + odd_checkpoint, + challenge, + )); + odd_checkpoint = odd[j].next_val; + j += 1; + } + } + } + for entry in &even[i..] { + out.push(bind_address_entry( + Some(entry), + None, + even_checkpoint, + odd_checkpoint, + challenge, + )); + even_checkpoint = entry.next_val; + } + for entry in &odd[j..] { + out.push(bind_address_entry( + None, + Some(entry), + even_checkpoint, + odd_checkpoint, + challenge, + )); + odd_checkpoint = entry.next_val; + } +} + +fn bind_address_entry( + even: Option<&RamAddressEntry>, + odd: Option<&RamAddressEntry>, + even_checkpoint: F, + odd_checkpoint: F, + r: F, +) -> RamAddressEntry { + match (even, odd) { + (Some(even), Some(odd)) => RamAddressEntry { + row: even.row, + col: even.col / 2, + ra_coeff: line(even.ra_coeff, odd.ra_coeff, r), + val_coeff: line(even.val_coeff, odd.val_coeff, r), + prev_val: line(even.prev_val, odd.prev_val, r), + next_val: line(even.next_val, odd.next_val, r), + }, + (Some(even), None) => RamAddressEntry { + row: even.row, + col: even.col / 2, + ra_coeff: line(even.ra_coeff, F::zero(), r), + val_coeff: line(even.val_coeff, odd_checkpoint, r), + prev_val: line(even.prev_val, odd_checkpoint, r), + next_val: line(even.next_val, odd_checkpoint, r), + }, + (None, Some(odd)) => RamAddressEntry { + row: odd.row, + col: odd.col / 2, + ra_coeff: line(F::zero(), odd.ra_coeff, r), + val_coeff: line(even_checkpoint, odd.val_coeff, r), + prev_val: line(even_checkpoint, odd.prev_val, r), + next_val: line(even_checkpoint, odd.next_val, r), + }, + (None, None) => unreachable!(), + } +} + +fn expected_batched_output_claim( + context: Stage2KernelContext<'_>, + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + point: &[F], + batching_coeffs: &[F], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let instance = context + .program + .instance_results + .iter() + .find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) + .ok_or(Stage2KernelError::MissingClaim { + batch: context.batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage2KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let claim_value = match Stage2Relation::from_symbol(instance.relation).ok_or( + Stage2KernelError::UnknownRelation { + relation: instance.relation, + }, + )? { + Stage2Relation::RamReadWrite => expected_ram_read_write(store, evals, local_point)?, + Stage2Relation::ProductVirtualRemainder => { + expected_product_remainder(store, evals, local_point)? + } + Stage2Relation::InstructionLookupClaimReduction => { + expected_instruction_lookup(store, evals, local_point)? + } + Stage2Relation::RamRafEvaluation => expected_ram_raf(store, evals, local_point, ram)?, + Stage2Relation::RamOutputCheck => expected_ram_output(store, evals, local_point, ram)?, + relation => { + return Err(Stage2KernelError::KernelNotImplemented { + abi: relation.symbol(), + }) + } + }; + expected += coefficient * claim_value; + } + Ok(expected) +} + +fn expected_ram_read_write( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[F], +) -> Result { + let r_cycle_stage1 = store.point("stage2.input.stage1.RamReadValue")?; + let log_t = r_cycle_stage1.len(); + let r_cycle = reverse_slice(&local_point[..log_t]); + let eq_eval = EqPolynomial::::mle(r_cycle_stage1, &r_cycle); + let gamma = store.scalar("stage2.ram_read_write.gamma")?; + let val = eval_by_name(evals, "stage2.ram_read_write.eval.RamVal")?; + let ra = eval_by_name(evals, "stage2.ram_read_write.eval.RamRa")?; + let inc = eval_by_name(evals, "stage2.ram_read_write.eval.RamInc")?; + Ok(eq_eval * ra * (val + gamma * (val + inc))) +} + +fn expected_product_remainder( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[F], +) -> Result { + let tau_low = store.point("stage2.input.stage1.Product")?; + let tau_high = store.scalar("stage2.product_virtual.tau_high")?; + let r0 = *store + .point("stage2.product_virtual.uniskip.sumcheck")? + .first() + .ok_or(Stage2KernelError::MissingValue { + symbol: "stage2.product_virtual.uniskip.sumcheck", + })?; + let r_tail = reverse_slice(local_point); + let low = EqPolynomial::::mle(tau_low, &r_tail); + let high = lagrange_kernel_eval( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + tau_high, + r0, + ); + let weights = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + r0, + ); + let left = weights[0] + * eval_by_name( + evals, + "stage2.product_virtual.remainder.eval.LeftInstructionInput", + )? + + weights[1] * eval_by_name(evals, "stage2.product_virtual.remainder.eval.LookupOutput")? + + weights[2] * eval_by_name(evals, "stage2.product_virtual.remainder.eval.OpFlagJump")?; + let right = weights[0] + * eval_by_name( + evals, + "stage2.product_virtual.remainder.eval.RightInstructionInput", + )? + + weights[1] + * eval_by_name( + evals, + "stage2.product_virtual.remainder.eval.InstructionFlagBranch", + )? + + weights[2] + * (F::one() - eval_by_name(evals, "stage2.product_virtual.remainder.eval.NextIsNoop")?); + Ok(high * low * left * right) +} + +fn expected_instruction_lookup( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[F], +) -> Result { + let opening_point = reverse_slice(local_point); + let r_spartan = store.point("stage2.input.stage1.LookupOutput")?; + let eq_eval = EqPolynomial::::mle(&opening_point, r_spartan); + let gamma = store.scalar("stage2.instruction_lookup.gamma")?; + let gamma_sqr = gamma.square(); + let gamma_cub = gamma_sqr * gamma; + let gamma_quart = gamma_sqr.square(); + let weighted = eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", + )? + gamma + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", + )? + + gamma_sqr + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", + )? + + gamma_cub + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", + )? + + gamma_quart + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", + )?; + Ok(eq_eval * weighted) +} + +fn expected_ram_raf( + _store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[F], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let ram = ram.ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_raf_evaluation", + input: "ram", + })?; + let address = reverse_slice(local_point); + let unmap = unmap_eval(ram.log_k, ram.start_address, &address); + Ok(unmap * eval_by_name(evals, "stage2.ram_raf.eval.RamRa")?) +} + +fn expected_ram_output( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[F], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let ram = ram.ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_output_check", + input: "ram", + })?; + let layout = ram + .output_layout + .ok_or(Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_ram_output_check", + input: "ram.output_layout", + })?; + let r_address = store.point("stage2.ram_output.r_address")?; + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle(r_address, &opening_point); + let io_mask = range_mask_eval(layout.io_start, layout.io_end, &opening_point); + let val_io = sparse_final_ram_eval( + ram.final_ram, + layout.io_start, + layout.io_end, + &opening_point, + ); + let val_final = eval_by_name(evals, "stage2.ram_output.eval.RamValFinal")?; + Ok(eq_eval * io_mask * (val_final - val_io)) +} + +fn eval_by_name( + evals: &[Stage2NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage2KernelError::MissingValue { symbol: name }) +} + +fn reverse_slice(values: &[F]) -> Vec { + values.iter().rev().copied().collect() +} + +fn unmap_eval(log_k: usize, start_address: u64, point: &[F]) -> F { + point + .iter() + .enumerate() + .fold(F::from_u64(start_address), |acc, (index, &value)| { + acc + value.mul_pow_2(log_k - 1 - index).mul_u64(8) + }) +} + +fn range_mask_eval(start: usize, end: usize, point: &[F]) -> F { + eq_prefix_sum(end, point) - eq_prefix_sum(start, point) +} + +fn sparse_final_ram_eval(values: &[u64], start: usize, end: usize, point: &[F]) -> F { + let mut total = F::zero(); + for (offset, &value) in values[start..end].iter().enumerate() { + if value != 0 { + total += F::from_u64(value) * eq_eval_at_index(start + offset, point); + } + } + total +} + +fn ram_eval_reversed(values: &[u64], nonzero_values: &[(usize, u64)], point: &[F]) -> F { + let opening_point = reverse_slice(point); + if nonzero_values.len() * opening_point.len() <= values.len() { + nonzero_values + .iter() + .map(|&(index, value)| F::from_u64(value) * eq_eval_at_index(index, &opening_point)) + .sum() + } else { + let eq = EqPolynomial::::evals(&opening_point, None); + values + .par_iter() + .zip(eq.par_iter()) + .fold(F::Accumulator::default, |mut total, (&value, &weight)| { + if value != 0 { + total.fmadd(F::from_u64(value), weight); + } + total + }) + .reduce(F::Accumulator::default, |mut left, right| { + left.merge(right); + left + }) + .reduce() + } +} + +fn eq_prefix_sum(end: usize, point: &[F]) -> F { + let domain_len = 1usize << point.len(); + if end >= domain_len { + return F::one(); + } + let mut sum = F::zero(); + let mut prefix = F::one(); + for (bit, &r) in point.iter().enumerate() { + let mask = 1usize << (point.len() - 1 - bit); + if end & mask == 0 { + prefix *= F::one() - r; + } else { + sum += prefix * (F::one() - r); + prefix *= r; + } + } + sum +} + +fn eq_eval_at_index(index: usize, point: &[F]) -> F { + point.iter().enumerate().fold(F::one(), |acc, (bit, &r)| { + let mask = 1usize << (point.len() - 1 - bit); + if index & mask == 0 { + acc * (F::one() - r) + } else { + acc * r + } + }) +} + +const PRODUCT_REMAINDER_EVAL_NAMES: [(&str, &str); 8] = [ + ( + "stage2.product_virtual.remainder.eval.LeftInstructionInput", + "LeftInstructionInput", + ), + ( + "stage2.product_virtual.remainder.eval.RightInstructionInput", + "RightInstructionInput", + ), + ( + "stage2.product_virtual.remainder.eval.OpFlagJump", + "OpFlagJump", + ), + ( + "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD", + "OpFlagWriteLookupOutputToRD", + ), + ( + "stage2.product_virtual.remainder.eval.LookupOutput", + "LookupOutput", + ), + ( + "stage2.product_virtual.remainder.eval.InstructionFlagBranch", + "InstructionFlagBranch", + ), + ( + "stage2.product_virtual.remainder.eval.NextIsNoop", + "NextIsNoop", + ), + ( + "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction", + "OpFlagVirtualInstruction", + ), +]; + +const INSTRUCTION_LOOKUP_EVAL_NAMES: [(&str, &str); 5] = [ + ( + "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", + "LookupOutput", + ), + ( + "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", + "LeftLookupOperand", + ), + ( + "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", + "RightLookupOperand", + ), + ( + "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", + "LeftInstructionInput", + ), + ( + "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", + "RightInstructionInput", + ), +]; + +fn product_remainder_final_evals( + cycles: &[Stage2ProductVirtualCycle], + point: &[F], + relation: Stage2Relation, +) -> Result>, Stage2KernelError> { + let values = product_remainder_output_evals(cycles, point, relation)?; + Ok(PRODUCT_REMAINDER_EVAL_NAMES + .iter() + .zip(values) + .map(|(&(name, oracle), value)| named_eval(name, oracle, value)) + .collect()) +} + +fn product_remainder_output_evals( + cycles: &[Stage2ProductVirtualCycle], + point: &[F], + relation: Stage2Relation, +) -> Result<[F; 8], Stage2KernelError> { + let expected = + 1usize + .checked_shl(point.len() as u32) + .ok_or(Stage2KernelError::InvalidInputLength { + input: "stage2.product_remainder_output.point", + expected: usize::BITS as usize, + actual: point.len(), + })?; + if cycles.len() != expected { + return Err(Stage2KernelError::InvalidInputLength { + input: relation.symbol(), + expected, + actual: cycles.len(), + }); + } + let opening_point = reverse_slice(point); + let (r_hi, r_lo) = opening_point.split_at(opening_point.len() / 2); + let (eq_out, eq_in) = rayon::join( + || EqPolynomial::::evals(r_hi, None), + || EqPolynomial::::evals(r_lo, None), + ); + let accumulators = (0..eq_out.len()) + .into_par_iter() + .map(|x_out| { + let start = x_out * eq_in.len(); + let mut inner = [F::Accumulator::default(); 8]; + for (x_in, &weight) in eq_in.iter().enumerate() { + accumulate_product_remainder_outputs(&mut inner, &cycles[start + x_in], weight); + } + let mut outer = [F::Accumulator::default(); 8]; + for (outer, inner) in outer.iter_mut().zip(inner) { + outer.fmadd(inner.reduce(), eq_out[x_out]); + } + outer + }) + .reduce( + || [F::Accumulator::default(); 8], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + Ok(accumulators.map(AdditiveAccumulator::reduce)) +} + +fn accumulate_product_remainder_outputs( + accumulators: &mut [F::Accumulator; 8], + cycle: &Stage2ProductVirtualCycle, + weight: F, +) { + accumulators[0].fmadd_u64(weight, cycle.instruction_left_input); + accumulators[1].fmadd(weight, F::from_i128(cycle.instruction_right_input)); + accumulators[2].fmadd_bool(weight, cycle.jump_flag); + accumulators[3].fmadd_bool(weight, cycle.write_lookup_output_to_rd_flag); + accumulators[4].fmadd_u64(weight, cycle.should_branch_lookup_output); + accumulators[5].fmadd_bool(weight, cycle.should_branch_flag); + accumulators[6].fmadd_bool(weight, !cycle.not_next_noop); + accumulators[7].fmadd_bool(weight, cycle.virtual_instruction_flag); +} + +fn accumulate_instruction_lookup_outputs( + accumulators: &mut [F::Accumulator; 5], + cycle: &Stage2InstructionLookupCycle, + weight: F, +) { + accumulators[0].fmadd_u64(weight, cycle.lookup_output); + accumulators[1].fmadd_u64(weight, cycle.left_lookup_operand); + accumulators[2].fmadd(weight, F::from_u128(cycle.right_lookup_operand)); + accumulators[3].fmadd_u64(weight, cycle.left_instruction_input); + accumulators[4].fmadd(weight, F::from_i128(cycle.right_instruction_input)); +} + +fn named_eval(name: &'static str, oracle: &'static str, value: F) -> Stage2NamedEval { + Stage2NamedEval { + name, + oracle, + value, + } +} + +fn claim_relation( + program: &'static Stage2CpuProgramPlan, + claim: &Stage2SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage2Relation::from_symbol(relation) + .ok_or(Stage2KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage2KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage2KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + kernel.relation_kind() +} + +fn instance_round_offset( + program: &'static Stage2CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage2KernelError::MissingClaim { + batch: driver, + claim, + }) +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + trim_trailing_zero_coefficients(UnivariatePoly::new(combined), 3) +} + +fn trim_trailing_zero_coefficients( + polynomial: UnivariatePoly, + min_len: usize, +) -> UnivariatePoly { + let mut coefficients = polynomial.into_coefficients(); + while coefficients.len() > min_len && coefficients.last() == Some(&F::zero()) { + let _ = coefficients.pop(); + } + UnivariatePoly::new(coefficients) +} + +fn round_poly_from_factors(factors: &[Vec], degree: usize) -> UnivariatePoly { + let factor_slices = factors.iter().map(Vec::as_slice).collect::>(); + round_poly_from_factor_slices(&factor_slices, degree) +} + +fn round_poly_from_factor_slices(factors: &[&[F]], degree: usize) -> UnivariatePoly { + if factors.is_empty() { + return UnivariatePoly::zero(); + } + let half = factors[0].len() / 2; + let accumulators = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .map(|row| dense_product_coefficients(factors, row)) + .reduce( + || [F::Accumulator::default(); 4], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + (0..half).fold([F::Accumulator::default(); 4], |mut total, row| { + let row_coeffs = dense_product_coefficients(factors, row); + for index in 0..total.len() { + total[index].merge(row_coeffs[index]); + } + total + }) + }; + UnivariatePoly::new( + accumulators[..=degree] + .iter() + .copied() + .map(AdditiveAccumulator::reduce) + .collect(), + ) +} + +fn dense_product_coefficients(factors: &[&[F]], row: usize) -> [F::Accumulator; 4] { + if factors.len() == 2 { + let left0 = factors[0][2 * row]; + let left_delta = factors[0][2 * row + 1] - left0; + let right0 = factors[1][2 * row]; + let right_delta = factors[1][2 * row + 1] - right0; + let mut accumulators = [F::Accumulator::default(); 4]; + accumulators[0].fmadd(left0, right0); + accumulators[1].fmadd(left_delta, right0); + accumulators[1].fmadd(left0, right_delta); + accumulators[2].fmadd(left_delta, right_delta); + return accumulators; + } + if factors.len() == 3 { + let first0 = factors[0][2 * row]; + let first_delta = factors[0][2 * row + 1] - first0; + let second0 = factors[1][2 * row]; + let second_delta = factors[1][2 * row + 1] - second0; + let third0 = factors[2][2 * row]; + let third_delta = factors[2][2 * row + 1] - third0; + let mut accumulators = [F::Accumulator::default(); 4]; + accumulate_cubic_product_coefficients( + &mut accumulators, + first0, + first_delta, + second0, + second_delta, + third0, + third_delta, + ); + return accumulators; + } + + let mut coefficients = [F::zero(); 4]; + coefficients[0] = F::one(); + for (degree, factor) in factors.iter().enumerate() { + let low = factor[2 * row]; + let delta = factor[2 * row + 1] - low; + for index in (0..=degree).rev() { + coefficients[index + 1] += coefficients[index] * delta; + coefficients[index] *= low; + } + } + let mut accumulators = [F::Accumulator::default(); 4]; + for (accumulator, coefficient) in accumulators.iter_mut().zip(coefficients) { + accumulator.add(coefficient); + } + accumulators +} + +fn accumulate_cubic_product_coefficients( + coefficients: &mut [F::Accumulator; 4], + first0: F, + first_delta: F, + second0: F, + second_delta: F, + third0: F, + third_delta: F, +) { + let second0_third0 = second0 * third0; + let second_delta_third0 = second_delta * third0; + let second0_third_delta = second0 * third_delta; + let second_delta_third_delta = second_delta * third_delta; + + coefficients[0].fmadd(first0, second0_third0); + coefficients[1].fmadd(first_delta, second0_third0); + coefficients[1].fmadd(first0, second_delta_third0); + coefficients[1].fmadd(first0, second0_third_delta); + coefficients[2].fmadd(first_delta, second_delta_third0); + coefficients[2].fmadd(first_delta, second0_third_delta); + coefficients[2].fmadd(first0, second_delta_third_delta); + coefficients[3].fmadd(first_delta, second_delta_third_delta); +} + +fn line(lo: F, hi: F, x: F) -> F { + lo + x * (hi - lo) +} + +fn product_uniskip_base_evals( + store: &Stage2ValueStore, +) -> Result<[F; PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE], Stage2KernelError> { + Ok([ + store.scalar("stage2.input.stage1.Product")?, + store.scalar("stage2.input.stage1.ShouldBranch")?, + store.scalar("stage2.input.stage1.ShouldJump")?, + ]) +} + +#[tracing::instrument(skip_all, name = "stage2_product_virtual_uniskip_extended_evals")] +pub fn product_virtual_uniskip_extended_evals( + cycles: &[Stage2ProductVirtualCycle], + tau_low: &[Fr], +) -> Result<[Fr; PRODUCT_VIRTUAL_UNISKIP_DEGREE], Stage2KernelError> { + let expected = + 1usize + .checked_shl(tau_low.len() as u32) + .ok_or(Stage2KernelError::InvalidInputLength { + input: "stage2.product_virtual.tau_low", + expected: usize::BITS as usize, + actual: tau_low.len(), + })?; + if cycles.len() != expected { + return Err(Stage2KernelError::InvalidInputLength { + input: "stage2.product_virtual.cycles", + expected, + actual: cycles.len(), + }); + } + + let eq_evals = EqPolynomial::::evals(tau_low, None); + let accumulators = eq_evals + .par_iter() + .zip(cycles.par_iter()) + .fold( + || [FrSignedScalarAccumulator::zero(); PRODUCT_VIRTUAL_UNISKIP_DEGREE], + |mut local, (&weight, cycle)| { + for (target, accumulator) in local.iter_mut().enumerate() { + accumulator.fmadd_s256( + weight, + product_virtual_extended_fused_product(cycle, target), + ); + } + local + }, + ) + .reduce( + || [FrSignedScalarAccumulator::zero(); PRODUCT_VIRTUAL_UNISKIP_DEGREE], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + + Ok(accumulators.map(FrSignedScalarAccumulator::reduce)) +} + +fn product_virtual_extended_fused_product( + cycle: &Stage2ProductVirtualCycle, + target: usize, +) -> S256 { + let coefficients = PRODUCT_VIRTUAL_UNISKIP_TARGET_COEFFS[target]; + let left = coefficients[0] as i128 * cycle.instruction_left_input as i128 + + coefficients[1] as i128 * cycle.should_branch_lookup_output as i128 + + coefficients[2] as i128 * i128::from(cycle.jump_flag); + let right = coefficients[0] as i128 * cycle.instruction_right_input + + coefficients[1] as i128 * i128::from(cycle.should_branch_flag) + + coefficients[2] as i128 * i128::from(cycle.not_next_noop); + S128::from_i128(left).mul_trunc::<2, 4>(&S128::from_i128(right)) +} + +#[derive(Clone, Copy)] +struct FrSignedScalarAccumulator { + positive: Limbs<9>, + negative: Limbs<9>, +} + +impl FrSignedScalarAccumulator { + fn zero() -> Self { + Self { + positive: Limbs::zero(), + negative: Limbs::zero(), + } + } + + fn fmadd_s256(&mut self, field: Fr, scalar: S256) { + if scalar.magnitude_limbs() == [0u64; 4] { + return; + } + self.fmadd_limbs(field, scalar.as_magnitude(), scalar.is_positive); + } + + fn fmadd_limbs(&mut self, field: Fr, scalar: &Limbs, is_positive: bool) { + let mut product = Limbs::<9>::zero(); + product.fmadd::<4, L>(&field.inner_limbs(), scalar); + if is_positive { + self.positive.add_assign_trunc::<9>(&product); + } else { + self.negative.add_assign_trunc::<9>(&product); + } + } + + fn merge(&mut self, other: Self) { + self.positive.add_assign_trunc::<9>(&other.positive); + self.negative.add_assign_trunc::<9>(&other.negative); + } + + fn reduce(self) -> Fr { + match self.positive.cmp(&self.negative) { + Ordering::Greater | Ordering::Equal => { + Fr::from_barrett_reduced_limbs(self.positive.sub_trunc::<9, 9>(&self.negative)) + } + Ordering::Less => { + -Fr::from_barrett_reduced_limbs(self.negative.sub_trunc::<9, 9>(&self.positive)) + } + } + } +} + +fn build_product_uniskip_poly( + base_evals: &[F; PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE], + extended_evals: &[F], + tau_high: F, +) -> Result, Stage2KernelError> { + if extended_evals.len() != PRODUCT_VIRTUAL_UNISKIP_DEGREE { + return Err(Stage2KernelError::InvalidInputLength { + input: "product_uniskip_extended_evals", + expected: PRODUCT_VIRTUAL_UNISKIP_DEGREE, + actual: extended_evals.len(), + }); + } + + let mut t1_values = vec![F::zero(); PRODUCT_VIRTUAL_UNISKIP_EXTENDED_SIZE]; + for (index, value) in base_evals.iter().enumerate() { + let target = PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START + index as i64; + t1_values[(target - PRODUCT_VIRTUAL_UNISKIP_EXTENDED_START) as usize] = *value; + } + for (value, target) in extended_evals.iter().zip(product_uniskip_targets()) { + t1_values[(target - PRODUCT_VIRTUAL_UNISKIP_EXTENDED_START) as usize] = *value; + } + + let t1_coeffs = interpolate_to_coeffs(PRODUCT_VIRTUAL_UNISKIP_EXTENDED_START, &t1_values); + let lagrange_values = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + tau_high, + ); + let lagrange_coeffs = + interpolate_to_coeffs(PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, &lagrange_values); + + let mut coefficients = vec![F::zero(); PRODUCT_VIRTUAL_UNISKIP_NUM_COEFFS]; + for (i, &lagrange_coeff) in lagrange_coeffs.iter().enumerate() { + for (j, &t1_coeff) in t1_coeffs.iter().enumerate() { + coefficients[i + j] += lagrange_coeff * t1_coeff; + } + } + Ok(UnivariatePoly::new(coefficients)) +} + +fn product_uniskip_targets() -> [i64; PRODUCT_VIRTUAL_UNISKIP_DEGREE] { + [-2, 2] +} + +fn product_uniskip_sum_matches(poly: &UnivariatePoly, claim: F) -> bool { + (0..PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE) + .map(|index| { + poly.evaluate(F::from_i64( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START + index as i64, + )) + }) + .sum::() + == claim +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn append_univariate_poly(transcript: &mut T, label: &'static str, poly: &UnivariatePoly) +where + F: Field, + T: Transcript, +{ + transcript.append(&LabelWithCount( + label.as_bytes(), + poly.coefficients().len() as u64, + )); + for coefficient in poly.coefficients() { + transcript.append(coefficient); + } +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims( + program: &'static Stage2CpuProgramPlan, + store: &mut Stage2ValueStore, + transcript: &mut T, + evals: &[Stage2NamedEval], +) -> Result>, Stage2KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + let mut seen = seed_stage2_opening_aliases(store, program); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage2KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let value = store.scalar(claim.eval_source)?; + let duplicate = has_seen_opening(&seen, claim.claim_kind, claim.oracle, &point); + if !duplicate { + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point.clone())); + } + opening_claims.push(Stage2OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: point.clone(), + eval: value, + }); + } + } + Ok(opening_claims) +} + +fn seed_stage2_opening_aliases( + store: &Stage2ValueStore, + program: &'static Stage2CpuProgramPlan, +) -> Vec<(&'static str, &'static str, Vec)> { + program + .opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect() +} + +fn has_seen_opening( + seen: &[(&'static str, &'static str, Vec)], + claim_kind: &'static str, + oracle: &'static str, + point: &[F], +) -> bool { + seen.iter().any(|(seen_kind, seen_oracle, seen_point)| { + *seen_kind == claim_kind && *seen_oracle == oracle && seen_point.as_slice() == point + }) +} + +fn driver_evals(context: Stage2KernelContext<'_>, value: F) -> Vec> { + context + .program + .evals_for_driver(context.driver.symbol) + .map(|eval| Stage2NamedEval { + name: eval.name, + oracle: eval.oracle, + value, + }) + .collect() +} + +fn verify_driver_evals( + driver: &'static str, + expected: &[Stage2NamedEval], + actual: &[Stage2NamedEval], +) -> Result<(), Stage2KernelError> { + if expected.len() != actual.len() { + return Err(Stage2KernelError::InvalidProof { + driver, + reason: "product uniskip eval count mismatch", + }); + } + for (expected, actual) in expected.iter().zip(actual) { + if expected.name != actual.name + || expected.oracle != actual.oracle + || expected.value != actual.value + { + return Err(Stage2KernelError::InvalidProof { + driver, + reason: "product uniskip eval mismatch", + }); + } + } + Ok(()) +} + +pub fn execute_stage2_program( + program: &'static Stage2CpuProgramPlan, + mode: Stage2ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + F: Field, + E: Stage2KernelExecutor, + T: Transcript, +{ + verify_static_program_shape(program)?; + let mut artifacts = Stage2ExecutionArtifacts::default(); + if program.steps.is_empty() { + for squeeze in program.transcript_squeezes { + execute_stage2_squeeze(squeeze, executor, transcript, &mut artifacts)?; + } + for driver in program.drivers { + execute_stage2_driver(program, mode, driver, executor, transcript, &mut artifacts)?; + } + } else { + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = find_transcript_squeeze(program, step.symbol).ok_or( + Stage2KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + execute_stage2_squeeze(squeeze, executor, transcript, &mut artifacts)?; + } + "sumcheck_driver" => { + let driver = find_driver(program, step.symbol).ok_or( + Stage2KernelError::MissingKernel { + driver: step.symbol, + kernel: step.symbol, + }, + )?; + execute_stage2_driver( + program, + mode, + driver, + executor, + transcript, + &mut artifacts, + )?; + } + _ => { + return Err(Stage2KernelError::InvalidProof { + driver: step.symbol, + reason: "unsupported stage2 program step", + }) + } + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +fn execute_stage2_squeeze( + squeeze: &'static Stage2TranscriptSqueezePlan, + executor: &mut E, + transcript: &mut T, + artifacts: &mut Stage2ExecutionArtifacts, +) -> Result<(), Stage2KernelError> +where + F: Field, + E: Stage2KernelExecutor, + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage2ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn execute_stage2_driver( + program: &'static Stage2CpuProgramPlan, + mode: Stage2ExecutionMode, + driver: &'static Stage2SumcheckDriverPlan, + executor: &mut E, + transcript: &mut T, + artifacts: &mut Stage2ExecutionArtifacts, +) -> Result<(), Stage2KernelError> +where + F: Field, + E: Stage2KernelExecutor, + T: Transcript, +{ + let kernel_symbol = driver.kernel.ok_or(Stage2KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage2KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + })?; + let batch = find_batch(program, driver.batch).ok_or(Stage2KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage2KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage2ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage2ExecutionMode::Verifier => executor.verify_sumcheck(context, transcript)?, + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_static_program_shape( + program: &'static Stage2CpuProgramPlan, +) -> Result<(), Stage2KernelError> { + for expr in program.field_exprs { + verify_count(expr.symbol, expr.operand_names.len(), expr.operands.len())?; + } + for batch in program.batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + for batch in program.opening_batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let _ = find_transcript_squeeze(program, step.symbol).ok_or( + Stage2KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + } + "sumcheck_driver" => { + let _ = + find_driver(program, step.symbol).ok_or(Stage2KernelError::MissingKernel { + driver: step.symbol, + kernel: step.symbol, + })?; + } + _ => { + return Err(Stage2KernelError::InvalidProof { + driver: step.symbol, + reason: "unsupported stage2 program step", + }) + } + } + } + Ok(()) +} + +fn verify_count( + artifact: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage2KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage2KernelError::PlanCountMismatch { + artifact, + expected, + actual, + }) + } +} + +fn find_kernel<'a>( + program: &'a Stage2CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage2KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch<'a>( + program: &'a Stage2CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage2SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +fn find_driver<'a>( + program: &'a Stage2CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage2SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_transcript_squeeze<'a>( + program: &'a Stage2CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage2TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|squeeze| squeeze.symbol == symbol) +} + +fn find_opening_claim<'a>( + program: &'a Stage2CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage2OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +#[cfg(test)] +#[expect(clippy::expect_used, reason = "tests use explicit panic messages")] +mod tests { + use super::*; + use jolt_field::Fr; + use jolt_transcript::MockTranscript; + + #[test] + fn stage2_relation_and_abi_registry_is_complete() { + let relations = [ + Stage2Relation::ProductVirtualUniskip, + Stage2Relation::RamReadWrite, + Stage2Relation::ProductVirtualRemainder, + Stage2Relation::InstructionLookupClaimReduction, + Stage2Relation::RamRafEvaluation, + Stage2Relation::RamOutputCheck, + Stage2Relation::Batched, + ]; + for relation in relations { + assert_eq!( + Stage2Relation::from_symbol(relation.symbol()), + Some(relation) + ); + } + + let abis = [ + Stage2KernelAbi::ProductVirtualUniskip, + Stage2KernelAbi::RamReadWrite, + Stage2KernelAbi::ProductVirtualRemainder, + Stage2KernelAbi::InstructionLookupClaimReduction, + Stage2KernelAbi::RamRafEvaluation, + Stage2KernelAbi::RamOutputCheck, + Stage2KernelAbi::Batched, + ]; + for abi in abis { + assert_eq!(Stage2KernelAbi::from_name(abi.name()), Some(abi)); + } + } + + #[test] + fn stage2_field_exprs_match_jolt_input_claim_formulas() { + let product_expr = Stage2FieldExprPlan { + symbol: "product_expr", + kind: "weighted_sum", + formula: "jolt_stage2_product_virtual_uniskip_input", + operand_names: &[], + operands: &[], + }; + let product = evaluate_stage2_field_expr( + &product_expr, + &[ + Fr::from_u64(0), + Fr::from_u64(11), + Fr::from_u64(13), + Fr::from_u64(17), + ], + ) + .expect("product expression evaluates"); + assert_eq!(product, Fr::from_u64(13)); + + let ram_expr = Stage2FieldExprPlan { + symbol: "ram_expr", + kind: "weighted_sum", + formula: "jolt_stage2_ram_read_write_input", + operand_names: &[], + operands: &[], + }; + let ram = evaluate_stage2_field_expr( + &ram_expr, + &[Fr::from_u64(7), Fr::from_u64(11), Fr::from_u64(13)], + ) + .expect("ram expression evaluates"); + assert_eq!(ram, Fr::from_u64(102)); + + let instruction_expr = Stage2FieldExprPlan { + symbol: "instruction_expr", + kind: "weighted_sum", + formula: "jolt_stage2_instruction_lookup_input", + operand_names: &[], + operands: &[], + }; + let instruction = evaluate_stage2_field_expr( + &instruction_expr, + &[ + Fr::from_u64(2), + Fr::from_u64(1), + Fr::from_u64(3), + Fr::from_u64(5), + Fr::from_u64(7), + Fr::from_u64(11), + ], + ) + .expect("instruction expression evaluates"); + assert_eq!(instruction, Fr::from_u64(259)); + + let add_expr = Stage2FieldExprPlan { + symbol: "add_expr", + kind: "op", + formula: "field.add", + operand_names: &[], + operands: &[], + }; + let add = evaluate_stage2_field_expr(&add_expr, &[Fr::from_u64(5), Fr::from_u64(8)]) + .expect("field add evaluates"); + assert_eq!(add, Fr::from_u64(13)); + + let lagrange_expr = Stage2FieldExprPlan { + symbol: "lagrange_expr", + kind: "op", + formula: "poly.lagrange_basis_eval:-1:3:1", + operand_names: &[], + operands: &[], + }; + let weight = evaluate_stage2_field_expr(&lagrange_expr, &[Fr::from_u64(0)]) + .expect("lagrange basis evaluates"); + assert_eq!(weight, Fr::from_u64(1)); + } + + #[test] + fn value_store_resolves_challenges_openings_and_claims() { + let program = minimal_program( + vec![Stage2TranscriptSqueezePlan { + symbol: "gamma", + label: "gamma", + kind: "challenge_scalar", + count: 1, + }], + Vec::new(), + vec![Stage2FieldExprPlan { + symbol: "ram_expr", + kind: "weighted_sum", + formula: "jolt_stage2_ram_read_write_input", + operand_names: &["gamma", "read", "write"], + operands: &["gamma", "read", "write"], + }], + vec![Stage2SumcheckClaimPlan { + symbol: "claim", + stage: "stage2", + domain: "domain", + num_rounds: 1, + degree: 3, + claim: "claim", + kernel: Some("kernel"), + relation: None, + claim_value: "ram_expr", + input_openings: &["read", "write"], + }], + Vec::new(), + Vec::new(), + ); + + let mut store = Stage2ValueStore::with_opening_inputs(&[ + Stage2OpeningInputValue { + symbol: "read", + point: vec![Fr::from_u64(0)], + eval: Fr::from_u64(11), + }, + Stage2OpeningInputValue { + symbol: "write", + point: vec![Fr::from_u64(1)], + eval: Fr::from_u64(13), + }, + ]); + store + .observe_challenge_vector(program, &program.transcript_squeezes[0], &[Fr::from_u64(7)]) + .expect("challenge vector observed"); + assert_eq!( + store + .claim_value(program, &program.claims[0]) + .expect("claim value resolves"), + Fr::from_u64(102) + ); + } + + #[test] + fn value_store_records_sumcheck_instance_points_and_evals() { + let program = minimal_program( + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + vec![Stage2SumcheckInstanceResultPlan { + symbol: "instance", + source: "driver", + claim: "claim", + relation: "relation", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 1, + point_order: "as_is", + degree: 3, + }], + vec![Stage2SumcheckEvalPlan { + symbol: "eval.symbol", + source: "driver", + name: "eval.name", + index: 0, + oracle: "Oracle", + }], + ); + let output = Stage2SumcheckOutput { + driver: "driver", + point: vec![Fr::from_u64(3), Fr::from_u64(5), Fr::from_u64(7)], + evals: vec![Stage2NamedEval { + name: "eval.name", + oracle: "Oracle", + value: Fr::from_u64(11), + }], + opening_claims: Vec::new(), + proof: SumcheckProof::default(), + }; + let mut store = Stage2ValueStore::new(); + store + .observe_sumcheck_output(program, &output) + .expect("sumcheck output observed"); + + assert_eq!( + store.point("instance").expect("instance point"), + &[Fr::from_u64(5), Fr::from_u64(7)] + ); + assert_eq!( + store.scalar("eval.symbol").expect("eval symbol"), + Fr::from_u64(11) + ); + assert_eq!( + store.scalar("eval.name").expect("eval name"), + Fr::from_u64(11) + ); + } + + #[test] + fn product_virtual_uniskip_kernel_proves_first_round_arithmetic() { + let program = product_uniskip_program(); + let opening_inputs = [ + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.Product", + point: vec![Fr::from_u64(0)], + eval: Fr::from_u64(11), + }, + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.ShouldBranch", + point: vec![Fr::from_u64(0)], + eval: Fr::from_u64(13), + }, + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.ShouldJump", + point: vec![Fr::from_u64(0)], + eval: Fr::from_u64(17), + }, + ]; + let extended_evals = [Fr::from_u64(23), Fr::from_u64(29)]; + let inputs = Stage2ProverInputs::new(&opening_inputs) + .with_product_uniskip_extended_evals(&extended_evals); + let mut executor = Stage2ProverKernelExecutor::new(inputs); + let mut transcript = MockTranscript::::new(b"stage2"); + + let artifacts = execute_stage2_program( + program, + Stage2ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect("product uniskip proves"); + + assert_eq!(artifacts.challenge_vectors.len(), 1); + assert_eq!(artifacts.sumchecks.len(), 1); + let output = &artifacts.sumchecks[0]; + let poly = &output.proof.round_polynomials[0]; + let tau = artifacts.challenge_vectors[0].values[0]; + let input_claim = evaluate_stage2_field_expr( + &program.field_exprs[0], + &[tau, Fr::from_u64(11), Fr::from_u64(13), Fr::from_u64(17)], + ) + .expect("input claim evaluates"); + + assert_eq!( + poly.coefficients().len(), + PRODUCT_VIRTUAL_UNISKIP_NUM_COEFFS + ); + assert!(product_uniskip_sum_matches(poly, input_claim)); + assert_eq!(output.evals.len(), 1); + assert_eq!( + output.evals[0].name, + "stage2.product_virtual.uniskip.eval.UnivariateSkip" + ); + assert_eq!(output.evals[0].value, poly.evaluate(output.point[0])); + } + + #[test] + fn product_virtual_uniskip_kernel_requires_extended_evals() { + let program = product_uniskip_program(); + let opening_inputs = [ + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.Product", + point: Vec::new(), + eval: Fr::from_u64(11), + }, + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.ShouldBranch", + point: Vec::new(), + eval: Fr::from_u64(13), + }, + Stage2OpeningInputValue { + symbol: "stage2.input.stage1.ShouldJump", + point: Vec::new(), + eval: Fr::from_u64(17), + }, + ]; + let mut executor = + Stage2ProverKernelExecutor::new(Stage2ProverInputs::new(&opening_inputs)); + let mut transcript = MockTranscript::::new(b"stage2"); + + let error = execute_stage2_program( + program, + Stage2ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect_err("missing extended evals are rejected"); + + assert_eq!( + error, + Stage2KernelError::MissingKernelInput { + kernel: "jolt_stage2_product_virtual_uniskip", + input: "product_uniskip_extended_evals", + } + ); + } + + #[test] + fn product_virtual_uniskip_extended_evals_use_trace_cycle_data() { + let cycles = [ + Stage2ProductVirtualCycle { + instruction_left_input: 7, + instruction_right_input: -3, + should_branch_lookup_output: 11, + write_lookup_output_to_rd_flag: true, + jump_flag: false, + should_branch_flag: true, + not_next_noop: true, + virtual_instruction_flag: false, + }, + Stage2ProductVirtualCycle { + instruction_left_input: 13, + instruction_right_input: 5, + should_branch_lookup_output: 17, + write_lookup_output_to_rd_flag: false, + jump_flag: true, + should_branch_flag: false, + not_next_noop: false, + virtual_instruction_flag: true, + }, + ]; + let tau_low = [Fr::from_u64(19)]; + let evals = product_virtual_uniskip_extended_evals(&cycles, &tau_low) + .expect("extended evals compute"); + + let eq = EqPolynomial::::evals(&tau_low, None); + let expected = core::array::from_fn(|target| { + eq.iter() + .zip(&cycles) + .map(|(&weight, cycle)| { + let product = product_virtual_extended_fused_product(cycle, target); + let mut accumulator = FrSignedScalarAccumulator::zero(); + accumulator.fmadd_s256(weight, product); + accumulator.reduce() + }) + .sum::() + }); + assert_eq!(evals, expected); + } + + #[test] + fn product_virtual_witness_builder_uses_product_opening_point() { + let cycles = [ + Stage2ProductVirtualCycle { + instruction_left_input: 7, + instruction_right_input: -3, + should_branch_lookup_output: 11, + write_lookup_output_to_rd_flag: true, + jump_flag: false, + should_branch_flag: true, + not_next_noop: true, + virtual_instruction_flag: false, + }, + Stage2ProductVirtualCycle { + instruction_left_input: 13, + instruction_right_input: 5, + should_branch_lookup_output: 17, + write_lookup_output_to_rd_flag: false, + jump_flag: true, + should_branch_flag: false, + not_next_noop: false, + virtual_instruction_flag: true, + }, + ]; + let opening_inputs = [Stage2OpeningInputValue { + symbol: "stage2.input.stage1.Product", + point: vec![Fr::from_u64(19)], + eval: Fr::from_u64(11), + }]; + let expected = product_virtual_uniskip_extended_evals(&cycles, &[Fr::from_u64(19)]) + .expect("extended evals compute"); + + let inputs = Stage2ProverInputs::new(&opening_inputs) + .with_product_virtual_witness(&cycles) + .expect("builder derives product virtual witness"); + + assert_eq!(inputs.product_virtual_cycles, Some(cycles.as_slice())); + assert_eq!( + inputs + .product_uniskip_extended_evals + .as_deref() + .expect("extended evals"), + expected.as_slice() + ); + } + + fn minimal_program( + transcript_squeezes: Vec, + field_constants: Vec, + field_exprs: Vec, + claims: Vec, + instance_results: Vec, + evals: Vec, + ) -> &'static Stage2CpuProgramPlan { + Box::leak(Box::new(Stage2CpuProgramPlan { + params: Stage2Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + steps: &[], + transcript_squeezes: leak_slice(transcript_squeezes), + opening_inputs: &[], + field_constants: leak_slice(field_constants), + field_exprs: leak_slice(field_exprs), + kernels: &[], + claims: leak_slice(claims), + batches: &[], + drivers: &[], + instance_results: leak_slice(instance_results), + evals: leak_slice(evals), + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_batches: &[], + })) + } + + fn leak_slice(values: Vec) -> &'static [T] { + Box::leak(values.into_boxed_slice()) + } + + fn product_uniskip_program() -> &'static Stage2CpuProgramPlan { + Box::leak(Box::new(Stage2CpuProgramPlan { + params: Stage2Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + steps: &[], + transcript_squeezes: leak_slice(vec![Stage2TranscriptSqueezePlan { + symbol: "stage2.product_virtual.tau_high", + label: "product_virtual_tau_high", + kind: "challenge_scalar", + count: 1, + }]), + opening_inputs: &[], + field_constants: &[], + field_exprs: leak_slice(vec![Stage2FieldExprPlan { + symbol: "stage2.product_virtual.uniskip.claim_expr", + kind: "weighted_sum", + formula: "jolt_stage2_product_virtual_uniskip_input", + operand_names: &[ + "stage2.product_virtual.tau_high", + "stage2.input.stage1.Product", + "stage2.input.stage1.ShouldBranch", + "stage2.input.stage1.ShouldJump", + ], + operands: &[ + "stage2.product_virtual.tau_high", + "stage2.input.stage1.Product", + "stage2.input.stage1.ShouldBranch", + "stage2.input.stage1.ShouldJump", + ], + }]), + kernels: leak_slice(vec![Stage2KernelPlan { + symbol: "jolt.cpu.stage2.product_virtual.uniskip", + relation: "jolt.stage2.product_virtual.uniskip", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage2_product_virtual_uniskip", + }]), + claims: leak_slice(vec![Stage2SumcheckClaimPlan { + symbol: "stage2.product_virtual.uniskip.input", + stage: "stage2", + domain: "jolt.stage2_uniskip_domain", + num_rounds: 1, + degree: 6, + claim: "stage2.product_virtual.weighted_stage1_outputs", + kernel: Some("jolt.cpu.stage2.product_virtual.uniskip"), + relation: None, + claim_value: "stage2.product_virtual.uniskip.claim_expr", + input_openings: &[ + "stage2.input.stage1.Product", + "stage2.input.stage1.ShouldBranch", + "stage2.input.stage1.ShouldJump", + ], + }]), + batches: leak_slice(vec![Stage2SumcheckBatchPlan { + symbol: "stage2.product_virtual.uniskip.batch", + stage: "stage2", + proof_slot: "stage2.product_virtual.uni_skip_first_round", + policy: "single_instance", + count: 1, + ordered_claims: &["stage2.product_virtual.uniskip.input"], + claim_operands: &["stage2.product_virtual.uniskip.input"], + claim_label: "uniskip_claim", + round_label: "uniskip_poly", + round_schedule: &[1], + }]), + drivers: leak_slice(vec![Stage2SumcheckDriverPlan { + symbol: "stage2.product_virtual.uniskip.sumcheck", + stage: "stage2", + proof_slot: "stage2.product_virtual.uni_skip_first_round", + kernel: Some("jolt.cpu.stage2.product_virtual.uniskip"), + relation: None, + batch: "stage2.product_virtual.uniskip.batch", + policy: "univariate_skip", + round_schedule: &[1], + claim_label: "uniskip_claim", + round_label: "uniskip_poly", + num_rounds: 1, + degree: 6, + }]), + instance_results: &[], + evals: leak_slice(vec![Stage2SumcheckEvalPlan { + symbol: "stage2.product_virtual.uniskip.eval.UnivariateSkip", + source: "stage2.product_virtual.uniskip.sumcheck", + name: "stage2.product_virtual.uniskip.eval.UnivariateSkip", + index: 0, + oracle: "UnivariateSkip", + }]), + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_batches: &[], + })) + } +} diff --git a/crates/jolt-kernels/src/stage3.rs b/crates/jolt-kernels/src/stage3.rs new file mode 100644 index 0000000000..8fb2e2ff95 --- /dev/null +++ b/crates/jolt-kernels/src/stage3.rs @@ -0,0 +1,4223 @@ +//! Stage 3 coarse-kernel ABI used by Bolt-generated Jolt prover code. + +#![expect( + clippy::too_many_arguments, + reason = "kernel constructors mirror generated staged protocol inputs" +)] + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +use crate::dense::DENSE_BIND_PAR_THRESHOLD; +use crate::split_eq::SplitEqState; +use jolt_field::{AdditiveAccumulator, Field, RingAccumulator}; +use jolt_poly::{EqPlusOnePolynomial, EqPlusOnePrefixSuffix, EqPolynomial, UnivariatePoly}; +use jolt_sumcheck::SumcheckProof; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use rayon::prelude::*; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage3ExecutionMode { + Prover, + Verifier, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage3Relation { + SpartanShift, + InstructionInput, + RegistersClaimReduction, + Batched, +} + +impl Stage3Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage3.spartan_shift" => Some(Self::SpartanShift), + "jolt.stage3.instruction_input" => Some(Self::InstructionInput), + "jolt.stage3.registers_claim_reduction" => Some(Self::RegistersClaimReduction), + "jolt.stage3.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::SpartanShift => "jolt.stage3.spartan_shift", + Self::InstructionInput => "jolt.stage3.instruction_input", + Self::RegistersClaimReduction => "jolt.stage3.registers_claim_reduction", + Self::Batched => "jolt.stage3.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage3KernelAbi { + SpartanShift, + InstructionInput, + RegistersClaimReduction, + Batched, +} + +impl Stage3KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage3_spartan_shift" => Some(Self::SpartanShift), + "jolt_stage3_instruction_input" => Some(Self::InstructionInput), + "jolt_stage3_registers_claim_reduction" => Some(Self::RegistersClaimReduction), + "jolt_stage3_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::SpartanShift => "jolt_stage3_spartan_shift", + Self::InstructionInput => "jolt_stage3_instruction_input", + Self::RegistersClaimReduction => "jolt_stage3_registers_claim_reduction", + Self::Batched => "jolt_stage3_batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +impl Stage3KernelPlan { + pub fn relation_kind(&self) -> Result { + Stage3Relation::from_symbol(self.relation).ok_or(Stage3KernelError::UnknownRelation { + relation: self.relation, + }) + } + + pub fn abi_kind(&self) -> Result { + Stage3KernelAbi::from_name(self.abi) + .ok_or(Stage3KernelError::UnknownKernelAbi { abi: self.abi }) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3TranscriptSqueezePlan { + pub symbol: &'static str, + pub label: &'static str, + pub kind: &'static str, + pub count: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3ProgramStepPlan { + pub kind: &'static str, + pub symbol: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3FieldConstantPlan { + pub symbol: &'static str, + pub field: &'static str, + pub value: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3FieldExprPlan { + pub symbol: &'static str, + pub kind: &'static str, + pub formula: &'static str, + pub operand_names: &'static [&'static str], + pub operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3SumcheckClaimPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub domain: &'static str, + pub num_rounds: usize, + pub degree: usize, + pub claim: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub claim_value: &'static str, + pub input_openings: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3SumcheckBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], + pub claim_label: &'static str, + pub round_label: &'static str, + pub round_schedule: &'static [usize], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3SumcheckDriverPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub batch: &'static str, + pub policy: &'static str, + pub round_schedule: &'static [usize], + pub claim_label: &'static str, + pub round_label: &'static str, + pub num_rounds: usize, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3SumcheckInstanceResultPlan { + pub symbol: &'static str, + pub source: &'static str, + pub claim: &'static str, + pub relation: &'static str, + pub index: usize, + pub point_arity: usize, + pub num_rounds: usize, + pub round_offset: usize, + pub point_order: &'static str, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3SumcheckEvalPlan { + pub symbol: &'static str, + pub source: &'static str, + pub name: &'static str, + pub index: usize, + pub oracle: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3PointSlicePlan { + pub symbol: &'static str, + pub source: &'static str, + pub offset: usize, + pub length: usize, + pub input: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3PointConcatPlan { + pub symbol: &'static str, + pub layout: &'static str, + pub arity: usize, + pub inputs: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, + pub point_source: &'static str, + pub eval_source: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3OpeningClaimEqualityPlan { + pub symbol: &'static str, + pub mode: &'static str, + pub lhs: &'static str, + pub rhs: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3OpeningBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3CpuProgramPlan { + pub params: Stage3Params, + pub steps: &'static [Stage3ProgramStepPlan], + pub transcript_squeezes: &'static [Stage3TranscriptSqueezePlan], + pub opening_inputs: &'static [Stage3OpeningInputPlan], + pub field_constants: &'static [Stage3FieldConstantPlan], + pub field_exprs: &'static [Stage3FieldExprPlan], + pub kernels: &'static [Stage3KernelPlan], + pub claims: &'static [Stage3SumcheckClaimPlan], + pub batches: &'static [Stage3SumcheckBatchPlan], + pub drivers: &'static [Stage3SumcheckDriverPlan], + pub instance_results: &'static [Stage3SumcheckInstanceResultPlan], + pub evals: &'static [Stage3SumcheckEvalPlan], + pub point_slices: &'static [Stage3PointSlicePlan], + pub point_concats: &'static [Stage3PointConcatPlan], + pub opening_claims: &'static [Stage3OpeningClaimPlan], + pub opening_equalities: &'static [Stage3OpeningClaimEqualityPlan], + pub opening_batches: &'static [Stage3OpeningBatchPlan], +} + +impl Stage3CpuProgramPlan { + pub fn kernel(&self, symbol: &str) -> Option<&Stage3KernelPlan> { + find_kernel(self, symbol) + } + + pub fn batch(&self, symbol: &str) -> Option<&Stage3SumcheckBatchPlan> { + find_batch(self, symbol) + } + + pub fn claim(&self, symbol: &str) -> Option<&Stage3SumcheckClaimPlan> { + self.claims.iter().find(|claim| claim.symbol == symbol) + } + + pub fn instance_results_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.instance_results + .iter() + .filter(move |instance| instance.source == driver) + } + + pub fn evals_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.evals.iter().filter(move |eval| eval.source == driver) + } +} + +#[derive(Clone, Debug)] +pub struct Stage3NamedEval { + pub name: &'static str, + pub oracle: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage3SumcheckOutput { + pub driver: &'static str, + pub point: Vec, + pub evals: Vec>, + pub opening_claims: Vec>, + pub proof: SumcheckProof, +} + +#[derive(Clone, Debug)] +pub struct Stage3ChallengeVector { + pub symbol: &'static str, + pub values: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage3OpeningClaimValue { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub claim_kind: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Debug)] +pub struct Stage3ExecutionArtifacts { + pub challenge_vectors: Vec>, + pub sumchecks: Vec>, + pub opening_claims: Vec>, + pub opening_batches: Vec<&'static Stage3OpeningBatchPlan>, +} + +impl Default for Stage3ExecutionArtifacts { + fn default() -> Self { + Self { + challenge_vectors: Vec::new(), + sumchecks: Vec::new(), + opening_claims: Vec::new(), + opening_batches: Vec::new(), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage3Proof { + pub sumchecks: Vec>, +} + +impl From> for Stage3Proof { + fn from(artifacts: Stage3ExecutionArtifacts) -> Self { + Self { + sumchecks: artifacts.sumchecks, + } + } +} + +#[derive(Clone, Debug)] +pub struct Stage3ScalarValue { + pub symbol: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage3PointValue { + pub symbol: &'static str, + pub point: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage3OpeningInputValue { + pub symbol: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage3Cycle { + pub unexpanded_pc: u64, + pub pc: u64, + pub is_virtual: bool, + pub is_first_in_sequence: bool, + pub is_noop: bool, + pub left_operand_is_rs1: bool, + pub rs1_value: u64, + pub left_operand_is_pc: bool, + pub right_operand_is_rs2: bool, + pub rs2_value: u64, + pub right_operand_is_imm: bool, + pub imm: i128, + pub rd_write_value: u64, +} + +impl Stage3Cycle { + pub fn padding() -> Self { + Self { + unexpanded_pc: 0, + pc: 0, + is_virtual: false, + is_first_in_sequence: false, + is_noop: true, + left_operand_is_rs1: false, + rs1_value: 0, + left_operand_is_pc: false, + right_operand_is_rs2: false, + rs2_value: 0, + right_operand_is_imm: false, + imm: 0, + rd_write_value: 0, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage3ValueStore { + scalars: Vec>, + points: Vec>, +} + +impl Stage3ValueStore { + pub fn new() -> Self { + Self::default() + } + + pub fn with_opening_inputs(inputs: &[Stage3OpeningInputValue]) -> Self { + let mut store = Self::new(); + store.insert_opening_inputs(inputs); + store + } + + pub fn insert_opening_inputs(&mut self, inputs: &[Stage3OpeningInputValue]) { + for input in inputs { + self.insert_scalar(input.symbol, input.eval); + self.insert_point(input.symbol, input.point.clone()); + } + } + + pub fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some(existing) = self + .scalars + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.value = value; + } else { + self.scalars.push(Stage3ScalarValue { symbol, value }); + } + } + + pub fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some(existing) = self + .points + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.point = point; + } else { + self.points.push(Stage3PointValue { symbol, point }); + } + } + + pub fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.value) + } + + pub fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage3KernelError::MissingValue { symbol }) + } + + pub fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.point.as_slice()) + } + + pub fn point(&self, symbol: &'static str) -> Result<&[F], Stage3KernelError> { + self.try_point(symbol) + .ok_or(Stage3KernelError::MissingValue { symbol }) + } + + pub fn seed_constants( + &mut self, + program: &'static Stage3CpuProgramPlan, + ) -> Result<(), Stage3KernelError> { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + Ok(()) + } + + pub fn observe_challenge_vector( + &mut self, + plan: &'static Stage3TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage3KernelError> { + if matches!(plan.kind, "challenge_scalar" | "scalar") { + require_operand_count(plan.symbol, 1, values.len())?; + self.insert_scalar(plan.symbol, values[0]); + } + self.insert_point(plan.symbol, values.to_vec()); + Ok(()) + } + + pub fn observe_sumcheck_output( + &mut self, + program: &'static Stage3CpuProgramPlan, + output: &Stage3SumcheckOutput, + ) -> Result<(), Stage3KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + pub fn observe_sumcheck_values( + &mut self, + program: &'static Stage3CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage3NamedEval], + ) -> Result<(), Stage3KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program.instance_results_for_driver(driver) { + let end = instance.round_offset + instance.point_arity; + let mut point = point + .get(instance.round_offset..end) + .ok_or(Stage3KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + _ => { + return Err(Stage3KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, point); + } + for eval in program.evals_for_driver(driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage3KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + Ok(()) + } + + pub fn evaluate_available_points( + &mut self, + program: &'static Stage3CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage3KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + verify_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage3CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate_stage3_field_expr(expr, &operands)?); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn verify_opening_equalities( + &self, + program: &'static Stage3CpuProgramPlan, + ) -> Result<(), Stage3KernelError> { + for equality in program.opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point(equality.lhs)? != self.point(equality.rhs)? + || self.scalar(equality.lhs)? != self.scalar(equality.rhs)? + { + return Err(Stage3KernelError::InvalidProof { + driver: equality.symbol, + reason: "opening claim equality failed", + }); + } + } + _ => { + return Err(Stage3KernelError::InvalidProof { + driver: equality.symbol, + reason: "unsupported opening equality mode", + }); + } + } + } + Ok(()) + } + + pub fn claim_value( + &mut self, + program: &'static Stage3CpuProgramPlan, + claim: &Stage3SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + pub fn batch_claim_values( + &mut self, + program: &'static Stage3CpuProgramPlan, + batch: &Stage3SumcheckBatchPlan, + ) -> Result, Stage3KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage3KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn try_expr_operands(&self, expr: &Stage3FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage3PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +pub fn evaluate_stage3_field_expr( + expr: &Stage3FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + _ => { + if let Some(exponent) = expr.formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage3KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(Stage3KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + }) + } + } +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage3KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage3KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage3KernelContext<'a> { + pub mode: Stage3ExecutionMode, + pub program: &'static Stage3CpuProgramPlan, + pub kernel: &'a Stage3KernelPlan, + pub batch: &'a Stage3SumcheckBatchPlan, + pub driver: &'a Stage3SumcheckDriverPlan, +} + +impl Stage3KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + self.kernel.relation_kind() + } + + pub fn abi_kind(&self) -> Result { + self.kernel.abi_kind() + } + + pub fn batch_claims(&self) -> Result, Stage3KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage3KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage3KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage3TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage3KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage3SumcheckOutput, + ) -> Result<(), Stage3KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage3KernelExecutor; + +impl Stage3KernelExecutor for UnsupportedStage3KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + Err(Stage3KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + Err(Stage3KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } +} + +#[derive(Clone, Copy)] +pub struct Stage3ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage3OpeningInputValue], + pub cycles: Option<&'a [Stage3Cycle]>, +} + +impl<'a, F: Field> Stage3ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage3OpeningInputValue]) -> Self { + Self { + opening_inputs, + cycles: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + cycles: None, + } + } + + pub fn with_cycles(mut self, cycles: &'a [Stage3Cycle]) -> Self { + self.cycles = Some(cycles); + self + } +} + +#[derive(Clone)] +pub struct Stage3ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage3ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage3ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage3ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage3CpuProgramPlan, + ) -> Result, Stage3KernelError> { + value_store_from_observations( + program, + self.inputs.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage3KernelExecutor for Stage3ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage3TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage3KernelError> { + self.challenge_vectors.push(Stage3ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage3SumcheckOutput, + ) -> Result<(), Stage3KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + prove_stage3_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + Err(Stage3KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage3ExecutionMode::Prover, + actual: Stage3ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage3VerifierKernelExecutor<'a, F: Field> { + pub proof: &'a Stage3Proof, + pub opening_inputs: &'a [Stage3OpeningInputValue], + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage3VerifierKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage3Proof, + opening_inputs: &'a [Stage3OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage3CpuProgramPlan, + ) -> Result, Stage3KernelError> { + value_store_from_observations( + program, + self.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage3KernelExecutor for Stage3VerifierKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage3TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage3KernelError> { + self.challenge_vectors.push(Stage3ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage3SumcheckOutput, + ) -> Result<(), Stage3KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + Err(Stage3KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage3ExecutionMode::Verifier, + actual: Stage3ExecutionMode::Prover, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage3KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage3KernelError> + where + T: Transcript, + { + let proof = + self.proof + .sumchecks + .get(self.cursor) + .ok_or(Stage3KernelError::MissingProof { + driver: context.driver.symbol, + })?; + self.cursor += 1; + verify_stage3_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } +} + +fn value_store_from_observations( + program: &'static Stage3CpuProgramPlan, + opening_inputs: &[Stage3OpeningInputValue], + challenge_vectors: &[Stage3ChallengeVector], + completed_sumchecks: &[Stage3SumcheckOutput], +) -> Result, Stage3KernelError> { + let mut store = Stage3ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(program)?; + for challenge in challenge_vectors { + let plan = program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == challenge.symbol) + .ok_or(Stage3KernelError::MissingValue { + symbol: challenge.symbol, + })?; + store.observe_challenge_vector(plan, &challenge.values)?; + } + for output in completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + store.verify_opening_equalities(program)?; + Ok(store) +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage3KernelError { + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage3ExecutionMode, + actual: Stage3ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage3KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage3 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage3 driver @{driver} references missing batch @{batch}" + ) + } + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage3 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage3 value @{symbol} is not available") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => write!( + formatter, + "stage3 plan @{artifact} count mismatch: expected {expected}, got {actual}" + ), + Self::InvalidInputLength { + input, + expected, + actual, + } => write!( + formatter, + "stage3 input `{input}` length mismatch: expected {expected}, got {actual}" + ), + Self::UnsupportedFieldExpr { symbol, formula } => write!( + formatter, + "stage3 field expr @{symbol} uses unsupported formula `{formula}`" + ), + Self::UnknownRelation { relation } => { + write!(formatter, "stage3 relation @{relation} is not registered") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "stage3 kernel ABI `{abi}` is not registered") + } + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage3 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => write!( + formatter, + "stage3 driver @{driver} ran with {actual:?} executor path, expected {expected:?}" + ), + Self::MissingProof { driver } => { + write!( + formatter, + "stage3 verifier missing proof for driver @{driver}" + ) + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage3 kernel `{kernel}` missing input `{input}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage3 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage3KernelError {} + +fn prove_stage3_kernel( + context: Stage3KernelContext<'_>, + inputs: &Stage3ProverInputs<'_, F>, + store: Stage3ValueStore, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage3KernelAbi::Batched => prove_batched_stage3(context, inputs, store, transcript), + abi => Err(Stage3KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +fn verify_stage3_kernel( + context: Stage3KernelContext<'_>, + store: Stage3ValueStore, + proof: &Stage3SumcheckOutput, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage3KernelAbi::Batched => verify_batched_stage3(context, store, proof, transcript), + abi => Err(Stage3KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +#[tracing::instrument(skip_all, name = "Stage3::prove_batched")] +fn prove_batched_stage3( + context: Stage3KernelContext<'_>, + inputs: &Stage3ProverInputs<'_, F>, + mut store: Stage3ValueStore, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + let mut instances = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + instances.push(Stage3BatchedInstance { + claim, + relation: claim_relation(context.program, claim)?, + offset: instance_round_offset(context.program, context.driver.symbol, claim.symbol)?, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state: Stage3ProverInstanceState::new(context.program, claim, inputs, &store)?, + }); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for instance in &mut instances { + let poly = if instance.is_active(round) { + instance + .state + .round_poly(round - instance.offset, instance.previous_claim)? + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + #[cfg(debug_assertions)] + { + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != instance.previous_claim { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched instance round claim mismatch", + }); + } + } + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + #[cfg(debug_assertions)] + { + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + for (instance, poly) in instances.iter_mut().zip(individual_polys) { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + instance.state.ingest_challenge(challenge); + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + for instance in &instances { + evals.extend(instance.state.final_evals(instance.relation)?); + } + let expected = + expected_batched_output_claim(context, &store, &evals, &point, &batching_coeffs)?; + if batched_claim != expected { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + Ok(Stage3SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage3( + context: Stage3KernelContext<'_>, + mut store: Stage3ValueStore, + proof: &Stage3SumcheckOutput, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = + expected_batched_output_claim(context, &store, &proof.evals, &point, &batching_coeffs)?; + if running_claim != expected { + return Err(Stage3KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &proof.evals)?; + let opening_claims = + append_opening_claims(context.program, &mut store, transcript, &proof.evals)?; + Ok(Stage3SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims, + proof: proof.proof.clone(), + }) +} + +struct Stage3BatchedInstance<'a, F: Field> { + claim: &'a Stage3SumcheckClaimPlan, + relation: Stage3Relation, + offset: usize, + previous_claim: F, + state: Stage3ProverInstanceState, +} + +impl Stage3BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage3ProverInstanceState { + SpartanShift(SpartanShiftState), + SumOfProducts(SumOfProductsState), +} + +impl Stage3ProverInstanceState { + fn new( + program: &'static Stage3CpuProgramPlan, + claim: &Stage3SumcheckClaimPlan, + inputs: &Stage3ProverInputs<'_, F>, + store: &Stage3ValueStore, + ) -> Result { + match claim_relation(program, claim)? { + Stage3Relation::SpartanShift => { + return spartan_shift_state(claim, inputs, store).map(Self::SpartanShift); + } + Stage3Relation::InstructionInput => instruction_input_state(claim, inputs, store), + Stage3Relation::RegistersClaimReduction => registers_state(claim, inputs, store), + relation @ Stage3Relation::Batched => Err(Stage3KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + .map(Self::SumOfProducts) + } + + fn round_poly( + &self, + _round: usize, + previous_claim: F, + ) -> Result, Stage3KernelError> { + match self { + Self::SpartanShift(state) => Ok(state.round_poly(previous_claim)), + Self::SumOfProducts(state) => Ok(state.round_poly(previous_claim)), + } + } + + fn ingest_challenge(&mut self, challenge: F) { + match self { + Self::SpartanShift(state) => state.bind(challenge), + Self::SumOfProducts(state) => state.bind(challenge), + } + } + + fn final_evals( + &self, + relation: Stage3Relation, + ) -> Result>, Stage3KernelError> { + match self { + Self::SpartanShift(state) => state.final_evals(relation), + Self::SumOfProducts(state) => state.final_evals(relation), + } + } +} + +#[derive(Clone)] +struct SpartanShiftState { + phase: SpartanShiftPhase, + r_outer: Vec, + r_product: Vec, + gamma: F, + gamma2: F, + gamma3: F, + gamma4: F, + point: Vec, +} + +#[derive(Clone)] +enum SpartanShiftPhase { + Phase1(SpartanShiftPhase1), + Phase2(SpartanShiftPhase2), +} + +#[derive(Clone)] +struct SpartanShiftPhase1 { + prefix_suffix_pairs: Vec<(Vec, Vec)>, + scratch: Vec<(Vec, Vec)>, + cycles: Vec, +} + +#[derive(Clone)] +struct SpartanShiftPhase2 { + eq_outer: Vec, + eq_product: Vec, + weighted_next_values: Vec, + not_noop: Vec, + unexpanded_pc: Vec, + pc: Vec, + is_virtual: Vec, + is_first_in_sequence: Vec, + is_noop: Vec, + scratch: Vec>, +} + +#[derive(Clone)] +struct SumOfProductsState { + kind: SumOfProductsKind, + factors: Vec>, + factor_scratch: Vec>, + split_eq: Option>, + terms: Vec>, + outputs: Vec, + deferred_outputs: Vec>, + point: Vec, +} + +#[derive(Clone, Copy)] +enum SumOfProductsKind { + InstructionInput, + Registers, +} + +#[derive(Clone)] +struct ProductTerm { + coefficient: F, +} + +#[derive(Clone, Copy)] +struct FactorOutput { + name: &'static str, + oracle: &'static str, + factor: usize, +} + +#[derive(Clone)] +struct DeferredOutput { + name: &'static str, + oracle: &'static str, + values: Vec, +} + +impl SumOfProductsState { + fn new( + kind: SumOfProductsKind, + factors: Vec>, + split_eq: Option>, + terms: Vec>, + outputs: Vec, + deferred_outputs: Vec>, + ) -> Self { + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Self { + kind, + factors, + factor_scratch, + split_eq, + terms, + outputs, + deferred_outputs, + point: Vec::new(), + } + } + + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + let Some(split_eq) = self.split_eq.as_ref() else { + std::process::abort(); + }; + match self.kind { + SumOfProductsKind::InstructionInput => round_poly_from_instruction_input( + &self.factors, + &self.terms, + split_eq, + previous_claim, + ), + SumOfProductsKind::Registers => { + round_poly_from_registers(&self.factors, &self.terms, split_eq, previous_claim) + } + } + } + + fn bind(&mut self, challenge: F) { + let half = self.factors.first().map_or(0, |factor| factor.len() / 2); + if half >= DENSE_BIND_PAR_THRESHOLD { + self.factors + .par_iter_mut() + .zip(self.factor_scratch.par_iter_mut()) + .for_each(|(factor, scratch)| { + bind_dense_evals_reuse_serial(factor, scratch, challenge); + }); + } else { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse_serial(factor, scratch, challenge); + } + } + if let Some(split_eq) = &mut self.split_eq { + split_eq.bind(challenge); + } + self.point.push(challenge); + } + + fn factor_eval(&self, index: usize, relation: Stage3Relation) -> Result { + self.factors + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage3KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty stage3 factor", + }) + } + + fn final_evals( + &self, + relation: Stage3Relation, + ) -> Result>, Stage3KernelError> { + let mut evals = self + .outputs + .iter() + .map(|output| { + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(output.factor, relation)?, + )) + }) + .collect::, _>>()?; + if !self.deferred_outputs.is_empty() { + let point = reverse_slice(&self.point); + let eq = EqPolynomial::::evals(&point, None); + evals.extend(self.deferred_outputs.iter().map(|output| { + named_eval( + output.name, + output.oracle, + deferred_output_eval(&output.values, &eq), + ) + })); + } + Ok(evals) + } +} + +impl SpartanShiftState { + fn new( + cycles: &[Stage3Cycle], + r_outer: &[F], + r_product: &[F], + gamma: F, + gamma2: F, + gamma3: F, + gamma4: F, + ) -> Self { + Self { + phase: SpartanShiftPhase::Phase1(SpartanShiftPhase1::new( + cycles, r_outer, r_product, gamma, gamma2, gamma3, gamma4, + )), + r_outer: r_outer.to_vec(), + r_product: r_product.to_vec(), + gamma, + gamma2, + gamma3, + gamma4, + point: Vec::new(), + } + } + + fn round_poly(&self, previous_claim: F) -> UnivariatePoly { + match &self.phase { + SpartanShiftPhase::Phase1(state) => state.round_poly(), + SpartanShiftPhase::Phase2(state) => state.round_poly(previous_claim), + } + } + + fn bind(&mut self, challenge: F) { + let transition = match &mut self.phase { + SpartanShiftPhase::Phase1(state) => { + if state.should_transition_to_phase2() { + true + } else { + state.bind(challenge); + false + } + } + SpartanShiftPhase::Phase2(state) => { + state.bind(challenge); + false + } + }; + self.point.push(challenge); + if transition { + let SpartanShiftPhase::Phase1(state) = &self.phase else { + unreachable!("checked phase before transition"); + }; + let phase2 = SpartanShiftPhase2::new( + &state.cycles, + &self.point, + &self.r_outer, + &self.r_product, + self.gamma, + self.gamma2, + self.gamma3, + self.gamma4, + ); + self.phase = SpartanShiftPhase::Phase2(phase2); + } + } + + fn final_evals( + &self, + relation: Stage3Relation, + ) -> Result>, Stage3KernelError> { + let SpartanShiftPhase::Phase2(state) = &self.phase else { + return Err(Stage3KernelError::InvalidProof { + driver: relation.symbol(), + reason: "spartan shift did not finish phase 2", + }); + }; + state.final_evals(relation) + } +} + +impl SpartanShiftPhase1 { + fn new( + cycles: &[Stage3Cycle], + r_outer: &[F], + r_product: &[F], + gamma: F, + gamma2: F, + gamma3: F, + gamma4: F, + ) -> Self { + let outer = EqPlusOnePrefixSuffix::new(r_outer); + let product = EqPlusOnePrefixSuffix::new(r_product); + let q_values = + spartan_shift_phase1_q_values(cycles, &outer, &product, gamma, gamma2, gamma3, gamma4); + let mut q_outer_0 = Vec::with_capacity(q_values.len()); + let mut q_outer_1 = Vec::with_capacity(q_values.len()); + let mut q_product_0 = Vec::with_capacity(q_values.len()); + let mut q_product_1 = Vec::with_capacity(q_values.len()); + for [outer_0, outer_1, product_0, product_1] in q_values { + q_outer_0.push(outer_0); + q_outer_1.push(outer_1); + q_product_0.push(product_0); + q_product_1.push(product_1); + } + let prefix_suffix_pairs = vec![ + (outer.prefix_0, q_outer_0), + (outer.prefix_1, q_outer_1), + (product.prefix_0, q_product_0), + (product.prefix_1, q_product_1), + ]; + let scratch = prefix_suffix_pairs + .iter() + .map(|_| (Vec::new(), Vec::new())) + .collect(); + Self { + prefix_suffix_pairs, + scratch, + cycles: cycles.to_vec(), + } + } + + fn round_poly(&self) -> UnivariatePoly { + let half = self.prefix_suffix_pairs[0].0.len() / 2; + round_poly_from_stage3_coefficients(half, 2, |row, acc| { + for (prefix, suffix) in &self.prefix_suffix_pairs { + let (prefix_0, prefix_delta) = linear_pair(prefix, row); + let (suffix_0, suffix_delta) = linear_pair(suffix, row); + accumulate_linear_product( + acc, + F::one(), + prefix_0, + prefix_delta, + suffix_0, + suffix_delta, + ); + } + }) + } + + fn bind(&mut self, challenge: F) { + for ((prefix, suffix), (prefix_scratch, suffix_scratch)) in self + .prefix_suffix_pairs + .iter_mut() + .zip(self.scratch.iter_mut()) + { + bind_dense_evals_reuse_serial(prefix, prefix_scratch, challenge); + bind_dense_evals_reuse_serial(suffix, suffix_scratch, challenge); + } + } + + fn should_transition_to_phase2(&self) -> bool { + self.prefix_suffix_pairs[0].0.len() == 2 + } +} + +impl SpartanShiftPhase2 { + fn new( + cycles: &[Stage3Cycle], + low_challenges: &[F], + r_outer: &[F], + r_product: &[F], + gamma: F, + gamma2: F, + gamma3: F, + gamma4: F, + ) -> Self { + let low_point = reverse_slice(low_challenges); + let low_eq = EqPolynomial::::evals(&low_point, None); + let eq_outer = spartan_shift_phase2_eq_plus_one(r_outer, &low_eq); + let eq_product = spartan_shift_phase2_eq_plus_one(r_product, &low_eq); + let ( + unexpanded_pc, + pc, + is_virtual, + is_first_in_sequence, + is_noop, + weighted_next_values, + not_noop, + ) = spartan_shift_phase2_outputs(cycles, &low_eq, gamma, gamma2, gamma3); + let not_noop = not_noop + .iter() + .map(|&value| gamma4 * value) + .collect::>(); + Self { + eq_outer, + eq_product, + weighted_next_values, + not_noop, + unexpanded_pc, + pc, + is_virtual, + is_first_in_sequence, + is_noop, + scratch: (0..9).map(|_| Vec::new()).collect(), + } + } + + fn round_poly(&self, _previous_claim: F) -> UnivariatePoly { + round_poly_from_stage3_coefficients(self.eq_outer.len() / 2, 2, |row, acc| { + let (eq_outer_0, eq_outer_delta) = linear_pair(&self.eq_outer, row); + let (eq_product_0, eq_product_delta) = linear_pair(&self.eq_product, row); + let (next_values_0, next_values_delta) = linear_pair(&self.weighted_next_values, row); + let (not_noop_0, not_noop_delta) = linear_pair(&self.not_noop, row); + accumulate_linear_product( + acc, + F::one(), + eq_outer_0, + eq_outer_delta, + next_values_0, + next_values_delta, + ); + accumulate_linear_product( + acc, + F::one(), + eq_product_0, + eq_product_delta, + not_noop_0, + not_noop_delta, + ); + }) + } + + fn bind(&mut self, challenge: F) { + bind_dense_evals_reuse_serial(&mut self.eq_outer, &mut self.scratch[0], challenge); + bind_dense_evals_reuse_serial(&mut self.eq_product, &mut self.scratch[1], challenge); + bind_dense_evals_reuse_serial( + &mut self.weighted_next_values, + &mut self.scratch[2], + challenge, + ); + bind_dense_evals_reuse_serial(&mut self.not_noop, &mut self.scratch[3], challenge); + bind_dense_evals_reuse_serial(&mut self.unexpanded_pc, &mut self.scratch[4], challenge); + bind_dense_evals_reuse_serial(&mut self.pc, &mut self.scratch[5], challenge); + bind_dense_evals_reuse_serial(&mut self.is_virtual, &mut self.scratch[6], challenge); + bind_dense_evals_reuse_serial( + &mut self.is_first_in_sequence, + &mut self.scratch[7], + challenge, + ); + bind_dense_evals_reuse_serial(&mut self.is_noop, &mut self.scratch[8], challenge); + } + + fn final_evals( + &self, + relation: Stage3Relation, + ) -> Result>, Stage3KernelError> { + let value = |values: &[F]| { + values + .first() + .copied() + .ok_or(Stage3KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty spartan shift output", + }) + }; + Ok(vec![ + named_eval( + "stage3.spartan_shift.eval.UnexpandedPC", + "UnexpandedPC", + value(&self.unexpanded_pc)?, + ), + named_eval("stage3.spartan_shift.eval.PC", "PC", value(&self.pc)?), + named_eval( + "stage3.spartan_shift.eval.OpFlagVirtualInstruction", + "OpFlagVirtualInstruction", + value(&self.is_virtual)?, + ), + named_eval( + "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", + "OpFlagIsFirstInSequence", + value(&self.is_first_in_sequence)?, + ), + named_eval( + "stage3.spartan_shift.eval.InstructionFlagIsNoop", + "InstructionFlagIsNoop", + value(&self.is_noop)?, + ), + ]) + } +} + +fn spartan_shift_state( + claim: &Stage3SumcheckClaimPlan, + inputs: &Stage3ProverInputs<'_, F>, + store: &Stage3ValueStore, +) -> Result, Stage3KernelError> { + let cycles = stage3_cycles(inputs, claim.num_rounds)?; + let r_outer = store.point("stage3.input.stage1.NextPC")?; + let r_product = store.point("stage3.input.stage2.product_virtual.NextIsNoop")?; + let gamma = store.scalar("stage3.spartan_shift.gamma")?; + let gamma2 = store.scalar("stage3.spartan_shift.gamma2")?; + let gamma3 = store.scalar("stage3.spartan_shift.gamma3")?; + let gamma4 = store.scalar("stage3.spartan_shift.gamma4")?; + Ok(SpartanShiftState::new( + cycles, r_outer, r_product, gamma, gamma2, gamma3, gamma4, + )) +} + +fn instruction_input_state( + claim: &Stage3SumcheckClaimPlan, + inputs: &Stage3ProverInputs<'_, F>, + store: &Stage3ValueStore, +) -> Result, Stage3KernelError> { + let cycles = stage3_cycles(inputs, claim.num_rounds)?; + let eq_point = store.point("stage3.input.stage2.product_virtual.LeftInstructionInput")?; + let gamma = store.scalar("stage3.instruction_input.gamma")?; + let ( + right_operand_is_rs2, + rs2_value, + right_operand_is_imm, + imm, + left_operand_is_rs1, + rs1_value, + left_operand_is_pc, + unexpanded_pc, + ) = instruction_input_factors(cycles); + let factors = vec![ + right_operand_is_rs2, + rs2_value, + right_operand_is_imm, + imm, + left_operand_is_rs1, + rs1_value, + left_operand_is_pc, + unexpanded_pc, + ]; + Ok(SumOfProductsState::new( + SumOfProductsKind::InstructionInput, + factors, + Some(SplitEqState::new_low_to_high(eq_point, None)), + vec![ + ProductTerm { + coefficient: F::one(), + }, + ProductTerm { + coefficient: F::one(), + }, + ProductTerm { coefficient: gamma }, + ProductTerm { coefficient: gamma }, + ], + vec![ + FactorOutput { + name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", + oracle: "InstructionFlagLeftOperandIsRs1Value", + factor: 4, + }, + FactorOutput { + name: "stage3.instruction_input.eval.Rs1Value", + oracle: "Rs1Value", + factor: 5, + }, + FactorOutput { + name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", + oracle: "InstructionFlagLeftOperandIsPC", + factor: 6, + }, + FactorOutput { + name: "stage3.instruction_input.eval.UnexpandedPC", + oracle: "UnexpandedPC", + factor: 7, + }, + FactorOutput { + name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", + oracle: "InstructionFlagRightOperandIsRs2Value", + factor: 0, + }, + FactorOutput { + name: "stage3.instruction_input.eval.Rs2Value", + oracle: "Rs2Value", + factor: 1, + }, + FactorOutput { + name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", + oracle: "InstructionFlagRightOperandIsImm", + factor: 2, + }, + FactorOutput { + name: "stage3.instruction_input.eval.Imm", + oracle: "Imm", + factor: 3, + }, + ], + Vec::new(), + )) +} + +fn registers_state( + claim: &Stage3SumcheckClaimPlan, + inputs: &Stage3ProverInputs<'_, F>, + store: &Stage3ValueStore, +) -> Result, Stage3KernelError> { + let cycles = stage3_cycles(inputs, claim.num_rounds)?; + let eq_point = store.point("stage3.input.stage1.RdWriteValue")?; + let gamma = store.scalar("stage3.registers.gamma")?; + let gamma2 = store.scalar("stage3.registers.gamma2")?; + let (rd_write_value, rs1_value, rs2_value) = register_factors(cycles); + let factors = vec![rd_write_value, rs1_value, rs2_value]; + Ok(SumOfProductsState::new( + SumOfProductsKind::Registers, + factors, + Some(SplitEqState::new_low_to_high(eq_point, None)), + vec![ + ProductTerm { + coefficient: F::one(), + }, + ProductTerm { coefficient: gamma }, + ProductTerm { + coefficient: gamma2, + }, + ], + vec![ + FactorOutput { + name: "stage3.registers_claim_reduction.eval.RdWriteValue", + oracle: "RdWriteValue", + factor: 0, + }, + FactorOutput { + name: "stage3.registers_claim_reduction.eval.Rs1Value", + oracle: "Rs1Value", + factor: 1, + }, + FactorOutput { + name: "stage3.registers_claim_reduction.eval.Rs2Value", + oracle: "Rs2Value", + factor: 2, + }, + ], + Vec::new(), + )) +} + +fn stage3_cycles<'a, F: Field>( + inputs: &'a Stage3ProverInputs<'_, F>, + num_rounds: usize, +) -> Result<&'a [Stage3Cycle], Stage3KernelError> { + let cycles = inputs.cycles.ok_or(Stage3KernelError::MissingKernelInput { + kernel: "jolt_stage3_batched", + input: "cycles", + })?; + let expected = + 1usize + .checked_shl(num_rounds as u32) + .ok_or(Stage3KernelError::InvalidInputLength { + input: "stage3.cycles", + expected: usize::BITS as usize, + actual: num_rounds, + })?; + require_operand_count("stage3.cycles", expected, cycles.len())?; + Ok(cycles) +} + +type InstructionInputFactors = ( + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, +); +type RegisterFactors = (Vec, Vec, Vec); + +fn spartan_shift_phase1_q_values( + cycles: &[Stage3Cycle], + outer: &EqPlusOnePrefixSuffix, + product: &EqPlusOnePrefixSuffix, + gamma: F, + gamma2: F, + gamma3: F, + gamma4: F, +) -> Vec<[F; 4]> { + let prefix_len = outer.prefix_0.len(); + let suffix_len = outer.suffix_0.len(); + debug_assert_eq!(prefix_len * suffix_len, cycles.len()); + (0..prefix_len) + .into_par_iter() + .map(|x_lo| { + let mut acc = [F::Accumulator::default(); 4]; + for x_hi in 0..suffix_len { + let cycle = cycles[x_lo + x_hi * prefix_len]; + let mut weighted = F::from_u64(cycle.unexpanded_pc) + gamma * F::from_u64(cycle.pc); + if cycle.is_virtual { + weighted += gamma2; + } + if cycle.is_first_in_sequence { + weighted += gamma3; + } + acc[0].fmadd(outer.suffix_0[x_hi], weighted); + acc[1].fmadd(outer.suffix_1[x_hi], weighted); + if !cycle.is_noop { + acc[2].fmadd(gamma4, product.suffix_0[x_hi]); + acc[3].fmadd(gamma4, product.suffix_1[x_hi]); + } + } + [ + acc[0].reduce(), + acc[1].reduce(), + acc[2].reduce(), + acc[3].reduce(), + ] + }) + .collect() +} + +fn spartan_shift_phase2_eq_plus_one(point: &[F], low_eq: &[F]) -> Vec { + let split = EqPlusOnePrefixSuffix::new(point); + let prefix_0_eval = deferred_output_eval(&split.prefix_0, low_eq); + let prefix_1_eval = deferred_output_eval(&split.prefix_1, low_eq); + debug_assert_eq!(split.prefix_0.len(), low_eq.len()); + split + .suffix_0 + .iter() + .zip(split.suffix_1.iter()) + .map(|(&suffix_0, &suffix_1)| prefix_0_eval * suffix_0 + prefix_1_eval * suffix_1) + .collect() +} + +type SpartanShiftPhase2Outputs = (Vec, Vec, Vec, Vec, Vec, Vec, Vec); + +fn spartan_shift_phase2_outputs( + cycles: &[Stage3Cycle], + low_eq: &[F], + gamma: F, + gamma2: F, + gamma3: F, +) -> SpartanShiftPhase2Outputs { + let low_len = low_eq.len(); + let high_len = cycles.len() / low_len; + let mut unexpanded_pc = vec![F::zero(); high_len]; + let mut pc = vec![F::zero(); high_len]; + let mut is_virtual = vec![F::zero(); high_len]; + let mut is_first_in_sequence = vec![F::zero(); high_len]; + let mut is_noop = vec![F::zero(); high_len]; + let mut weighted_next_values = vec![F::zero(); high_len]; + let mut not_noop = vec![F::zero(); high_len]; + ( + &mut unexpanded_pc, + &mut pc, + &mut is_virtual, + &mut is_first_in_sequence, + &mut is_noop, + &mut weighted_next_values, + &mut not_noop, + 0..high_len, + ) + .into_par_iter() + .for_each( + |( + unexpanded_pc, + pc, + is_virtual, + is_first_in_sequence, + is_noop, + weighted_next_values, + not_noop, + x_hi, + )| { + let mut unexpanded_acc = F::Accumulator::default(); + let mut pc_acc = F::Accumulator::default(); + let mut virtual_acc = F::Accumulator::default(); + let mut first_acc = F::Accumulator::default(); + let mut noop_acc = F::Accumulator::default(); + let base = x_hi * low_len; + for (x_lo, &weight) in low_eq.iter().enumerate() { + let cycle = cycles[base + x_lo]; + unexpanded_acc.fmadd_u64(weight, cycle.unexpanded_pc); + pc_acc.fmadd_u64(weight, cycle.pc); + virtual_acc.fmadd_bool(weight, cycle.is_virtual); + first_acc.fmadd_bool(weight, cycle.is_first_in_sequence); + noop_acc.fmadd_bool(weight, cycle.is_noop); + } + *unexpanded_pc = unexpanded_acc.reduce(); + *pc = pc_acc.reduce(); + *is_virtual = virtual_acc.reduce(); + *is_first_in_sequence = first_acc.reduce(); + *is_noop = noop_acc.reduce(); + *weighted_next_values = *unexpanded_pc + + gamma * *pc + + gamma2 * *is_virtual + + gamma3 * *is_first_in_sequence; + *not_noop = F::one() - *is_noop; + }, + ); + ( + unexpanded_pc, + pc, + is_virtual, + is_first_in_sequence, + is_noop, + weighted_next_values, + not_noop, + ) +} + +fn instruction_input_factors(cycles: &[Stage3Cycle]) -> InstructionInputFactors { + let mut right_operand_is_rs2 = vec![F::zero(); cycles.len()]; + let mut rs2_value = vec![F::zero(); cycles.len()]; + let mut right_operand_is_imm = vec![F::zero(); cycles.len()]; + let mut imm = vec![F::zero(); cycles.len()]; + let mut left_operand_is_rs1 = vec![F::zero(); cycles.len()]; + let mut rs1_value = vec![F::zero(); cycles.len()]; + let mut left_operand_is_pc = vec![F::zero(); cycles.len()]; + let mut unexpanded_pc = vec![F::zero(); cycles.len()]; + ( + &mut right_operand_is_rs2, + &mut rs2_value, + &mut right_operand_is_imm, + &mut imm, + &mut left_operand_is_rs1, + &mut rs1_value, + &mut left_operand_is_pc, + &mut unexpanded_pc, + cycles, + ) + .into_par_iter() + .for_each( + |( + right_operand_is_rs2, + rs2_value, + right_operand_is_imm, + imm, + left_operand_is_rs1, + rs1_value, + left_operand_is_pc, + unexpanded_pc, + cycle, + )| { + *right_operand_is_rs2 = F::from_bool(cycle.right_operand_is_rs2); + *rs2_value = F::from_u64(cycle.rs2_value); + *right_operand_is_imm = F::from_bool(cycle.right_operand_is_imm); + *imm = F::from_i128(cycle.imm); + *left_operand_is_rs1 = F::from_bool(cycle.left_operand_is_rs1); + *rs1_value = F::from_u64(cycle.rs1_value); + *left_operand_is_pc = F::from_bool(cycle.left_operand_is_pc); + *unexpanded_pc = F::from_u64(cycle.unexpanded_pc); + }, + ); + ( + right_operand_is_rs2, + rs2_value, + right_operand_is_imm, + imm, + left_operand_is_rs1, + rs1_value, + left_operand_is_pc, + unexpanded_pc, + ) +} + +fn register_factors(cycles: &[Stage3Cycle]) -> RegisterFactors { + let mut rd_write_value = vec![F::zero(); cycles.len()]; + let mut rs1_value = vec![F::zero(); cycles.len()]; + let mut rs2_value = vec![F::zero(); cycles.len()]; + (&mut rd_write_value, &mut rs1_value, &mut rs2_value, cycles) + .into_par_iter() + .for_each(|(rd_write_value, rs1_value, rs2_value, cycle)| { + *rd_write_value = F::from_u64(cycle.rd_write_value); + *rs1_value = F::from_u64(cycle.rs1_value); + *rs2_value = F::from_u64(cycle.rs2_value); + }); + (rd_write_value, rs1_value, rs2_value) +} + +fn expected_batched_output_claim( + context: Stage3KernelContext<'_>, + store: &Stage3ValueStore, + evals: &[Stage3NamedEval], + point: &[F], + batching_coeffs: &[F], +) -> Result { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let instance = context + .program + .instance_results + .iter() + .find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) + .ok_or(Stage3KernelError::MissingClaim { + batch: context.batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage3KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let claim_value = match Stage3Relation::from_symbol(instance.relation).ok_or( + Stage3KernelError::UnknownRelation { + relation: instance.relation, + }, + )? { + Stage3Relation::SpartanShift => expected_spartan_shift(store, evals, local_point)?, + Stage3Relation::InstructionInput => { + expected_instruction_input(store, evals, local_point)? + } + Stage3Relation::RegistersClaimReduction => { + expected_registers(store, evals, local_point)? + } + relation @ Stage3Relation::Batched => { + return Err(Stage3KernelError::KernelNotImplemented { + abi: relation.symbol(), + }) + } + }; + expected += coefficient * claim_value; + } + Ok(expected) +} + +fn expected_spartan_shift( + store: &Stage3ValueStore, + evals: &[Stage3NamedEval], + local_point: &[F], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_outer = + EqPlusOnePolynomial::::new(store.point("stage3.input.stage1.NextPC")?.to_vec()) + .evaluate(&opening_point); + let eq_product = EqPlusOnePolynomial::::new( + store + .point("stage3.input.stage2.product_virtual.NextIsNoop")? + .to_vec(), + ) + .evaluate(&opening_point); + let gamma = store.scalar("stage3.spartan_shift.gamma")?; + let gamma2 = store.scalar("stage3.spartan_shift.gamma2")?; + let gamma3 = store.scalar("stage3.spartan_shift.gamma3")?; + let gamma4 = store.scalar("stage3.spartan_shift.gamma4")?; + let weighted_outer = eval_by_name(evals, "stage3.spartan_shift.eval.UnexpandedPC")? + + gamma * eval_by_name(evals, "stage3.spartan_shift.eval.PC")? + + gamma2 * eval_by_name(evals, "stage3.spartan_shift.eval.OpFlagVirtualInstruction")? + + gamma3 * eval_by_name(evals, "stage3.spartan_shift.eval.OpFlagIsFirstInSequence")?; + Ok(eq_outer * weighted_outer + + gamma4 + * eq_product + * (F::one() - eval_by_name(evals, "stage3.spartan_shift.eval.InstructionFlagIsNoop")?)) +} + +fn expected_instruction_input( + store: &Stage3ValueStore, + evals: &[Stage3NamedEval], + local_point: &[F], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle( + &opening_point, + store.point("stage3.input.stage2.product_virtual.LeftInstructionInput")?, + ); + let left = eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Rs1Value")? + + eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", + )? * eval_by_name(evals, "stage3.instruction_input.eval.UnexpandedPC")?; + let right = eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Rs2Value")? + + eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Imm")?; + Ok(eq_eval * (right + store.scalar("stage3.instruction_input.gamma")? * left)) +} + +fn expected_registers( + store: &Stage3ValueStore, + evals: &[Stage3NamedEval], + local_point: &[F], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle( + &opening_point, + store.point("stage3.input.stage1.RdWriteValue")?, + ); + Ok(eq_eval + * (eval_by_name(evals, "stage3.registers_claim_reduction.eval.RdWriteValue")? + + store.scalar("stage3.registers.gamma")? + * eval_by_name(evals, "stage3.registers_claim_reduction.eval.Rs1Value")? + + store.scalar("stage3.registers.gamma2")? + * eval_by_name(evals, "stage3.registers_claim_reduction.eval.Rs2Value")?)) +} + +fn eval_by_name( + evals: &[Stage3NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage3KernelError::MissingValue { symbol: name }) +} + +fn deferred_output_eval(values: &[F], eq: &[F]) -> F { + debug_assert_eq!(values.len(), eq.len()); + if values.len() >= DENSE_BIND_PAR_THRESHOLD { + values + .par_iter() + .zip(eq.par_iter()) + .map(|(&value, &weight)| value * weight) + .sum() + } else { + values + .iter() + .zip(eq) + .map(|(&value, &weight)| value * weight) + .sum() + } +} + +fn reverse_slice(values: &[F]) -> Vec { + values.iter().rev().copied().collect() +} + +fn named_eval(name: &'static str, oracle: &'static str, value: F) -> Stage3NamedEval { + Stage3NamedEval { + name, + oracle, + value, + } +} + +fn claim_relation( + program: &'static Stage3CpuProgramPlan, + claim: &Stage3SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage3Relation::from_symbol(relation) + .ok_or(Stage3KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage3KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage3KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + kernel.relation_kind() +} + +fn instance_round_offset( + program: &'static Stage3CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage3KernelError::MissingClaim { + batch: driver, + claim, + }) +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + UnivariatePoly::new(combined) +} + +fn round_poly_from_instruction_input( + factors: &[Vec], + terms: &[ProductTerm], + split_eq: &SplitEqState, + previous_claim: F, +) -> UnivariatePoly { + debug_assert_eq!(factors.len(), 8); + debug_assert_eq!(terms.len(), 4); + let gamma = terms[2].coefficient; + let (q_constant, q_quadratic) = + instruction_input_split_round_coefficients(factors, split_eq, gamma); + gruen_cubic_poly( + split_eq.current_target(), + q_constant, + q_quadratic, + previous_claim, + ) +} + +fn round_poly_from_registers( + factors: &[Vec], + terms: &[ProductTerm], + split_eq: &SplitEqState, + previous_claim: F, +) -> UnivariatePoly { + debug_assert_eq!(factors.len(), 3); + debug_assert_eq!(terms.len(), 3); + let gamma = terms[1].coefficient; + let gamma2 = terms[2].coefficient; + let q_constant = registers_split_round_constant(factors, split_eq, gamma, gamma2); + gruen_quadratic_poly(split_eq.current_target(), q_constant, previous_claim) +} + +fn instruction_input_split_round_coefficients( + factors: &[Vec], + split_eq: &SplitEqState, + gamma: F, +) -> (F, F) { + let e_in = split_eq.e_in(); + let e_out = split_eq.e_out(); + if e_in.len() > 1 { + instruction_input_low_round_coefficients(factors, e_in, e_out, gamma) + } else { + instruction_input_high_round_coefficients(factors, e_in[0], e_out, gamma) + } +} + +fn instruction_input_low_round_coefficients( + factors: &[Vec], + e_in: &[F], + e_out: &[F], + gamma: F, +) -> (F, F) { + let in_len = e_in.len(); + let in_pairs = in_len / 2; + if factors[0].len() / 2 >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = (0..e_out.len()) + .into_par_iter() + .map(|x_out| { + let mut local = [F::Accumulator::default(); 2]; + let base_pair = x_out * in_pairs; + let out_weight = e_out[x_out]; + for pair in 0..in_pairs { + accumulate_instruction_input_quadratic_pair( + &mut local, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + factors, + base_pair + pair, + gamma, + ); + } + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + (accumulators[0].reduce(), accumulators[1].reduce()) + } else { + let mut total = [F::Accumulator::default(); 2]; + for (x_out, &out_weight) in e_out.iter().enumerate() { + let base_pair = x_out * in_pairs; + for pair in 0..in_pairs { + accumulate_instruction_input_quadratic_pair( + &mut total, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + factors, + base_pair + pair, + gamma, + ); + } + } + (total[0].reduce(), total[1].reduce()) + } +} + +fn instruction_input_high_round_coefficients( + factors: &[Vec], + in_weight: F, + e_out: &[F], + gamma: F, +) -> (F, F) { + let pairs = e_out.len() / 2; + if pairs >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = (0..pairs) + .into_par_iter() + .map(|pair| { + let mut local = [F::Accumulator::default(); 2]; + accumulate_instruction_input_quadratic_pair( + &mut local, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + factors, + pair, + gamma, + ); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + (accumulators[0].reduce(), accumulators[1].reduce()) + } else { + let mut total = [F::Accumulator::default(); 2]; + for pair in 0..pairs { + accumulate_instruction_input_quadratic_pair( + &mut total, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + factors, + pair, + gamma, + ); + } + (total[0].reduce(), total[1].reduce()) + } +} + +fn accumulate_instruction_input_quadratic_pair( + accumulators: &mut [F::Accumulator; 2], + weight: F, + factors: &[Vec], + row: usize, + gamma: F, +) { + accumulate_quadratic_coefficients( + accumulators, + weight, + F::one(), + &factors[0], + &factors[1], + row, + ); + accumulate_quadratic_coefficients( + accumulators, + weight, + F::one(), + &factors[2], + &factors[3], + row, + ); + accumulate_quadratic_coefficients(accumulators, weight, gamma, &factors[4], &factors[5], row); + accumulate_quadratic_coefficients(accumulators, weight, gamma, &factors[6], &factors[7], row); +} + +fn accumulate_quadratic_coefficients( + accumulators: &mut [F::Accumulator; 2], + weight: F, + scale: F, + left: &[F], + right: &[F], + row: usize, +) { + let (left_0, left_delta) = linear_pair(left, row); + let (right_0, right_delta) = linear_pair(right, row); + let scaled_weight = weight * scale; + accumulators[0].fmadd(scaled_weight * left_0, right_0); + accumulators[1].fmadd(scaled_weight * left_delta, right_delta); +} + +fn registers_split_round_constant( + factors: &[Vec], + split_eq: &SplitEqState, + gamma: F, + gamma2: F, +) -> F { + let e_in = split_eq.e_in(); + let e_out = split_eq.e_out(); + if e_in.len() > 1 { + registers_low_round_constant(factors, e_in, e_out, gamma, gamma2) + } else { + registers_high_round_constant(factors, e_in[0], e_out, gamma, gamma2) + } +} + +fn registers_low_round_constant( + factors: &[Vec], + e_in: &[F], + e_out: &[F], + gamma: F, + gamma2: F, +) -> F { + let in_len = e_in.len(); + let in_pairs = in_len / 2; + if factors[0].len() / 2 >= DENSE_BIND_PAR_THRESHOLD { + (0..e_out.len()) + .into_par_iter() + .map(|x_out| { + let mut local = F::Accumulator::default(); + let base_pair = x_out * in_pairs; + let out_weight = e_out[x_out]; + for pair in 0..in_pairs { + accumulate_register_constant( + &mut local, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + factors, + base_pair + pair, + gamma, + gamma2, + ); + } + local + }) + .reduce(F::Accumulator::default, |mut left, right| { + left.merge(right); + left + }) + .reduce() + } else { + let mut total = F::Accumulator::default(); + for (x_out, &out_weight) in e_out.iter().enumerate() { + let base_pair = x_out * in_pairs; + for pair in 0..in_pairs { + accumulate_register_constant( + &mut total, + out_weight * (e_in[2 * pair] + e_in[2 * pair + 1]), + factors, + base_pair + pair, + gamma, + gamma2, + ); + } + } + total.reduce() + } +} + +fn registers_high_round_constant( + factors: &[Vec], + in_weight: F, + e_out: &[F], + gamma: F, + gamma2: F, +) -> F { + let pairs = e_out.len() / 2; + if pairs >= DENSE_BIND_PAR_THRESHOLD { + (0..pairs) + .into_par_iter() + .map(|pair| { + let mut local = F::Accumulator::default(); + accumulate_register_constant( + &mut local, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + factors, + pair, + gamma, + gamma2, + ); + local + }) + .reduce(F::Accumulator::default, |mut left, right| { + left.merge(right); + left + }) + .reduce() + } else { + let mut total = F::Accumulator::default(); + for pair in 0..pairs { + accumulate_register_constant( + &mut total, + in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]), + factors, + pair, + gamma, + gamma2, + ); + } + total.reduce() + } +} + +fn accumulate_register_constant( + accumulator: &mut F::Accumulator, + weight: F, + factors: &[Vec], + row: usize, + gamma: F, + gamma2: F, +) { + accumulator.fmadd(weight, factors[0][2 * row]); + accumulator.fmadd(weight * gamma, factors[1][2 * row]); + accumulator.fmadd(weight * gamma2, factors[2][2 * row]); +} + +fn gruen_cubic_poly( + target: F, + q_constant: F, + q_quadratic_coeff: F, + previous_claim: F, +) -> UnivariatePoly { + let eq_eval_1 = target; + let eq_eval_0 = F::one() - target; + let eq_delta = eq_eval_1 - eq_eval_0; + let eq_eval_2 = eq_eval_1 + eq_delta; + let eq_eval_3 = eq_eval_2 + eq_delta; + let cubic_eval_0 = eq_eval_0 * q_constant; + let cubic_eval_1 = previous_claim - cubic_eval_0; + let quadratic_eval_1 = cubic_eval_1 / eq_eval_1; + let e_times_2 = q_quadratic_coeff + q_quadratic_coeff; + let quadratic_eval_2 = quadratic_eval_1 + quadratic_eval_1 - q_constant + e_times_2; + let quadratic_eval_3 = quadratic_eval_2 + quadratic_eval_1 - q_constant + e_times_2 + e_times_2; + UnivariatePoly::from_evals(&[ + cubic_eval_0, + cubic_eval_1, + eq_eval_2 * quadratic_eval_2, + eq_eval_3 * quadratic_eval_3, + ]) +} + +fn gruen_quadratic_poly( + target: F, + q_constant: F, + previous_claim: F, +) -> UnivariatePoly { + let eq_eval_1 = target; + let eq_eval_0 = F::one() - target; + let eq_delta = eq_eval_1 - eq_eval_0; + let eq_eval_2 = eq_eval_1 + eq_delta; + let quadratic_eval_0 = eq_eval_0 * q_constant; + let quadratic_eval_1 = previous_claim - quadratic_eval_0; + let linear_eval_1 = quadratic_eval_1 / eq_eval_1; + let linear_eval_2 = linear_eval_1 + linear_eval_1 - q_constant; + UnivariatePoly::from_evals(&[ + quadratic_eval_0, + quadratic_eval_1, + eq_eval_2 * linear_eval_2, + ]) +} + +fn round_poly_from_stage3_coefficients( + half: usize, + degree: usize, + coefficients: C, +) -> UnivariatePoly +where + F: Field, + C: Fn(usize, &mut [F::Accumulator; 4]) + Sync, +{ + let accumulators = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .map(|row| { + let mut local = [F::Accumulator::default(); 4]; + coefficients(row, &mut local); + local + }) + .reduce( + || [F::Accumulator::default(); 4], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + (0..half).fold([F::Accumulator::default(); 4], |mut total, row| { + coefficients(row, &mut total); + total + }) + }; + UnivariatePoly::new( + accumulators[..=degree] + .iter() + .copied() + .map(AdditiveAccumulator::reduce) + .collect(), + ) +} + +#[inline] +fn linear_pair(factor: &[F], row: usize) -> (F, F) { + let low = factor[2 * row]; + (low, factor[2 * row + 1] - low) +} + +#[inline] +fn accumulate_linear_product( + acc: &mut [F::Accumulator; 4], + scale: F, + left_0: F, + left_delta: F, + right_0: F, + right_delta: F, +) { + acc[0].fmadd(scale * left_0, right_0); + acc[1].fmadd(scale * left_delta, right_0); + acc[1].fmadd(scale * left_0, right_delta); + acc[2].fmadd(scale * left_delta, right_delta); +} + +#[inline] +fn bind_dense_evals_reuse_serial( + values: &mut Vec, + scratch: &mut Vec, + challenge: F, +) { + let half = values.len() / 2; + scratch.resize(half, F::zero()); + for (index, output) in scratch.iter_mut().enumerate() { + let low = values[index << 1]; + let high = values[(index << 1) + 1]; + *output = low + challenge * (high - low); + } + std::mem::swap(values, scratch); + scratch.clear(); +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims( + program: &'static Stage3CpuProgramPlan, + store: &mut Stage3ValueStore, + transcript: &mut T, + evals: &[Stage3NamedEval], +) -> Result>, Stage3KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + let mut seen = seed_stage3_opening_aliases(store, program); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage3KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let value = store.scalar(claim.eval_source)?; + let duplicate = has_seen_opening(&seen, claim.claim_kind, claim.oracle, &point); + if !duplicate { + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point.clone())); + } + opening_claims.push(Stage3OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: point.clone(), + eval: value, + }); + } + } + Ok(opening_claims) +} + +fn seed_stage3_opening_aliases( + store: &Stage3ValueStore, + program: &'static Stage3CpuProgramPlan, +) -> Vec<(&'static str, &'static str, Vec)> { + program + .opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect() +} + +fn has_seen_opening( + seen: &[(&'static str, &'static str, Vec)], + claim_kind: &'static str, + oracle: &'static str, + point: &[F], +) -> bool { + seen.iter().any(|(seen_kind, seen_oracle, seen_point)| { + *seen_kind == claim_kind && *seen_oracle == oracle && seen_point.as_slice() == point + }) +} + +fn find_opening_claim<'a>( + program: &'a Stage3CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage3OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +pub fn execute_stage3_program( + program: &'static Stage3CpuProgramPlan, + mode: Stage3ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + F: Field, + E: Stage3KernelExecutor, + T: Transcript, +{ + verify_static_program_shape(program)?; + let mut artifacts = Stage3ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = find_transcript_squeeze(program, step.symbol).ok_or( + Stage3KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + execute_stage3_squeeze(squeeze, executor, transcript, &mut artifacts)?; + } + "sumcheck_driver" => { + let driver = + find_driver(program, step.symbol).ok_or(Stage3KernelError::MissingKernel { + driver: step.symbol, + kernel: step.symbol, + })?; + execute_stage3_driver(program, mode, driver, executor, transcript, &mut artifacts)?; + } + _ => { + return Err(Stage3KernelError::InvalidProof { + driver: step.symbol, + reason: "unsupported stage3 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +fn execute_stage3_squeeze( + squeeze: &'static Stage3TranscriptSqueezePlan, + executor: &mut E, + transcript: &mut T, + artifacts: &mut Stage3ExecutionArtifacts, +) -> Result<(), Stage3KernelError> +where + F: Field, + E: Stage3KernelExecutor, + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage3ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn execute_stage3_driver( + program: &'static Stage3CpuProgramPlan, + mode: Stage3ExecutionMode, + driver: &'static Stage3SumcheckDriverPlan, + executor: &mut E, + transcript: &mut T, + artifacts: &mut Stage3ExecutionArtifacts, +) -> Result<(), Stage3KernelError> +where + F: Field, + E: Stage3KernelExecutor, + T: Transcript, +{ + let kernel_symbol = driver.kernel.ok_or(Stage3KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage3KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + })?; + let batch = find_batch(program, driver.batch).ok_or(Stage3KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage3KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage3ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage3ExecutionMode::Verifier => executor.verify_sumcheck(context, transcript)?, + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_static_program_shape( + program: &'static Stage3CpuProgramPlan, +) -> Result<(), Stage3KernelError> { + for expr in program.field_exprs { + verify_count(expr.symbol, expr.operand_names.len(), expr.operands.len())?; + } + for batch in program.batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + for batch in program.opening_batches { + verify_count(batch.symbol, batch.count, batch.ordered_claims.len())?; + verify_count(batch.symbol, batch.count, batch.claim_operands.len())?; + } + for kernel in program.kernels { + let relation = kernel.relation_kind()?; + let abi = kernel.abi_kind()?; + if relation + .symbol() + .replace("jolt.stage3.", "jolt_stage3_") + .replace('.', "_") + != abi.name() + { + return Err(Stage3KernelError::InvalidProof { + driver: kernel.symbol, + reason: "kernel relation and ABI mismatch", + }); + } + } + Ok(()) +} + +fn verify_count( + artifact: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage3KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage3KernelError::PlanCountMismatch { + artifact, + expected, + actual, + }) + } +} + +fn find_kernel<'a>( + program: &'a Stage3CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage3KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch<'a>( + program: &'a Stage3CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage3SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +fn find_driver<'a>( + program: &'a Stage3CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage3SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_transcript_squeeze<'a>( + program: &'a Stage3CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage3TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|squeeze| squeeze.symbol == symbol) +} + +#[cfg(test)] +#[expect(clippy::expect_used, reason = "stage3 kernel tests fail fast")] +mod tests { + use super::*; + use jolt_field::Fr; + use jolt_transcript::Blake2bTranscript; + + #[test] + fn stage3_relation_and_abi_registry_is_complete() { + let relations = [ + Stage3Relation::SpartanShift, + Stage3Relation::InstructionInput, + Stage3Relation::RegistersClaimReduction, + Stage3Relation::Batched, + ]; + for relation in relations { + assert_eq!( + Stage3Relation::from_symbol(relation.symbol()), + Some(relation) + ); + } + + let abis = [ + Stage3KernelAbi::SpartanShift, + Stage3KernelAbi::InstructionInput, + Stage3KernelAbi::RegistersClaimReduction, + Stage3KernelAbi::Batched, + ]; + for abi in abis { + assert_eq!(Stage3KernelAbi::from_name(abi.name()), Some(abi)); + } + } + + #[test] + fn stage3_batched_kernel_proves_and_verifies_synthetic_trace() { + let program = synthetic_stage3_program(); + let cycles = synthetic_cycles(); + let opening_inputs = synthetic_opening_inputs(&cycles); + let prover_inputs = Stage3ProverInputs::new(&opening_inputs).with_cycles(&cycles); + let mut prover = Stage3ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage3_test"); + + let artifacts = execute_stage3_program( + program, + Stage3ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage3 prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].proof.round_polynomials.len(), 2); + let proof = Stage3Proof::from(artifacts); + let mut verifier = Stage3VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage3_test"); + let verified = execute_stage3_program( + program, + Stage3ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage3 verifier accepts prover proof"); + + assert_eq!(verified.sumchecks.len(), 1); + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + } + + #[test] + fn stage3_batched_kernel_rejects_tampered_eval() { + let program = synthetic_stage3_program(); + let cycles = synthetic_cycles(); + let opening_inputs = synthetic_opening_inputs(&cycles); + let mut prover = Stage3ProverKernelExecutor::new( + Stage3ProverInputs::new(&opening_inputs).with_cycles(&cycles), + ); + let mut prover_transcript = Blake2bTranscript::::new(b"stage3_test"); + let mut proof = Stage3Proof::from( + execute_stage3_program( + program, + Stage3ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage3 prover succeeds"), + ); + proof.sumchecks[0].evals[0].value += Fr::from_u64(1); + + let mut verifier = Stage3VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage3_test"); + let error = execute_stage3_program( + program, + Stage3ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered proof is rejected"); + + assert!(matches!(error, Stage3KernelError::InvalidProof { .. })); + } + + fn synthetic_stage3_program() -> &'static Stage3CpuProgramPlan { + let exprs = leak_slice(vec![ + field_expr( + "stage3.spartan_shift.gamma2", + "field.pow:2", + vec!["stage3.spartan_shift.gamma"], + ), + field_expr( + "stage3.spartan_shift.gamma3", + "field.mul", + vec!["stage3.spartan_shift.gamma2", "stage3.spartan_shift.gamma"], + ), + field_expr( + "stage3.spartan_shift.gamma4", + "field.mul", + vec!["stage3.spartan_shift.gamma2", "stage3.spartan_shift.gamma2"], + ), + field_expr( + "stage3.spartan_shift.term.NextPC", + "field.mul", + vec!["stage3.spartan_shift.gamma", "stage3.input.stage1.NextPC"], + ), + field_expr( + "stage3.spartan_shift.term.NextIsVirtual", + "field.mul", + vec![ + "stage3.spartan_shift.gamma2", + "stage3.input.stage1.NextIsVirtual", + ], + ), + field_expr( + "stage3.spartan_shift.term.NextIsFirstInSequence", + "field.mul", + vec![ + "stage3.spartan_shift.gamma3", + "stage3.input.stage1.NextIsFirstInSequence", + ], + ), + field_expr( + "stage3.spartan_shift.one_minus.NextIsNoop", + "field.sub", + vec![ + "stage3.field.one", + "stage3.input.stage2.product_virtual.NextIsNoop", + ], + ), + field_expr( + "stage3.spartan_shift.term.NextIsNoop", + "field.mul", + vec![ + "stage3.spartan_shift.gamma4", + "stage3.spartan_shift.one_minus.NextIsNoop", + ], + ), + field_expr( + "stage3.spartan_shift.partial.NextUnexpandedPCNextPC", + "field.add", + vec![ + "stage3.input.stage1.NextUnexpandedPC", + "stage3.spartan_shift.term.NextPC", + ], + ), + field_expr( + "stage3.spartan_shift.partial.NextIsVirtual", + "field.add", + vec![ + "stage3.spartan_shift.partial.NextUnexpandedPCNextPC", + "stage3.spartan_shift.term.NextIsVirtual", + ], + ), + field_expr( + "stage3.spartan_shift.partial.NextIsFirstInSequence", + "field.add", + vec![ + "stage3.spartan_shift.partial.NextIsVirtual", + "stage3.spartan_shift.term.NextIsFirstInSequence", + ], + ), + field_expr( + "stage3.spartan_shift.claim_expr", + "field.add", + vec![ + "stage3.spartan_shift.partial.NextIsFirstInSequence", + "stage3.spartan_shift.term.NextIsNoop", + ], + ), + field_expr( + "stage3.instruction_input.term.LeftInstructionInput", + "field.mul", + vec![ + "stage3.instruction_input.gamma", + "stage3.input.stage2.product_virtual.LeftInstructionInput", + ], + ), + field_expr( + "stage3.instruction_input.claim_expr", + "field.add", + vec![ + "stage3.input.stage2.product_virtual.RightInstructionInput", + "stage3.instruction_input.term.LeftInstructionInput", + ], + ), + field_expr( + "stage3.registers.gamma2", + "field.pow:2", + vec!["stage3.registers.gamma"], + ), + field_expr( + "stage3.registers.term.Rs1Value", + "field.mul", + vec!["stage3.registers.gamma", "stage3.input.stage1.Rs1Value"], + ), + field_expr( + "stage3.registers.term.Rs2Value", + "field.mul", + vec!["stage3.registers.gamma2", "stage3.input.stage1.Rs2Value"], + ), + field_expr( + "stage3.registers.partial.RdWriteValueRs1Value", + "field.add", + vec![ + "stage3.input.stage1.RdWriteValue", + "stage3.registers.term.Rs1Value", + ], + ), + field_expr( + "stage3.registers.claim_expr", + "field.add", + vec![ + "stage3.registers.partial.RdWriteValueRs1Value", + "stage3.registers.term.Rs2Value", + ], + ), + ]); + + Box::leak(Box::new(Stage3CpuProgramPlan { + params: Stage3Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + steps: leak_slice(vec![ + Stage3ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage3.spartan_shift.gamma", + }, + Stage3ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage3.instruction_input.gamma", + }, + Stage3ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage3.registers.gamma", + }, + Stage3ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage3.sumcheck", + }, + ]), + transcript_squeezes: leak_slice(vec![ + Stage3TranscriptSqueezePlan { + symbol: "stage3.spartan_shift.gamma", + label: "spartan_shift_gamma", + kind: "challenge_scalar", + count: 1, + }, + Stage3TranscriptSqueezePlan { + symbol: "stage3.instruction_input.gamma", + label: "instruction_input_gamma", + kind: "challenge_scalar", + count: 1, + }, + Stage3TranscriptSqueezePlan { + symbol: "stage3.registers.gamma", + label: "registers_gamma", + kind: "challenge_scalar", + count: 1, + }, + ]), + opening_inputs: leak_slice(stage3_opening_input_plans()), + field_constants: leak_slice(vec![Stage3FieldConstantPlan { + symbol: "stage3.field.one", + field: "bn254_fr", + value: 1, + }]), + field_exprs: exprs, + kernels: leak_slice(vec![ + kernel( + "jolt.cpu.stage3.spartan_shift", + "jolt.stage3.spartan_shift", + "jolt_stage3_spartan_shift", + ), + kernel( + "jolt.cpu.stage3.instruction_input", + "jolt.stage3.instruction_input", + "jolt_stage3_instruction_input", + ), + kernel( + "jolt.cpu.stage3.registers_claim_reduction", + "jolt.stage3.registers_claim_reduction", + "jolt_stage3_registers_claim_reduction", + ), + kernel( + "jolt.cpu.stage3.batched", + "jolt.stage3.batched", + "jolt_stage3_batched", + ), + ]), + claims: leak_slice(vec![ + claim( + "stage3.spartan_shift.input", + "jolt.cpu.stage3.spartan_shift", + "stage3.spartan_shift.claim_expr", + 2, + vec![ + "stage3.input.stage1.NextUnexpandedPC", + "stage3.input.stage1.NextPC", + "stage3.input.stage1.NextIsVirtual", + "stage3.input.stage1.NextIsFirstInSequence", + "stage3.input.stage2.product_virtual.NextIsNoop", + ], + ), + claim( + "stage3.instruction_input.input", + "jolt.cpu.stage3.instruction_input", + "stage3.instruction_input.claim_expr", + 3, + vec![ + "stage3.input.stage2.product_virtual.RightInstructionInput", + "stage3.input.stage2.product_virtual.LeftInstructionInput", + ], + ), + claim( + "stage3.registers_claim_reduction.input", + "jolt.cpu.stage3.registers_claim_reduction", + "stage3.registers.claim_expr", + 2, + vec![ + "stage3.input.stage1.RdWriteValue", + "stage3.input.stage1.Rs1Value", + "stage3.input.stage1.Rs2Value", + ], + ), + ]), + batches: leak_slice(vec![Stage3SumcheckBatchPlan { + symbol: "stage3.batch", + stage: "stage3", + proof_slot: "stage3.sumcheck", + policy: "jolt_core_stage3_aligned", + count: 3, + ordered_claims: leak_slice(vec![ + "stage3.spartan_shift.input", + "stage3.instruction_input.input", + "stage3.registers_claim_reduction.input", + ]), + claim_operands: leak_slice(vec![ + "stage3.spartan_shift.input", + "stage3.instruction_input.input", + "stage3.registers_claim_reduction.input", + ]), + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: leak_slice(vec![2]), + }]), + drivers: leak_slice(vec![Stage3SumcheckDriverPlan { + symbol: "stage3.sumcheck", + stage: "stage3", + proof_slot: "stage3.sumcheck", + kernel: Some("jolt.cpu.stage3.batched"), + relation: None, + batch: "stage3.batch", + policy: "jolt_core_stage3_aligned", + round_schedule: leak_slice(vec![2]), + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 3, + }]), + instance_results: leak_slice(vec![ + instance( + "stage3.spartan_shift.instance", + "stage3.spartan_shift.input", + "jolt.stage3.spartan_shift", + 0, + 2, + ), + instance( + "stage3.instruction_input.instance", + "stage3.instruction_input.input", + "jolt.stage3.instruction_input", + 1, + 3, + ), + instance( + "stage3.registers_claim_reduction.instance", + "stage3.registers_claim_reduction.input", + "jolt.stage3.registers_claim_reduction", + 2, + 2, + ), + ]), + evals: leak_slice(stage3_eval_plans()), + point_slices: &[], + point_concats: &[], + opening_claims: leak_slice(stage3_opening_claim_plans()), + opening_equalities: leak_slice(vec![ + Stage3OpeningClaimEqualityPlan { + symbol: "stage3.instruction_input.left_claim_consistency", + mode: "point_and_eval", + lhs: "stage3.input.stage2.product_virtual.LeftInstructionInput", + rhs: "stage3.input.stage2.instruction_lookup.LeftInstructionInput", + }, + Stage3OpeningClaimEqualityPlan { + symbol: "stage3.instruction_input.right_claim_consistency", + mode: "point_and_eval", + lhs: "stage3.input.stage2.product_virtual.RightInstructionInput", + rhs: "stage3.input.stage2.instruction_lookup.RightInstructionInput", + }, + ]), + opening_batches: leak_slice(vec![Stage3OpeningBatchPlan { + symbol: "stage3.openings", + stage: "stage3", + proof_slot: "stage3.openings", + policy: "jolt_stage3_output_order", + count: 16, + ordered_claims: leak_slice( + stage3_opening_claim_plans() + .iter() + .map(|claim| claim.symbol) + .collect(), + ), + claim_operands: leak_slice( + stage3_opening_claim_plans() + .iter() + .map(|claim| claim.symbol) + .collect(), + ), + }]), + })) + } + + fn synthetic_cycles() -> [Stage3Cycle; 4] { + [ + Stage3Cycle { + unexpanded_pc: 10, + pc: 0, + is_virtual: false, + is_first_in_sequence: false, + is_noop: false, + left_operand_is_rs1: true, + rs1_value: 3, + left_operand_is_pc: false, + right_operand_is_rs2: true, + rs2_value: 5, + right_operand_is_imm: false, + imm: 0, + rd_write_value: 8, + }, + Stage3Cycle { + unexpanded_pc: 14, + pc: 1, + is_virtual: true, + is_first_in_sequence: true, + is_noop: false, + left_operand_is_rs1: false, + rs1_value: 0, + left_operand_is_pc: true, + right_operand_is_rs2: false, + rs2_value: 0, + right_operand_is_imm: true, + imm: -7, + rd_write_value: 21, + }, + Stage3Cycle { + unexpanded_pc: 18, + pc: 2, + is_virtual: false, + is_first_in_sequence: false, + is_noop: true, + left_operand_is_rs1: false, + rs1_value: 0, + left_operand_is_pc: false, + right_operand_is_rs2: false, + rs2_value: 0, + right_operand_is_imm: false, + imm: 0, + rd_write_value: 0, + }, + Stage3Cycle { + unexpanded_pc: 22, + pc: 3, + is_virtual: true, + is_first_in_sequence: false, + is_noop: false, + left_operand_is_rs1: true, + rs1_value: 9, + left_operand_is_pc: false, + right_operand_is_rs2: false, + rs2_value: 0, + right_operand_is_imm: true, + imm: 11, + rd_write_value: 20, + }, + ] + } + + fn synthetic_opening_inputs(cycles: &[Stage3Cycle]) -> Vec> { + let r_outer = vec![Fr::from_u64(2), Fr::from_u64(3)]; + let r_product = vec![Fr::from_u64(5), Fr::from_u64(7)]; + let r_instruction = vec![Fr::from_u64(11), Fr::from_u64(13)]; + let r_registers = vec![Fr::from_u64(17), Fr::from_u64(19)]; + vec![ + opening( + "stage3.input.stage1.NextUnexpandedPC", + &r_outer, + eq_plus_one_eval(cycles, &r_outer, |cycle| Fr::from_u64(cycle.unexpanded_pc)), + ), + opening( + "stage3.input.stage1.NextPC", + &r_outer, + eq_plus_one_eval(cycles, &r_outer, |cycle| Fr::from_u64(cycle.pc)), + ), + opening( + "stage3.input.stage1.NextIsVirtual", + &r_outer, + eq_plus_one_eval(cycles, &r_outer, |cycle| Fr::from_bool(cycle.is_virtual)), + ), + opening( + "stage3.input.stage1.NextIsFirstInSequence", + &r_outer, + eq_plus_one_eval(cycles, &r_outer, |cycle| { + Fr::from_bool(cycle.is_first_in_sequence) + }), + ), + opening( + "stage3.input.stage2.product_virtual.NextIsNoop", + &r_product, + eq_plus_one_eval(cycles, &r_product, |cycle| Fr::from_bool(cycle.is_noop)) + + r_product.iter().copied().product::(), + ), + opening( + "stage3.input.stage2.product_virtual.LeftInstructionInput", + &r_instruction, + mle_eval(cycles, &r_instruction, left_instruction_input), + ), + opening( + "stage3.input.stage2.product_virtual.RightInstructionInput", + &r_instruction, + mle_eval(cycles, &r_instruction, right_instruction_input), + ), + opening( + "stage3.input.stage2.instruction_lookup.LeftInstructionInput", + &r_instruction, + mle_eval(cycles, &r_instruction, left_instruction_input), + ), + opening( + "stage3.input.stage2.instruction_lookup.RightInstructionInput", + &r_instruction, + mle_eval(cycles, &r_instruction, right_instruction_input), + ), + opening( + "stage3.input.stage1.RdWriteValue", + &r_registers, + mle_eval(cycles, &r_registers, |cycle| { + Fr::from_u64(cycle.rd_write_value) + }), + ), + opening( + "stage3.input.stage1.Rs1Value", + &r_registers, + mle_eval(cycles, &r_registers, |cycle| Fr::from_u64(cycle.rs1_value)), + ), + opening( + "stage3.input.stage1.Rs2Value", + &r_registers, + mle_eval(cycles, &r_registers, |cycle| Fr::from_u64(cycle.rs2_value)), + ), + ] + } + + fn field_expr( + symbol: &'static str, + formula: &'static str, + operands: Vec<&'static str>, + ) -> Stage3FieldExprPlan { + let operands = leak_slice(operands); + Stage3FieldExprPlan { + symbol, + kind: "op", + formula, + operand_names: operands, + operands, + } + } + + fn kernel(symbol: &'static str, relation: &'static str, abi: &'static str) -> Stage3KernelPlan { + Stage3KernelPlan { + symbol, + relation, + kind: "sumcheck", + backend: "cpu", + abi, + } + } + + fn claim( + symbol: &'static str, + kernel: &'static str, + claim_value: &'static str, + degree: usize, + input_openings: Vec<&'static str>, + ) -> Stage3SumcheckClaimPlan { + Stage3SumcheckClaimPlan { + symbol, + stage: "stage3", + domain: "jolt.trace_domain", + num_rounds: 2, + degree, + claim: symbol, + kernel: Some(kernel), + relation: None, + claim_value, + input_openings: leak_slice(input_openings), + } + } + + fn instance( + symbol: &'static str, + claim: &'static str, + relation: &'static str, + index: usize, + degree: usize, + ) -> Stage3SumcheckInstanceResultPlan { + Stage3SumcheckInstanceResultPlan { + symbol, + source: "stage3.sumcheck", + claim, + relation, + index, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree, + } + } + + fn opening(symbol: &'static str, point: &[Fr], eval: Fr) -> Stage3OpeningInputValue { + Stage3OpeningInputValue { + symbol, + point: point.to_vec(), + eval, + } + } + + fn mle_eval(cycles: &[Stage3Cycle], point: &[Fr], f: impl Fn(&Stage3Cycle) -> Fr) -> Fr { + EqPolynomial::::evals(point, None) + .iter() + .zip(cycles) + .map(|(&weight, cycle)| weight * f(cycle)) + .sum() + } + + fn eq_plus_one_eval( + cycles: &[Stage3Cycle], + point: &[Fr], + f: impl Fn(&Stage3Cycle) -> Fr, + ) -> Fr { + EqPlusOnePolynomial::::evals(point, None) + .1 + .iter() + .zip(cycles) + .map(|(&weight, cycle)| weight * f(cycle)) + .sum() + } + + fn left_instruction_input(cycle: &Stage3Cycle) -> Fr { + Fr::from_bool(cycle.left_operand_is_rs1) * Fr::from_u64(cycle.rs1_value) + + Fr::from_bool(cycle.left_operand_is_pc) * Fr::from_u64(cycle.unexpanded_pc) + } + + fn right_instruction_input(cycle: &Stage3Cycle) -> Fr { + Fr::from_bool(cycle.right_operand_is_rs2) * Fr::from_u64(cycle.rs2_value) + + Fr::from_bool(cycle.right_operand_is_imm) * Fr::from_i128(cycle.imm) + } + + fn stage3_opening_input_plans() -> Vec { + vec![ + opening_input_plan( + "stage3.input.stage1.NextUnexpandedPC", + "stage1", + "NextUnexpandedPC", + ), + opening_input_plan("stage3.input.stage1.NextPC", "stage1", "NextPC"), + opening_input_plan( + "stage3.input.stage1.NextIsVirtual", + "stage1", + "NextIsVirtual", + ), + opening_input_plan( + "stage3.input.stage1.NextIsFirstInSequence", + "stage1", + "NextIsFirstInSequence", + ), + opening_input_plan( + "stage3.input.stage2.product_virtual.NextIsNoop", + "stage2", + "NextIsNoop", + ), + opening_input_plan( + "stage3.input.stage2.product_virtual.LeftInstructionInput", + "stage2", + "LeftInstructionInput", + ), + opening_input_plan( + "stage3.input.stage2.product_virtual.RightInstructionInput", + "stage2", + "RightInstructionInput", + ), + opening_input_plan( + "stage3.input.stage2.instruction_lookup.LeftInstructionInput", + "stage2", + "LeftInstructionInput", + ), + opening_input_plan( + "stage3.input.stage2.instruction_lookup.RightInstructionInput", + "stage2", + "RightInstructionInput", + ), + opening_input_plan("stage3.input.stage1.RdWriteValue", "stage1", "RdWriteValue"), + opening_input_plan("stage3.input.stage1.Rs1Value", "stage1", "Rs1Value"), + opening_input_plan("stage3.input.stage1.Rs2Value", "stage1", "Rs2Value"), + ] + } + + fn opening_input_plan( + symbol: &'static str, + source_stage: &'static str, + oracle: &'static str, + ) -> Stage3OpeningInputPlan { + Stage3OpeningInputPlan { + symbol, + source_stage, + source_claim: symbol, + oracle, + domain: "jolt.trace_domain", + point_arity: 2, + claim_kind: "virtual", + } + } + + fn stage3_eval_plans() -> Vec { + vec![ + eval("stage3.spartan_shift.eval.UnexpandedPC", "UnexpandedPC", 0), + eval("stage3.spartan_shift.eval.PC", "PC", 1), + eval( + "stage3.spartan_shift.eval.OpFlagVirtualInstruction", + "OpFlagVirtualInstruction", + 2, + ), + eval( + "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", + "OpFlagIsFirstInSequence", + 3, + ), + eval( + "stage3.spartan_shift.eval.InstructionFlagIsNoop", + "InstructionFlagIsNoop", + 4, + ), + eval( + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", + "InstructionFlagLeftOperandIsRs1Value", + 5, + ), + eval("stage3.instruction_input.eval.Rs1Value", "Rs1Value", 6), + eval( + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", + "InstructionFlagLeftOperandIsPC", + 7, + ), + eval( + "stage3.instruction_input.eval.UnexpandedPC", + "UnexpandedPC", + 8, + ), + eval( + "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", + "InstructionFlagRightOperandIsRs2Value", + 9, + ), + eval("stage3.instruction_input.eval.Rs2Value", "Rs2Value", 10), + eval( + "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", + "InstructionFlagRightOperandIsImm", + 11, + ), + eval("stage3.instruction_input.eval.Imm", "Imm", 12), + eval( + "stage3.registers_claim_reduction.eval.RdWriteValue", + "RdWriteValue", + 13, + ), + eval( + "stage3.registers_claim_reduction.eval.Rs1Value", + "Rs1Value", + 14, + ), + eval( + "stage3.registers_claim_reduction.eval.Rs2Value", + "Rs2Value", + 15, + ), + ] + } + + fn eval(symbol: &'static str, oracle: &'static str, index: usize) -> Stage3SumcheckEvalPlan { + Stage3SumcheckEvalPlan { + symbol, + source: "stage3.sumcheck", + name: symbol, + index, + oracle, + } + } + + fn stage3_opening_claim_plans() -> Vec { + stage3_eval_plans() + .into_iter() + .map(|eval| Stage3OpeningClaimPlan { + symbol: eval.symbol.replace(".eval.", ".opening.").leak(), + oracle: eval.oracle, + domain: "jolt.trace_domain", + point_arity: 2, + claim_kind: "virtual", + point_source: match eval.symbol { + name if name.starts_with("stage3.spartan_shift.") => { + "stage3.spartan_shift.instance" + } + name if name.starts_with("stage3.instruction_input.") => { + "stage3.instruction_input.instance" + } + _ => "stage3.registers_claim_reduction.instance", + }, + eval_source: eval.symbol, + }) + .collect() + } + + fn leak_slice(values: Vec) -> &'static [T] { + Box::leak(values.into_boxed_slice()) + } +} diff --git a/crates/jolt-kernels/src/stage4.rs b/crates/jolt-kernels/src/stage4.rs new file mode 100644 index 0000000000..04528a56b3 --- /dev/null +++ b/crates/jolt-kernels/src/stage4.rs @@ -0,0 +1,4667 @@ +//! Stage 4 coarse-kernel ABI used by Bolt-generated Jolt prover code. + +#![expect( + clippy::large_enum_variant, + reason = "kernel states stay inline to avoid boxing hot prover state" +)] +#![expect( + clippy::too_many_arguments, + reason = "kernel constructors mirror generated staged protocol inputs" +)] + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; +use std::mem::MaybeUninit; + +use crate::dense::{bind_dense_evals_reuse, DENSE_BIND_PAR_THRESHOLD}; +use crate::split_eq::SplitEqState; +use crate::stage2::Stage2RamAccess; +use jolt_field::{AdditiveAccumulator, Field, RingAccumulator}; +use jolt_poly::{EqPolynomial, UnivariatePoly}; +use jolt_sumcheck::SumcheckProof; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use jolt_witness::{stage4_5_sparse_trace_witness, Stage45SparseTraceWitness}; +use rayon::prelude::*; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage4ExecutionMode { + Prover, + Verifier, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage4Relation { + RegistersReadWrite, + RamValCheck, + Batched, +} + +impl Stage4Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage4.registers_read_write" => Some(Self::RegistersReadWrite), + "jolt.stage4.ram_val_check" => Some(Self::RamValCheck), + "jolt.stage4.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::RegistersReadWrite => "jolt.stage4.registers_read_write", + Self::RamValCheck => "jolt.stage4.ram_val_check", + Self::Batched => "jolt.stage4.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage4KernelAbi { + RegistersReadWrite, + RamValCheck, + Batched, +} + +impl Stage4KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage4_registers_read_write" => Some(Self::RegistersReadWrite), + "jolt_stage4_ram_val_check" => Some(Self::RamValCheck), + "jolt_stage4_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::RegistersReadWrite => "jolt_stage4_registers_read_write", + Self::RamValCheck => "jolt_stage4_ram_val_check", + Self::Batched => "jolt_stage4_batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +impl Stage4KernelPlan { + pub fn relation_kind(&self) -> Result { + Stage4Relation::from_symbol(self.relation).ok_or(Stage4KernelError::UnknownRelation { + relation: self.relation, + }) + } + + pub fn abi_kind(&self) -> Result { + Stage4KernelAbi::from_name(self.abi) + .ok_or(Stage4KernelError::UnknownKernelAbi { abi: self.abi }) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4TranscriptSqueezePlan { + pub symbol: &'static str, + pub label: &'static str, + pub kind: &'static str, + pub count: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4TranscriptAbsorbBytesPlan { + pub symbol: &'static str, + pub label: &'static str, + pub payload: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4ProgramStepPlan { + pub kind: &'static str, + pub symbol: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4FieldConstantPlan { + pub symbol: &'static str, + pub field: &'static str, + pub value: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4FieldExprPlan { + pub symbol: &'static str, + pub kind: &'static str, + pub formula: &'static str, + pub operand_names: &'static [&'static str], + pub operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4SumcheckClaimPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub domain: &'static str, + pub num_rounds: usize, + pub degree: usize, + pub claim: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub claim_value: &'static str, + pub input_openings: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4SumcheckBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], + pub claim_label: &'static str, + pub round_label: &'static str, + pub round_schedule: &'static [usize], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4SumcheckDriverPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub batch: &'static str, + pub policy: &'static str, + pub round_schedule: &'static [usize], + pub claim_label: &'static str, + pub round_label: &'static str, + pub num_rounds: usize, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4SumcheckInstanceResultPlan { + pub symbol: &'static str, + pub source: &'static str, + pub claim: &'static str, + pub relation: &'static str, + pub index: usize, + pub point_arity: usize, + pub num_rounds: usize, + pub round_offset: usize, + pub point_order: &'static str, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4SumcheckEvalPlan { + pub symbol: &'static str, + pub source: &'static str, + pub name: &'static str, + pub index: usize, + pub oracle: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4PointSlicePlan { + pub symbol: &'static str, + pub source: &'static str, + pub offset: usize, + pub length: usize, + pub input: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4PointConcatPlan { + pub symbol: &'static str, + pub layout: &'static str, + pub arity: usize, + pub inputs: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, + pub point_source: &'static str, + pub eval_source: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4OpeningClaimEqualityPlan { + pub symbol: &'static str, + pub mode: &'static str, + pub lhs: &'static str, + pub rhs: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4OpeningBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], + pub claim_operands: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4CpuProgramPlan { + pub role: &'static str, + pub params: Stage4Params, + pub steps: &'static [Stage4ProgramStepPlan], + pub transcript_squeezes: &'static [Stage4TranscriptSqueezePlan], + pub transcript_absorb_bytes: &'static [Stage4TranscriptAbsorbBytesPlan], + pub opening_inputs: &'static [Stage4OpeningInputPlan], + pub field_constants: &'static [Stage4FieldConstantPlan], + pub field_exprs: &'static [Stage4FieldExprPlan], + pub kernels: &'static [Stage4KernelPlan], + pub claims: &'static [Stage4SumcheckClaimPlan], + pub batches: &'static [Stage4SumcheckBatchPlan], + pub drivers: &'static [Stage4SumcheckDriverPlan], + pub instance_results: &'static [Stage4SumcheckInstanceResultPlan], + pub evals: &'static [Stage4SumcheckEvalPlan], + pub point_slices: &'static [Stage4PointSlicePlan], + pub point_concats: &'static [Stage4PointConcatPlan], + pub opening_claims: &'static [Stage4OpeningClaimPlan], + pub opening_equalities: &'static [Stage4OpeningClaimEqualityPlan], + pub opening_batches: &'static [Stage4OpeningBatchPlan], +} + +impl Stage4CpuProgramPlan { + pub fn claim(&self, symbol: &str) -> Option<&Stage4SumcheckClaimPlan> { + self.claims.iter().find(|claim| claim.symbol == symbol) + } + + pub fn instance_results_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.instance_results + .iter() + .filter(move |instance| instance.source == driver) + } + + pub fn evals_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.evals.iter().filter(move |eval| eval.source == driver) + } +} + +#[derive(Clone, Debug)] +pub struct Stage4NamedEval { + pub name: &'static str, + pub oracle: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage4SumcheckOutput { + pub driver: &'static str, + pub point: Vec, + pub evals: Vec>, + pub opening_claims: Vec>, + pub proof: SumcheckProof, +} + +#[derive(Clone, Debug)] +pub struct Stage4ChallengeVector { + pub symbol: &'static str, + pub values: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stage4OpeningClaimValue { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub claim_kind: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Debug)] +pub struct Stage4ExecutionArtifacts { + pub challenge_vectors: Vec>, + pub sumchecks: Vec>, + pub opening_claims: Vec>, + pub opening_batches: Vec<&'static Stage4OpeningBatchPlan>, +} + +impl Default for Stage4ExecutionArtifacts { + fn default() -> Self { + Self { + challenge_vectors: Vec::new(), + sumchecks: Vec::new(), + opening_claims: Vec::new(), + opening_batches: Vec::new(), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage4Proof { + pub sumchecks: Vec>, +} + +impl From> for Stage4Proof { + fn from(artifacts: Stage4ExecutionArtifacts) -> Self { + Self { + sumchecks: artifacts.sumchecks, + } + } +} + +#[derive(Clone, Debug)] +pub struct Stage4OpeningInputValue { + pub symbol: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Copy)] +pub struct Stage4RegistersWitness<'a, F: Field> { + pub register_count: usize, + pub trace_len: usize, + pub registers_val: &'a [F], + pub rs1_ra: &'a [F], + pub rs2_ra: &'a [F], + pub rd_wa: &'a [F], + pub accesses: Option<&'a [Stage4RegisterAccess]>, + pub rd_inc: &'a [F], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4RegisterRead { + pub address: usize, + pub value: u64, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage4RegisterWrite { + pub address: usize, + pub pre_value: u64, + pub post_value: u64, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct Stage4RegisterAccess { + pub rs1: Option, + pub rs2: Option, + pub rd: Option, +} + +pub fn stage4_5_sparse_trace_witness_from_accesses( + register_accesses: &[Stage4RegisterAccess], + ram_accesses: &[Stage2RamAccess], +) -> Stage45SparseTraceWitness { + stage4_5_sparse_trace_witness( + register_accesses.iter().map(|access| { + access + .rd + .map(|rd| (rd.address, rd.pre_value, rd.post_value)) + }), + ram_accesses.iter().map(|access| { + ( + access.remapped_address, + access.read_value, + access.write_value, + ) + }), + ) +} + +#[derive(Clone, Copy)] +pub struct Stage4RamWitness<'a, F: Field> { + pub ram_k: usize, + pub trace_len: usize, + pub ram_ra: &'a [F], + pub write_address_indices: Option<&'a [Option]>, + pub ram_inc: &'a [F], +} + +#[derive(Clone, Copy)] +pub struct Stage4ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage4OpeningInputValue], + pub registers: Option>, + pub ram: Option>, +} + +impl<'a, F: Field> Stage4ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage4OpeningInputValue]) -> Self { + Self { + opening_inputs, + registers: None, + ram: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + registers: None, + ram: None, + } + } + + pub fn with_registers(mut self, registers: Stage4RegistersWitness<'a, F>) -> Self { + self.registers = Some(registers); + self + } + + pub fn with_ram(mut self, ram: Stage4RamWitness<'a, F>) -> Self { + self.ram = Some(ram); + self + } + + pub fn with_sparse_trace_witness( + self, + register_count: usize, + trace_len: usize, + ram_k: usize, + register_accesses: &'a [Stage4RegisterAccess], + rd_inc: &'a [F], + write_address_indices: &'a [Option], + ram_inc: &'a [F], + ) -> Self { + self.with_registers(Stage4RegistersWitness { + register_count, + trace_len, + registers_val: &[], + rs1_ra: &[], + rs2_ra: &[], + rd_wa: &[], + accesses: Some(register_accesses), + rd_inc, + }) + .with_ram(Stage4RamWitness { + ram_k, + trace_len, + ram_ra: &[], + write_address_indices: Some(write_address_indices), + ram_inc, + }) + } + + pub fn with_stage45_sparse_trace_witness( + self, + register_count: usize, + trace_len: usize, + ram_k: usize, + register_accesses: &'a [Stage4RegisterAccess], + witness: &'a Stage45SparseTraceWitness, + ) -> Self { + self.with_sparse_trace_witness( + register_count, + trace_len, + ram_k, + register_accesses, + &witness.rd_inc, + &witness.ram_addresses, + &witness.ram_inc, + ) + } +} + +#[derive(Clone, Debug)] +pub struct Stage4ScalarValue { + pub symbol: &'static str, + pub value: F, +} + +#[derive(Clone, Debug)] +pub struct Stage4PointValue { + pub symbol: &'static str, + pub point: Vec, +} + +#[derive(Clone, Debug, Default)] +pub struct Stage4ValueStore { + scalars: Vec>, + points: Vec>, +} + +impl Stage4ValueStore { + pub fn new() -> Self { + Self::default() + } + + pub fn with_opening_inputs(inputs: &[Stage4OpeningInputValue]) -> Self { + let mut store = Self::new(); + store.insert_opening_inputs(inputs); + store + } + + pub fn insert_opening_inputs(&mut self, inputs: &[Stage4OpeningInputValue]) { + for input in inputs { + self.insert_scalar(input.symbol, input.eval); + self.insert_point(input.symbol, input.point.clone()); + } + } + + pub fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some(existing) = self + .scalars + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.value = value; + } else { + self.scalars.push(Stage4ScalarValue { symbol, value }); + } + } + + pub fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some(existing) = self + .points + .iter_mut() + .find(|existing| existing.symbol == symbol) + { + existing.point = point; + } else { + self.points.push(Stage4PointValue { symbol, point }); + } + } + + pub fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.value) + } + + pub fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage4KernelError::MissingValue { symbol }) + } + + pub fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|value| value.symbol == symbol) + .map(|value| value.point.as_slice()) + } + + pub fn point(&self, symbol: &'static str) -> Result<&[F], Stage4KernelError> { + self.try_point(symbol) + .ok_or(Stage4KernelError::MissingValue { symbol }) + } + + pub fn seed_constants( + &mut self, + program: &'static Stage4CpuProgramPlan, + ) -> Result<(), Stage4KernelError> { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + Ok(()) + } + + pub fn observe_challenge_vector( + &mut self, + plan: &'static Stage4TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage4KernelError> { + if matches!(plan.kind, "challenge_scalar" | "scalar") { + require_operand_count(plan.symbol, 1, values.len())?; + self.insert_scalar(plan.symbol, values[0]); + } + self.insert_point(plan.symbol, values.to_vec()); + let _ = values; + Ok(()) + } + + pub fn observe_sumcheck_output( + &mut self, + program: &'static Stage4CpuProgramPlan, + output: &Stage4SumcheckOutput, + ) -> Result<(), Stage4KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + pub fn observe_sumcheck_values( + &mut self, + program: &'static Stage4CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage4NamedEval], + ) -> Result<(), Stage4KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program.instance_results_for_driver(driver) { + let end = instance.round_offset + instance.point_arity; + let mut instance_point = point + .get(instance.round_offset..end) + .ok_or(Stage4KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "reverse" => instance_point.reverse(), + "stage4_registers_rw" => { + instance_point = + normalize_stage4_registers_rw_point(program, driver, &instance_point)?; + } + _ => { + return Err(Stage4KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, instance_point); + } + for eval in program.evals_for_driver(driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage4KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + let _ = self.evaluate_available_points(program)?; + let _ = self.evaluate_available_field_exprs(program)?; + self.verify_opening_equalities(program)?; + Ok(()) + } + + pub fn evaluate_available_points( + &mut self, + program: &'static Stage4CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage4KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + verify_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage4CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate_stage4_field_expr(expr, &operands)?); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn verify_opening_equalities( + &self, + program: &'static Stage4CpuProgramPlan, + ) -> Result<(), Stage4KernelError> { + for equality in program.opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point(equality.lhs)? != self.point(equality.rhs)? + || self.scalar(equality.lhs)? != self.scalar(equality.rhs)? + { + return Err(Stage4KernelError::InvalidProof { + driver: equality.symbol, + reason: "opening claim equality failed", + }); + } + } + _ => { + return Err(Stage4KernelError::InvalidProof { + driver: equality.symbol, + reason: "unsupported opening equality mode", + }); + } + } + } + Ok(()) + } + + pub fn claim_value( + &mut self, + program: &'static Stage4CpuProgramPlan, + claim: &Stage4SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + pub fn batch_claim_values( + &mut self, + program: &'static Stage4CpuProgramPlan, + batch: &Stage4SumcheckBatchPlan, + ) -> Result, Stage4KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage4KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn try_expr_operands(&self, expr: &Stage4FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage4PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +pub fn evaluate_stage4_field_expr( + expr: &Stage4FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + _ => { + if let Some(exponent) = expr.formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage4KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(Stage4KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula: expr.formula, + }) + } + } +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage4KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage4KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage4KernelContext<'a> { + pub mode: Stage4ExecutionMode, + pub program: &'static Stage4CpuProgramPlan, + pub kernel: &'a Stage4KernelPlan, + pub batch: &'a Stage4SumcheckBatchPlan, + pub driver: &'a Stage4SumcheckDriverPlan, +} + +impl Stage4KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + self.kernel.relation_kind() + } + + pub fn abi_kind(&self) -> Result { + self.kernel.abi_kind() + } + + pub fn batch_claims(&self) -> Result, Stage4KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage4KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage4KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage4TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage4KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage4SumcheckOutput, + ) -> Result<(), Stage4KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage4KernelExecutor; + +impl Stage4KernelExecutor for UnsupportedStage4KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + Err(Stage4KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + Err(Stage4KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } +} + +#[derive(Clone)] +pub struct Stage4ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage4ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage4ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage4ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage4CpuProgramPlan, + ) -> Result, Stage4KernelError> { + value_store_from_observations( + program, + self.inputs.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage4KernelExecutor for Stage4ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage4TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage4KernelError> { + self.challenge_vectors.push(Stage4ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage4SumcheckOutput, + ) -> Result<(), Stage4KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + prove_stage4_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + Err(Stage4KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage4ExecutionMode::Prover, + actual: Stage4ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage4VerifierKernelExecutor<'a, F: Field> { + pub proof: &'a Stage4Proof, + pub opening_inputs: &'a [Stage4OpeningInputValue], + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage4VerifierKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage4Proof, + opening_inputs: &'a [Stage4OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage4CpuProgramPlan, + ) -> Result, Stage4KernelError> { + value_store_from_observations( + program, + self.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage4KernelExecutor for Stage4VerifierKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage4TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage4KernelError> { + self.challenge_vectors.push(Stage4ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage4SumcheckOutput, + ) -> Result<(), Stage4KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + Err(Stage4KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage4ExecutionMode::Verifier, + actual: Stage4ExecutionMode::Prover, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage4KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage4KernelError> + where + T: Transcript, + { + let proof = + self.proof + .sumchecks + .get(self.cursor) + .ok_or(Stage4KernelError::MissingProof { + driver: context.driver.symbol, + })?; + self.cursor += 1; + verify_stage4_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } +} + +fn value_store_from_observations( + program: &'static Stage4CpuProgramPlan, + opening_inputs: &[Stage4OpeningInputValue], + challenge_vectors: &[Stage4ChallengeVector], + completed_sumchecks: &[Stage4SumcheckOutput], +) -> Result, Stage4KernelError> { + let mut store = Stage4ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(program)?; + for challenge in challenge_vectors { + let plan = program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == challenge.symbol) + .ok_or(Stage4KernelError::MissingValue { + symbol: challenge.symbol, + })?; + store.observe_challenge_vector(plan, &challenge.values)?; + } + for output in completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + store.verify_opening_equalities(program)?; + Ok(store) +} + +pub fn execute_stage4_program( + program: &'static Stage4CpuProgramPlan, + mode: Stage4ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + F: Field, + T: Transcript, + E: Stage4KernelExecutor, +{ + let mut artifacts = Stage4ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_squeeze(program, step.symbol).ok_or(Stage4KernelError::MissingValue { + symbol: step.symbol, + })?; + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage4ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + "transcript_absorb_bytes" => { + let absorb = find_absorb_bytes(program, step.symbol).ok_or( + Stage4KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage4_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_driver(program, step.symbol).ok_or(Stage4KernelError::MissingDriver { + driver: step.symbol, + })?; + let kernel_symbol = driver.kernel.ok_or(Stage4KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or( + Stage4KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + }, + )?; + let batch = + find_batch(program, driver.batch).ok_or(Stage4KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage4KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage4ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage4ExecutionMode::Verifier => { + executor.verify_sumcheck(context, transcript)? + } + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + } + _ => { + return Err(Stage4KernelError::InvalidProgramStep { + symbol: step.symbol, + kind: step.kind, + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +fn absorb_stage4_bytes(absorb: &'static Stage4TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn prove_stage4_kernel( + context: Stage4KernelContext<'_>, + inputs: &Stage4ProverInputs<'_, F>, + store: Stage4ValueStore, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage4KernelAbi::Batched => prove_batched_stage4(context, inputs, store, transcript), + abi => Err(Stage4KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +fn verify_stage4_kernel( + context: Stage4KernelContext<'_>, + store: Stage4ValueStore, + proof: &Stage4SumcheckOutput, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage4KernelAbi::Batched => verify_batched_stage4(context, store, proof, transcript), + abi => Err(Stage4KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +#[tracing::instrument(skip_all, name = "Stage4::prove_batched")] +fn prove_batched_stage4( + context: Stage4KernelContext<'_>, + inputs: &Stage4ProverInputs<'_, F>, + mut store: Stage4ValueStore, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + let mut instances = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + let offset = instance_round_offset(context.program, context.driver.symbol, claim.symbol)?; + if offset + claim.num_rounds > max_rounds { + return Err(Stage4KernelError::InvalidInputLength { + input: claim.symbol, + expected: max_rounds, + actual: offset + claim.num_rounds, + }); + } + let active_scale = F::one().mul_pow_2(max_rounds - offset - claim.num_rounds); + instances.push(Stage4BatchedInstance { + claim, + relation: claim_relation(context.program, claim)?, + offset, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state: Stage4ProverInstanceState::new( + context.program, + claim, + inputs, + &store, + active_scale, + )?, + }); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for instance in &mut instances { + let poly = if instance.is_active(round) { + instance + .state + .round_poly(instance.previous_claim, instance.relation)? + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + #[cfg(debug_assertions)] + { + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != instance.previous_claim { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched instance round claim mismatch", + }); + } + } + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + #[cfg(debug_assertions)] + { + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + for (instance, poly) in instances.iter_mut().zip(individual_polys) { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + instance.state.ingest_challenge(challenge); + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + for instance in &instances { + evals.extend(instance.state.final_evals(instance.relation)?); + } + let expected = + expected_batched_output_claim(context, &store, &evals, &point, &batching_coeffs)?; + if batched_claim != expected { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + Ok(Stage4SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage4( + context: Stage4KernelContext<'_>, + mut store: Stage4ValueStore, + proof: &Stage4SumcheckOutput, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = + expected_batched_output_claim(context, &store, &proof.evals, &point, &batching_coeffs)?; + if running_claim != expected { + return Err(Stage4KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + let output = Stage4SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims: Vec::new(), + proof: proof.proof.clone(), + }; + store.observe_sumcheck_output(context.program, &output)?; + let opening_claims = + append_opening_claims(context.program, &mut store, transcript, &output.evals)?; + let output = Stage4SumcheckOutput { + opening_claims, + ..output + }; + Ok(output) +} + +struct Stage4BatchedInstance<'a, F: Field> { + claim: &'a Stage4SumcheckClaimPlan, + relation: Stage4Relation, + offset: usize, + previous_claim: F, + state: Stage4ProverInstanceState, +} + +impl Stage4BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage4ProverInstanceState { + Dense(DenseStage4State), + SparseRegisters(SparseRegistersState), +} + +impl Stage4ProverInstanceState { + fn new( + program: &'static Stage4CpuProgramPlan, + claim: &Stage4SumcheckClaimPlan, + inputs: &Stage4ProverInputs<'_, F>, + store: &Stage4ValueStore, + active_scale: F, + ) -> Result { + match claim_relation(program, claim)? { + Stage4Relation::RegistersReadWrite => { + registers_read_write_state(claim, inputs, store, active_scale) + } + Stage4Relation::RamValCheck => { + ram_val_check_state(claim, inputs, store, active_scale).map(Self::Dense) + } + relation @ Stage4Relation::Batched => Err(Stage4KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + } + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage4Relation, + ) -> Result, Stage4KernelError> { + match self { + Self::Dense(state) => state.round_poly(previous_claim, relation), + Self::SparseRegisters(state) => state.round_poly(previous_claim, relation), + } + } + + fn ingest_challenge(&mut self, challenge: F) { + match self { + Self::Dense(state) => state.bind(challenge), + Self::SparseRegisters(state) => state.bind(challenge), + } + } + + fn final_evals( + &self, + relation: Stage4Relation, + ) -> Result>, Stage4KernelError> { + match self { + Self::Dense(state) => state.final_evals(relation), + Self::SparseRegisters(state) => state.final_evals(relation), + } + } +} + +#[derive(Clone)] +struct DenseStage4State { + factors: Vec>, + factor_scratch: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, +} + +#[derive(Clone)] +struct DenseTerm { + coefficient: F, + factors: Vec, +} + +#[derive(Clone, Copy)] +struct FactorOutput { + name: &'static str, + oracle: &'static str, + factor: usize, +} + +impl DenseStage4State { + fn new( + factors: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, + ) -> Self { + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Self { + factors, + factor_scratch, + terms, + outputs, + active_scale, + } + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage4Relation, + ) -> Result, Stage4KernelError> { + let first_len = self.factors.first().map_or(0, Vec::len); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 dense factor has invalid length", + }); + } + if self.factors.iter().any(|factor| factor.len() != first_len) { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 dense factors have inconsistent lengths", + }); + } + let poly = + round_poly_from_dense_terms(&self.factors, &self.terms, self.active_scale, relation)?; + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 relation input claim mismatch", + }); + } + Ok(poly) + } + + fn bind(&mut self, challenge: F) { + if self.factors.first().map_or(0, Vec::len) / 2 >= DENSE_BIND_PAR_THRESHOLD { + self.factors + .par_iter_mut() + .zip(self.factor_scratch.par_iter_mut()) + .for_each(|(factor, scratch)| { + bind_dense_evals_reuse(factor, scratch, challenge); + }); + } else { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse(factor, scratch, challenge); + } + } + } + + fn factor_eval(&self, index: usize, relation: Stage4Relation) -> Result { + self.factors + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty stage4 factor", + }) + } + + fn final_evals( + &self, + relation: Stage4Relation, + ) -> Result>, Stage4KernelError> { + self.outputs + .iter() + .map(|output| { + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(output.factor, relation)?, + )) + }) + .collect() + } +} + +#[derive(Clone)] +struct SparseRegistersState { + register_count: usize, + trace_len: usize, + current_trace_len: usize, + entries: Vec>, + entry_scratch: Vec>, + rs2_reads: Vec<(usize, usize)>, + eq_cycle: SplitEqState, + rd_inc: Vec, + rd_inc_scratch: Vec, + gamma: F, + gamma2: F, + active_scale: F, + bound_point: Vec, + dense: Option>, +} + +#[derive(Clone, Copy, Debug)] +struct SparseRegisterEntry { + row: usize, + col: u8, + val: F, + prev_val: u64, + next_val: u64, + read_ra: F, + rd_wa: F, +} + +impl SparseRegistersState { + fn new( + register_count: usize, + trace_len: usize, + accesses: &[Stage4RegisterAccess], + rd_inc: &[F], + trace_point: &[F], + gamma: F, + gamma2: F, + active_scale: F, + ) -> Result { + require_operand_count("stage4.registers.accesses", trace_len, accesses.len())?; + require_operand_count("stage4.registers.RdInc", trace_len, rd_inc.len())?; + let mut entries = Vec::with_capacity(accesses.len().saturating_mul(3)); + let mut rs2_reads = Vec::with_capacity(accesses.len()); + for (row, access) in accesses.iter().enumerate() { + append_sparse_register_entries( + register_count, + row, + *access, + gamma, + gamma2, + &mut entries, + )?; + if let Some(rs2) = access.rs2 { + rs2_reads.push((row, rs2.address)); + } + } + let eq_cycle = SplitEqState::new_low_to_high(trace_point, None); + let mut state = Self { + register_count, + trace_len, + current_trace_len: trace_len, + entries, + entry_scratch: Vec::new(), + rs2_reads, + eq_cycle, + rd_inc: rd_inc.to_vec(), + rd_inc_scratch: Vec::new(), + gamma, + gamma2, + active_scale, + bound_point: Vec::with_capacity( + log2_exact(register_count, "stage4.register_count")? + + log2_exact(trace_len, "stage4.trace_len")?, + ), + dense: None, + }; + if trace_len == 1 { + state.materialize_dense()?; + } + Ok(state) + } + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage4Relation, + ) -> Result, Stage4KernelError> { + if let Some(dense) = &self.dense { + return dense.round_poly(previous_claim, relation); + } + if self.current_trace_len <= 1 { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 sparse registers state was not materialized", + }); + } + let (mut q_constant, mut q_quadratic) = sparse_register_split_round_coefficients( + &self.entries, + &self.eq_cycle, + &self.rd_inc, + self.current_trace_len, + )?; + q_constant *= self.active_scale; + q_quadratic *= self.active_scale; + let poly = gruen_cubic_poly( + self.eq_cycle.current_target(), + q_constant, + q_quadratic, + previous_claim, + ); + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 sparse registers input claim mismatch", + }); + } + Ok(poly) + } + + fn bind(&mut self, challenge: F) { + self.bound_point.push(challenge); + if let Some(dense) = &mut self.dense { + dense.bind(challenge); + return; + } + bind_sparse_register_entries_into( + &self.entries, + self.current_trace_len, + challenge, + &mut self.entry_scratch, + ); + std::mem::swap(&mut self.entries, &mut self.entry_scratch); + self.entry_scratch.clear(); + self.eq_cycle.bind(challenge); + bind_dense_evals_reuse(&mut self.rd_inc, &mut self.rd_inc_scratch, challenge); + self.current_trace_len /= 2; + if self.current_trace_len == 1 { + let _ = self.materialize_dense(); + } + } + + fn final_evals( + &self, + relation: Stage4Relation, + ) -> Result>, Stage4KernelError> { + let dense = self.dense.as_ref().ok_or(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 sparse registers state was not materialized", + })?; + let registers_val = dense.factor_eval(1, relation)?; + let combined_read_ra = dense.factor_eval(2, relation)?; + let rd_wa = dense.factor_eval(3, relation)?; + let rd_inc = dense.factor_eval(4, relation)?; + let rs2_ra = self.final_rs2_read_eval(relation)?; + let gamma_inverse = self + .gamma + .inverse() + .ok_or(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 registers challenge is not invertible", + })?; + let rs1_ra = (combined_read_ra - self.gamma2 * rs2_ra) * gamma_inverse; + #[cfg(debug_assertions)] + { + let expected = self.gamma * rs1_ra + self.gamma2 * rs2_ra; + if combined_read_ra != expected { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 sparse registers final read claim mismatch", + }); + } + } + Ok(vec![ + named_eval( + "stage4.registers_read_write.eval.RegistersVal", + "RegistersVal", + registers_val, + ), + named_eval("stage4.registers_read_write.eval.Rs1Ra", "Rs1Ra", rs1_ra), + named_eval("stage4.registers_read_write.eval.Rs2Ra", "Rs2Ra", rs2_ra), + named_eval("stage4.registers_read_write.eval.RdWa", "RdWa", rd_wa), + named_eval("stage4.registers_read_write.eval.RdInc", "RdInc", rd_inc), + ]) + } + + fn materialize_dense(&mut self) -> Result<(), Stage4KernelError> { + let mut registers_val = vec![F::zero(); self.register_count]; + let mut read_ra = vec![F::zero(); self.register_count]; + let mut rd_wa = vec![F::zero(); self.register_count]; + for entry in &self.entries { + let col = usize::from(entry.col); + if entry.row != 0 || col >= self.register_count { + return Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers.accesses", + expected: self.register_count, + actual: col + 1, + }); + } + registers_val[col] = entry.val; + read_ra[col] = entry.read_ra; + rd_wa[col] = entry.rd_wa; + } + let eq_eval = self.eq_cycle.eval(); + let rd_inc_eval = + self.rd_inc + .first() + .copied() + .ok_or(Stage4KernelError::InvalidInputLength { + input: "stage4.registers.RdInc", + expected: 1, + actual: 0, + })?; + self.dense = Some(registers_combined_dense_state( + vec![eq_eval; self.register_count], + registers_val, + read_ra, + rd_wa, + vec![rd_inc_eval; self.register_count], + self.active_scale, + )); + Ok(()) + } + + fn final_rs2_read_eval(&self, relation: Stage4Relation) -> Result { + let trace_rounds = log2_exact(self.trace_len, "stage4.trace_len")?; + let register_rounds = log2_exact(self.register_count, "stage4.register_count")?; + if self.bound_point.len() != trace_rounds + register_rounds { + return Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers_read_write.instance", + expected: trace_rounds + register_rounds, + actual: self.bound_point.len(), + }); + } + let (cycle_point, address_point) = self.bound_point.split_at(trace_rounds); + let r_cycle = reverse_slice(cycle_point); + let r_address = reverse_slice(address_point); + let (cycle_eq, address_eq) = rayon::join( + || EqPolynomial::::evals(&r_cycle, None), + || EqPolynomial::::evals(&r_address, None), + ); + if cycle_eq.len() != self.trace_len || address_eq.len() != self.register_count { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 sparse registers final read point has invalid shape", + }); + } + Ok(sparse_register_read_eval( + &self.rs2_reads, + &cycle_eq, + &address_eq, + )) + } +} + +fn registers_read_write_state( + claim: &Stage4SumcheckClaimPlan, + inputs: &Stage4ProverInputs<'_, F>, + store: &Stage4ValueStore, + active_scale: F, +) -> Result, Stage4KernelError> { + let witness = inputs + .registers + .ok_or(Stage4KernelError::MissingKernelInput { + kernel: "jolt_stage4_batched", + input: "registers", + })?; + let expected_len = witness + .register_count + .checked_mul(witness.trace_len) + .ok_or(Stage4KernelError::InvalidInputLength { + input: "stage4.registers", + expected: usize::MAX, + actual: witness.register_count, + })?; + + let trace_point = store.point("stage4.input.stage3.registers.RdWriteValue")?; + let register_rounds = log2_exact(witness.register_count, "stage4.register_count")?; + let trace_rounds = log2_exact(witness.trace_len, "stage4.trace_len")?; + require_operand_count( + "stage4.registers.trace_point", + trace_rounds, + trace_point.len(), + )?; + require_operand_count( + claim.symbol, + register_rounds + trace_rounds, + claim.num_rounds, + )?; + + let gamma = store.scalar("stage4.registers_read_write.gamma")?; + let gamma2 = store + .try_scalar("stage4.registers_read_write.gamma2") + .unwrap_or_else(|| gamma * gamma); + + if let Some(accesses) = witness.accesses { + return SparseRegistersState::new( + witness.register_count, + witness.trace_len, + accesses, + witness.rd_inc, + trace_point, + gamma, + gamma2, + active_scale, + ) + .map(Stage4ProverInstanceState::SparseRegisters); + } + + require_operand_count( + "stage4.registers.RegistersVal", + expected_len, + witness.registers_val.len(), + )?; + require_operand_count("stage4.registers.Rs1Ra", expected_len, witness.rs1_ra.len())?; + require_operand_count("stage4.registers.Rs2Ra", expected_len, witness.rs2_ra.len())?; + require_operand_count("stage4.registers.RdWa", expected_len, witness.rd_wa.len())?; + require_operand_count( + "stage4.registers.RdInc", + witness.trace_len, + witness.rd_inc.len(), + )?; + let eq_cycle = EqPolynomial::::evals(trace_point, None); + let mut eq_cycle_expanded = Vec::with_capacity(expected_len); + let mut rd_inc_expanded = Vec::with_capacity(expected_len); + for _address in 0..witness.register_count { + eq_cycle_expanded.extend_from_slice(&eq_cycle); + rd_inc_expanded.extend_from_slice(witness.rd_inc); + } + + Ok(Stage4ProverInstanceState::Dense(registers_dense_state( + eq_cycle_expanded, + witness.registers_val.to_vec(), + witness.rs1_ra.to_vec(), + witness.rs2_ra.to_vec(), + witness.rd_wa.to_vec(), + rd_inc_expanded, + gamma, + gamma2, + active_scale, + ))) +} + +fn registers_dense_state( + eq_cycle: Vec, + registers_val: Vec, + rs1_ra: Vec, + rs2_ra: Vec, + rd_wa: Vec, + rd_inc: Vec, + gamma: F, + gamma2: F, + active_scale: F, +) -> DenseStage4State { + DenseStage4State::new( + vec![eq_cycle, registers_val, rs1_ra, rs2_ra, rd_wa, rd_inc], + vec![ + DenseTerm { + coefficient: F::one(), + factors: vec![0, 4, 1], + }, + DenseTerm { + coefficient: F::one(), + factors: vec![0, 4, 5], + }, + DenseTerm { + coefficient: gamma, + factors: vec![0, 2, 1], + }, + DenseTerm { + coefficient: gamma2, + factors: vec![0, 3, 1], + }, + ], + vec![ + FactorOutput { + name: "stage4.registers_read_write.eval.RegistersVal", + oracle: "RegistersVal", + factor: 1, + }, + FactorOutput { + name: "stage4.registers_read_write.eval.Rs1Ra", + oracle: "Rs1Ra", + factor: 2, + }, + FactorOutput { + name: "stage4.registers_read_write.eval.Rs2Ra", + oracle: "Rs2Ra", + factor: 3, + }, + FactorOutput { + name: "stage4.registers_read_write.eval.RdWa", + oracle: "RdWa", + factor: 4, + }, + FactorOutput { + name: "stage4.registers_read_write.eval.RdInc", + oracle: "RdInc", + factor: 5, + }, + ], + active_scale, + ) +} + +fn registers_combined_dense_state( + eq_cycle: Vec, + registers_val: Vec, + read_ra: Vec, + rd_wa: Vec, + rd_inc: Vec, + active_scale: F, +) -> DenseStage4State { + DenseStage4State::new( + vec![eq_cycle, registers_val, read_ra, rd_wa, rd_inc], + vec![ + DenseTerm { + coefficient: F::one(), + factors: vec![0, 3, 1], + }, + DenseTerm { + coefficient: F::one(), + factors: vec![0, 3, 4], + }, + DenseTerm { + coefficient: F::one(), + factors: vec![0, 2, 1], + }, + ], + Vec::new(), + active_scale, + ) +} + +fn append_sparse_register_entries( + register_count: usize, + row: usize, + access: Stage4RegisterAccess, + gamma: F, + gamma2: F, + entries: &mut Vec>, +) -> Result<(), Stage4KernelError> { + let start = entries.len(); + if let Some(rs1) = access.rs1 { + validate_register_address(register_count, rs1.address)?; + let col = sparse_register_col(rs1.address)?; + entries.push(SparseRegisterEntry { + row, + col, + val: F::from_u64(rs1.value), + prev_val: rs1.value, + next_val: rs1.value, + read_ra: gamma, + rd_wa: F::zero(), + }); + } + if let Some(rs2) = access.rs2 { + validate_register_address(register_count, rs2.address)?; + let col = sparse_register_col(rs2.address)?; + if let Some(entry) = entries[start..].iter_mut().find(|entry| entry.col == col) { + entry.read_ra += gamma2; + } else { + entries.push(SparseRegisterEntry { + row, + col, + val: F::from_u64(rs2.value), + prev_val: rs2.value, + next_val: rs2.value, + read_ra: gamma2, + rd_wa: F::zero(), + }); + } + } + if let Some(rd) = access.rd { + validate_register_address(register_count, rd.address)?; + let col = sparse_register_col(rd.address)?; + if let Some(entry) = entries[start..].iter_mut().find(|entry| entry.col == col) { + entry.rd_wa = F::one(); + entry.next_val = rd.post_value; + } else { + entries.push(SparseRegisterEntry { + row, + col, + val: F::from_u64(rd.pre_value), + prev_val: rd.pre_value, + next_val: rd.post_value, + read_ra: F::zero(), + rd_wa: F::one(), + }); + } + } + entries[start..].sort_by_key(|entry| entry.col); + Ok(()) +} + +fn sparse_register_col(address: usize) -> Result { + u8::try_from(address).map_err(|_| Stage4KernelError::InvalidInputLength { + input: "stage4.registers.accesses", + expected: usize::from(u8::MAX) + 1, + actual: address + 1, + }) +} + +fn validate_register_address( + register_count: usize, + address: usize, +) -> Result<(), Stage4KernelError> { + if address < register_count { + Ok(()) + } else { + Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers.accesses", + expected: register_count, + actual: address + 1, + }) + } +} + +fn sparse_register_split_round_coefficients( + entries: &[SparseRegisterEntry], + eq_cycle: &SplitEqState, + rd_inc: &[F], + current_trace_len: usize, +) -> Result<(F, F), Stage4KernelError> { + if let Some(entry) = entries.last() { + if entry.row >= current_trace_len { + return Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers.accesses", + expected: current_trace_len, + actual: entry.row + 1, + }); + } + } + let e_in = eq_cycle.e_in(); + let e_out = eq_cycle.e_out(); + if e_in.len() > 1 { + sparse_register_low_round_coefficients(entries, rd_inc, e_in, e_out) + } else { + sparse_register_high_round_coefficients(entries, rd_inc, e_in[0], e_out) + } +} + +fn sparse_register_low_round_coefficients( + entries: &[SparseRegisterEntry], + rd_inc: &[F], + e_in: &[F], + e_out: &[F], +) -> Result<(F, F), Stage4KernelError> { + let in_pairs = e_in.len() / 2; + if entries.len() >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = entries + .par_chunk_by(|left, right| (left.row / 2) / in_pairs == (right.row / 2) / in_pairs) + .map(|entries| { + let mut local = [F::Accumulator::default(); 2]; + accumulate_sparse_register_low_outer_chunk( + &mut local, entries, rd_inc, e_in, e_out, in_pairs, + ); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + return Ok((accumulators[0].reduce(), accumulators[1].reduce())); + } + + let mut accumulators = [F::Accumulator::default(); 2]; + let mut cursor = 0usize; + while cursor < entries.len() { + let pair = entries[cursor].row / 2; + let x_out = pair / in_pairs; + let x_in = pair % in_pairs; + let weight = e_out[x_out] * (e_in[2 * x_in] + e_in[2 * x_in + 1]); + let even_row = 2 * pair; + let odd_row = even_row + 1; + let even_start = cursor; + while cursor < entries.len() && entries[cursor].row == even_row { + cursor += 1; + } + let even = &entries[even_start..cursor]; + let odd_start = cursor; + while cursor < entries.len() && entries[cursor].row == odd_row { + cursor += 1; + } + let odd = &entries[odd_start..cursor]; + accumulate_sparse_register_row_pair_body_coefficients( + &mut accumulators, + even, + odd, + rd_inc[even_row], + rd_inc[odd_row] - rd_inc[even_row], + weight, + ); + } + Ok((accumulators[0].reduce(), accumulators[1].reduce())) +} + +fn sparse_register_high_round_coefficients( + entries: &[SparseRegisterEntry], + rd_inc: &[F], + in_weight: F, + e_out: &[F], +) -> Result<(F, F), Stage4KernelError> { + if entries.len() >= DENSE_BIND_PAR_THRESHOLD { + let accumulators = entries + .par_chunk_by(|left, right| left.row / 2 == right.row / 2) + .map(|entries| { + let mut local = [F::Accumulator::default(); 2]; + let pair = entries[0].row / 2; + let weight = in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]); + accumulate_sparse_register_row_pair_chunk(&mut local, entries, rd_inc, weight); + local + }) + .reduce( + || [F::Accumulator::default(); 2], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + left.merge(right); + } + left + }, + ); + return Ok((accumulators[0].reduce(), accumulators[1].reduce())); + } + + let mut accumulators = [F::Accumulator::default(); 2]; + let mut cursor = 0usize; + while cursor < entries.len() { + let pair = entries[cursor].row / 2; + let weight = in_weight * (e_out[2 * pair] + e_out[2 * pair + 1]); + let start = cursor; + let even_row = 2 * pair; + while cursor < entries.len() + && (entries[cursor].row == even_row || entries[cursor].row == even_row + 1) + { + cursor += 1; + } + accumulate_sparse_register_row_pair_chunk( + &mut accumulators, + &entries[start..cursor], + rd_inc, + weight, + ); + } + Ok((accumulators[0].reduce(), accumulators[1].reduce())) +} + +fn accumulate_sparse_register_low_outer_chunk( + accumulators: &mut [F::Accumulator; 2], + entries: &[SparseRegisterEntry], + rd_inc: &[F], + e_in: &[F], + e_out: &[F], + in_pairs: usize, +) { + let x_out = (entries[0].row / 2) / in_pairs; + let out_weight = e_out[x_out]; + for entries in entries.chunk_by(|left, right| left.row / 2 == right.row / 2) { + let pair = entries[0].row / 2; + let x_in = pair % in_pairs; + let weight = out_weight * (e_in[2 * x_in] + e_in[2 * x_in + 1]); + accumulate_sparse_register_row_pair_chunk(accumulators, entries, rd_inc, weight); + } +} + +fn accumulate_sparse_register_row_pair_chunk( + accumulators: &mut [F::Accumulator; 2], + entries: &[SparseRegisterEntry], + rd_inc: &[F], + weight: F, +) { + let pair = entries[0].row / 2; + let even_row = 2 * pair; + let odd_start = entries.partition_point(|entry| entry.row == even_row); + let (even, odd) = entries.split_at(odd_start); + accumulate_sparse_register_row_pair_body_coefficients( + accumulators, + even, + odd, + rd_inc[even_row], + rd_inc[even_row + 1] - rd_inc[even_row], + weight, + ); +} + +#[derive(Clone)] +struct SparseRegisterPairRange { + pair: usize, + even: std::ops::Range, + odd: std::ops::Range, +} + +fn sparse_register_pair_ranges_into( + entries: &[SparseRegisterEntry], + current_trace_len: usize, + ranges: &mut Vec, +) -> Result<(), Stage4KernelError> { + let half = current_trace_len / 2; + ranges.clear(); + let mut cursor = 0usize; + while cursor < entries.len() { + let pair = entries[cursor].row / 2; + if pair >= half { + return Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers.accesses", + expected: current_trace_len, + actual: entries[cursor].row + 1, + }); + } + let even_row = 2 * pair; + let odd_row = even_row + 1; + let even_start = cursor; + while cursor < entries.len() && entries[cursor].row == even_row { + cursor += 1; + } + let even = even_start..cursor; + let odd_start = cursor; + while cursor < entries.len() && entries[cursor].row == odd_row { + cursor += 1; + } + let odd = odd_start..cursor; + ranges.push(SparseRegisterPairRange { pair, even, odd }); + } + Ok(()) +} + +fn sparse_register_pair_ranges( + entries: &[SparseRegisterEntry], + current_trace_len: usize, +) -> Result, Stage4KernelError> { + let mut ranges = Vec::new(); + sparse_register_pair_ranges_into(entries, current_trace_len, &mut ranges)?; + Ok(ranges) +} + +fn accumulate_sparse_register_row_pair_body_coefficients( + accumulators: &mut [F::Accumulator; 2], + even: &[SparseRegisterEntry], + odd: &[SparseRegisterEntry], + inc0: F, + inc_delta: F, + weight: F, +) { + let mut i = 0usize; + let mut j = 0usize; + while i < even.len() || j < odd.len() { + let (even_entry, odd_entry) = + if j >= odd.len() || (i < even.len() && even[i].col < odd[j].col) { + let pair = (Some(&even[i]), None); + i += 1; + pair + } else if i >= even.len() || odd[j].col < even[i].col { + let pair = (None, Some(&odd[j])); + j += 1; + pair + } else { + let pair = (Some(&even[i]), Some(&odd[j])); + i += 1; + j += 1; + pair + }; + accumulate_sparse_register_entry_pair_body_coefficients( + accumulators, + even_entry, + odd_entry, + inc0, + inc_delta, + weight, + ); + } +} + +#[derive(Clone, Copy)] +struct SparseRegisterEval { + val: F, + read_ra: F, + rd_wa: F, +} + +#[derive(Clone, Copy)] +struct SparseRegisterLinear { + val0: F, + val_delta: F, + read_ra0: F, + read_ra_delta: F, + rd_wa0: F, + rd_wa_delta: F, +} + +fn accumulate_sparse_register_entry_pair_body_coefficients( + accumulators: &mut [F::Accumulator; 2], + even: Option<&SparseRegisterEntry>, + odd: Option<&SparseRegisterEntry>, + inc0: F, + inc_delta: F, + weight: F, +) { + let linear = sparse_register_entry_linear(even, odd); + let val_inc0 = linear.val0 + inc0; + let val_inc_delta = linear.val_delta + inc_delta; + let body0 = linear.rd_wa0 * val_inc0 + linear.read_ra0 * linear.val0; + let body2 = linear.rd_wa_delta * val_inc_delta + linear.read_ra_delta * linear.val_delta; + + accumulators[0].fmadd(weight, body0); + accumulators[1].fmadd(weight, body2); +} + +fn sparse_register_entry_linear( + even: Option<&SparseRegisterEntry>, + odd: Option<&SparseRegisterEntry>, +) -> SparseRegisterLinear { + match (even, odd) { + (Some(even), Some(odd)) => SparseRegisterLinear { + val0: even.val, + val_delta: odd.val - even.val, + read_ra0: even.read_ra, + read_ra_delta: odd.read_ra - even.read_ra, + rd_wa0: even.rd_wa, + rd_wa_delta: odd.rd_wa - even.rd_wa, + }, + (Some(even), None) => SparseRegisterLinear { + val0: even.val, + val_delta: F::from_u64(even.next_val) - even.val, + read_ra0: even.read_ra, + read_ra_delta: -even.read_ra, + rd_wa0: even.rd_wa, + rd_wa_delta: -even.rd_wa, + }, + (None, Some(odd)) => SparseRegisterLinear { + val0: F::from_u64(odd.prev_val), + val_delta: odd.val - F::from_u64(odd.prev_val), + read_ra0: F::zero(), + read_ra_delta: odd.read_ra, + rd_wa0: F::zero(), + rd_wa_delta: odd.rd_wa, + }, + (None, None) => SparseRegisterLinear { + val0: F::zero(), + val_delta: F::zero(), + read_ra0: F::zero(), + read_ra_delta: F::zero(), + rd_wa0: F::zero(), + rd_wa_delta: F::zero(), + }, + } +} + +fn sparse_register_entry_eval( + even: Option<&SparseRegisterEntry>, + odd: Option<&SparseRegisterEntry>, + x: F, +) -> SparseRegisterEval { + match (even, odd) { + (Some(even), Some(odd)) => SparseRegisterEval { + val: linear_eval(even.val, odd.val, x), + read_ra: linear_eval(even.read_ra, odd.read_ra, x), + rd_wa: linear_eval(even.rd_wa, odd.rd_wa, x), + }, + (Some(even), None) => SparseRegisterEval { + val: linear_eval(even.val, F::from_u64(even.next_val), x), + read_ra: linear_eval(even.read_ra, F::zero(), x), + rd_wa: linear_eval(even.rd_wa, F::zero(), x), + }, + (None, Some(odd)) => SparseRegisterEval { + val: linear_eval(F::from_u64(odd.prev_val), odd.val, x), + read_ra: linear_eval(F::zero(), odd.read_ra, x), + rd_wa: linear_eval(F::zero(), odd.rd_wa, x), + }, + (None, None) => SparseRegisterEval { + val: F::zero(), + read_ra: F::zero(), + rd_wa: F::zero(), + }, + } +} + +fn bind_sparse_register_entries_into( + entries: &[SparseRegisterEntry], + current_trace_len: usize, + challenge: F, + output: &mut Vec>, +) { + output.clear(); + if entries.len() >= DENSE_BIND_PAR_THRESHOLD { + if let Ok(ranges) = sparse_register_pair_ranges(entries, current_trace_len) { + let bound_lengths = ranges + .par_iter() + .map(|range| { + sparse_register_row_pair_bound_len( + &entries[range.even.clone()], + &entries[range.odd.clone()], + ) + }) + .collect::>(); + let output_len = bound_lengths.iter().sum(); + output.reserve(output_len); + let mut spare = output.spare_capacity_mut(); + let mut output_slices = Vec::with_capacity(ranges.len()); + for &bound_len in &bound_lengths { + let (slice, rest) = spare.split_at_mut(bound_len); + output_slices.push(slice); + spare = rest; + } + ranges + .par_iter() + .zip(output_slices.into_par_iter()) + .for_each(|(range, output)| { + bind_sparse_register_row_pair_into( + &entries[range.even.clone()], + &entries[range.odd.clone()], + range.pair, + challenge, + output, + ); + }); + // SAFETY: every slot in `output_slices` was initialized exactly once by + // `bind_sparse_register_row_pair_into`. + unsafe { + output.set_len(output_len); + } + return; + } + } + + bind_sparse_register_entries_sequential_into(entries, challenge, output); +} + +fn bind_sparse_register_entries_sequential_into( + entries: &[SparseRegisterEntry], + challenge: F, + output: &mut Vec>, +) { + output.reserve(entries.len()); + let mut cursor = 0usize; + while cursor < entries.len() { + let pair = entries[cursor].row / 2; + let even_row = 2 * pair; + let odd_row = even_row + 1; + let even_start = cursor; + while cursor < entries.len() && entries[cursor].row == even_row { + cursor += 1; + } + let even = &entries[even_start..cursor]; + let odd_start = cursor; + while cursor < entries.len() && entries[cursor].row == odd_row { + cursor += 1; + } + let odd = &entries[odd_start..cursor]; + bind_sparse_register_row_pair(even, odd, pair, challenge, output); + } +} + +fn sparse_register_row_pair_bound_len( + even: &[SparseRegisterEntry], + odd: &[SparseRegisterEntry], +) -> usize { + let mut i = 0usize; + let mut j = 0usize; + let mut len = 0usize; + while i < even.len() || j < odd.len() { + if j >= odd.len() || (i < even.len() && even[i].col < odd[j].col) { + i += 1; + } else if i >= even.len() || odd[j].col < even[i].col { + j += 1; + } else { + i += 1; + j += 1; + } + len += 1; + } + len +} + +fn bind_sparse_register_row_pair_into( + even: &[SparseRegisterEntry], + odd: &[SparseRegisterEntry], + row: usize, + challenge: F, + output: &mut [MaybeUninit>], +) { + let mut i = 0usize; + let mut j = 0usize; + let mut out = 0usize; + while i < even.len() || j < odd.len() { + let (even_entry, odd_entry, col) = + if j >= odd.len() || (i < even.len() && even[i].col < odd[j].col) { + let pair = (Some(&even[i]), None, even[i].col); + i += 1; + pair + } else if i >= even.len() || odd[j].col < even[i].col { + let pair = (None, Some(&odd[j]), odd[j].col); + j += 1; + pair + } else { + let pair = (Some(&even[i]), Some(&odd[j]), even[i].col); + i += 1; + j += 1; + pair + }; + output[out] = MaybeUninit::new(bind_sparse_register_entry_pair( + even_entry, odd_entry, row, col, challenge, + )); + out += 1; + } + debug_assert_eq!(out, output.len()); +} + +fn bind_sparse_register_row_pair( + even: &[SparseRegisterEntry], + odd: &[SparseRegisterEntry], + row: usize, + challenge: F, + output: &mut Vec>, +) { + let mut i = 0usize; + let mut j = 0usize; + while i < even.len() || j < odd.len() { + let (even_entry, odd_entry, col) = + if j >= odd.len() || (i < even.len() && even[i].col < odd[j].col) { + let pair = (Some(&even[i]), None, even[i].col); + i += 1; + pair + } else if i >= even.len() || odd[j].col < even[i].col { + let pair = (None, Some(&odd[j]), odd[j].col); + j += 1; + pair + } else { + let pair = (Some(&even[i]), Some(&odd[j]), even[i].col); + i += 1; + j += 1; + pair + }; + output.push(bind_sparse_register_entry_pair( + even_entry, odd_entry, row, col, challenge, + )); + } +} + +fn bind_sparse_register_entry_pair( + even: Option<&SparseRegisterEntry>, + odd: Option<&SparseRegisterEntry>, + row: usize, + col: u8, + challenge: F, +) -> SparseRegisterEntry { + let value = sparse_register_entry_eval(even, odd, challenge); + let (prev_val, next_val) = match (even, odd) { + (Some(even), Some(odd)) => (even.prev_val, odd.next_val), + (Some(even), None) => (even.prev_val, even.next_val), + (None, Some(odd)) => (odd.prev_val, odd.next_val), + (None, None) => (0, 0), + }; + SparseRegisterEntry { + row, + col, + val: value.val, + prev_val, + next_val, + read_ra: value.read_ra, + rd_wa: value.rd_wa, + } +} + +fn sparse_register_read_eval( + reads: &[(usize, usize)], + cycle_eq: &[F], + address_eq: &[F], +) -> F { + if reads.len() >= DENSE_BIND_PAR_THRESHOLD { + reads + .par_iter() + .map(|&(row, col)| { + debug_assert!(row < cycle_eq.len()); + debug_assert!(col < address_eq.len()); + cycle_eq[row] * address_eq[col] + }) + .sum() + } else { + reads + .iter() + .map(|&(row, col)| { + debug_assert!(row < cycle_eq.len()); + debug_assert!(col < address_eq.len()); + cycle_eq[row] * address_eq[col] + }) + .sum() + } +} + +fn linear_eval(low: F, high: F, x: F) -> F { + low + x * (high - low) +} + +fn gruen_cubic_poly( + target: F, + q_constant: F, + q_quadratic_coeff: F, + previous_claim: F, +) -> UnivariatePoly { + let eq_eval_1 = target; + let eq_eval_0 = F::one() - target; + let eq_delta = eq_eval_1 - eq_eval_0; + let eq_eval_2 = eq_eval_1 + eq_delta; + let eq_eval_3 = eq_eval_2 + eq_delta; + let cubic_eval_0 = eq_eval_0 * q_constant; + let cubic_eval_1 = previous_claim - cubic_eval_0; + let quadratic_eval_1 = cubic_eval_1 / eq_eval_1; + let e_times_2 = q_quadratic_coeff + q_quadratic_coeff; + let quadratic_eval_2 = quadratic_eval_1 + quadratic_eval_1 - q_constant + e_times_2; + let quadratic_eval_3 = quadratic_eval_2 + quadratic_eval_1 - q_constant + e_times_2 + e_times_2; + UnivariatePoly::from_evals(&[ + cubic_eval_0, + cubic_eval_1, + eq_eval_2 * quadratic_eval_2, + eq_eval_3 * quadratic_eval_3, + ]) +} + +#[tracing::instrument(skip_all, name = "ram_val_check_state")] +fn ram_val_check_state( + claim: &Stage4SumcheckClaimPlan, + inputs: &Stage4ProverInputs<'_, F>, + store: &Stage4ValueStore, + active_scale: F, +) -> Result, Stage4KernelError> { + let witness = inputs.ram.ok_or(Stage4KernelError::MissingKernelInput { + kernel: "jolt_stage4_batched", + input: "ram", + })?; + let expected_len = witness.ram_k.checked_mul(witness.trace_len).ok_or( + Stage4KernelError::InvalidInputLength { + input: "stage4.ram", + expected: usize::MAX, + actual: witness.ram_k, + }, + )?; + require_operand_count( + "stage4.ram.RamInc", + witness.trace_len, + witness.ram_inc.len(), + )?; + + let ram_val_point = store.point("stage4.input.stage2.RamVal")?; + let trace_rounds = log2_exact(witness.trace_len, "stage4.ram.trace_len")?; + let ram_rounds = log2_exact(witness.ram_k, "stage4.ram_k")?; + require_operand_count("stage4.ram_val_check.input", trace_rounds, claim.num_rounds)?; + require_operand_count( + "stage4.input.stage2.RamVal", + ram_rounds + trace_rounds, + ram_val_point.len(), + )?; + let (address_point, cycle_point) = ram_val_point.split_at(ram_rounds); + let address_eq = EqPolynomial::::evals(address_point, None); + let ram_ra_at_address = ram_ra_at_address(witness, &address_eq, expected_len)?; + + let gamma = store.scalar("stage4.ram_val_check.gamma")?; + let mut lt_plus_gamma = lt_evals_big_endian(cycle_point); + require_operand_count( + "stage4.ram_val_check.lt", + witness.trace_len, + lt_plus_gamma.len(), + )?; + lt_plus_gamma + .par_iter_mut() + .for_each(|value| *value += gamma); + + Ok(DenseStage4State::new( + vec![lt_plus_gamma, ram_ra_at_address, witness.ram_inc.to_vec()], + vec![DenseTerm { + coefficient: F::one(), + factors: vec![0, 1, 2], + }], + vec![ + FactorOutput { + name: "stage4.ram_val_check.eval.RamRa", + oracle: "RamRa", + factor: 1, + }, + FactorOutput { + name: "stage4.ram_val_check.eval.RamInc", + oracle: "RamInc", + factor: 2, + }, + ], + active_scale, + )) +} + +fn ram_ra_at_address( + witness: Stage4RamWitness<'_, F>, + address_eq: &[F], + dense_len: usize, +) -> Result, Stage4KernelError> { + if !witness.ram_ra.is_empty() { + require_operand_count("stage4.ram.RamRa", dense_len, witness.ram_ra.len())?; + let mut output = vec![F::zero(); witness.trace_len]; + for (address, &weight) in address_eq.iter().enumerate() { + let base = address * witness.trace_len; + for (cycle, output) in output.iter_mut().enumerate() { + *output += weight * witness.ram_ra[base + cycle]; + } + } + return Ok(output); + } + + let Some(write_address_indices) = witness.write_address_indices else { + return Err(Stage4KernelError::MissingKernelInput { + kernel: "jolt_stage4_batched", + input: "ram_ra", + }); + }; + require_operand_count( + "stage4.ram.write_address_indices", + witness.trace_len, + write_address_indices.len(), + )?; + write_address_indices + .iter() + .map(|address| match address { + Some(address) => { + address_eq + .get(*address) + .copied() + .ok_or(Stage4KernelError::InvalidInputLength { + input: "stage4.ram.write_address_indices", + expected: address_eq.len(), + actual: address + 1, + }) + } + None => Ok(F::zero()), + }) + .collect() +} + +fn round_poly_from_dense_terms( + factors: &[Vec], + terms: &[DenseTerm], + active_scale: F, + relation: Stage4Relation, +) -> Result, Stage4KernelError> { + let half = factors.first().map_or(0, |factor| factor.len() / 2); + for term in terms { + if term.factors.len() > 3 { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 dense term exceeds degree bound", + }); + } + if term.factors.iter().any(|factor| *factor >= factors.len()) { + return Err(Stage4KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage4 dense term references missing factor", + }); + } + } + + let accumulators = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .map(|row| dense_row_coefficients(factors, terms, row)) + .reduce( + || [F::Accumulator::default(); 4], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + (0..half).fold([F::Accumulator::default(); 4], |mut total, row| { + let row_coefficients = dense_row_coefficients(factors, terms, row); + for index in 0..total.len() { + total[index].merge(row_coefficients[index]); + } + total + }) + }; + + Ok(UnivariatePoly::new( + accumulators + .into_iter() + .map(AdditiveAccumulator::reduce) + .map(|coefficient| coefficient * active_scale) + .collect(), + )) +} + +fn dense_row_coefficients( + factors: &[Vec], + terms: &[DenseTerm], + row: usize, +) -> [F::Accumulator; 4] { + let mut coefficients = [F::Accumulator::default(); 4]; + for term in terms { + match term.factors.as_slice() { + [] => coefficients[0].add(term.coefficient), + [first] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + coefficients[0].fmadd(term.coefficient, first0); + coefficients[1].fmadd(term.coefficient, first_delta); + } + [first, second] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + let (second0, second_delta) = linear_factor_pair(&factors[*second], row); + accumulate_quadratic_coefficients( + &mut coefficients, + term.coefficient, + first0, + first_delta, + second0, + second_delta, + ); + } + [first, second, third] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + let (second0, second_delta) = linear_factor_pair(&factors[*second], row); + let (third0, third_delta) = linear_factor_pair(&factors[*third], row); + accumulate_cubic_coefficients( + &mut coefficients, + term.coefficient, + first0, + first_delta, + second0, + second_delta, + third0, + third_delta, + ); + } + _ => unreachable!("dense terms are validated before evaluation"), + } + } + coefficients +} + +#[inline] +fn linear_factor_pair(factor: &[F], row: usize) -> (F, F) { + let low = factor[2 * row]; + (low, factor[2 * row + 1] - low) +} + +#[inline] +fn accumulate_quadratic_coefficients( + coefficients: &mut [F::Accumulator; 4], + scale: F, + first0: F, + first_delta: F, + second0: F, + second_delta: F, +) { + coefficients[0].fmadd(scale * first0, second0); + coefficients[1].fmadd(scale * first_delta, second0); + coefficients[1].fmadd(scale * first0, second_delta); + coefficients[2].fmadd(scale * first_delta, second_delta); +} + +#[inline] +fn accumulate_cubic_coefficients( + coefficients: &mut [F::Accumulator; 4], + scale: F, + first0: F, + first_delta: F, + second0: F, + second_delta: F, + third0: F, + third_delta: F, +) { + let second0_third0 = second0 * third0; + let second_delta_third0 = second_delta * third0; + let second0_third_delta = second0 * third_delta; + let second_delta_third_delta = second_delta * third_delta; + let scaled_first0 = scale * first0; + let scaled_first_delta = scale * first_delta; + + coefficients[0].fmadd(scaled_first0, second0_third0); + coefficients[1].fmadd(scaled_first_delta, second0_third0); + coefficients[1].fmadd(scaled_first0, second_delta_third0); + coefficients[1].fmadd(scaled_first0, second0_third_delta); + coefficients[2].fmadd(scaled_first_delta, second_delta_third0); + coefficients[2].fmadd(scaled_first_delta, second0_third_delta); + coefficients[2].fmadd(scaled_first0, second_delta_third_delta); + coefficients[3].fmadd(scaled_first_delta, second_delta_third_delta); +} + +fn expected_batched_output_claim( + context: Stage4KernelContext<'_>, + store: &Stage4ValueStore, + evals: &[Stage4NamedEval], + point: &[F], + batching_coeffs: &[F], +) -> Result { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let instance = context + .program + .instance_results + .iter() + .find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) + .ok_or(Stage4KernelError::MissingClaim { + batch: context.batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage4KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let claim_value = match Stage4Relation::from_symbol(instance.relation).ok_or( + Stage4KernelError::UnknownRelation { + relation: instance.relation, + }, + )? { + Stage4Relation::RegistersReadWrite => { + expected_registers_read_write(store, evals, local_point)? + } + Stage4Relation::RamValCheck => expected_ram_val_check(store, evals, local_point)?, + relation @ Stage4Relation::Batched => { + return Err(Stage4KernelError::KernelNotImplemented { + abi: relation.symbol(), + }) + } + }; + expected += coefficient * claim_value; + } + Ok(expected) +} + +fn expected_registers_read_write( + store: &Stage4ValueStore, + evals: &[Stage4NamedEval], + local_point: &[F], +) -> Result { + let trace_point = store.point("stage4.input.stage3.registers.RdWriteValue")?; + let r_cycle = normalize_stage4_registers_rw_cycle_point( + local_point, + trace_point.len(), + "stage4.registers_read_write.instance", + )?; + let eq_eval = EqPolynomial::::mle(&r_cycle, trace_point); + let registers_val = eval_by_name(evals, "stage4.registers_read_write.eval.RegistersVal")?; + let rs1_ra = eval_by_name(evals, "stage4.registers_read_write.eval.Rs1Ra")?; + let rs2_ra = eval_by_name(evals, "stage4.registers_read_write.eval.Rs2Ra")?; + let rd_wa = eval_by_name(evals, "stage4.registers_read_write.eval.RdWa")?; + let rd_inc = eval_by_name(evals, "stage4.registers_read_write.eval.RdInc")?; + let gamma = store.scalar("stage4.registers_read_write.gamma")?; + Ok(eq_eval + * (rd_wa * (registers_val + rd_inc) + + gamma * (rs1_ra * registers_val + gamma * rs2_ra * registers_val))) +} + +fn expected_ram_val_check( + store: &Stage4ValueStore, + evals: &[Stage4NamedEval], + local_point: &[F], +) -> Result { + let ram_val_point = store.point("stage4.input.stage2.RamVal")?; + let r_cycle_prime = reverse_slice(local_point); + let r_cycle = suffix_point( + ram_val_point, + r_cycle_prime.len(), + "stage4.input.stage2.RamVal", + )?; + let lt_eval = lt_polynomial_eval(&r_cycle_prime, r_cycle); + let gamma = store.scalar("stage4.ram_val_check.gamma")?; + let ram_ra = eval_by_name(evals, "stage4.ram_val_check.eval.RamRa")?; + let ram_inc = eval_by_name(evals, "stage4.ram_val_check.eval.RamInc")?; + Ok(ram_inc * ram_ra * (lt_eval + gamma)) +} + +fn eval_by_name( + evals: &[Stage4NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage4KernelError::MissingValue { symbol: name }) +} + +fn named_eval(name: &'static str, oracle: &'static str, value: F) -> Stage4NamedEval { + Stage4NamedEval { + name, + oracle, + value, + } +} + +fn claim_relation( + program: &'static Stage4CpuProgramPlan, + claim: &Stage4SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage4Relation::from_symbol(relation) + .ok_or(Stage4KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage4KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage4KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + kernel.relation_kind() +} + +fn instance_round_offset( + program: &'static Stage4CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage4KernelError::MissingClaim { + batch: driver, + claim, + }) +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + UnivariatePoly::new(combined) +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims( + program: &'static Stage4CpuProgramPlan, + store: &mut Stage4ValueStore, + transcript: &mut T, + evals: &[Stage4NamedEval], +) -> Result>, Stage4KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + let mut seen = seed_stage4_opening_aliases(store, program); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage4KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let value = store.scalar(claim.eval_source)?; + let duplicate = has_seen_opening(&seen, claim.claim_kind, claim.oracle, &point); + if !duplicate { + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point.clone())); + } + opening_claims.push(Stage4OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: point.clone(), + eval: value, + }); + } + } + Ok(opening_claims) +} + +fn seed_stage4_opening_aliases( + store: &Stage4ValueStore, + program: &'static Stage4CpuProgramPlan, +) -> Vec<(&'static str, &'static str, Vec)> { + program + .opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect() +} + +fn has_seen_opening( + seen: &[(&'static str, &'static str, Vec)], + claim_kind: &'static str, + oracle: &'static str, + point: &[F], +) -> bool { + seen.iter().any(|(seen_kind, seen_oracle, seen_point)| { + *seen_kind == claim_kind && *seen_oracle == oracle && seen_point.as_slice() == point + }) +} + +fn find_opening_claim<'a>( + program: &'a Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage4OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +fn normalize_stage4_registers_rw_point( + program: &'static Stage4CpuProgramPlan, + driver: &'static str, + point: &[F], +) -> Result, Stage4KernelError> { + let driver_plan = + find_driver(program, driver).ok_or(Stage4KernelError::MissingDriver { driver })?; + if driver_plan.round_schedule.len() != 2 { + return Err(Stage4KernelError::InvalidProof { + driver, + reason: "stage4 registers point normalization requires [cycle, address] schedule", + }); + } + let cycle_rounds = driver_plan.round_schedule[0]; + let address_rounds = driver_plan.round_schedule[1]; + if point.len() != cycle_rounds + address_rounds { + return Err(Stage4KernelError::InvalidInputLength { + input: "stage4.registers_read_write.instance", + expected: cycle_rounds + address_rounds, + actual: point.len(), + }); + } + let (cycle, address) = point.split_at(cycle_rounds); + Ok(address + .iter() + .rev() + .copied() + .chain(cycle.iter().rev().copied()) + .collect()) +} + +fn normalize_stage4_registers_rw_cycle_point( + point: &[F], + cycle_rounds: usize, + input: &'static str, +) -> Result, Stage4KernelError> { + let cycle = point + .get(..cycle_rounds) + .filter(|cycle| cycle.len() == cycle_rounds) + .ok_or(Stage4KernelError::InvalidInputLength { + input, + expected: cycle_rounds, + actual: point.len(), + })?; + Ok(cycle.iter().rev().copied().collect()) +} + +fn suffix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], Stage4KernelError> { + point + .get(point.len().saturating_sub(length)..) + .filter(|suffix| suffix.len() == length) + .ok_or(Stage4KernelError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +fn reverse_slice(values: &[F]) -> Vec { + values.iter().rev().copied().collect() +} + +fn lt_polynomial_eval(x: &[F], y: &[F]) -> F { + debug_assert_eq!(x.len(), y.len()); + let mut lt_eval = F::zero(); + let mut eq_term = F::one(); + for (x_i, y_i) in x.iter().zip(y.iter()) { + lt_eval += (F::one() - *x_i) * *y_i * eq_term; + eq_term *= F::one() - *x_i - *y_i + *x_i * *y_i + *x_i * *y_i; + } + lt_eval +} + +fn lt_evals_big_endian(point: &[F]) -> Vec { + let mut evals = vec![F::zero(); 1usize << point.len()]; + for (index, r) in point.iter().rev().enumerate() { + let (left, right) = evals.split_at_mut(1usize << index); + left.iter_mut().zip(right).for_each(|(left, right)| { + *right = *left * *r; + *left += *r - *right; + }); + } + evals +} + +#[cfg(test)] +fn boolean_point_from_index(index: usize, bits: usize) -> Vec { + (0..bits) + .rev() + .map(|bit| F::from_bool(((index >> bit) & 1) == 1)) + .collect() +} + +fn log2_exact(value: usize, input: &'static str) -> Result { + if value.is_power_of_two() { + Ok(value.ilog2() as usize) + } else { + Err(Stage4KernelError::InvalidInputLength { + input, + expected: value.next_power_of_two(), + actual: value, + }) + } +} + +fn verify_count( + artifact: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage4KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage4KernelError::PlanCountMismatch { + artifact, + expected, + actual, + }) + } +} + +fn find_squeeze( + program: &'static Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage4TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|squeeze| squeeze.symbol == symbol) +} + +fn find_absorb_bytes( + program: &'static Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage4TranscriptAbsorbBytesPlan> { + program + .transcript_absorb_bytes + .iter() + .find(|absorb| absorb.symbol == symbol) +} + +fn find_driver( + program: &'static Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage4SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_kernel( + program: &'static Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage4KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch( + program: &'static Stage4CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage4SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage4KernelError { + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + MissingDriver { + driver: &'static str, + }, + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage4ExecutionMode, + actual: Stage4ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProgramStep { + symbol: &'static str, + kind: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage4KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage4 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage4 value @{symbol} is not available") + } + Self::MissingDriver { driver } => { + write!(formatter, "stage4 driver @{driver} is not available") + } + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage4 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage4 driver @{driver} references missing batch @{batch}" + ) + } + Self::UnknownRelation { relation } => { + write!(formatter, "stage4 relation @{relation} is not registered") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "stage4 kernel ABI `{abi}` is not registered") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => write!( + formatter, + "stage4 plan @{artifact} count mismatch: expected {expected}, got {actual}" + ), + Self::InvalidInputLength { + input, + expected, + actual, + } => write!( + formatter, + "stage4 input `{input}` length mismatch: expected {expected}, got {actual}" + ), + Self::UnsupportedFieldExpr { symbol, formula } => write!( + formatter, + "stage4 field expr @{symbol} uses unsupported formula `{formula}`" + ), + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage4 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => write!( + formatter, + "stage4 driver @{driver} ran with {actual:?} executor path, expected {expected:?}" + ), + Self::MissingProof { driver } => { + write!( + formatter, + "stage4 verifier missing proof for driver @{driver}" + ) + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage4 kernel `{kernel}` missing input `{input}`" + ) + } + Self::InvalidProgramStep { symbol, kind } => { + write!( + formatter, + "stage4 program step @{symbol} has unsupported kind `{kind}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage4 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage4KernelError {} + +#[cfg(test)] +#[expect(clippy::expect_used, reason = "stage4 kernel tests fail fast")] +mod tests { + use super::*; + use jolt_field::Fr; + use jolt_transcript::Blake2bTranscript; + + #[test] + fn lt_evals_big_endian_matches_pointwise() { + let point = frs(&[3, 5, 7]); + let table = lt_evals_big_endian(&point); + + assert_eq!(table.len(), 8); + for (index, value) in table.iter().enumerate() { + let bits = boolean_point_from_index::(index, point.len()); + assert_eq!(*value, lt_polynomial_eval(&bits, &point)); + } + } + + #[test] + fn stage4_batched_kernel_proves_and_verifies_synthetic_witness() { + let program = synthetic_stage4_program(); + let data = SyntheticStage4Data::new(); + let opening_inputs = data.opening_inputs(); + let prover_inputs = Stage4ProverInputs::new(&opening_inputs) + .with_registers(data.registers_witness()) + .with_ram(data.ram_witness()); + let mut prover = Stage4ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage4_test"); + + let artifacts = execute_stage4_program( + program, + Stage4ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage4 prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].proof.round_polynomials.len(), 3); + let proof = Stage4Proof::from(artifacts); + let mut verifier = Stage4VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage4_test"); + let verified = execute_stage4_program( + program, + Stage4ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage4 verifier accepts prover proof"); + + assert_eq!(verified.sumchecks.len(), 1); + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + } + + #[test] + fn stage4_batched_kernel_proves_with_sparse_ram_addresses() { + let program = synthetic_stage4_program(); + let data = SyntheticStage4Data::new(); + let opening_inputs = data.opening_inputs(); + let prover_inputs = Stage4ProverInputs::new(&opening_inputs) + .with_registers(data.registers_witness()) + .with_ram(data.sparse_ram_witness()); + let mut prover = Stage4ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage4_test"); + + let artifacts = execute_stage4_program( + program, + Stage4ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage4 prover succeeds with sparse RAM addresses"); + + let proof = Stage4Proof::from(artifacts); + let mut verifier = Stage4VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage4_test"); + let verified = execute_stage4_program( + program, + Stage4ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage4 verifier accepts sparse RAM proof"); + + assert_eq!(verified.sumchecks.len(), 1); + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + } + + #[test] + fn stage4_batched_kernel_proves_with_sparse_register_accesses() { + let program = synthetic_stage4_program(); + let data = SyntheticStage4Data::new(); + let opening_inputs = data.opening_inputs(); + let prover_inputs = Stage4ProverInputs::new(&opening_inputs) + .with_registers(data.sparse_registers_witness()) + .with_ram(data.sparse_ram_witness()); + let mut prover = Stage4ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage4_test"); + + let artifacts = execute_stage4_program( + program, + Stage4ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage4 prover succeeds with sparse register accesses"); + + let proof = Stage4Proof::from(artifacts); + let mut verifier = Stage4VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage4_test"); + let verified = execute_stage4_program( + program, + Stage4ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage4 verifier accepts sparse register proof"); + + assert_eq!(verified.sumchecks.len(), 1); + assert_eq!(prover_transcript.state(), verifier_transcript.state()); + } + + #[test] + fn stage4_batched_kernel_rejects_tampered_eval() { + let program = synthetic_stage4_program(); + let data = SyntheticStage4Data::new(); + let opening_inputs = data.opening_inputs(); + let mut prover = Stage4ProverKernelExecutor::new( + Stage4ProverInputs::new(&opening_inputs) + .with_registers(data.registers_witness()) + .with_ram(data.ram_witness()), + ); + let mut prover_transcript = Blake2bTranscript::::new(b"stage4_test"); + let mut proof = Stage4Proof::from( + execute_stage4_program( + program, + Stage4ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage4 prover succeeds"), + ); + proof.sumchecks[0].evals[0].value += Fr::from_u64(1); + + let mut verifier = Stage4VerifierKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage4_test"); + let error = execute_stage4_program( + program, + Stage4ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered proof is rejected"); + + assert!(matches!(error, Stage4KernelError::InvalidProof { .. })); + } + + #[test] + fn sparse_trace_witness_from_accesses_groups_stage4_and_stage2_accesses() { + let register_accesses = [ + Stage4RegisterAccess { + rd: Some(Stage4RegisterWrite { + address: 2, + pre_value: 5, + post_value: 9, + }), + ..Stage4RegisterAccess::default() + }, + Stage4RegisterAccess::default(), + ]; + let ram_accesses = [ + Stage2RamAccess { + remapped_address: Some(7), + read_value: 11, + write_value: 3, + }, + Stage2RamAccess::noop(), + ]; + + let witness = + stage4_5_sparse_trace_witness_from_accesses::(®ister_accesses, &ram_accesses); + + assert_eq!(witness.rd_inc, vec![Fr::from_u64(4), Fr::from_u64(0)]); + assert_eq!(witness.rd_write_addresses, vec![Some(2), None]); + assert_eq!(witness.ram_addresses, vec![Some(7), None]); + assert_eq!(witness.ram_inc, vec![-Fr::from_u64(8), Fr::from_u64(0)]); + } + + #[derive(Clone)] + struct SyntheticStage4Data { + registers_val: Vec, + rs1_ra: Vec, + rs2_ra: Vec, + rd_wa: Vec, + register_accesses: Vec, + rd_inc: Vec, + ram_ra: Vec, + ram_write_addresses: Vec>, + ram_inc: Vec, + } + + impl SyntheticStage4Data { + fn new() -> Self { + Self { + registers_val: frs(&[10, 12, 12, 15, 20, 20, 21, 21]), + rs1_ra: frs(&[1, 0, 1, 0, 0, 1, 0, 1]), + rs2_ra: frs(&[0, 1, 0, 1, 1, 0, 1, 0]), + rd_wa: frs(&[1, 0, 1, 0, 0, 1, 0, 1]), + register_accesses: synthetic_register_accesses(), + rd_inc: frs(&[2, 1, 3, 4]), + ram_ra: frs(&[1, 0, 1, 0, 0, 1, 0, 1]), + ram_write_addresses: vec![Some(0), Some(1), Some(0), Some(1)], + ram_inc: frs(&[5, 7, 0, 2]), + } + } + + fn registers_witness(&self) -> Stage4RegistersWitness<'_, Fr> { + Stage4RegistersWitness { + register_count: 2, + trace_len: 4, + registers_val: &self.registers_val, + rs1_ra: &self.rs1_ra, + rs2_ra: &self.rs2_ra, + rd_wa: &self.rd_wa, + accesses: None, + rd_inc: &self.rd_inc, + } + } + + fn sparse_registers_witness(&self) -> Stage4RegistersWitness<'_, Fr> { + Stage4RegistersWitness { + register_count: 2, + trace_len: 4, + registers_val: &[], + rs1_ra: &[], + rs2_ra: &[], + rd_wa: &[], + accesses: Some(&self.register_accesses), + rd_inc: &self.rd_inc, + } + } + + fn ram_witness(&self) -> Stage4RamWitness<'_, Fr> { + Stage4RamWitness { + ram_k: 2, + trace_len: 4, + ram_ra: &self.ram_ra, + write_address_indices: None, + ram_inc: &self.ram_inc, + } + } + + fn sparse_ram_witness(&self) -> Stage4RamWitness<'_, Fr> { + Stage4RamWitness { + ram_k: 2, + trace_len: 4, + ram_ra: &[], + write_address_indices: Some(&self.ram_write_addresses), + ram_inc: &self.ram_inc, + } + } + + fn opening_inputs(&self) -> Vec> { + let trace_point = frs(&[5, 7]); + let ram_address_point = frs(&[11]); + let ram_cycle_point = frs(&[13, 17]); + let ram_val_point = [ram_address_point.as_slice(), ram_cycle_point.as_slice()].concat(); + let rd_write_values = self.rd_write_values(); + let rs1_values = self.read_values(&self.rs1_ra); + let rs2_values = self.read_values(&self.rs2_ra); + let ram_init = ram_initial_eval(&ram_address_point); + let ram_ra_at_address = self.ram_ra_at_address(&ram_address_point); + let ram_val_delta = ram_val_delta(&ram_ra_at_address, &self.ram_inc, &ram_cycle_point); + let ram_final_delta = ram_final_delta(&ram_ra_at_address, &self.ram_inc); + vec![ + opening( + "stage4.input.stage3.registers.RdWriteValue", + &trace_point, + mle_eval(&rd_write_values, &trace_point), + ), + opening( + "stage4.input.stage3.registers.Rs1Value", + &trace_point, + mle_eval(&rs1_values, &trace_point), + ), + opening( + "stage4.input.stage3.registers.Rs2Value", + &trace_point, + mle_eval(&rs2_values, &trace_point), + ), + opening( + "stage4.input.stage3.instruction.Rs1Value", + &trace_point, + mle_eval(&rs1_values, &trace_point), + ), + opening( + "stage4.input.stage3.instruction.Rs2Value", + &trace_point, + mle_eval(&rs2_values, &trace_point), + ), + opening( + "stage4.input.stage2.RamVal", + &ram_val_point, + ram_init + ram_val_delta, + ), + opening( + "stage4.input.stage2.RamValFinal", + &ram_address_point, + ram_init + ram_final_delta, + ), + opening( + "stage4.input.initial_ram.RamValInit", + &ram_address_point, + ram_init, + ), + ] + } + + fn rd_write_values(&self) -> Vec { + (0..4) + .map(|cycle| { + (0..2) + .map(|address| { + let index = address * 4 + cycle; + self.rd_wa[index] * (self.registers_val[index] + self.rd_inc[cycle]) + }) + .sum() + }) + .collect() + } + + fn read_values(&self, read_address: &[Fr]) -> Vec { + (0..4) + .map(|cycle| { + (0..2) + .map(|address| { + let index = address * 4 + cycle; + read_address[index] * self.registers_val[index] + }) + .sum() + }) + .collect() + } + + fn ram_ra_at_address(&self, address_point: &[Fr]) -> Vec { + let address_eq = EqPolynomial::::evals(address_point, None); + (0..4) + .map(|cycle| { + (0..2) + .map(|address| address_eq[address] * self.ram_ra[address * 4 + cycle]) + .sum() + }) + .collect() + } + } + + fn synthetic_stage4_program() -> &'static Stage4CpuProgramPlan { + Box::leak(Box::new(Stage4CpuProgramPlan { + role: "prover", + params: Stage4Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }, + steps: leak_slice(vec![ + Stage4ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage4.registers_read_write.gamma", + }, + Stage4ProgramStepPlan { + kind: "transcript_absorb_bytes", + symbol: "stage4.ram_val_check.domain_separator", + }, + Stage4ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage4.ram_val_check.gamma", + }, + Stage4ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage4.sumcheck", + }, + ]), + transcript_squeezes: leak_slice(vec![ + Stage4TranscriptSqueezePlan { + symbol: "stage4.registers_read_write.gamma", + label: "registers_read_write_gamma", + kind: "challenge_scalar", + count: 1, + }, + Stage4TranscriptSqueezePlan { + symbol: "stage4.ram_val_check.gamma", + label: "ram_val_check_gamma", + kind: "challenge_scalar", + count: 1, + }, + ]), + transcript_absorb_bytes: leak_slice(vec![Stage4TranscriptAbsorbBytesPlan { + symbol: "stage4.ram_val_check.domain_separator", + label: "ram_val_check_gamma", + payload: "", + }]), + opening_inputs: leak_slice(stage4_opening_input_plans()), + field_constants: &[], + field_exprs: leak_slice(stage4_field_exprs()), + kernels: leak_slice(vec![ + kernel( + "jolt.cpu.stage4.registers_read_write", + "jolt.stage4.registers_read_write", + "jolt_stage4_registers_read_write", + ), + kernel( + "jolt.cpu.stage4.ram_val_check", + "jolt.stage4.ram_val_check", + "jolt_stage4_ram_val_check", + ), + kernel( + "jolt.cpu.stage4.batched", + "jolt.stage4.batched", + "jolt_stage4_batched", + ), + ]), + claims: leak_slice(vec![ + Stage4SumcheckClaimPlan { + symbol: "stage4.registers_read_write.input", + stage: "stage4", + domain: "jolt.stage4_registers_rw_domain", + num_rounds: 3, + degree: 3, + claim: "stage4.registers_read_write.weighted_values", + kernel: Some("jolt.cpu.stage4.registers_read_write"), + relation: None, + claim_value: "stage4.registers_read_write.claim_expr", + input_openings: leak_slice(vec![ + "stage4.input.stage3.registers.RdWriteValue", + "stage4.input.stage3.registers.Rs1Value", + "stage4.input.stage3.registers.Rs2Value", + ]), + }, + Stage4SumcheckClaimPlan { + symbol: "stage4.ram_val_check.input", + stage: "stage4", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 3, + claim: "stage4.ram_val_check.weighted_values", + kernel: Some("jolt.cpu.stage4.ram_val_check"), + relation: None, + claim_value: "stage4.ram_val_check.claim_expr", + input_openings: leak_slice(vec![ + "stage4.input.stage2.RamVal", + "stage4.input.stage2.RamValFinal", + "stage4.input.initial_ram.RamValInit", + ]), + }, + ]), + batches: leak_slice(vec![Stage4SumcheckBatchPlan { + symbol: "stage4.batch", + stage: "stage4", + proof_slot: "stage4.sumcheck", + policy: "jolt_core_stage4_aligned", + count: 2, + ordered_claims: leak_slice(vec![ + "stage4.registers_read_write.input", + "stage4.ram_val_check.input", + ]), + claim_operands: leak_slice(vec![ + "stage4.registers_read_write.input", + "stage4.ram_val_check.input", + ]), + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: leak_slice(vec![2, 1]), + }]), + drivers: leak_slice(vec![Stage4SumcheckDriverPlan { + symbol: "stage4.sumcheck", + stage: "stage4", + proof_slot: "stage4.sumcheck", + kernel: Some("jolt.cpu.stage4.batched"), + relation: None, + batch: "stage4.batch", + policy: "jolt_core_stage4_aligned", + round_schedule: leak_slice(vec![2, 1]), + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 3, + degree: 3, + }]), + instance_results: leak_slice(vec![ + Stage4SumcheckInstanceResultPlan { + symbol: "stage4.registers_read_write.instance", + source: "stage4.sumcheck", + claim: "stage4.registers_read_write.input", + relation: "jolt.stage4.registers_read_write", + index: 0, + point_arity: 3, + num_rounds: 3, + round_offset: 0, + point_order: "stage4_registers_rw", + degree: 3, + }, + Stage4SumcheckInstanceResultPlan { + symbol: "stage4.ram_val_check.instance", + source: "stage4.sumcheck", + claim: "stage4.ram_val_check.input", + relation: "jolt.stage4.ram_val_check", + index: 1, + point_arity: 2, + num_rounds: 2, + round_offset: 1, + point_order: "reverse", + degree: 3, + }, + ]), + evals: leak_slice(stage4_eval_plans()), + point_slices: leak_slice(vec![ + Stage4PointSlicePlan { + symbol: "stage4.registers_read_write.point.RdInc", + source: "stage4.registers_read_write.instance", + offset: 1, + length: 2, + input: "stage4.registers_read_write.instance", + }, + Stage4PointSlicePlan { + symbol: "stage4.ram_val_check.point.RamAddress", + source: "stage4.input.stage2.RamVal", + offset: 0, + length: 1, + input: "stage4.input.stage2.RamVal", + }, + ]), + point_concats: leak_slice(vec![Stage4PointConcatPlan { + symbol: "stage4.ram_val_check.point.RamRa", + layout: "address_then_cycle", + arity: 3, + inputs: leak_slice(vec![ + "stage4.ram_val_check.point.RamAddress", + "stage4.ram_val_check.instance", + ]), + }]), + opening_claims: leak_slice(stage4_opening_claim_plans()), + opening_equalities: leak_slice(vec![ + Stage4OpeningClaimEqualityPlan { + symbol: "stage4.registers.rs1_claim_consistency", + mode: "point_and_eval", + lhs: "stage4.input.stage3.registers.Rs1Value", + rhs: "stage4.input.stage3.instruction.Rs1Value", + }, + Stage4OpeningClaimEqualityPlan { + symbol: "stage4.registers.rs2_claim_consistency", + mode: "point_and_eval", + lhs: "stage4.input.stage3.registers.Rs2Value", + rhs: "stage4.input.stage3.instruction.Rs2Value", + }, + ]), + opening_batches: leak_slice(vec![Stage4OpeningBatchPlan { + symbol: "stage4.openings", + stage: "stage4", + proof_slot: "stage4.openings", + policy: "jolt_stage4_output_order", + count: 7, + ordered_claims: leak_slice( + stage4_opening_claim_plans() + .iter() + .map(|claim| claim.symbol) + .collect(), + ), + claim_operands: leak_slice( + stage4_opening_claim_plans() + .iter() + .map(|claim| claim.symbol) + .collect(), + ), + }]), + })) + } + + fn stage4_field_exprs() -> Vec { + vec![ + field_expr( + "stage4.registers_read_write.gamma2", + "field.pow:2", + vec!["stage4.registers_read_write.gamma"], + ), + field_expr( + "stage4.registers_read_write.term.Rs1Value", + "field.mul", + vec![ + "stage4.registers_read_write.gamma", + "stage4.input.stage3.registers.Rs1Value", + ], + ), + field_expr( + "stage4.registers_read_write.term.Rs2Value", + "field.mul", + vec![ + "stage4.registers_read_write.gamma2", + "stage4.input.stage3.registers.Rs2Value", + ], + ), + field_expr( + "stage4.registers_read_write.partial.RdWriteValueRs1Value", + "field.add", + vec![ + "stage4.input.stage3.registers.RdWriteValue", + "stage4.registers_read_write.term.Rs1Value", + ], + ), + field_expr( + "stage4.registers_read_write.claim_expr", + "field.add", + vec![ + "stage4.registers_read_write.partial.RdWriteValueRs1Value", + "stage4.registers_read_write.term.Rs2Value", + ], + ), + field_expr( + "stage4.ram_val_check.delta.RamVal", + "field.sub", + vec![ + "stage4.input.stage2.RamVal", + "stage4.input.initial_ram.RamValInit", + ], + ), + field_expr( + "stage4.ram_val_check.delta.RamValFinal", + "field.sub", + vec![ + "stage4.input.stage2.RamValFinal", + "stage4.input.initial_ram.RamValInit", + ], + ), + field_expr( + "stage4.ram_val_check.term.RamValFinal", + "field.mul", + vec![ + "stage4.ram_val_check.gamma", + "stage4.ram_val_check.delta.RamValFinal", + ], + ), + field_expr( + "stage4.ram_val_check.claim_expr", + "field.add", + vec![ + "stage4.ram_val_check.delta.RamVal", + "stage4.ram_val_check.term.RamValFinal", + ], + ), + ] + } + + fn stage4_opening_input_plans() -> Vec { + vec![ + opening_input_plan( + "stage4.input.stage3.registers.RdWriteValue", + "RdWriteValue", + 2, + ), + opening_input_plan("stage4.input.stage3.registers.Rs1Value", "Rs1Value", 2), + opening_input_plan("stage4.input.stage3.registers.Rs2Value", "Rs2Value", 2), + opening_input_plan("stage4.input.stage3.instruction.Rs1Value", "Rs1Value", 2), + opening_input_plan("stage4.input.stage3.instruction.Rs2Value", "Rs2Value", 2), + opening_input_plan("stage4.input.stage2.RamVal", "RamVal", 3), + opening_input_plan("stage4.input.stage2.RamValFinal", "RamValFinal", 1), + opening_input_plan("stage4.input.initial_ram.RamValInit", "RamValInit", 1), + ] + } + + fn stage4_eval_plans() -> Vec { + vec![ + eval( + "stage4.registers_read_write.eval.RegistersVal", + "RegistersVal", + 0, + ), + eval("stage4.registers_read_write.eval.Rs1Ra", "Rs1Ra", 1), + eval("stage4.registers_read_write.eval.Rs2Ra", "Rs2Ra", 2), + eval("stage4.registers_read_write.eval.RdWa", "RdWa", 3), + eval("stage4.registers_read_write.eval.RdInc", "RdInc", 4), + eval("stage4.ram_val_check.eval.RamRa", "RamRa", 0), + eval("stage4.ram_val_check.eval.RamInc", "RamInc", 1), + ] + } + + fn stage4_opening_claim_plans() -> Vec { + vec![ + opening_claim( + "stage4.registers_read_write.opening.RegistersVal", + "RegistersVal", + "stage4.registers_read_write.instance", + "stage4.registers_read_write.eval.RegistersVal", + 3, + "virtual", + ), + opening_claim( + "stage4.registers_read_write.opening.Rs1Ra", + "Rs1Ra", + "stage4.registers_read_write.instance", + "stage4.registers_read_write.eval.Rs1Ra", + 3, + "virtual", + ), + opening_claim( + "stage4.registers_read_write.opening.Rs2Ra", + "Rs2Ra", + "stage4.registers_read_write.instance", + "stage4.registers_read_write.eval.Rs2Ra", + 3, + "virtual", + ), + opening_claim( + "stage4.registers_read_write.opening.RdWa", + "RdWa", + "stage4.registers_read_write.instance", + "stage4.registers_read_write.eval.RdWa", + 3, + "virtual", + ), + opening_claim( + "stage4.registers_read_write.opening.RdInc", + "RdInc", + "stage4.registers_read_write.point.RdInc", + "stage4.registers_read_write.eval.RdInc", + 2, + "committed", + ), + opening_claim( + "stage4.ram_val_check.opening.RamRa", + "RamRa", + "stage4.ram_val_check.point.RamRa", + "stage4.ram_val_check.eval.RamRa", + 3, + "virtual", + ), + opening_claim( + "stage4.ram_val_check.opening.RamInc", + "RamInc", + "stage4.ram_val_check.instance", + "stage4.ram_val_check.eval.RamInc", + 2, + "committed", + ), + ] + } + + fn field_expr( + symbol: &'static str, + formula: &'static str, + operands: Vec<&'static str>, + ) -> Stage4FieldExprPlan { + let operands = leak_slice(operands); + Stage4FieldExprPlan { + symbol, + kind: "op", + formula, + operand_names: operands, + operands, + } + } + + fn kernel(symbol: &'static str, relation: &'static str, abi: &'static str) -> Stage4KernelPlan { + Stage4KernelPlan { + symbol, + relation, + kind: "sumcheck", + backend: "cpu", + abi, + } + } + + fn opening_input_plan( + symbol: &'static str, + oracle: &'static str, + point_arity: usize, + ) -> Stage4OpeningInputPlan { + Stage4OpeningInputPlan { + symbol, + source_stage: "synthetic", + source_claim: symbol, + oracle, + domain: "synthetic", + point_arity, + claim_kind: "virtual", + } + } + + fn eval(symbol: &'static str, oracle: &'static str, index: usize) -> Stage4SumcheckEvalPlan { + Stage4SumcheckEvalPlan { + symbol, + source: "stage4.sumcheck", + name: symbol, + index, + oracle, + } + } + + fn opening_claim( + symbol: &'static str, + oracle: &'static str, + point_source: &'static str, + eval_source: &'static str, + point_arity: usize, + claim_kind: &'static str, + ) -> Stage4OpeningClaimPlan { + Stage4OpeningClaimPlan { + symbol, + oracle, + domain: "synthetic", + point_arity, + claim_kind, + point_source, + eval_source, + } + } + + fn opening(symbol: &'static str, point: &[Fr], eval: Fr) -> Stage4OpeningInputValue { + Stage4OpeningInputValue { + symbol, + point: point.to_vec(), + eval, + } + } + + fn mle_eval(values: &[Fr], point: &[Fr]) -> Fr { + EqPolynomial::::evals(point, None) + .iter() + .zip(values) + .map(|(&weight, &value)| weight * value) + .sum() + } + + fn ram_initial_eval(address_point: &[Fr]) -> Fr { + let initial = frs(&[11, 13]); + mle_eval(&initial, address_point) + } + + fn ram_val_delta(ram_ra_at_address: &[Fr], ram_inc: &[Fr], cycle_point: &[Fr]) -> Fr { + (0..4) + .map(|cycle| { + let cycle_bits = boolean_point_from_index::(cycle, 2); + ram_inc[cycle] + * ram_ra_at_address[cycle] + * lt_polynomial_eval(&cycle_bits, cycle_point) + }) + .sum() + } + + fn ram_final_delta(ram_ra_at_address: &[Fr], ram_inc: &[Fr]) -> Fr { + ram_ra_at_address + .iter() + .zip(ram_inc) + .map(|(&ra, &inc)| ra * inc) + .sum() + } + + fn synthetic_register_accesses() -> Vec { + vec![ + Stage4RegisterAccess { + rs1: Some(Stage4RegisterRead { + address: 0, + value: 10, + }), + rs2: Some(Stage4RegisterRead { + address: 1, + value: 20, + }), + rd: Some(Stage4RegisterWrite { + address: 0, + pre_value: 10, + post_value: 12, + }), + }, + Stage4RegisterAccess { + rs1: Some(Stage4RegisterRead { + address: 1, + value: 20, + }), + rs2: Some(Stage4RegisterRead { + address: 0, + value: 12, + }), + rd: Some(Stage4RegisterWrite { + address: 1, + pre_value: 20, + post_value: 21, + }), + }, + Stage4RegisterAccess { + rs1: Some(Stage4RegisterRead { + address: 0, + value: 12, + }), + rs2: Some(Stage4RegisterRead { + address: 1, + value: 21, + }), + rd: Some(Stage4RegisterWrite { + address: 0, + pre_value: 12, + post_value: 15, + }), + }, + Stage4RegisterAccess { + rs1: Some(Stage4RegisterRead { + address: 1, + value: 21, + }), + rs2: Some(Stage4RegisterRead { + address: 0, + value: 15, + }), + rd: Some(Stage4RegisterWrite { + address: 1, + pre_value: 21, + post_value: 25, + }), + }, + ] + } + + fn frs(values: &[u64]) -> Vec { + values.iter().copied().map(Fr::from_u64).collect() + } + + fn leak_slice(values: Vec) -> &'static [T] { + Box::leak(values.into_boxed_slice()) + } +} diff --git a/crates/jolt-kernels/src/stage5.rs b/crates/jolt-kernels/src/stage5.rs new file mode 100644 index 0000000000..d721acf4d8 --- /dev/null +++ b/crates/jolt-kernels/src/stage5.rs @@ -0,0 +1,4949 @@ +//! Stage 5 coarse-kernel ABI used by Bolt-generated Jolt prover code. + +#![expect( + clippy::large_enum_variant, + reason = "kernel states stay inline to avoid boxing hot prover state" +)] +#![expect( + clippy::too_many_arguments, + reason = "kernel constructors mirror generated staged protocol inputs" +)] + +use std::collections::HashMap; +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +use crate::dense::{bind_dense_evals_reuse, DENSE_BIND_PAR_THRESHOLD}; +use jolt_field::{AdditiveAccumulator, Field, RingAccumulator}; +use jolt_lookup_tables::{ + tables::{ + prefixes::{PrefixEval, ALL_PREFIXES, NUM_PREFIXES}, + Suffixes, + }, + uninterleave_bits, LookupBits, LookupTableKind, +}; +use jolt_poly::{bind_high_to_low, EqPolynomial, UnivariatePoly}; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use jolt_witness::Stage45SparseTraceWitness; +use rayon::prelude::*; + +type PrefixPairEvals = ([PrefixEval; NUM_PREFIXES], [PrefixEval; NUM_PREFIXES]); + +pub use crate::stage4::{ + Stage4ChallengeVector as Stage5ChallengeVector, Stage4CpuProgramPlan as Stage5CpuProgramPlan, + Stage4ExecutionArtifacts as Stage5ExecutionArtifacts, + Stage4ExecutionMode as Stage5ExecutionMode, Stage4FieldConstantPlan as Stage5FieldConstantPlan, + Stage4FieldExprPlan as Stage5FieldExprPlan, Stage4KernelPlan as Stage5KernelPlan, + Stage4NamedEval as Stage5NamedEval, Stage4OpeningBatchPlan as Stage5OpeningBatchPlan, + Stage4OpeningClaimEqualityPlan as Stage5OpeningClaimEqualityPlan, + Stage4OpeningClaimPlan as Stage5OpeningClaimPlan, + Stage4OpeningClaimValue as Stage5OpeningClaimValue, + Stage4OpeningInputPlan as Stage5OpeningInputPlan, + Stage4OpeningInputValue as Stage5OpeningInputValue, Stage4Params as Stage5Params, + Stage4PointConcatPlan as Stage5PointConcatPlan, Stage4PointSlicePlan as Stage5PointSlicePlan, + Stage4ProgramStepPlan as Stage5ProgramStepPlan, Stage4Proof as Stage5Proof, + Stage4SumcheckBatchPlan as Stage5SumcheckBatchPlan, + Stage4SumcheckClaimPlan as Stage5SumcheckClaimPlan, + Stage4SumcheckDriverPlan as Stage5SumcheckDriverPlan, + Stage4SumcheckEvalPlan as Stage5SumcheckEvalPlan, + Stage4SumcheckInstanceResultPlan as Stage5SumcheckInstanceResultPlan, + Stage4SumcheckOutput as Stage5SumcheckOutput, + Stage4TranscriptAbsorbBytesPlan as Stage5TranscriptAbsorbBytesPlan, + Stage4TranscriptSqueezePlan as Stage5TranscriptSqueezePlan, +}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage5Relation { + InstructionReadRaf, + RamRaClaimReduction, + RegistersValEvaluation, + Batched, +} + +impl Stage5Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage5.instruction_read_raf" => Some(Self::InstructionReadRaf), + "jolt.stage5.ram_ra_claim_reduction" => Some(Self::RamRaClaimReduction), + "jolt.stage5.registers_val_evaluation" => Some(Self::RegistersValEvaluation), + "jolt.stage5.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::InstructionReadRaf => "jolt.stage5.instruction_read_raf", + Self::RamRaClaimReduction => "jolt.stage5.ram_ra_claim_reduction", + Self::RegistersValEvaluation => "jolt.stage5.registers_val_evaluation", + Self::Batched => "jolt.stage5.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage5KernelAbi { + InstructionReadRaf, + RamRaClaimReduction, + RegistersValEvaluation, + Batched, +} + +impl Stage5KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage5_instruction_read_raf" => Some(Self::InstructionReadRaf), + "jolt_stage5_ram_ra_claim_reduction" => Some(Self::RamRaClaimReduction), + "jolt_stage5_registers_val_evaluation" => Some(Self::RegistersValEvaluation), + "jolt_stage5_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::InstructionReadRaf => "jolt_stage5_instruction_read_raf", + Self::RamRaClaimReduction => "jolt_stage5_ram_ra_claim_reduction", + Self::RegistersValEvaluation => "jolt_stage5_registers_val_evaluation", + Self::Batched => "jolt_stage5_batched", + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage5KernelError { + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + MissingDriver { + driver: &'static str, + }, + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage5ExecutionMode, + actual: Stage5ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProgramStep { + symbol: &'static str, + kind: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage5KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage5 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage5 value @{symbol} is not available") + } + Self::MissingDriver { driver } => { + write!(formatter, "stage5 driver @{driver} is not available") + } + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage5 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage5 driver @{driver} references missing batch @{batch}" + ) + } + Self::UnknownRelation { relation } => { + write!(formatter, "unknown stage5 relation `{relation}`") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "unknown stage5 kernel ABI `{abi}`") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => { + write!( + formatter, + "stage5 {artifact} plan count mismatch: expected {expected}, got {actual}" + ) + } + Self::InvalidInputLength { + input, + expected, + actual, + } => { + write!( + formatter, + "stage5 input `{input}` has length {actual}, expected {expected}" + ) + } + Self::UnsupportedFieldExpr { symbol, formula } => { + write!( + formatter, + "stage5 field expr @{symbol} uses unsupported formula `{formula}`" + ) + } + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage5 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => { + write!( + formatter, + "stage5 driver @{driver} expected {expected:?} executor, got {actual:?}" + ) + } + Self::MissingProof { driver } => { + write!(formatter, "stage5 proof for driver @{driver} is missing") + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage5 kernel `{kernel}` is missing required input `{input}`" + ) + } + Self::InvalidProgramStep { symbol, kind } => { + write!( + formatter, + "stage5 program step @{symbol} has invalid kind `{kind}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage5 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage5KernelError {} + +#[derive(Clone, Copy)] +pub struct Stage5RegistersValWitness<'a, F: Field> { + pub register_count: usize, + pub trace_len: usize, + pub rd_inc: &'a [F], + pub rd_wa: &'a [F], + pub rd_write_addresses: Option<&'a [Option]>, +} + +#[derive(Clone, Copy)] +pub struct Stage5RamRaWitness<'a, F: Field> { + pub ram_k: usize, + pub trace_len: usize, + pub ram_ra: &'a [F], + pub remapped_addresses: Option<&'a [Option]>, +} + +#[derive(Clone, Copy)] +pub struct Stage5InstructionReadRafWitness<'a> { + pub trace_len: usize, + pub lookup_indices: &'a [u128], + pub lookup_table_indices: &'a [Option], + pub is_interleaved_operands: &'a [bool], + pub ra_virtual_log_k_chunk: usize, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Stage5InstructionReadRafEvaluations { + pub lookup_table_flags: Vec, + pub instruction_ra: Vec, + pub instruction_raf_flag: F, +} + +#[derive(Clone, Copy)] +pub struct Stage5ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage5OpeningInputValue], + pub instruction_read_raf: Option>, + pub ram_ra: Option>, + pub registers_val: Option>, +} + +impl<'a, F: Field> Stage5ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage5OpeningInputValue]) -> Self { + Self { + opening_inputs, + instruction_read_raf: None, + ram_ra: None, + registers_val: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + instruction_read_raf: None, + ram_ra: None, + registers_val: None, + } + } + + pub fn with_instruction_read_raf( + mut self, + instruction_read_raf: Stage5InstructionReadRafWitness<'a>, + ) -> Self { + self.instruction_read_raf = Some(instruction_read_raf); + self + } + + pub fn with_ram_ra(mut self, ram_ra: Stage5RamRaWitness<'a, F>) -> Self { + self.ram_ra = Some(ram_ra); + self + } + + pub fn with_registers_val(mut self, registers_val: Stage5RegistersValWitness<'a, F>) -> Self { + self.registers_val = Some(registers_val); + self + } + + pub fn with_sparse_trace_witness( + self, + trace_len: usize, + ram_k: usize, + register_count: usize, + lookup_indices: &'a [u128], + lookup_table_indices: &'a [Option], + is_interleaved_operands: &'a [bool], + ra_virtual_log_k_chunk: usize, + remapped_addresses: &'a [Option], + rd_inc: &'a [F], + rd_write_addresses: &'a [Option], + ) -> Self { + self.with_instruction_read_raf(Stage5InstructionReadRafWitness { + trace_len, + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + ra_virtual_log_k_chunk, + }) + .with_ram_ra(Stage5RamRaWitness { + ram_k, + trace_len, + ram_ra: &[], + remapped_addresses: Some(remapped_addresses), + }) + .with_registers_val(Stage5RegistersValWitness { + register_count, + trace_len, + rd_inc, + rd_wa: &[], + rd_write_addresses: Some(rd_write_addresses), + }) + } + + pub fn with_stage45_sparse_trace_witness( + self, + trace_len: usize, + ram_k: usize, + register_count: usize, + lookup_indices: &'a [u128], + lookup_table_indices: &'a [Option], + is_interleaved_operands: &'a [bool], + ra_virtual_log_k_chunk: usize, + witness: &'a Stage45SparseTraceWitness, + ) -> Self { + self.with_sparse_trace_witness( + trace_len, + ram_k, + register_count, + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + ra_virtual_log_k_chunk, + &witness.ram_addresses, + &witness.rd_inc, + &witness.rd_write_addresses, + ) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage5KernelContext<'a> { + pub mode: Stage5ExecutionMode, + pub program: &'static Stage5CpuProgramPlan, + pub kernel: &'a Stage5KernelPlan, + pub batch: &'a Stage5SumcheckBatchPlan, + pub driver: &'a Stage5SumcheckDriverPlan, +} + +impl Stage5KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + Stage5Relation::from_symbol(self.kernel.relation).ok_or( + Stage5KernelError::UnknownRelation { + relation: self.kernel.relation, + }, + ) + } + + pub fn abi_kind(&self) -> Result { + Stage5KernelAbi::from_name(self.kernel.abi).ok_or(Stage5KernelError::UnknownKernelAbi { + abi: self.kernel.abi, + }) + } + + pub fn batch_claims(&self) -> Result, Stage5KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage5KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage5KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage5TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage5KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage5SumcheckOutput, + ) -> Result<(), Stage5KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage5KernelExecutor; + +impl Stage5KernelExecutor for UnsupportedStage5KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + Err(Stage5KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + Err(Stage5KernelError::KernelNotImplemented { + abi: context.kernel.abi, + }) + } +} + +#[derive(Clone)] +pub struct Stage5ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage5ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage5ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage5ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage5CpuProgramPlan, + ) -> Result, Stage5KernelError> { + value_store_from_observations( + program, + self.inputs.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage5KernelExecutor for Stage5ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage5TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage5KernelError> { + self.challenge_vectors.push(Stage5ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage5SumcheckOutput, + ) -> Result<(), Stage5KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + prove_stage5_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + Err(Stage5KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage5ExecutionMode::Prover, + actual: Stage5ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage5ProofCarryingKernelExecutor<'a, F: Field> { + pub proof: &'a Stage5Proof, + pub opening_inputs: &'a [Stage5OpeningInputValue], + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage5ProofCarryingKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage5Proof, + opening_inputs: &'a [Stage5OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage5CpuProgramPlan, + ) -> Result, Stage5KernelError> { + value_store_from_observations( + program, + self.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } + + fn next_proof( + &mut self, + driver: &'static str, + ) -> Result<&'a Stage5SumcheckOutput, Stage5KernelError> { + let proof = self + .proof + .sumchecks + .get(self.cursor) + .ok_or(Stage5KernelError::MissingProof { driver })?; + self.cursor += 1; + Ok(proof) + } +} + +impl Stage5KernelExecutor for Stage5ProofCarryingKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage5TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage5KernelError> { + self.challenge_vectors.push(Stage5ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage5SumcheckOutput, + ) -> Result<(), Stage5KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage5_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage5_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } +} + +#[derive(Clone, Debug, Default)] +pub struct Stage5ValueStore { + scalars: Vec<(&'static str, F)>, + points: Vec<(&'static str, Vec)>, +} + +impl Stage5ValueStore { + pub fn with_opening_inputs(inputs: &[Stage5OpeningInputValue]) -> Self { + let mut store = Self::default(); + for input in inputs { + store.insert_scalar(input.symbol, input.eval); + store.insert_point(input.symbol, input.point.clone()); + } + store + } + + pub fn seed_constants(&mut self, program: &'static Stage5CpuProgramPlan) { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + } + + pub fn observe_challenge_vector( + &mut self, + program: &'static Stage5CpuProgramPlan, + plan: &'static Stage5TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage5KernelError> { + self.insert_point(plan.symbol, values.to_vec()); + if matches!(plan.kind, "challenge_scalar" | "scalar") { + require_operand_count(plan.symbol, 1, values.len())?; + self.insert_scalar(plan.symbol, values[0]); + } + let _ = self.evaluate_available_field_exprs(program)?; + Ok(()) + } + + pub fn observe_sumcheck_output( + &mut self, + program: &'static Stage5CpuProgramPlan, + output: &Stage5SumcheckOutput, + ) -> Result<(), Stage5KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + pub fn observe_sumcheck_values( + &mut self, + program: &'static Stage5CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage5NamedEval], + ) -> Result<(), Stage5KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program + .instance_results + .iter() + .filter(|instance| instance.source == driver) + { + let end = instance.round_offset + instance.point_arity; + let mut instance_point = point + .get(instance.round_offset..end) + .ok_or(Stage5KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "instruction_read_raf" => { + instance_point = normalize_instruction_read_raf_point(&instance_point)?; + } + "reverse" => instance_point.reverse(), + _ => { + return Err(Stage5KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, instance_point); + } + for eval in program.evals.iter().filter(|eval| eval.source == driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage5KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + let _ = self.evaluate_available_points(program)?; + let _ = self.evaluate_available_field_exprs(program)?; + self.verify_opening_equalities(program)?; + Ok(()) + } + + pub fn claim_value( + &mut self, + program: &'static Stage5CpuProgramPlan, + claim: &Stage5SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + pub fn batch_claim_values( + &mut self, + program: &'static Stage5CpuProgramPlan, + batch: &Stage5SumcheckBatchPlan, + ) -> Result, Stage5KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage5KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + pub fn evaluate_available_points( + &mut self, + program: &'static Stage5CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage5KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + require_operand_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage5CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate_stage5_field_expr(expr, &operands)?); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + pub fn verify_opening_equalities( + &self, + program: &'static Stage5CpuProgramPlan, + ) -> Result<(), Stage5KernelError> { + for equality in program.opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point(equality.lhs)? != self.point(equality.rhs)? + || self.scalar(equality.lhs)? != self.scalar(equality.rhs)? + { + return Err(Stage5KernelError::InvalidProof { + driver: equality.symbol, + reason: "opening claim equality failed", + }); + } + } + _ => { + return Err(Stage5KernelError::InvalidProof { + driver: equality.symbol, + reason: "unsupported opening equality mode", + }); + } + } + } + Ok(()) + } + + pub fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some((_, existing)) = self + .scalars + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = value; + } else { + self.scalars.push((symbol, value)); + } + } + + pub fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some((_, existing)) = self + .points + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = point; + } else { + self.points.push((symbol, point)); + } + } + + pub fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage5KernelError::MissingValue { symbol }) + } + + pub fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, value)| *value) + } + + pub fn point(&self, symbol: &'static str) -> Result<&[F], Stage5KernelError> { + self.try_point(symbol) + .ok_or(Stage5KernelError::MissingValue { symbol }) + } + + pub fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, point)| point.as_slice()) + } + + fn try_expr_operands(&self, expr: &Stage5FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage5PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +fn value_store_from_observations( + program: &'static Stage5CpuProgramPlan, + opening_inputs: &[Stage5OpeningInputValue], + challenge_vectors: &[Stage5ChallengeVector], + completed_sumchecks: &[Stage5SumcheckOutput], +) -> Result, Stage5KernelError> { + let mut store = Stage5ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(program); + for challenge in challenge_vectors { + let plan = program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == challenge.symbol) + .ok_or(Stage5KernelError::MissingValue { + symbol: challenge.symbol, + })?; + store.observe_challenge_vector(program, plan, &challenge.values)?; + } + for output in completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + store.verify_opening_equalities(program)?; + Ok(store) +} + +pub fn evaluate_stage5_field_expr( + expr: &Stage5FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + formula => { + if let Some(exponent) = formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage5KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(Stage5KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }) + } + } +} + +fn prove_stage5_kernel( + context: Stage5KernelContext<'_>, + inputs: &Stage5ProverInputs<'_, F>, + store: Stage5ValueStore, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage5KernelAbi::Batched => prove_batched_stage5(context, inputs, store, transcript), + abi => Err(Stage5KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +fn verify_stage5_kernel( + context: Stage5KernelContext<'_>, + store: Stage5ValueStore, + proof: &Stage5SumcheckOutput, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage5KernelAbi::Batched => verify_batched_stage5(context, store, proof, transcript), + abi => Err(Stage5KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +#[tracing::instrument(skip_all, name = "Stage5::prove_batched")] +fn prove_batched_stage5( + context: Stage5KernelContext<'_>, + inputs: &Stage5ProverInputs<'_, F>, + mut store: Stage5ValueStore, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + let mut instances = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + let offset = instance_round_offset(context.program, context.driver.symbol, claim.symbol)?; + if offset + claim.num_rounds > max_rounds { + return Err(Stage5KernelError::InvalidInputLength { + input: claim.symbol, + expected: max_rounds, + actual: offset + claim.num_rounds, + }); + } + let active_scale = F::one().mul_pow_2(max_rounds - offset - claim.num_rounds); + instances.push(Stage5BatchedInstance { + claim, + relation: claim_relation(context.program, claim)?, + offset, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state: Stage5ProverInstanceState::new( + context.program, + claim, + inputs, + &store, + active_scale, + )?, + }); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for instance in &mut instances { + let poly = if instance.is_active(round) { + instance + .state + .round_poly(instance.previous_claim, instance.relation)? + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + for (instance, poly) in instances.iter_mut().zip(individual_polys) { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + instance.state.ingest_challenge(challenge); + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + for instance in &instances { + evals.extend(instance.state.final_evals(instance.relation)?); + } + let expected = + expected_batched_output_claim(context, &store, &evals, &point, &batching_coeffs)?; + if batched_claim != expected { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + Ok(Stage5SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: jolt_sumcheck::SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage5( + context: Stage5KernelContext<'_>, + mut store: Stage5ValueStore, + proof: &Stage5SumcheckOutput, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = + expected_batched_output_claim(context, &store, &proof.evals, &point, &batching_coeffs)?; + if running_claim != expected { + return Err(Stage5KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + + let output = Stage5SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims: Vec::new(), + proof: proof.proof.clone(), + }; + store.observe_sumcheck_output(context.program, &output)?; + let opening_claims = + append_opening_claims(context.program, &mut store, transcript, &output.evals)?; + let output = Stage5SumcheckOutput { + opening_claims, + ..output + }; + Ok(output) +} + +struct Stage5BatchedInstance<'a, F: Field> { + claim: &'a Stage5SumcheckClaimPlan, + relation: Stage5Relation, + offset: usize, + previous_claim: F, + state: Stage5ProverInstanceState, +} + +impl Stage5BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage5ProverInstanceState { + Dense(DenseStage5State), + InstructionReadRaf(InstructionReadRafStage5State), +} + +impl Stage5ProverInstanceState { + fn new( + program: &'static Stage5CpuProgramPlan, + claim: &Stage5SumcheckClaimPlan, + inputs: &Stage5ProverInputs<'_, F>, + store: &Stage5ValueStore, + active_scale: F, + ) -> Result { + match claim_relation(program, claim)? { + Stage5Relation::InstructionReadRaf => { + instruction_read_raf_state(program, claim, inputs, store, active_scale) + .map(Self::InstructionReadRaf) + } + Stage5Relation::RegistersValEvaluation => { + registers_val_evaluation_state(claim, inputs, store, active_scale).map(Self::Dense) + } + Stage5Relation::RamRaClaimReduction => { + ram_ra_claim_reduction_state(claim, inputs, store, active_scale).map(Self::Dense) + } + relation @ Stage5Relation::Batched => Err(Stage5KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + } + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage5Relation, + ) -> Result, Stage5KernelError> { + match self { + Self::Dense(state) => state.round_poly(previous_claim, relation), + Self::InstructionReadRaf(state) => state.round_poly(previous_claim, relation), + } + } + + fn ingest_challenge(&mut self, challenge: F) { + match self { + Self::Dense(state) => state.bind(challenge), + Self::InstructionReadRaf(state) => state.bind(challenge), + } + } + + fn final_evals( + &self, + relation: Stage5Relation, + ) -> Result>, Stage5KernelError> { + match self { + Self::Dense(state) => state.final_evals(relation), + Self::InstructionReadRaf(state) => state.final_evals(relation), + } + } +} + +struct DenseStage5State { + factors: Vec>, + factor_scratch: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, +} + +#[derive(Clone)] +struct DenseTerm { + coefficient: F, + factors: Vec, +} + +#[derive(Clone, Copy)] +struct FactorOutput { + name: &'static str, + oracle: &'static str, + factor: usize, +} + +#[derive(Clone, Copy)] +enum InstructionReadRafOutputKind { + LookupTableFlag(usize), + InstructionRa(usize), + InstructionRafFlag, +} + +#[derive(Clone, Copy)] +struct InstructionReadRafOutputPlan { + index: usize, + name: &'static str, + oracle: &'static str, + kind: InstructionReadRafOutputKind, +} + +struct InstructionReadRafStage5State { + trace_len: usize, + lookup_indices: Vec, + lookup_table_indices: Vec>, + is_interleaved_operands: Vec, + lookup_groups: Vec>, + lookup_group_indices_by_cycle: Vec, + lookup_groups_by_table: Vec>, + ra_virtual_log_k_chunk: usize, + u_evals: Vec, + gamma: F, + gamma2: F, + active_scale: F, + round: usize, + address_challenges: Vec, + cycle_challenges: Vec, + address_phase: Option>, + left_operand_checkpoint: F, + right_operand_checkpoint: F, + identity_checkpoint: F, + read_prefix_checkpoints: Vec>, + cycle_state: Option>, + outputs: Vec, +} + +struct InstructionReadRafLookupGroup { + lookup_index: u128, + lookup_table_index: Option, + is_interleaved_operands: bool, + u_eval_sum: F, + phase_u_eval_sum: F, +} + +struct InstructionReadRafAddressPhase { + phase: usize, + left_operand_prefix: Vec, + right_operand_prefix: Vec, + identity_prefix: Vec, + raf_shift_half_q: Vec, + raf_left_q: Vec, + raf_right_q: Vec, + raf_shift_full_q: Vec, + raf_identity_q: Vec, + read_prefix_polys: Vec>, + read_suffix_polys: Vec>, +} + +struct InstructionReadRafReadTablePhase { + table: LookupTableKind<64>, + suffix_polys: Vec>, +} + +struct InstructionReadRafCycleState { + factors: Vec>, + factor_scratch: Vec>, +} + +impl DenseStage5State { + fn new( + factors: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, + ) -> Self { + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Self { + factors, + factor_scratch, + terms, + outputs, + active_scale, + } + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage5Relation, + ) -> Result, Stage5KernelError> { + let first_len = self.factors.first().map_or(0, Vec::len); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage5 dense factor has invalid length", + }); + } + if self.factors.iter().any(|factor| factor.len() != first_len) { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage5 dense factors have inconsistent lengths", + }); + } + let poly = + round_poly_from_dense_terms(&self.factors, &self.terms, self.active_scale, relation)?; + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage5 relation input claim mismatch", + }); + } + Ok(poly) + } + + fn bind(&mut self, challenge: F) { + if self.factors.first().map_or(0, Vec::len) / 2 >= DENSE_BIND_PAR_THRESHOLD { + self.factors + .par_iter_mut() + .zip(self.factor_scratch.par_iter_mut()) + .for_each(|(factor, scratch)| { + bind_dense_evals_reuse(factor, scratch, challenge); + }); + } else { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse(factor, scratch, challenge); + } + } + } + + fn factor_eval(&self, index: usize, relation: Stage5Relation) -> Result { + self.factors + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty stage5 factor", + }) + } + + fn final_evals( + &self, + relation: Stage5Relation, + ) -> Result>, Stage5KernelError> { + self.outputs + .iter() + .map(|output| { + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(output.factor, relation)?, + )) + }) + .collect() + } +} + +impl InstructionReadRafStage5State { + const LOG_K: usize = 128; + const ADDRESS_CHUNK_BITS: usize = 8; + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage5Relation, + ) -> Result, Stage5KernelError> { + if self.round < Self::LOG_K { + self.ensure_address_phase(); + let Some(address_phase) = self.address_phase.as_ref() else { + std::process::abort(); + }; + let (read, raf_components) = if address_phase.left_operand_prefix.len() <= 32 { + ( + address_phase.read_table_round_evals(), + address_phase.raf_round_component_evals(), + ) + } else { + rayon::join( + || address_phase.read_table_round_evals(), + || address_phase.raf_round_component_evals(), + ) + }; + let eval_at_0 = (read[0] + + self.gamma * raf_components[0][0] + + self.gamma2 * (raf_components[1][0] + raf_components[2][0])) + * self.active_scale; + let eval_at_2 = (read[1] + + self.gamma * raf_components[0][1] + + self.gamma2 * (raf_components[1][1] + raf_components[2][1])) + * self.active_scale; + let result = Ok(UnivariatePoly::from_evals_and_hint( + previous_claim, + &[eval_at_0, eval_at_2], + )); + return result; + } + + if self.cycle_state.is_none() { + self.cycle_state = Some(self.materialize_cycle_state()?); + } + let Some(cycle_state) = self.cycle_state.as_ref() else { + std::process::abort(); + }; + cycle_state.round_poly(previous_claim, self.active_scale, relation) + } + + fn bind(&mut self, challenge: F) { + if self.round < Self::LOG_K { + self.ensure_address_phase(); + self.address_challenges.push(challenge); + if let Some(phase) = &mut self.address_phase { + phase.bind(challenge); + } + if (self.round + 1).is_multiple_of(Self::ADDRESS_CHUNK_BITS) { + self.finish_address_phase(); + } + } else { + self.cycle_challenges.push(challenge); + if let Some(cycle_state) = &mut self.cycle_state { + cycle_state.bind(challenge); + } + } + self.round += 1; + } + + fn final_evals( + &self, + relation: Stage5Relation, + ) -> Result>, Stage5KernelError> { + require_operand_count( + "stage5.instruction_read_raf.address_challenges", + Self::LOG_K, + self.address_challenges.len(), + )?; + require_operand_count( + "stage5.instruction_read_raf.cycle_challenges", + log2_exact(self.trace_len, "stage5.instruction_read_raf.trace_len")?, + self.cycle_challenges.len(), + )?; + + let normalized_cycle_point = reverse_slice(&self.cycle_challenges); + let evaluations = self.instruction_read_raf_output_evals_from_groups( + &self.address_challenges, + &normalized_cycle_point, + )?; + self.outputs + .iter() + .map(|output| { + let value = match output.kind { + InstructionReadRafOutputKind::LookupTableFlag(index) => { + evaluations.lookup_table_flags.get(index).copied().ok_or( + Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.lookup_table_flags", + expected: evaluations.lookup_table_flags.len(), + actual: index + 1, + }, + )? + } + InstructionReadRafOutputKind::InstructionRa(index) => { + evaluations.instruction_ra.get(index).copied().ok_or( + Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.instruction_ra", + expected: evaluations.instruction_ra.len(), + actual: index + 1, + }, + )? + } + InstructionReadRafOutputKind::InstructionRafFlag => { + evaluations.instruction_raf_flag + } + }; + Ok(named_eval(output.name, output.oracle, value)) + }) + .collect::, _>>() + .map_err(|error| match error { + Stage5KernelError::InvalidInputLength { .. } => error, + _ => Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "invalid instruction read raf output", + }, + }) + } + + fn ensure_address_phase(&mut self) { + debug_assert!(Self::LOG_K.is_multiple_of(Self::ADDRESS_CHUNK_BITS)); + let phase = self.round / Self::ADDRESS_CHUNK_BITS; + if self + .address_phase + .as_ref() + .is_some_and(|address_phase| address_phase.phase == phase) + { + return; + } + self.address_phase = Some(self.build_address_phase(phase)); + } + + fn build_address_phase(&self, phase: usize) -> InstructionReadRafAddressPhase { + let chunk_bits = Self::ADDRESS_CHUNK_BITS; + let poly_len = 1usize << chunk_bits; + let suffix_len = Self::LOG_K - (phase + 1) * chunk_bits; + let left_operand_prefix = + operand_prefix_poly(self.left_operand_checkpoint, chunk_bits, true); + let right_operand_prefix = + operand_prefix_poly(self.right_operand_checkpoint, chunk_bits, false); + let identity_prefix = identity_prefix_poly(self.identity_checkpoint, chunk_bits); + let read_prefix_polys = ALL_PREFIXES + .par_iter() + .map(|prefix| { + (0..poly_len) + .map(|bits| { + prefix + .evaluate( + &self.read_prefix_checkpoints, + LookupBits::new(bits as u128, chunk_bits), + suffix_len, + ) + .into_inner() + }) + .collect::>() + }) + .collect::>(); + + let shift_half_value = 1u128 << (suffix_len / 2); + let shift_full_value = 1u128 << suffix_len; + let shift_half = F::from_u128(shift_half_value); + let shift_full = F::from_u128(shift_full_value); + let suffix_mask = if suffix_len == 128 { + u128::MAX + } else { + (1u128 << suffix_len) - 1 + }; + + let q_total_len = 5 * poly_len; + let q_chunk_size = self + .lookup_groups + .len() + .div_ceil(rayon::current_num_threads()) + .max(1); + let q_rows = self + .lookup_groups + .par_chunks(q_chunk_size) + .fold( + || vec![F::zero(); q_total_len], + |mut acc, groups| { + let shift_half_offset = 0; + let left_offset = poly_len; + let right_offset = 2 * poly_len; + let shift_full_offset = 3 * poly_len; + let identity_offset = 4 * poly_len; + + for group in groups { + let index = ((group.lookup_index >> suffix_len) as usize) & (poly_len - 1); + let suffix_bits = group.lookup_index & suffix_mask; + let weight = group.phase_u_eval_sum; + + if group.is_interleaved_operands { + acc[shift_half_offset + index] += weight; + let (left_suffix, right_suffix) = uninterleave_bits(suffix_bits); + if left_suffix != 0 { + acc[left_offset + index] += weight.mul_u64(left_suffix); + } + if right_suffix != 0 { + acc[right_offset + index] += weight.mul_u64(right_suffix); + } + } else { + acc[shift_full_offset + index] += weight; + if suffix_bits != 0 { + acc[identity_offset + index] += weight.mul_u128(suffix_bits); + } + } + } + acc + }, + ) + .reduce( + || vec![F::zero(); q_total_len], + |mut left, right| { + for (left_value, right_value) in left.iter_mut().zip(right) { + *left_value += right_value; + } + left + }, + ); + let mut raf_shift_half_q = q_rows[..poly_len].to_vec(); + let raf_left_q = q_rows[poly_len..2 * poly_len].to_vec(); + let raf_right_q = q_rows[2 * poly_len..3 * poly_len].to_vec(); + let mut raf_shift_full_q = q_rows[3 * poly_len..4 * poly_len].to_vec(); + let raf_identity_q = q_rows[4 * poly_len..5 * poly_len].to_vec(); + if shift_half_value != 1 { + for value in &mut raf_shift_half_q { + *value *= shift_half; + } + } + if shift_full_value != 1 { + for value in &mut raf_shift_full_q { + *value *= shift_full; + } + } + + let tables = LookupTableKind::<64>::all(); + let read_suffix_polys = tables + .par_iter() + .enumerate() + .filter_map(|(table_index, table)| { + if self.lookup_groups_by_table[table_index].is_empty() { + return None; + } + let suffixes = table.suffixes(); + let mut accumulators = + vec![vec![F::Accumulator::default(); poly_len]; suffixes.len()]; + let mut one_suffix = None; + let mut boolean_suffixes = Vec::new(); + let mut valued_suffixes = Vec::new(); + for (suffix_index, suffix) in suffixes.iter().enumerate() { + if matches!(suffix, Suffixes::One) { + one_suffix = Some(suffix_index); + } else if suffix.is_01_valued() { + boolean_suffixes.push((suffix_index, suffix)); + } else { + valued_suffixes.push((suffix_index, suffix)); + } + } + for &group_index in &self.lookup_groups_by_table[table_index] { + let group = &self.lookup_groups[group_index]; + let index = ((group.lookup_index >> suffix_len) as usize) & (poly_len - 1); + let suffix_bits = LookupBits::new(group.lookup_index & suffix_mask, suffix_len); + let weight = group.phase_u_eval_sum; + if let Some(suffix_index) = one_suffix { + accumulators[suffix_index][index].add(weight); + } + for &(suffix_index, suffix) in &boolean_suffixes { + let suffix_value = suffix.suffix_mle(suffix_bits); + debug_assert!(suffix_value == 0 || suffix_value == 1); + if suffix_value == 1 { + accumulators[suffix_index][index].add(weight); + } + } + for &(suffix_index, suffix) in &valued_suffixes { + let suffix_value = suffix.suffix_mle(suffix_bits); + accumulators[suffix_index][index].fmadd_u64(weight, suffix_value); + } + } + let polys = accumulators + .into_iter() + .map(|poly| { + poly.into_iter() + .map(AdditiveAccumulator::reduce) + .collect::>() + }) + .collect::>(); + Some(InstructionReadRafReadTablePhase { + table: *table, + suffix_polys: polys, + }) + }) + .collect::>(); + + InstructionReadRafAddressPhase { + phase, + left_operand_prefix, + right_operand_prefix, + identity_prefix, + raf_shift_half_q, + raf_left_q, + raf_right_q, + raf_shift_full_q, + raf_identity_q, + read_prefix_polys, + read_suffix_polys, + } + } + + fn finish_address_phase(&mut self) { + let Some(phase) = self.address_phase.take() else { + return; + }; + self.left_operand_checkpoint = phase.left_operand_prefix[0]; + self.right_operand_checkpoint = phase.right_operand_prefix[0]; + self.identity_checkpoint = phase.identity_prefix[0]; + self.read_prefix_checkpoints = phase + .read_prefix_polys + .iter() + .map(|poly| PrefixEval::from(poly[0])) + .collect(); + + let chunk_bits = Self::ADDRESS_CHUNK_BITS; + let start = phase.phase * chunk_bits; + let end = start + chunk_bits; + let point = &self.address_challenges[start..end]; + let shift = Self::LOG_K - end; + let mask = (1u128 << chunk_bits) - 1; + let eq_table = (0..(1usize << chunk_bits)) + .map(|bits| eq_eval_at_bits(point, bits as u128, chunk_bits)) + .collect::>(); + self.lookup_groups.par_iter_mut().for_each(|group| { + let chunk_value = (group.lookup_index >> shift) & mask; + group.phase_u_eval_sum *= eq_table[chunk_value as usize]; + }); + } + + fn materialize_cycle_state( + &self, + ) -> Result, Stage5KernelError> { + require_operand_count( + "stage5.instruction_read_raf.address_challenges", + Self::LOG_K, + self.address_challenges.len(), + )?; + let tables = LookupTableKind::<64>::all(); + let ra_chunks = Self::LOG_K / self.ra_virtual_log_k_chunk; + let mut factors = Vec::with_capacity(2 + ra_chunks); + factors.push(self.u_evals.clone()); + let table_values_at_address = tables + .par_iter() + .enumerate() + .map(|(table_index, table)| { + if self.lookup_groups_by_table[table_index].is_empty() { + F::zero() + } else { + table.evaluate_mle::(&self.address_challenges) + } + }) + .collect::>(); + let raf_interleaved = self.gamma * operand_polynomial_eval(&self.address_challenges, true) + + self.gamma2 * operand_polynomial_eval(&self.address_challenges, false); + let raf_identity = self.gamma2 * identity_polynomial_eval(&self.address_challenges); + factors.push( + (0..self.trace_len) + .into_par_iter() + .map(|cycle| { + let table_value = self.lookup_table_indices[cycle] + .map_or_else(F::zero, |table_index| table_values_at_address[table_index]); + let raf_value = if self.is_interleaved_operands[cycle] { + raf_interleaved + } else { + raf_identity + }; + table_value + raf_value + }) + .collect(), + ); + + let chunk_bits = self.ra_virtual_log_k_chunk; + let chunk_mask = if chunk_bits == 128 { + u128::MAX + } else { + (1u128 << chunk_bits) - 1 + }; + for chunk in 0..ra_chunks { + let chunk_point = + &self.address_challenges[chunk * chunk_bits..(chunk + 1) * chunk_bits]; + let eq_tables = eq_eval_bit_chunk_tables(chunk_point, 8); + let shift = Self::LOG_K - (chunk + 1) * chunk_bits; + factors.push( + self.lookup_indices + .par_iter() + .map(|&lookup_index| { + let chunk_value = (lookup_index >> shift) & chunk_mask; + eq_eval_at_bits_from_chunk_tables(&eq_tables, chunk_value, chunk_bits, 8) + }) + .collect(), + ); + } + InstructionReadRafCycleState::new(factors, Stage5Relation::InstructionReadRaf) + } + + fn instruction_read_raf_output_evals_from_groups( + &self, + address_point: &[F], + cycle_point: &[F], + ) -> Result, Stage5KernelError> { + require_operand_count( + "stage5.instruction_read_raf.address_point", + Self::LOG_K, + address_point.len(), + )?; + let trace_len_from_point = 1usize.checked_shl(cycle_point.len() as u32).ok_or( + Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.cycle_point", + expected: usize::BITS as usize, + actual: cycle_point.len(), + }, + )?; + require_operand_count( + "stage5.instruction_read_raf.trace_len", + trace_len_from_point, + self.trace_len, + )?; + + let tables = LookupTableKind::<64>::all(); + let table_count = tables.len(); + let cycle_eq = EqPolynomial::::evals(cycle_point, None); + require_operand_count( + "stage5.instruction_read_raf.eq_cycle", + self.trace_len, + cycle_eq.len(), + )?; + + let mut lookup_table_flags = vec![F::zero(); table_count]; + let mut instruction_raf_flag = F::zero(); + let mut group_weights = vec![F::zero(); self.lookup_groups.len()]; + for (&group_index, &weight) in self.lookup_group_indices_by_cycle.iter().zip(&cycle_eq) { + group_weights[group_index] += weight; + } + + for (group, &weight) in self.lookup_groups.iter().zip(&group_weights) { + if let Some(table_index) = group.lookup_table_index { + let Some(flag) = lookup_table_flags.get_mut(table_index) else { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.lookup_table_indices", + expected: table_count, + actual: table_index + 1, + }); + }; + *flag += weight; + } + if !group.is_interleaved_operands { + instruction_raf_flag += weight; + } + } + + let ra_chunks = Self::LOG_K / self.ra_virtual_log_k_chunk; + let cycle_state = self + .cycle_state + .as_ref() + .ok_or(Stage5KernelError::InvalidProof { + driver: Stage5Relation::InstructionReadRaf.symbol(), + reason: "instruction read raf cycle state is not materialized", + })?; + let instruction_ra = (0..ra_chunks) + .map(|chunk| { + cycle_state + .factor_eval(2 + chunk) + .ok_or(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.instruction_ra", + expected: cycle_state.factors.len(), + actual: 2 + chunk + 1, + }) + }) + .collect::, _>>()?; + + Ok(Stage5InstructionReadRafEvaluations { + lookup_table_flags, + instruction_ra, + instruction_raf_flag, + }) + } +} + +impl InstructionReadRafAddressPhase { + fn read_table_round_evals(&self) -> [F; 2] { + let len = self.read_prefix_polys.first().map_or(0, |poly| poly.len()); + debug_assert!(len > 1); + debug_assert!(self.read_prefix_polys.iter().all(|poly| poly.len() == len)); + debug_assert!(self + .read_suffix_polys + .iter() + .flat_map(|read_table| read_table.suffix_polys.iter()) + .all(|poly| poly.len() == len)); + let half = len / 2; + let prefix_evals = (0..half) + .map(|row| { + ( + self.read_prefix_evals(row, false), + self.read_prefix_evals(row, true), + ) + }) + .collect::>(); + if half <= 16 { + self.read_suffix_polys + .iter() + .fold([F::zero(), F::zero()], |mut total, read_table| { + let eval = read_table_component_eval(read_table, half, &prefix_evals); + total[0] += eval[0]; + total[1] += eval[1]; + total + }) + } else { + self.read_suffix_polys + .par_iter() + .map(|read_table| read_table_component_eval(read_table, half, &prefix_evals)) + .reduce( + || [F::zero(), F::zero()], + |mut left, right| { + left[0] += right[0]; + left[1] += right[1]; + left + }, + ) + } + } + + fn read_prefix_evals(&self, row: usize, at_2: bool) -> [PrefixEval; NUM_PREFIXES] { + let half = self.read_prefix_polys[0].len() / 2; + let mut values = [PrefixEval::from(F::zero()); NUM_PREFIXES]; + for (value, poly) in values.iter_mut().zip(&self.read_prefix_polys) { + let low = poly[row]; + let eval = if at_2 { + let high = poly[row + half]; + high + high - low + } else { + low + }; + *value = PrefixEval::from(eval); + } + values + } + + fn raf_round_component_evals(&self) -> [[F; 2]; 3] { + let (left_0, left_2) = prefix_suffix_round_evals( + Some(&self.left_operand_prefix), + &self.raf_shift_half_q, + &self.raf_left_q, + ); + let (right_0, right_2) = prefix_suffix_round_evals( + Some(&self.right_operand_prefix), + &self.raf_shift_half_q, + &self.raf_right_q, + ); + let (identity_0, identity_2) = prefix_suffix_round_evals( + Some(&self.identity_prefix), + &self.raf_shift_full_q, + &self.raf_identity_q, + ); + [ + [left_0, left_2], + [right_0, right_2], + [identity_0, identity_2], + ] + } + + fn bind(&mut self, challenge: F) { + if self.left_operand_prefix.len() <= 32 { + bind_high_to_low(&mut self.left_operand_prefix, challenge); + bind_high_to_low(&mut self.right_operand_prefix, challenge); + bind_high_to_low(&mut self.identity_prefix, challenge); + bind_high_to_low(&mut self.raf_shift_half_q, challenge); + bind_high_to_low(&mut self.raf_left_q, challenge); + bind_high_to_low(&mut self.raf_right_q, challenge); + bind_high_to_low(&mut self.raf_shift_full_q, challenge); + bind_high_to_low(&mut self.raf_identity_q, challenge); + for poly in &mut self.read_prefix_polys { + bind_high_to_low(poly, challenge); + } + for read_table in &mut self.read_suffix_polys { + for poly in &mut read_table.suffix_polys { + bind_high_to_low(poly, challenge); + } + } + return; + } + + let left_operand_prefix = &mut self.left_operand_prefix; + let right_operand_prefix = &mut self.right_operand_prefix; + let identity_prefix = &mut self.identity_prefix; + let raf_shift_half_q = &mut self.raf_shift_half_q; + let raf_left_q = &mut self.raf_left_q; + let raf_right_q = &mut self.raf_right_q; + let raf_shift_full_q = &mut self.raf_shift_full_q; + let raf_identity_q = &mut self.raf_identity_q; + let read_prefix_polys = &mut self.read_prefix_polys; + let read_suffix_polys = &mut self.read_suffix_polys; + rayon::scope(|scope| { + scope.spawn(|_| { + bind_high_to_low(left_operand_prefix, challenge); + bind_high_to_low(right_operand_prefix, challenge); + bind_high_to_low(identity_prefix, challenge); + }); + scope.spawn(|_| { + bind_high_to_low(raf_shift_half_q, challenge); + bind_high_to_low(raf_left_q, challenge); + bind_high_to_low(raf_right_q, challenge); + bind_high_to_low(raf_shift_full_q, challenge); + bind_high_to_low(raf_identity_q, challenge); + }); + scope.spawn(|_| { + read_prefix_polys + .par_iter_mut() + .for_each(|poly| bind_high_to_low(poly, challenge)); + }); + scope.spawn(|_| { + read_suffix_polys.par_iter_mut().for_each(|read_table| { + for poly in &mut read_table.suffix_polys { + bind_high_to_low(poly, challenge); + } + }); + }); + }); + } +} + +fn read_table_component_eval( + read_table: &InstructionReadRafReadTablePhase, + half: usize, + prefix_evals: &[PrefixPairEvals], +) -> [F; 2] { + let mut eval_0 = F::zero(); + let mut eval_2_left = F::zero(); + let mut eval_2_right = F::zero(); + for row in 0..half { + let (prefixes_0, prefixes_2) = &prefix_evals[row]; + let mut suffixes_left = [F::zero(); 4]; + let mut suffixes_right = [F::zero(); 4]; + for (suffix_index, poly) in read_table.suffix_polys.iter().enumerate() { + suffixes_left[suffix_index] = poly[row]; + suffixes_right[suffix_index] = poly[row + half]; + } + let suffix_count = read_table.suffix_polys.len(); + eval_0 += read_table + .table + .combine(prefixes_0, &suffixes_left[..suffix_count]); + eval_2_left += read_table + .table + .combine(prefixes_2, &suffixes_left[..suffix_count]); + eval_2_right += read_table + .table + .combine(prefixes_2, &suffixes_right[..suffix_count]); + } + [eval_0, eval_2_right + eval_2_right - eval_2_left] +} + +#[inline] +fn prefix_suffix_round_evals(prefix: Option<&[F]>, q0: &[F], q1: &[F]) -> (F, F) { + let len = q0.len(); + debug_assert_eq!(q1.len(), len); + debug_assert!(len > 1); + let half = len / 2; + let mut eval_0 = F::zero(); + let mut eval_2_left = F::zero(); + let mut eval_2_right = F::zero(); + for row in 0..half { + let (prefix_0, prefix_2) = prefix.map_or((F::one(), F::one()), |poly| { + debug_assert_eq!(poly.len(), len); + let low = poly[row]; + let high = poly[row + half]; + (low, high + high - low) + }); + eval_0 += prefix_0 * q0[row] + q1[row]; + eval_2_left += prefix_2 * q0[row] + q1[row]; + eval_2_right += prefix_2 * q0[row + half] + q1[row + half]; + } + (eval_0, eval_2_right + eval_2_right - eval_2_left) +} + +fn operand_prefix_poly(checkpoint: F, chunk_bits: usize, left: bool) -> Vec { + debug_assert!(chunk_bits.is_multiple_of(2)); + let shift = 1u128 << (chunk_bits / 2); + (0..(1usize << chunk_bits)) + .map(|bits| { + let lookup_bits = LookupBits::new(bits as u128, chunk_bits); + let (left_bits, right_bits) = lookup_bits.uninterleave(); + let operand_bits: u64 = if left { + left_bits.into() + } else { + right_bits.into() + }; + checkpoint.mul_u128(shift) + F::from_u64(operand_bits) + }) + .collect() +} + +fn identity_prefix_poly(checkpoint: F, chunk_bits: usize) -> Vec { + let shift = 1u128 << chunk_bits; + (0..(1usize << chunk_bits)) + .map(|bits| checkpoint.mul_u128(shift) + F::from_u64(bits as u64)) + .collect() +} + +impl InstructionReadRafCycleState { + fn new(factors: Vec>, relation: Stage5Relation) -> Result { + let first_len = factors.first().map_or(0, Vec::len); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "instruction read raf cycle factor has invalid length", + }); + } + if factors.iter().any(|factor| factor.len() != first_len) { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "instruction read raf cycle factors have inconsistent lengths", + }); + } + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Ok(Self { + factors, + factor_scratch, + }) + } + + fn round_poly( + &self, + previous_claim: F, + active_scale: F, + relation: Stage5Relation, + ) -> Result, Stage5KernelError> { + let coefficients = self.round_coefficients(active_scale); + let poly = UnivariatePoly::new(coefficients); + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "instruction read raf cycle input claim mismatch", + }); + } + Ok(poly) + } + + fn factor_eval(&self, index: usize) -> Option { + self.factors + .get(index) + .and_then(|factor| factor.first()) + .copied() + } + + fn round_coefficients(&self, active_scale: F) -> Vec { + const MAX_DEGREE_PLUS_ONE: usize = 16; + let degree = self.factors.len(); + debug_assert!(degree < MAX_DEGREE_PLUS_ONE); + let half = self.factors[0].len() / 2; + let mut sums = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .fold( + || [F::zero(); MAX_DEGREE_PLUS_ONE], + |mut sums, row| { + accumulate_cycle_row_coefficients(&mut sums, &self.factors, degree, row); + sums + }, + ) + .reduce( + || [F::zero(); MAX_DEGREE_PLUS_ONE], + |mut left, right| { + for coefficient_index in 0..=degree { + left[coefficient_index] += right[coefficient_index]; + } + left + }, + ) + } else { + (0..half).fold([F::zero(); MAX_DEGREE_PLUS_ONE], |mut sums, row| { + accumulate_cycle_row_coefficients(&mut sums, &self.factors, degree, row); + sums + }) + }; + sums[..=degree] + .iter_mut() + .map(|coefficient| *coefficient * active_scale) + .collect() + } + + fn bind(&mut self, challenge: F) { + if self.factors.first().map_or(0, Vec::len) / 2 >= DENSE_BIND_PAR_THRESHOLD { + self.factors + .par_iter_mut() + .zip(self.factor_scratch.par_iter_mut()) + .for_each(|(factor, scratch)| { + bind_dense_evals_reuse(factor, scratch, challenge); + }); + } else { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse(factor, scratch, challenge); + } + } + } +} + +fn accumulate_cycle_row_coefficients( + sums: &mut [F; N], + factors: &[Vec], + degree: usize, + row: usize, +) { + let mut coefficients = [F::zero(); N]; + coefficients[0] = F::one(); + for (current_degree, factor) in factors.iter().enumerate() { + let low = factor[2 * row]; + let diff = factor[2 * row + 1] - low; + coefficients[current_degree + 1] = F::zero(); + for coefficient_index in (0..=current_degree).rev() { + let coefficient = coefficients[coefficient_index]; + coefficients[coefficient_index + 1] += coefficient * diff; + coefficients[coefficient_index] = coefficient * low; + } + } + for coefficient_index in 0..=degree { + sums[coefficient_index] += coefficients[coefficient_index]; + } +} + +fn instruction_read_raf_state( + program: &'static Stage5CpuProgramPlan, + claim: &Stage5SumcheckClaimPlan, + inputs: &Stage5ProverInputs<'_, F>, + store: &Stage5ValueStore, + active_scale: F, +) -> Result, Stage5KernelError> { + const LOG_K: usize = 128; + const XLEN: usize = 64; + + let witness = inputs + .instruction_read_raf + .ok_or(Stage5KernelError::MissingKernelInput { + kernel: "jolt_stage5_instruction_read_raf", + input: "instruction_read_raf", + })?; + let trace_rounds = log2_exact(witness.trace_len, "stage5.instruction_read_raf.trace_len")?; + require_operand_count( + "stage5.instruction_read_raf.input", + LOG_K + trace_rounds, + claim.num_rounds, + )?; + require_operand_count( + "stage5.instruction_read_raf.lookup_indices", + witness.trace_len, + witness.lookup_indices.len(), + )?; + require_operand_count( + "stage5.instruction_read_raf.lookup_table_indices", + witness.trace_len, + witness.lookup_table_indices.len(), + )?; + require_operand_count( + "stage5.instruction_read_raf.is_interleaved_operands", + witness.trace_len, + witness.is_interleaved_operands.len(), + )?; + if witness.ra_virtual_log_k_chunk == 0 || !LOG_K.is_multiple_of(witness.ra_virtual_log_k_chunk) + { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.ra_virtual_log_k_chunk", + expected: LOG_K, + actual: witness.ra_virtual_log_k_chunk, + }); + } + + let table_count = LookupTableKind::::all().len(); + for table_index in witness.lookup_table_indices.iter().flatten() { + if *table_index >= table_count { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.lookup_table_indices", + expected: table_count, + actual: table_index + 1, + }); + } + } + + let r_reduction = store.point("stage5.input.stage2.instruction.LookupOutput")?; + require_operand_count( + "stage5.input.stage2.instruction.LookupOutput", + trace_rounds, + r_reduction.len(), + )?; + let u_evals = EqPolynomial::::evals(r_reduction, None); + require_operand_count( + "stage5.instruction_read_raf.u_evals", + witness.trace_len, + u_evals.len(), + )?; + + let gamma = store.scalar("stage5.instruction_read_raf.gamma")?; + let gamma2 = store + .try_scalar("stage5.instruction_read_raf.gamma2") + .unwrap_or_else(|| gamma * gamma); + let ra_chunks = LOG_K / witness.ra_virtual_log_k_chunk; + let outputs = instruction_read_raf_output_plans(program, claim, table_count, ra_chunks)?; + + let (lookup_groups, lookup_group_indices_by_cycle) = + instruction_read_raf_lookup_groups(witness, &u_evals)?; + let mut lookup_groups_by_table = vec![Vec::new(); table_count]; + for (group_index, group) in lookup_groups.iter().enumerate() { + if let Some(table_index) = group.lookup_table_index { + lookup_groups_by_table[table_index].push(group_index); + } + } + + Ok(InstructionReadRafStage5State { + trace_len: witness.trace_len, + lookup_indices: witness.lookup_indices.to_vec(), + lookup_table_indices: witness.lookup_table_indices.to_vec(), + is_interleaved_operands: witness.is_interleaved_operands.to_vec(), + lookup_groups, + lookup_group_indices_by_cycle, + lookup_groups_by_table, + ra_virtual_log_k_chunk: witness.ra_virtual_log_k_chunk, + u_evals, + gamma, + gamma2, + active_scale, + round: 0, + address_challenges: Vec::with_capacity(LOG_K), + cycle_challenges: Vec::with_capacity(trace_rounds), + address_phase: None, + left_operand_checkpoint: F::zero(), + right_operand_checkpoint: F::zero(), + identity_checkpoint: F::zero(), + read_prefix_checkpoints: ALL_PREFIXES + .iter() + .map(|prefix| prefix.default_checkpoint::()) + .collect(), + cycle_state: None, + outputs, + }) +} + +fn instruction_read_raf_lookup_groups( + witness: Stage5InstructionReadRafWitness<'_>, + u_evals: &[F], +) -> Result<(Vec>, Vec), Stage5KernelError> { + require_operand_count( + "stage5.instruction_read_raf.group_u_evals", + witness.trace_len, + u_evals.len(), + )?; + + let mut index_by_key: std::collections::HashMap<(u128, Option, bool), usize> = + std::collections::HashMap::with_capacity(witness.trace_len); + let mut groups = Vec::>::new(); + let mut group_indices_by_cycle = Vec::with_capacity(witness.trace_len); + for (cycle, u_eval) in u_evals.iter().copied().enumerate().take(witness.trace_len) { + let key = ( + witness.lookup_indices[cycle], + witness.lookup_table_indices[cycle], + witness.is_interleaved_operands[cycle], + ); + if let Some(&group_index) = index_by_key.get(&key) { + groups[group_index].u_eval_sum += u_eval; + groups[group_index].phase_u_eval_sum += u_eval; + group_indices_by_cycle.push(group_index); + } else { + let group_index = groups.len(); + let _ = index_by_key.insert(key, group_index); + groups.push(InstructionReadRafLookupGroup { + lookup_index: key.0, + lookup_table_index: key.1, + is_interleaved_operands: key.2, + u_eval_sum: u_eval, + phase_u_eval_sum: u_eval, + }); + group_indices_by_cycle.push(group_index); + } + } + Ok((groups, group_indices_by_cycle)) +} + +fn instruction_read_raf_output_plans( + program: &'static Stage5CpuProgramPlan, + claim: &Stage5SumcheckClaimPlan, + table_count: usize, + ra_chunks: usize, +) -> Result, Stage5KernelError> { + let instance = program + .instance_results + .iter() + .find(|instance| { + instance.claim == claim.symbol + && instance.relation == Stage5Relation::InstructionReadRaf.symbol() + }) + .ok_or(Stage5KernelError::MissingClaim { + batch: "stage5.instruction_read_raf.outputs", + claim: claim.symbol, + })?; + + let mut outputs = Vec::with_capacity(table_count + ra_chunks + 1); + let mut table_flags = vec![false; table_count]; + let mut instruction_ra = vec![false; ra_chunks]; + let mut has_raf_flag = false; + + for eval in program + .evals + .iter() + .filter(|eval| eval.source == instance.source) + { + if let Some(suffix) = eval + .name + .strip_prefix("stage5.instruction_read_raf.eval.LookupTableFlag_") + { + let index = parse_instruction_read_raf_eval_index( + suffix, + "stage5.instruction_read_raf.eval.LookupTableFlag_", + )?; + if index >= table_count || table_flags[index] { + return Err(Stage5KernelError::InvalidProof { + driver: eval.name, + reason: "invalid instruction read raf table flag eval", + }); + } + table_flags[index] = true; + outputs.push(InstructionReadRafOutputPlan { + index: eval.index, + name: eval.name, + oracle: eval.oracle, + kind: InstructionReadRafOutputKind::LookupTableFlag(index), + }); + continue; + } + + if let Some(suffix) = eval + .name + .strip_prefix("stage5.instruction_read_raf.eval.InstructionRa_") + { + let index = parse_instruction_read_raf_eval_index( + suffix, + "stage5.instruction_read_raf.eval.InstructionRa_", + )?; + if index >= ra_chunks || instruction_ra[index] { + return Err(Stage5KernelError::InvalidProof { + driver: eval.name, + reason: "invalid instruction read raf ra eval", + }); + } + instruction_ra[index] = true; + outputs.push(InstructionReadRafOutputPlan { + index: eval.index, + name: eval.name, + oracle: eval.oracle, + kind: InstructionReadRafOutputKind::InstructionRa(index), + }); + continue; + } + + if eval.name == "stage5.instruction_read_raf.eval.InstructionRafFlag" { + if has_raf_flag { + return Err(Stage5KernelError::InvalidProof { + driver: eval.name, + reason: "duplicate instruction read raf flag eval", + }); + } + has_raf_flag = true; + outputs.push(InstructionReadRafOutputPlan { + index: eval.index, + name: eval.name, + oracle: eval.oracle, + kind: InstructionReadRafOutputKind::InstructionRafFlag, + }); + } + } + + if table_flags.iter().any(|seen| !*seen) { + return Err(Stage5KernelError::MissingValue { + symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_", + }); + } + if instruction_ra.iter().any(|seen| !*seen) { + return Err(Stage5KernelError::MissingValue { + symbol: "stage5.instruction_read_raf.eval.InstructionRa_", + }); + } + if !has_raf_flag { + return Err(Stage5KernelError::MissingValue { + symbol: "stage5.instruction_read_raf.eval.InstructionRafFlag", + }); + } + outputs.sort_by_key(|output| output.index); + Ok(outputs) +} + +fn parse_instruction_read_raf_eval_index( + suffix: &str, + prefix: &'static str, +) -> Result { + suffix + .parse::() + .map_err(|_| Stage5KernelError::InvalidProof { + driver: prefix, + reason: "invalid instruction read raf eval suffix", + }) +} + +fn ram_ra_claim_reduction_state( + claim: &Stage5SumcheckClaimPlan, + inputs: &Stage5ProverInputs<'_, F>, + store: &Stage5ValueStore, + active_scale: F, +) -> Result, Stage5KernelError> { + let witness = inputs.ram_ra.ok_or(Stage5KernelError::MissingKernelInput { + kernel: "jolt_stage5_batched", + input: "ram_ra", + })?; + let trace_rounds = log2_exact(witness.trace_len, "stage5.ram.trace_len")?; + let ram_rounds = log2_exact(witness.ram_k, "stage5.ram_k")?; + require_operand_count( + "stage5.ram_ra_claim_reduction.input", + trace_rounds, + claim.num_rounds, + )?; + + let ram_raf_point = store.point("stage5.input.stage2.ram_raf.RamRa")?; + let ram_rw_point = store.point("stage5.input.stage2.ram_read_write.RamRa")?; + let ram_val_point = store.point("stage5.input.stage4.ram_val_check.RamRa")?; + for (input, point) in [ + ("stage5.input.stage2.ram_raf.RamRa", ram_raf_point), + ("stage5.input.stage2.ram_read_write.RamRa", ram_rw_point), + ("stage5.input.stage4.ram_val_check.RamRa", ram_val_point), + ] { + require_operand_count(input, ram_rounds + trace_rounds, point.len())?; + } + let (address_point, r_cycle_raf) = ram_raf_point.split_at(ram_rounds); + let (_, r_cycle_rw) = ram_rw_point.split_at(ram_rounds); + let (_, r_cycle_val) = ram_val_point.split_at(ram_rounds); + let address_eq = EqPolynomial::::evals(address_point, None); + let ram_ra = ram_ra_at_address(witness, &address_eq)?; + let gamma = store.scalar("stage5.ram_ra_claim_reduction.gamma")?; + let gamma2 = store + .try_scalar("stage5.ram_ra_claim_reduction.gamma2") + .unwrap_or_else(|| gamma * gamma); + let mut eq_combined = EqPolynomial::::evals(r_cycle_raf, None); + let eq_rw = EqPolynomial::::evals(r_cycle_rw, None); + let eq_val = EqPolynomial::::evals(r_cycle_val, None); + require_operand_count( + "stage5.ram_ra_claim_reduction.eq", + witness.trace_len, + eq_combined.len(), + )?; + for ((combined, rw), val) in eq_combined.iter_mut().zip(eq_rw).zip(eq_val) { + *combined += gamma * rw + gamma2 * val; + } + + Ok(DenseStage5State::new( + vec![eq_combined, ram_ra], + vec![DenseTerm { + coefficient: F::one(), + factors: vec![0, 1], + }], + vec![FactorOutput { + name: "stage5.ram_ra_claim_reduction.eval.RamRa", + oracle: "RamRa", + factor: 1, + }], + active_scale, + )) +} + +fn ram_ra_at_address( + witness: Stage5RamRaWitness<'_, F>, + address_eq: &[F], +) -> Result, Stage5KernelError> { + let expected_len = witness.ram_k.checked_mul(witness.trace_len).ok_or( + Stage5KernelError::InvalidInputLength { + input: "stage5.ram_ra_claim_reduction.RamRa", + expected: usize::MAX, + actual: witness.ram_k, + }, + )?; + if !witness.ram_ra.is_empty() { + require_operand_count( + "stage5.ram_ra_claim_reduction.RamRa", + expected_len, + witness.ram_ra.len(), + )?; + let mut output = vec![F::zero(); witness.trace_len]; + for (address, &weight) in address_eq.iter().enumerate() { + let base = address * witness.trace_len; + for (cycle, output) in output.iter_mut().enumerate() { + *output += weight * witness.ram_ra[base + cycle]; + } + } + return Ok(output); + } + + let Some(remapped_addresses) = witness.remapped_addresses else { + return Err(Stage5KernelError::MissingKernelInput { + kernel: "jolt_stage5_batched", + input: "ram_ra.remapped_addresses", + }); + }; + require_operand_count( + "stage5.ram_ra_claim_reduction.remapped_addresses", + witness.trace_len, + remapped_addresses.len(), + )?; + remapped_addresses + .iter() + .map(|address| match address { + Some(address) => { + address_eq + .get(*address) + .copied() + .ok_or(Stage5KernelError::InvalidInputLength { + input: "stage5.ram_ra_claim_reduction.remapped_addresses", + expected: address_eq.len(), + actual: address + 1, + }) + } + None => Ok(F::zero()), + }) + .collect() +} + +fn registers_val_evaluation_state( + claim: &Stage5SumcheckClaimPlan, + inputs: &Stage5ProverInputs<'_, F>, + store: &Stage5ValueStore, + active_scale: F, +) -> Result, Stage5KernelError> { + let witness = inputs + .registers_val + .ok_or(Stage5KernelError::MissingKernelInput { + kernel: "jolt_stage5_batched", + input: "registers_val", + })?; + require_operand_count( + "stage5.registers_val_evaluation.RdInc", + witness.trace_len, + witness.rd_inc.len(), + )?; + require_operand_count( + "stage5.registers_val_evaluation.input", + log2_exact(witness.trace_len, "stage5.trace_len")?, + claim.num_rounds, + )?; + + let registers_val_point = store.point("stage5.input.stage4.registers.RegistersVal")?; + let register_rounds = log2_exact(witness.register_count, "stage5.register_count")?; + let trace_rounds = log2_exact(witness.trace_len, "stage5.trace_len")?; + require_operand_count( + "stage5.input.stage4.registers.RegistersVal", + register_rounds + trace_rounds, + registers_val_point.len(), + )?; + let (address_point, cycle_point) = registers_val_point.split_at(register_rounds); + let address_eq = EqPolynomial::::evals(address_point, None); + let rd_wa_at_address = rd_wa_at_register_address(witness, &address_eq)?; + let lt = lt_evals_big_endian(cycle_point); + require_operand_count( + "stage5.registers_val_evaluation.lt", + witness.trace_len, + lt.len(), + )?; + + Ok(DenseStage5State::new( + vec![witness.rd_inc.to_vec(), rd_wa_at_address, lt], + vec![DenseTerm { + coefficient: F::one(), + factors: vec![0, 1, 2], + }], + vec![ + FactorOutput { + name: "stage5.registers_val_evaluation.eval.RdInc", + oracle: "RdInc", + factor: 0, + }, + FactorOutput { + name: "stage5.registers_val_evaluation.eval.RdWa", + oracle: "RdWa", + factor: 1, + }, + ], + active_scale, + )) +} + +fn rd_wa_at_register_address( + witness: Stage5RegistersValWitness<'_, F>, + address_eq: &[F], +) -> Result, Stage5KernelError> { + let expected_len = witness + .register_count + .checked_mul(witness.trace_len) + .ok_or(Stage5KernelError::InvalidInputLength { + input: "stage5.registers_val_evaluation.RdWa", + expected: usize::MAX, + actual: witness.register_count, + })?; + if !witness.rd_wa.is_empty() { + require_operand_count( + "stage5.registers_val_evaluation.RdWa", + expected_len, + witness.rd_wa.len(), + )?; + let mut output = vec![F::zero(); witness.trace_len]; + for (address, &weight) in address_eq.iter().enumerate() { + let base = address * witness.trace_len; + for (cycle, output) in output.iter_mut().enumerate() { + *output += weight * witness.rd_wa[base + cycle]; + } + } + return Ok(output); + } + + let Some(rd_write_addresses) = witness.rd_write_addresses else { + return Err(Stage5KernelError::MissingKernelInput { + kernel: "jolt_stage5_batched", + input: "registers_val.rd_wa", + }); + }; + require_operand_count( + "stage5.registers_val_evaluation.rd_write_addresses", + witness.trace_len, + rd_write_addresses.len(), + )?; + rd_write_addresses + .iter() + .map(|address| match address { + Some(address) => { + address_eq + .get(*address) + .copied() + .ok_or(Stage5KernelError::InvalidInputLength { + input: "stage5.registers_val_evaluation.rd_write_addresses", + expected: address_eq.len(), + actual: address + 1, + }) + } + None => Ok(F::zero()), + }) + .collect() +} + +fn expected_batched_output_claim( + context: Stage5KernelContext<'_>, + store: &Stage5ValueStore, + evals: &[Stage5NamedEval], + point: &[F], + batching_coeffs: &[F], +) -> Result { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let instance = context + .program + .instance_results + .iter() + .find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) + .ok_or(Stage5KernelError::MissingClaim { + batch: context.batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage5KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let relation = claim.relation.unwrap_or(instance.relation); + let value = match Stage5Relation::from_symbol(relation) + .ok_or(Stage5KernelError::UnknownRelation { relation })? + { + Stage5Relation::InstructionReadRaf => { + expected_instruction_read_raf(store, evals, local_point)? + } + Stage5Relation::RamRaClaimReduction => { + expected_ram_ra_claim_reduction(store, evals, local_point)? + } + Stage5Relation::RegistersValEvaluation => { + expected_registers_val_evaluation(store, evals, local_point)? + } + relation @ Stage5Relation::Batched => { + return Err(Stage5KernelError::KernelNotImplemented { + abi: relation.symbol(), + }) + } + }; + expected += coefficient * value; + } + Ok(expected) +} + +fn expected_instruction_read_raf( + store: &Stage5ValueStore, + evals: &[Stage5NamedEval], + local_point: &[F], +) -> Result { + const LOG_K: usize = 128; + const XLEN: usize = 64; + + if local_point.len() < LOG_K { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.point", + expected: LOG_K, + actual: local_point.len(), + }); + } + + let (r_address_prime, r_cycle) = local_point.split_at(LOG_K); + let r_cycle_prime = reverse_slice(r_cycle); + let r_reduction = store.point("stage5.input.stage2.instruction.LookupOutput")?; + let eq_eval_r_reduction = EqPolynomial::::mle(r_reduction, &r_cycle_prime); + + let left_operand_eval = operand_polynomial_eval(r_address_prime, true); + let right_operand_eval = operand_polynomial_eval(r_address_prime, false); + let identity_poly_eval = identity_polynomial_eval(r_address_prime); + + let table_values = LookupTableKind::::all() + .iter() + .map(|table| table.evaluate_mle::(r_address_prime)) + .collect::>(); + let table_flag_claims = indexed_evals_by_prefix( + evals, + "stage5.instruction_read_raf.eval.LookupTableFlag_", + table_values.len(), + )?; + let val_claim = table_values + .into_iter() + .zip(table_flag_claims) + .map(|(table_value, flag_claim)| table_value * flag_claim) + .sum::(); + + let ra_claim = + indexed_evals_by_prefix_any(evals, "stage5.instruction_read_raf.eval.InstructionRa_")? + .into_iter() + .product::(); + let raf_flag_claim = + eval_by_name(evals, "stage5.instruction_read_raf.eval.InstructionRafFlag")?; + let gamma = store.scalar("stage5.instruction_read_raf.gamma")?; + + let raf_claim = (F::one() - raf_flag_claim) * (left_operand_eval + gamma * right_operand_eval) + + raf_flag_claim * gamma * identity_poly_eval; + Ok(eq_eval_r_reduction * ra_claim * (val_claim + gamma * raf_claim)) +} + +pub fn instruction_read_raf_output_evals( + witness: Stage5InstructionReadRafWitness<'_>, + address_point: &[F], + cycle_point: &[F], +) -> Result, Stage5KernelError> { + const LOG_K: usize = 128; + const XLEN: usize = 64; + + require_operand_count( + "stage5.instruction_read_raf.address_point", + LOG_K, + address_point.len(), + )?; + let trace_len_from_point = 1usize.checked_shl(cycle_point.len() as u32).ok_or( + Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.cycle_point", + expected: usize::BITS as usize, + actual: cycle_point.len(), + }, + )?; + require_operand_count( + "stage5.instruction_read_raf.trace_len", + trace_len_from_point, + witness.trace_len, + )?; + require_operand_count( + "stage5.instruction_read_raf.lookup_indices", + witness.trace_len, + witness.lookup_indices.len(), + )?; + require_operand_count( + "stage5.instruction_read_raf.lookup_table_indices", + witness.trace_len, + witness.lookup_table_indices.len(), + )?; + require_operand_count( + "stage5.instruction_read_raf.is_interleaved_operands", + witness.trace_len, + witness.is_interleaved_operands.len(), + )?; + if witness.ra_virtual_log_k_chunk == 0 || !LOG_K.is_multiple_of(witness.ra_virtual_log_k_chunk) + { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.ra_virtual_log_k_chunk", + expected: LOG_K, + actual: witness.ra_virtual_log_k_chunk, + }); + } + + let table_count = LookupTableKind::::all().len(); + let ra_chunks = LOG_K / witness.ra_virtual_log_k_chunk; + let cycle_eq = EqPolynomial::::evals(cycle_point, None); + require_operand_count( + "stage5.instruction_read_raf.eq_cycle", + witness.trace_len, + cycle_eq.len(), + )?; + + let mut grouped_weights = + HashMap::<(u128, Option, bool), F>::with_capacity(witness.trace_len.min(1 << 14)); + for (((&lookup_index, table_index), is_interleaved), &weight) in witness + .lookup_indices + .iter() + .zip(witness.lookup_table_indices.iter()) + .zip(witness.is_interleaved_operands.iter()) + .zip(&cycle_eq) + { + *grouped_weights + .entry((lookup_index, *table_index, *is_interleaved)) + .or_insert_with(F::zero) += weight; + } + + let mut lookup_table_flags = vec![F::zero(); table_count]; + let mut instruction_raf_flag = F::zero(); + for ((_, table_index, is_interleaved), &weight) in &grouped_weights { + if let Some(table_index) = table_index { + let Some(flag) = lookup_table_flags.get_mut(*table_index) else { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.lookup_table_indices", + expected: table_count, + actual: *table_index + 1, + }); + }; + *flag += weight; + } + if !*is_interleaved { + instruction_raf_flag += weight; + } + } + + let chunk_bits = witness.ra_virtual_log_k_chunk; + let chunk_mask = if chunk_bits == 128 { + u128::MAX + } else { + (1u128 << chunk_bits) - 1 + }; + let instruction_ra = (0..ra_chunks) + .map(|chunk| { + let chunk_point = &address_point[chunk * chunk_bits..(chunk + 1) * chunk_bits]; + let eq_tables = eq_eval_bit_chunk_tables(chunk_point, 8); + let shift = LOG_K - (chunk + 1) * chunk_bits; + grouped_weights + .iter() + .map(|((lookup_index, _, _), &cycle_weight)| { + let chunk_value = (*lookup_index >> shift) & chunk_mask; + cycle_weight + * eq_eval_at_bits_from_chunk_tables(&eq_tables, chunk_value, chunk_bits, 8) + }) + .sum() + }) + .collect(); + + Ok(Stage5InstructionReadRafEvaluations { + lookup_table_flags, + instruction_ra, + instruction_raf_flag, + }) +} + +fn expected_ram_ra_claim_reduction( + store: &Stage5ValueStore, + evals: &[Stage5NamedEval], + local_point: &[F], +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle_raf = suffix_point( + store.point("stage5.input.stage2.ram_raf.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage2.ram_raf.RamRa", + )?; + let r_cycle_rw = suffix_point( + store.point("stage5.input.stage2.ram_read_write.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage2.ram_read_write.RamRa", + )?; + let r_cycle_val = suffix_point( + store.point("stage5.input.stage4.ram_val_check.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage4.ram_val_check.RamRa", + )?; + let gamma = store.scalar("stage5.ram_ra_claim_reduction.gamma")?; + let eq_combined = EqPolynomial::::mle(r_cycle_raf, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(r_cycle_rw, &r_cycle_reduced) + + gamma.square() * EqPolynomial::::mle(r_cycle_val, &r_cycle_reduced); + let ram_ra = eval_by_name(evals, "stage5.ram_ra_claim_reduction.eval.RamRa")?; + Ok(eq_combined * ram_ra) +} + +fn expected_registers_val_evaluation( + store: &Stage5ValueStore, + evals: &[Stage5NamedEval], + local_point: &[F], +) -> Result { + let registers_val_point = store.point("stage5.input.stage4.registers.RegistersVal")?; + let r_cycle = suffix_point( + registers_val_point, + local_point.len(), + "stage5.input.stage4.registers.RegistersVal", + )?; + let r_reduced = reverse_slice(local_point); + let lt_eval = lt_polynomial_eval(&r_reduced, r_cycle); + let rd_inc = eval_by_name(evals, "stage5.registers_val_evaluation.eval.RdInc")?; + let rd_wa = eval_by_name(evals, "stage5.registers_val_evaluation.eval.RdWa")?; + Ok(rd_inc * rd_wa * lt_eval) +} + +fn eval_by_name( + evals: &[Stage5NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage5KernelError::MissingValue { symbol: name }) +} + +fn named_eval(name: &'static str, oracle: &'static str, value: F) -> Stage5NamedEval { + Stage5NamedEval { + name, + oracle, + value, + } +} + +fn claim_relation( + program: &'static Stage5CpuProgramPlan, + claim: &Stage5SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage5Relation::from_symbol(relation) + .ok_or(Stage5KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage5KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage5KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + Stage5Relation::from_symbol(kernel.relation).ok_or(Stage5KernelError::UnknownRelation { + relation: kernel.relation, + }) +} + +fn instance_round_offset( + program: &'static Stage5CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage5KernelError::MissingClaim { + batch: driver, + claim, + }) +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + UnivariatePoly::new(combined) +} + +fn round_poly_from_dense_terms( + factors: &[Vec], + terms: &[DenseTerm], + active_scale: F, + relation: Stage5Relation, +) -> Result, Stage5KernelError> { + let half = factors.first().map_or(0, |factor| factor.len() / 2); + for term in terms { + if term.factors.len() > 3 { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage5 dense term exceeds degree bound", + }); + } + if term.factors.iter().any(|factor| *factor >= factors.len()) { + return Err(Stage5KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage5 dense term references missing factor", + }); + } + } + + let accumulators = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .map(|row| dense_row_coefficients(factors, terms, row)) + .reduce( + || [F::Accumulator::default(); 4], + |mut left, right| { + for index in 0..left.len() { + left[index].merge(right[index]); + } + left + }, + ) + } else { + (0..half).fold([F::Accumulator::default(); 4], |mut total, row| { + let row_coefficients = dense_row_coefficients(factors, terms, row); + for index in 0..total.len() { + total[index].merge(row_coefficients[index]); + } + total + }) + }; + + Ok(UnivariatePoly::new( + accumulators + .into_iter() + .map(AdditiveAccumulator::reduce) + .map(|coefficient| coefficient * active_scale) + .collect(), + )) +} + +fn dense_row_coefficients( + factors: &[Vec], + terms: &[DenseTerm], + row: usize, +) -> [F::Accumulator; 4] { + let mut coefficients = [F::Accumulator::default(); 4]; + for term in terms { + match term.factors.as_slice() { + [] => coefficients[0].add(term.coefficient), + [first] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + coefficients[0].fmadd(term.coefficient, first0); + coefficients[1].fmadd(term.coefficient, first_delta); + } + [first, second] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + let (second0, second_delta) = linear_factor_pair(&factors[*second], row); + accumulate_quadratic_coefficients( + &mut coefficients, + term.coefficient, + first0, + first_delta, + second0, + second_delta, + ); + } + [first, second, third] => { + let (first0, first_delta) = linear_factor_pair(&factors[*first], row); + let (second0, second_delta) = linear_factor_pair(&factors[*second], row); + let (third0, third_delta) = linear_factor_pair(&factors[*third], row); + accumulate_cubic_coefficients( + &mut coefficients, + term.coefficient, + first0, + first_delta, + second0, + second_delta, + third0, + third_delta, + ); + } + _ => unreachable!("dense terms are validated before evaluation"), + } + } + coefficients +} + +#[inline] +fn linear_factor_pair(factor: &[F], row: usize) -> (F, F) { + let low = factor[2 * row]; + (low, factor[2 * row + 1] - low) +} + +#[inline] +fn accumulate_quadratic_coefficients( + coefficients: &mut [F::Accumulator; 4], + scale: F, + first0: F, + first_delta: F, + second0: F, + second_delta: F, +) { + coefficients[0].fmadd(scale * first0, second0); + coefficients[1].fmadd(scale * first_delta, second0); + coefficients[1].fmadd(scale * first0, second_delta); + coefficients[2].fmadd(scale * first_delta, second_delta); +} + +#[inline] +fn accumulate_cubic_coefficients( + coefficients: &mut [F::Accumulator; 4], + scale: F, + first0: F, + first_delta: F, + second0: F, + second_delta: F, + third0: F, + third_delta: F, +) { + let second0_third0 = second0 * third0; + let second_delta_third0 = second_delta * third0; + let second0_third_delta = second0 * third_delta; + let second_delta_third_delta = second_delta * third_delta; + let scaled_first0 = scale * first0; + let scaled_first_delta = scale * first_delta; + + coefficients[0].fmadd(scaled_first0, second0_third0); + coefficients[1].fmadd(scaled_first_delta, second0_third0); + coefficients[1].fmadd(scaled_first0, second_delta_third0); + coefficients[1].fmadd(scaled_first0, second0_third_delta); + coefficients[2].fmadd(scaled_first_delta, second_delta_third0); + coefficients[2].fmadd(scaled_first_delta, second0_third_delta); + coefficients[2].fmadd(scaled_first0, second_delta_third_delta); + coefficients[3].fmadd(scaled_first_delta, second_delta_third_delta); +} + +fn indexed_evals_by_prefix( + evals: &[Stage5NamedEval], + prefix: &'static str, + count: usize, +) -> Result, Stage5KernelError> { + let mut values = vec![None; count]; + for eval in evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| Stage5KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if index >= count || values[index].is_some() { + return Err(Stage5KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval", + }); + } + values[index] = Some(eval.value); + } + values + .into_iter() + .map(|value| value.ok_or(Stage5KernelError::MissingValue { symbol: prefix })) + .collect() +} + +fn indexed_evals_by_prefix_any( + evals: &[Stage5NamedEval], + prefix: &'static str, +) -> Result, Stage5KernelError> { + let mut indexed_values = Vec::new(); + for eval in evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| Stage5KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if indexed_values + .iter() + .any(|(existing_index, _)| *existing_index == index) + { + return Err(Stage5KernelError::InvalidProof { + driver: prefix, + reason: "duplicate indexed eval", + }); + } + indexed_values.push((index, eval.value)); + } + if indexed_values.is_empty() { + return Err(Stage5KernelError::MissingValue { symbol: prefix }); + } + indexed_values.sort_by_key(|(index, _)| *index); + for (expected, (actual, _)) in indexed_values.iter().enumerate() { + if *actual != expected { + return Err(Stage5KernelError::InvalidProof { + driver: prefix, + reason: "non-contiguous indexed eval", + }); + } + } + Ok(indexed_values.into_iter().map(|(_, value)| value).collect()) +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims( + program: &'static Stage5CpuProgramPlan, + store: &mut Stage5ValueStore, + transcript: &mut T, + evals: &[Stage5NamedEval], +) -> Result>, Stage5KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + let mut seen = program + .opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect::>(); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage5KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let duplicate = seen.iter().any(|(kind, oracle, seen_point)| { + *kind == claim.claim_kind && *oracle == claim.oracle && seen_point == &point + }); + let value = store.scalar(claim.eval_source)?; + if !duplicate { + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point.clone())); + } + opening_claims.push(Stage5OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: point.clone(), + eval: value, + }); + } + } + Ok(opening_claims) +} + +fn find_opening_claim<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage5KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage5KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +fn suffix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], Stage5KernelError> { + point + .get(point.len().saturating_sub(length)..) + .filter(|suffix| suffix.len() == length) + .ok_or(Stage5KernelError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +fn reverse_slice(values: &[F]) -> Vec { + values.iter().rev().copied().collect() +} + +fn normalize_instruction_read_raf_point( + point: &[F], +) -> Result, Stage5KernelError> { + const LOG_K: usize = 128; + if point.len() < LOG_K { + return Err(Stage5KernelError::InvalidInputLength { + input: "stage5.instruction_read_raf.point", + expected: LOG_K, + actual: point.len(), + }); + } + let mut normalized = point.to_vec(); + normalized[LOG_K..].reverse(); + Ok(normalized) +} + +fn lt_polynomial_eval(x: &[F], y: &[F]) -> F { + debug_assert_eq!(x.len(), y.len()); + let mut lt_eval = F::zero(); + let mut eq_term = F::one(); + for (x_i, y_i) in x.iter().zip(y.iter()) { + lt_eval += (F::one() - *x_i) * *y_i * eq_term; + eq_term *= F::one() - *x_i - *y_i + *x_i * *y_i + *x_i * *y_i; + } + lt_eval +} + +fn lt_evals_big_endian(point: &[F]) -> Vec { + let mut evals = vec![F::zero(); 1usize << point.len()]; + for (index, r) in point.iter().rev().enumerate() { + let (left, right) = evals.split_at_mut(1usize << index); + left.iter_mut().zip(right).for_each(|(left, right)| { + *right = *left * *r; + *left += *r - *right; + }); + } + evals +} + +fn operand_polynomial_eval(point: &[F], left: bool) -> F { + let stride_offset = usize::from(!left); + let operand_bits = point.len() / 2; + (0..operand_bits) + .map(|index| point[2 * index + stride_offset].mul_pow_2(operand_bits - 1 - index)) + .sum() +} + +fn eq_eval_at_bits(point: &[F], bits: u128, num_bits: usize) -> F { + debug_assert_eq!(point.len(), num_bits); + point + .iter() + .enumerate() + .map(|(index, &challenge)| { + if ((bits >> (num_bits - 1 - index)) & 1) == 1 { + challenge + } else { + F::one() - challenge + } + }) + .product() +} + +fn eq_eval_bit_chunk_tables(point: &[F], chunk_bits: usize) -> Vec> { + point + .chunks(chunk_bits) + .map(|chunk| { + let len = chunk.len(); + (0..(1usize << len)) + .map(|bits| eq_eval_at_bits(chunk, bits as u128, len)) + .collect() + }) + .collect() +} + +fn eq_eval_at_bits_from_chunk_tables( + tables: &[Vec], + bits: u128, + num_bits: usize, + chunk_bits: usize, +) -> F { + tables + .iter() + .enumerate() + .map(|(chunk_index, table)| { + let start = chunk_index * chunk_bits; + let len = table.len().ilog2() as usize; + let shift = num_bits - start - len; + let mask = (1u128 << len) - 1; + table[((bits >> shift) & mask) as usize] + }) + .product() +} + +#[cfg(test)] +#[inline] +fn lookup_bit(lookup_index: u128, index: usize, total_bits: usize) -> bool { + ((lookup_index >> (total_bits - 1 - index)) & 1) == 1 +} + +fn identity_polynomial_eval(point: &[F]) -> F { + point + .iter() + .enumerate() + .map(|(index, value)| value.mul_pow_2(point.len() - 1 - index)) + .sum() +} + +fn log2_exact(value: usize, input: &'static str) -> Result { + if value.is_power_of_two() { + Ok(value.ilog2() as usize) + } else { + Err(Stage5KernelError::InvalidInputLength { + input, + expected: value.next_power_of_two(), + actual: value, + }) + } +} + +pub fn execute_stage5_program( + program: &'static Stage5CpuProgramPlan, + mode: Stage5ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + F: Field, + T: Transcript, + E: Stage5KernelExecutor, +{ + let mut artifacts = Stage5ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_squeeze(program, step.symbol).ok_or(Stage5KernelError::MissingValue { + symbol: step.symbol, + })?; + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage5ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + "transcript_absorb_bytes" => { + let absorb = find_absorb_bytes(program, step.symbol).ok_or( + Stage5KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage5_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_driver(program, step.symbol).ok_or(Stage5KernelError::MissingDriver { + driver: step.symbol, + })?; + let kernel_symbol = driver.kernel.ok_or(Stage5KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or( + Stage5KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + }, + )?; + let batch = + find_batch(program, driver.batch).ok_or(Stage5KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage5KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage5ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage5ExecutionMode::Verifier => { + executor.verify_sumcheck(context, transcript)? + } + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + } + _ => { + return Err(Stage5KernelError::InvalidProgramStep { + symbol: step.symbol, + kind: step.kind, + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +fn absorb_stage5_bytes(absorb: &'static Stage5TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn find_squeeze<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|plan| plan.symbol == symbol) +} + +fn find_absorb_bytes<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5TranscriptAbsorbBytesPlan> { + program + .transcript_absorb_bytes + .iter() + .find(|plan| plan.symbol == symbol) +} + +fn find_driver<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_kernel<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch<'a>( + program: &'a Stage5CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage5SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +#[cfg(test)] +#[expect( + clippy::expect_used, + reason = "tests use expect to keep failure context concise" +)] +mod tests { + use super::*; + use jolt_field::{Fr, RingCore}; + use jolt_sumcheck::SumcheckProof; + use jolt_transcript::Blake2bTranscript; + + const PARAMS: Stage5Params = Stage5Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }; + const STEPS: &[Stage5ProgramStepPlan] = &[ + Stage5ProgramStepPlan { + kind: "transcript_squeeze", + symbol: "stage5.gamma", + }, + Stage5ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage5.sumcheck", + }, + ]; + const SQUEEZES: &[Stage5TranscriptSqueezePlan] = &[Stage5TranscriptSqueezePlan { + symbol: "stage5.gamma", + label: "stage5_gamma", + kind: "challenge_scalar", + count: 1, + }]; + const KERNELS: &[Stage5KernelPlan] = &[Stage5KernelPlan { + symbol: "jolt.cpu.stage5.batched", + relation: "jolt.stage5.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_batched", + }]; + const CLAIM_INPUTS: &[&str] = &[]; + const CLAIMS: &[Stage5SumcheckClaimPlan] = &[Stage5SumcheckClaimPlan { + symbol: "stage5.claim", + stage: "stage5", + domain: "jolt.trace_domain", + num_rounds: 1, + degree: 1, + claim: "stage5.claim", + kernel: Some("jolt.cpu.stage5.batched"), + relation: Some("jolt.stage5.batched"), + claim_value: "stage5.gamma", + input_openings: CLAIM_INPUTS, + }]; + const ORDERED_CLAIMS: &[&str] = &["stage5.claim"]; + const ROUND_SCHEDULE: &[usize] = &[1]; + const BATCHES: &[Stage5SumcheckBatchPlan] = &[Stage5SumcheckBatchPlan { + symbol: "stage5.batch", + stage: "stage5", + proof_slot: "stage5.sumcheck", + policy: "test", + count: 1, + ordered_claims: ORDERED_CLAIMS, + claim_operands: ORDERED_CLAIMS, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: ROUND_SCHEDULE, + }]; + const DRIVERS: &[Stage5SumcheckDriverPlan] = &[Stage5SumcheckDriverPlan { + symbol: "stage5.sumcheck", + stage: "stage5", + proof_slot: "stage5.sumcheck", + kernel: Some("jolt.cpu.stage5.batched"), + relation: Some("jolt.stage5.batched"), + batch: "stage5.batch", + policy: "test", + round_schedule: ROUND_SCHEDULE, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 1, + degree: 1, + }]; + const PROGRAM: Stage5CpuProgramPlan = Stage5CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: SQUEEZES, + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: &[], + field_exprs: &[], + kernels: KERNELS, + claims: CLAIMS, + batches: BATCHES, + drivers: DRIVERS, + instance_results: &[], + evals: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + + const REGISTERS_STEPS: &[Stage5ProgramStepPlan] = &[Stage5ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage5.registers.sumcheck", + }]; + const REGISTERS_OPENING_INPUTS: &[Stage5OpeningInputPlan] = &[Stage5OpeningInputPlan { + symbol: "stage5.input.stage4.registers.RegistersVal", + source_stage: "stage4", + source_claim: "stage4.registers_read_write.opening.RegistersVal", + oracle: "RegistersVal", + domain: "jolt.stage4_registers_rw_domain", + point_arity: 3, + claim_kind: "virtual", + }]; + const REGISTERS_KERNELS: &[Stage5KernelPlan] = &[ + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.registers_val_evaluation", + relation: "jolt.stage5.registers_val_evaluation", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_registers_val_evaluation", + }, + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.batched", + relation: "jolt.stage5.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_batched", + }, + ]; + const REGISTERS_CLAIM_INPUTS: &[&str] = &["stage5.input.stage4.registers.RegistersVal"]; + const REGISTERS_CLAIMS: &[Stage5SumcheckClaimPlan] = &[Stage5SumcheckClaimPlan { + symbol: "stage5.registers_val_evaluation.input", + stage: "stage5", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 3, + claim: "stage5.registers_val_evaluation.registers_val", + kernel: Some("jolt.cpu.stage5.registers_val_evaluation"), + relation: Some("jolt.stage5.registers_val_evaluation"), + claim_value: "stage5.input.stage4.registers.RegistersVal", + input_openings: REGISTERS_CLAIM_INPUTS, + }]; + const REGISTERS_ORDERED_CLAIMS: &[&str] = &["stage5.registers_val_evaluation.input"]; + const REGISTERS_ROUND_SCHEDULE: &[usize] = &[2]; + const REGISTERS_BATCHES: &[Stage5SumcheckBatchPlan] = &[Stage5SumcheckBatchPlan { + symbol: "stage5.registers.batch", + stage: "stage5", + proof_slot: "stage5.registers.sumcheck", + policy: "test", + count: 1, + ordered_claims: REGISTERS_ORDERED_CLAIMS, + claim_operands: REGISTERS_ORDERED_CLAIMS, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: REGISTERS_ROUND_SCHEDULE, + }]; + const REGISTERS_DRIVERS: &[Stage5SumcheckDriverPlan] = &[Stage5SumcheckDriverPlan { + symbol: "stage5.registers.sumcheck", + stage: "stage5", + proof_slot: "stage5.registers.sumcheck", + kernel: Some("jolt.cpu.stage5.batched"), + relation: Some("jolt.stage5.batched"), + batch: "stage5.registers.batch", + policy: "test", + round_schedule: REGISTERS_ROUND_SCHEDULE, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 3, + }]; + const REGISTERS_INSTANCES: &[Stage5SumcheckInstanceResultPlan] = + &[Stage5SumcheckInstanceResultPlan { + symbol: "stage5.registers_val_evaluation.instance", + source: "stage5.registers.sumcheck", + claim: "stage5.registers_val_evaluation.input", + relation: "jolt.stage5.registers_val_evaluation", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 3, + }]; + const REGISTERS_EVALS: &[Stage5SumcheckEvalPlan] = &[ + Stage5SumcheckEvalPlan { + symbol: "stage5.registers_val_evaluation.eval.RdInc", + source: "stage5.registers.sumcheck", + name: "stage5.registers_val_evaluation.eval.RdInc", + index: 0, + oracle: "RdInc", + }, + Stage5SumcheckEvalPlan { + symbol: "stage5.registers_val_evaluation.eval.RdWa", + source: "stage5.registers.sumcheck", + name: "stage5.registers_val_evaluation.eval.RdWa", + index: 1, + oracle: "RdWa", + }, + ]; + const REGISTERS_PROGRAM: Stage5CpuProgramPlan = Stage5CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: REGISTERS_STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: REGISTERS_OPENING_INPUTS, + field_constants: &[], + field_exprs: &[], + kernels: REGISTERS_KERNELS, + claims: REGISTERS_CLAIMS, + batches: REGISTERS_BATCHES, + drivers: REGISTERS_DRIVERS, + instance_results: REGISTERS_INSTANCES, + evals: REGISTERS_EVALS, + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + + const RAM_RA_STEPS: &[Stage5ProgramStepPlan] = &[Stage5ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage5.ram_ra.sumcheck", + }]; + const RAM_RA_OPENING_INPUTS: &[Stage5OpeningInputPlan] = &[ + Stage5OpeningInputPlan { + symbol: "stage5.input.stage2.ram_raf.RamRa", + source_stage: "stage2", + source_claim: "stage2.ram_raf.opening.RamRa", + oracle: "RamRa", + domain: "jolt.stage2_ram_rw_domain", + point_arity: 3, + claim_kind: "virtual", + }, + Stage5OpeningInputPlan { + symbol: "stage5.input.stage2.ram_read_write.RamRa", + source_stage: "stage2", + source_claim: "stage2.ram_read_write.opening.RamRa", + oracle: "RamRa", + domain: "jolt.stage2_ram_rw_domain", + point_arity: 3, + claim_kind: "virtual", + }, + Stage5OpeningInputPlan { + symbol: "stage5.input.stage4.ram_val_check.RamRa", + source_stage: "stage4", + source_claim: "stage4.ram_val_check.opening.RamRa", + oracle: "RamRa", + domain: "jolt.stage2_ram_rw_domain", + point_arity: 3, + claim_kind: "virtual", + }, + ]; + const RAM_RA_FIELD_CONSTANTS: &[Stage5FieldConstantPlan] = &[Stage5FieldConstantPlan { + symbol: "stage5.ram_ra_claim_reduction.gamma", + field: "bn254_fr", + value: 2, + }]; + const RAM_RA_GAMMA2_OPERANDS: &[&str] = &["stage5.ram_ra_claim_reduction.gamma"]; + const RAM_RA_RW_TERM_OPERANDS: &[&str] = &[ + "stage5.ram_ra_claim_reduction.gamma", + "stage5.input.stage2.ram_read_write.RamRa", + ]; + const RAM_RA_VAL_TERM_OPERANDS: &[&str] = &[ + "stage5.ram_ra_claim_reduction.gamma2", + "stage5.input.stage4.ram_val_check.RamRa", + ]; + const RAM_RA_PARTIAL_OPERANDS: &[&str] = &[ + "stage5.input.stage2.ram_raf.RamRa", + "stage5.ram_ra_claim_reduction.term.RamRaReadWrite", + ]; + const RAM_RA_CLAIM_OPERANDS_EXPR: &[&str] = &[ + "stage5.ram_ra_claim_reduction.partial.RafReadWrite", + "stage5.ram_ra_claim_reduction.term.RamRaValCheck", + ]; + const RAM_RA_FIELD_EXPRS: &[Stage5FieldExprPlan] = &[ + Stage5FieldExprPlan { + symbol: "stage5.ram_ra_claim_reduction.gamma2", + kind: "op", + formula: "field.pow:2", + operand_names: RAM_RA_GAMMA2_OPERANDS, + operands: RAM_RA_GAMMA2_OPERANDS, + }, + Stage5FieldExprPlan { + symbol: "stage5.ram_ra_claim_reduction.term.RamRaReadWrite", + kind: "op", + formula: "field.mul", + operand_names: RAM_RA_RW_TERM_OPERANDS, + operands: RAM_RA_RW_TERM_OPERANDS, + }, + Stage5FieldExprPlan { + symbol: "stage5.ram_ra_claim_reduction.term.RamRaValCheck", + kind: "op", + formula: "field.mul", + operand_names: RAM_RA_VAL_TERM_OPERANDS, + operands: RAM_RA_VAL_TERM_OPERANDS, + }, + Stage5FieldExprPlan { + symbol: "stage5.ram_ra_claim_reduction.partial.RafReadWrite", + kind: "op", + formula: "field.add", + operand_names: RAM_RA_PARTIAL_OPERANDS, + operands: RAM_RA_PARTIAL_OPERANDS, + }, + Stage5FieldExprPlan { + symbol: "stage5.ram_ra_claim_reduction.claim_expr", + kind: "op", + formula: "field.add", + operand_names: RAM_RA_CLAIM_OPERANDS_EXPR, + operands: RAM_RA_CLAIM_OPERANDS_EXPR, + }, + ]; + const RAM_RA_KERNELS: &[Stage5KernelPlan] = &[ + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.ram_ra_claim_reduction", + relation: "jolt.stage5.ram_ra_claim_reduction", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_ram_ra_claim_reduction", + }, + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.batched", + relation: "jolt.stage5.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_batched", + }, + ]; + const RAM_RA_CLAIM_INPUTS: &[&str] = &[ + "stage5.input.stage2.ram_raf.RamRa", + "stage5.input.stage2.ram_read_write.RamRa", + "stage5.input.stage4.ram_val_check.RamRa", + ]; + const RAM_RA_CLAIMS: &[Stage5SumcheckClaimPlan] = &[Stage5SumcheckClaimPlan { + symbol: "stage5.ram_ra_claim_reduction.input", + stage: "stage5", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 2, + claim: "stage5.ram_ra_claim_reduction.weighted_ram_ra", + kernel: Some("jolt.cpu.stage5.ram_ra_claim_reduction"), + relation: Some("jolt.stage5.ram_ra_claim_reduction"), + claim_value: "stage5.ram_ra_claim_reduction.claim_expr", + input_openings: RAM_RA_CLAIM_INPUTS, + }]; + const RAM_RA_ORDERED_CLAIMS: &[&str] = &["stage5.ram_ra_claim_reduction.input"]; + const RAM_RA_ROUND_SCHEDULE: &[usize] = &[2]; + const RAM_RA_BATCHES: &[Stage5SumcheckBatchPlan] = &[Stage5SumcheckBatchPlan { + symbol: "stage5.ram_ra.batch", + stage: "stage5", + proof_slot: "stage5.ram_ra.sumcheck", + policy: "test", + count: 1, + ordered_claims: RAM_RA_ORDERED_CLAIMS, + claim_operands: RAM_RA_ORDERED_CLAIMS, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: RAM_RA_ROUND_SCHEDULE, + }]; + const RAM_RA_DRIVERS: &[Stage5SumcheckDriverPlan] = &[Stage5SumcheckDriverPlan { + symbol: "stage5.ram_ra.sumcheck", + stage: "stage5", + proof_slot: "stage5.ram_ra.sumcheck", + kernel: Some("jolt.cpu.stage5.batched"), + relation: Some("jolt.stage5.batched"), + batch: "stage5.ram_ra.batch", + policy: "test", + round_schedule: RAM_RA_ROUND_SCHEDULE, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 2, + }]; + const RAM_RA_INSTANCES: &[Stage5SumcheckInstanceResultPlan] = + &[Stage5SumcheckInstanceResultPlan { + symbol: "stage5.ram_ra_claim_reduction.instance", + source: "stage5.ram_ra.sumcheck", + claim: "stage5.ram_ra_claim_reduction.input", + relation: "jolt.stage5.ram_ra_claim_reduction", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 2, + }]; + const RAM_RA_EVALS: &[Stage5SumcheckEvalPlan] = &[Stage5SumcheckEvalPlan { + symbol: "stage5.ram_ra_claim_reduction.eval.RamRa", + source: "stage5.ram_ra.sumcheck", + name: "stage5.ram_ra_claim_reduction.eval.RamRa", + index: 0, + oracle: "RamRa", + }]; + const RAM_RA_PROGRAM: Stage5CpuProgramPlan = Stage5CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: RAM_RA_STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: RAM_RA_OPENING_INPUTS, + field_constants: RAM_RA_FIELD_CONSTANTS, + field_exprs: RAM_RA_FIELD_EXPRS, + kernels: RAM_RA_KERNELS, + claims: RAM_RA_CLAIMS, + batches: RAM_RA_BATCHES, + drivers: RAM_RA_DRIVERS, + instance_results: RAM_RA_INSTANCES, + evals: RAM_RA_EVALS, + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + + #[derive(Default)] + struct RecordingExecutor { + observed_challenges: usize, + proved: bool, + } + + impl Stage5KernelExecutor for RecordingExecutor { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage5TranscriptSqueezePlan, + values: &[Fr], + ) -> Result<(), Stage5KernelError> { + assert_eq!(plan.symbol, "stage5.gamma"); + assert_eq!(values.len(), 1); + self.observed_challenges += 1; + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + assert_eq!(context.mode, Stage5ExecutionMode::Prover); + assert_eq!(context.abi_kind()?, Stage5KernelAbi::Batched); + assert_eq!(context.relation_kind()?, Stage5Relation::Batched); + assert_eq!(context.batch_claims()?.len(), 1); + self.proved = true; + Ok(Stage5SumcheckOutput { + driver: context.driver.symbol, + point: vec![Fr::from_u64(7)], + evals: Vec::new(), + opening_claims: Vec::new(), + proof: SumcheckProof { + round_polynomials: Vec::new(), + }, + }) + } + + fn verify_sumcheck( + &mut self, + context: Stage5KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage5KernelError> + where + T: Transcript, + { + Err(Stage5KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage5ExecutionMode::Prover, + actual: Stage5ExecutionMode::Verifier, + }) + } + } + + #[test] + fn stage5_program_executes_with_stage5_abi_and_relation_names() { + let mut transcript = Blake2bTranscript::::new(b"Jolt"); + let mut executor = RecordingExecutor::default(); + + let artifacts = execute_stage5_program( + &PROGRAM, + Stage5ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect("stage5 program executes"); + + assert_eq!(executor.observed_challenges, 1); + assert!(executor.proved); + assert_eq!(artifacts.challenge_vectors.len(), 1); + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].driver, "stage5.sumcheck"); + } + + #[test] + fn stage5_registers_val_prover_produces_verifiable_sumcheck() { + let registers_point = frs(&[1, 2, 3]); + let rd_inc = frs(&[2, 3, 4, 5]); + let rd_write_addresses = [Some(0usize), Some(1usize), None, Some(1usize)]; + let input_eval = registers_val_input_claim(®isters_point, &rd_inc, &rd_write_addresses); + let opening_inputs = vec![Stage5OpeningInputValue { + symbol: "stage5.input.stage4.registers.RegistersVal", + point: registers_point, + eval: input_eval, + }]; + let prover_inputs = Stage5ProverInputs::new(&opening_inputs).with_registers_val( + Stage5RegistersValWitness { + register_count: 2, + trace_len: 4, + rd_inc: &rd_inc, + rd_wa: &[], + rd_write_addresses: Some(&rd_write_addresses), + }, + ); + let mut prover = Stage5ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"Jolt"); + let artifacts = execute_stage5_program( + ®ISTERS_PROGRAM, + Stage5ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("registers val prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 2); + + let proof = Stage5Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage5ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"Jolt"); + let verified = execute_stage5_program( + ®ISTERS_PROGRAM, + Stage5ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("registers val verifier accepts prover output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn stage5_ram_ra_prover_produces_verifiable_sumcheck() { + let ram_raf_point = frs(&[1, 2, 3]); + let ram_rw_point = frs(&[1, 5, 7]); + let ram_val_point = frs(&[1, 11, 13]); + let remapped_addresses = [Some(0usize), Some(1usize), None, Some(1usize)]; + let gamma = Fr::from_u64(2); + let claim_raf = ram_ra_input_claim(&ram_raf_point, &remapped_addresses); + let claim_rw = ram_ra_input_claim(&ram_rw_point, &remapped_addresses); + let claim_val = ram_ra_input_claim(&ram_val_point, &remapped_addresses); + let opening_inputs = vec![ + Stage5OpeningInputValue { + symbol: "stage5.input.stage2.ram_raf.RamRa", + point: ram_raf_point, + eval: claim_raf, + }, + Stage5OpeningInputValue { + symbol: "stage5.input.stage2.ram_read_write.RamRa", + point: ram_rw_point, + eval: claim_rw, + }, + Stage5OpeningInputValue { + symbol: "stage5.input.stage4.ram_val_check.RamRa", + point: ram_val_point, + eval: claim_val, + }, + ]; + let mut store = Stage5ValueStore::with_opening_inputs(&opening_inputs); + store.seed_constants(&RAM_RA_PROGRAM); + let _ = store + .evaluate_available_field_exprs(&RAM_RA_PROGRAM) + .expect("field exprs"); + assert_eq!( + claim_raf + gamma * claim_rw + gamma.square() * claim_val, + store + .scalar("stage5.ram_ra_claim_reduction.claim_expr") + .expect("claim expr") + ); + + let prover_inputs = + Stage5ProverInputs::new(&opening_inputs).with_ram_ra(Stage5RamRaWitness { + ram_k: 2, + trace_len: 4, + ram_ra: &[], + remapped_addresses: Some(&remapped_addresses), + }); + let mut prover = Stage5ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"Jolt"); + let artifacts = execute_stage5_program( + &RAM_RA_PROGRAM, + Stage5ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("ram ra prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 1); + + let proof = Stage5Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage5ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"Jolt"); + let verified = execute_stage5_program( + &RAM_RA_PROGRAM, + Stage5ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("ram ra verifier accepts prover output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn stage5_instruction_read_raf_prover_produces_verifiable_sumcheck() { + const CHUNK_BITS: usize = 64; + let r_reduction = frs(&[3, 5]); + let lookup_indices = [ + 0u128, + 1u128 << 127, + (0x1234u128 << 64) | 0xABCDu128, + (0x55AAu128 << 96) | (0xAA55u128 << 32), + ]; + let table_indices = [Some(0usize), Some(0usize), None, Some(0usize)]; + let is_interleaved = [true, false, true, false]; + let gamma = Fr::from_u64(2); + let (lookup_output_claim, left_claim, right_claim) = instruction_read_raf_input_claim( + &r_reduction, + &lookup_indices, + &table_indices, + &is_interleaved, + ); + let input_claim = lookup_output_claim + gamma * left_claim + gamma.square() * right_claim; + let opening_inputs = vec![ + Stage5OpeningInputValue { + symbol: "stage5.input.stage2.instruction.LookupOutput", + point: r_reduction.clone(), + eval: lookup_output_claim, + }, + Stage5OpeningInputValue { + symbol: "stage5.input.stage2.instruction.LeftLookupOperand", + point: r_reduction.clone(), + eval: left_claim, + }, + Stage5OpeningInputValue { + symbol: "stage5.input.stage2.instruction.RightLookupOperand", + point: r_reduction, + eval: right_claim, + }, + Stage5OpeningInputValue { + symbol: "stage5.instruction_read_raf.claim_expr", + point: Vec::new(), + eval: input_claim, + }, + ]; + let program = instruction_read_raf_test_program(2, 128 / CHUNK_BITS); + let prover_inputs = Stage5ProverInputs::new(&opening_inputs).with_instruction_read_raf( + Stage5InstructionReadRafWitness { + trace_len: 4, + lookup_indices: &lookup_indices, + lookup_table_indices: &table_indices, + is_interleaved_operands: &is_interleaved, + ra_virtual_log_k_chunk: CHUNK_BITS, + }, + ); + let mut prover = Stage5ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"Jolt"); + let artifacts = execute_stage5_program( + program, + Stage5ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("instruction read raf prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!( + artifacts.sumchecks[0].evals.len(), + LookupTableKind::<64>::all().len() + 128 / CHUNK_BITS + 1 + ); + + let proof = Stage5Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage5ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"Jolt"); + let verified = execute_stage5_program( + program, + Stage5ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("instruction read raf verifier accepts prover output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn instruction_read_raf_output_evals_follow_trace_flags_and_ra_chunks() { + const CHUNK_BITS: usize = 16; + let lookup_indices = [ + 0u128, + 1u128 << 112, + 0xABCDu128 << 96, + (0x12u128 << 112) | 0x34u128, + ]; + let table_indices = [Some(0usize), Some(2usize), None, Some(0usize)]; + let is_interleaved = [true, false, true, false]; + let address_point = (0..128) + .map(|index| Fr::from_u64(index as u64 + 2)) + .collect::>(); + let cycle_point = frs(&[3, 5]); + let witness = Stage5InstructionReadRafWitness { + trace_len: 4, + lookup_indices: &lookup_indices, + lookup_table_indices: &table_indices, + is_interleaved_operands: &is_interleaved, + ra_virtual_log_k_chunk: CHUNK_BITS, + }; + + let output = instruction_read_raf_output_evals(witness, &address_point, &cycle_point) + .expect("instruction read raf evals"); + let cycle_eq = EqPolynomial::::evals(&cycle_point, None); + assert_eq!(output.lookup_table_flags[0], cycle_eq[0] + cycle_eq[3]); + assert_eq!(output.lookup_table_flags[2], cycle_eq[1]); + assert_eq!(output.instruction_raf_flag, cycle_eq[1] + cycle_eq[3]); + assert_eq!(output.instruction_ra.len(), 8); + + for chunk in 0..output.instruction_ra.len() { + let chunk_point = &address_point[chunk * CHUNK_BITS..(chunk + 1) * CHUNK_BITS]; + let shift = 128 - (chunk + 1) * CHUNK_BITS; + let expected = lookup_indices + .iter() + .zip(&cycle_eq) + .map(|(&lookup_index, &cycle_weight)| { + let chunk_value = (lookup_index >> shift) & ((1u128 << CHUNK_BITS) - 1); + cycle_weight * manual_eq_bits(chunk_point, chunk_value, CHUNK_BITS) + }) + .sum::(); + assert_eq!(output.instruction_ra[chunk], expected, "chunk={chunk}"); + } + } + + fn frs(values: &[u64]) -> Vec { + values.iter().map(|value| Fr::from_u64(*value)).collect() + } + + fn manual_eq_bits(point: &[Fr], bits: u128, num_bits: usize) -> Fr { + point + .iter() + .enumerate() + .map(|(index, &challenge)| { + if ((bits >> (num_bits - 1 - index)) & 1) == 1 { + challenge + } else { + Fr::from_u64(1) - challenge + } + }) + .product() + } + + fn registers_val_input_claim( + registers_point: &[Fr], + rd_inc: &[Fr], + rd_write_addresses: &[Option], + ) -> Fr { + let (address_point, cycle_point) = registers_point.split_at(1); + let address_eq = EqPolynomial::::evals(address_point, None); + let lt = lt_evals_big_endian(cycle_point); + rd_inc + .iter() + .zip(rd_write_addresses) + .zip(lt) + .map(|((&inc, address), lt)| { + let wa = address + .and_then(|address| address_eq.get(address)) + .copied() + .unwrap_or_else(|| Fr::from_u64(0)); + inc * wa * lt + }) + .sum() + } + + fn ram_ra_input_claim(ram_ra_point: &[Fr], remapped_addresses: &[Option]) -> Fr { + let (address_point, cycle_point) = ram_ra_point.split_at(1); + let address_eq = EqPolynomial::::evals(address_point, None); + let eq_cycle = EqPolynomial::::evals(cycle_point, None); + remapped_addresses + .iter() + .zip(eq_cycle) + .map(|(address, eq)| { + let ra = address + .and_then(|address| address_eq.get(address)) + .copied() + .unwrap_or_else(|| Fr::from_u64(0)); + ra * eq + }) + .sum() + } + + fn instruction_read_raf_input_claim( + r_reduction: &[Fr], + lookup_indices: &[u128], + table_indices: &[Option], + is_interleaved: &[bool], + ) -> (Fr, Fr, Fr) { + let tables = LookupTableKind::<64>::all(); + let eq_cycle = EqPolynomial::::evals(r_reduction, None); + let mut lookup_output_claim = Fr::from_u64(0); + let mut left_claim = Fr::from_u64(0); + let mut right_claim = Fr::from_u64(0); + for (((&lookup_index, table_index), &is_interleaved), &cycle_weight) in lookup_indices + .iter() + .zip(table_indices) + .zip(is_interleaved) + .zip(&eq_cycle) + { + let address_point = field_bit_point_128(lookup_index); + if let Some(table_index) = table_index { + lookup_output_claim += + cycle_weight * tables[*table_index].evaluate_mle::(&address_point); + } + if is_interleaved { + left_claim += cycle_weight * operand_polynomial_eval(&address_point, true); + right_claim += cycle_weight * operand_polynomial_eval(&address_point, false); + } else { + right_claim += cycle_weight * identity_polynomial_eval(&address_point); + } + } + (lookup_output_claim, left_claim, right_claim) + } + + fn field_bit_point_128(value: u128) -> Vec { + (0..128) + .map(|index| Fr::from_bool(lookup_bit(value, index, 128))) + .collect() + } + + fn instruction_read_raf_test_program( + trace_rounds: usize, + ra_chunks: usize, + ) -> &'static Stage5CpuProgramPlan { + let table_count = LookupTableKind::<64>::all().len(); + let driver_symbol = "stage5.instruction_read_raf.sumcheck"; + let claim_symbol = "stage5.instruction_read_raf.input"; + let ordered_claims = Box::leak(vec![claim_symbol].into_boxed_slice()); + let round_schedule = Box::leak(vec![128, trace_rounds].into_boxed_slice()); + let claim_inputs = Box::leak( + vec![ + "stage5.input.stage2.instruction.LookupOutput", + "stage5.input.stage2.instruction.LeftLookupOperand", + "stage5.input.stage2.instruction.RightLookupOperand", + ] + .into_boxed_slice(), + ); + let mut evals = Vec::with_capacity(table_count + ra_chunks + 1); + for index in 0..table_count { + let name = leak_test_str(format!( + "stage5.instruction_read_raf.eval.LookupTableFlag_{index}" + )); + let oracle = leak_test_str(format!("LookupTableFlag_{index}")); + evals.push(Stage5SumcheckEvalPlan { + symbol: name, + source: driver_symbol, + name, + index, + oracle, + }); + } + for index in 0..ra_chunks { + let name = leak_test_str(format!( + "stage5.instruction_read_raf.eval.InstructionRa_{index}" + )); + let oracle = leak_test_str(format!("InstructionRa_{index}")); + evals.push(Stage5SumcheckEvalPlan { + symbol: name, + source: driver_symbol, + name, + index: table_count + index, + oracle, + }); + } + evals.push(Stage5SumcheckEvalPlan { + symbol: "stage5.instruction_read_raf.eval.InstructionRafFlag", + source: driver_symbol, + name: "stage5.instruction_read_raf.eval.InstructionRafFlag", + index: table_count + ra_chunks, + oracle: "InstructionRafFlag", + }); + + Box::leak(Box::new(Stage5CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: Box::leak( + vec![Stage5ProgramStepPlan { + kind: "sumcheck_driver", + symbol: driver_symbol, + }] + .into_boxed_slice(), + ), + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: Box::leak( + vec![ + Stage5OpeningInputPlan { + symbol: "stage5.input.stage2.instruction.LookupOutput", + source_stage: "stage2", + source_claim: + "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", + oracle: "LookupOutput", + domain: "jolt.trace_domain", + point_arity: trace_rounds, + claim_kind: "virtual", + }, + Stage5OpeningInputPlan { + symbol: "stage5.input.stage2.instruction.LeftLookupOperand", + source_stage: "stage2", + source_claim: + "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", + oracle: "LeftLookupOperand", + domain: "jolt.trace_domain", + point_arity: trace_rounds, + claim_kind: "virtual", + }, + Stage5OpeningInputPlan { + symbol: "stage5.input.stage2.instruction.RightLookupOperand", + source_stage: "stage2", + source_claim: + "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", + oracle: "RightLookupOperand", + domain: "jolt.trace_domain", + point_arity: trace_rounds, + claim_kind: "virtual", + }, + ] + .into_boxed_slice(), + ), + field_constants: Box::leak( + vec![Stage5FieldConstantPlan { + symbol: "stage5.instruction_read_raf.gamma", + field: "bn254_fr", + value: 2, + }] + .into_boxed_slice(), + ), + field_exprs: &[], + kernels: Box::leak( + vec![ + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.instruction_read_raf", + relation: "jolt.stage5.instruction_read_raf", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_instruction_read_raf", + }, + Stage5KernelPlan { + symbol: "jolt.cpu.stage5.batched", + relation: "jolt.stage5.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage5_batched", + }, + ] + .into_boxed_slice(), + ), + claims: Box::leak( + vec![Stage5SumcheckClaimPlan { + symbol: claim_symbol, + stage: "stage5", + domain: "jolt.stage5_instruction_read_raf_domain", + num_rounds: 128 + trace_rounds, + degree: ra_chunks + 2, + claim: "stage5.instruction_read_raf.weighted_lookup_values", + kernel: Some("jolt.cpu.stage5.instruction_read_raf"), + relation: Some("jolt.stage5.instruction_read_raf"), + claim_value: "stage5.instruction_read_raf.claim_expr", + input_openings: claim_inputs, + }] + .into_boxed_slice(), + ), + batches: Box::leak( + vec![Stage5SumcheckBatchPlan { + symbol: "stage5.instruction_read_raf.batch", + stage: "stage5", + proof_slot: driver_symbol, + policy: "test", + count: 1, + ordered_claims, + claim_operands: ordered_claims, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule, + }] + .into_boxed_slice(), + ), + drivers: Box::leak( + vec![Stage5SumcheckDriverPlan { + symbol: driver_symbol, + stage: "stage5", + proof_slot: driver_symbol, + kernel: Some("jolt.cpu.stage5.batched"), + relation: Some("jolt.stage5.batched"), + batch: "stage5.instruction_read_raf.batch", + policy: "test", + round_schedule, + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 128 + trace_rounds, + degree: ra_chunks + 2, + }] + .into_boxed_slice(), + ), + instance_results: Box::leak( + vec![Stage5SumcheckInstanceResultPlan { + symbol: "stage5.instruction_read_raf.instance", + source: driver_symbol, + claim: claim_symbol, + relation: "jolt.stage5.instruction_read_raf", + index: 0, + point_arity: 128 + trace_rounds, + num_rounds: 128 + trace_rounds, + round_offset: 0, + point_order: "instruction_read_raf", + degree: ra_chunks + 2, + }] + .into_boxed_slice(), + ), + evals: Box::leak(evals.into_boxed_slice()), + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + })) + } + + fn leak_test_str(value: String) -> &'static str { + Box::leak(value.into_boxed_str()) + } + + fn named_eval_values(evals: &[Stage5NamedEval]) -> Vec<(&'static str, &'static str, Fr)> { + evals + .iter() + .map(|eval| (eval.name, eval.oracle, eval.value)) + .collect() + } +} diff --git a/crates/jolt-kernels/src/stage6.rs b/crates/jolt-kernels/src/stage6.rs new file mode 100644 index 0000000000..45fc91d893 --- /dev/null +++ b/crates/jolt-kernels/src/stage6.rs @@ -0,0 +1,7163 @@ +//! Stage 6 coarse-kernel ABI used by Bolt-generated Jolt prover code. + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +use crate::dense::{bind_dense_evals_reuse, DENSE_BIND_PAR_THRESHOLD}; +use jolt_field::Field; +use jolt_poly::{ + BindingOrder, EqPolynomial, ExpandingTable, GruenSplitEqPolynomial, UnivariatePoly, +}; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +pub use jolt_witness::Stage6WitnessParams; +use jolt_witness::{ + stage6_witness_polynomials, CycleInput, Stage6OpeningInputRef, Stage6WitnessInputs, + Stage6WitnessPolynomials, Stage6WitnessSlices, +}; +use rayon::prelude::*; + +pub use crate::stage4::{ + Stage4ChallengeVector as Stage6ChallengeVector, + Stage4ExecutionArtifacts as Stage6ExecutionArtifacts, + Stage4ExecutionMode as Stage6ExecutionMode, Stage4FieldConstantPlan as Stage6FieldConstantPlan, + Stage4FieldExprPlan as Stage6FieldExprPlan, Stage4NamedEval as Stage6NamedEval, + Stage4OpeningBatchPlan as Stage6OpeningBatchPlan, + Stage4OpeningClaimEqualityPlan as Stage6OpeningClaimEqualityPlan, + Stage4OpeningClaimPlan as Stage6OpeningClaimPlan, + Stage4OpeningClaimValue as Stage6OpeningClaimValue, + Stage4OpeningInputPlan as Stage6OpeningInputPlan, + Stage4OpeningInputValue as Stage6OpeningInputValue, Stage4Params as Stage6Params, + Stage4PointConcatPlan as Stage6PointConcatPlan, Stage4PointSlicePlan as Stage6PointSlicePlan, + Stage4ProgramStepPlan as Stage6ProgramStepPlan, Stage4Proof as Stage6Proof, + Stage4SumcheckBatchPlan as Stage6SumcheckBatchPlan, + Stage4SumcheckClaimPlan as Stage6SumcheckClaimPlan, + Stage4SumcheckDriverPlan as Stage6SumcheckDriverPlan, + Stage4SumcheckEvalPlan as Stage6SumcheckEvalPlan, + Stage4SumcheckInstanceResultPlan as Stage6SumcheckInstanceResultPlan, + Stage4SumcheckOutput as Stage6SumcheckOutput, + Stage4TranscriptAbsorbBytesPlan as Stage6TranscriptAbsorbBytesPlan, + Stage4TranscriptSqueezePlan as Stage6TranscriptSqueezePlan, +}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage6KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage6PointZeroPlan { + pub symbol: &'static str, + pub field: &'static str, + pub arity: usize, +} + +impl Stage6KernelPlan { + pub fn relation_kind(&self) -> Result { + Stage6Relation::from_symbol(self.relation).ok_or(Stage6KernelError::UnknownRelation { + relation: self.relation, + }) + } + + pub fn abi_kind(&self) -> Result { + Stage6KernelAbi::from_name(self.abi) + .ok_or(Stage6KernelError::UnknownKernelAbi { abi: self.abi }) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage6CpuProgramPlan { + pub role: &'static str, + pub params: Stage6Params, + pub steps: &'static [Stage6ProgramStepPlan], + pub transcript_squeezes: &'static [Stage6TranscriptSqueezePlan], + pub transcript_absorb_bytes: &'static [Stage6TranscriptAbsorbBytesPlan], + pub opening_inputs: &'static [Stage6OpeningInputPlan], + pub field_constants: &'static [Stage6FieldConstantPlan], + pub field_exprs: &'static [Stage6FieldExprPlan], + pub kernels: &'static [Stage6KernelPlan], + pub claims: &'static [Stage6SumcheckClaimPlan], + pub batches: &'static [Stage6SumcheckBatchPlan], + pub drivers: &'static [Stage6SumcheckDriverPlan], + pub instance_results: &'static [Stage6SumcheckInstanceResultPlan], + pub evals: &'static [Stage6SumcheckEvalPlan], + pub point_zeros: &'static [Stage6PointZeroPlan], + pub point_slices: &'static [Stage6PointSlicePlan], + pub point_concats: &'static [Stage6PointConcatPlan], + pub opening_claims: &'static [Stage6OpeningClaimPlan], + pub opening_equalities: &'static [Stage6OpeningClaimEqualityPlan], + pub opening_batches: &'static [Stage6OpeningBatchPlan], +} + +impl Stage6CpuProgramPlan { + pub fn claim(&self, symbol: &str) -> Option<&Stage6SumcheckClaimPlan> { + self.claims.iter().find(|claim| claim.symbol == symbol) + } + + pub fn instance_results_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.instance_results + .iter() + .filter(move |instance| instance.source == driver) + } + + pub fn evals_for_driver( + &self, + driver: &'static str, + ) -> impl Iterator { + self.evals.iter().filter(move |eval| eval.source == driver) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage6Relation { + BytecodeReadRaf, + Booleanity, + HammingBooleanity, + RamRaVirtual, + InstructionRaVirtual, + IncClaimReduction, + Batched, +} + +impl Stage6Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage6.bytecode_read_raf" => Some(Self::BytecodeReadRaf), + "jolt.stage6.booleanity" => Some(Self::Booleanity), + "jolt.stage6.hamming_booleanity" => Some(Self::HammingBooleanity), + "jolt.stage6.ram_ra_virtual" => Some(Self::RamRaVirtual), + "jolt.stage6.instruction_ra_virtual" => Some(Self::InstructionRaVirtual), + "jolt.stage6.inc_claim_reduction" => Some(Self::IncClaimReduction), + "jolt.stage6.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::BytecodeReadRaf => "jolt.stage6.bytecode_read_raf", + Self::Booleanity => "jolt.stage6.booleanity", + Self::HammingBooleanity => "jolt.stage6.hamming_booleanity", + Self::RamRaVirtual => "jolt.stage6.ram_ra_virtual", + Self::InstructionRaVirtual => "jolt.stage6.instruction_ra_virtual", + Self::IncClaimReduction => "jolt.stage6.inc_claim_reduction", + Self::Batched => "jolt.stage6.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage6KernelAbi { + BytecodeReadRaf, + Booleanity, + HammingBooleanity, + RamRaVirtual, + InstructionRaVirtual, + IncClaimReduction, + Batched, +} + +impl Stage6KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage6_bytecode_read_raf" => Some(Self::BytecodeReadRaf), + "jolt_stage6_booleanity" => Some(Self::Booleanity), + "jolt_stage6_hamming_booleanity" => Some(Self::HammingBooleanity), + "jolt_stage6_ram_ra_virtual" => Some(Self::RamRaVirtual), + "jolt_stage6_instruction_ra_virtual" => Some(Self::InstructionRaVirtual), + "jolt_stage6_inc_claim_reduction" => Some(Self::IncClaimReduction), + "jolt_stage6_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::BytecodeReadRaf => "jolt_stage6_bytecode_read_raf", + Self::Booleanity => "jolt_stage6_booleanity", + Self::HammingBooleanity => "jolt_stage6_hamming_booleanity", + Self::RamRaVirtual => "jolt_stage6_ram_ra_virtual", + Self::InstructionRaVirtual => "jolt_stage6_instruction_ra_virtual", + Self::IncClaimReduction => "jolt_stage6_inc_claim_reduction", + Self::Batched => "jolt_stage6_batched", + } + } +} + +const BYTECODE_READ_RAF_STAGE_COUNT: usize = 5; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage6KernelError { + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + MissingDriver { + driver: &'static str, + }, + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage6ExecutionMode, + actual: Stage6ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProgramStep { + symbol: &'static str, + kind: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage6KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage6 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage6 value @{symbol} is not available") + } + Self::MissingDriver { driver } => { + write!(formatter, "stage6 driver @{driver} is not available") + } + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage6 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage6 driver @{driver} references missing batch @{batch}" + ) + } + Self::UnknownRelation { relation } => { + write!(formatter, "unknown stage6 relation `{relation}`") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "unknown stage6 kernel ABI `{abi}`") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => { + write!( + formatter, + "stage6 {artifact} plan count mismatch: expected {expected}, got {actual}" + ) + } + Self::InvalidInputLength { + input, + expected, + actual, + } => { + write!( + formatter, + "stage6 input `{input}` has length {actual}, expected {expected}" + ) + } + Self::UnsupportedFieldExpr { symbol, formula } => { + write!( + formatter, + "stage6 field expr @{symbol} uses unsupported formula `{formula}`" + ) + } + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage6 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => { + write!( + formatter, + "stage6 driver @{driver} expected {expected:?} executor, got {actual:?}" + ) + } + Self::MissingProof { driver } => { + write!(formatter, "stage6 proof for driver @{driver} is missing") + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage6 kernel `{kernel}` is missing required input `{input}`" + ) + } + Self::InvalidProgramStep { symbol, kind } => { + write!( + formatter, + "stage6 program step @{symbol} has invalid kind `{kind}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage6 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage6KernelError {} + +#[derive(Clone, Copy)] +pub struct Stage6BooleanityWitness<'a, F: Field> { + pub chunks: &'a [&'a [F]], + pub index_chunks: Option<&'a [&'a [Option]]>, +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage6BytecodeEntry { + pub address: F, + pub imm: F, + pub circuit_flags: [bool; 14], + pub rd: Option, + pub rs1: Option, + pub rs2: Option, + pub lookup_table: Option, + pub is_interleaved: bool, + pub is_branch: bool, + pub left_is_rs1: bool, + pub left_is_pc: bool, + pub right_is_rs2: bool, + pub right_is_imm: bool, + pub is_noop: bool, +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage6BytecodeReadRafData<'a, F: Field> { + pub entries: &'a [Stage6BytecodeEntry], + pub entry_bytecode_index: usize, + pub num_lookup_tables: usize, +} + +impl From> for Stage6BytecodeEntry { + fn from(entry: jolt_witness::Stage6BytecodeEntry) -> Self { + Self { + address: entry.address, + imm: entry.imm, + circuit_flags: entry.circuit_flags, + rd: entry.rd, + rs1: entry.rs1, + rs2: entry.rs2, + lookup_table: entry.lookup_table, + is_interleaved: entry.is_interleaved, + is_branch: entry.is_branch, + left_is_rs1: entry.left_is_rs1, + left_is_pc: entry.left_is_pc, + right_is_rs2: entry.right_is_rs2, + right_is_imm: entry.right_is_imm, + is_noop: entry.is_noop, + } + } +} + +#[derive(Clone, Debug)] +pub struct Stage6BytecodeReadRafDataStorage { + entries: Vec>, + entry_bytecode_index: usize, + num_lookup_tables: usize, +} + +impl Stage6BytecodeReadRafDataStorage { + pub fn from_witness_entries( + entries: &[jolt_witness::Stage6BytecodeEntry], + entry_bytecode_index: usize, + num_lookup_tables: usize, + ) -> Self { + Self { + entries: entries.iter().copied().map(Into::into).collect(), + entry_bytecode_index, + num_lookup_tables, + } + } + + pub fn as_input(&self) -> Stage6BytecodeReadRafData<'_, F> { + Stage6BytecodeReadRafData { + entries: &self.entries, + entry_bytecode_index: self.entry_bytecode_index, + num_lookup_tables: self.num_lookup_tables, + } + } +} + +#[derive(Clone, Copy)] +pub struct Stage6BytecodeReadRafWitness<'a, F: Field> { + pub data: Stage6BytecodeReadRafData<'a, F>, + pub bytecode_ra_chunks: &'a [&'a [F]], + pub bytecode_ra_chunk_lens: Option<&'a [usize]>, + pub bytecode_ra_index_chunks: Option<&'a [&'a [Option]]>, +} + +#[derive(Clone, Copy)] +pub struct Stage6HammingBooleanityWitness<'a, F: Field> { + pub hamming_weight: &'a [F], +} + +#[derive(Clone, Copy)] +pub struct Stage6IncClaimReductionWitness<'a, F: Field> { + pub ram_inc: &'a [F], + pub rd_inc: &'a [F], +} + +#[derive(Clone, Copy)] +pub struct Stage6RamRaVirtualWitness<'a, F: Field> { + pub ram_ra_chunks: &'a [&'a [F]], +} + +#[derive(Clone, Copy)] +pub struct Stage6InstructionRaVirtualWitness<'a, F: Field> { + pub instruction_ra_chunks: &'a [&'a [F]], + pub virtual_count: usize, +} + +pub fn stage6_witness_from_opening_inputs( + params: Stage6WitnessParams, + cycle_inputs: &[CycleInput], + opening_inputs: &[Stage6OpeningInputValue], +) -> Stage6WitnessPolynomials { + let opening_refs = opening_inputs + .iter() + .map(|input| Stage6OpeningInputRef { + symbol: input.symbol, + point: input.point.as_slice(), + }) + .collect::>(); + stage6_witness_polynomials(Stage6WitnessInputs { + params, + cycle_inputs, + opening_inputs: &opening_refs, + }) +} + +#[derive(Clone, Copy)] +pub struct Stage6ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage6OpeningInputValue], + pub bytecode_read_raf: Option>, + pub booleanity: Option>, + pub hamming_booleanity: Option>, + pub inc_claim_reduction: Option>, + pub ram_ra_virtual: Option>, + pub instruction_ra_virtual: Option>, +} + +impl<'a, F: Field> Stage6ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage6OpeningInputValue]) -> Self { + Self { + opening_inputs, + bytecode_read_raf: None, + booleanity: None, + hamming_booleanity: None, + inc_claim_reduction: None, + ram_ra_virtual: None, + instruction_ra_virtual: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + bytecode_read_raf: None, + booleanity: None, + hamming_booleanity: None, + inc_claim_reduction: None, + ram_ra_virtual: None, + instruction_ra_virtual: None, + } + } + + pub fn with_hamming_booleanity( + mut self, + hamming_booleanity: Stage6HammingBooleanityWitness<'a, F>, + ) -> Self { + self.hamming_booleanity = Some(hamming_booleanity); + self + } + + pub fn with_booleanity(mut self, booleanity: Stage6BooleanityWitness<'a, F>) -> Self { + self.booleanity = Some(booleanity); + self + } + + pub fn with_bytecode_read_raf( + mut self, + bytecode_read_raf: Stage6BytecodeReadRafWitness<'a, F>, + ) -> Self { + self.bytecode_read_raf = Some(bytecode_read_raf); + self + } + + pub fn with_inc_claim_reduction( + mut self, + inc_claim_reduction: Stage6IncClaimReductionWitness<'a, F>, + ) -> Self { + self.inc_claim_reduction = Some(inc_claim_reduction); + self + } + + pub fn with_ram_ra_virtual(mut self, ram_ra_virtual: Stage6RamRaVirtualWitness<'a, F>) -> Self { + self.ram_ra_virtual = Some(ram_ra_virtual); + self + } + + pub fn with_instruction_ra_virtual( + mut self, + instruction_ra_virtual: Stage6InstructionRaVirtualWitness<'a, F>, + ) -> Self { + self.instruction_ra_virtual = Some(instruction_ra_virtual); + self + } + + pub fn with_stage6_witness( + self, + bytecode_data: Stage6BytecodeReadRafData<'a, F>, + witness: &'a Stage6WitnessPolynomials, + slices: &'a Stage6WitnessSlices<'a, F>, + instruction_ra_virtual_count: usize, + ) -> Self { + self.with_bytecode_read_raf(Stage6BytecodeReadRafWitness { + data: bytecode_data, + bytecode_ra_chunks: &slices.bytecode_ra_read_raf_chunks, + bytecode_ra_chunk_lens: Some(&slices.bytecode_ra_read_raf_chunk_lens), + bytecode_ra_index_chunks: Some(&slices.bytecode_ra_index_chunks), + }) + .with_booleanity(Stage6BooleanityWitness { + chunks: &slices.booleanity_chunks, + index_chunks: Some(&slices.booleanity_index_chunks), + }) + .with_hamming_booleanity(Stage6HammingBooleanityWitness { + hamming_weight: &witness.hamming_weight, + }) + .with_ram_ra_virtual(Stage6RamRaVirtualWitness { + ram_ra_chunks: &slices.ram_ra_virtual_chunks, + }) + .with_instruction_ra_virtual(Stage6InstructionRaVirtualWitness { + instruction_ra_chunks: &slices.instruction_ra_virtual_chunks, + virtual_count: instruction_ra_virtual_count, + }) + .with_inc_claim_reduction(Stage6IncClaimReductionWitness { + ram_inc: &witness.ram_inc, + rd_inc: &witness.rd_inc, + }) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage6KernelContext<'a> { + pub mode: Stage6ExecutionMode, + pub program: &'static Stage6CpuProgramPlan, + pub kernel: &'a Stage6KernelPlan, + pub batch: &'a Stage6SumcheckBatchPlan, + pub driver: &'a Stage6SumcheckDriverPlan, +} + +impl Stage6KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + self.kernel.relation_kind() + } + + pub fn abi_kind(&self) -> Result { + self.kernel.abi_kind() + } + + pub fn batch_claims(&self) -> Result, Stage6KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage6KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage6KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage6TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage6KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage6SumcheckOutput, + ) -> Result<(), Stage6KernelError> { + Ok(()) + } + + fn opening_claim_values( + &self, + _program: &'static Stage6CpuProgramPlan, + ) -> Result>, Stage6KernelError> { + Ok(Vec::new()) + } + + fn prove_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage6KernelExecutor; + +impl Stage6KernelExecutor for UnsupportedStage6KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + let abi = context.abi_kind()?; + let _ = context.relation_kind()?; + Err(Stage6KernelError::KernelNotImplemented { abi: abi.name() }) + } + + fn verify_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + let abi = context.abi_kind()?; + let _ = context.relation_kind()?; + Err(Stage6KernelError::KernelNotImplemented { abi: abi.name() }) + } +} + +#[derive(Clone)] +pub struct Stage6ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage6ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage6ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage6ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage6CpuProgramPlan, + ) -> Result, Stage6KernelError> { + value_store_from_observations( + program, + self.inputs.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage6KernelExecutor for Stage6ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage6TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage6KernelError> { + self.challenge_vectors.push(Stage6ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage6SumcheckOutput, + ) -> Result<(), Stage6KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn opening_claim_values( + &self, + program: &'static Stage6CpuProgramPlan, + ) -> Result>, Stage6KernelError> { + self.value_store(program)?.opening_claim_values(program) + } + + fn prove_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + prove_stage6_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + Err(Stage6KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage6ExecutionMode::Prover, + actual: Stage6ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage6ProofCarryingKernelExecutor<'a, F: Field> { + pub proof: &'a Stage6Proof, + pub opening_inputs: &'a [Stage6OpeningInputValue], + pub bytecode_read_raf: Option>, + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage6ProofCarryingKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage6Proof, + opening_inputs: &'a [Stage6OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + bytecode_read_raf: None, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + pub fn with_bytecode_read_raf_data( + mut self, + bytecode_read_raf: Stage6BytecodeReadRafData<'a, F>, + ) -> Self { + self.bytecode_read_raf = Some(bytecode_read_raf); + self + } + + fn value_store( + &self, + program: &'static Stage6CpuProgramPlan, + ) -> Result, Stage6KernelError> { + value_store_from_observations( + program, + self.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } + + fn next_proof( + &mut self, + driver: &'static str, + ) -> Result<&'a Stage6SumcheckOutput, Stage6KernelError> { + let proof = self + .proof + .sumchecks + .get(self.cursor) + .ok_or(Stage6KernelError::MissingProof { driver })?; + self.cursor += 1; + Ok(proof) + } +} + +impl Stage6KernelExecutor for Stage6ProofCarryingKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage6TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage6KernelError> { + self.challenge_vectors.push(Stage6ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage6SumcheckOutput, + ) -> Result<(), Stage6KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn opening_claim_values( + &self, + program: &'static Stage6CpuProgramPlan, + ) -> Result>, Stage6KernelError> { + self.value_store(program)?.opening_claim_values(program) + } + + fn prove_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage6_kernel( + context, + self.value_store(context.program)?, + proof, + self.bytecode_read_raf, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage6KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage6KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage6_kernel( + context, + self.value_store(context.program)?, + proof, + self.bytecode_read_raf, + transcript, + ) + } +} + +#[derive(Clone, Debug, Default)] +struct Stage6ValueStore { + scalars: Vec<(&'static str, F)>, + points: Vec<(&'static str, Vec)>, +} + +impl Stage6ValueStore { + fn with_opening_inputs(inputs: &[Stage6OpeningInputValue]) -> Self { + let mut store = Self::default(); + for input in inputs { + store.insert_scalar(input.symbol, input.eval); + store.insert_point(input.symbol, input.point.clone()); + } + store + } + + fn seed_constants(&mut self, program: &'static Stage6CpuProgramPlan) { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + for zero in program.point_zeros { + self.insert_point(zero.symbol, vec![F::from_u64(0); zero.arity]); + } + } + + fn observe_challenge_vector( + &mut self, + plan: &'static Stage6TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage6KernelError> { + self.insert_point(plan.symbol, values.to_vec()); + if matches!(plan.kind, "challenge_scalar" | "scalar") { + require_operand_count(plan.symbol, 1, values.len())?; + self.insert_scalar(plan.symbol, values[0]); + } + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + program: &'static Stage6CpuProgramPlan, + output: &Stage6SumcheckOutput, + ) -> Result<(), Stage6KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + fn observe_sumcheck_values( + &mut self, + program: &'static Stage6CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage6NamedEval], + ) -> Result<(), Stage6KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program + .instance_results + .iter() + .filter(|instance| instance.source == driver) + { + let end = instance.round_offset + instance.point_arity; + let mut point = point + .get(instance.round_offset..end) + .ok_or(Stage6KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + "bytecode_read_raf" => point = normalize_bytecode_read_raf_point(program, &point)?, + "stage6_booleanity" => point = normalize_stage6_booleanity_point(program, &point)?, + "instruction_read_raf" => point = normalize_instruction_read_raf_point(&point)?, + _ => { + return Err(Stage6KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, point); + } + for eval in program.evals.iter().filter(|eval| eval.source == driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage6KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + let _ = self.evaluate_available_points(program)?; + let _ = self.evaluate_available_field_exprs(program)?; + self.verify_opening_equalities(program)?; + Ok(()) + } + + fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage6CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate_stage6_field_expr(expr, &operands)?); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + fn evaluate_available_points( + &mut self, + program: &'static Stage6CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage6KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + require_operand_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + fn verify_opening_equalities( + &self, + program: &'static Stage6CpuProgramPlan, + ) -> Result<(), Stage6KernelError> { + for equality in program.opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point(equality.lhs)? != self.point(equality.rhs)? + || self.scalar(equality.lhs)? != self.scalar(equality.rhs)? + { + return Err(Stage6KernelError::InvalidProof { + driver: equality.symbol, + reason: "opening claim equality failed", + }); + } + } + _ => { + return Err(Stage6KernelError::InvalidProof { + driver: equality.symbol, + reason: "unsupported opening equality mode", + }); + } + } + } + Ok(()) + } + + fn claim_value( + &mut self, + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + fn batch_claim_values( + &mut self, + program: &'static Stage6CpuProgramPlan, + batch: &Stage6SumcheckBatchPlan, + ) -> Result, Stage6KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage6KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some((_, existing)) = self + .scalars + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = value; + } else { + self.scalars.push((symbol, value)); + } + } + + fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some((_, existing)) = self + .points + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = point; + } else { + self.points.push((symbol, point)); + } + } + + fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage6KernelError::MissingValue { symbol }) + } + + fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, value)| *value) + } + + fn point(&self, symbol: &'static str) -> Result<&[F], Stage6KernelError> { + self.try_point(symbol) + .ok_or(Stage6KernelError::MissingValue { symbol }) + } + + fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, point)| point.as_slice()) + } + + fn try_expr_operands(&self, expr: &Stage6FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage6PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } + + fn opening_claim_values( + mut self, + program: &'static Stage6CpuProgramPlan, + ) -> Result>, Stage6KernelError> { + let _ = self.evaluate_available_points(program)?; + let _ = self.evaluate_available_field_exprs(program)?; + program + .opening_claims + .iter() + .map(|claim| { + Ok(Stage6OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: self.point(claim.point_source)?.to_vec(), + eval: self.scalar(claim.eval_source)?, + }) + }) + .collect() + } +} + +fn value_store_from_observations( + program: &'static Stage6CpuProgramPlan, + opening_inputs: &[Stage6OpeningInputValue], + challenge_vectors: &[Stage6ChallengeVector], + completed_sumchecks: &[Stage6SumcheckOutput], +) -> Result, Stage6KernelError> { + let mut store = Stage6ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(program); + for challenge in challenge_vectors { + let plan = + find_squeeze(program, challenge.symbol).ok_or(Stage6KernelError::MissingValue { + symbol: challenge.symbol, + })?; + store.observe_challenge_vector(plan, &challenge.values)?; + } + for output in completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + store.verify_opening_equalities(program)?; + Ok(store) +} + +fn prove_stage6_kernel( + context: Stage6KernelContext<'_>, + inputs: &Stage6ProverInputs<'_, F>, + store: Stage6ValueStore, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage6KernelAbi::Batched => prove_batched_stage6(context, inputs, store, transcript), + abi => Err(Stage6KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +fn verify_stage6_kernel( + context: Stage6KernelContext<'_>, + store: Stage6ValueStore, + proof: &Stage6SumcheckOutput, + bytecode_read_raf: Option>, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage6KernelAbi::Batched => { + verify_batched_stage6(context, store, proof, bytecode_read_raf, transcript) + } + abi => Err(Stage6KernelError::KernelNotImplemented { abi: abi.name() }), + } +} + +#[tracing::instrument(skip_all, name = "Stage6::prove_batched")] +fn prove_batched_stage6( + context: Stage6KernelContext<'_>, + inputs: &Stage6ProverInputs<'_, F>, + mut store: Stage6ValueStore, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let timing_enabled = std::env::var_os("JOLT_STAGE6_KERNEL_TIMINGS").is_some(); + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + let mut instances = Vec::with_capacity(claims.len()); + let mut timing_stats = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + let offset = instance_round_offset(context.program, context.driver.symbol, claim.symbol)?; + if offset + claim.num_rounds > max_rounds { + return Err(Stage6KernelError::InvalidInputLength { + input: claim.symbol, + expected: max_rounds, + actual: offset + claim.num_rounds, + }); + } + let relation = claim_relation(context.program, claim)?; + let active_scale = F::one().mul_pow_2(max_rounds - offset - claim.num_rounds); + let init_start = timing_enabled.then(std::time::Instant::now); + let state = + Stage6ProverInstanceState::new(context.program, claim, inputs, &store, active_scale)?; + let init_nanos = init_start.map_or(0, |start| start.elapsed().as_nanos()); + instances.push(Stage6BatchedInstance { + claim, + relation, + offset, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state, + }); + timing_stats.push((relation, init_nanos, 0u128, 0u128)); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for (index, instance) in instances.iter_mut().enumerate() { + let poly = if instance.is_active(round) { + let round_start = timing_enabled.then(std::time::Instant::now); + let poly = instance + .state + .round_poly(instance.previous_claim, instance.relation)?; + if let Some(start) = round_start { + timing_stats[index].2 += start.elapsed().as_nanos(); + } + poly + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + for (index, (instance, poly)) in instances.iter_mut().zip(individual_polys).enumerate() { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + let bind_start = timing_enabled.then(std::time::Instant::now); + instance.state.ingest_challenge(challenge); + if let Some(start) = bind_start { + timing_stats[index].3 += start.elapsed().as_nanos(); + } + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + let mut expected = F::zero(); + for (instance, &coefficient) in instances.iter().zip(&batching_coeffs) { + let relation_claim = instance.state.final_relation_eval(instance.relation)?; + if instance.previous_claim != relation_claim { + return Err(Stage6KernelError::InvalidProof { + driver: instance.relation.symbol(), + reason: "stage6 relation output claim mismatch", + }); + } + expected += coefficient * relation_claim; + evals.extend(instance.state.final_evals(instance.relation)?); + } + if batched_claim != expected { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + if timing_enabled { + for (relation, init_nanos, round_nanos, bind_nanos) in timing_stats { + tracing::info!( + "[stage6 timings] relation={} init_ms={:.3} round_ms={:.3} bind_ms={:.3}", + relation.symbol(), + init_nanos as f64 / 1_000_000.0, + round_nanos as f64 / 1_000_000.0, + bind_nanos as f64 / 1_000_000.0, + ); + } + } + Ok(Stage6SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: jolt_sumcheck::SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage6( + context: Stage6KernelContext<'_>, + mut store: Stage6ValueStore, + proof: &Stage6SumcheckOutput, + bytecode_read_raf: Option>, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + if let Some(expected) = expected_batched_output_claim_if_supported( + context, + &store, + &proof.evals, + &point, + &batching_coeffs, + bytecode_read_raf, + )? { + if running_claim != expected { + return Err(Stage6KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + } + + let output = Stage6SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims: Vec::new(), + proof: proof.proof.clone(), + }; + store.observe_sumcheck_output(context.program, &output)?; + let opening_claims = + append_opening_claims(context.program, &mut store, transcript, &output.evals)?; + let output = Stage6SumcheckOutput { + opening_claims, + ..output + }; + Ok(output) +} + +fn expected_batched_output_claim_if_supported( + context: Stage6KernelContext<'_>, + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + point: &[F], + batching_coeffs: &[F], + bytecode_read_raf: Option>, +) -> Result, Stage6KernelError> { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let Some(instance) = context.program.instance_results.iter().find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) else { + return Ok(None); + }; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage6KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let value = match claim_relation(context.program, claim)? { + Stage6Relation::HammingBooleanity => { + expected_hamming_booleanity(store, evals, local_point)? + } + Stage6Relation::IncClaimReduction => { + expected_inc_claim_reduction(store, evals, local_point)? + } + Stage6Relation::RamRaVirtual => expected_ram_ra_virtual(store, evals, local_point)?, + Stage6Relation::InstructionRaVirtual => { + expected_instruction_ra_virtual(context.program, store, evals, local_point)? + } + Stage6Relation::Booleanity => { + expected_booleanity(context.program, store, evals, local_point)? + } + Stage6Relation::BytecodeReadRaf => { + let Some(data) = bytecode_read_raf else { + return Ok(None); + }; + expected_bytecode_read_raf(context.program, data, store, evals, local_point)? + } + Stage6Relation::Batched => return Ok(None), + }; + expected += coefficient * value; + } + Ok(Some(expected)) +} + +fn expected_bytecode_read_raf( + program: &'static Stage6CpuProgramPlan, + data: Stage6BytecodeReadRafData<'_, F>, + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let log_t = stage6_trace_rounds(program)?; + let opening_point = normalize_bytecode_read_raf_point(program, local_point)?; + let log_k = opening_point.len() - log_t; + let (r_address_prime, r_cycle_prime) = opening_point.split_at(log_k); + + let gamma = store.scalar("stage6.bytecode_read_raf.gamma")?; + let gamma_powers = bytecode_gamma_powers(gamma); + let int_eval = identity_polynomial_eval(r_address_prime); + let stage_value_evals = bytecode_stage_value_evals(data, store, r_address_prime, log_t)?; + let stage_cycle_points = bytecode_stage_cycle_points(store, log_t)?; + let int_contrib = [ + gamma_powers[5] * int_eval, + F::zero(), + gamma_powers[4] * int_eval, + F::zero(), + F::zero(), + ]; + + let mut val = F::zero(); + for index in 0..stage_value_evals.len() { + val += (stage_value_evals[index] + int_contrib[index]) + * EqPolynomial::::mle(&stage_cycle_points[index], r_cycle_prime) + * gamma_powers[index]; + } + + let entry_bits = index_bits(data.entry_bytecode_index, log_k)?; + let zero_cycle = vec![F::zero(); r_cycle_prime.len()]; + let entry_contrib = gamma_powers[7] + * EqPolynomial::::mle(&entry_bits, r_address_prime) + * EqPolynomial::::mle(&zero_cycle, r_cycle_prime); + let bytecode_ra = + indexed_evals_by_prefix_any(evals, "stage6.bytecode_read_raf.eval.BytecodeRa_")? + .into_iter() + .product::(); + Ok((val + entry_contrib) * bytecode_ra) +} + +fn expected_booleanity( + program: &'static Stage6CpuProgramPlan, + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let log_t = stage6_trace_rounds(program)?; + let log_k_chunk = + local_point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.point", + expected: log_t, + actual: local_point.len(), + })?; + let stage5_point = store.point("stage6.input.stage5.instruction_read_raf.InstructionRa_0")?; + let stage5_address_len = + stage5_point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + expected: log_t, + actual: stage5_point.len(), + })?; + if stage5_address_len < log_k_chunk { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + expected: log_k_chunk + log_t, + actual: stage5_point.len(), + }); + } + + let mut stage5_addr = stage5_point[..stage5_address_len].to_vec(); + stage5_addr.reverse(); + let mut combined_r = stage5_addr[stage5_address_len - log_k_chunk..].to_vec(); + combined_r.extend(stage5_point[stage5_address_len..].iter().rev().copied()); + require_operand_count( + "stage6.booleanity.combined_point", + local_point.len(), + combined_r.len(), + )?; + let mut verifier_point = combined_r[..log_k_chunk].to_vec(); + verifier_point.reverse(); + verifier_point.extend(combined_r[log_k_chunk..].iter().rev().copied()); + let eq_eval = EqPolynomial::::mle(local_point, &verifier_point); + + let gamma = store.scalar("stage6.booleanity.gamma")?; + let gamma_sq = gamma.square(); + let mut gamma_power = F::one(); + let mut booleanity = F::zero(); + for ra in booleanity_evals(evals)? { + booleanity += gamma_power * (ra.square() - ra); + gamma_power *= gamma_sq; + } + Ok(eq_eval * booleanity) +} + +fn expected_hamming_booleanity( + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let hamming = eval_by_name(evals, "stage6.hamming_booleanity.eval.HammingWeight")?; + let lookup_output_point = reverse_slice(store.point("stage6.input.stage1.LookupOutput")?); + require_operand_count( + "stage6.input.stage1.LookupOutput", + local_point.len(), + lookup_output_point.len(), + )?; + let eq_eval = EqPolynomial::::mle(local_point, &lookup_output_point); + Ok((hamming.square() - hamming) * eq_eval) +} + +fn expected_inc_claim_reduction( + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let ram_inc_stage2 = suffix_point( + store.point("stage6.input.stage2.ram_read_write.RamInc")?, + r_cycle_reduced.len(), + "stage6.input.stage2.ram_read_write.RamInc", + )?; + let ram_inc_stage4 = suffix_point( + store.point("stage6.input.stage4.ram_val_check.RamInc")?, + r_cycle_reduced.len(), + "stage6.input.stage4.ram_val_check.RamInc", + )?; + let rd_inc_stage4 = suffix_point( + store.point("stage6.input.stage4.registers_read_write.RdInc")?, + r_cycle_reduced.len(), + "stage6.input.stage4.registers_read_write.RdInc", + )?; + let rd_inc_stage5 = suffix_point( + store.point("stage6.input.stage5.registers_val_evaluation.RdInc")?, + r_cycle_reduced.len(), + "stage6.input.stage5.registers_val_evaluation.RdInc", + )?; + let gamma = store.scalar("stage6.inc_claim_reduction.gamma")?; + let eq_ram_combined = EqPolynomial::::mle(ram_inc_stage2, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(ram_inc_stage4, &r_cycle_reduced); + let eq_rd_combined = EqPolynomial::::mle(rd_inc_stage4, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(rd_inc_stage5, &r_cycle_reduced); + let ram_inc = eval_by_name(evals, "stage6.inc_claim_reduction.eval.RamInc")?; + let rd_inc = eval_by_name(evals, "stage6.inc_claim_reduction.eval.RdInc")?; + Ok(ram_inc * eq_ram_combined + gamma.square() * rd_inc * eq_rd_combined) +} + +fn expected_ram_ra_virtual( + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle = suffix_point( + store.point("stage6.input.stage5.ram_ra_claim_reduction.RamRa")?, + r_cycle_reduced.len(), + "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + )?; + let eq_eval = EqPolynomial::::mle(r_cycle, &r_cycle_reduced); + let ram_ra = indexed_evals_by_prefix_any(evals, "stage6.ram_ra_virtual.eval.RamRa_")? + .into_iter() + .product::(); + Ok(eq_eval * ram_ra) +} + +fn expected_instruction_ra_virtual( + program: &'static Stage6CpuProgramPlan, + store: &Stage6ValueStore, + evals: &[Stage6NamedEval], + local_point: &[F], +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle = suffix_point( + store.point("stage6.input.stage5.instruction_read_raf.InstructionRa_0")?, + r_cycle_reduced.len(), + "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + )?; + let eq_eval = EqPolynomial::::mle(r_cycle, &r_cycle_reduced); + let committed_ra = + indexed_evals_by_prefix_any(evals, "stage6.instruction_ra_virtual.eval.InstructionRa_")?; + let virtual_count = program + .opening_inputs + .iter() + .filter(|input| { + input + .symbol + .starts_with("stage6.input.stage5.instruction_read_raf.InstructionRa_") + }) + .count(); + if virtual_count == 0 || committed_ra.len() % virtual_count != 0 { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.instruction_ra_virtual.eval.InstructionRa_", + expected: virtual_count, + actual: committed_ra.len(), + }); + } + let committed_per_virtual = committed_ra.len() / virtual_count; + let gamma = store.scalar("stage6.instruction_ra_virtual.gamma")?; + let mut gamma_power = F::one(); + let mut value = F::zero(); + for chunk in committed_ra.chunks(committed_per_virtual) { + value += gamma_power * chunk.iter().copied().product::(); + gamma_power *= gamma; + } + Ok(eq_eval * value) +} + +struct Stage6BatchedInstance<'a, F: Field> { + claim: &'a Stage6SumcheckClaimPlan, + relation: Stage6Relation, + offset: usize, + previous_claim: F, + state: Stage6ProverInstanceState, +} + +impl Stage6BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage6ProverInstanceState { + Booleanity(BooleanityStage6State), + CoreBooleanity(CoreBooleanityStage6State), + BytecodeReadRaf(BytecodeReadRafStage6State), + Dense(DenseStage6State), +} + +impl Stage6ProverInstanceState { + fn new( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, + ) -> Result { + match claim_relation(program, claim)? { + Stage6Relation::BytecodeReadRaf => { + bytecode_read_raf_state(program, claim, inputs, store, active_scale) + } + Stage6Relation::Booleanity => { + booleanity_state(program, claim, inputs, store, active_scale) + } + Stage6Relation::HammingBooleanity => { + hamming_booleanity_state(program, claim, inputs, store, active_scale) + .map(Self::Dense) + } + Stage6Relation::IncClaimReduction => { + inc_claim_reduction_state(program, claim, inputs, store, active_scale) + .map(Self::Dense) + } + Stage6Relation::RamRaVirtual => { + ram_ra_virtual_state(program, claim, inputs, store, active_scale).map(Self::Dense) + } + Stage6Relation::InstructionRaVirtual => { + instruction_ra_virtual_state(program, claim, inputs, store, active_scale) + .map(Self::Dense) + } + relation @ Stage6Relation::Batched => Err(Stage6KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + } + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + match self { + Self::Booleanity(state) => state.round_poly(previous_claim, relation), + Self::CoreBooleanity(state) => state.round_poly(previous_claim, relation), + Self::BytecodeReadRaf(state) => state.round_poly(previous_claim, relation), + Self::Dense(state) => state.round_poly(previous_claim, relation), + } + } + + fn ingest_challenge(&mut self, challenge: F) { + match self { + Self::Booleanity(state) => state.bind(challenge), + Self::CoreBooleanity(state) => state.bind(challenge), + Self::BytecodeReadRaf(state) => state.bind(challenge), + Self::Dense(state) => state.bind(challenge), + } + } + + fn final_relation_eval(&self, relation: Stage6Relation) -> Result { + match self { + Self::Booleanity(state) => state.final_relation_eval(relation), + Self::CoreBooleanity(state) => state.final_relation_eval(relation), + Self::BytecodeReadRaf(state) => state.final_relation_eval(relation), + Self::Dense(state) => state.final_relation_eval(relation), + } + } + + fn final_evals( + &self, + relation: Stage6Relation, + ) -> Result>, Stage6KernelError> { + match self { + Self::Booleanity(state) => state.final_evals(relation), + Self::CoreBooleanity(state) => state.final_evals(relation), + Self::BytecodeReadRaf(state) => state.final_evals(relation), + Self::Dense(state) => state.final_evals(relation), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum BytecodeReadRafPhase { + Address, + Cycle, +} + +struct BytecodeReadRafStage6State { + log_k: usize, + log_t: usize, + chunk_lens: Vec, + bytecode_ra_chunks: Vec>, + bytecode_ra_indices: Option>>>, + stage_factors: [Vec; BYTECODE_READ_RAF_STAGE_COUNT], + stage_values: [Vec; BYTECODE_READ_RAF_STAGE_COUNT], + entry_trace: Vec, + entry_expected: Vec, + address_challenges: Vec, + cycle_factors: Vec>, + cycle_eqs: [Vec; BYTECODE_READ_RAF_STAGE_COUNT], + cycle_entry_eq: Vec, + bound_stage_values: Option<[F; BYTECODE_READ_RAF_STAGE_COUNT]>, + bound_entry_expected: Option, + outputs: Vec, + gamma_powers: [F; 8], + active_scale: F, + degree_bound: usize, + phase: BytecodeReadRafPhase, +} + +impl BytecodeReadRafStage6State { + #[expect(clippy::too_many_arguments)] + fn new( + data: Stage6BytecodeReadRafData<'_, F>, + bytecode_ra_chunks: &[&[F]], + bytecode_ra_index_chunks: Option<&[&[Option]]>, + bytecode_cycle_indices: Vec, + chunk_lens: Vec, + store: &Stage6ValueStore, + log_k: usize, + log_t: usize, + active_scale: F, + degree_bound: usize, + outputs: Vec, + ) -> Result { + if degree_bound < 2 || degree_bound < chunk_lens.len() + 1 { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::BytecodeReadRaf.symbol(), + reason: "bytecode read RAF degree bound is too small", + }); + } + let expected_entries = + 1usize + .checked_shl(log_k as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entries", + expected: usize::BITS as usize, + actual: log_k, + })?; + require_operand_count( + "stage6.bytecode_read_raf.entries", + expected_entries, + data.entries.len(), + )?; + require_operand_count( + "stage6.bytecode_read_raf.trace", + 1usize << log_t, + bytecode_cycle_indices.len(), + )?; + if data.entry_bytecode_index >= expected_entries { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entry_bytecode_index", + expected: expected_entries, + actual: data.entry_bytecode_index + 1, + }); + } + if bytecode_cycle_indices + .iter() + .any(|&index| index >= expected_entries) + { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRa", + expected: expected_entries, + actual: expected_entries + 1, + }); + } + let bytecode_ra_indices = match bytecode_ra_index_chunks { + Some(chunks) if !chunks.is_empty() => { + validate_bytecode_ra_index_chunks(chunks, &chunk_lens, log_t)?; + Some(chunks.iter().map(|chunk| (*chunk).to_vec()).collect()) + } + _ => None, + }; + + let gamma = store.scalar("stage6.bytecode_read_raf.gamma")?; + let gamma_powers = bytecode_gamma_powers(gamma); + let stage_cycle_points = bytecode_stage_cycle_points(store, log_t)?; + let cycle_eqs = stage_cycle_points.each_ref().map(|point| { + let eq = EqPolynomial::::evals(point, None); + debug_assert_eq!(eq.len(), 1usize << log_t); + eq + }); + + let stage1_gamma = store.scalar("stage6.bytecode_read_raf.stage1_gamma")?; + let stage2_gamma = store.scalar("stage6.bytecode_read_raf.stage2_gamma")?; + let stage3_gamma = store.scalar("stage6.bytecode_read_raf.stage3_gamma")?; + let stage4_gamma = store.scalar("stage6.bytecode_read_raf.stage4_gamma")?; + let stage5_gamma = store.scalar("stage6.bytecode_read_raf.stage5_gamma")?; + let stage1_gamma_powers = field_powers(stage1_gamma, 16); + let stage2_gamma_powers = field_powers(stage2_gamma, 4); + let stage3_gamma_powers = field_powers(stage3_gamma, 9); + let stage4_gamma_powers = field_powers(stage4_gamma, 3); + let stage5_gamma_powers = field_powers(stage5_gamma, data.num_lookup_tables + 2); + let stage4_register_point = + register_prefix_point(store, "stage6.input.stage4.Rs1Ra", log_t)?; + let stage5_register_point = register_prefix_point( + store, + "stage6.input.stage5.registers_val_evaluation.RdWa", + log_t, + )?; + + let mut stage_values: [Vec; BYTECODE_READ_RAF_STAGE_COUNT] = + std::array::from_fn(|_| vec![F::zero(); expected_entries]); + for (index, entry) in data.entries.iter().enumerate() { + let mut values = bytecode_entry_stage_values( + entry, + data.num_lookup_tables, + stage4_register_point, + stage5_register_point, + &stage1_gamma_powers, + &stage2_gamma_powers, + &stage3_gamma_powers, + &stage4_gamma_powers, + &stage5_gamma_powers, + )?; + let int_eval = F::from_u64(index as u64); + values[0] += gamma_powers[5] * int_eval; + values[2] += gamma_powers[4] * int_eval; + for stage in 0..BYTECODE_READ_RAF_STAGE_COUNT { + stage_values[stage][index] = values[stage]; + } + } + + let mut stage_factors: [Vec; BYTECODE_READ_RAF_STAGE_COUNT] = + std::array::from_fn(|_| vec![F::zero(); expected_entries]); + for (cycle, &bytecode_index) in bytecode_cycle_indices.iter().enumerate() { + for stage in 0..BYTECODE_READ_RAF_STAGE_COUNT { + stage_factors[stage][bytecode_index] += cycle_eqs[stage][cycle]; + } + } + + let mut entry_trace = vec![F::zero(); expected_entries]; + entry_trace[bytecode_cycle_indices[0]] = F::one(); + let mut entry_expected = vec![F::zero(); expected_entries]; + entry_expected[data.entry_bytecode_index] = F::one(); + + let mut cycle_entry_eq = vec![F::zero(); 1usize << log_t]; + cycle_entry_eq[0] = F::one(); + + Ok(Self { + log_k, + log_t, + chunk_lens, + bytecode_ra_chunks: bytecode_ra_chunks + .iter() + .map(|chunk| (*chunk).to_vec()) + .collect(), + bytecode_ra_indices, + stage_factors, + stage_values, + entry_trace, + entry_expected, + address_challenges: Vec::with_capacity(log_k), + cycle_factors: Vec::new(), + cycle_eqs, + cycle_entry_eq, + bound_stage_values: None, + bound_entry_expected: None, + outputs, + gamma_powers, + active_scale, + degree_bound, + phase: BytecodeReadRafPhase::Address, + }) + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + let poly = match self.phase { + BytecodeReadRafPhase::Address => self.address_round_poly(relation)?, + BytecodeReadRafPhase::Cycle => self.cycle_round_poly(relation)?, + }; + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 relation input claim mismatch", + }); + } + Ok(poly) + } + + fn address_round_poly( + &self, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + let first_len = self.stage_values[0].len(); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF address phase has invalid length", + }); + } + let eval_count = self.degree_bound + 1; + let mut evals = if first_len / 2 >= DENSE_BIND_PAR_THRESHOLD { + (0..first_len / 2) + .into_par_iter() + .fold( + || vec![F::zero(); eval_count], + |mut row_evals, row| { + self.accumulate_address_row(row, &mut row_evals); + row_evals + }, + ) + .reduce( + || vec![F::zero(); eval_count], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + *left += right; + } + left + }, + ) + } else { + let mut evals = vec![F::zero(); eval_count]; + for row in 0..first_len / 2 { + self.accumulate_address_row(row, &mut evals); + } + evals + }; + for eval in &mut evals { + *eval *= self.active_scale; + } + Ok(UnivariatePoly::from_evals(&evals)) + } + + fn accumulate_address_row(&self, row: usize, evals: &mut [F]) { + for (point_index, eval) in evals.iter_mut().enumerate() { + let point = F::from_u64(point_index as u64); + let mut value = F::zero(); + for stage in 0..BYTECODE_READ_RAF_STAGE_COUNT { + let trace_eval = pair_linear_eval(&self.stage_factors[stage], row, point); + let value_eval = pair_linear_eval(&self.stage_values[stage], row, point); + value += self.gamma_powers[stage] * trace_eval * value_eval; + } + let entry_trace = pair_linear_eval(&self.entry_trace, row, point); + let entry_expected = pair_linear_eval(&self.entry_expected, row, point); + value += self.gamma_powers[7] * entry_trace * entry_expected; + *eval += value; + } + } + + fn cycle_round_poly( + &self, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + let Some(bound_stage_values) = self.bound_stage_values else { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF cycle phase missing bound values", + }); + }; + let Some(bound_entry_expected) = self.bound_entry_expected else { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF cycle phase missing entry value", + }); + }; + let first_len = self.cycle_factors.first().map_or(0, Vec::len); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF cycle phase has invalid length", + }); + } + let eval_count = self.degree_bound + 1; + let mut evals = if first_len / 2 >= DENSE_BIND_PAR_THRESHOLD { + (0..first_len / 2) + .into_par_iter() + .fold( + || vec![F::zero(); eval_count], + |mut row_evals, row| { + self.accumulate_cycle_row( + row, + bound_stage_values, + bound_entry_expected, + &mut row_evals, + ); + row_evals + }, + ) + .reduce( + || vec![F::zero(); eval_count], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + *left += right; + } + left + }, + ) + } else { + let mut evals = vec![F::zero(); eval_count]; + for row in 0..first_len / 2 { + self.accumulate_cycle_row( + row, + bound_stage_values, + bound_entry_expected, + &mut evals, + ); + } + evals + }; + for eval in &mut evals { + *eval *= self.active_scale; + } + Ok(UnivariatePoly::from_evals(&evals)) + } + + fn accumulate_cycle_row( + &self, + row: usize, + bound_stage_values: [F; BYTECODE_READ_RAF_STAGE_COUNT], + bound_entry_expected: F, + evals: &mut [F], + ) { + for (point_index, eval) in evals.iter_mut().enumerate() { + let point = F::from_u64(point_index as u64); + let mut ra_product = F::one(); + for factor in &self.cycle_factors { + ra_product *= pair_linear_eval(factor, row, point); + } + let mut weighted_value = F::zero(); + for (stage, bound_stage_value) in bound_stage_values.iter().enumerate() { + weighted_value += self.gamma_powers[stage] + * *bound_stage_value + * pair_linear_eval(&self.cycle_eqs[stage], row, point); + } + weighted_value += self.gamma_powers[7] + * bound_entry_expected + * pair_linear_eval(&self.cycle_entry_eq, row, point); + *eval += ra_product * weighted_value; + } + } + + fn bind(&mut self, challenge: F) { + match self.phase { + BytecodeReadRafPhase::Address => self.bind_address(challenge), + BytecodeReadRafPhase::Cycle => self.bind_cycle(challenge), + } + } + + fn bind_address(&mut self, challenge: F) { + for stage in 0..BYTECODE_READ_RAF_STAGE_COUNT { + bind_dense_evals_reuse(&mut self.stage_factors[stage], &mut Vec::new(), challenge); + bind_dense_evals_reuse(&mut self.stage_values[stage], &mut Vec::new(), challenge); + } + bind_dense_evals_reuse(&mut self.entry_trace, &mut Vec::new(), challenge); + bind_dense_evals_reuse(&mut self.entry_expected, &mut Vec::new(), challenge); + self.address_challenges.push(challenge); + if self.address_challenges.len() == self.log_k { + self.init_cycle_phase(); + } + } + + fn init_cycle_phase(&mut self) { + let bound_stage_values = std::array::from_fn(|stage| { + self.stage_values[stage] + .first() + .copied() + .unwrap_or(F::zero()) + }); + let bound_entry_expected = self.entry_expected.first().copied().unwrap_or(F::zero()); + let mut address_point = self.address_challenges.clone(); + address_point.reverse(); + + self.cycle_factors = if let Some(bytecode_ra_indices) = &self.bytecode_ra_indices { + self.sparse_cycle_factors(bytecode_ra_indices, &address_point) + } else { + self.dense_cycle_factors(&address_point) + }; + + self.bound_stage_values = Some(bound_stage_values); + self.bound_entry_expected = Some(bound_entry_expected); + self.stage_factors = std::array::from_fn(|_| Vec::new()); + self.stage_values = std::array::from_fn(|_| Vec::new()); + self.entry_trace.clear(); + self.entry_expected.clear(); + self.phase = BytecodeReadRafPhase::Cycle; + } + + fn sparse_cycle_factors( + &self, + bytecode_ra_indices: &[Vec>], + address_point: &[F], + ) -> Vec> { + let trace_len = 1usize << self.log_t; + bytecode_ra_indices + .iter() + .zip(&self.chunk_lens) + .scan(0usize, |offset, (indices, &chunk_len)| { + let start = *offset; + *offset += chunk_len; + Some((indices, start, chunk_len)) + }) + .map(|(indices, offset, chunk_len)| { + let eq_chunk = + EqPolynomial::::evals(&address_point[offset..offset + chunk_len], None); + indices + .iter() + .take(trace_len) + .map(|index| match index { + Some(index) => eq_chunk[usize::from(*index)], + None => F::zero(), + }) + .collect() + }) + .collect() + } + + fn dense_cycle_factors(&self, address_point: &[F]) -> Vec> { + self.bytecode_ra_chunks + .iter() + .zip(&self.chunk_lens) + .scan(0usize, |offset, (chunk, &chunk_len)| { + let start = *offset; + *offset += chunk_len; + Some((chunk, start, chunk_len)) + }) + .map(|(chunk, offset, chunk_len)| { + let eq_chunk = + EqPolynomial::::evals(&address_point[offset..offset + chunk_len], None); + let trace_len = 1usize << self.log_t; + (0..trace_len) + .map(|cycle| { + eq_chunk + .iter() + .enumerate() + .map(|(chunk_value, &eq)| chunk[chunk_value * trace_len + cycle] * eq) + .sum() + }) + .collect() + }) + .collect() + } + + fn bind_cycle(&mut self, challenge: F) { + for factor in &mut self.cycle_factors { + bind_dense_evals_reuse(factor, &mut Vec::new(), challenge); + } + for eq in &mut self.cycle_eqs { + bind_dense_evals_reuse(eq, &mut Vec::new(), challenge); + } + bind_dense_evals_reuse(&mut self.cycle_entry_eq, &mut Vec::new(), challenge); + } + + fn final_relation_eval(&self, relation: Stage6Relation) -> Result { + let Some(bound_stage_values) = self.bound_stage_values else { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing bound values", + }); + }; + let Some(bound_entry_expected) = self.bound_entry_expected else { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing entry value", + }); + }; + let mut ra_product = F::one(); + for factor in &self.cycle_factors { + ra_product *= factor + .first() + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing RA factor", + })?; + } + let mut weighted_value = F::zero(); + for (stage, bound_stage_value) in bound_stage_values.iter().enumerate() { + weighted_value += self.gamma_powers[stage] + * *bound_stage_value + * self.cycle_eqs[stage].first().copied().ok_or( + Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing cycle eq", + }, + )?; + } + weighted_value += self.gamma_powers[7] + * bound_entry_expected + * self + .cycle_entry_eq + .first() + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing entry eq", + })?; + Ok(ra_product * weighted_value) + } + + fn final_evals( + &self, + relation: Stage6Relation, + ) -> Result>, Stage6KernelError> { + self.outputs + .iter() + .map(|output| { + let factor = + output + .factor + .checked_sub(1) + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF output factor underflow", + })?; + let value = self + .cycle_factors + .get(factor) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "bytecode read RAF final eval missing output factor", + })?; + Ok(named_eval(output.name, output.oracle, value)) + }) + .collect() + } +} + +#[inline] +fn pair_linear_eval(values: &[F], row: usize, point: F) -> F { + let low = values[row << 1]; + let high = values[(row << 1) + 1]; + low + (high - low) * point +} + +struct BooleanityStage6State { + eq: Vec, + eq_scratch: Vec, + chunks: Vec>, + chunk_scratch: Vec>, + gamma_powers: Vec, + outputs: Vec, + active_scale: F, + degree_bound: usize, +} + +impl BooleanityStage6State { + fn new( + eq: Vec, + chunks: Vec>, + gamma_powers: Vec, + outputs: Vec, + active_scale: F, + degree_bound: usize, + ) -> Result { + if degree_bound < 3 { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity degree bound is too small", + }); + } + require_operand_count("stage6.booleanity.gamma", chunks.len(), gamma_powers.len())?; + if chunks.iter().any(|chunk| chunk.len() != eq.len()) { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity chunks have inconsistent lengths", + }); + } + let chunk_scratch = (0..chunks.len()).map(|_| Vec::new()).collect(); + Ok(Self { + eq, + eq_scratch: Vec::new(), + chunks, + chunk_scratch, + gamma_powers, + outputs, + active_scale, + degree_bound, + }) + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + let first_len = self.eq.len(); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "booleanity factor has invalid length", + }); + } + let mut evals = if self.degree_bound == 3 { + self.round_evals_degree3(first_len / 2) + } else { + self.round_evals_generic(first_len / 2) + }; + for eval in &mut evals { + *eval *= self.active_scale; + } + let poly = UnivariatePoly::from_evals(&evals); + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 relation input claim mismatch", + }); + } + Ok(poly) + } + + fn round_evals_degree3(&self, half_len: usize) -> Vec { + let evals = if half_len >= DENSE_BIND_PAR_THRESHOLD { + (0..half_len) + .into_par_iter() + .fold( + || [F::zero(); 4], + |mut row_evals, row| { + self.accumulate_row_degree3(row, &mut row_evals); + row_evals + }, + ) + .reduce( + || [F::zero(); 4], + |left, right| { + [ + left[0] + right[0], + left[1] + right[1], + left[2] + right[2], + left[3] + right[3], + ] + }, + ) + } else { + let mut evals = [F::zero(); 4]; + for row in 0..half_len { + self.accumulate_row_degree3(row, &mut evals); + } + evals + }; + evals.to_vec() + } + + fn accumulate_row_degree3(&self, row: usize, evals: &mut [F; 4]) { + let eq_low = self.eq[row << 1]; + let eq_high = self.eq[(row << 1) + 1]; + let delta_eq = eq_high - eq_low; + let eq_at_0 = eq_low; + let eq_at_1 = eq_high; + let eq_at_2 = eq_low + delta_eq.mul_u64(2); + let eq_at_3 = eq_low + delta_eq.mul_u64(3); + for (chunk_index, chunk) in self.chunks.iter().enumerate() { + let ra_low = chunk[row << 1]; + let ra_high = chunk[(row << 1) + 1]; + if ra_low == F::zero() && ra_high == F::zero() { + continue; + } + let delta_ra = ra_high - ra_low; + let gamma_power = self.gamma_powers[chunk_index]; + let ra_at_0 = ra_low; + let ra_at_1 = ra_high; + let ra_at_2 = ra_low + delta_ra.mul_u64(2); + let ra_at_3 = ra_low + delta_ra.mul_u64(3); + evals[0] += gamma_power * eq_at_0 * (ra_at_0.square() - ra_at_0); + evals[1] += gamma_power * eq_at_1 * (ra_at_1.square() - ra_at_1); + evals[2] += gamma_power * eq_at_2 * (ra_at_2.square() - ra_at_2); + evals[3] += gamma_power * eq_at_3 * (ra_at_3.square() - ra_at_3); + } + } + + fn round_evals_generic(&self, half_len: usize) -> Vec { + let eval_count = self.degree_bound + 1; + if half_len >= DENSE_BIND_PAR_THRESHOLD { + (0..half_len) + .into_par_iter() + .fold( + || vec![F::zero(); eval_count], + |mut row_evals, row| { + self.accumulate_row_generic(row, &mut row_evals); + row_evals + }, + ) + .reduce( + || vec![F::zero(); eval_count], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + *left += right; + } + left + }, + ) + } else { + let mut evals = vec![F::zero(); eval_count]; + for row in 0..half_len { + self.accumulate_row_generic(row, &mut evals); + } + evals + } + } + + fn accumulate_row_generic(&self, row: usize, evals: &mut [F]) { + let eq_low = self.eq[row << 1]; + let eq_high = self.eq[(row << 1) + 1]; + let delta_eq = eq_high - eq_low; + for (chunk_index, chunk) in self.chunks.iter().enumerate() { + let ra_low = chunk[row << 1]; + let ra_high = chunk[(row << 1) + 1]; + if ra_low == F::zero() && ra_high == F::zero() { + continue; + } + let delta_ra = ra_high - ra_low; + let gamma_power = self.gamma_powers[chunk_index]; + for (point_index, eval) in evals.iter_mut().enumerate() { + let point = F::from_u64(point_index as u64); + let eq_at_point = eq_low + delta_eq * point; + let ra_at_point = ra_low + delta_ra * point; + *eval += gamma_power * eq_at_point * (ra_at_point.square() - ra_at_point); + } + } + } + + fn bind(&mut self, challenge: F) { + bind_dense_evals_reuse(&mut self.eq, &mut self.eq_scratch, challenge); + if self.eq.len() >= DENSE_BIND_PAR_THRESHOLD { + self.chunks + .par_iter_mut() + .zip(self.chunk_scratch.par_iter_mut()) + .for_each(|(chunk, scratch)| { + bind_dense_evals_reuse(chunk, scratch, challenge); + }); + } else { + for (chunk, scratch) in self.chunks.iter_mut().zip(&mut self.chunk_scratch) { + bind_dense_evals_reuse(chunk, scratch, challenge); + } + } + } + + fn factor_eval(&self, index: usize, relation: Stage6Relation) -> Result { + self.chunks + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty booleanity factor", + }) + } + + fn final_relation_eval(&self, relation: Stage6Relation) -> Result { + let eq = self + .eq + .first() + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty booleanity eq factor", + })?; + let mut booleanity = F::zero(); + for (index, &gamma_power) in self.gamma_powers.iter().enumerate() { + let ra = self.factor_eval(index, relation)?; + booleanity += gamma_power * (ra.square() - ra); + } + Ok(eq * booleanity) + } + + fn final_evals( + &self, + relation: Stage6Relation, + ) -> Result>, Stage6KernelError> { + self.outputs + .iter() + .map(|output| { + let factor = + output + .factor + .checked_sub(1) + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "booleanity output factor underflow", + })?; + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(factor, relation)?, + )) + }) + .collect() + } +} + +struct CoreBooleanityStage6State { + log_k_chunk: usize, + address_round: usize, + b: GruenSplitEqPolynomial, + d: GruenSplitEqPolynomial, + f_table: ExpandingTable, + eq_r_r: F, + g: Vec>, + indices: Vec>>, + h: Option>>, + h_scratch: Vec>, + gamma_powers: Vec, + gamma_powers_inv: Vec, + gamma_powers_square: Vec, + outputs: Vec, + active_scale: F, +} + +impl CoreBooleanityStage6State { + fn new( + r_address: &[F], + r_cycle: &[F], + indices: Vec>>, + gamma: F, + outputs: Vec, + active_scale: F, + ) -> Result { + let log_k_chunk = r_address.len(); + let chunk_domain = 1usize << log_k_chunk; + let trace_len = 1usize << r_cycle.len(); + if indices.iter().any(|chunk| chunk.len() != trace_len) { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity index chunks have inconsistent trace lengths", + }); + } + + let eq_cycle = EqPolynomial::::evals(r_cycle, None); + let mut g = (0..indices.len()) + .map(|_| vec![F::zero(); chunk_domain]) + .collect::>(); + for (chunk_index, chunk) in indices.iter().enumerate() { + for (cycle, index) in chunk.iter().enumerate() { + let Some(index) = index else { + continue; + }; + let index = usize::from(*index); + if index >= chunk_domain { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity index exceeds chunk domain", + }); + } + g[chunk_index][index] += eq_cycle[cycle]; + } + } + + let mut gamma_powers = Vec::with_capacity(indices.len()); + let mut gamma_powers_inv = Vec::with_capacity(indices.len()); + let mut gamma_powers_square = Vec::with_capacity(indices.len()); + let mut gamma_power = F::one(); + let gamma_square = gamma.square(); + let mut gamma_square_power = F::one(); + for _ in 0..indices.len() { + gamma_powers.push(gamma_power); + gamma_powers_inv.push(gamma_power.inverse().ok_or( + Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity gamma power is not invertible", + }, + )?); + gamma_powers_square.push(gamma_square_power); + gamma_power *= gamma; + gamma_square_power *= gamma_square; + } + + let mut f_table = ExpandingTable::new(chunk_domain, BindingOrder::LowToHigh); + f_table.reset(F::one()); + + Ok(Self { + log_k_chunk, + address_round: 0, + b: GruenSplitEqPolynomial::new(r_address, BindingOrder::LowToHigh), + d: GruenSplitEqPolynomial::new(r_cycle, BindingOrder::LowToHigh), + f_table, + eq_r_r: F::zero(), + g, + indices, + h: None, + h_scratch: Vec::new(), + gamma_powers, + gamma_powers_inv, + gamma_powers_square, + outputs, + active_scale, + }) + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + if relation != Stage6Relation::Booleanity { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "wrong relation for core booleanity state", + }); + } + let mut poly = if self.h.is_none() { + self.address_round_poly(previous_claim) + } else { + self.cycle_round_poly(previous_claim)? + }; + if self.active_scale != F::one() { + poly *= self.active_scale; + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 booleanity input claim mismatch", + }); + } + Ok(poly) + } + + fn address_round_poly(&self, previous_claim: F) -> UnivariatePoly { + let m = self.address_round + 1; + let f_values = self.f_table.values(); + let quadratic_coeffs = self.b.fold_out_in( + || [F::zero(); 2], + |inner, k_prime, _x_in, e_in| { + let block_start = k_prime << m; + let block_end = block_start + (1 << m); + for (index, g_i) in self.g.iter().enumerate() { + let mut eval_0 = F::zero(); + let mut eval_infty = F::zero(); + for (local, &g_k) in g_i[block_start..block_end].iter().enumerate() { + let k_m = local >> (m - 1); + let f_k = f_values[local & ((1 << (m - 1)) - 1)]; + let g_times_f = g_k * f_k; + let eval_inf = g_times_f * f_k; + if k_m == 0 { + eval_0 += eval_inf - g_times_f; + } + eval_infty += eval_inf; + } + inner[0] += e_in * self.gamma_powers_square[index] * eval_0; + inner[1] += e_in * self.gamma_powers_square[index] * eval_infty; + } + }, + |_x_out, e_out, inner| [e_out * inner[0], e_out * inner[1]], + |left, right| [left[0] + right[0], left[1] + right[1]], + ); + self.b + .gruen_poly_deg_3(quadratic_coeffs[0], quadratic_coeffs[1], previous_claim) + } + + fn cycle_round_poly(&self, previous_claim: F) -> Result, Stage6KernelError> { + let h = self.h.as_ref().ok_or(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity cycle state is missing", + })?; + let quadratic_coeffs = self.d.fold_out_in( + || [F::zero(); 2], + |inner, j_prime, _x_in, e_in| { + for (index, h_i) in h.iter().enumerate() { + let h_0 = h_i[2 * j_prime]; + let h_1 = h_i[2 * j_prime + 1]; + let delta = h_1 - h_0; + let rho = self.gamma_powers[index]; + inner[0] += e_in * h_0 * (h_0 - rho); + inner[1] += e_in * delta.square(); + } + }, + |_x_out, e_out, inner| [e_out * inner[0], e_out * inner[1]], + |left, right| [left[0] + right[0], left[1] + right[1]], + ); + let adjusted_claim = previous_claim + * self + .eq_r_r + .inverse() + .ok_or(Stage6KernelError::InvalidProof { + driver: Stage6Relation::Booleanity.symbol(), + reason: "booleanity address equality scalar is not invertible", + })?; + Ok(self + .d + .gruen_poly_deg_3(quadratic_coeffs[0], quadratic_coeffs[1], adjusted_claim) + * self.eq_r_r) + } + + fn bind(&mut self, challenge: F) { + if self.h.is_none() { + self.b.bind(challenge); + self.f_table.update(challenge); + self.address_round += 1; + if self.address_round == self.log_k_chunk { + self.eq_r_r = self.b.current_scalar(); + let base_eq = self.f_table.clone_values(); + let h = self + .indices + .iter() + .enumerate() + .map(|(chunk_index, chunk)| { + let rho = self.gamma_powers[chunk_index]; + chunk + .iter() + .map(|index| { + index.map_or(F::zero(), |index| rho * base_eq[usize::from(index)]) + }) + .collect::>() + }) + .collect::>(); + self.h_scratch = (0..h.len()).map(|_| Vec::new()).collect(); + self.h = Some(h); + } + } else { + self.d.bind(challenge); + if let Some(h) = &mut self.h { + for (chunk, scratch) in h.iter_mut().zip(&mut self.h_scratch) { + bind_dense_evals_reuse(chunk, scratch, challenge); + } + } + } + } + + fn factor_eval(&self, index: usize, relation: Stage6Relation) -> Result { + self.h + .as_ref() + .and_then(|h| h.get(index)) + .and_then(|values| values.first()) + .copied() + .map(|value| value * self.gamma_powers_inv[index]) + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty core booleanity factor", + }) + } + + fn final_relation_eval(&self, relation: Stage6Relation) -> Result { + if relation != Stage6Relation::Booleanity { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "wrong relation for core booleanity state", + }); + } + let eq = self.d.current_scalar() * self.eq_r_r; + let h = self.h.as_ref().ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "booleanity cycle state is missing", + })?; + let mut booleanity = F::zero(); + for (index, h_i) in h.iter().enumerate() { + let scaled = h_i + .first() + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty core booleanity factor", + })?; + booleanity += scaled * (scaled - self.gamma_powers[index]); + } + Ok(eq * booleanity) + } + + fn final_evals( + &self, + relation: Stage6Relation, + ) -> Result>, Stage6KernelError> { + self.outputs + .iter() + .map(|output| { + let factor = + output + .factor + .checked_sub(1) + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "booleanity output factor underflow", + })?; + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(factor, relation)?, + )) + }) + .collect() + } +} + +struct DenseStage6State { + factors: Vec>, + factor_scratch: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, + degree_bound: usize, +} + +#[derive(Clone)] +struct DenseTerm { + coefficient: F, + factors: Vec, +} + +#[derive(Clone, Copy)] +struct FactorOutput { + name: &'static str, + oracle: &'static str, + factor: usize, +} + +impl DenseStage6State { + fn new( + factors: Vec>, + terms: Vec>, + outputs: Vec, + active_scale: F, + degree_bound: usize, + ) -> Self { + let factor_scratch = (0..factors.len()).map(|_| Vec::new()).collect(); + Self { + factors, + factor_scratch, + terms, + outputs, + active_scale, + degree_bound, + } + } + + fn round_poly( + &self, + previous_claim: F, + relation: Stage6Relation, + ) -> Result, Stage6KernelError> { + let first_len = self.factors.first().map_or(0, Vec::len); + if first_len == 0 || !first_len.is_power_of_two() { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 dense factor has invalid length", + }); + } + if self.factors.iter().any(|factor| factor.len() != first_len) { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 dense factors have inconsistent lengths", + }); + } + let poly = round_poly_from_dense_terms( + &self.factors, + &self.terms, + self.active_scale, + self.degree_bound, + relation, + )?; + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != previous_claim { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 relation input claim mismatch", + }); + } + Ok(poly) + } + + fn bind(&mut self, challenge: F) { + if self.factors.first().map_or(0, Vec::len) / 2 >= DENSE_BIND_PAR_THRESHOLD { + self.factors + .par_iter_mut() + .zip(self.factor_scratch.par_iter_mut()) + .for_each(|(factor, scratch)| { + bind_dense_evals_reuse(factor, scratch, challenge); + }); + } else { + for (factor, scratch) in self.factors.iter_mut().zip(&mut self.factor_scratch) { + bind_dense_evals_reuse(factor, scratch, challenge); + } + } + } + + fn factor_eval(&self, index: usize, relation: Stage6Relation) -> Result { + self.factors + .get(index) + .and_then(|values| values.first()) + .copied() + .ok_or(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "empty stage6 factor", + }) + } + + fn final_relation_eval(&self, relation: Stage6Relation) -> Result { + let mut result = F::zero(); + for term in &self.terms { + let mut value = term.coefficient; + for &factor in &term.factors { + value *= self.factor_eval(factor, relation)?; + } + result += value; + } + Ok(result) + } + + fn final_evals( + &self, + relation: Stage6Relation, + ) -> Result>, Stage6KernelError> { + self.outputs + .iter() + .map(|output| { + Ok(named_eval( + output.name, + output.oracle, + self.factor_eval(output.factor, relation)?, + )) + }) + .collect() + } +} + +fn bytecode_read_raf_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .bytecode_read_raf + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "bytecode_read_raf", + })?; + if witness.bytecode_ra_chunks.is_empty() + && matches!(witness.bytecode_ra_index_chunks, None | Some([])) + { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRa", + expected: 1, + actual: 0, + }); + } + + let log_t = stage6_trace_rounds(program)?; + let log_k = + claim + .num_rounds + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.input", + expected: log_t, + actual: claim.num_rounds, + })?; + let domain_len = 1usize.checked_shl(claim.num_rounds as u32).ok_or( + Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.domain", + expected: usize::BITS as usize, + actual: claim.num_rounds, + }, + )?; + let expected_entries = + 1usize + .checked_shl(log_k as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entries", + expected: usize::BITS as usize, + actual: log_k, + })?; + require_operand_count( + "stage6.bytecode_read_raf.entries", + expected_entries, + witness.data.entries.len(), + )?; + if witness.data.entry_bytecode_index >= expected_entries { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entry_bytecode_index", + expected: expected_entries, + actual: witness.data.entry_bytecode_index + 1, + }); + } + + let chunk_lens = if witness.bytecode_ra_chunks.is_empty() { + witness + .bytecode_ra_chunk_lens + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRa", + expected: 1, + actual: 0, + })? + .to_vec() + } else { + let mut chunk_lens = Vec::with_capacity(witness.bytecode_ra_chunks.len()); + for chunk in witness.bytecode_ra_chunks { + let rounds = log2_exact(chunk.len(), "stage6.bytecode_read_raf.BytecodeRa")?; + let chunk_len = + rounds + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRa", + expected: log_t, + actual: rounds, + })?; + chunk_lens.push(chunk_len); + } + chunk_lens + }; + let covered_address_len = chunk_lens.iter().sum::(); + require_operand_count( + "stage6.bytecode_read_raf.address_chunks", + log_k, + covered_address_len, + )?; + + let sparse_cycle_indices = match witness.bytecode_ra_index_chunks { + Some(chunks) if !chunks.is_empty() => Some(bytecode_cycle_indices_from_sparse_chunks( + chunks, + &chunk_lens, + log_t, + )?), + _ => None, + }; + + if let Some(bytecode_cycle_indices) = sparse_cycle_indices.or_else(|| { + bytecode_cycle_indices_from_one_hot(witness.bytecode_ra_chunks, &chunk_lens, log_t) + }) { + let outputs = bytecode_read_raf_output_plans(program, chunk_lens.len())?; + return BytecodeReadRafStage6State::new( + witness.data, + witness.bytecode_ra_chunks, + witness.bytecode_ra_index_chunks, + bytecode_cycle_indices, + chunk_lens, + store, + log_k, + log_t, + active_scale, + claim.degree, + outputs, + ) + .map(Stage6ProverInstanceState::BytecodeReadRaf); + } + + bytecode_read_raf_dense_state( + program, + claim, + witness, + store, + active_scale, + log_k, + log_t, + domain_len, + chunk_lens, + ) + .map(Stage6ProverInstanceState::Dense) +} + +#[expect(clippy::too_many_arguments)] +fn bytecode_read_raf_dense_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + witness: Stage6BytecodeReadRafWitness<'_, F>, + store: &Stage6ValueStore, + active_scale: F, + log_k: usize, + log_t: usize, + domain_len: usize, + chunk_lens: Vec, +) -> Result, Stage6KernelError> { + let mut factors = Vec::with_capacity(witness.bytecode_ra_chunks.len() + 1); + factors.push(bytecode_weighted_value_factor( + witness.data, + store, + log_k, + log_t, + domain_len, + )?); + factors.extend(expanded_bytecode_ra_factors( + witness.bytecode_ra_chunks, + &chunk_lens, + log_k, + log_t, + domain_len, + )?); + let term_factors = (0..factors.len()).collect::>(); + let outputs = bytecode_read_raf_output_plans(program, witness.bytecode_ra_chunks.len())?; + + Ok(DenseStage6State::new( + factors, + vec![DenseTerm { + coefficient: F::one(), + factors: term_factors, + }], + outputs, + active_scale, + claim.degree, + )) +} + +fn booleanity_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .booleanity + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "booleanity", + })?; + let log_t = stage6_trace_rounds(program)?; + if let Some(index_chunks) = witness.index_chunks { + if index_chunks.is_empty() { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.index_chunks", + expected: 1, + actual: 0, + }); + } + let trace_len = 1usize << log_t; + for chunk in index_chunks { + require_operand_count("stage6.booleanity.index_chunk", trace_len, chunk.len())?; + } + let log_k_chunk = + claim + .num_rounds + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.input", + expected: log_t, + actual: claim.num_rounds, + })?; + let combined_r = booleanity_combined_point(store, log_t, log_k_chunk)?; + require_operand_count( + "stage6.booleanity.combined_point", + claim.num_rounds, + combined_r.len(), + )?; + let r_address = &combined_r[..log_k_chunk]; + let r_cycle = &combined_r[log_k_chunk..]; + return CoreBooleanityStage6State::new( + r_address, + r_cycle, + index_chunks.iter().map(|chunk| (*chunk).to_vec()).collect(), + store.scalar("stage6.booleanity.gamma")?, + booleanity_output_plans(program, index_chunks.len())?, + active_scale, + ) + .map(Stage6ProverInstanceState::CoreBooleanity); + } + + if witness.chunks.is_empty() { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.Ra", + expected: 1, + actual: 0, + }); + } + let domain_len = witness.chunks[0].len(); + let booleanity_rounds = log2_exact(domain_len, "stage6.booleanity.trace_len")?; + require_operand_count( + "stage6.booleanity.input", + booleanity_rounds, + claim.num_rounds, + )?; + for chunk in witness.chunks { + require_operand_count("stage6.booleanity.Ra", domain_len, chunk.len())?; + } + let log_k_chunk = + booleanity_rounds + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.trace_len", + expected: log_t, + actual: booleanity_rounds, + })?; + let combined_r = booleanity_combined_point(store, log_t, log_k_chunk)?; + let mut eq_point = combined_r[..log_k_chunk].to_vec(); + eq_point.reverse(); + eq_point.extend(combined_r[log_k_chunk..].iter().rev().copied()); + eq_point.reverse(); + let eq = EqPolynomial::::evals(&eq_point, None); + require_operand_count("stage6.booleanity.eq", domain_len, eq.len())?; + + let gamma = store.scalar("stage6.booleanity.gamma")?; + let gamma_sq = gamma.square(); + let mut gamma_power = F::one(); + let mut gamma_powers = Vec::with_capacity(witness.chunks.len()); + for _ in 0..witness.chunks.len() { + gamma_powers.push(gamma_power); + gamma_power *= gamma_sq; + } + + BooleanityStage6State::new( + eq, + witness + .chunks + .iter() + .map(|chunk| (*chunk).to_vec()) + .collect(), + gamma_powers, + booleanity_output_plans(program, witness.chunks.len())?, + active_scale, + claim.degree, + ) + .map(Stage6ProverInstanceState::Booleanity) +} + +fn booleanity_combined_point( + store: &Stage6ValueStore, + log_t: usize, + log_k_chunk: usize, +) -> Result, Stage6KernelError> { + let stage5_point = store.point("stage6.input.stage5.instruction_read_raf.InstructionRa_0")?; + let stage5_address_len = + stage5_point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + expected: log_t, + actual: stage5_point.len(), + })?; + if stage5_address_len < log_k_chunk { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + expected: log_k_chunk + log_t, + actual: stage5_point.len(), + }); + } + + let mut stage5_addr = stage5_point[..stage5_address_len].to_vec(); + stage5_addr.reverse(); + let mut combined_r = stage5_addr[stage5_address_len - log_k_chunk..].to_vec(); + combined_r.extend(stage5_point[stage5_address_len..].iter().rev().copied()); + require_operand_count( + "stage6.booleanity.combined_point", + log_k_chunk + log_t, + combined_r.len(), + )?; + Ok(combined_r) +} + +fn hamming_booleanity_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .hamming_booleanity + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "hamming_booleanity", + })?; + let trace_rounds = log2_exact( + witness.hamming_weight.len(), + "stage6.hamming_booleanity.trace_len", + )?; + require_operand_count( + "stage6.hamming_booleanity.input", + trace_rounds, + claim.num_rounds, + )?; + let lookup_output_point = store.point("stage6.input.stage1.LookupOutput")?.to_vec(); + require_operand_count( + "stage6.input.stage1.LookupOutput", + trace_rounds, + lookup_output_point.len(), + )?; + let eq_lookup_output = EqPolynomial::::evals(&lookup_output_point, None); + require_operand_count( + "stage6.hamming_booleanity.eq", + witness.hamming_weight.len(), + eq_lookup_output.len(), + )?; + let output = program + .evals + .iter() + .find(|eval| eval.name == "stage6.hamming_booleanity.eval.HammingWeight") + .map(|eval| FactorOutput { + name: eval.name, + oracle: eval.oracle, + factor: 1, + }) + .ok_or(Stage6KernelError::MissingValue { + symbol: "stage6.hamming_booleanity.eval.HammingWeight", + })?; + + Ok(DenseStage6State::new( + vec![eq_lookup_output, witness.hamming_weight.to_vec()], + vec![ + DenseTerm { + coefficient: F::one(), + factors: vec![0, 1, 1], + }, + DenseTerm { + coefficient: -F::one(), + factors: vec![0, 1], + }, + ], + vec![output], + active_scale, + claim.degree, + )) +} + +fn inc_claim_reduction_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .inc_claim_reduction + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "inc_claim_reduction", + })?; + let trace_rounds = log2_exact( + witness.ram_inc.len(), + "stage6.inc_claim_reduction.trace_len", + )?; + require_operand_count( + "stage6.inc_claim_reduction.RdInc", + witness.ram_inc.len(), + witness.rd_inc.len(), + )?; + require_operand_count( + "stage6.inc_claim_reduction.input", + trace_rounds, + claim.num_rounds, + )?; + + let ram_inc_stage2 = suffix_point( + store.point("stage6.input.stage2.ram_read_write.RamInc")?, + trace_rounds, + "stage6.input.stage2.ram_read_write.RamInc", + )?; + let ram_inc_stage4 = suffix_point( + store.point("stage6.input.stage4.ram_val_check.RamInc")?, + trace_rounds, + "stage6.input.stage4.ram_val_check.RamInc", + )?; + let rd_inc_stage4 = suffix_point( + store.point("stage6.input.stage4.registers_read_write.RdInc")?, + trace_rounds, + "stage6.input.stage4.registers_read_write.RdInc", + )?; + let rd_inc_stage5 = suffix_point( + store.point("stage6.input.stage5.registers_val_evaluation.RdInc")?, + trace_rounds, + "stage6.input.stage5.registers_val_evaluation.RdInc", + )?; + let gamma = store.scalar("stage6.inc_claim_reduction.gamma")?; + let gamma2 = gamma.square(); + + let mut eq_ram_combined = EqPolynomial::::evals(ram_inc_stage2, None); + let eq_ram_stage4 = EqPolynomial::::evals(ram_inc_stage4, None); + let mut eq_rd_combined = EqPolynomial::::evals(rd_inc_stage4, None); + let eq_rd_stage5 = EqPolynomial::::evals(rd_inc_stage5, None); + require_operand_count( + "stage6.inc_claim_reduction.eq_ram", + witness.ram_inc.len(), + eq_ram_combined.len(), + )?; + require_operand_count( + "stage6.inc_claim_reduction.eq_rd", + witness.rd_inc.len(), + eq_rd_combined.len(), + )?; + for (combined, stage4) in eq_ram_combined.iter_mut().zip(eq_ram_stage4) { + *combined += gamma * stage4; + } + for (combined, stage5) in eq_rd_combined.iter_mut().zip(eq_rd_stage5) { + *combined += gamma * stage5; + } + + Ok(DenseStage6State::new( + vec![ + eq_ram_combined, + witness.ram_inc.to_vec(), + eq_rd_combined, + witness.rd_inc.to_vec(), + ], + vec![ + DenseTerm { + coefficient: F::one(), + factors: vec![0, 1], + }, + DenseTerm { + coefficient: gamma2, + factors: vec![2, 3], + }, + ], + vec![ + factor_output_by_name(program, "stage6.inc_claim_reduction.eval.RamInc", 1)?, + factor_output_by_name(program, "stage6.inc_claim_reduction.eval.RdInc", 3)?, + ], + active_scale, + claim.degree, + )) +} + +fn ram_ra_virtual_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .ram_ra_virtual + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "ram_ra_virtual", + })?; + if witness.ram_ra_chunks.is_empty() { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.ram_ra_virtual.RamRa", + expected: 1, + actual: 0, + }); + } + let trace_len = witness.ram_ra_chunks[0].len(); + let trace_rounds = log2_exact(trace_len, "stage6.ram_ra_virtual.trace_len")?; + require_operand_count( + "stage6.ram_ra_virtual.input", + trace_rounds, + claim.num_rounds, + )?; + for chunk in witness.ram_ra_chunks { + require_operand_count("stage6.ram_ra_virtual.RamRa", trace_len, chunk.len())?; + } + + let input_point = store.point("stage6.input.stage5.ram_ra_claim_reduction.RamRa")?; + let r_cycle = suffix_point( + input_point, + trace_rounds, + "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + )?; + let eq_cycle = EqPolynomial::::evals(r_cycle, None); + require_operand_count("stage6.ram_ra_virtual.eq", trace_len, eq_cycle.len())?; + + let mut factors = Vec::with_capacity(witness.ram_ra_chunks.len() + 1); + factors.push(eq_cycle); + factors.extend(witness.ram_ra_chunks.iter().map(|chunk| (*chunk).to_vec())); + let term_factors = (0..factors.len()).collect::>(); + let outputs = ram_ra_virtual_output_plans(program, witness.ram_ra_chunks.len())?; + + Ok(DenseStage6State::new( + factors, + vec![DenseTerm { + coefficient: F::one(), + factors: term_factors, + }], + outputs, + active_scale, + claim.degree, + )) +} + +fn instruction_ra_virtual_state( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, + inputs: &Stage6ProverInputs<'_, F>, + store: &Stage6ValueStore, + active_scale: F, +) -> Result, Stage6KernelError> { + let witness = inputs + .instruction_ra_virtual + .ok_or(Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "instruction_ra_virtual", + })?; + if witness.instruction_ra_chunks.is_empty() + || witness.virtual_count == 0 + || witness.instruction_ra_chunks.len() % witness.virtual_count != 0 + { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.instruction_ra_virtual.InstructionRa", + expected: witness.virtual_count, + actual: witness.instruction_ra_chunks.len(), + }); + } + let trace_len = witness.instruction_ra_chunks[0].len(); + let trace_rounds = log2_exact(trace_len, "stage6.instruction_ra_virtual.trace_len")?; + require_operand_count( + "stage6.instruction_ra_virtual.input", + trace_rounds, + claim.num_rounds, + )?; + for chunk in witness.instruction_ra_chunks { + require_operand_count( + "stage6.instruction_ra_virtual.InstructionRa", + trace_len, + chunk.len(), + )?; + } + + let input_point = store.point("stage6.input.stage5.instruction_read_raf.InstructionRa_0")?; + let r_cycle = suffix_point( + input_point, + trace_rounds, + "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + )?; + let eq_cycle = EqPolynomial::::evals(r_cycle, None); + require_operand_count( + "stage6.instruction_ra_virtual.eq", + trace_len, + eq_cycle.len(), + )?; + + let mut factors = Vec::with_capacity(witness.instruction_ra_chunks.len() + 1); + factors.push(eq_cycle); + factors.extend( + witness + .instruction_ra_chunks + .iter() + .map(|chunk| (*chunk).to_vec()), + ); + + let chunks_per_virtual = witness.instruction_ra_chunks.len() / witness.virtual_count; + let gamma = store.scalar("stage6.instruction_ra_virtual.gamma")?; + let mut gamma_power = F::one(); + let mut terms = Vec::with_capacity(witness.virtual_count); + for virtual_index in 0..witness.virtual_count { + let start = 1 + virtual_index * chunks_per_virtual; + let end = start + chunks_per_virtual; + let mut factors = Vec::with_capacity(chunks_per_virtual + 1); + factors.push(0); + factors.extend(start..end); + terms.push(DenseTerm { + coefficient: gamma_power, + factors, + }); + gamma_power *= gamma; + } + let outputs = + instruction_ra_virtual_output_plans(program, witness.instruction_ra_chunks.len())?; + + Ok(DenseStage6State::new( + factors, + terms, + outputs, + active_scale, + claim.degree, + )) +} + +fn evaluate_stage6_field_expr( + expr: &Stage6FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + formula => { + if let Some(exponent) = formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage6KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(Stage6KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }) + } + } +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage6KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage6KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +fn append_opening_claims( + program: &'static Stage6CpuProgramPlan, + store: &mut Stage6ValueStore, + transcript: &mut T, + evals: &[Stage6NamedEval], +) -> Result>, Stage6KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + let mut seen = program + .opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect::>(); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage6KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let duplicate = seen.iter().any(|(kind, oracle, seen_point)| { + *kind == claim.claim_kind && *oracle == claim.oracle && seen_point == &point + }); + let value = store.scalar(claim.eval_source)?; + if !duplicate { + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point.clone())); + } + opening_claims.push(Stage6OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point: point.clone(), + eval: value, + }); + } + } + Ok(opening_claims) +} + +fn find_opening_claim<'a>( + program: &'a Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'a Stage6OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +fn stage6_trace_rounds(program: &'static Stage6CpuProgramPlan) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.relation == "jolt.stage6.hamming_booleanity") + .map(|instance| instance.num_rounds) + .ok_or(Stage6KernelError::MissingValue { + symbol: "stage6.hamming_booleanity.instance", + }) +} + +fn bytecode_gamma_powers(gamma: F) -> [F; 8] { + let mut powers = [F::one(); 8]; + for index in 1..powers.len() { + powers[index] = powers[index - 1] * gamma; + } + powers +} + +fn bytecode_stage_cycle_points( + store: &Stage6ValueStore, + log_t: usize, +) -> Result<[Vec; 5], Stage6KernelError> { + Ok([ + suffix_point( + store.point("stage6.input.stage1.Imm")?, + log_t, + "stage6.input.stage1.Imm", + )? + .to_vec(), + suffix_point( + store.point("stage6.input.stage2.OpFlagJump")?, + log_t, + "stage6.input.stage2.OpFlagJump", + )? + .to_vec(), + suffix_point( + store.point("stage6.input.stage3.spartan_shift.UnexpandedPC")?, + log_t, + "stage6.input.stage3.spartan_shift.UnexpandedPC", + )? + .to_vec(), + suffix_point( + store.point("stage6.input.stage4.Rs1Ra")?, + log_t, + "stage6.input.stage4.Rs1Ra", + )? + .to_vec(), + suffix_point( + store.point("stage6.input.stage5.registers_val_evaluation.RdWa")?, + log_t, + "stage6.input.stage5.registers_val_evaluation.RdWa", + )? + .to_vec(), + ]) +} + +fn bytecode_stage_value_evals( + data: Stage6BytecodeReadRafData<'_, F>, + store: &Stage6ValueStore, + r_address: &[F], + log_t: usize, +) -> Result<[F; 5], Stage6KernelError> { + let expected_len = 1usize.checked_shl(r_address.len() as u32).ok_or( + Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entries", + expected: usize::BITS as usize, + actual: r_address.len(), + }, + )?; + require_operand_count( + "stage6.bytecode_read_raf.entries", + expected_len, + data.entries.len(), + )?; + if data.entry_bytecode_index >= expected_len { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.entry_bytecode_index", + expected: expected_len, + actual: data.entry_bytecode_index + 1, + }); + } + + let stage1_gamma = store.scalar("stage6.bytecode_read_raf.stage1_gamma")?; + let stage2_gamma = store.scalar("stage6.bytecode_read_raf.stage2_gamma")?; + let stage3_gamma = store.scalar("stage6.bytecode_read_raf.stage3_gamma")?; + let stage4_gamma = store.scalar("stage6.bytecode_read_raf.stage4_gamma")?; + let stage5_gamma = store.scalar("stage6.bytecode_read_raf.stage5_gamma")?; + let stage1_gamma_powers = field_powers(stage1_gamma, 16); + let stage2_gamma_powers = field_powers(stage2_gamma, 4); + let stage3_gamma_powers = field_powers(stage3_gamma, 9); + let stage4_gamma_powers = field_powers(stage4_gamma, 3); + let stage5_gamma_powers = field_powers(stage5_gamma, data.num_lookup_tables + 2); + + let stage4_register_point = register_prefix_point(store, "stage6.input.stage4.Rs1Ra", log_t)?; + let stage5_register_point = register_prefix_point( + store, + "stage6.input.stage5.registers_val_evaluation.RdWa", + log_t, + )?; + + let mut evals = [F::zero(); 5]; + for (index, entry) in data.entries.iter().enumerate() { + let eq = indexed_boolean_eq(index, r_address)?; + let values = bytecode_entry_stage_values( + entry, + data.num_lookup_tables, + stage4_register_point, + stage5_register_point, + &stage1_gamma_powers, + &stage2_gamma_powers, + &stage3_gamma_powers, + &stage4_gamma_powers, + &stage5_gamma_powers, + )?; + for stage in 0..evals.len() { + evals[stage] += eq * values[stage]; + } + } + Ok(evals) +} + +fn bytecode_weighted_value_factor( + data: Stage6BytecodeReadRafData<'_, F>, + store: &Stage6ValueStore, + log_k: usize, + log_t: usize, + domain_len: usize, +) -> Result, Stage6KernelError> { + let gamma = store.scalar("stage6.bytecode_read_raf.gamma")?; + let gamma_powers = bytecode_gamma_powers(gamma); + let stage_cycle_points = bytecode_stage_cycle_points(store, log_t)?; + + let stage1_gamma = store.scalar("stage6.bytecode_read_raf.stage1_gamma")?; + let stage2_gamma = store.scalar("stage6.bytecode_read_raf.stage2_gamma")?; + let stage3_gamma = store.scalar("stage6.bytecode_read_raf.stage3_gamma")?; + let stage4_gamma = store.scalar("stage6.bytecode_read_raf.stage4_gamma")?; + let stage5_gamma = store.scalar("stage6.bytecode_read_raf.stage5_gamma")?; + let stage1_gamma_powers = field_powers(stage1_gamma, 16); + let stage2_gamma_powers = field_powers(stage2_gamma, 4); + let stage3_gamma_powers = field_powers(stage3_gamma, 9); + let stage4_gamma_powers = field_powers(stage4_gamma, 3); + let stage5_gamma_powers = field_powers(stage5_gamma, data.num_lookup_tables + 2); + let stage4_register_point = register_prefix_point(store, "stage6.input.stage4.Rs1Ra", log_t)?; + let stage5_register_point = register_prefix_point( + store, + "stage6.input.stage5.registers_val_evaluation.RdWa", + log_t, + )?; + let stage_values = data + .entries + .iter() + .map(|entry| { + bytecode_entry_stage_values( + entry, + data.num_lookup_tables, + stage4_register_point, + stage5_register_point, + &stage1_gamma_powers, + &stage2_gamma_powers, + &stage3_gamma_powers, + &stage4_gamma_powers, + &stage5_gamma_powers, + ) + }) + .collect::, _>>()?; + + (0..domain_len) + .map(|row| { + let (address_bits, cycle_bits) = normalized_bytecode_row_bits::(row, log_k, log_t)?; + let address_index = bits_to_index(&address_bits); + let int_eval = identity_polynomial_eval(&address_bits); + let int_contrib = [ + gamma_powers[5] * int_eval, + F::zero(), + gamma_powers[4] * int_eval, + F::zero(), + F::zero(), + ]; + let mut value = F::zero(); + for stage in 0..stage_values[address_index].len() { + value += (stage_values[address_index][stage] + int_contrib[stage]) + * EqPolynomial::::mle(&stage_cycle_points[stage], &cycle_bits) + * gamma_powers[stage]; + } + if address_index == data.entry_bytecode_index + && cycle_bits.iter().all(|bit| *bit == F::zero()) + { + value += gamma_powers[7]; + } + Ok(value) + }) + .collect() +} + +fn expanded_bytecode_ra_factors( + chunks: &[&[F]], + chunk_lens: &[usize], + log_k: usize, + log_t: usize, + domain_len: usize, +) -> Result>, Stage6KernelError> { + let mut factors = Vec::with_capacity(chunks.len()); + let mut offset = 0usize; + for (chunk, &chunk_len) in chunks.iter().zip(chunk_lens) { + let factor = (0..domain_len) + .map(|row| { + let (address_bits, cycle_bits) = + normalized_bytecode_row_bits::(row, log_k, log_t)?; + let mut chunk_bits = address_bits[offset..offset + chunk_len].to_vec(); + chunk_bits.extend(cycle_bits); + let index = bits_to_index(&chunk_bits); + chunk + .get(index) + .copied() + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRa", + expected: index + 1, + actual: chunk.len(), + }) + }) + .collect::, _>>()?; + factors.push(factor); + offset += chunk_len; + } + Ok(factors) +} + +fn bytecode_cycle_indices_from_one_hot( + chunks: &[&[F]], + chunk_lens: &[usize], + log_t: usize, +) -> Option> { + let trace_len = 1usize.checked_shl(log_t as u32)?; + let mut indices = vec![0usize; trace_len]; + let mut remaining_address_bits = chunk_lens.iter().sum::(); + for (chunk, &chunk_len) in chunks.iter().zip(chunk_lens) { + remaining_address_bits = remaining_address_bits.checked_sub(chunk_len)?; + let chunk_domain = 1usize.checked_shl(chunk_len as u32)?; + if chunk.len() != chunk_domain.checked_mul(trace_len)? { + return None; + } + for cycle in 0..trace_len { + let mut selected = None; + for chunk_value in 0..chunk_domain { + let value = chunk[chunk_value * trace_len + cycle]; + if value == F::one() { + if selected.replace(chunk_value).is_some() { + return None; + } + } else if value != F::zero() { + return None; + } + } + let selected = selected?; + indices[cycle] |= selected << remaining_address_bits; + } + } + Some(indices) +} + +fn bytecode_cycle_indices_from_sparse_chunks( + chunks: &[&[Option]], + chunk_lens: &[usize], + log_t: usize, +) -> Result, Stage6KernelError> { + validate_bytecode_ra_index_chunks(chunks, chunk_lens, log_t)?; + let trace_len = + 1usize + .checked_shl(log_t as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRaIndex", + expected: usize::BITS as usize, + actual: log_t, + })?; + let mut indices = vec![0usize; trace_len]; + let mut remaining_address_bits = chunk_lens.iter().sum::(); + for (chunk, &chunk_len) in chunks.iter().zip(chunk_lens) { + remaining_address_bits = remaining_address_bits.checked_sub(chunk_len).ok_or( + Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRaIndex", + expected: chunk_len, + actual: remaining_address_bits, + }, + )?; + for (cycle, index) in chunk.iter().enumerate() { + let Some(index) = *index else { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::BytecodeReadRaf.symbol(), + reason: "bytecode read RAF sparse index is missing", + }); + }; + indices[cycle] |= usize::from(index) << remaining_address_bits; + } + } + Ok(indices) +} + +fn validate_bytecode_ra_index_chunks( + chunks: &[&[Option]], + chunk_lens: &[usize], + log_t: usize, +) -> Result<(), Stage6KernelError> { + require_operand_count( + "stage6.bytecode_read_raf.BytecodeRaIndex", + chunk_lens.len(), + chunks.len(), + )?; + let trace_len = + 1usize + .checked_shl(log_t as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRaIndex", + expected: usize::BITS as usize, + actual: log_t, + })?; + for (chunk, &chunk_len) in chunks.iter().zip(chunk_lens) { + require_operand_count( + "stage6.bytecode_read_raf.BytecodeRaIndex", + trace_len, + chunk.len(), + )?; + let chunk_domain = + 1usize + .checked_shl(chunk_len as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRaIndex", + expected: usize::BITS as usize, + actual: chunk_len, + })?; + for index in *chunk { + let Some(index) = *index else { + return Err(Stage6KernelError::InvalidProof { + driver: Stage6Relation::BytecodeReadRaf.symbol(), + reason: "bytecode read RAF sparse index is missing", + }); + }; + let index = usize::from(index); + if index >= chunk_domain { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.BytecodeRaIndex", + expected: chunk_domain, + actual: index + 1, + }); + } + } + } + Ok(()) +} + +fn normalized_bytecode_row_bits( + row: usize, + log_k: usize, + log_t: usize, +) -> Result<(Vec, Vec), Stage6KernelError> { + let mut raw_bits = index_bits(row, log_k + log_t)?; + raw_bits.reverse(); + let mut cycle_bits = raw_bits.split_off(log_k); + raw_bits.reverse(); + cycle_bits.reverse(); + Ok((raw_bits, cycle_bits)) +} + +#[expect( + clippy::too_many_arguments, + reason = "bytecode stage evaluator mirrors generated stage challenge layout" +)] +fn bytecode_entry_stage_values( + entry: &Stage6BytecodeEntry, + num_lookup_tables: usize, + stage4_register_point: &[F], + stage5_register_point: &[F], + stage1_gamma_powers: &[F], + stage2_gamma_powers: &[F], + stage3_gamma_powers: &[F], + stage4_gamma_powers: &[F], + stage5_gamma_powers: &[F], +) -> Result<[F; 5], Stage6KernelError> { + let mut stage1 = entry.address + entry.imm * stage1_gamma_powers[1]; + for (flag, gamma) in entry + .circuit_flags + .iter() + .zip(stage1_gamma_powers.iter().skip(2)) + { + if *flag { + stage1 += *gamma; + } + } + + let mut stage2 = F::zero(); + if entry.circuit_flags[5] { + stage2 += stage2_gamma_powers[0]; + } + if entry.is_branch { + stage2 += stage2_gamma_powers[1]; + } + if entry.circuit_flags[6] { + stage2 += stage2_gamma_powers[2]; + } + if entry.circuit_flags[7] { + stage2 += stage2_gamma_powers[3]; + } + + let mut stage3 = entry.imm + entry.address * stage3_gamma_powers[1]; + if entry.left_is_rs1 { + stage3 += stage3_gamma_powers[2]; + } + if entry.left_is_pc { + stage3 += stage3_gamma_powers[3]; + } + if entry.right_is_rs2 { + stage3 += stage3_gamma_powers[4]; + } + if entry.right_is_imm { + stage3 += stage3_gamma_powers[5]; + } + if entry.is_noop { + stage3 += stage3_gamma_powers[6]; + } + if entry.circuit_flags[7] { + stage3 += stage3_gamma_powers[7]; + } + if entry.circuit_flags[12] { + stage3 += stage3_gamma_powers[8]; + } + + let stage4 = register_eq(entry.rd, stage4_register_point, "stage6.bytecode.entry.rd")? + * stage4_gamma_powers[0] + + register_eq( + entry.rs1, + stage4_register_point, + "stage6.bytecode.entry.rs1", + )? * stage4_gamma_powers[1] + + register_eq( + entry.rs2, + stage4_register_point, + "stage6.bytecode.entry.rs2", + )? * stage4_gamma_powers[2]; + + let mut stage5 = register_eq(entry.rd, stage5_register_point, "stage6.bytecode.entry.rd")? + * stage5_gamma_powers[0]; + if !entry.is_interleaved { + stage5 += stage5_gamma_powers[1]; + } + if let Some(table) = entry.lookup_table { + if table >= num_lookup_tables { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode.entry.lookup_table", + expected: num_lookup_tables, + actual: table + 1, + }); + } + stage5 += stage5_gamma_powers[2 + table]; + } + + Ok([stage1, stage2, stage3, stage4, stage5]) +} + +fn register_eq( + index: Option, + point: &[F], + input: &'static str, +) -> Result { + let Some(index) = index else { + return Ok(F::zero()); + }; + let register_count = + 1usize + .checked_shl(point.len() as u32) + .ok_or(Stage6KernelError::InvalidInputLength { + input, + expected: usize::BITS as usize, + actual: point.len(), + })?; + if index >= register_count { + return Err(Stage6KernelError::InvalidInputLength { + input, + expected: register_count, + actual: index + 1, + }); + } + indexed_boolean_eq(index, point) +} + +fn indexed_boolean_eq(index: usize, point: &[F]) -> Result { + let bits = index_bits(index, point.len())?; + Ok(EqPolynomial::::mle(&bits, point)) +} + +fn index_bits(index: usize, len: usize) -> Result, Stage6KernelError> { + if len >= usize::BITS as usize { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.index_bits", + expected: usize::BITS as usize - 1, + actual: len, + }); + } + let limit = 1usize << len; + if index >= limit { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.index_bits.index", + expected: limit, + actual: index + 1, + }); + } + Ok((0..len) + .map(|bit| F::from_u64(((index >> (len - 1 - bit)) & 1) as u64)) + .collect()) +} + +fn bits_to_index(bits: &[F]) -> usize { + bits.iter().fold(0usize, |index, bit| { + let bit_value = usize::from(*bit != F::zero()); + (index << 1) | bit_value + }) +} + +fn field_powers(base: F, count: usize) -> Vec { + let mut powers = Vec::with_capacity(count); + let mut power = F::one(); + for _ in 0..count { + powers.push(power); + power *= base; + } + powers +} + +fn identity_polynomial_eval(point: &[F]) -> F { + point + .iter() + .enumerate() + .map(|(index, value)| value.mul_pow_2(point.len() - 1 - index)) + .sum() +} + +fn register_prefix_point<'a, F: Field>( + store: &'a Stage6ValueStore, + symbol: &'static str, + log_t: usize, +) -> Result<&'a [F], Stage6KernelError> { + let point = store.point(symbol)?; + let register_len = + point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: symbol, + expected: log_t, + actual: point.len(), + })?; + prefix_point(point, register_len, symbol) +} + +fn normalize_bytecode_read_raf_point( + program: &'static Stage6CpuProgramPlan, + point: &[F], +) -> Result, Stage6KernelError> { + let log_t = stage6_trace_rounds(program)?; + let log_k = point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.bytecode_read_raf.point", + expected: log_t, + actual: point.len(), + })?; + let mut normalized = point.to_vec(); + normalized[..log_k].reverse(); + normalized[log_k..].reverse(); + Ok(normalized) +} + +fn normalize_stage6_booleanity_point( + program: &'static Stage6CpuProgramPlan, + point: &[F], +) -> Result, Stage6KernelError> { + let log_t = stage6_trace_rounds(program)?; + let log_k = point + .len() + .checked_sub(log_t) + .ok_or(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.point", + expected: log_t, + actual: point.len(), + })?; + let mut normalized = point.to_vec(); + normalized[..log_k].reverse(); + normalized[log_k..].reverse(); + Ok(normalized) +} + +fn normalize_instruction_read_raf_point( + point: &[F], +) -> Result, Stage6KernelError> { + const LOG_K: usize = 128; + if point.len() < LOG_K { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.instruction_read_raf.point", + expected: LOG_K, + actual: point.len(), + }); + } + let mut normalized = point.to_vec(); + normalized[LOG_K..].reverse(); + Ok(normalized) +} + +fn reverse_slice(values: &[F]) -> Vec { + values.iter().rev().copied().collect() +} + +fn prefix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], Stage6KernelError> { + point + .get(..length) + .filter(|prefix| prefix.len() == length) + .ok_or(Stage6KernelError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +fn suffix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], Stage6KernelError> { + point + .get(point.len().saturating_sub(length)..) + .filter(|suffix| suffix.len() == length) + .ok_or(Stage6KernelError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +fn log2_exact(value: usize, input: &'static str) -> Result { + if value != 0 && value.is_power_of_two() { + Ok(value.trailing_zeros() as usize) + } else { + Err(Stage6KernelError::InvalidInputLength { + input, + expected: value.next_power_of_two(), + actual: value, + }) + } +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn named_eval(name: &'static str, oracle: &'static str, value: F) -> Stage6NamedEval { + Stage6NamedEval { + name, + oracle, + value, + } +} + +fn factor_output_by_name( + program: &'static Stage6CpuProgramPlan, + name: &'static str, + factor: usize, +) -> Result { + program + .evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| FactorOutput { + name: eval.name, + oracle: eval.oracle, + factor, + }) + .ok_or(Stage6KernelError::MissingValue { symbol: name }) +} + +fn ram_ra_virtual_output_plans( + program: &'static Stage6CpuProgramPlan, + chunk_count: usize, +) -> Result, Stage6KernelError> { + indexed_output_plans_by_prefix(program, "stage6.ram_ra_virtual.eval.RamRa_", chunk_count, 1) +} + +fn bytecode_read_raf_output_plans( + program: &'static Stage6CpuProgramPlan, + chunk_count: usize, +) -> Result, Stage6KernelError> { + indexed_output_plans_by_prefix( + program, + "stage6.bytecode_read_raf.eval.BytecodeRa_", + chunk_count, + 1, + ) +} + +fn booleanity_output_plans( + program: &'static Stage6CpuProgramPlan, + chunk_count: usize, +) -> Result, Stage6KernelError> { + let mut evals = program + .evals + .iter() + .filter(|eval| { + eval.name + .starts_with("stage6.booleanity.eval.InstructionRa_") + || eval.name.starts_with("stage6.booleanity.eval.BytecodeRa_") + || eval.name.starts_with("stage6.booleanity.eval.RamRa_") + }) + .collect::>(); + evals.sort_by_key(|eval| eval.index); + if evals.len() != chunk_count { + return Err(Stage6KernelError::InvalidInputLength { + input: "stage6.booleanity.eval", + expected: chunk_count, + actual: evals.len(), + }); + } + evals + .into_iter() + .enumerate() + .map(|(index, eval)| { + if eval.index != index { + return Err(Stage6KernelError::InvalidProof { + driver: "stage6.booleanity.eval", + reason: "non-contiguous indexed eval", + }); + } + Ok(FactorOutput { + name: eval.name, + oracle: eval.oracle, + factor: index + 1, + }) + }) + .collect() +} + +fn instruction_ra_virtual_output_plans( + program: &'static Stage6CpuProgramPlan, + chunk_count: usize, +) -> Result, Stage6KernelError> { + indexed_output_plans_by_prefix( + program, + "stage6.instruction_ra_virtual.eval.InstructionRa_", + chunk_count, + 1, + ) +} + +fn indexed_output_plans_by_prefix( + program: &'static Stage6CpuProgramPlan, + prefix: &'static str, + count: usize, + first_factor: usize, +) -> Result, Stage6KernelError> { + let mut outputs = vec![None; count]; + for eval in program.evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| Stage6KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if index >= count || outputs[index].is_some() { + return Err(Stage6KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval", + }); + } + outputs[index] = Some(FactorOutput { + name: eval.name, + oracle: eval.oracle, + factor: first_factor + index, + }); + } + outputs + .into_iter() + .map(|output| output.ok_or(Stage6KernelError::MissingValue { symbol: prefix })) + .collect() +} + +fn eval_by_name( + evals: &[Stage6NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage6KernelError::MissingValue { symbol: name }) +} + +fn indexed_evals_by_prefix_any( + evals: &[Stage6NamedEval], + prefix: &'static str, +) -> Result, Stage6KernelError> { + let mut indexed_values = Vec::new(); + for eval in evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| Stage6KernelError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if indexed_values + .iter() + .any(|(existing_index, _)| *existing_index == index) + { + return Err(Stage6KernelError::InvalidProof { + driver: prefix, + reason: "duplicate indexed eval", + }); + } + indexed_values.push((index, eval.value)); + } + if indexed_values.is_empty() { + return Err(Stage6KernelError::MissingValue { symbol: prefix }); + } + indexed_values.sort_by_key(|(index, _)| *index); + for (expected, (actual, _)) in indexed_values.iter().enumerate() { + if *actual != expected { + return Err(Stage6KernelError::InvalidProof { + driver: prefix, + reason: "non-contiguous indexed eval", + }); + } + } + Ok(indexed_values.into_iter().map(|(_, value)| value).collect()) +} + +fn booleanity_evals(evals: &[Stage6NamedEval]) -> Result, Stage6KernelError> { + let mut values = indexed_evals_by_prefix_any(evals, "stage6.booleanity.eval.InstructionRa_")?; + values.extend(indexed_evals_by_prefix_any( + evals, + "stage6.booleanity.eval.BytecodeRa_", + )?); + values.extend(indexed_evals_by_prefix_any( + evals, + "stage6.booleanity.eval.RamRa_", + )?); + Ok(values) +} + +fn claim_relation( + program: &'static Stage6CpuProgramPlan, + claim: &Stage6SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage6Relation::from_symbol(relation) + .ok_or(Stage6KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage6KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage6KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + Stage6Relation::from_symbol(kernel.relation).ok_or(Stage6KernelError::UnknownRelation { + relation: kernel.relation, + }) +} + +fn instance_round_offset( + program: &'static Stage6CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage6KernelError::MissingClaim { + batch: driver, + claim, + }) +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + trim_trailing_zero_coefficients(&mut combined); + UnivariatePoly::new(combined) +} + +fn trim_trailing_zero_coefficients(coefficients: &mut Vec) { + while coefficients.len() > 1 && coefficients.last() == Some(&F::zero()) { + let _ = coefficients.pop(); + } +} + +fn round_poly_from_dense_terms( + factors: &[Vec], + terms: &[DenseTerm], + active_scale: F, + degree_bound: usize, + relation: Stage6Relation, +) -> Result, Stage6KernelError> { + if degree_bound > 5 { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 dense degree bound is unsupported", + }); + } + let half = factors.first().map_or(0, |factor| factor.len() / 2); + for term in terms { + if term.factors.len() > degree_bound { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 dense term exceeds degree bound", + }); + } + if term.factors.iter().any(|factor| *factor >= factors.len()) { + return Err(Stage6KernelError::InvalidProof { + driver: relation.symbol(), + reason: "stage6 dense term references missing factor", + }); + } + } + + let eval_count = degree_bound + 1; + let mut evals = if half >= DENSE_BIND_PAR_THRESHOLD { + (0..half) + .into_par_iter() + .fold( + || vec![F::zero(); eval_count], + |mut row_evals, row| { + accumulate_dense_row_evaluations(factors, terms, row, &mut row_evals); + row_evals + }, + ) + .reduce( + || vec![F::zero(); eval_count], + |mut left, right| { + for (left, right) in left.iter_mut().zip(right) { + *left += right; + } + left + }, + ) + } else { + let mut total = vec![F::zero(); eval_count]; + for row in 0..half { + accumulate_dense_row_evaluations(factors, terms, row, &mut total); + } + total + }; + for eval in &mut evals { + *eval *= active_scale; + } + Ok(UnivariatePoly::interpolate_over_integers(&evals)) +} + +fn accumulate_dense_row_evaluations( + factors: &[Vec], + terms: &[DenseTerm], + row: usize, + evals: &mut [F], +) { + for (point, eval) in evals.iter_mut().enumerate() { + let point = F::from_u64(point as u64); + for term in terms { + let mut term_eval = term.coefficient; + for &factor in &term.factors { + let low = factors[factor][2 * row]; + let high = factors[factor][2 * row + 1]; + term_eval *= low + (high - low) * point; + } + *eval += term_eval; + } + } +} + +pub fn execute_stage6_program( + program: &'static Stage6CpuProgramPlan, + mode: Stage6ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + F: Field, + T: Transcript, + E: Stage6KernelExecutor, +{ + let mut artifacts = Stage6ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_squeeze(program, step.symbol).ok_or(Stage6KernelError::MissingValue { + symbol: step.symbol, + })?; + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage6ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + "transcript_absorb_bytes" => { + let absorb = find_absorb_bytes(program, step.symbol).ok_or( + Stage6KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage6_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_driver(program, step.symbol).ok_or(Stage6KernelError::MissingDriver { + driver: step.symbol, + })?; + let kernel_symbol = driver.kernel.ok_or(Stage6KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or( + Stage6KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + }, + )?; + let batch = + find_batch(program, driver.batch).ok_or(Stage6KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage6KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage6ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage6ExecutionMode::Verifier => { + executor.verify_sumcheck(context, transcript)? + } + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + } + _ => { + return Err(Stage6KernelError::InvalidProgramStep { + symbol: step.symbol, + kind: step.kind, + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + artifacts.opening_claims = executor.opening_claim_values(program)?; + Ok(artifacts) +} + +fn absorb_stage6_bytes(absorb: &'static Stage6TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn find_squeeze( + program: &'static Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage6TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|squeeze| squeeze.symbol == symbol) +} + +fn find_absorb_bytes( + program: &'static Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage6TranscriptAbsorbBytesPlan> { + program + .transcript_absorb_bytes + .iter() + .find(|absorb| absorb.symbol == symbol) +} + +fn find_driver( + program: &'static Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage6SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_kernel( + program: &'static Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage6KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch( + program: &'static Stage6CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage6SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +#[cfg(test)] +#[expect( + clippy::expect_used, + clippy::unwrap_used, + reason = "tests use panic-on-error helpers to keep failure context concise" +)] +mod tests { + use super::*; + use jolt_field::{Fr, RingCore}; + use jolt_transcript::Blake2bTranscript; + + const PARAMS: Stage6Params = Stage6Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }; + const STEPS: &[Stage6ProgramStepPlan] = &[Stage6ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage6.sumcheck", + }]; + const CLAIM_INPUT_OPENINGS: &[&str] = &["stage6.input.claim"]; + const CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.claim", + stage: "stage6", + domain: "jolt.test_domain", + num_rounds: 1, + degree: 1, + claim: "stage6.claim", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + claim_value: "stage6.input.claim", + input_openings: CLAIM_INPUT_OPENINGS, + }]; + const KERNELS: &[Stage6KernelPlan] = &[Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }]; + const BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 0, + ordered_claims: &[], + claim_operands: &[], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[], + }]; + const DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 0, + degree: 0, + }]; + const PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: &[], + field_exprs: &[], + kernels: KERNELS, + claims: &[], + batches: BATCHES, + drivers: DRIVERS, + instance_results: &[], + evals: &[], + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const REPLAY_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.claim"], + claim_operands: &["stage6.claim"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[1], + }]; + const REPLAY_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[1], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 1, + degree: 1, + }]; + const REPLAY_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: &[], + field_exprs: &[], + kernels: KERNELS, + claims: CLAIMS, + batches: REPLAY_BATCHES, + drivers: REPLAY_DRIVERS, + instance_results: &[], + evals: &[], + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const BYTECODE_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[ + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.gamma", + field: "bn254_fr", + value: 2, + }, + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.stage1_gamma", + field: "bn254_fr", + value: 3, + }, + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.stage2_gamma", + field: "bn254_fr", + value: 5, + }, + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.stage3_gamma", + field: "bn254_fr", + value: 7, + }, + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.stage4_gamma", + field: "bn254_fr", + value: 11, + }, + Stage6FieldConstantPlan { + symbol: "stage6.bytecode_read_raf.stage5_gamma", + field: "bn254_fr", + value: 13, + }, + ]; + const BYTECODE_CLAIM_INPUT_OPENINGS: &[&str] = &["stage6.input.bytecode_read_raf_claim"]; + const BYTECODE_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.bytecode_read_raf.input", + stage: "stage6", + domain: "jolt.stage6_bytecode_read_raf_domain", + num_rounds: 3, + degree: 3, + claim: "stage6.bytecode_read_raf.weighted_prior_stage_values", + kernel: Some("jolt.cpu.stage6.bytecode_read_raf"), + relation: None, + claim_value: "stage6.input.bytecode_read_raf_claim", + input_openings: BYTECODE_CLAIM_INPUT_OPENINGS, + }]; + const BYTECODE_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.bytecode_read_raf", + relation: "jolt.stage6.bytecode_read_raf", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_bytecode_read_raf", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const BYTECODE_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.bytecode_read_raf.input"], + claim_operands: &["stage6.bytecode_read_raf.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[3], + }]; + const BYTECODE_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[3], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 3, + degree: 3, + }]; + const BYTECODE_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = &[ + Stage6SumcheckInstanceResultPlan { + symbol: "stage6.bytecode_read_raf.instance", + source: "stage6.sumcheck", + claim: "stage6.bytecode_read_raf.input", + relation: "jolt.stage6.bytecode_read_raf", + index: 0, + point_arity: 3, + num_rounds: 3, + round_offset: 0, + point_order: "bytecode_read_raf", + degree: 3, + }, + Stage6SumcheckInstanceResultPlan { + symbol: "stage6.hamming_booleanity.instance", + source: "stage6.sumcheck", + claim: "stage6.hamming_booleanity.input", + relation: "jolt.stage6.hamming_booleanity", + index: 1, + point_arity: 1, + num_rounds: 1, + round_offset: 0, + point_order: "reverse", + degree: 3, + }, + ]; + const BYTECODE_EVALS: &[Stage6SumcheckEvalPlan] = &[ + Stage6SumcheckEvalPlan { + symbol: "stage6.bytecode_read_raf.eval.BytecodeRa_0", + source: "stage6.sumcheck", + name: "stage6.bytecode_read_raf.eval.BytecodeRa_0", + index: 0, + oracle: "BytecodeRa_0", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.bytecode_read_raf.eval.BytecodeRa_1", + source: "stage6.sumcheck", + name: "stage6.bytecode_read_raf.eval.BytecodeRa_1", + index: 1, + oracle: "BytecodeRa_1", + }, + ]; + const BYTECODE_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: BYTECODE_FIELD_CONSTANTS, + field_exprs: &[], + kernels: BYTECODE_KERNELS, + claims: BYTECODE_CLAIMS, + batches: BYTECODE_BATCHES, + drivers: BYTECODE_DRIVERS, + instance_results: BYTECODE_INSTANCE_RESULTS, + evals: BYTECODE_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const BOOLEANITY_OPENING_INPUTS: &[Stage6OpeningInputPlan] = &[Stage6OpeningInputPlan { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + source_stage: "stage5", + source_claim: "stage5.instruction_read_raf.opening.InstructionRa_0", + oracle: "InstructionRa_0", + domain: "jolt.stage5_instruction_ra_chunk_domain", + point_arity: 4, + claim_kind: "virtual", + }]; + const BOOLEANITY_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[ + Stage6FieldConstantPlan { + symbol: "stage6.zero", + field: "bn254_fr", + value: 0, + }, + Stage6FieldConstantPlan { + symbol: "stage6.booleanity.gamma", + field: "bn254_fr", + value: 2, + }, + ]; + const BOOLEANITY_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.booleanity.input", + stage: "stage6", + domain: "jolt.stage6_booleanity_domain", + num_rounds: 3, + degree: 3, + claim: "stage6.booleanity.zero", + kernel: Some("jolt.cpu.stage6.booleanity"), + relation: None, + claim_value: "stage6.zero", + input_openings: &[], + }]; + const BOOLEANITY_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.booleanity", + relation: "jolt.stage6.booleanity", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_booleanity", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const BOOLEANITY_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.booleanity.input"], + claim_operands: &["stage6.booleanity.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[3], + }]; + const BOOLEANITY_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[3], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 3, + degree: 3, + }]; + const BOOLEANITY_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = &[ + Stage6SumcheckInstanceResultPlan { + symbol: "stage6.booleanity.instance", + source: "stage6.sumcheck", + claim: "stage6.booleanity.input", + relation: "jolt.stage6.booleanity", + index: 0, + point_arity: 3, + num_rounds: 3, + round_offset: 0, + point_order: "stage6_booleanity", + degree: 3, + }, + Stage6SumcheckInstanceResultPlan { + symbol: "stage6.hamming_booleanity.instance", + source: "stage6.sumcheck", + claim: "stage6.hamming_booleanity.input", + relation: "jolt.stage6.hamming_booleanity", + index: 1, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 3, + }, + ]; + const BOOLEANITY_EVALS: &[Stage6SumcheckEvalPlan] = &[ + Stage6SumcheckEvalPlan { + symbol: "stage6.booleanity.eval.InstructionRa_0", + source: "stage6.sumcheck", + name: "stage6.booleanity.eval.InstructionRa_0", + index: 0, + oracle: "InstructionRa_0", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.booleanity.eval.BytecodeRa_0", + source: "stage6.sumcheck", + name: "stage6.booleanity.eval.BytecodeRa_0", + index: 1, + oracle: "BytecodeRa_0", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.booleanity.eval.RamRa_0", + source: "stage6.sumcheck", + name: "stage6.booleanity.eval.RamRa_0", + index: 2, + oracle: "RamRa_0", + }, + ]; + const BOOLEANITY_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: BOOLEANITY_OPENING_INPUTS, + field_constants: BOOLEANITY_FIELD_CONSTANTS, + field_exprs: &[], + kernels: BOOLEANITY_KERNELS, + claims: BOOLEANITY_CLAIMS, + batches: BOOLEANITY_BATCHES, + drivers: BOOLEANITY_DRIVERS, + instance_results: BOOLEANITY_INSTANCE_RESULTS, + evals: BOOLEANITY_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const HAMMING_OPENING_INPUTS: &[Stage6OpeningInputPlan] = &[Stage6OpeningInputPlan { + symbol: "stage6.input.stage1.LookupOutput", + source_stage: "stage1", + source_claim: "stage1.outer_remaining.opening.LookupOutput", + oracle: "LookupOutput", + domain: "jolt.trace_domain", + point_arity: 2, + claim_kind: "virtual", + }]; + const HAMMING_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[Stage6FieldConstantPlan { + symbol: "stage6.zero", + field: "bn254_fr", + value: 0, + }]; + const HAMMING_CLAIM_INPUT_OPENINGS: &[&str] = &["stage6.input.stage1.LookupOutput"]; + const HAMMING_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.hamming_booleanity.input", + stage: "stage6", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 3, + claim: "stage6.hamming_booleanity.zero", + kernel: Some("jolt.cpu.stage6.hamming_booleanity"), + relation: None, + claim_value: "stage6.zero", + input_openings: HAMMING_CLAIM_INPUT_OPENINGS, + }]; + const HAMMING_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.hamming_booleanity", + relation: "jolt.stage6.hamming_booleanity", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_hamming_booleanity", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const HAMMING_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.hamming_booleanity.input"], + claim_operands: &["stage6.hamming_booleanity.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[2], + }]; + const HAMMING_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[2], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 3, + }]; + const HAMMING_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = + &[Stage6SumcheckInstanceResultPlan { + symbol: "stage6.hamming_booleanity.instance", + source: "stage6.sumcheck", + claim: "stage6.hamming_booleanity.input", + relation: "jolt.stage6.hamming_booleanity", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 3, + }]; + const HAMMING_EVALS: &[Stage6SumcheckEvalPlan] = &[Stage6SumcheckEvalPlan { + symbol: "stage6.hamming_booleanity.eval.HammingWeight", + source: "stage6.sumcheck", + name: "stage6.hamming_booleanity.eval.HammingWeight", + index: 0, + oracle: "HammingWeight", + }]; + const HAMMING_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: HAMMING_OPENING_INPUTS, + field_constants: HAMMING_FIELD_CONSTANTS, + field_exprs: &[], + kernels: HAMMING_KERNELS, + claims: HAMMING_CLAIMS, + batches: HAMMING_BATCHES, + drivers: HAMMING_DRIVERS, + instance_results: HAMMING_INSTANCE_RESULTS, + evals: HAMMING_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const INC_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[Stage6FieldConstantPlan { + symbol: "stage6.inc_claim_reduction.gamma", + field: "bn254_fr", + value: 2, + }]; + const INC_CLAIM_INPUT_OPENINGS: &[&str] = &[ + "stage6.input.stage2.ram_read_write.RamInc", + "stage6.input.stage4.ram_val_check.RamInc", + "stage6.input.stage4.registers_read_write.RdInc", + "stage6.input.stage5.registers_val_evaluation.RdInc", + ]; + const INC_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.inc_claim_reduction.input", + stage: "stage6", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 2, + claim: "stage6.inc_claim_reduction.weighted_increments", + kernel: Some("jolt.cpu.stage6.inc_claim_reduction"), + relation: None, + claim_value: "stage6.input.inc_claim", + input_openings: INC_CLAIM_INPUT_OPENINGS, + }]; + const INC_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.inc_claim_reduction", + relation: "jolt.stage6.inc_claim_reduction", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_inc_claim_reduction", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const INC_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.inc_claim_reduction.input"], + claim_operands: &["stage6.inc_claim_reduction.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[2], + }]; + const INC_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[2], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 2, + }]; + const INC_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = + &[Stage6SumcheckInstanceResultPlan { + symbol: "stage6.inc_claim_reduction.instance", + source: "stage6.sumcheck", + claim: "stage6.inc_claim_reduction.input", + relation: "jolt.stage6.inc_claim_reduction", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 2, + }]; + const INC_EVALS: &[Stage6SumcheckEvalPlan] = &[ + Stage6SumcheckEvalPlan { + symbol: "stage6.inc_claim_reduction.eval.RamInc", + source: "stage6.sumcheck", + name: "stage6.inc_claim_reduction.eval.RamInc", + index: 0, + oracle: "RamInc", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.inc_claim_reduction.eval.RdInc", + source: "stage6.sumcheck", + name: "stage6.inc_claim_reduction.eval.RdInc", + index: 1, + oracle: "RdInc", + }, + ]; + const INC_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: INC_FIELD_CONSTANTS, + field_exprs: &[], + kernels: INC_KERNELS, + claims: INC_CLAIMS, + batches: INC_BATCHES, + drivers: INC_DRIVERS, + instance_results: INC_INSTANCE_RESULTS, + evals: INC_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const RAM_RA_CLAIM_INPUT_OPENINGS: &[&str] = + &["stage6.input.stage5.ram_ra_claim_reduction.RamRa"]; + const RAM_RA_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.ram_ra_virtual.input", + stage: "stage6", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 5, + claim: "stage6.ram_ra_virtual.weighted_ram_ra", + kernel: Some("jolt.cpu.stage6.ram_ra_virtual"), + relation: None, + claim_value: "stage6.input.ram_ra_virtual_claim", + input_openings: RAM_RA_CLAIM_INPUT_OPENINGS, + }]; + const RAM_RA_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.ram_ra_virtual", + relation: "jolt.stage6.ram_ra_virtual", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_ram_ra_virtual", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const RAM_RA_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.ram_ra_virtual.input"], + claim_operands: &["stage6.ram_ra_virtual.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[2], + }]; + const RAM_RA_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[2], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 5, + }]; + const RAM_RA_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = + &[Stage6SumcheckInstanceResultPlan { + symbol: "stage6.ram_ra_virtual.instance", + source: "stage6.sumcheck", + claim: "stage6.ram_ra_virtual.input", + relation: "jolt.stage6.ram_ra_virtual", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 5, + }]; + const RAM_RA_EVALS: &[Stage6SumcheckEvalPlan] = &[ + Stage6SumcheckEvalPlan { + symbol: "stage6.ram_ra_virtual.eval.RamRa_0", + source: "stage6.sumcheck", + name: "stage6.ram_ra_virtual.eval.RamRa_0", + index: 0, + oracle: "RamRa_0", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.ram_ra_virtual.eval.RamRa_1", + source: "stage6.sumcheck", + name: "stage6.ram_ra_virtual.eval.RamRa_1", + index: 1, + oracle: "RamRa_1", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.ram_ra_virtual.eval.RamRa_2", + source: "stage6.sumcheck", + name: "stage6.ram_ra_virtual.eval.RamRa_2", + index: 2, + oracle: "RamRa_2", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.ram_ra_virtual.eval.RamRa_3", + source: "stage6.sumcheck", + name: "stage6.ram_ra_virtual.eval.RamRa_3", + index: 3, + oracle: "RamRa_3", + }, + ]; + const RAM_RA_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: &[], + field_exprs: &[], + kernels: RAM_RA_KERNELS, + claims: RAM_RA_CLAIMS, + batches: RAM_RA_BATCHES, + drivers: RAM_RA_DRIVERS, + instance_results: RAM_RA_INSTANCE_RESULTS, + evals: RAM_RA_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + const INSTRUCTION_RA_OPENING_INPUTS: &[Stage6OpeningInputPlan] = &[ + Stage6OpeningInputPlan { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + source_stage: "stage5", + source_claim: "stage5.instruction_read_raf.opening.InstructionRa_0", + oracle: "InstructionRa_0", + domain: "jolt.stage5_instruction_ra_chunk_domain", + point_arity: 2, + claim_kind: "virtual", + }, + Stage6OpeningInputPlan { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", + source_stage: "stage5", + source_claim: "stage5.instruction_read_raf.opening.InstructionRa_1", + oracle: "InstructionRa_1", + domain: "jolt.stage5_instruction_ra_chunk_domain", + point_arity: 2, + claim_kind: "virtual", + }, + ]; + const INSTRUCTION_RA_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[Stage6FieldConstantPlan { + symbol: "stage6.instruction_ra_virtual.gamma", + field: "bn254_fr", + value: 3, + }]; + const INSTRUCTION_RA_CLAIM_INPUT_OPENINGS: &[&str] = &[ + "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + "stage6.input.stage5.instruction_read_raf.InstructionRa_1", + ]; + const INSTRUCTION_RA_CLAIMS: &[Stage6SumcheckClaimPlan] = &[Stage6SumcheckClaimPlan { + symbol: "stage6.instruction_ra_virtual.input", + stage: "stage6", + domain: "jolt.trace_domain", + num_rounds: 2, + degree: 5, + claim: "stage6.instruction_ra_virtual.weighted_instruction_ra", + kernel: Some("jolt.cpu.stage6.instruction_ra_virtual"), + relation: None, + claim_value: "stage6.input.instruction_ra_virtual_claim", + input_openings: INSTRUCTION_RA_CLAIM_INPUT_OPENINGS, + }]; + const INSTRUCTION_RA_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.instruction_ra_virtual", + relation: "jolt.stage6.instruction_ra_virtual", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_instruction_ra_virtual", + }, + Stage6KernelPlan { + symbol: "jolt.cpu.stage6.batched", + relation: "jolt.stage6.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage6_batched", + }, + ]; + const INSTRUCTION_RA_BATCHES: &[Stage6SumcheckBatchPlan] = &[Stage6SumcheckBatchPlan { + symbol: "stage6.batch", + stage: "stage6", + proof_slot: "stage6.sumcheck", + policy: "jolt_core_stage6_aligned", + count: 1, + ordered_claims: &["stage6.instruction_ra_virtual.input"], + claim_operands: &["stage6.instruction_ra_virtual.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[2], + }]; + const INSTRUCTION_RA_DRIVERS: &[Stage6SumcheckDriverPlan] = &[Stage6SumcheckDriverPlan { + symbol: "stage6.sumcheck", + stage: "stage6", + proof_slot: "stage6.sumcheck", + kernel: Some("jolt.cpu.stage6.batched"), + relation: None, + batch: "stage6.batch", + policy: "jolt_core_stage6_aligned", + round_schedule: &[2], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 2, + degree: 5, + }]; + const INSTRUCTION_RA_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = + &[Stage6SumcheckInstanceResultPlan { + symbol: "stage6.instruction_ra_virtual.instance", + source: "stage6.sumcheck", + claim: "stage6.instruction_ra_virtual.input", + relation: "jolt.stage6.instruction_ra_virtual", + index: 0, + point_arity: 2, + num_rounds: 2, + round_offset: 0, + point_order: "reverse", + degree: 5, + }]; + const INSTRUCTION_RA_EVALS: &[Stage6SumcheckEvalPlan] = &[ + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_0", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_0", + index: 0, + oracle: "InstructionRa_0", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_1", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_1", + index: 1, + oracle: "InstructionRa_1", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_2", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_2", + index: 2, + oracle: "InstructionRa_2", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_3", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_3", + index: 3, + oracle: "InstructionRa_3", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_4", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_4", + index: 4, + oracle: "InstructionRa_4", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_5", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_5", + index: 5, + oracle: "InstructionRa_5", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_6", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_6", + index: 6, + oracle: "InstructionRa_6", + }, + Stage6SumcheckEvalPlan { + symbol: "stage6.instruction_ra_virtual.eval.InstructionRa_7", + source: "stage6.sumcheck", + name: "stage6.instruction_ra_virtual.eval.InstructionRa_7", + index: 7, + oracle: "InstructionRa_7", + }, + ]; + const INSTRUCTION_RA_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: INSTRUCTION_RA_OPENING_INPUTS, + field_constants: INSTRUCTION_RA_FIELD_CONSTANTS, + field_exprs: &[], + kernels: INSTRUCTION_RA_KERNELS, + claims: INSTRUCTION_RA_CLAIMS, + batches: INSTRUCTION_RA_BATCHES, + drivers: INSTRUCTION_RA_DRIVERS, + instance_results: INSTRUCTION_RA_INSTANCE_RESULTS, + evals: INSTRUCTION_RA_EVALS, + point_zeros: &[], + point_slices: &[], + point_concats: &[], + opening_claims: &[], + opening_equalities: &[], + opening_batches: &[], + }; + + #[test] + fn stage6_symbols_parse_as_stage6_relations_and_abis() { + assert_eq!( + Stage6Relation::from_symbol("jolt.stage6.bytecode_read_raf"), + Some(Stage6Relation::BytecodeReadRaf) + ); + assert_eq!( + Stage6Relation::from_symbol("jolt.stage6.batched"), + Some(Stage6Relation::Batched) + ); + assert_eq!( + Stage6KernelAbi::from_name("jolt_stage6_bytecode_read_raf"), + Some(Stage6KernelAbi::BytecodeReadRaf) + ); + assert_eq!( + Stage6KernelAbi::from_name("jolt_stage6_batched"), + Some(Stage6KernelAbi::Batched) + ); + assert_eq!(Stage6Relation::from_symbol("jolt.stage5.batched"), None); + assert_eq!(Stage6KernelAbi::from_name("jolt_stage5_batched"), None); + } + + #[test] + fn unsupported_executor_reaches_stage6_batched_abi() { + let mut executor = UnsupportedStage6KernelExecutor; + let mut transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &PROGRAM, + Stage6ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect_err("stage6 kernels are not implemented yet"); + + assert_eq!( + error, + Stage6KernelError::KernelNotImplemented { + abi: "jolt_stage6_batched" + } + ); + } + + #[test] + fn proof_carrying_executor_replays_stage6_sumcheck_transcript() { + let input_claim = Fr::from_u64(3); + let (proof, opening_inputs) = replay_proof(input_claim); + let mut executor = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut transcript = Blake2bTranscript::::new(b"stage6_test"); + + let artifacts = execute_stage6_program( + &REPLAY_PROGRAM, + Stage6ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect("proof-carrying Stage 6 replay succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].point, proof.sumchecks[0].point); + } + + #[test] + fn proof_carrying_executor_rejects_bad_round_polynomial() { + let input_claim = Fr::from_u64(3); + let (mut proof, opening_inputs) = replay_proof(input_claim); + let mut coefficients = proof.sumchecks[0].proof.round_polynomials[0] + .coefficients() + .to_vec(); + coefficients[0] += Fr::from_u64(1); + proof.sumchecks[0].proof.round_polynomials[0] = UnivariatePoly::new(coefficients); + let mut executor = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut transcript = Blake2bTranscript::::new(b"stage6_test"); + + let error = execute_stage6_program( + &REPLAY_PROGRAM, + Stage6ExecutionMode::Prover, + &mut executor, + &mut transcript, + ) + .expect_err("tampered Stage 6 replay is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched round check failed" + } + ); + } + + #[test] + fn bytecode_read_raf_prover_produces_verifiable_sumcheck() { + let entries = bytecode_entries(); + let data = Stage6BytecodeReadRafData { + entries: &entries, + entry_bytecode_index: 2, + num_lookup_tables: 2, + }; + let bytecode_ra_0 = frs(&[1, 2, 3, 4]); + let bytecode_ra_1 = frs(&[2, 1, 4, 3]); + let bytecode_ra_chunks: [&[Fr]; 2] = [&bytecode_ra_0, &bytecode_ra_1]; + let mut opening_inputs = bytecode_opening_inputs(); + let input_claim = bytecode_read_raf_claim(data, &bytecode_ra_chunks, &opening_inputs); + opening_inputs.push(Stage6OpeningInputValue { + symbol: "stage6.input.bytecode_read_raf_claim", + point: Vec::new(), + eval: input_claim, + }); + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_bytecode_read_raf( + Stage6BytecodeReadRafWitness { + data, + bytecode_ra_chunks: &bytecode_ra_chunks, + bytecode_ra_chunk_lens: None, + bytecode_ra_index_chunks: None, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("bytecode read RAF prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 2); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs) + .with_bytecode_read_raf_data(data); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts bytecode read RAF output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn bytecode_read_raf_prover_accepts_sparse_index_chunks() { + let entries = bytecode_entries(); + let data = Stage6BytecodeReadRafData { + entries: &entries, + entry_bytecode_index: 2, + num_lookup_tables: 2, + }; + let bytecode_ra_0 = frs(&[0, 1, 1, 0]); + let bytecode_ra_1 = frs(&[1, 0, 0, 1]); + let bytecode_ra_chunks: [&[Fr]; 2] = [&bytecode_ra_0, &bytecode_ra_1]; + let bytecode_ra_index_0 = [Some(1u8), Some(0u8)]; + let bytecode_ra_index_1 = [Some(0u8), Some(1u8)]; + let bytecode_ra_index_chunks: [&[Option]; 2] = + [&bytecode_ra_index_0, &bytecode_ra_index_1]; + let bytecode_ra_chunk_lens = [1usize, 1usize]; + let sparse_only_bytecode_ra_chunks: [&[Fr]; 0] = []; + let mut opening_inputs = bytecode_opening_inputs(); + let input_claim = bytecode_read_raf_claim(data, &bytecode_ra_chunks, &opening_inputs); + opening_inputs.push(Stage6OpeningInputValue { + symbol: "stage6.input.bytecode_read_raf_claim", + point: Vec::new(), + eval: input_claim, + }); + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_bytecode_read_raf( + Stage6BytecodeReadRafWitness { + data, + bytecode_ra_chunks: &sparse_only_bytecode_ra_chunks, + bytecode_ra_chunk_lens: Some(&bytecode_ra_chunk_lens), + bytecode_ra_index_chunks: Some(&bytecode_ra_index_chunks), + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("bytecode read RAF prover accepts sparse index chunks"); + + assert_eq!( + bytecode_cycle_indices_from_sparse_chunks(&bytecode_ra_index_chunks, &[1, 1], 1) + .expect("sparse bytecode indices are valid"), + vec![2, 1] + ); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs) + .with_bytecode_read_raf_data(data); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts sparse bytecode read RAF output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn bytecode_read_raf_verifier_rejects_bad_final_eval() { + let entries = bytecode_entries(); + let data = Stage6BytecodeReadRafData { + entries: &entries, + entry_bytecode_index: 2, + num_lookup_tables: 2, + }; + let bytecode_ra_0 = frs(&[1, 2, 3, 4]); + let bytecode_ra_1 = frs(&[2, 1, 4, 3]); + let bytecode_ra_chunks: [&[Fr]; 2] = [&bytecode_ra_0, &bytecode_ra_1]; + let mut opening_inputs = bytecode_opening_inputs(); + let input_claim = bytecode_read_raf_claim(data, &bytecode_ra_chunks, &opening_inputs); + opening_inputs.push(Stage6OpeningInputValue { + symbol: "stage6.input.bytecode_read_raf_claim", + point: Vec::new(), + eval: input_claim, + }); + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_bytecode_read_raf( + Stage6BytecodeReadRafWitness { + data, + bytecode_ra_chunks: &bytecode_ra_chunks, + bytecode_ra_chunk_lens: None, + bytecode_ra_index_chunks: None, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("bytecode read RAF prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs) + .with_bytecode_read_raf_data(data); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &BYTECODE_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered bytecode read RAF eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + #[test] + fn booleanity_prover_produces_verifiable_sumcheck() { + let instruction_ra = frs(&[0, 1, 0, 1, 1, 0, 1, 0]); + let bytecode_ra = frs(&[1, 0, 1, 0, 0, 1, 0, 1]); + let ram_ra = frs(&[0, 0, 1, 1, 0, 1, 1, 0]); + let chunks: [&[Fr]; 3] = [&instruction_ra, &bytecode_ra, &ram_ra]; + let stage5_point = frs(&[11, 13, 2, 3]); + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + point: stage5_point, + eval: Fr::from_u64(0), + }]; + let prover_inputs = + Stage6ProverInputs::new(&opening_inputs).with_booleanity(Stage6BooleanityWitness { + chunks: &chunks, + index_chunks: None, + }); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &BOOLEANITY_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("booleanity prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 3); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &BOOLEANITY_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts booleanity output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn booleanity_verifier_rejects_bad_final_eval() { + let instruction_ra = frs(&[0, 1, 0, 1, 1, 0, 1, 0]); + let bytecode_ra = frs(&[1, 0, 1, 0, 0, 1, 0, 1]); + let ram_ra = frs(&[0, 0, 1, 1, 0, 1, 1, 0]); + let chunks: [&[Fr]; 3] = [&instruction_ra, &bytecode_ra, &ram_ra]; + let stage5_point = frs(&[11, 13, 2, 3]); + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + point: stage5_point, + eval: Fr::from_u64(0), + }]; + let prover_inputs = + Stage6ProverInputs::new(&opening_inputs).with_booleanity(Stage6BooleanityWitness { + chunks: &chunks, + index_chunks: None, + }); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &BOOLEANITY_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("booleanity prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &BOOLEANITY_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered booleanity eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + #[test] + fn hamming_booleanity_prover_produces_verifiable_sumcheck() { + let lookup_output_point = frs(&[3, 5]); + let hamming_weight = frs(&[0, 1, 1, 0]); + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.stage1.LookupOutput", + point: lookup_output_point, + eval: Fr::from_u64(9), + }]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_hamming_booleanity( + Stage6HammingBooleanityWitness { + hamming_weight: &hamming_weight, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &HAMMING_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("hamming booleanity prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 1); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &HAMMING_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts hamming output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn stage6_witness_helper_adapts_kernel_opening_inputs() { + let params = Stage6WitnessParams { + trace_len: 2, + log_k_chunk: 1, + log_k_bytecode: 1, + log_k_ram: 1, + lookups_ra_virtual_log_k_chunk: 1, + instruction_d: 1, + instruction_ra_virtual_d: 1, + bytecode_d: 1, + ram_d: 1, + }; + let cycle_inputs = [ + CycleInput { + dense: [2, 3], + one_hot: [Some(1), Some(0), Some(1)], + }, + CycleInput::PADDING, + ]; + let opening_inputs = [ + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + point: frs(&[5]), + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + point: frs(&[7]), + eval: Fr::from_u64(0), + }, + ]; + + let witness = stage6_witness_from_opening_inputs(params, &cycle_inputs, &opening_inputs); + + assert_eq!(witness.ram_ra_virtual.len(), 1); + assert_eq!(witness.instruction_ra_virtual.len(), 1); + assert_eq!(witness.rd_inc, vec![Fr::from_u64(2), Fr::from_u64(0)]); + assert_eq!(witness.ram_inc, vec![Fr::from_u64(3), Fr::from_u64(0)]); + } + + #[test] + fn hamming_booleanity_prover_requires_witness() { + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.stage1.LookupOutput", + point: frs(&[3, 5]), + eval: Fr::from_u64(9), + }]; + let mut prover = Stage6ProverKernelExecutor::new(Stage6ProverInputs::new(&opening_inputs)); + let mut transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &HAMMING_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut transcript, + ) + .expect_err("hamming booleanity witness is required"); + + assert_eq!( + error, + Stage6KernelError::MissingKernelInput { + kernel: "jolt_stage6_batched", + input: "hamming_booleanity" + } + ); + } + + #[test] + fn hamming_booleanity_verifier_rejects_bad_final_eval() { + let lookup_output_point = frs(&[3, 5]); + let hamming_weight = frs(&[0, 1, 1, 0]); + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.stage1.LookupOutput", + point: lookup_output_point, + eval: Fr::from_u64(9), + }]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_hamming_booleanity( + Stage6HammingBooleanityWitness { + hamming_weight: &hamming_weight, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &HAMMING_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("hamming booleanity prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &HAMMING_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered hamming eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + #[test] + fn inc_claim_reduction_prover_produces_verifiable_sumcheck() { + let ram_inc = frs(&[1, 3, 5, 7]); + let rd_inc = frs(&[2, 4, 6, 8]); + let ram_inc_stage2_point = frs(&[2, 3]); + let ram_inc_stage4_point = frs(&[5, 7]); + let rd_inc_stage4_point = frs(&[11, 13]); + let rd_inc_stage5_point = frs(&[17, 19]); + let gamma = Fr::from_u64(2); + let input_claim = multilinear_eval(&ram_inc, &ram_inc_stage2_point) + + gamma * multilinear_eval(&ram_inc, &ram_inc_stage4_point) + + gamma.square() * multilinear_eval(&rd_inc, &rd_inc_stage4_point) + + gamma.square() * gamma * multilinear_eval(&rd_inc, &rd_inc_stage5_point); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage2.ram_read_write.RamInc", + point: ram_inc_stage2_point.clone(), + eval: multilinear_eval(&ram_inc, &ram_inc_stage2_point), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage4.ram_val_check.RamInc", + point: ram_inc_stage4_point.clone(), + eval: multilinear_eval(&ram_inc, &ram_inc_stage4_point), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage4.registers_read_write.RdInc", + point: rd_inc_stage4_point.clone(), + eval: multilinear_eval(&rd_inc, &rd_inc_stage4_point), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.registers_val_evaluation.RdInc", + point: rd_inc_stage5_point.clone(), + eval: multilinear_eval(&rd_inc, &rd_inc_stage5_point), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.inc_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_inc_claim_reduction( + Stage6IncClaimReductionWitness { + ram_inc: &ram_inc, + rd_inc: &rd_inc, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &INC_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("increment claim-reduction prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 2); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &INC_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts increment output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn inc_claim_reduction_verifier_rejects_bad_final_eval() { + let ram_inc = frs(&[1, 3, 5, 7]); + let rd_inc = frs(&[2, 4, 6, 8]); + let ram_inc_stage2_point = frs(&[2, 3]); + let ram_inc_stage4_point = frs(&[5, 7]); + let rd_inc_stage4_point = frs(&[11, 13]); + let rd_inc_stage5_point = frs(&[17, 19]); + let gamma = Fr::from_u64(2); + let input_claim = multilinear_eval(&ram_inc, &ram_inc_stage2_point) + + gamma * multilinear_eval(&ram_inc, &ram_inc_stage4_point) + + gamma.square() * multilinear_eval(&rd_inc, &rd_inc_stage4_point) + + gamma.square() * gamma * multilinear_eval(&rd_inc, &rd_inc_stage5_point); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage2.ram_read_write.RamInc", + point: ram_inc_stage2_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage4.ram_val_check.RamInc", + point: ram_inc_stage4_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage4.registers_read_write.RdInc", + point: rd_inc_stage4_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.registers_val_evaluation.RdInc", + point: rd_inc_stage5_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.inc_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_inc_claim_reduction( + Stage6IncClaimReductionWitness { + ram_inc: &ram_inc, + rd_inc: &rd_inc, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &INC_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("increment claim-reduction prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &INC_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered increment eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + #[test] + fn ram_ra_virtual_prover_produces_verifiable_sumcheck() { + let ram_ra_0 = frs(&[1, 2, 3, 4]); + let ram_ra_1 = frs(&[2, 3, 4, 5]); + let ram_ra_2 = frs(&[3, 4, 5, 6]); + let ram_ra_3 = frs(&[4, 5, 6, 7]); + let ram_ra_chunks: [&[Fr]; 4] = [&ram_ra_0, &ram_ra_1, &ram_ra_2, &ram_ra_3]; + let input_point = frs(&[2, 3]); + let input_claim = product_virtual_claim(&ram_ra_chunks, &input_point); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + point: input_point, + eval: input_claim, + }, + Stage6OpeningInputValue { + symbol: "stage6.input.ram_ra_virtual_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_ram_ra_virtual( + Stage6RamRaVirtualWitness { + ram_ra_chunks: &ram_ra_chunks, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &RAM_RA_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("RAM RA virtualization prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 4); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &RAM_RA_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts RAM RA virtualization output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn ram_ra_virtual_verifier_rejects_bad_final_eval() { + let ram_ra_0 = frs(&[1, 2, 3, 4]); + let ram_ra_1 = frs(&[2, 3, 4, 5]); + let ram_ra_2 = frs(&[3, 4, 5, 6]); + let ram_ra_3 = frs(&[4, 5, 6, 7]); + let ram_ra_chunks: [&[Fr]; 4] = [&ram_ra_0, &ram_ra_1, &ram_ra_2, &ram_ra_3]; + let input_point = frs(&[2, 3]); + let input_claim = product_virtual_claim(&ram_ra_chunks, &input_point); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + point: input_point, + eval: input_claim, + }, + Stage6OpeningInputValue { + symbol: "stage6.input.ram_ra_virtual_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_ram_ra_virtual( + Stage6RamRaVirtualWitness { + ram_ra_chunks: &ram_ra_chunks, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &RAM_RA_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("RAM RA virtualization prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &RAM_RA_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered RAM RA eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + #[test] + fn instruction_ra_virtual_prover_produces_verifiable_sumcheck() { + let instruction_ra_0 = frs(&[1, 2, 3, 4]); + let instruction_ra_1 = frs(&[2, 3, 4, 5]); + let instruction_ra_2 = frs(&[3, 4, 5, 6]); + let instruction_ra_3 = frs(&[4, 5, 6, 7]); + let instruction_ra_4 = frs(&[5, 6, 7, 8]); + let instruction_ra_5 = frs(&[6, 7, 8, 9]); + let instruction_ra_6 = frs(&[7, 8, 9, 10]); + let instruction_ra_7 = frs(&[8, 9, 10, 11]); + let instruction_ra_chunks: [&[Fr]; 8] = [ + &instruction_ra_0, + &instruction_ra_1, + &instruction_ra_2, + &instruction_ra_3, + &instruction_ra_4, + &instruction_ra_5, + &instruction_ra_6, + &instruction_ra_7, + ]; + let input_point = frs(&[2, 3]); + let gamma = Fr::from_u64(3); + let input_claim = + grouped_product_virtual_claim(&instruction_ra_chunks, 2, &input_point, gamma); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + point: input_point.clone(), + eval: input_claim, + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", + point: input_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.instruction_ra_virtual_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_instruction_ra_virtual( + Stage6InstructionRaVirtualWitness { + instruction_ra_chunks: &instruction_ra_chunks, + virtual_count: 2, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let artifacts = execute_stage6_program( + &INSTRUCTION_RA_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("instruction RA virtualization prover succeeds"); + + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 8); + + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let verified = execute_stage6_program( + &INSTRUCTION_RA_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("proof-carrying verifier accepts instruction RA virtualization output"); + + assert_eq!(artifacts.sumchecks[0].point, verified.sumchecks[0].point); + assert_eq!( + named_eval_values(&artifacts.sumchecks[0].evals), + named_eval_values(&verified.sumchecks[0].evals) + ); + } + + #[test] + fn instruction_ra_virtual_verifier_rejects_bad_final_eval() { + let instruction_ra_0 = frs(&[1, 2, 3, 4]); + let instruction_ra_1 = frs(&[2, 3, 4, 5]); + let instruction_ra_2 = frs(&[3, 4, 5, 6]); + let instruction_ra_3 = frs(&[4, 5, 6, 7]); + let instruction_ra_4 = frs(&[5, 6, 7, 8]); + let instruction_ra_5 = frs(&[6, 7, 8, 9]); + let instruction_ra_6 = frs(&[7, 8, 9, 10]); + let instruction_ra_7 = frs(&[8, 9, 10, 11]); + let instruction_ra_chunks: [&[Fr]; 8] = [ + &instruction_ra_0, + &instruction_ra_1, + &instruction_ra_2, + &instruction_ra_3, + &instruction_ra_4, + &instruction_ra_5, + &instruction_ra_6, + &instruction_ra_7, + ]; + let input_point = frs(&[2, 3]); + let gamma = Fr::from_u64(3); + let input_claim = + grouped_product_virtual_claim(&instruction_ra_chunks, 2, &input_point, gamma); + let opening_inputs = vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + point: input_point.clone(), + eval: input_claim, + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", + point: input_point, + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.instruction_ra_virtual_claim", + point: Vec::new(), + eval: input_claim, + }, + ]; + let prover_inputs = Stage6ProverInputs::new(&opening_inputs).with_instruction_ra_virtual( + Stage6InstructionRaVirtualWitness { + instruction_ra_chunks: &instruction_ra_chunks, + virtual_count: 2, + }, + ); + let mut prover = Stage6ProverKernelExecutor::new(prover_inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage6_test"); + let mut artifacts = execute_stage6_program( + &INSTRUCTION_RA_PROGRAM, + Stage6ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("instruction RA virtualization prover succeeds"); + + artifacts.sumchecks[0].evals[0].value += Fr::from_u64(1); + let proof = Stage6Proof { + sumchecks: artifacts.sumchecks, + }; + let mut verifier = Stage6ProofCarryingKernelExecutor::new(&proof, &opening_inputs); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage6_test"); + let error = execute_stage6_program( + &INSTRUCTION_RA_PROGRAM, + Stage6ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect_err("tampered instruction RA eval is rejected"); + + assert_eq!( + error, + Stage6KernelError::InvalidProof { + driver: "stage6.sumcheck", + reason: "batched output claim mismatch" + } + ); + } + + fn replay_proof(input_claim: Fr) -> (Stage6Proof, Vec>) { + let opening_inputs = vec![Stage6OpeningInputValue { + symbol: "stage6.input.claim", + point: Vec::new(), + eval: input_claim, + }]; + let mut transcript = Blake2bTranscript::::new(b"stage6_test"); + append_labeled_scalar(&mut transcript, "sumcheck_claim", &input_claim); + let batching_coeff = transcript.challenge_vector(1)[0]; + let claimed_sum = input_claim * batching_coeff; + let round_poly = UnivariatePoly::new(vec![claimed_sum, -claimed_sum]); + append_compressed_univariate_poly(&mut transcript, "sumcheck_poly", &round_poly); + let point = vec![transcript.challenge()]; + let proof = Stage6Proof { + sumchecks: vec![Stage6SumcheckOutput { + driver: "stage6.sumcheck", + point, + evals: Vec::new(), + opening_claims: Vec::new(), + proof: jolt_sumcheck::SumcheckProof { + round_polynomials: vec![round_poly], + }, + }], + }; + (proof, opening_inputs) + } + + fn bytecode_entries() -> [Stage6BytecodeEntry; 4] { + [ + bytecode_entry(0, 3, &[0, 5, 12], Some(0), Some(1), Some(2), Some(0)), + bytecode_entry(1, 5, &[1, 6], Some(1), None, Some(3), Some(1)), + bytecode_entry(2, 7, &[2, 7, 10], Some(2), Some(0), None, None), + bytecode_entry(3, 11, &[3, 8, 13], None, Some(2), Some(1), Some(0)), + ] + } + + fn bytecode_entry( + address: u64, + imm: u64, + flags: &[usize], + rd: Option, + rs1: Option, + rs2: Option, + lookup_table: Option, + ) -> Stage6BytecodeEntry { + let mut circuit_flags = [false; 14]; + for &flag in flags { + circuit_flags[flag] = true; + } + Stage6BytecodeEntry { + address: Fr::from_u64(address), + imm: Fr::from_u64(imm), + circuit_flags, + rd, + rs1, + rs2, + lookup_table, + is_interleaved: address.is_multiple_of(2), + is_branch: address == 1, + left_is_rs1: rs1.is_some(), + left_is_pc: address == 2, + right_is_rs2: rs2.is_some(), + right_is_imm: address == 3, + is_noop: address == 0, + } + } + + fn bytecode_opening_inputs() -> Vec> { + vec![ + Stage6OpeningInputValue { + symbol: "stage6.input.stage1.Imm", + point: frs(&[17]), + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage2.OpFlagJump", + point: frs(&[19]), + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage3.spartan_shift.UnexpandedPC", + point: frs(&[23]), + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage4.Rs1Ra", + point: frs(&[2, 3, 29]), + eval: Fr::from_u64(0), + }, + Stage6OpeningInputValue { + symbol: "stage6.input.stage5.registers_val_evaluation.RdWa", + point: frs(&[5, 7, 31]), + eval: Fr::from_u64(0), + }, + ] + } + + fn bytecode_read_raf_claim( + data: Stage6BytecodeReadRafData<'_, Fr>, + bytecode_ra_chunks: &[&[Fr]], + opening_inputs: &[Stage6OpeningInputValue], + ) -> Fr { + let mut store = Stage6ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(&BYTECODE_PROGRAM); + let log_k = 2; + let log_t = 1; + let domain_len = 1 << (log_k + log_t); + let weighted = + bytecode_weighted_value_factor(data, &store, log_k, log_t, domain_len).unwrap(); + let ra_factors = + expanded_bytecode_ra_factors(bytecode_ra_chunks, &[1, 1], log_k, log_t, domain_len) + .unwrap(); + (0..domain_len) + .map(|row| weighted[row] * ra_factors.iter().map(|factor| factor[row]).product::()) + .sum() + } + + fn frs(values: &[u64]) -> Vec { + values.iter().map(|value| Fr::from_u64(*value)).collect() + } + + fn multilinear_eval(values: &[Fr], point: &[Fr]) -> Fr { + EqPolynomial::::evals(point, None) + .into_iter() + .zip(values) + .map(|(eq, value)| eq * *value) + .sum() + } + + fn product_virtual_claim(chunks: &[&[Fr]], point: &[Fr]) -> Fr { + let eq = EqPolynomial::::evals(point, None); + (0..eq.len()) + .map(|row| eq[row] * chunks.iter().map(|chunk| chunk[row]).product::()) + .sum() + } + + fn grouped_product_virtual_claim( + chunks: &[&[Fr]], + virtual_count: usize, + point: &[Fr], + gamma: Fr, + ) -> Fr { + let eq = EqPolynomial::::evals(point, None); + let chunks_per_virtual = chunks.len() / virtual_count; + (0..eq.len()) + .map(|row| { + let mut gamma_power = Fr::from_u64(1); + let mut row_value = Fr::from_u64(0); + for group in chunks.chunks(chunks_per_virtual) { + row_value += gamma_power * group.iter().map(|chunk| chunk[row]).product::(); + gamma_power *= gamma; + } + eq[row] * row_value + }) + .sum() + } + + fn named_eval_values(evals: &[Stage6NamedEval]) -> Vec<(&'static str, &'static str, Fr)> { + evals + .iter() + .map(|eval| (eval.name, eval.oracle, eval.value)) + .collect() + } +} diff --git a/crates/jolt-kernels/src/stage7.rs b/crates/jolt-kernels/src/stage7.rs new file mode 100644 index 0000000000..32d87cb7cf --- /dev/null +++ b/crates/jolt-kernels/src/stage7.rs @@ -0,0 +1,2586 @@ +//! Stage 7 coarse-kernel ABI used by Bolt-generated Jolt prover code. +//! +//! Stage 7 fuses hamming-weight claim reduction with the address reduction for +//! all RA one-hot polynomials. This module owns the prover-side runtime behind +//! the generated `jolt.stage7.*` CPU ABI. + +use std::error::Error; +use std::fmt::{self, Display, Formatter}; + +use crate::dense::bind_dense_evals_reuse; +use jolt_field::Field; +use jolt_poly::{EqPolynomial, UnivariatePoly}; +use jolt_sumcheck::SumcheckProof; +use jolt_transcript::{Label, LabelWithCount, Transcript}; +use jolt_witness::Stage6WitnessSlices; + +pub use crate::stage6::{ + Stage6ChallengeVector as Stage7ChallengeVector, + Stage6ExecutionArtifacts as Stage7ExecutionArtifacts, + Stage6ExecutionMode as Stage7ExecutionMode, Stage6FieldConstantPlan as Stage7FieldConstantPlan, + Stage6FieldExprPlan as Stage7FieldExprPlan, Stage6NamedEval as Stage7NamedEval, + Stage6OpeningBatchPlan as Stage7OpeningBatchPlan, + Stage6OpeningClaimEqualityPlan as Stage7OpeningClaimEqualityPlan, + Stage6OpeningClaimPlan as Stage7OpeningClaimPlan, + Stage6OpeningClaimValue as Stage7OpeningClaimValue, + Stage6OpeningInputPlan as Stage7OpeningInputPlan, + Stage6OpeningInputValue as Stage7OpeningInputValue, Stage6Params as Stage7Params, + Stage6PointConcatPlan as Stage7PointConcatPlan, Stage6PointSlicePlan as Stage7PointSlicePlan, + Stage6PointZeroPlan as Stage7PointZeroPlan, Stage6ProgramStepPlan as Stage7ProgramStepPlan, + Stage6Proof as Stage7Proof, Stage6SumcheckBatchPlan as Stage7SumcheckBatchPlan, + Stage6SumcheckClaimPlan as Stage7SumcheckClaimPlan, + Stage6SumcheckDriverPlan as Stage7SumcheckDriverPlan, + Stage6SumcheckEvalPlan as Stage7SumcheckEvalPlan, + Stage6SumcheckInstanceResultPlan as Stage7SumcheckInstanceResultPlan, + Stage6SumcheckOutput as Stage7SumcheckOutput, + Stage6TranscriptAbsorbBytesPlan as Stage7TranscriptAbsorbBytesPlan, + Stage6TranscriptSqueezePlan as Stage7TranscriptSqueezePlan, +}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage7KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +impl Stage7KernelPlan { + pub fn relation_kind(&self) -> Result { + Stage7Relation::from_symbol(self.relation).ok_or(Stage7KernelError::UnknownRelation { + relation: self.relation, + }) + } + + pub fn abi_kind(&self) -> Result { + Stage7KernelAbi::from_name(self.abi) + .ok_or(Stage7KernelError::UnknownKernelAbi { abi: self.abi }) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage7CpuProgramPlan { + pub role: &'static str, + pub params: Stage7Params, + pub steps: &'static [Stage7ProgramStepPlan], + pub transcript_squeezes: &'static [Stage7TranscriptSqueezePlan], + pub transcript_absorb_bytes: &'static [Stage7TranscriptAbsorbBytesPlan], + pub opening_inputs: &'static [Stage7OpeningInputPlan], + pub field_constants: &'static [Stage7FieldConstantPlan], + pub field_exprs: &'static [Stage7FieldExprPlan], + pub kernels: &'static [Stage7KernelPlan], + pub claims: &'static [Stage7SumcheckClaimPlan], + pub batches: &'static [Stage7SumcheckBatchPlan], + pub drivers: &'static [Stage7SumcheckDriverPlan], + pub instance_results: &'static [Stage7SumcheckInstanceResultPlan], + pub evals: &'static [Stage7SumcheckEvalPlan], + pub point_zeros: &'static [Stage7PointZeroPlan], + pub point_slices: &'static [Stage7PointSlicePlan], + pub point_concats: &'static [Stage7PointConcatPlan], + pub opening_claims: &'static [Stage7OpeningClaimPlan], + pub opening_equalities: &'static [Stage7OpeningClaimEqualityPlan], + pub opening_batches: &'static [Stage7OpeningBatchPlan], +} + +impl Stage7CpuProgramPlan { + pub fn claim(&self, symbol: &str) -> Option<&Stage7SumcheckClaimPlan> { + self.claims.iter().find(|claim| claim.symbol == symbol) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage7Relation { + HammingWeightClaimReduction, + Batched, +} + +impl Stage7Relation { + pub fn from_symbol(symbol: &str) -> Option { + match symbol { + "jolt.stage7.hamming_weight_claim_reduction" => Some(Self::HammingWeightClaimReduction), + "jolt.stage7.batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn symbol(self) -> &'static str { + match self { + Self::HammingWeightClaimReduction => "jolt.stage7.hamming_weight_claim_reduction", + Self::Batched => "jolt.stage7.batched", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage7KernelAbi { + HammingWeightClaimReduction, + Batched, +} + +impl Stage7KernelAbi { + pub fn from_name(name: &str) -> Option { + match name { + "jolt_stage7_hamming_weight_claim_reduction" => Some(Self::HammingWeightClaimReduction), + "jolt_stage7_batched" => Some(Self::Batched), + _ => None, + } + } + + pub fn name(self) -> &'static str { + match self { + Self::HammingWeightClaimReduction => "jolt_stage7_hamming_weight_claim_reduction", + Self::Batched => "jolt_stage7_batched", + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Stage7KernelError { + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + MissingDynamicValue { + symbol: String, + }, + MissingDriver { + driver: &'static str, + }, + MissingKernel { + driver: &'static str, + kernel: &'static str, + }, + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + UnknownRelation { + relation: &'static str, + }, + UnknownKernelAbi { + abi: &'static str, + }, + PlanCountMismatch { + artifact: &'static str, + expected: usize, + actual: usize, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, + KernelNotImplemented { + abi: &'static str, + }, + WrongExecutorMode { + driver: &'static str, + expected: Stage7ExecutionMode, + actual: Stage7ExecutionMode, + }, + MissingProof { + driver: &'static str, + }, + MissingKernelInput { + kernel: &'static str, + input: &'static str, + }, + InvalidProgramStep { + symbol: &'static str, + kind: &'static str, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, +} + +impl Display for Stage7KernelError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::MissingClaim { batch, claim } => { + write!( + formatter, + "stage7 batch @{batch} references missing claim @{claim}" + ) + } + Self::MissingValue { symbol } => { + write!(formatter, "stage7 value @{symbol} is not available") + } + Self::MissingDynamicValue { symbol } => { + write!(formatter, "stage7 value @{symbol} is not available") + } + Self::MissingDriver { driver } => { + write!(formatter, "stage7 driver @{driver} is not available") + } + Self::MissingKernel { driver, kernel } => { + write!( + formatter, + "stage7 driver @{driver} references missing kernel @{kernel}" + ) + } + Self::MissingBatch { driver, batch } => { + write!( + formatter, + "stage7 driver @{driver} references missing batch @{batch}" + ) + } + Self::UnknownRelation { relation } => { + write!(formatter, "unknown stage7 relation `{relation}`") + } + Self::UnknownKernelAbi { abi } => { + write!(formatter, "unknown stage7 kernel ABI `{abi}`") + } + Self::PlanCountMismatch { + artifact, + expected, + actual, + } => { + write!( + formatter, + "stage7 {artifact} plan count mismatch: expected {expected}, got {actual}" + ) + } + Self::InvalidInputLength { + input, + expected, + actual, + } => { + write!( + formatter, + "stage7 input `{input}` has length {actual}, expected {expected}" + ) + } + Self::UnsupportedFieldExpr { symbol, formula } => { + write!( + formatter, + "stage7 field expr @{symbol} uses unsupported formula `{formula}`" + ) + } + Self::KernelNotImplemented { abi } => { + write!(formatter, "stage7 kernel ABI `{abi}` is not implemented") + } + Self::WrongExecutorMode { + driver, + expected, + actual, + } => { + write!( + formatter, + "stage7 driver @{driver} expected {expected:?} executor, got {actual:?}" + ) + } + Self::MissingProof { driver } => { + write!(formatter, "stage7 proof for driver @{driver} is missing") + } + Self::MissingKernelInput { kernel, input } => { + write!( + formatter, + "stage7 kernel `{kernel}` is missing required input `{input}`" + ) + } + Self::InvalidProgramStep { symbol, kind } => { + write!( + formatter, + "stage7 program step @{symbol} has invalid kind `{kind}`" + ) + } + Self::InvalidProof { driver, reason } => { + write!( + formatter, + "stage7 proof for driver @{driver} is invalid: {reason}" + ) + } + } + } +} + +impl Error for Stage7KernelError {} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Stage7RaChunkLayout { + CycleMajor, + AddressMajor, +} + +#[derive(Clone, Copy)] +pub struct Stage7RaChunks<'a, F: Field> { + pub chunks: &'a [&'a [F]], + pub layout: Stage7RaChunkLayout, +} + +#[derive(Clone, Copy)] +pub struct Stage7HammingWeightClaimReductionWitness<'a, F: Field> { + pub instruction_ra: Stage7RaChunks<'a, F>, + pub bytecode_ra: Stage7RaChunks<'a, F>, + pub ram_ra: Stage7RaChunks<'a, F>, +} + +#[derive(Clone, Copy)] +pub struct Stage7RaIndexChunks<'a> { + pub chunks: &'a [&'a [Option]], +} + +#[derive(Clone, Copy)] +pub struct Stage7HammingWeightClaimReductionIndexWitness<'a> { + pub instruction_ra: Stage7RaIndexChunks<'a>, + pub bytecode_ra: Stage7RaIndexChunks<'a>, + pub ram_ra: Stage7RaIndexChunks<'a>, +} + +#[derive(Clone, Copy)] +pub struct Stage7ProverInputs<'a, F: Field> { + pub opening_inputs: &'a [Stage7OpeningInputValue], + pub hamming_weight_claim_reduction: Option>, + pub hamming_weight_claim_reduction_indices: + Option>, +} + +impl<'a, F: Field> Stage7ProverInputs<'a, F> { + pub fn new(opening_inputs: &'a [Stage7OpeningInputValue]) -> Self { + Self { + opening_inputs, + hamming_weight_claim_reduction: None, + hamming_weight_claim_reduction_indices: None, + } + } + + pub fn empty() -> Self { + Self { + opening_inputs: &[], + hamming_weight_claim_reduction: None, + hamming_weight_claim_reduction_indices: None, + } + } + + pub fn with_hamming_weight_claim_reduction( + mut self, + witness: Stage7HammingWeightClaimReductionWitness<'a, F>, + ) -> Self { + self.hamming_weight_claim_reduction = Some(witness); + self + } + + pub fn with_hamming_weight_claim_reduction_indices( + mut self, + witness: Stage7HammingWeightClaimReductionIndexWitness<'a>, + ) -> Self { + self.hamming_weight_claim_reduction_indices = Some(witness); + self + } + + pub fn with_stage6_witness_indices(self, slices: &'a Stage6WitnessSlices<'a, F>) -> Self { + self.with_hamming_weight_claim_reduction_indices( + Stage7HammingWeightClaimReductionIndexWitness { + instruction_ra: Stage7RaIndexChunks { + chunks: &slices.instruction_ra_index_chunks, + }, + bytecode_ra: Stage7RaIndexChunks { + chunks: &slices.bytecode_ra_index_chunks, + }, + ram_ra: Stage7RaIndexChunks { + chunks: &slices.ram_ra_index_chunks, + }, + }, + ) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage7KernelContext<'a> { + pub mode: Stage7ExecutionMode, + pub program: &'static Stage7CpuProgramPlan, + pub kernel: &'a Stage7KernelPlan, + pub batch: &'a Stage7SumcheckBatchPlan, + pub driver: &'a Stage7SumcheckDriverPlan, +} + +impl Stage7KernelContext<'_> { + pub fn relation_kind(&self) -> Result { + self.kernel.relation_kind() + } + + pub fn abi_kind(&self) -> Result { + self.kernel.abi_kind() + } + + pub fn batch_claims(&self) -> Result, Stage7KernelError> { + self.batch + .claim_operands + .iter() + .map(|symbol| { + self.program + .claim(symbol) + .ok_or(Stage7KernelError::MissingClaim { + batch: self.batch.symbol, + claim: symbol, + }) + }) + .collect() + } +} + +pub trait Stage7KernelExecutor { + fn observe_challenge_vector( + &mut self, + _plan: &'static Stage7TranscriptSqueezePlan, + _values: &[F], + ) -> Result<(), Stage7KernelError> { + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + _output: &Stage7SumcheckOutput, + ) -> Result<(), Stage7KernelError> { + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript; + + fn verify_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript; +} + +#[derive(Clone, Debug, Default)] +pub struct UnsupportedStage7KernelExecutor; + +impl Stage7KernelExecutor for UnsupportedStage7KernelExecutor { + fn prove_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + let abi = context.abi_kind()?; + let _ = context.relation_kind()?; + Err(Stage7KernelError::KernelNotImplemented { abi: abi.name() }) + } + + fn verify_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + let abi = context.abi_kind()?; + let _ = context.relation_kind()?; + Err(Stage7KernelError::KernelNotImplemented { abi: abi.name() }) + } +} + +#[derive(Clone)] +pub struct Stage7ProverKernelExecutor<'a, F: Field> { + pub inputs: Stage7ProverInputs<'a, F>, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage7ProverKernelExecutor<'a, F> { + pub fn new(inputs: Stage7ProverInputs<'a, F>) -> Self { + Self { + inputs, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage7CpuProgramPlan, + ) -> Result, Stage7KernelError> { + value_store_from_observations( + program, + self.inputs.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } +} + +impl Stage7KernelExecutor for Stage7ProverKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage7TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage7KernelError> { + self.challenge_vectors.push(Stage7ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage7SumcheckOutput, + ) -> Result<(), Stage7KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + prove_stage7_kernel( + context, + &self.inputs, + self.value_store(context.program)?, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + _transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + Err(Stage7KernelError::WrongExecutorMode { + driver: context.driver.symbol, + expected: Stage7ExecutionMode::Prover, + actual: Stage7ExecutionMode::Verifier, + }) + } +} + +#[derive(Clone)] +pub struct Stage7ProofCarryingKernelExecutor<'a, F: Field> { + pub proof: &'a Stage7Proof, + pub opening_inputs: &'a [Stage7OpeningInputValue], + pub cursor: usize, + challenge_vectors: Vec>, + completed_sumchecks: Vec>, +} + +impl<'a, F: Field> Stage7ProofCarryingKernelExecutor<'a, F> { + pub fn new( + proof: &'a Stage7Proof, + opening_inputs: &'a [Stage7OpeningInputValue], + ) -> Self { + Self { + proof, + opening_inputs, + cursor: 0, + challenge_vectors: Vec::new(), + completed_sumchecks: Vec::new(), + } + } + + fn value_store( + &self, + program: &'static Stage7CpuProgramPlan, + ) -> Result, Stage7KernelError> { + value_store_from_observations( + program, + self.opening_inputs, + &self.challenge_vectors, + &self.completed_sumchecks, + ) + } + + fn next_proof( + &mut self, + driver: &'static str, + ) -> Result<&'a Stage7SumcheckOutput, Stage7KernelError> { + let proof = self + .proof + .sumchecks + .get(self.cursor) + .ok_or(Stage7KernelError::MissingProof { driver })?; + self.cursor += 1; + Ok(proof) + } +} + +impl Stage7KernelExecutor for Stage7ProofCarryingKernelExecutor<'_, F> { + fn observe_challenge_vector( + &mut self, + plan: &'static Stage7TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage7KernelError> { + self.challenge_vectors.push(Stage7ChallengeVector { + symbol: plan.symbol, + values: values.to_vec(), + }); + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + output: &Stage7SumcheckOutput, + ) -> Result<(), Stage7KernelError> { + self.completed_sumchecks.push(output.clone()); + Ok(()) + } + + fn prove_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage7_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } + + fn verify_sumcheck( + &mut self, + context: Stage7KernelContext<'_>, + transcript: &mut T, + ) -> Result, Stage7KernelError> + where + T: Transcript, + { + let proof = self.next_proof(context.driver.symbol)?; + verify_stage7_kernel( + context, + self.value_store(context.program)?, + proof, + transcript, + ) + } +} + +#[derive(Clone, Debug, Default)] +struct Stage7ValueStore { + scalars: Vec<(&'static str, F)>, + points: Vec<(&'static str, Vec)>, +} + +impl Stage7ValueStore { + fn with_opening_inputs(inputs: &[Stage7OpeningInputValue]) -> Self { + let mut store = Self::default(); + for input in inputs { + store.insert_scalar(input.symbol, input.eval); + store.insert_point(input.symbol, input.point.clone()); + } + store + } + + fn seed_constants(&mut self, program: &'static Stage7CpuProgramPlan) { + for constant in program.field_constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + for zero in program.point_zeros { + self.insert_point(zero.symbol, vec![F::from_u64(0); zero.arity]); + } + } + + fn observe_challenge_vector( + &mut self, + plan: &'static Stage7TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), Stage7KernelError> { + self.insert_point(plan.symbol, values.to_vec()); + if matches!(plan.kind, "challenge_scalar" | "scalar") { + require_operand_count(plan.symbol, 1, values.len())?; + self.insert_scalar(plan.symbol, values[0]); + } + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + program: &'static Stage7CpuProgramPlan, + output: &Stage7SumcheckOutput, + ) -> Result<(), Stage7KernelError> { + self.observe_sumcheck_values(program, output.driver, &output.point, &output.evals) + } + + fn observe_sumcheck_values( + &mut self, + program: &'static Stage7CpuProgramPlan, + driver: &'static str, + point: &[F], + evals: &[Stage7NamedEval], + ) -> Result<(), Stage7KernelError> { + self.insert_point(driver, point.to_vec()); + for instance in program + .instance_results + .iter() + .filter(|instance| instance.source == driver) + { + let end = instance.round_offset + instance.point_arity; + let mut point = point + .get(instance.round_offset..end) + .ok_or(Stage7KernelError::InvalidInputLength { + input: instance.symbol, + expected: end, + actual: point.len(), + })? + .to_vec(); + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + _ => { + return Err(Stage7KernelError::InvalidProof { + driver, + reason: "unsupported point order", + }); + } + } + self.insert_point(instance.symbol, point); + } + for eval in program.evals.iter().filter(|eval| eval.source == driver) { + let value = evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| evals.get(eval.index)) + .ok_or(Stage7KernelError::MissingValue { + symbol: eval.symbol, + })? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + let _ = self.evaluate_available_points(program)?; + let _ = self.evaluate_available_field_exprs(program)?; + self.verify_opening_equalities(program)?; + Ok(()) + } + + fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage7CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for expr in program.field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate_stage7_field_expr(expr, &operands)?); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + fn evaluate_available_points( + &mut self, + program: &'static Stage7CpuProgramPlan, + ) -> Result { + let mut inserted = 0usize; + loop { + let mut progress = 0usize; + for slice in program.point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or(Stage7KernelError::InvalidInputLength { + input: slice.symbol, + expected: end, + actual: input.len(), + })? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in program.point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + require_operand_count(concat.symbol, concat.arity, point.len())?; + self.insert_point(concat.symbol, point); + progress += 1; + } + inserted += progress; + if progress == 0 { + return Ok(inserted); + } + } + } + + fn verify_opening_equalities( + &self, + program: &'static Stage7CpuProgramPlan, + ) -> Result<(), Stage7KernelError> { + for equality in program.opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point(equality.lhs)? != self.point(equality.rhs)? + || self.scalar(equality.lhs)? != self.scalar(equality.rhs)? + { + return Err(Stage7KernelError::InvalidProof { + driver: equality.symbol, + reason: "opening claim equality failed", + }); + } + } + _ => { + return Err(Stage7KernelError::InvalidProof { + driver: equality.symbol, + reason: "unsupported opening equality mode", + }); + } + } + } + Ok(()) + } + + fn claim_value( + &mut self, + program: &'static Stage7CpuProgramPlan, + claim: &Stage7SumcheckClaimPlan, + ) -> Result { + let _ = self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + fn batch_claim_values( + &mut self, + program: &'static Stage7CpuProgramPlan, + batch: &Stage7SumcheckBatchPlan, + ) -> Result, Stage7KernelError> { + batch + .claim_operands + .iter() + .map(|symbol| { + let claim = program + .claim(symbol) + .ok_or(Stage7KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some((_, existing)) = self + .scalars + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = value; + } else { + self.scalars.push((symbol, value)); + } + } + + fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some((_, existing)) = self + .points + .iter_mut() + .find(|(existing, _)| *existing == symbol) + { + *existing = point; + } else { + self.points.push((symbol, point)); + } + } + + fn scalar(&self, symbol: &'static str) -> Result { + self.try_scalar(symbol) + .ok_or(Stage7KernelError::MissingValue { symbol }) + } + + fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, value)| *value) + } + + fn point(&self, symbol: &'static str) -> Result<&[F], Stage7KernelError> { + self.try_point(symbol) + .ok_or(Stage7KernelError::MissingValue { symbol }) + } + + fn dynamic_point(&self, symbol: String) -> Result<&[F], Stage7KernelError> { + self.try_point(&symbol) + .ok_or(Stage7KernelError::MissingDynamicValue { symbol }) + } + + fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|(existing, _)| *existing == symbol) + .map(|(_, point)| point.as_slice()) + } + + fn try_expr_operands(&self, expr: &Stage7FieldExprPlan) -> Option> { + expr.operands + .iter() + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &Stage7PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in concat.inputs { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +fn value_store_from_observations( + program: &'static Stage7CpuProgramPlan, + opening_inputs: &[Stage7OpeningInputValue], + challenge_vectors: &[Stage7ChallengeVector], + completed_sumchecks: &[Stage7SumcheckOutput], +) -> Result, Stage7KernelError> { + let mut store = Stage7ValueStore::with_opening_inputs(opening_inputs); + store.seed_constants(program); + for challenge in challenge_vectors { + let plan = + find_squeeze(program, challenge.symbol).ok_or(Stage7KernelError::MissingValue { + symbol: challenge.symbol, + })?; + store.observe_challenge_vector(plan, &challenge.values)?; + } + for output in completed_sumchecks { + store.observe_sumcheck_output(program, output)?; + } + let _ = store.evaluate_available_points(program)?; + let _ = store.evaluate_available_field_exprs(program)?; + store.verify_opening_equalities(program)?; + Ok(store) +} + +fn prove_stage7_kernel( + context: Stage7KernelContext<'_>, + inputs: &Stage7ProverInputs<'_, F>, + store: Stage7ValueStore, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage7KernelAbi::Batched => prove_batched_stage7(context, inputs, store, transcript), + abi @ Stage7KernelAbi::HammingWeightClaimReduction => { + Err(Stage7KernelError::KernelNotImplemented { abi: abi.name() }) + } + } +} + +fn verify_stage7_kernel( + context: Stage7KernelContext<'_>, + store: Stage7ValueStore, + proof: &Stage7SumcheckOutput, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + F: Field, + T: Transcript, +{ + match context.abi_kind()? { + Stage7KernelAbi::Batched => verify_batched_stage7(context, store, proof, transcript), + abi @ Stage7KernelAbi::HammingWeightClaimReduction => { + Err(Stage7KernelError::KernelNotImplemented { abi: abi.name() }) + } + } +} + +#[tracing::instrument(skip_all, name = "Stage7::prove_batched")] +fn prove_batched_stage7( + context: Stage7KernelContext<'_>, + inputs: &Stage7ProverInputs<'_, F>, + mut store: Stage7ValueStore, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + F: Field, + T: Transcript, +{ + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let two_inv = F::from_u64(2) + .inverse() + .ok_or(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "field element 2 is not invertible", + })?; + let mut instances = Vec::with_capacity(claims.len()); + for (index, claim) in claims.iter().enumerate() { + let offset = instance_round_offset(context.program, context.driver.symbol, claim.symbol)?; + if offset + claim.num_rounds > max_rounds { + return Err(Stage7KernelError::InvalidInputLength { + input: claim.symbol, + expected: max_rounds, + actual: offset + claim.num_rounds, + }); + } + let relation = claim_relation(context.program, claim)?; + let active_scale = F::one().mul_pow_2(max_rounds - offset - claim.num_rounds); + let state = + Stage7ProverInstanceState::new(context.program, claim, inputs, &store, active_scale)?; + instances.push(Stage7BatchedInstance { + claim, + relation, + offset, + previous_claim: input_claims[index].mul_pow_2(max_rounds - claim.num_rounds), + state, + }); + } + + let mut point = Vec::with_capacity(max_rounds); + let mut round_polynomials = Vec::with_capacity(max_rounds); + let mut batched_claim = instances + .iter() + .zip(&batching_coeffs) + .map(|(instance, &coefficient)| instance.previous_claim * coefficient) + .sum::(); + for round in 0..max_rounds { + let mut individual_polys = Vec::with_capacity(instances.len()); + for instance in &mut instances { + let poly = if instance.is_active(round) { + instance + .state + .round_poly(instance.previous_claim, instance.relation)? + } else { + UnivariatePoly::new(vec![instance.previous_claim * two_inv]) + }; + individual_polys.push(poly); + } + let batched_poly = combine_univariate_polys(&individual_polys, &batching_coeffs); + if batched_poly.evaluate(F::zero()) + batched_poly.evaluate(F::one()) != batched_claim { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round claim mismatch", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, &batched_poly); + let challenge = transcript.challenge(); + point.push(challenge); + batched_claim = batched_poly.evaluate(challenge); + for (instance, poly) in instances.iter_mut().zip(individual_polys) { + instance.previous_claim = poly.evaluate(challenge); + if instance.is_active(round) { + instance.state.ingest_challenge(challenge); + } + } + round_polynomials.push(batched_poly); + } + + let mut evals = Vec::new(); + let mut expected = F::zero(); + for (instance, &coefficient) in instances.iter().zip(&batching_coeffs) { + let relation_claim = instance.state.final_relation_eval(instance.relation)?; + if instance.previous_claim != relation_claim { + return Err(Stage7KernelError::InvalidProof { + driver: instance.relation.symbol(), + reason: "stage7 relation output claim mismatch", + }); + } + expected += coefficient * relation_claim; + evals.extend(instance.state.final_evals(instance.relation)?); + } + if batched_claim != expected { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + store.observe_sumcheck_values(context.program, context.driver.symbol, &point, &evals)?; + let opening_claims = append_opening_claims(context.program, &mut store, transcript, &evals)?; + Ok(Stage7SumcheckOutput { + driver: context.driver.symbol, + point, + evals, + opening_claims, + proof: SumcheckProof { round_polynomials }, + }) +} + +fn verify_batched_stage7( + context: Stage7KernelContext<'_>, + mut store: Stage7ValueStore, + proof: &Stage7SumcheckOutput, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + F: Field, + T: Transcript, +{ + if proof.driver != context.driver.symbol { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "driver symbol mismatch", + }); + } + if proof.proof.round_polynomials.len() != context.driver.num_rounds { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "unexpected batched round count", + }); + } + + let claims = context.batch_claims()?; + let input_claims = store.batch_claim_values(context.program, context.batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, context.batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let max_rounds = context.driver.num_rounds; + let mut running_claim = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), &coefficient)| { + claim.mul_pow_2(max_rounds - plan.num_rounds) * coefficient + }) + .sum::(); + let mut point = Vec::with_capacity(max_rounds); + for poly in &proof.proof.round_polynomials { + if polynomial_degree(poly) > context.driver.degree { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched polynomial exceeds degree bound", + }); + } + if poly.evaluate(F::zero()) + poly.evaluate(F::one()) != running_claim { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched round check failed", + }); + } + append_compressed_univariate_poly(transcript, context.driver.round_label, poly); + let challenge = transcript.challenge(); + running_claim = poly.evaluate(challenge); + point.push(challenge); + } + if !proof.point.is_empty() && proof.point != point { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = + expected_batched_output_claim(context, &store, &proof.evals, &point, &batching_coeffs)?; + if running_claim != expected { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "batched output claim mismatch", + }); + } + + let output = Stage7SumcheckOutput { + driver: context.driver.symbol, + point, + evals: proof.evals.clone(), + opening_claims: Vec::new(), + proof: proof.proof.clone(), + }; + store.observe_sumcheck_output(context.program, &output)?; + let opening_claims = + append_opening_claims(context.program, &mut store, &mut *transcript, &output.evals)?; + let output = Stage7SumcheckOutput { + opening_claims, + ..output + }; + Ok(output) +} + +fn expected_batched_output_claim( + context: Stage7KernelContext<'_>, + store: &Stage7ValueStore, + evals: &[Stage7NamedEval], + point: &[F], + batching_coeffs: &[F], +) -> Result { + let mut expected = F::zero(); + for (claim, &coefficient) in context.batch_claims()?.iter().zip(batching_coeffs) { + let Some(instance) = context.program.instance_results.iter().find(|instance| { + instance.claim == claim.symbol && instance.source == context.driver.symbol + }) else { + return Err(Stage7KernelError::MissingValue { + symbol: claim.symbol, + }); + }; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(Stage7KernelError::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let value = match claim_relation(context.program, claim)? { + Stage7Relation::HammingWeightClaimReduction => { + expected_hamming_weight_claim_reduction(context.program, store, evals, local_point)? + } + Stage7Relation::Batched => { + return Err(Stage7KernelError::InvalidProof { + driver: context.driver.symbol, + reason: "nested batched relation is unsupported", + }); + } + }; + expected += coefficient * value; + } + Ok(expected) +} + +fn expected_hamming_weight_claim_reduction( + program: &'static Stage7CpuProgramPlan, + store: &Stage7ValueStore, + evals: &[Stage7NamedEval], + local_point: &[F], +) -> Result { + let log_k_chunk = local_point.len(); + let booleanity_point = store.point("stage7.input.stage6.booleanity.InstructionRa_0")?; + if booleanity_point.len() < log_k_chunk { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.input.stage6.booleanity.InstructionRa_0", + expected: log_k_chunk, + actual: booleanity_point.len(), + }); + } + let r_addr_bool = &booleanity_point[..log_k_chunk]; + let rho_rev = reverse_slice(local_point); + let eq_bool_eval = EqPolynomial::::mle(&rho_rev, r_addr_bool); + let gamma = store.scalar("stage7.hamming_weight_claim_reduction.gamma")?; + let gamma_powers = gamma_powers(gamma, 3 * ra_eval_plans(program).len()); + + let mut output_claim = F::zero(); + for (index, eval_plan) in ra_eval_plans(program).iter().enumerate() { + let g_i = eval_by_name(evals, eval_plan.name)?; + let virtual_point = + store.dynamic_point(stage7_virtualization_input_symbol(eval_plan.oracle)?)?; + if virtual_point.len() < log_k_chunk { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.hamming_weight_claim_reduction.virtualization_point", + expected: log_k_chunk, + actual: virtual_point.len(), + }); + } + let eq_virt_eval = EqPolynomial::::mle(&rho_rev, &virtual_point[..log_k_chunk]); + output_claim += g_i + * (gamma_powers[3 * index] + + gamma_powers[3 * index + 1] * eq_bool_eval + + gamma_powers[3 * index + 2] * eq_virt_eval); + } + Ok(output_claim) +} + +struct Stage7BatchedInstance<'a, F: Field> { + claim: &'a Stage7SumcheckClaimPlan, + relation: Stage7Relation, + offset: usize, + previous_claim: F, + state: Stage7ProverInstanceState, +} + +impl Stage7BatchedInstance<'_, F> { + fn is_active(&self, round: usize) -> bool { + round >= self.offset && round < self.offset + self.claim.num_rounds + } +} + +enum Stage7ProverInstanceState { + HammingWeightClaimReduction(HammingWeightClaimReductionState), +} + +impl Stage7ProverInstanceState { + fn new( + program: &'static Stage7CpuProgramPlan, + claim: &Stage7SumcheckClaimPlan, + inputs: &Stage7ProverInputs<'_, F>, + store: &Stage7ValueStore, + active_scale: F, + ) -> Result { + match claim_relation(program, claim)? { + Stage7Relation::HammingWeightClaimReduction => { + hamming_weight_claim_reduction_state(program, claim, inputs, store, active_scale) + .map(Self::HammingWeightClaimReduction) + } + relation @ Stage7Relation::Batched => Err(Stage7KernelError::KernelNotImplemented { + abi: relation.symbol(), + }), + } + } + + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage7Relation, + ) -> Result, Stage7KernelError> { + match self { + Self::HammingWeightClaimReduction(state) => state.round_poly(previous_claim, relation), + } + } + + fn ingest_challenge(&mut self, challenge: F) { + match self { + Self::HammingWeightClaimReduction(state) => state.bind(challenge), + } + } + + fn final_relation_eval(&self, relation: Stage7Relation) -> Result { + match self { + Self::HammingWeightClaimReduction(state) => state.final_relation_eval(relation), + } + } + + fn final_evals( + &self, + relation: Stage7Relation, + ) -> Result>, Stage7KernelError> { + match self { + Self::HammingWeightClaimReduction(state) => state.final_evals(relation), + } + } +} + +struct HammingWeightClaimReductionState { + g: Vec>, + eq_bool: Vec, + eq_virt: Vec>, + gamma_powers: Vec, + outputs: Vec, + active_scale: F, +} + +#[derive(Clone, Copy)] +struct Stage7RaOutputPlan { + name: &'static str, + oracle: &'static str, +} + +impl HammingWeightClaimReductionState { + fn round_poly( + &mut self, + previous_claim: F, + relation: Stage7Relation, + ) -> Result, Stage7KernelError> { + if relation != Stage7Relation::HammingWeightClaimReduction { + return Err(Stage7KernelError::InvalidProof { + driver: relation.symbol(), + reason: "wrong relation for hamming-weight claim-reduction state", + }); + } + let half_len = self + .g + .first() + .ok_or(Stage7KernelError::InvalidProof { + driver: relation.symbol(), + reason: "missing G polynomial", + })? + .len() + / 2; + let mut evals = [F::zero(); 2]; + for row in 0..half_len { + let eq_bool_evals = low_to_high_linear_evals(&self.eq_bool, row); + for index in 0..self.g.len() { + let g_evals = low_to_high_linear_evals(&self.g[index], row); + let eq_virt_evals = low_to_high_linear_evals(&self.eq_virt[index], row); + let gamma_hw = self.gamma_powers[3 * index]; + let gamma_bool = self.gamma_powers[3 * index + 1]; + let gamma_virt = self.gamma_powers[3 * index + 2]; + for eval_index in 0..2 { + evals[eval_index] += g_evals[eval_index] + * (gamma_hw + + gamma_bool * eq_bool_evals[eval_index] + + gamma_virt * eq_virt_evals[eval_index]); + } + } + } + for eval in &mut evals { + *eval *= self.active_scale; + } + Ok(UnivariatePoly::from_evals_and_hint(previous_claim, &evals)) + } + + fn bind(&mut self, challenge: F) { + let mut scratch = Vec::new(); + for g in &mut self.g { + bind_dense_evals_reuse(g, &mut scratch, challenge); + } + bind_dense_evals_reuse(&mut self.eq_bool, &mut scratch, challenge); + for eq in &mut self.eq_virt { + bind_dense_evals_reuse(eq, &mut scratch, challenge); + } + } + + fn final_relation_eval(&self, relation: Stage7Relation) -> Result { + if relation != Stage7Relation::HammingWeightClaimReduction { + return Err(Stage7KernelError::InvalidProof { + driver: relation.symbol(), + reason: "wrong relation for hamming-weight claim-reduction state", + }); + } + let eq_bool = single_final_eval(&self.eq_bool, "stage7.eq_bool")?; + let mut value = F::zero(); + for index in 0..self.g.len() { + let g = single_final_eval(&self.g[index], "stage7.G")?; + let eq_virt = single_final_eval(&self.eq_virt[index], "stage7.eq_virt")?; + value += g + * (self.gamma_powers[3 * index] + + self.gamma_powers[3 * index + 1] * eq_bool + + self.gamma_powers[3 * index + 2] * eq_virt); + } + Ok(value * self.active_scale) + } + + fn final_evals( + &self, + relation: Stage7Relation, + ) -> Result>, Stage7KernelError> { + if relation != Stage7Relation::HammingWeightClaimReduction { + return Err(Stage7KernelError::InvalidProof { + driver: relation.symbol(), + reason: "wrong relation for hamming-weight claim-reduction state", + }); + } + if self.outputs.len() != self.g.len() { + return Err(Stage7KernelError::PlanCountMismatch { + artifact: "hamming-weight claim-reduction eval outputs", + expected: self.g.len(), + actual: self.outputs.len(), + }); + } + self.g + .iter() + .zip(&self.outputs) + .map(|(g, output)| { + Ok(Stage7NamedEval { + name: output.name, + oracle: output.oracle, + value: single_final_eval(g, output.name)?, + }) + }) + .collect() + } +} + +fn hamming_weight_claim_reduction_state( + program: &'static Stage7CpuProgramPlan, + claim: &Stage7SumcheckClaimPlan, + inputs: &Stage7ProverInputs<'_, F>, + store: &Stage7ValueStore, + active_scale: F, +) -> Result, Stage7KernelError> { + let log_k_chunk = claim.num_rounds; + let booleanity_point = store.point("stage7.input.stage6.booleanity.InstructionRa_0")?; + if booleanity_point.len() < log_k_chunk { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.input.stage6.booleanity.InstructionRa_0", + expected: log_k_chunk, + actual: booleanity_point.len(), + }); + } + let r_addr_bool = &booleanity_point[..log_k_chunk]; + let r_cycle = &booleanity_point[log_k_chunk..]; + let outputs = ra_eval_plans(program); + let eq_cycle = EqPolynomial::::evals(r_cycle, None); + let g = if let Some(index_witness) = inputs.hamming_weight_claim_reduction_indices { + let chunks = index_witness.ra_chunks_in_program_order(); + if chunks.len() != outputs.len() { + return Err(Stage7KernelError::PlanCountMismatch { + artifact: "stage7 RA index witness chunks", + expected: outputs.len(), + actual: chunks.len(), + }); + } + chunks + .iter() + .map(|chunk| pushforward_ra_indices(chunk.indices, log_k_chunk, &eq_cycle)) + .collect::, _>>()? + } else { + let witness = + inputs + .hamming_weight_claim_reduction + .ok_or(Stage7KernelError::MissingKernelInput { + kernel: "jolt_stage7_hamming_weight_claim_reduction", + input: "hamming_weight_claim_reduction", + })?; + let chunks = witness.ra_chunks_in_program_order(); + if chunks.len() != outputs.len() { + return Err(Stage7KernelError::PlanCountMismatch { + artifact: "stage7 RA witness chunks", + expected: outputs.len(), + actual: chunks.len(), + }); + } + chunks + .iter() + .map(|chunk| pushforward_ra_chunk(chunk.evals, chunk.layout, log_k_chunk, &eq_cycle)) + .collect::, _>>()? + }; + let eq_bool = EqPolynomial::::evals(r_addr_bool, None); + let mut eq_virt = Vec::with_capacity(outputs.len()); + for output in &outputs { + let virtual_point = + store.dynamic_point(stage7_virtualization_input_symbol(output.oracle)?)?; + if virtual_point.len() < log_k_chunk { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.hamming_weight_claim_reduction.virtualization_point", + expected: log_k_chunk, + actual: virtual_point.len(), + }); + } + eq_virt.push(EqPolynomial::::evals( + &virtual_point[..log_k_chunk], + None, + )); + } + let gamma = store.scalar("stage7.hamming_weight_claim_reduction.gamma")?; + let gamma_powers = gamma_powers(gamma, 3 * outputs.len()); + Ok(HammingWeightClaimReductionState { + g, + eq_bool, + eq_virt, + gamma_powers, + outputs, + active_scale, + }) +} + +#[derive(Clone, Copy)] +struct Stage7RaChunk<'a, F: Field> { + evals: &'a [F], + layout: Stage7RaChunkLayout, +} + +#[derive(Clone, Copy)] +struct Stage7RaIndexChunk<'a> { + indices: &'a [Option], +} + +impl<'a, F: Field> Stage7HammingWeightClaimReductionWitness<'a, F> { + fn ra_chunks_in_program_order(&self) -> Vec> { + let mut chunks = Vec::with_capacity( + self.instruction_ra.chunks.len() + + self.bytecode_ra.chunks.len() + + self.ram_ra.chunks.len(), + ); + chunks.extend( + self.instruction_ra + .chunks + .iter() + .map(|chunk| Stage7RaChunk { + evals: chunk, + layout: self.instruction_ra.layout, + }), + ); + chunks.extend(self.bytecode_ra.chunks.iter().map(|chunk| Stage7RaChunk { + evals: chunk, + layout: self.bytecode_ra.layout, + })); + chunks.extend(self.ram_ra.chunks.iter().map(|chunk| Stage7RaChunk { + evals: chunk, + layout: self.ram_ra.layout, + })); + chunks + } +} + +impl<'a> Stage7HammingWeightClaimReductionIndexWitness<'a> { + fn ra_chunks_in_program_order(&self) -> Vec> { + let mut chunks = Vec::with_capacity( + self.instruction_ra.chunks.len() + + self.bytecode_ra.chunks.len() + + self.ram_ra.chunks.len(), + ); + chunks.extend( + self.instruction_ra + .chunks + .iter() + .map(|indices| Stage7RaIndexChunk { indices }), + ); + chunks.extend( + self.bytecode_ra + .chunks + .iter() + .map(|indices| Stage7RaIndexChunk { indices }), + ); + chunks.extend( + self.ram_ra + .chunks + .iter() + .map(|indices| Stage7RaIndexChunk { indices }), + ); + chunks + } +} + +fn pushforward_ra_chunk( + chunk: &[F], + layout: Stage7RaChunkLayout, + log_k_chunk: usize, + eq_cycle: &[F], +) -> Result, Stage7KernelError> { + let address_len = 1usize << log_k_chunk; + let cycle_len = eq_cycle.len(); + let expected = address_len * cycle_len; + if chunk.len() != expected { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.ra_chunk", + expected, + actual: chunk.len(), + }); + } + let mut output = vec![F::zero(); address_len]; + match layout { + Stage7RaChunkLayout::CycleMajor => { + for (cycle, weight) in eq_cycle.iter().copied().enumerate().take(cycle_len) { + let row_start = cycle * address_len; + for address in 0..address_len { + output[address] += chunk[row_start + address] * weight; + } + } + } + Stage7RaChunkLayout::AddressMajor => { + for (address, output_value) in output.iter_mut().enumerate().take(address_len) { + let row_start = address * cycle_len; + for (cycle, weight) in eq_cycle.iter().copied().enumerate().take(cycle_len) { + *output_value += chunk[row_start + cycle] * weight; + } + } + } + } + Ok(output) +} + +fn pushforward_ra_indices( + indices: &[Option], + log_k_chunk: usize, + eq_cycle: &[F], +) -> Result, Stage7KernelError> { + let address_len = 1usize << log_k_chunk; + if indices.len() != eq_cycle.len() { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.ra_index_chunk", + expected: eq_cycle.len(), + actual: indices.len(), + }); + } + let mut output = vec![F::zero(); address_len]; + for (cycle, index) in indices.iter().enumerate() { + if let Some(index) = index { + let index = usize::from(*index); + if index >= address_len { + return Err(Stage7KernelError::InvalidInputLength { + input: "stage7.ra_index", + expected: address_len, + actual: index + 1, + }); + } + output[index] += eq_cycle[cycle]; + } + } + Ok(output) +} + +fn low_to_high_linear_evals(evals: &[F], row: usize) -> [F; 2] { + let low = evals[2 * row]; + let high = evals[2 * row + 1]; + [low, low + (high - low) * F::from_u64(2)] +} + +fn single_final_eval(evals: &[F], symbol: &'static str) -> Result { + if evals.len() == 1 { + Ok(evals[0]) + } else { + Err(Stage7KernelError::InvalidInputLength { + input: symbol, + expected: 1, + actual: evals.len(), + }) + } +} + +fn gamma_powers(gamma: F, count: usize) -> Vec { + let mut powers = Vec::with_capacity(count); + let mut power = F::one(); + for _ in 0..count { + powers.push(power); + power *= gamma; + } + powers +} + +fn ra_eval_plans(program: &'static Stage7CpuProgramPlan) -> Vec { + let mut evals = program + .evals + .iter() + .filter(|eval| { + eval.name + .starts_with("stage7.hamming_weight_claim_reduction.eval.") + }) + .collect::>(); + evals.sort_by_key(|eval| eval.index); + evals + .into_iter() + .map(|eval| Stage7RaOutputPlan { + name: eval.name, + oracle: eval.oracle, + }) + .collect() +} + +fn stage7_virtualization_input_symbol(oracle: &str) -> Result { + if oracle.starts_with("InstructionRa_") { + Ok(format!( + "stage7.input.stage6.instruction_ra_virtual.{oracle}" + )) + } else if oracle.starts_with("BytecodeRa_") { + Ok(format!("stage7.input.stage6.bytecode_read_raf.{oracle}")) + } else if oracle.starts_with("RamRa_") { + Ok(format!("stage7.input.stage6.ram_ra_virtual.{oracle}")) + } else { + Err(Stage7KernelError::InvalidProof { + driver: "stage7.hamming_weight_claim_reduction.oracle", + reason: "unknown RA oracle family", + }) + } +} + +fn eval_by_name( + evals: &[Stage7NamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(Stage7KernelError::MissingValue { symbol: name }) +} + +fn claim_relation( + program: &'static Stage7CpuProgramPlan, + claim: &Stage7SumcheckClaimPlan, +) -> Result { + if let Some(relation) = claim.relation { + return Stage7Relation::from_symbol(relation) + .ok_or(Stage7KernelError::UnknownRelation { relation }); + } + let kernel_symbol = claim.kernel.ok_or(Stage7KernelError::MissingKernel { + driver: claim.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or(Stage7KernelError::MissingKernel { + driver: claim.symbol, + kernel: kernel_symbol, + })?; + kernel.relation_kind() +} + +fn instance_round_offset( + program: &'static Stage7CpuProgramPlan, + driver: &'static str, + claim: &'static str, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.source == driver && instance.claim == claim) + .map(|instance| instance.round_offset) + .ok_or(Stage7KernelError::MissingValue { symbol: claim }) +} + +fn evaluate_stage7_field_expr( + expr: &Stage7FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => single_operand(expr.symbol, operands), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + formula => { + if let Some(exponent) = formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + Stage7KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(Stage7KernelError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }) + } + } +} + +fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +fn single_operand(symbol: &'static str, operands: &[F]) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), Stage7KernelError> { + if expected == actual { + Ok(()) + } else { + Err(Stage7KernelError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +fn combine_univariate_polys( + polynomials: &[UnivariatePoly], + coefficients: &[F], +) -> UnivariatePoly { + let max_len = polynomials + .iter() + .map(|poly| poly.coefficients().len()) + .max() + .unwrap_or(0); + let mut combined = vec![F::zero(); max_len]; + for (poly, &coefficient) in polynomials.iter().zip(coefficients) { + for (combined, &term) in combined.iter_mut().zip(poly.coefficients()) { + *combined += term * coefficient; + } + } + UnivariatePoly::new(combined) +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != F::zero()) + .unwrap_or(0) +} + +fn append_compressed_univariate_poly( + transcript: &mut T, + label: &'static str, + poly: &UnivariatePoly, +) where + F: Field, + T: Transcript, +{ + let compressed = poly.compress(); + transcript.append(&LabelWithCount( + label.as_bytes(), + compressed.coeffs_except_linear_term().len() as u64, + )); + for coefficient in compressed.coeffs_except_linear_term() { + transcript.append(coefficient); + } +} + +fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &F) +where + F: Field, + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +fn append_opening_claims( + program: &'static Stage7CpuProgramPlan, + store: &mut Stage7ValueStore, + transcript: &mut T, + evals: &[Stage7NamedEval], +) -> Result>, Stage7KernelError> +where + F: Field, + T: Transcript, +{ + if program.opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(Vec::new()); + } + let _ = store.evaluate_available_points(program)?; + let mut opening_claims = Vec::new(); + for batch in program.opening_batches { + for symbol in batch.claim_operands { + let claim = + find_opening_claim(program, symbol).ok_or(Stage7KernelError::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + let point = store.point(claim.point_source)?.to_vec(); + let value = store.scalar(claim.eval_source)?; + append_labeled_scalar(transcript, "opening_claim", &value); + opening_claims.push(Stage7OpeningClaimValue { + symbol: claim.symbol, + oracle: claim.oracle, + domain: claim.domain, + claim_kind: claim.claim_kind, + point, + eval: value, + }); + } + } + Ok(opening_claims) +} + +pub fn execute_stage7_program( + program: &'static Stage7CpuProgramPlan, + mode: Stage7ExecutionMode, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + F: Field, + T: Transcript, + E: Stage7KernelExecutor, +{ + let mut artifacts = Stage7ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_squeeze(program, step.symbol).ok_or(Stage7KernelError::MissingValue { + symbol: step.symbol, + })?; + let values = transcript.challenge_vector(squeeze.count); + executor.observe_challenge_vector(squeeze, &values)?; + artifacts.challenge_vectors.push(Stage7ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + "transcript_absorb_bytes" => { + let absorb = find_absorb_bytes(program, step.symbol).ok_or( + Stage7KernelError::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage7_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_driver(program, step.symbol).ok_or(Stage7KernelError::MissingDriver { + driver: step.symbol, + })?; + let kernel_symbol = driver.kernel.ok_or(Stage7KernelError::MissingKernel { + driver: driver.symbol, + kernel: "", + })?; + let kernel = find_kernel(program, kernel_symbol).ok_or( + Stage7KernelError::MissingKernel { + driver: driver.symbol, + kernel: kernel_symbol, + }, + )?; + let batch = + find_batch(program, driver.batch).ok_or(Stage7KernelError::MissingBatch { + driver: driver.symbol, + batch: driver.batch, + })?; + let context = Stage7KernelContext { + mode, + program, + kernel, + batch, + driver, + }; + let output = match mode { + Stage7ExecutionMode::Prover => executor.prove_sumcheck(context, transcript)?, + Stage7ExecutionMode::Verifier => { + executor.verify_sumcheck(context, transcript)? + } + }; + executor.observe_sumcheck_output(&output)?; + artifacts + .opening_claims + .extend(output.opening_claims.clone()); + artifacts.sumchecks.push(output); + } + _ => { + return Err(Stage7KernelError::InvalidProgramStep { + symbol: step.symbol, + kind: step.kind, + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +fn absorb_stage7_bytes(absorb: &'static Stage7TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn find_squeeze( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7TranscriptSqueezePlan> { + program + .transcript_squeezes + .iter() + .find(|squeeze| squeeze.symbol == symbol) +} + +fn find_absorb_bytes( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7TranscriptAbsorbBytesPlan> { + program + .transcript_absorb_bytes + .iter() + .find(|absorb| absorb.symbol == symbol) +} + +fn find_driver( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7SumcheckDriverPlan> { + program + .drivers + .iter() + .find(|driver| driver.symbol == symbol) +} + +fn find_kernel( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7KernelPlan> { + program + .kernels + .iter() + .find(|kernel| kernel.symbol == symbol) +} + +fn find_batch( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7SumcheckBatchPlan> { + program.batches.iter().find(|batch| batch.symbol == symbol) +} + +fn find_opening_claim( + program: &'static Stage7CpuProgramPlan, + symbol: &str, +) -> Option<&'static Stage7OpeningClaimPlan> { + program + .opening_claims + .iter() + .find(|claim| claim.symbol == symbol) +} + +fn reverse_slice(slice: &[F]) -> Vec { + slice.iter().rev().copied().collect() +} + +#[cfg(test)] +#[expect( + clippy::expect_used, + reason = "tests use expect to keep failure context concise" +)] +mod tests { + use super::*; + use jolt_field::Fr; + use jolt_transcript::Blake2bTranscript; + + const PARAMS: Stage7Params = Stage7Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", + }; + const STEPS: &[Stage7ProgramStepPlan] = &[Stage7ProgramStepPlan { + kind: "sumcheck_driver", + symbol: "stage7.sumcheck", + }]; + const FIELD_CONSTANTS: &[Stage7FieldConstantPlan] = &[ + Stage7FieldConstantPlan { + symbol: "stage7.field.one", + field: "bn254_fr", + value: 1, + }, + Stage7FieldConstantPlan { + symbol: "stage7.hamming_weight_claim_reduction.gamma", + field: "bn254_fr", + value: 2, + }, + ]; + const CLAIM_INPUTS: &[&str] = &["stage7.input.claim"]; + const CLAIMS: &[Stage7SumcheckClaimPlan] = &[Stage7SumcheckClaimPlan { + symbol: "stage7.hamming_weight_claim_reduction.input", + stage: "stage7", + domain: "jolt.stage7_hamming_weight_claim_reduction_domain", + num_rounds: 1, + degree: 2, + claim: "stage7.hamming_weight_claim_reduction.weighted_stage6_claims", + kernel: Some("jolt.cpu.stage7.hamming_weight_claim_reduction"), + relation: None, + claim_value: "stage7.input.claim", + input_openings: CLAIM_INPUTS, + }]; + const KERNELS: &[Stage7KernelPlan] = &[ + Stage7KernelPlan { + symbol: "jolt.cpu.stage7.hamming_weight_claim_reduction", + relation: "jolt.stage7.hamming_weight_claim_reduction", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage7_hamming_weight_claim_reduction", + }, + Stage7KernelPlan { + symbol: "jolt.cpu.stage7.batched", + relation: "jolt.stage7.batched", + kind: "sumcheck", + backend: "cpu", + abi: "jolt_stage7_batched", + }, + ]; + const BATCHES: &[Stage7SumcheckBatchPlan] = &[Stage7SumcheckBatchPlan { + symbol: "stage7.batch", + stage: "stage7", + proof_slot: "stage7.sumcheck", + policy: "jolt_core_stage7_aligned", + count: 1, + ordered_claims: &["stage7.hamming_weight_claim_reduction.input"], + claim_operands: &["stage7.hamming_weight_claim_reduction.input"], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + round_schedule: &[1], + }]; + const DRIVERS: &[Stage7SumcheckDriverPlan] = &[Stage7SumcheckDriverPlan { + symbol: "stage7.sumcheck", + stage: "stage7", + proof_slot: "stage7.sumcheck", + kernel: Some("jolt.cpu.stage7.batched"), + relation: Some("jolt.stage7.batched"), + batch: "stage7.batch", + policy: "jolt_core_stage7_aligned", + round_schedule: &[1], + claim_label: "sumcheck_claim", + round_label: "sumcheck_poly", + num_rounds: 1, + degree: 2, + }]; + const INSTANCE_RESULTS: &[Stage7SumcheckInstanceResultPlan] = + &[Stage7SumcheckInstanceResultPlan { + symbol: "stage7.hamming_weight_claim_reduction.instance", + source: "stage7.sumcheck", + claim: "stage7.hamming_weight_claim_reduction.input", + relation: "jolt.stage7.hamming_weight_claim_reduction", + index: 0, + point_arity: 1, + num_rounds: 1, + round_offset: 0, + point_order: "reverse", + degree: 2, + }]; + const EVALS: &[Stage7SumcheckEvalPlan] = &[ + Stage7SumcheckEvalPlan { + symbol: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", + source: "stage7.sumcheck", + name: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", + index: 0, + oracle: "InstructionRa_0", + }, + Stage7SumcheckEvalPlan { + symbol: "stage7.hamming_weight_claim_reduction.eval.RamRa_0", + source: "stage7.sumcheck", + name: "stage7.hamming_weight_claim_reduction.eval.RamRa_0", + index: 1, + oracle: "RamRa_0", + }, + ]; + const OPENING_CLAIMS: &[Stage7OpeningClaimPlan] = &[ + Stage7OpeningClaimPlan { + symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", + oracle: "InstructionRa_0", + domain: "jolt.main_witness_commit_domain", + point_arity: 2, + claim_kind: "committed", + point_source: "stage7.hamming_weight_claim_reduction.point", + eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", + }, + Stage7OpeningClaimPlan { + symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_0", + oracle: "RamRa_0", + domain: "jolt.main_witness_commit_domain", + point_arity: 2, + claim_kind: "committed", + point_source: "stage7.hamming_weight_claim_reduction.point", + eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_0", + }, + ]; + const OPENING_BATCHES: &[Stage7OpeningBatchPlan] = &[Stage7OpeningBatchPlan { + symbol: "stage7.openings", + stage: "stage7", + proof_slot: "stage7.openings", + policy: "jolt_stage7_output_order", + count: 2, + ordered_claims: &[ + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", + "stage7.hamming_weight_claim_reduction.opening.RamRa_0", + ], + claim_operands: &[ + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", + "stage7.hamming_weight_claim_reduction.opening.RamRa_0", + ], + }]; + const POINT_SLICES: &[Stage7PointSlicePlan] = &[Stage7PointSlicePlan { + symbol: "stage7.hamming_weight_claim_reduction.point.cycle", + source: "stage7.input.stage6.booleanity.InstructionRa_0", + offset: 1, + length: 1, + input: "stage7.input.stage6.booleanity.InstructionRa_0", + }]; + const POINT_CONCAT_INPUTS: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.instance", + "stage7.hamming_weight_claim_reduction.point.cycle", + ]; + const POINT_CONCATS: &[Stage7PointConcatPlan] = &[Stage7PointConcatPlan { + symbol: "stage7.hamming_weight_claim_reduction.point", + layout: "address_chunk_then_cycle", + arity: 2, + inputs: POINT_CONCAT_INPUTS, + }]; + const PROGRAM: Stage7CpuProgramPlan = Stage7CpuProgramPlan { + role: "prover", + params: PARAMS, + steps: STEPS, + transcript_squeezes: &[], + transcript_absorb_bytes: &[], + opening_inputs: &[], + field_constants: FIELD_CONSTANTS, + field_exprs: &[], + kernels: KERNELS, + claims: CLAIMS, + batches: BATCHES, + drivers: DRIVERS, + instance_results: INSTANCE_RESULTS, + evals: EVALS, + point_zeros: &[], + point_slices: POINT_SLICES, + point_concats: POINT_CONCATS, + opening_claims: OPENING_CLAIMS, + opening_equalities: &[], + opening_batches: OPENING_BATCHES, + }; + + #[test] + fn hamming_weight_claim_reduction_prover_and_replay_agree() { + let r_bool = Fr::from_u64(5); + let r_cycle = Fr::from_u64(3); + let r_instr_virt = Fr::from_u64(7); + let r_ram_virt = Fr::from_u64(11); + let instruction_ra = vec![ + Fr::from_u64(1), + Fr::from_u64(0), + Fr::from_u64(0), + Fr::from_u64(1), + ]; + let ram_ra = vec![ + Fr::from_u64(0), + Fr::from_u64(0), + Fr::from_u64(1), + Fr::from_u64(0), + ]; + let bool_point = vec![r_bool, r_cycle]; + let instr_virt_point = vec![r_instr_virt, r_cycle]; + let ram_virt_point = vec![r_ram_virt, r_cycle]; + let instr_bool = eval_full_cycle_major(&instruction_ra, &bool_point); + let ram_bool = eval_full_cycle_major(&ram_ra, &bool_point); + let instr_virt = eval_full_cycle_major(&instruction_ra, &instr_virt_point); + let ram_virt = eval_full_cycle_major(&ram_ra, &ram_virt_point); + let ram_hw = r_cycle; + let gamma = Fr::from_u64(2); + let gamma_powers = gamma_powers(gamma, 6); + let input_claim = gamma_powers[0] * Fr::from_u64(1) + + gamma_powers[1] * instr_bool + + gamma_powers[2] * instr_virt + + gamma_powers[3] * ram_hw + + gamma_powers[4] * ram_bool + + gamma_powers[5] * ram_virt; + let openings = vec![ + Stage7OpeningInputValue { + symbol: "stage7.input.claim", + point: Vec::new(), + eval: input_claim, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.hamming_booleanity.HammingWeight", + point: vec![r_cycle], + eval: ram_hw, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.booleanity.InstructionRa_0", + point: bool_point.clone(), + eval: instr_bool, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", + point: instr_virt_point, + eval: instr_virt, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.booleanity.RamRa_0", + point: bool_point, + eval: ram_bool, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_0", + point: ram_virt_point, + eval: ram_virt, + }, + ]; + let instruction_chunks: Vec<&[Fr]> = vec![&instruction_ra]; + let ram_chunks: Vec<&[Fr]> = vec![&ram_ra]; + let inputs = Stage7ProverInputs::new(&openings).with_hamming_weight_claim_reduction( + Stage7HammingWeightClaimReductionWitness { + instruction_ra: Stage7RaChunks { + chunks: &instruction_chunks, + layout: Stage7RaChunkLayout::CycleMajor, + }, + bytecode_ra: Stage7RaChunks { + chunks: &[], + layout: Stage7RaChunkLayout::CycleMajor, + }, + ram_ra: Stage7RaChunks { + chunks: &ram_chunks, + layout: Stage7RaChunkLayout::CycleMajor, + }, + }, + ); + let mut prover = Stage7ProverKernelExecutor::new(inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage7-test"); + let artifacts = execute_stage7_program( + &PROGRAM, + Stage7ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage7 prover succeeds"); + assert_eq!(artifacts.sumchecks.len(), 1); + assert_eq!(artifacts.sumchecks[0].evals.len(), 2); + + let proof = Stage7Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage7ProofCarryingKernelExecutor::new(&proof, &openings); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage7-test"); + let verified = execute_stage7_program( + &PROGRAM, + Stage7ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage7 replay succeeds"); + assert_eq!(verified.sumchecks[0].point, artifacts.sumchecks[0].point); + assert_eq!(verifier_transcript.state(), prover_transcript.state()); + } + + #[test] + fn hamming_weight_claim_reduction_index_witness_matches_dense_witness() { + let r_bool = Fr::from_u64(5); + let r_cycle = Fr::from_u64(3); + let r_instr_virt = Fr::from_u64(7); + let r_ram_virt = Fr::from_u64(11); + let instruction_ra = vec![ + Fr::from_u64(1), + Fr::from_u64(0), + Fr::from_u64(0), + Fr::from_u64(1), + ]; + let ram_ra = vec![ + Fr::from_u64(0), + Fr::from_u64(0), + Fr::from_u64(1), + Fr::from_u64(0), + ]; + let bool_point = vec![r_bool, r_cycle]; + let instr_virt_point = vec![r_instr_virt, r_cycle]; + let ram_virt_point = vec![r_ram_virt, r_cycle]; + let instr_bool = eval_full_cycle_major(&instruction_ra, &bool_point); + let ram_bool = eval_full_cycle_major(&ram_ra, &bool_point); + let instr_virt = eval_full_cycle_major(&instruction_ra, &instr_virt_point); + let ram_virt = eval_full_cycle_major(&ram_ra, &ram_virt_point); + let ram_hw = r_cycle; + let gamma = Fr::from_u64(2); + let gamma_powers = gamma_powers(gamma, 6); + let input_claim = gamma_powers[0] * Fr::from_u64(1) + + gamma_powers[1] * instr_bool + + gamma_powers[2] * instr_virt + + gamma_powers[3] * ram_hw + + gamma_powers[4] * ram_bool + + gamma_powers[5] * ram_virt; + let openings = vec![ + Stage7OpeningInputValue { + symbol: "stage7.input.claim", + point: Vec::new(), + eval: input_claim, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.hamming_booleanity.HammingWeight", + point: vec![r_cycle], + eval: ram_hw, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.booleanity.InstructionRa_0", + point: bool_point.clone(), + eval: instr_bool, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", + point: instr_virt_point, + eval: instr_virt, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.booleanity.RamRa_0", + point: bool_point, + eval: ram_bool, + }, + Stage7OpeningInputValue { + symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_0", + point: ram_virt_point, + eval: ram_virt, + }, + ]; + let instruction_indices = vec![Some(0), Some(1)]; + let ram_indices = vec![None, Some(0)]; + let instruction_chunks: Vec<&[Option]> = vec![&instruction_indices]; + let ram_chunks: Vec<&[Option]> = vec![&ram_indices]; + let inputs = Stage7ProverInputs::new(&openings) + .with_hamming_weight_claim_reduction_indices( + Stage7HammingWeightClaimReductionIndexWitness { + instruction_ra: Stage7RaIndexChunks { + chunks: &instruction_chunks, + }, + bytecode_ra: Stage7RaIndexChunks { chunks: &[] }, + ram_ra: Stage7RaIndexChunks { + chunks: &ram_chunks, + }, + }, + ); + let mut prover = Stage7ProverKernelExecutor::new(inputs); + let mut prover_transcript = Blake2bTranscript::::new(b"stage7-test"); + let artifacts = execute_stage7_program( + &PROGRAM, + Stage7ExecutionMode::Prover, + &mut prover, + &mut prover_transcript, + ) + .expect("stage7 index prover succeeds"); + assert_eq!(artifacts.sumchecks.len(), 1); + + let proof = Stage7Proof { + sumchecks: artifacts.sumchecks.clone(), + }; + let mut verifier = Stage7ProofCarryingKernelExecutor::new(&proof, &openings); + let mut verifier_transcript = Blake2bTranscript::::new(b"stage7-test"); + let verified = execute_stage7_program( + &PROGRAM, + Stage7ExecutionMode::Verifier, + &mut verifier, + &mut verifier_transcript, + ) + .expect("stage7 index replay succeeds"); + assert_eq!(verified.sumchecks[0].point, artifacts.sumchecks[0].point); + assert_eq!(verifier_transcript.state(), prover_transcript.state()); + } + + fn eval_full_cycle_major(evals: &[Fr], point: &[Fr]) -> Fr { + let address = EqPolynomial::::evals(&point[..1], None); + let cycle = EqPolynomial::::evals(&point[1..], None); + let mut value = Fr::from_u64(0); + for cycle_index in 0..2 { + for address_index in 0..2 { + value += evals[cycle_index * 2 + address_index] + * cycle[cycle_index] + * address[address_index]; + } + } + value + } +} diff --git a/crates/jolt-kernels/src/trace.rs b/crates/jolt-kernels/src/trace.rs new file mode 100644 index 0000000000..5def4169a2 --- /dev/null +++ b/crates/jolt-kernels/src/trace.rs @@ -0,0 +1,605 @@ +//! Trace-to-kernel witness views for Bolt-generated Jolt stages. + +use jolt_field::signed::{S128, S64}; +use jolt_field::Field; +use jolt_program::{ + execution::{RamAccess, TraceRow}, + preprocess::BytecodePreprocessing, +}; +use jolt_riscv::{ + CircuitFlagSet, CircuitFlags, Flags, InstructionFlagSet, InstructionFlags, + InterleavedBitsMarker, JoltInstructionKind, LookupInstruction, NormalizedInstruction, + NUM_CIRCUIT_FLAGS, +}; +use jolt_witness::Stage6BytecodeEntry; + +use crate::stage1::Stage1Rv64Cycle; +use crate::stage2::{Stage2InstructionLookupCycle, Stage2ProductVirtualCycle, Stage2RamAccess}; +use crate::stage3::Stage3Cycle; +use crate::stage4::{Stage4RegisterAccess, Stage4RegisterRead, Stage4RegisterWrite}; + +pub trait CycleRow: Copy { + fn is_noop(&self) -> bool; + fn instruction(&self) -> NormalizedInstruction; + fn unexpanded_pc(&self) -> u64; + fn rs1_read(&self) -> Option<(u8, u64)>; + fn rs2_read(&self) -> Option<(u8, u64)>; + fn rd_write(&self) -> Option<(u8, u64, u64)>; + fn ram_access_address(&self) -> Option; + fn ram_read_value(&self) -> Option; + fn ram_write_value(&self) -> Option; + fn imm(&self) -> i128; + fn circuit_flags(&self) -> CircuitFlagSet; + fn instruction_flags(&self) -> InstructionFlagSet; + fn lookup_index(&self) -> u128; + fn lookup_output(&self) -> u64; +} + +impl CycleRow for TraceRow { + fn is_noop(&self) -> bool { + self.instruction_flags()[InstructionFlags::IsNoop] + } + + fn instruction(&self) -> NormalizedInstruction { + self.instruction + } + + fn unexpanded_pc(&self) -> u64 { + if self.is_noop() { + 0 + } else { + self.instruction.address as u64 + } + } + + fn rs1_read(&self) -> Option<(u8, u64)> { + self.registers.rs1.map(|read| (read.register, read.value)) + } + + fn rs2_read(&self) -> Option<(u8, u64)> { + self.registers.rs2.map(|read| (read.register, read.value)) + } + + fn rd_write(&self) -> Option<(u8, u64, u64)> { + self.registers + .rd + .map(|write| (write.register, write.pre_value, write.post_value)) + } + + fn ram_access_address(&self) -> Option { + match self.ram_access { + RamAccess::Read(read) => Some(read.address), + RamAccess::Write(write) => Some(write.address), + RamAccess::NoOp => None, + } + } + + fn ram_read_value(&self) -> Option { + match self.ram_access { + RamAccess::Read(read) => Some(read.value), + RamAccess::Write(write) => Some(write.pre_value), + RamAccess::NoOp => None, + } + } + + fn ram_write_value(&self) -> Option { + match self.ram_access { + RamAccess::Read(read) => Some(read.value), + RamAccess::Write(write) => Some(write.post_value), + RamAccess::NoOp => None, + } + } + + fn imm(&self) -> i128 { + if self.is_noop() { + 0 + } else { + self.instruction.operands.imm + } + } + + fn circuit_flags(&self) -> CircuitFlagSet { + instruction_circuit_flags(&self.instruction) + } + + fn instruction_flags(&self) -> InstructionFlagSet { + instruction_instruction_flags(&self.instruction) + } + + fn lookup_index(&self) -> u128 { + let cflags = self.circuit_flags(); + let iflags = self.instruction_flags(); + let (left, right) = instruction_inputs_with_flags(self, iflags); + + if cflags[CircuitFlags::AddOperands] { + (left as u128).wrapping_add(right) + } else if cflags[CircuitFlags::SubtractOperands] { + (1u128 << 64).wrapping_sub(right).wrapping_add(left as u128) + } else if cflags[CircuitFlags::MultiplyOperands] { + (left as u128).wrapping_mul(right) + } else if cflags[CircuitFlags::Advice] { + self.rd_write().map_or(0, |(_, _, post)| post as u128) + } else if self.is_noop() { + 0 + } else { + interleave_bits(left, right as u64) + } + } + + fn lookup_output(&self) -> u64 { + if self.is_noop() { + return 0; + } + let cflags = self.circuit_flags(); + let iflags = self.instruction_flags(); + + if cflags[CircuitFlags::Jump] { + let left = if iflags[InstructionFlags::LeftOperandIsPC] { + self.unexpanded_pc() + } else { + self.rs1_read().map_or(0, |(_, value)| value) + }; + let target = (left as i64).wrapping_add(self.imm() as i64) as u64; + if iflags[InstructionFlags::LeftOperandIsRs1Value] { + target & !1 + } else { + target + } + } else if cflags[CircuitFlags::Assert] { + 1 + } else if iflags[InstructionFlags::Branch] { + let rs1 = self.rs1_read().map_or(0, |(_, value)| value); + let rs2 = self.rs2_read().map_or(0, |(_, value)| value); + branch_result(self.instruction.instruction_kind, rs1, rs2) + } else if cflags[CircuitFlags::WriteLookupOutputToRD] { + self.rd_write().map_or(0, |(_, _, post)| post) + } else { + 0 + } + } +} + +pub fn stage1_rv64_cycles( + trace: &[C], + size: usize, + bytecode: &BytecodePreprocessing, +) -> Vec { + (0..size) + .map(|cycle| stage1_rv64_cycle(trace, cycle, bytecode)) + .collect() +} + +pub fn stage2_product_virtual_cycles( + trace: &[C], + size: usize, +) -> Vec { + (0..size) + .map(|index| stage2_product_virtual_cycle(trace, index)) + .collect() +} + +pub fn stage2_instruction_lookup_cycles( + trace: &[C], + size: usize, +) -> Vec { + (0..size) + .map(|index| stage2_instruction_lookup_cycle(trace.get(index).copied())) + .collect() +} + +pub fn stage2_ram_accesses( + trace: &[C], + size: usize, + mut remap_address: R, +) -> Vec +where + C: CycleRow, + R: FnMut(u64) -> Option, +{ + (0..size) + .map(|index| { + let Some(cycle) = trace.get(index) else { + return Stage2RamAccess::noop(); + }; + let Some(address) = cycle.ram_access_address() else { + return Stage2RamAccess::noop(); + }; + Stage2RamAccess { + remapped_address: remap_address(address), + read_value: cycle.ram_read_value().unwrap_or(0), + write_value: cycle.ram_write_value().unwrap_or(0), + } + }) + .collect() +} + +pub fn stage3_cycles( + trace: &[C], + size: usize, + bytecode: &BytecodePreprocessing, +) -> Vec { + (0..size) + .map(|cycle| stage3_cycle(trace.get(cycle).copied(), bytecode)) + .collect() +} + +pub fn stage4_register_accesses( + trace: &[C], + size: usize, +) -> Vec { + (0..size) + .map(|cycle| stage4_register_access(trace.get(cycle).copied())) + .collect() +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Stage5LookupTrace { + pub lookup_indices: Vec, + pub lookup_table_indices: Vec>, + pub is_interleaved_operands: Vec, +} + +pub fn stage5_lookup_trace( + trace: &[C], + size: usize, + mut lookup_table_index: L, +) -> Stage5LookupTrace +where + C: CycleRow, + L: FnMut(&C) -> Option, +{ + let mut lookup_indices = Vec::with_capacity(size); + let mut lookup_table_indices = Vec::with_capacity(size); + let mut is_interleaved_operands = Vec::with_capacity(size); + for index in 0..size { + let Some(cycle) = trace.get(index) else { + lookup_indices.push(0); + lookup_table_indices.push(None); + is_interleaved_operands.push(false); + continue; + }; + lookup_indices.push(cycle.lookup_index()); + lookup_table_indices.push(lookup_table_index(cycle)); + is_interleaved_operands.push(cycle.circuit_flags().is_interleaved_operands()); + } + Stage5LookupTrace { + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + } +} + +pub fn stage6_bytecode_entries( + bytecode: &BytecodePreprocessing, + mut lookup_table_index: L, +) -> Vec> +where + F: Field, + L: FnMut(&NormalizedInstruction) -> Option, +{ + bytecode + .bytecode + .iter() + .map(|instruction| { + let instr = *instruction; + let circuit_flags = instruction_circuit_flags(instruction); + let instruction_flags = instruction_instruction_flags(instruction); + Stage6BytecodeEntry { + address: F::from_u64(instr.address as u64), + imm: F::from_i128(instr.operands.imm), + circuit_flags: stage6_circuit_flags(circuit_flags), + rd: instr.operands.rd.map(usize::from), + rs1: instr.operands.rs1.map(usize::from), + rs2: instr.operands.rs2.map(usize::from), + lookup_table: lookup_table_index(instruction), + is_interleaved: circuit_flags.is_interleaved_operands(), + is_branch: instruction_flags[InstructionFlags::Branch], + left_is_rs1: instruction_flags[InstructionFlags::LeftOperandIsRs1Value], + left_is_pc: instruction_flags[InstructionFlags::LeftOperandIsPC], + right_is_rs2: instruction_flags[InstructionFlags::RightOperandIsRs2Value], + right_is_imm: instruction_flags[InstructionFlags::RightOperandIsImm], + is_noop: instruction_flags[InstructionFlags::IsNoop], + } + }) + .collect() +} + +fn stage2_product_virtual_cycle( + trace: &[C], + index: usize, +) -> Stage2ProductVirtualCycle { + let Some(cycle) = trace.get(index) else { + return Stage2ProductVirtualCycle::padding(); + }; + let (instruction_left_input, instruction_right_input) = instruction_inputs(cycle); + let flags = cycle.circuit_flags(); + let instruction_flags = cycle.instruction_flags(); + let not_next_noop = trace.get(index + 1).is_some_and(|next| !next.is_noop()); + Stage2ProductVirtualCycle { + instruction_left_input, + instruction_right_input, + should_branch_lookup_output: cycle.lookup_output(), + write_lookup_output_to_rd_flag: flags[CircuitFlags::WriteLookupOutputToRD], + jump_flag: flags[CircuitFlags::Jump], + should_branch_flag: instruction_flags[InstructionFlags::Branch], + not_next_noop, + virtual_instruction_flag: flags[CircuitFlags::VirtualInstruction], + } +} + +fn stage2_instruction_lookup_cycle(cycle: Option) -> Stage2InstructionLookupCycle { + let Some(cycle) = cycle else { + return Stage2InstructionLookupCycle::padding(); + }; + let (left_instruction_input, right_instruction_input) = instruction_inputs(&cycle); + let product = instruction_product(left_instruction_input, right_instruction_input); + let (left_lookup_operand, right_lookup_operand) = lookup_operands_raw( + left_instruction_input, + right_instruction_input, + product, + cycle.circuit_flags(), + cycle.lookup_output(), + ); + Stage2InstructionLookupCycle { + lookup_output: cycle.lookup_output(), + left_lookup_operand, + right_lookup_operand, + left_instruction_input, + right_instruction_input, + } +} + +fn stage4_register_access(cycle: Option) -> Stage4RegisterAccess { + let Some(cycle) = cycle else { + return Stage4RegisterAccess::default(); + }; + Stage4RegisterAccess { + rs1: cycle.rs1_read().map(|(address, value)| Stage4RegisterRead { + address: address as usize, + value, + }), + rs2: cycle.rs2_read().map(|(address, value)| Stage4RegisterRead { + address: address as usize, + value, + }), + rd: cycle + .rd_write() + .map(|(address, pre_value, post_value)| Stage4RegisterWrite { + address: address as usize, + pre_value, + post_value, + }), + } +} + +fn stage3_cycle(cycle: Option, bytecode: &BytecodePreprocessing) -> Stage3Cycle { + let Some(cycle) = cycle else { + return Stage3Cycle::padding(); + }; + let circuit_flags = cycle.circuit_flags(); + let instruction_flags = cycle.instruction_flags(); + Stage3Cycle { + unexpanded_pc: cycle.unexpanded_pc(), + pc: bytecode_pc(bytecode, &cycle.instruction()) as u64, + is_virtual: circuit_flags[CircuitFlags::VirtualInstruction], + is_first_in_sequence: circuit_flags[CircuitFlags::IsFirstInSequence], + is_noop: instruction_flags[InstructionFlags::IsNoop], + left_operand_is_rs1: instruction_flags[InstructionFlags::LeftOperandIsRs1Value], + rs1_value: cycle.rs1_read().map_or(0, |(_, value)| value), + left_operand_is_pc: instruction_flags[InstructionFlags::LeftOperandIsPC], + right_operand_is_rs2: instruction_flags[InstructionFlags::RightOperandIsRs2Value], + rs2_value: cycle.rs2_read().map_or(0, |(_, value)| value), + right_operand_is_imm: instruction_flags[InstructionFlags::RightOperandIsImm], + imm: cycle.imm(), + rd_write_value: cycle.rd_write().map_or(0, |(_, _, post)| post), + } +} + +fn stage1_rv64_cycle( + trace: &[C], + cycle_index: usize, + bytecode: &BytecodePreprocessing, +) -> Stage1Rv64Cycle { + let Some(cycle) = trace.get(cycle_index) else { + return Stage1Rv64Cycle::padding(); + }; + let next = trace.get(cycle_index + 1); + if cycle.is_noop() { + let mut row = Stage1Rv64Cycle::padding(); + fill_next_rv64_fields(&mut row, next, bytecode); + return row; + } + + let flags_set = cycle.circuit_flags(); + let instruction_flags = cycle.instruction_flags(); + let (left_input, right_i128) = instruction_inputs(cycle); + let right_input = s64_from_i128(right_i128); + let product = instruction_product(left_input, right_i128); + let lookup_output = cycle.lookup_output(); + let (left_lookup, right_lookup) = + lookup_operands_raw(left_input, right_i128, product, flags_set, lookup_output); + let next_is_noop = next.is_none_or(CycleRow::is_noop); + let flags = stage1_rv64_flags(flags_set); + + let mut row = Stage1Rv64Cycle { + left_input, + right_input, + product, + left_lookup, + right_lookup, + lookup_output, + rs1_read_value: cycle.rs1_read().map_or(0, |(_, value)| value), + rs2_read_value: cycle.rs2_read().map_or(0, |(_, value)| value), + rd_write_value: cycle.rd_write().map_or(0, |(_, _, post)| post), + ram_addr: cycle.ram_access_address().unwrap_or(0), + ram_read_value: cycle.ram_read_value().unwrap_or(0), + ram_write_value: cycle.ram_write_value().unwrap_or(0), + pc: bytecode_pc(bytecode, &cycle.instruction()) as u64, + next_pc: 0, + unexpanded_pc: cycle.unexpanded_pc(), + next_unexpanded_pc: 0, + imm: s64_from_i128(cycle.imm()), + flags, + should_jump: flags_set[CircuitFlags::Jump] && !next_is_noop, + should_branch: instruction_flags[InstructionFlags::Branch] && lookup_output == 1, + next_is_virtual: false, + next_is_first_in_sequence: false, + }; + fill_next_rv64_fields(&mut row, next, bytecode); + row +} + +fn fill_next_rv64_fields( + row: &mut Stage1Rv64Cycle, + next: Option<&C>, + bytecode: &BytecodePreprocessing, +) { + if let Some(next_cycle) = next { + row.next_pc = bytecode_pc(bytecode, &next_cycle.instruction()) as u64; + row.next_unexpanded_pc = next_cycle.unexpanded_pc(); + let next_flags = next_cycle.circuit_flags(); + row.next_is_virtual = next_flags[CircuitFlags::VirtualInstruction]; + row.next_is_first_in_sequence = next_flags[CircuitFlags::IsFirstInSequence]; + } +} + +fn instruction_inputs(cycle: &impl CycleRow) -> (u64, i128) { + let instruction_flags = cycle.instruction_flags(); + instruction_inputs_i128_with_flags(cycle, instruction_flags) +} + +fn instruction_inputs_i128_with_flags( + cycle: &impl CycleRow, + instruction_flags: InstructionFlagSet, +) -> (u64, i128) { + let left_input = if instruction_flags[InstructionFlags::LeftOperandIsPC] { + cycle.unexpanded_pc() + } else if instruction_flags[InstructionFlags::LeftOperandIsRs1Value] { + cycle.rs1_read().map_or(0, |(_, value)| value) + } else { + 0 + }; + let right_input = if instruction_flags[InstructionFlags::RightOperandIsImm] { + cycle.imm() + } else if instruction_flags[InstructionFlags::RightOperandIsRs2Value] { + cycle.rs2_read().map_or(0, |(_, value)| value as i128) + } else { + 0 + }; + (left_input, right_input) +} + +fn instruction_inputs_with_flags( + cycle: &impl CycleRow, + instruction_flags: InstructionFlagSet, +) -> (u64, u128) { + let (left, right) = instruction_inputs_i128_with_flags(cycle, instruction_flags); + (left, right as u64 as u128) +} + +fn instruction_circuit_flags(instruction: &NormalizedInstruction) -> CircuitFlagSet { + lookup_instruction(instruction).map_or_else(CircuitFlagSet::default, |instruction| { + instruction.circuit_flags() + }) +} + +fn instruction_instruction_flags(instruction: &NormalizedInstruction) -> InstructionFlagSet { + lookup_instruction(instruction).map_or_else(InstructionFlagSet::default, |instruction| { + instruction.instruction_flags() + }) +} + +fn lookup_instruction(instruction: &NormalizedInstruction) -> Option { + LookupInstruction::try_from(*instruction).ok() +} + +fn bytecode_pc(bytecode: &BytecodePreprocessing, instruction: &NormalizedInstruction) -> usize { + bytecode.get_pc(instruction).unwrap_or(0) +} + +fn instruction_product(left: u64, right: i128) -> S128 { + S64::from_u64(left).mul_trunc::<2, 2>(&S128::from_i128(right)) +} + +fn stage1_rv64_flags(flags: CircuitFlagSet) -> [bool; NUM_CIRCUIT_FLAGS] { + [ + flags[CircuitFlags::AddOperands], + flags[CircuitFlags::SubtractOperands], + flags[CircuitFlags::MultiplyOperands], + flags[CircuitFlags::Load], + flags[CircuitFlags::Store], + flags[CircuitFlags::Jump], + flags[CircuitFlags::WriteLookupOutputToRD], + flags[CircuitFlags::VirtualInstruction], + flags[CircuitFlags::Assert], + flags[CircuitFlags::DoNotUpdateUnexpandedPC], + flags[CircuitFlags::Advice], + flags[CircuitFlags::IsCompressed], + flags[CircuitFlags::IsFirstInSequence], + flags[CircuitFlags::IsLastInSequence], + ] +} + +fn stage6_circuit_flags(flags: CircuitFlagSet) -> [bool; NUM_CIRCUIT_FLAGS] { + stage1_rv64_flags(flags) +} + +fn s64_from_i128(value: i128) -> S64 { + let magnitude = value.unsigned_abs(); + assert!(magnitude <= u64::MAX as u128, "S64 input overflow"); + S64::from_u64_with_sign(magnitude as u64, value >= 0) +} + +fn lookup_operands_raw( + left: u64, + right: i128, + product: S128, + flags: CircuitFlagSet, + lookup_output: u64, +) -> (u64, u128) { + if flags[CircuitFlags::AddOperands] { + (0, (left as i128 + right) as u128) + } else if flags[CircuitFlags::SubtractOperands] { + (0, (left as i128 - right + (1i128 << 64)) as u128) + } else if flags[CircuitFlags::MultiplyOperands] { + (0, product.magnitude_as_u128()) + } else if flags[CircuitFlags::Advice] { + (0, lookup_output as u128) + } else { + (left, right as u128) + } +} + +#[inline] +fn interleave_bits(x: u64, y: u64) -> u128 { + let mut x_bits = x as u128; + x_bits = (x_bits | (x_bits << 32)) & 0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF; + x_bits = (x_bits | (x_bits << 16)) & 0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF; + x_bits = (x_bits | (x_bits << 8)) & 0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF; + x_bits = (x_bits | (x_bits << 4)) & 0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F; + x_bits = (x_bits | (x_bits << 2)) & 0x3333_3333_3333_3333_3333_3333_3333_3333; + x_bits = (x_bits | (x_bits << 1)) & 0x5555_5555_5555_5555_5555_5555_5555_5555; + + let mut y_bits = y as u128; + y_bits = (y_bits | (y_bits << 32)) & 0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF; + y_bits = (y_bits | (y_bits << 16)) & 0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF; + y_bits = (y_bits | (y_bits << 8)) & 0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF; + y_bits = (y_bits | (y_bits << 4)) & 0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F; + y_bits = (y_bits | (y_bits << 2)) & 0x3333_3333_3333_3333_3333_3333_3333_3333; + y_bits = (y_bits | (y_bits << 1)) & 0x5555_5555_5555_5555_5555_5555_5555_5555; + + (x_bits << 1) | y_bits +} + +fn branch_result(kind: JoltInstructionKind, rs1: u64, rs2: u64) -> u64 { + let taken = match kind { + JoltInstructionKind::BEQ => rs1 == rs2, + JoltInstructionKind::BNE => rs1 != rs2, + JoltInstructionKind::BLT => (rs1 as i64) < (rs2 as i64), + JoltInstructionKind::BGE => (rs1 as i64) >= (rs2 as i64), + JoltInstructionKind::BLTU => rs1 < rs2, + JoltInstructionKind::BGEU => rs1 >= rs2, + _ => false, + }; + taken as u64 +} diff --git a/crates/jolt-lookup-tables/src/tables/mod.rs b/crates/jolt-lookup-tables/src/tables/mod.rs index d6b629cac9..f50d764341 100644 --- a/crates/jolt-lookup-tables/src/tables/mod.rs +++ b/crates/jolt-lookup-tables/src/tables/mod.rs @@ -197,6 +197,53 @@ macro_rules! dispatch { } impl LookupTableKind { + /// Returns the canonical modular Jolt lookup table list. + pub fn all() -> [Self; 41] { + [ + Self::RangeCheck(Default::default()), + Self::RangeCheckAligned(Default::default()), + Self::And(Default::default()), + Self::Andn(Default::default()), + Self::Or(Default::default()), + Self::Xor(Default::default()), + Self::Equal(Default::default()), + Self::NotEqual(Default::default()), + Self::SignedLessThan(Default::default()), + Self::UnsignedLessThan(Default::default()), + Self::SignedGreaterThanEqual(Default::default()), + Self::UnsignedGreaterThanEqual(Default::default()), + Self::UnsignedLessThanEqual(Default::default()), + Self::UpperWord(Default::default()), + Self::LowerHalfWord(Default::default()), + Self::SignExtendHalfWord(Default::default()), + Self::SignMask(Default::default()), + Self::Pow2(Default::default()), + Self::Pow2W(Default::default()), + Self::ShiftRightBitmask(Default::default()), + Self::VirtualSRL(Default::default()), + Self::VirtualSRA(Default::default()), + Self::VirtualROTR(Default::default()), + Self::VirtualROTRW(Default::default()), + Self::ValidDiv0(Default::default()), + Self::ValidUnsignedRemainder(Default::default()), + Self::ValidSignedRemainder(Default::default()), + Self::VirtualChangeDivisor(Default::default()), + Self::VirtualChangeDivisorW(Default::default()), + Self::HalfwordAlignment(Default::default()), + Self::WordAlignment(Default::default()), + Self::MulUNoOverflow(Default::default()), + Self::VirtualRev8W(Default::default()), + Self::VirtualXORROT32(Default::default()), + Self::VirtualXORROT24(Default::default()), + Self::VirtualXORROT16(Default::default()), + Self::VirtualXORROT63(Default::default()), + Self::VirtualXORROTW16(Default::default()), + Self::VirtualXORROTW12(Default::default()), + Self::VirtualXORROTW8(Default::default()), + Self::VirtualXORROTW7(Default::default()), + ] + } + /// Returns the discriminant as a `usize`, suitable for array indexing. #[inline] pub fn index(&self) -> usize { diff --git a/crates/jolt-lookup-tables/src/tables/prefixes/mod.rs b/crates/jolt-lookup-tables/src/tables/prefixes/mod.rs index d3943afb9c..302ea13677 100644 --- a/crates/jolt-lookup-tables/src/tables/prefixes/mod.rs +++ b/crates/jolt-lookup-tables/src/tables/prefixes/mod.rs @@ -88,6 +88,12 @@ impl From for PrefixEval { } } +impl PrefixEval { + pub fn into_inner(self) -> F { + self.0 + } +} + impl Index for &[PrefixEval] { type Output = F; diff --git a/crates/jolt-openings/src/mock.rs b/crates/jolt-openings/src/mock.rs index 8ff531493c..0c57a5a9d5 100644 --- a/crates/jolt-openings/src/mock.rs +++ b/crates/jolt-openings/src/mock.rs @@ -210,7 +210,7 @@ impl ZkOpeningScheme for MockCommitmentScheme { mod tests { use super::*; use crate::{reduce_prover, reduce_verifier, ProverClaim, VerifierClaim}; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use jolt_poly::Polynomial; use jolt_transcript::Blake2bTranscript; use rand_chacha::rand_core::SeedableRng; diff --git a/crates/jolt-openings/src/reduction.rs b/crates/jolt-openings/src/reduction.rs index 9cd5402312..60f62fa5c2 100644 --- a/crates/jolt-openings/src/reduction.rs +++ b/crates/jolt-openings/src/reduction.rs @@ -168,7 +168,7 @@ fn group_verifier_claims_by_point( #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use jolt_poly::Polynomial; #[test] diff --git a/crates/jolt-poly/src/compressed_univariate.rs b/crates/jolt-poly/src/compressed_univariate.rs index e013789f29..ff0c4e5b83 100644 --- a/crates/jolt-poly/src/compressed_univariate.rs +++ b/crates/jolt-poly/src/compressed_univariate.rs @@ -95,7 +95,7 @@ impl CompressedPoly { #[expect(clippy::unwrap_used)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; use num_traits::{One, Zero}; /// Helper: build a standard polynomial p(x) = c0 + c1*x + c2*x^2 + ... diff --git a/crates/jolt-poly/src/dense.rs b/crates/jolt-poly/src/dense.rs index 749f65dee8..b1cdfc4810 100644 --- a/crates/jolt-poly/src/dense.rs +++ b/crates/jolt-poly/src/dense.rs @@ -575,7 +575,7 @@ impl Neg for Polynomial { mod tests { use super::*; use jolt_field::Fr; - use jolt_field::{FromPrimitiveInt, RandomSampling}; + use jolt_field::RandomSampling; use num_traits::{One, Zero}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/eq.rs b/crates/jolt-poly/src/eq.rs index 94dfcf44b3..206daec033 100644 --- a/crates/jolt-poly/src/eq.rs +++ b/crates/jolt-poly/src/eq.rs @@ -348,7 +348,7 @@ impl crate::MultilinearEvaluation for EqPolynomial { mod tests { use super::*; use jolt_field::Fr; - use jolt_field::{FromPrimitiveInt, RandomSampling}; + use jolt_field::RandomSampling; use num_traits::{One, Zero}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/eq_plus_one.rs b/crates/jolt-poly/src/eq_plus_one.rs index e05cb69ded..371486d1fc 100644 --- a/crates/jolt-poly/src/eq_plus_one.rs +++ b/crates/jolt-poly/src/eq_plus_one.rs @@ -170,7 +170,7 @@ impl EqPlusOnePrefixSuffix { #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use num_traits::{One, Zero}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/expanding_table.rs b/crates/jolt-poly/src/expanding_table.rs index 1f48734d4f..42131ddaba 100644 --- a/crates/jolt-poly/src/expanding_table.rs +++ b/crates/jolt-poly/src/expanding_table.rs @@ -159,7 +159,7 @@ fn join_or_serial(left: impl FnOnce() -> A, right: impl FnOnce() -> B) -> mod tests { use super::*; use crate::EqPolynomial; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use num_traits::One; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/identity.rs b/crates/jolt-poly/src/identity.rs index 2cc61284b5..e2df04a5a1 100644 --- a/crates/jolt-poly/src/identity.rs +++ b/crates/jolt-poly/src/identity.rs @@ -60,7 +60,6 @@ impl crate::MultilinearEvaluation for IdentityPolynomial { mod tests { use super::*; use jolt_field::Fr; - use jolt_field::FromPrimitiveInt; use num_traits::{One, Zero}; #[test] diff --git a/crates/jolt-poly/src/lagrange.rs b/crates/jolt-poly/src/lagrange.rs index 485e0742f8..6a21a18cfe 100644 --- a/crates/jolt-poly/src/lagrange.rs +++ b/crates/jolt-poly/src/lagrange.rs @@ -61,6 +61,35 @@ pub fn lagrange_evals(domain_start: i64, domain_size: usize, r: F) -> result } +/// Evaluates the `k`-th Lagrange basis polynomial over a consecutive integer domain. +#[expect(clippy::expect_used)] +pub fn lagrange_basis_eval(domain_start: i64, domain_size: usize, k: usize, r: F) -> F { + let mut numerator = F::one(); + let mut denominator = F::one(); + for j in 0..domain_size { + if j == k { + continue; + } + numerator *= r - F::from_i64(domain_start + j as i64); + denominator *= F::from_i128(k as i128 - j as i128); + } + numerator + * denominator + .inverse() + .expect("Lagrange basis denominator must be invertible") +} + +/// Evaluates `sum_k L_k(tau) * L_k(r)` over a consecutive integer domain. +pub fn lagrange_kernel_eval(domain_start: i64, domain_size: usize, tau: F, r: F) -> F { + let tau_evals = lagrange_evals(domain_start, domain_size, tau); + let r_evals = lagrange_evals(domain_start, domain_size, r); + tau_evals + .iter() + .zip(r_evals.iter()) + .map(|(&a, &b)| a * b) + .fold(F::zero(), |acc, value| acc + value) +} + /// Computes power sums $S_k = \sum_{t=-D}^{D} t^k$ for $k = 0, 1, \ldots, \text{num\_powers}-1$ /// over the symmetric integer domain $\{-D, \ldots, D\}$ of size $2D+1$. /// @@ -157,7 +186,7 @@ pub fn interpolate_to_coeffs(domain_start: i64, values: &[F]) -> Vec(v: &mut Vec, challenge: F) { #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use num_traits::{One, Zero}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/split_eq.rs b/crates/jolt-poly/src/split_eq.rs index 7b256a7ee1..42a2c0b441 100644 --- a/crates/jolt-poly/src/split_eq.rs +++ b/crates/jolt-poly/src/split_eq.rs @@ -361,7 +361,7 @@ fn join_or_serial(left: impl FnOnce() -> A, right: impl FnOnce() -> B) -> mod tests { use super::*; use crate::math::Math; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use num_traits::{One, Zero}; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; diff --git a/crates/jolt-poly/src/univariate.rs b/crates/jolt-poly/src/univariate.rs index 47cc890e80..aedc76b0ab 100644 --- a/crates/jolt-poly/src/univariate.rs +++ b/crates/jolt-poly/src/univariate.rs @@ -544,7 +544,6 @@ fn gaussian_elimination_augmented(matrix: &mut [Vec]) -> Vec { mod tests { use super::*; use jolt_field::Fr; - use jolt_field::FromPrimitiveInt; use num_traits::{One, Zero}; #[test] diff --git a/crates/jolt-poly/tests/integration.rs b/crates/jolt-poly/tests/integration.rs index 5ffa348a39..91bd86ef0e 100644 --- a/crates/jolt-poly/tests/integration.rs +++ b/crates/jolt-poly/tests/integration.rs @@ -5,7 +5,7 @@ //! (Polynomial, EqPolynomial, UnivariatePoly, IdentityPolynomial, RlcSource) //! that are used throughout the proving system. -use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; +use jolt_field::{Fr, RandomSampling}; use jolt_poly::{ EqPolynomial, IdentityPolynomial, MultilinearPoly, Polynomial, RlcSource, UnivariatePoly, }; diff --git a/crates/jolt-prover/Cargo.toml b/crates/jolt-prover/Cargo.toml new file mode 100644 index 0000000000..c323cdb4c2 --- /dev/null +++ b/crates/jolt-prover/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "jolt-prover" +version = "0.0.0" +edition = "2021" +license = "MIT OR Apache-2.0" +description = "Bolt-generated Jolt prover role crate" +repository = "https://github.com/a16z/jolt" + +[lints] +workspace = true + +[dependencies] +jolt-dory.workspace = true +jolt-field.workspace = true +jolt-kernels.workspace = true +jolt-openings.workspace = true +jolt-poly.workspace = true +jolt-transcript.workspace = true +jolt-verifier.workspace = true +jolt-witness.workspace = true +rayon.workspace = true +tracing.workspace = true diff --git a/crates/jolt-prover/src/lib.rs b/crates/jolt-prover/src/lib.rs new file mode 100644 index 0000000000..a6ced62faa --- /dev/null +++ b/crates/jolt-prover/src/lib.rs @@ -0,0 +1,100 @@ +#[rustfmt::skip] +pub mod prover; +pub mod stages; + +pub use prover::{ + default_prover_programs, jolt_proof_through_stage5, jolt_proof_through_stage6, + jolt_proof_through_stage7, prove_jolt, prove_jolt_evaluation_proof, prove_jolt_with_programs, + prove_jolt_with_stage_inputs, prove_jolt_with_witness_inputs, + prove_stage1_outer_inputs_with_program, prove_stage2_inputs_with_program, + prove_stage3_inputs_with_program, prove_stage4_inputs_with_program, + prove_stage5_inputs_with_program, prove_stage6_inputs_with_program, + prove_stage7_inputs_with_program, replay_stage1_outer_proof_with_program, + replay_stage2_proof_with_program, replay_stage3_proof_with_program, + replay_stage4_proof_with_program, replay_stage5_proof_with_program, + replay_stage6_proof_with_program, replay_stage7_proof_with_program, stage1_outer_proof, + stage1_outer_proof_from_kernel_proof, stage1_outer_prover_inputs, + stage2_opening_inputs_from_artifacts, stage2_proof, stage2_prover_inputs, + stage2_verifier_ram_data, stage3_opening_inputs_from_artifacts, stage3_proof, + stage3_prover_inputs, stage4_opening_inputs_from_artifacts, stage4_proof, stage4_prover_inputs, + stage5_kernel_proof, stage5_opening_inputs_from_artifacts, stage5_proof, stage5_prover_inputs, + stage6_bytecode_read_raf_data_from_witness_entries, stage6_execution_artifacts, + stage6_kernel_proof, stage6_opening_inputs_from_artifacts, stage6_proof, stage6_prover_inputs, + stage6_witness_from_opening_inputs, stage7_execution_artifacts, stage7_kernel_proof, + stage7_opening_inputs_from_stage6_artifacts, + stage7_opening_inputs_from_stage6_artifacts_with_program, stage7_proof, stage7_prover_inputs, + verifier_opening_inputs_from_kernel, DefaultJoltTranscript, JoltEvaluationProveError, + JoltKernelOpeningInput, JoltOpeningInputError, JoltProveError, JoltProverArtifacts, + JoltProverInputs, JoltProverPrograms, JoltProverStageInputs, JoltProverWitnessInputs, + JoltStage2RamDataStorage, +}; + +pub use prover::{ + prove_stage1_outer_with_witness_inputs, prove_stage2_with_witness_inputs, + prove_stage3_with_witness_inputs, prove_stage4_with_trace_witness_inputs, + prove_stage4_with_witness_inputs, prove_stage5_with_trace_witness_inputs, + prove_stage5_with_witness_inputs, prove_stage6_with_trace_witness_inputs, + prove_stage6_with_witness_inputs, prove_stage7_with_trace_witness_inputs, + prove_stage7_with_witness_inputs, stage6_verifier_data_from_witness_entries, +}; + +pub const TRANSCRIPT_LABEL: &[u8] = b"Jolt"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct GeneratedStage { + pub name: &'static str, + pub module: &'static str, + pub ordinal: usize, +} + +pub const GENERATED_STAGES: &[GeneratedStage] = &[ + GeneratedStage { + name: "commitment", + module: "commitment", + ordinal: 0, + }, + GeneratedStage { + name: "stage1_outer", + module: "stage1_outer", + ordinal: 1, + }, + GeneratedStage { + name: "stage2", + module: "stage2", + ordinal: 2, + }, + GeneratedStage { + name: "stage3", + module: "stage3", + ordinal: 3, + }, + GeneratedStage { + name: "stage4", + module: "stage4", + ordinal: 4, + }, + GeneratedStage { + name: "stage5", + module: "stage5", + ordinal: 5, + }, + GeneratedStage { + name: "stage6", + module: "stage6", + ordinal: 6, + }, + GeneratedStage { + name: "stage7", + module: "stage7", + ordinal: 7, + }, + GeneratedStage { + name: "stage8", + module: "stage8", + ordinal: 8, + }, +]; + +pub fn generated_stage_names() -> impl Iterator { + GENERATED_STAGES.iter().map(|stage| stage.name) +} diff --git a/crates/jolt-prover/src/prover.rs b/crates/jolt-prover/src/prover.rs new file mode 100644 index 0000000000..f459d454be --- /dev/null +++ b/crates/jolt-prover/src/prover.rs @@ -0,0 +1,2090 @@ +#![expect( + clippy::too_many_arguments, + reason = "generated prover helpers mirror staged protocol ABIs" +)] + +use jolt_dory::{DoryCommitment, DoryHint, DoryProverSetup, DoryScheme}; +use jolt_field::Fr; +use jolt_kernels::{stage1, stage2, stage3, stage4, stage5, stage6, stage7}; +use jolt_openings::{AdditivelyHomomorphic, CommitmentScheme}; +use jolt_poly::{EqPolynomial, Polynomial}; +use jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript}; +use jolt_verifier::{JoltEvaluationProof, JoltNamedEval, JoltProof, JoltStage2RamAccess, JoltStage2RamData, JoltStage2RamOutputLayout, JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, JoltStage6VerifierData, JoltStageChallengeVector, JoltStageExecutionArtifacts, JoltStageOpeningInputValue, JoltStageProof, JoltSumcheckOutput}; +use jolt_witness::{stage4_ram_val_init_opening, CycleInput, Stage45SparseTraceWitness, Stage6BytecodeEntry as WitnessStage6BytecodeEntry, Stage6WitnessParams, Stage6WitnessPolynomials, Stage6WitnessSlices}; +use rayon::prelude::*; + +use crate::stages::{commitment as commitment_stage, stage1_outer as stage1_outer_stage, stage2 as stage2_stage, stage3 as stage3_stage, stage4 as stage4_stage, stage5 as stage5_stage, stage6 as stage6_stage, stage7 as stage7_stage, stage8 as stage8_stage}; + +pub type DefaultJoltTranscript = Blake2bTranscript; + +pub struct JoltProverInputs<'a, CommitmentInputs, Stage1OuterExecutor, Stage2Executor, Stage3Executor, Stage4Executor, Stage5Executor, Stage6Executor, Stage7Executor> { + pub commitment_inputs: &'a mut CommitmentInputs, + pub prover_setup: &'a DoryProverSetup, + pub stage1_outer_executor: &'a mut Stage1OuterExecutor, + pub stage2_executor: &'a mut Stage2Executor, + pub stage3_executor: &'a mut Stage3Executor, + pub stage4_executor: &'a mut Stage4Executor, + pub stage5_executor: &'a mut Stage5Executor, + pub stage6_executor: &'a mut Stage6Executor, + pub stage7_executor: &'a mut Stage7Executor, + pub stage7_openings: Option<&'a [stage7::Stage7OpeningInputValue]>, +} + +#[derive(Clone, Copy, Debug)] +pub struct JoltProverPrograms { + pub commitment: &'static commitment_stage::CommitmentProverProgramPlan, + pub stage1_outer: &'static stage1::Stage1CpuProgramPlan, + pub stage2: &'static stage2::Stage2CpuProgramPlan, + pub stage3: &'static stage3::Stage3CpuProgramPlan, + pub stage4: &'static stage4::Stage4CpuProgramPlan, + pub stage5: &'static stage5::Stage5CpuProgramPlan, + pub stage6: &'static stage6::Stage6CpuProgramPlan, + pub stage7: &'static stage7::Stage7CpuProgramPlan, + pub stage8: &'static stage8_stage::Stage8EvaluationProgramPlan, +} + +pub fn default_prover_programs() -> JoltProverPrograms { + JoltProverPrograms { + commitment: &commitment_stage::COMMITMENT_PROGRAM, + stage1_outer: &stage1_outer_stage::STAGE1_PROGRAM, + stage2: &stage2_stage::STAGE2_PROGRAM, + stage3: &stage3_stage::STAGE3_PROGRAM, + stage4: &stage4_stage::STAGE4_PROGRAM, + stage5: &stage5_stage::STAGE5_PROGRAM, + stage6: &stage6_stage::STAGE6_PROGRAM, + stage7: &stage7_stage::STAGE7_PROGRAM, + stage8: &stage8_stage::STAGE8_PROGRAM, + } +} + +#[derive(Clone, Debug)] +pub struct JoltProverArtifacts { + pub commitment: commitment_stage::CommitmentArtifacts, + pub stage1_outer: stage1::Stage1ExecutionArtifacts, + pub stage2: stage2::Stage2ExecutionArtifacts, + pub stage3: stage3::Stage3ExecutionArtifacts, + pub stage4: stage4::Stage4ExecutionArtifacts, + pub stage5: stage5::Stage5ExecutionArtifacts, + pub stage6: stage6::Stage6ExecutionArtifacts, + pub stage7: stage7::Stage7ExecutionArtifacts, +} + +#[derive(Debug)] +pub enum JoltProveError { + Commitment(commitment_stage::CommitmentPhaseError), + Stage1Outer(stage1::Stage1KernelError), + Stage2(stage2::Stage2KernelError), + Stage3(stage3::Stage3KernelError), + Stage4(stage4::Stage4KernelError), + Stage5(stage5::Stage5KernelError), + Stage6(stage6::Stage6KernelError), + Stage7(stage7::Stage7KernelError), + Evaluation(JoltEvaluationProveError), +} + +#[derive(Debug)] +pub enum JoltEvaluationProveError { + MissingOracle { oracle: &'static str }, + MissingOpeningHint { oracle: &'static str }, + MissingStageEval { stage: &'static str, eval: &'static str }, + MissingStage7RaEval, + MissingStage7EvaluationPoint, + InvalidPointLength { + artifact: &'static str, + expected: usize, + actual: usize, + }, + TargetSizeOverflow { num_vars: usize }, +} + +#[derive(Debug)] +pub enum JoltOpeningInputError { + MissingOpeningClaim { stage: &'static str, source_claim: &'static str }, + MissingStage6OpeningClaim { source_claim: &'static str }, + UnsupportedOpeningInputSource { stage: &'static str, symbol: &'static str, source_stage: &'static str }, + UnsupportedStage7InputSource { symbol: &'static str, source_stage: &'static str }, + InvalidPointLength { + symbol: &'static str, + expected: usize, + actual: usize, + }, +} + +impl From for JoltProveError { + fn from(error: commitment_stage::CommitmentPhaseError) -> Self { + Self::Commitment(error) + } +} + +impl From for JoltProveError { + fn from(error: stage1::Stage1KernelError) -> Self { + Self::Stage1Outer(error) + } +} + +impl From for JoltProveError { + fn from(error: stage2::Stage2KernelError) -> Self { + Self::Stage2(error) + } +} + +impl From for JoltProveError { + fn from(error: stage3::Stage3KernelError) -> Self { + Self::Stage3(error) + } +} + +impl From for JoltProveError { + fn from(error: stage4::Stage4KernelError) -> Self { + Self::Stage4(error) + } +} + +impl From for JoltProveError { + fn from(error: stage5::Stage5KernelError) -> Self { + Self::Stage5(error) + } +} + +impl From for JoltProveError { + fn from(error: stage6::Stage6KernelError) -> Self { + Self::Stage6(error) + } +} + +impl From for JoltProveError { + fn from(error: stage7::Stage7KernelError) -> Self { + Self::Stage7(error) + } +} + +impl From for JoltProveError { + fn from(error: JoltEvaluationProveError) -> Self { + Self::Evaluation(error) + } +} + +pub fn prove_jolt( + inputs: JoltProverInputs<'_, CommitmentInputs, Stage1OuterExecutor, Stage2Executor, Stage3Executor, Stage4Executor, Stage5Executor, Stage6Executor, Stage7Executor>, + transcript: &mut T, +) -> Result<(JoltProof, JoltProverArtifacts), JoltProveError> +where + CommitmentInputs: commitment_stage::CommitmentInputProvider, + Stage1OuterExecutor: stage1::Stage1KernelExecutor, + Stage2Executor: stage2::Stage2KernelExecutor, + Stage3Executor: stage3::Stage3KernelExecutor, + Stage4Executor: stage4::Stage4KernelExecutor, + Stage5Executor: stage5::Stage5KernelExecutor, + Stage6Executor: stage6::Stage6KernelExecutor, + Stage7Executor: stage7::Stage7KernelExecutor, + T: Transcript, +{ + prove_jolt_with_programs(inputs, default_prover_programs(), transcript) +} + +pub fn prove_jolt_with_programs( + inputs: JoltProverInputs<'_, CommitmentInputs, Stage1OuterExecutor, Stage2Executor, Stage3Executor, Stage4Executor, Stage5Executor, Stage6Executor, Stage7Executor>, + programs: JoltProverPrograms, + transcript: &mut T, +) -> Result<(JoltProof, JoltProverArtifacts), JoltProveError> +where + CommitmentInputs: commitment_stage::CommitmentInputProvider, + Stage1OuterExecutor: stage1::Stage1KernelExecutor, + Stage2Executor: stage2::Stage2KernelExecutor, + Stage3Executor: stage3::Stage3KernelExecutor, + Stage4Executor: stage4::Stage4KernelExecutor, + Stage5Executor: stage5::Stage5KernelExecutor, + Stage6Executor: stage6::Stage6KernelExecutor, + Stage7Executor: stage7::Stage7KernelExecutor, + T: Transcript, +{ + let _prove_span = tracing::info_span!("bolt.prove").entered(); + let _commitment_span = tracing::info_span!("bolt.commitment").entered(); + let commitment = commitment_stage::prove_commitment_phase_with_program( + programs.commitment, inputs.commitment_inputs, + inputs.prover_setup, + transcript, + )?; + drop(_commitment_span); + let _stage1_outer_span = tracing::info_span!("bolt.stage1").entered(); + let stage1_outer = stage1_outer_stage::prove_stage1_outer_with_program(programs.stage1_outer, inputs.stage1_outer_executor, transcript)?; + drop(_stage1_outer_span); + let _stage2_span = tracing::info_span!("bolt.stage2").entered(); + let stage2 = stage2_stage::execute_stage2_prover_with_program(programs.stage2, inputs.stage2_executor, transcript)?; + drop(_stage2_span); + let _stage3_span = tracing::info_span!("bolt.stage3").entered(); + let stage3 = stage3_stage::execute_stage3_prover_with_program(programs.stage3, inputs.stage3_executor, transcript)?; + drop(_stage3_span); + let _stage4_span = tracing::info_span!("bolt.stage4").entered(); + let stage4 = stage4_stage::execute_stage4_prover_with_program(programs.stage4, inputs.stage4_executor, transcript)?; + drop(_stage4_span); + let _stage5_span = tracing::info_span!("bolt.stage5").entered(); + let stage5 = stage5_stage::execute_stage5_prover_with_program(programs.stage5, inputs.stage5_executor, transcript)?; + drop(_stage5_span); + let _stage6_span = tracing::info_span!("bolt.stage6").entered(); + let stage6 = stage6_stage::execute_stage6_prover_with_program(programs.stage6, inputs.stage6_executor, transcript)?; + drop(_stage6_span); + let _stage7_span = tracing::info_span!("bolt.stage7").entered(); + let stage7 = stage7_stage::execute_stage7_prover_with_program(programs.stage7, inputs.stage7_executor, transcript)?; + drop(_stage7_span); + let evaluation = if let Some(stage7_openings) = inputs.stage7_openings { + let _stage8_span = tracing::info_span!("bolt.stage8").entered(); + let _evaluate_span = tracing::info_span!("bolt.evaluate").entered(); + Some(prove_jolt_evaluation_proof( + programs.stage8, + inputs.commitment_inputs, + inputs.prover_setup, + &commitment, + &stage6, + &stage7, + stage7_openings, + transcript, + )?) + } else { + None + }; + + let proof = JoltProof { + commitments: commitment.commitments.clone(), + stage1_outer: stage1_outer_proof(&stage1_outer), + stage2: stage2_proof(&stage2), + stage3: stage3_proof(&stage3), + stage4: stage4_proof(&stage4), + stage5: stage5_proof(&stage5), + stage6: stage6_proof(&stage6), + stage7: stage7_proof(&stage7), + evaluation, + }; + let artifacts = JoltProverArtifacts { + commitment, + stage1_outer, + stage2, + stage3, + stage4, + stage5, + stage6, + stage7, + }; + Ok((proof, artifacts)) +} + +pub fn prove_jolt_evaluation_proof( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + commitment_inputs: &mut I, + prover_setup: &DoryProverSetup, + commitments: &commitment_stage::CommitmentArtifacts, + stage6: &stage6::Stage6ExecutionArtifacts, + stage7: &stage7::Stage7ExecutionArtifacts, + stage7_openings: &[stage7::Stage7OpeningInputValue], + transcript: &mut T, +) -> Result +where + I: commitment_stage::CommitmentInputProvider, + T: Transcript, +{ + let _claims_span = tracing::info_span!("bolt.evaluate.claims").entered(); + let (sumcheck_address_point, stage7_values) = stage7_claim_values(program, stage7)?; + let address_point = reverse_point(&sumcheck_address_point); + let (opening_point, log_t) = + stage7_evaluation_opening_point(program, &address_point, stage7_openings)?; + let lagrange_factor = EqPolynomial::::zero_selector(&address_point); + let claims = evaluation_claims(program, stage6, &stage7_values, lagrange_factor)?; + drop(_claims_span); + + let _rlc_span = tracing::info_span!("bolt.evaluate.rlc_claims").entered(); + append_rlc_claims(transcript, &claims); + let gamma_powers = gamma_powers(transcript, claims.len()); + let joint_claim = claims + .iter() + .zip(&gamma_powers) + .map(|(claim, gamma)| claim.value * *gamma) + .sum(); + drop(_rlc_span); + let _materialize_span = + tracing::info_span!("bolt.evaluate.materialize_joint_polynomial").entered(); + let joint_evals = materialize_joint_polynomial( + commitment_inputs, + &claims, + &gamma_powers, + log_t, + opening_point.len(), + )?; + drop(_materialize_span); + let joint_poly = Polynomial::new(joint_evals); + let _hint_span = tracing::info_span!("bolt.evaluate.joint_opening_hint").entered(); + let joint_hint = joint_opening_hint(commitments, &claims, &gamma_powers)?; + drop(_hint_span); + let _dory_open_span = tracing::info_span!("bolt.evaluate.dory_open").entered(); + let joint_opening_proof = ::open( + &joint_poly, + &opening_point, + joint_claim, + prover_setup, + Some(joint_hint), + transcript, + ); + drop(_dory_open_span); + let _bind_span = tracing::info_span!("bolt.evaluate.bind_opening_inputs").entered(); + ::bind_opening_inputs( + transcript, + &opening_point, + &joint_claim, + ); + drop(_bind_span); + Ok(JoltEvaluationProof { joint_opening_proof }) +} + +struct EvaluationClaim { + oracle: &'static str, + source_stage: &'static str, + value: Fr, +} + +fn stage6_eval_claim( + artifacts: &stage6::Stage6ExecutionArtifacts, + eval_name: &'static str, +) -> Result { + for output in &artifacts.sumchecks { + if let Some(eval) = output.evals.iter().find(|eval| eval.name == eval_name) { + return Ok(eval.value); + } + } + Err(JoltEvaluationProveError::MissingStageEval { + stage: "stage6", + eval: eval_name, + }) +} + +fn evaluation_claims( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + stage6: &stage6::Stage6ExecutionArtifacts, + stage7_values: &std::collections::BTreeMap<&'static str, Fr>, + lagrange_factor: Fr, +) -> Result, JoltEvaluationProveError> { + let mut claims = Vec::with_capacity(program.opening_claims.len()); + for plan in program.opening_claims { + let value = match plan.source_stage { + "stage6" => stage6_eval_claim(stage6, plan.source_claim)? * lagrange_factor, + "stage7" => *stage7_values.get(plan.source_claim).ok_or( + JoltEvaluationProveError::MissingStageEval { + stage: plan.source_stage, + eval: plan.source_claim, + }, + )?, + _ => { + return Err(JoltEvaluationProveError::MissingStageEval { + stage: plan.source_stage, + eval: plan.source_claim, + }); + } + }; + claims.push(EvaluationClaim { + oracle: plan.oracle, + source_stage: plan.source_stage, + value, + }); + } + Ok(claims) +} + +fn stage7_claim_values( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + artifacts: &stage7::Stage7ExecutionArtifacts, +) -> Result<(Vec, std::collections::BTreeMap<&'static str, Fr>), JoltEvaluationProveError> { + let stage7_plans = program + .opening_claims + .iter() + .filter(|plan| plan.source_stage == "stage7") + .collect::>(); + for output in &artifacts.sumchecks { + let mut values = std::collections::BTreeMap::new(); + for plan in &stage7_plans { + if let Some(eval) = output.evals.iter().find(|eval| eval.name == plan.source_claim) { + let _ = values.insert(plan.source_claim, eval.value); + } + } + if values.len() == stage7_plans.len() { + return Ok((output.point.clone(), values)); + } + } + Err(JoltEvaluationProveError::MissingStage7RaEval) +} + +fn reverse_point(point: &[Fr]) -> Vec { + point.iter().rev().copied().collect() +} + +fn stage7_evaluation_opening_point( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + address_point: &[Fr], + stage7_openings: &[stage7::Stage7OpeningInputValue], +) -> Result<(Vec, usize), JoltEvaluationProveError> { + let cycle_source_symbol = program.evaluation_point_source.source_claim; + let cycle_source = stage7_openings + .iter() + .find(|input| input.symbol == cycle_source_symbol) + .ok_or(JoltEvaluationProveError::MissingStage7EvaluationPoint)?; + if cycle_source.point.len() < address_point.len() { + return Err(JoltEvaluationProveError::InvalidPointLength { + artifact: cycle_source_symbol, + expected: address_point.len(), + actual: cycle_source.point.len(), + }); + } + let cycle_len = cycle_source.point.len() - address_point.len(); + let mut point = Vec::with_capacity(cycle_source.point.len()); + point.extend_from_slice(address_point); + point.extend_from_slice(&cycle_source.point[address_point.len()..]); + Ok((point, cycle_len)) +} + +fn append_rlc_claims(transcript: &mut T, claims: &[EvaluationClaim]) +where + T: Transcript, +{ + transcript.append(&LabelWithCount(b"rlc_claims", claims.len() as u64)); + for claim in claims { + claim.value.append_to_transcript(transcript); + } +} + +fn gamma_powers(transcript: &mut T, count: usize) -> Vec +where + T: Transcript, +{ + let gamma = transcript.challenge(); + let mut powers = Vec::with_capacity(count); + let mut power = Fr::from_u64(1); + for _ in 0..count { + powers.push(power); + power *= gamma; + } + powers +} + +fn materialize_joint_polynomial( + commitment_inputs: &mut I, + claims: &[EvaluationClaim], + gamma_powers: &[Fr], + log_t: usize, + main_num_vars: usize, +) -> Result, JoltEvaluationProveError> +where + I: commitment_stage::CommitmentInputProvider, +{ + let trace_len = target_len(log_t)?; + let main_len = target_len(main_num_vars)?; + let mut joint = vec![Fr::from_u64(0); main_len]; + for (claim, gamma) in claims.iter().zip(gamma_powers) { + if claim.source_stage == "stage6" { + add_oracle_scaled(commitment_inputs, &mut joint, claim.oracle, log_t, trace_len, *gamma)?; + } else { + add_oracle_scaled( + commitment_inputs, + &mut joint, + claim.oracle, + main_num_vars, + main_len, + *gamma, + )?; + } + } + Ok(joint) +} + +fn add_oracle_scaled( + commitment_inputs: &mut I, + joint: &mut [Fr], + oracle: &'static str, + num_vars: usize, + limit: usize, + scalar: Fr, +) -> Result<(), JoltEvaluationProveError> +where + I: commitment_stage::CommitmentInputProvider, +{ + if commitment_inputs.add_scaled_to_joint(oracle, joint, num_vars, limit, scalar) { + return Ok(()); + } + let target_len = target_len(num_vars)?; + let data = commitment_inputs + .materialize_with_num_vars(oracle, num_vars) + .ok_or(JoltEvaluationProveError::MissingOracle { oracle })?; + if data.len() > target_len { + return Err(JoltEvaluationProveError::InvalidPointLength { + artifact: oracle, + expected: target_len, + actual: data.len(), + }); + } + let zero = Fr::from_u64(0); + let one = Fr::from_u64(1); + let len = limit.min(joint.len()).min(data.len()); + if len >= 1 << 15 { + joint[..len] + .par_iter_mut() + .zip(data[..len].par_iter()) + .for_each(|(dst, value)| { + if *value == zero { + return; + } + if *value == one { + *dst += scalar; + } else { + *dst += *value * scalar; + } + }); + } else { + for (dst, value) in joint.iter_mut().take(len).zip(data.iter()) { + if *value == zero { + continue; + } + if *value == one { + *dst += scalar; + } else { + *dst += *value * scalar; + } + } + } + Ok(()) +} + +fn joint_opening_hint( + commitments: &commitment_stage::CommitmentArtifacts, + claims: &[EvaluationClaim], + gamma_powers: &[Fr], +) -> Result { + let mut coefficients = std::collections::BTreeMap::<&'static str, Fr>::new(); + for (claim, gamma) in claims.iter().zip(gamma_powers) { + let coefficient = coefficients.entry(claim.oracle).or_insert(Fr::from_u64(0)); + *coefficient += *gamma; + } + + let mut hints = Vec::with_capacity(coefficients.len()); + let mut scalars = Vec::with_capacity(coefficients.len()); + for (oracle, coefficient) in coefficients { + hints.push(opening_hint_for_oracle(commitments, oracle)?); + scalars.push(coefficient); + } + + Ok(::combine_hints( + hints, &scalars, + )) +} + +fn opening_hint_for_oracle( + commitments: &commitment_stage::CommitmentArtifacts, + oracle: &'static str, +) -> Result { + commitments + .hints + .iter() + .find(|hint| hint.oracle == oracle) + .map(|hint| hint.hint.clone()) + .ok_or(JoltEvaluationProveError::MissingOpeningHint { oracle }) +} + +fn target_len(num_vars: usize) -> Result { + if num_vars >= usize::BITS as usize { + return Err(JoltEvaluationProveError::TargetSizeOverflow { num_vars }); + } + Ok(1usize << num_vars) +} + +pub struct JoltProverStageInputs<'a, CommitmentInputs> { + pub commitment_inputs: &'a mut CommitmentInputs, + pub prover_setup: &'a DoryProverSetup, + pub stage1_outer: stage1::Stage1ProverInputs<'a, Fr>, + pub stage2: stage2::Stage2ProverInputs<'a, Fr>, + pub stage3: stage3::Stage3ProverInputs<'a, Fr>, + pub stage4: stage4::Stage4ProverInputs<'a, Fr>, + pub stage5: stage5::Stage5ProverInputs<'a, Fr>, + pub stage6: stage6::Stage6ProverInputs<'a, Fr>, + pub stage7: stage7::Stage7ProverInputs<'a, Fr>, + pub stage7_openings: Option<&'a [stage7::Stage7OpeningInputValue]>, +} + +pub fn prove_jolt_with_stage_inputs( + inputs: JoltProverStageInputs<'_, CommitmentInputs>, + programs: JoltProverPrograms, + transcript: &mut T, +) -> Result<(JoltProof, JoltProverArtifacts), JoltProveError> +where + CommitmentInputs: commitment_stage::CommitmentInputProvider, + T: Transcript, +{ + let JoltProverStageInputs { + commitment_inputs, + prover_setup, + stage1_outer, + stage2, + stage3, + stage4, + stage5, + stage6, + stage7, + stage7_openings, + } = inputs; + let mut stage1_outer_executor = stage1::Stage1ProverKernelExecutor::new(stage1_outer); + let mut stage2_executor = stage2::Stage2ProverKernelExecutor::new(stage2); + let mut stage3_executor = stage3::Stage3ProverKernelExecutor::new(stage3); + let mut stage4_executor = stage4::Stage4ProverKernelExecutor::new(stage4); + let mut stage5_executor = stage5::Stage5ProverKernelExecutor::new(stage5); + let mut stage6_executor = stage6::Stage6ProverKernelExecutor::new(stage6); + let mut stage7_executor = stage7::Stage7ProverKernelExecutor::new(stage7); + prove_jolt_with_programs( + JoltProverInputs { + commitment_inputs, + prover_setup, + stage1_outer_executor: &mut stage1_outer_executor, + stage2_executor: &mut stage2_executor, + stage3_executor: &mut stage3_executor, + stage4_executor: &mut stage4_executor, + stage5_executor: &mut stage5_executor, + stage6_executor: &mut stage6_executor, + stage7_executor: &mut stage7_executor, + stage7_openings, + }, + programs, + transcript, + ) +} + +pub struct JoltProverWitnessInputs<'a, CommitmentInputs> { + pub commitment_inputs: &'a mut CommitmentInputs, + pub prover_setup: &'a DoryProverSetup, + pub stage1_trace_num_vars: usize, + pub stage1_outer_evaluator: &'a dyn stage1::Stage1OuterRemainingEvaluator, + pub stage2_openings: &'a [stage2::Stage2OpeningInputValue], + pub product_virtual_cycles: &'a [stage2::Stage2ProductVirtualCycle], + pub instruction_lookup_cycles: &'a [stage2::Stage2InstructionLookupCycle], + pub ram: &'a stage2::Stage2RamData<'a>, + pub stage3_openings: &'a [stage3::Stage3OpeningInputValue], + pub stage3_cycles: &'a [stage3::Stage3Cycle], + pub stage4_openings: &'a [stage4::Stage4OpeningInputValue], + pub register_count: usize, + pub trace_len: usize, + pub ram_k: usize, + pub register_accesses: &'a [stage4::Stage4RegisterAccess], + pub stage5_openings: &'a [stage5::Stage5OpeningInputValue], + pub lookup_indices: &'a [u128], + pub lookup_table_indices: &'a [Option], + pub is_interleaved_operands: &'a [bool], + pub ra_virtual_log_k_chunk: usize, + pub stage6_openings: &'a [stage6::Stage6OpeningInputValue], + pub stage6_bytecode_data: stage6::Stage6BytecodeReadRafData<'a, Fr>, + pub stage6_witness_params: Stage6WitnessParams, + pub cycle_inputs: &'a [CycleInput], + pub instruction_ra_virtual_d: usize, + pub stage7_openings: &'a [stage7::Stage7OpeningInputValue], + pub evaluation_openings: Option<&'a [stage7::Stage7OpeningInputValue]>, +} + +pub fn prove_jolt_with_witness_inputs( + inputs: JoltProverWitnessInputs<'_, CommitmentInputs>, + programs: JoltProverPrograms, + transcript: &mut T, +) -> Result<(JoltProof, JoltProverArtifacts), JoltProveError> +where + CommitmentInputs: commitment_stage::CommitmentInputProvider, + T: Transcript, +{ + let _input_span = tracing::info_span!("bolt.prove.inputs").entered(); + let _stage1_input_span = tracing::info_span!("bolt.prove.inputs.stage1").entered(); + let stage1_outer = + stage1_outer_prover_inputs(inputs.stage1_trace_num_vars, inputs.stage1_outer_evaluator); + drop(_stage1_input_span); + let _stage2_input_span = tracing::info_span!("bolt.prove.inputs.stage2").entered(); + let stage2 = stage2_prover_inputs( + inputs.stage2_openings, + inputs.product_virtual_cycles, + inputs.instruction_lookup_cycles, + inputs.ram, + )?; + drop(_stage2_input_span); + let _stage3_input_span = tracing::info_span!("bolt.prove.inputs.stage3").entered(); + let stage3 = stage3_prover_inputs(inputs.stage3_openings, inputs.stage3_cycles); + drop(_stage3_input_span); + let _stage45_witness_span = tracing::info_span!("bolt.prove.inputs.stage45_witness").entered(); + let stage45_witness = stage4::stage4_5_sparse_trace_witness_from_accesses( + inputs.register_accesses, + inputs.ram.accesses, + ); + drop(_stage45_witness_span); + let _stage4_input_span = tracing::info_span!("bolt.prove.inputs.stage4").entered(); + let stage4 = stage4_prover_inputs( + inputs.stage4_openings, + inputs.register_count, + inputs.trace_len, + inputs.ram_k, + inputs.register_accesses, + &stage45_witness, + ); + drop(_stage4_input_span); + let _stage5_input_span = tracing::info_span!("bolt.prove.inputs.stage5").entered(); + let stage5 = stage5_prover_inputs( + inputs.stage5_openings, + inputs.trace_len, + inputs.ram_k, + inputs.register_count, + inputs.lookup_indices, + inputs.lookup_table_indices, + inputs.is_interleaved_operands, + inputs.ra_virtual_log_k_chunk, + &stage45_witness, + ); + drop(_stage5_input_span); + let _stage6_witness_span = tracing::info_span!("bolt.prove.inputs.stage6_witness").entered(); + let stage6_witness = stage6_witness_from_opening_inputs( + inputs.stage6_witness_params, + inputs.cycle_inputs, + inputs.stage6_openings, + ); + let stage6_witness_slices = stage6_witness.slices(); + drop(_stage6_witness_span); + let _stage6_input_span = tracing::info_span!("bolt.prove.inputs.stage6").entered(); + let stage6 = stage6_prover_inputs( + inputs.stage6_openings, + inputs.stage6_bytecode_data, + &stage6_witness, + &stage6_witness_slices, + inputs.instruction_ra_virtual_d, + ); + drop(_stage6_input_span); + let _stage7_input_span = tracing::info_span!("bolt.prove.inputs.stage7").entered(); + let stage7 = stage7_prover_inputs(inputs.stage7_openings, &stage6_witness_slices); + drop(_stage7_input_span); + drop(_input_span); + prove_jolt_with_stage_inputs( + JoltProverStageInputs { + commitment_inputs: inputs.commitment_inputs, + prover_setup: inputs.prover_setup, + stage1_outer, + stage2, + stage3, + stage4, + stage5, + stage6, + stage7, + stage7_openings: inputs.evaluation_openings, + }, + programs, + transcript, + ) +} + +pub fn stage1_outer_prover_inputs( + trace_num_vars: usize, + evaluator: &dyn stage1::Stage1OuterRemainingEvaluator, +) -> stage1::Stage1ProverInputs<'_, Fr> { + stage1::Stage1ProverInputs::empty(trace_num_vars).with_outer_remaining_evaluator(evaluator) +} + +pub fn prove_stage1_outer_inputs_with_program( + program: &'static stage1::Stage1CpuProgramPlan, + inputs: stage1::Stage1ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage1::Stage1KernelError> +where + T: Transcript, +{ + let mut executor = stage1::Stage1ProverKernelExecutor::new(inputs); + stage1_outer_stage::prove_stage1_outer_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage1_outer_with_witness_inputs( + program: &'static stage1::Stage1CpuProgramPlan, + trace_num_vars: usize, + evaluator: &dyn stage1::Stage1OuterRemainingEvaluator, + transcript: &mut T, +) -> Result, stage1::Stage1KernelError> +where + T: Transcript, +{ + let inputs = stage1_outer_prover_inputs(trace_num_vars, evaluator); + prove_stage1_outer_inputs_with_program(program, inputs, transcript) +} + +pub fn replay_stage1_outer_proof_with_program( + program: &'static stage1::Stage1CpuProgramPlan, + proof: &stage1::Stage1Proof, + transcript: &mut T, +) -> Result, stage1::Stage1KernelError> +where + T: Transcript, +{ + let mut executor = stage1::Stage1VerifierKernelExecutor::new(proof); + stage1::execute_stage1_program( + program, + stage1::Stage1ExecutionMode::Verifier, + &mut executor, + transcript, + ) +} + +pub fn stage1_outer_proof_from_kernel_proof( + proof: &stage1::Stage1Proof, +) -> JoltStageProof { + JoltStageProof { + sumchecks: proof + .sumchecks + .iter() + .map(stage1_outer_sumcheck) + .collect(), + } +} + +pub fn stage2_prover_inputs<'a>( + opening_inputs: &'a [stage2::Stage2OpeningInputValue], + product_virtual_cycles: &'a [stage2::Stage2ProductVirtualCycle], + instruction_lookup_cycles: &'a [stage2::Stage2InstructionLookupCycle], + ram: &'a stage2::Stage2RamData<'a>, +) -> Result, stage2::Stage2KernelError> { + Ok(stage2::Stage2ProverInputs::new(opening_inputs) + .with_product_virtual_witness(product_virtual_cycles)? + .with_instruction_lookup_cycles(instruction_lookup_cycles) + .with_ram_data(ram)) +} + +pub struct JoltStage2RamDataStorage<'a> { + log_k: usize, + start_address: u64, + initial_ram: &'a [u64], + final_ram: &'a [u64], + accesses: Vec, + output_layout: Option, +} + +impl<'a> JoltStage2RamDataStorage<'a> { + pub fn from_kernel(ram: &stage2::Stage2RamData<'a>) -> Self { + Self { + log_k: ram.log_k, + start_address: ram.start_address, + initial_ram: ram.initial_ram, + final_ram: ram.final_ram, + accesses: ram + .accesses + .iter() + .map(|access| JoltStage2RamAccess { + remapped_address: access.remapped_address, + read_value: access.read_value, + write_value: access.write_value, + }) + .collect(), + output_layout: ram.output_layout.map(|layout| JoltStage2RamOutputLayout { + io_start: layout.io_start, + io_end: layout.io_end, + }), + } + } + + pub fn as_input(&self) -> JoltStage2RamData<'_> { + JoltStage2RamData { + log_k: self.log_k, + start_address: self.start_address, + initial_ram: self.initial_ram, + final_ram: self.final_ram, + accesses: &self.accesses, + output_layout: self.output_layout, + } + } +} + +pub fn stage2_verifier_ram_data<'a>( + ram: &stage2::Stage2RamData<'a>, +) -> JoltStage2RamDataStorage<'a> { + JoltStage2RamDataStorage::from_kernel(ram) +} + +pub trait JoltKernelOpeningInput { + fn symbol(&self) -> &'static str; + fn point(&self) -> &[Fr]; + fn eval(&self) -> Fr; +} + +macro_rules! impl_jolt_kernel_opening_input { + ($opening:ty) => { + impl JoltKernelOpeningInput for $opening { + fn symbol(&self) -> &'static str { + self.symbol + } + + fn point(&self) -> &[Fr] { + &self.point + } + + fn eval(&self) -> Fr { + self.eval + } + } + }; +} + +impl_jolt_kernel_opening_input!(stage2::Stage2OpeningInputValue); +impl_jolt_kernel_opening_input!(stage3::Stage3OpeningInputValue); +impl_jolt_kernel_opening_input!(stage4::Stage4OpeningInputValue); + +pub fn verifier_opening_inputs_from_kernel(inputs: &[I]) -> Vec +where + I: JoltKernelOpeningInput, +{ + inputs + .iter() + .map(|input| JoltStageOpeningInputValue { + symbol: input.symbol(), + point: input.point().to_vec(), + eval: input.eval(), + }) + .collect() +} + +pub fn prove_stage2_inputs_with_program( + program: &'static stage2::Stage2CpuProgramPlan, + inputs: stage2::Stage2ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage2::Stage2KernelError> +where + T: Transcript, +{ + let mut executor = stage2::Stage2ProverKernelExecutor::new(inputs); + stage2_stage::execute_stage2_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage2_with_witness_inputs<'a, T>( + program: &'static stage2::Stage2CpuProgramPlan, + opening_inputs: &'a [stage2::Stage2OpeningInputValue], + product_virtual_cycles: &'a [stage2::Stage2ProductVirtualCycle], + instruction_lookup_cycles: &'a [stage2::Stage2InstructionLookupCycle], + ram: &'a stage2::Stage2RamData<'a>, + transcript: &mut T, +) -> Result, stage2::Stage2KernelError> +where + T: Transcript, +{ + let inputs = stage2_prover_inputs( + opening_inputs, + product_virtual_cycles, + instruction_lookup_cycles, + ram, + )?; + prove_stage2_inputs_with_program(program, inputs, transcript) +} + +pub fn stage2_opening_inputs_from_artifacts( + program: &'static stage2::Stage2CpuProgramPlan, + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = match input.source_stage { + "stage1" => stage1_opening_claim(stage1_artifacts, input.source_claim)?, + source_stage => { + return Err(JoltOpeningInputError::UnsupportedOpeningInputSource { + stage: "stage2", + symbol: input.symbol, + source_stage, + }); + } + }; + validate_point_len(input.symbol, input.point_arity, point.len())?; + Ok(stage2::Stage2OpeningInputValue { + symbol: input.symbol, + point, + eval, + }) + }) + .collect() +} + +pub fn replay_stage2_proof_with_program<'a, T>( + program: &'static stage2::Stage2CpuProgramPlan, + proof: &'a stage2::Stage2Proof, + opening_inputs: &'a [stage2::Stage2OpeningInputValue], + ram: Option<&'a stage2::Stage2RamData<'a>>, + transcript: &mut T, +) -> Result, stage2::Stage2KernelError> +where + T: Transcript, +{ + let mut executor = stage2::Stage2VerifierKernelExecutor::new(proof, opening_inputs); + if let Some(ram) = ram { + executor = executor.with_ram_data(ram); + } + stage2::execute_stage2_program( + program, + stage2::Stage2ExecutionMode::Verifier, + &mut executor, + transcript, + ) +} + +pub fn stage3_prover_inputs<'a>( + opening_inputs: &'a [stage3::Stage3OpeningInputValue], + cycles: &'a [stage3::Stage3Cycle], +) -> stage3::Stage3ProverInputs<'a, Fr> { + stage3::Stage3ProverInputs::new(opening_inputs).with_cycles(cycles) +} + +pub fn prove_stage3_inputs_with_program( + program: &'static stage3::Stage3CpuProgramPlan, + inputs: stage3::Stage3ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage3::Stage3KernelError> +where + T: Transcript, +{ + let mut executor = stage3::Stage3ProverKernelExecutor::new(inputs); + stage3_stage::execute_stage3_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage3_with_witness_inputs( + program: &'static stage3::Stage3CpuProgramPlan, + opening_inputs: &[stage3::Stage3OpeningInputValue], + cycles: &[stage3::Stage3Cycle], + transcript: &mut T, +) -> Result, stage3::Stage3KernelError> +where + T: Transcript, +{ + let inputs = stage3_prover_inputs(opening_inputs, cycles); + prove_stage3_inputs_with_program(program, inputs, transcript) +} + +pub fn stage3_opening_inputs_from_artifacts( + program: &'static stage3::Stage3CpuProgramPlan, + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = match input.source_stage { + "stage1" => stage1_opening_claim(stage1_artifacts, input.source_claim)?, + "stage2" => stage2_opening_claim(stage2_artifacts, input.source_claim)?, + source_stage => { + return Err(JoltOpeningInputError::UnsupportedOpeningInputSource { + stage: "stage3", + symbol: input.symbol, + source_stage, + }); + } + }; + validate_point_len(input.symbol, input.point_arity, point.len())?; + Ok(stage3::Stage3OpeningInputValue { + symbol: input.symbol, + point, + eval, + }) + }) + .collect() +} + +pub fn replay_stage3_proof_with_program( + program: &'static stage3::Stage3CpuProgramPlan, + proof: &stage3::Stage3Proof, + opening_inputs: &[stage3::Stage3OpeningInputValue], + transcript: &mut T, +) -> Result, stage3::Stage3KernelError> +where + T: Transcript, +{ + let mut executor = stage3::Stage3VerifierKernelExecutor::new(proof, opening_inputs); + stage3::execute_stage3_program( + program, + stage3::Stage3ExecutionMode::Verifier, + &mut executor, + transcript, + ) +} + +pub fn stage4_prover_inputs<'a>( + opening_inputs: &'a [stage4::Stage4OpeningInputValue], + register_count: usize, + trace_len: usize, + ram_k: usize, + register_accesses: &'a [stage4::Stage4RegisterAccess], + witness: &'a Stage45SparseTraceWitness, +) -> stage4::Stage4ProverInputs<'a, Fr> { + stage4::Stage4ProverInputs::new(opening_inputs).with_stage45_sparse_trace_witness( + register_count, + trace_len, + ram_k, + register_accesses, + witness, + ) +} + +pub fn prove_stage4_inputs_with_program( + program: &'static stage4::Stage4CpuProgramPlan, + inputs: stage4::Stage4ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage4::Stage4KernelError> +where + T: Transcript, +{ + let mut executor = stage4::Stage4ProverKernelExecutor::new(inputs); + stage4_stage::execute_stage4_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage4_with_witness_inputs( + program: &'static stage4::Stage4CpuProgramPlan, + opening_inputs: &[stage4::Stage4OpeningInputValue], + register_count: usize, + trace_len: usize, + ram_k: usize, + register_accesses: &[stage4::Stage4RegisterAccess], + witness: &Stage45SparseTraceWitness, + transcript: &mut T, +) -> Result, stage4::Stage4KernelError> +where + T: Transcript, +{ + let inputs = stage4_prover_inputs( + opening_inputs, + register_count, + trace_len, + ram_k, + register_accesses, + witness, + ); + prove_stage4_inputs_with_program(program, inputs, transcript) +} + +pub fn prove_stage4_with_trace_witness_inputs( + program: &'static stage4::Stage4CpuProgramPlan, + opening_inputs: &[stage4::Stage4OpeningInputValue], + register_count: usize, + trace_len: usize, + ram_k: usize, + register_accesses: &[stage4::Stage4RegisterAccess], + ram_accesses: &[stage2::Stage2RamAccess], + transcript: &mut T, +) -> Result, stage4::Stage4KernelError> +where + T: Transcript, +{ + let witness = stage4::stage4_5_sparse_trace_witness_from_accesses( + register_accesses, + ram_accesses, + ); + prove_stage4_with_witness_inputs( + program, + opening_inputs, + register_count, + trace_len, + ram_k, + register_accesses, + &witness, + transcript, + ) +} + +pub fn stage4_opening_inputs_from_artifacts( + program: &'static stage4::Stage4CpuProgramPlan, + initial_ram_state: &[u64], + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage3_artifacts: &stage3::Stage3ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = match input.source_stage { + "stage2" => stage2_opening_claim(stage2_artifacts, input.source_claim)?, + "stage3" => stage3_opening_claim(stage3_artifacts, input.source_claim)?, + "stage4_precomputed" => { + let (point, _) = stage2_opening_claim( + stage2_artifacts, + "stage2.ram_output.opening.RamValFinal", + )?; + stage4_ram_val_init_opening(initial_ram_state, &point) + } + source_stage => { + return Err(JoltOpeningInputError::UnsupportedOpeningInputSource { + stage: "stage4", + symbol: input.symbol, + source_stage, + }); + } + }; + opening_input_value(input.symbol, input.point_arity, point, eval) + }) + .collect() +} + +pub fn replay_stage4_proof_with_program( + program: &'static stage4::Stage4CpuProgramPlan, + proof: &stage4::Stage4Proof, + opening_inputs: &[stage4::Stage4OpeningInputValue], + transcript: &mut T, +) -> Result, stage4::Stage4KernelError> +where + T: Transcript, +{ + let mut executor = stage4::Stage4VerifierKernelExecutor::new(proof, opening_inputs); + stage4::execute_stage4_program( + program, + stage4::Stage4ExecutionMode::Verifier, + &mut executor, + transcript, + ) +} + +pub fn stage5_prover_inputs<'a>( + opening_inputs: &'a [stage5::Stage5OpeningInputValue], + trace_len: usize, + ram_k: usize, + register_count: usize, + lookup_indices: &'a [u128], + lookup_table_indices: &'a [Option], + is_interleaved_operands: &'a [bool], + ra_virtual_log_k_chunk: usize, + witness: &'a Stage45SparseTraceWitness, +) -> stage5::Stage5ProverInputs<'a, Fr> { + stage5::Stage5ProverInputs::new(opening_inputs).with_stage45_sparse_trace_witness( + trace_len, + ram_k, + register_count, + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + ra_virtual_log_k_chunk, + witness, + ) +} + +pub fn prove_stage5_inputs_with_program( + program: &'static stage5::Stage5CpuProgramPlan, + inputs: stage5::Stage5ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage5::Stage5KernelError> +where + T: Transcript, +{ + let mut executor = stage5::Stage5ProverKernelExecutor::new(inputs); + stage5_stage::execute_stage5_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage5_with_witness_inputs( + program: &'static stage5::Stage5CpuProgramPlan, + opening_inputs: &[stage5::Stage5OpeningInputValue], + trace_len: usize, + ram_k: usize, + register_count: usize, + lookup_indices: &[u128], + lookup_table_indices: &[Option], + is_interleaved_operands: &[bool], + ra_virtual_log_k_chunk: usize, + witness: &Stage45SparseTraceWitness, + transcript: &mut T, +) -> Result, stage5::Stage5KernelError> +where + T: Transcript, +{ + let inputs = stage5_prover_inputs( + opening_inputs, + trace_len, + ram_k, + register_count, + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + ra_virtual_log_k_chunk, + witness, + ); + prove_stage5_inputs_with_program(program, inputs, transcript) +} + +pub fn prove_stage5_with_trace_witness_inputs( + program: &'static stage5::Stage5CpuProgramPlan, + opening_inputs: &[stage5::Stage5OpeningInputValue], + trace_len: usize, + ram_k: usize, + register_count: usize, + lookup_indices: &[u128], + lookup_table_indices: &[Option], + is_interleaved_operands: &[bool], + ra_virtual_log_k_chunk: usize, + register_accesses: &[stage4::Stage4RegisterAccess], + ram_accesses: &[stage2::Stage2RamAccess], + transcript: &mut T, +) -> Result, stage5::Stage5KernelError> +where + T: Transcript, +{ + let witness = stage4::stage4_5_sparse_trace_witness_from_accesses( + register_accesses, + ram_accesses, + ); + prove_stage5_with_witness_inputs( + program, + opening_inputs, + trace_len, + ram_k, + register_count, + lookup_indices, + lookup_table_indices, + is_interleaved_operands, + ra_virtual_log_k_chunk, + &witness, + transcript, + ) +} + +pub fn stage5_opening_inputs_from_artifacts( + program: &'static stage5::Stage5CpuProgramPlan, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage4_artifacts: &stage4::Stage4ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = match input.source_stage { + "stage2" => stage2_opening_claim(stage2_artifacts, input.source_claim)?, + "stage4" => stage4_opening_claim(stage4_artifacts, input.source_claim)?, + source_stage => { + return Err(JoltOpeningInputError::UnsupportedOpeningInputSource { + stage: "stage5", + symbol: input.symbol, + source_stage, + }); + } + }; + opening_input_value(input.symbol, input.point_arity, point, eval) + }) + .collect() +} + +pub fn stage5_kernel_proof( + artifacts: &stage5::Stage5ExecutionArtifacts, +) -> stage5::Stage5Proof { + stage5::Stage5Proof { + sumchecks: artifacts.sumchecks.clone(), + } +} + +pub fn jolt_proof_through_stage5( + commitments: &[Option], + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage3_artifacts: &stage3::Stage3ExecutionArtifacts, + stage4_artifacts: &stage4::Stage4ExecutionArtifacts, + stage5_proof: &JoltStageProof, +) -> JoltProof { + JoltProof { + commitments: commitments.to_vec(), + stage1_outer: stage1_outer_proof(stage1_artifacts), + stage2: stage2_proof(stage2_artifacts), + stage3: stage3_proof(stage3_artifacts), + stage4: stage4_proof(stage4_artifacts), + stage5: stage5_proof.clone(), + stage6: JoltStageProof::default(), + stage7: JoltStageProof::default(), + evaluation: None, + } +} + +pub fn jolt_proof_through_stage6( + commitments: &[Option], + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage3_artifacts: &stage3::Stage3ExecutionArtifacts, + stage4_artifacts: &stage4::Stage4ExecutionArtifacts, + stage5_proof: &JoltStageProof, + stage6_proof: &JoltStageProof, +) -> JoltProof { + let mut proof = jolt_proof_through_stage5( + commitments, + stage1_artifacts, + stage2_artifacts, + stage3_artifacts, + stage4_artifacts, + stage5_proof, + ); + proof.stage6 = stage6_proof.clone(); + proof +} + +pub fn jolt_proof_through_stage7( + commitments: &[Option], + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage3_artifacts: &stage3::Stage3ExecutionArtifacts, + stage4_artifacts: &stage4::Stage4ExecutionArtifacts, + stage5_proof: &JoltStageProof, + stage6_proof: &JoltStageProof, + stage7_proof: &JoltStageProof, +) -> JoltProof { + let mut proof = jolt_proof_through_stage6( + commitments, + stage1_artifacts, + stage2_artifacts, + stage3_artifacts, + stage4_artifacts, + stage5_proof, + stage6_proof, + ); + proof.stage7 = stage7_proof.clone(); + proof +} + +pub fn replay_stage5_proof_with_program( + program: &'static stage5::Stage5CpuProgramPlan, + proof: &stage5::Stage5Proof, + opening_inputs: &[stage5::Stage5OpeningInputValue], + transcript: &mut T, +) -> Result, stage5::Stage5KernelError> +where + T: Transcript, +{ + let mut executor = stage5::Stage5ProofCarryingKernelExecutor::new(proof, opening_inputs); + stage5_stage::execute_stage5_prover_with_program(program, &mut executor, transcript) +} + +pub fn stage6_witness_from_opening_inputs( + params: Stage6WitnessParams, + cycle_inputs: &[CycleInput], + opening_inputs: &[stage6::Stage6OpeningInputValue], +) -> Stage6WitnessPolynomials { + stage6::stage6_witness_from_opening_inputs(params, cycle_inputs, opening_inputs) +} + +pub fn stage6_bytecode_read_raf_data_from_witness_entries( + entries: &[WitnessStage6BytecodeEntry], + entry_bytecode_index: usize, + num_lookup_tables: usize, +) -> stage6::Stage6BytecodeReadRafDataStorage { + stage6::Stage6BytecodeReadRafDataStorage::from_witness_entries( + entries, + entry_bytecode_index, + num_lookup_tables, + ) +} + +pub fn stage6_verifier_data_from_witness_entries( + entries: &[WitnessStage6BytecodeEntry], + entry_bytecode_index: usize, + num_lookup_tables: usize, +) -> JoltStage6VerifierData { + JoltStage6VerifierData { + bytecode_read_raf: Some(JoltStage6BytecodeReadRafData { + entries: entries + .iter() + .map(|entry| JoltStage6BytecodeEntry { + address: entry.address, + imm: entry.imm, + circuit_flags: entry.circuit_flags, + rd: entry.rd, + rs1: entry.rs1, + rs2: entry.rs2, + lookup_table: entry.lookup_table, + is_interleaved: entry.is_interleaved, + is_branch: entry.is_branch, + left_is_rs1: entry.left_is_rs1, + left_is_pc: entry.left_is_pc, + right_is_rs2: entry.right_is_rs2, + right_is_imm: entry.right_is_imm, + is_noop: entry.is_noop, + }) + .collect(), + entry_bytecode_index, + num_lookup_tables, + }), + } +} + +pub fn stage6_prover_inputs<'a>( + opening_inputs: &'a [stage6::Stage6OpeningInputValue], + bytecode_data: stage6::Stage6BytecodeReadRafData<'a, Fr>, + witness: &'a Stage6WitnessPolynomials, + slices: &'a Stage6WitnessSlices<'a, Fr>, + instruction_ra_virtual_d: usize, +) -> stage6::Stage6ProverInputs<'a, Fr> { + stage6::Stage6ProverInputs::new(opening_inputs).with_stage6_witness( + bytecode_data, + witness, + slices, + instruction_ra_virtual_d, + ) +} + +pub fn prove_stage6_inputs_with_program( + program: &'static stage6::Stage6CpuProgramPlan, + inputs: stage6::Stage6ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage6::Stage6KernelError> +where + T: Transcript, +{ + let mut executor = stage6::Stage6ProverKernelExecutor::new(inputs); + stage6_stage::execute_stage6_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage6_with_witness_inputs( + program: &'static stage6::Stage6CpuProgramPlan, + opening_inputs: &[stage6::Stage6OpeningInputValue], + bytecode_data: stage6::Stage6BytecodeReadRafData<'_, Fr>, + witness: &Stage6WitnessPolynomials, + slices: &Stage6WitnessSlices<'_, Fr>, + instruction_ra_virtual_d: usize, + transcript: &mut T, +) -> Result, stage6::Stage6KernelError> +where + T: Transcript, +{ + let inputs = stage6_prover_inputs( + opening_inputs, + bytecode_data, + witness, + slices, + instruction_ra_virtual_d, + ); + prove_stage6_inputs_with_program(program, inputs, transcript) +} + +pub fn prove_stage6_with_trace_witness_inputs( + program: &'static stage6::Stage6CpuProgramPlan, + opening_inputs: &[stage6::Stage6OpeningInputValue], + bytecode_data: stage6::Stage6BytecodeReadRafData<'_, Fr>, + witness_params: Stage6WitnessParams, + cycle_inputs: &[CycleInput], + instruction_ra_virtual_d: usize, + transcript: &mut T, +) -> Result, stage6::Stage6KernelError> +where + T: Transcript, +{ + let witness = stage6_witness_from_opening_inputs(witness_params, cycle_inputs, opening_inputs); + let slices = witness.slices(); + prove_stage6_with_witness_inputs( + program, + opening_inputs, + bytecode_data, + &witness, + &slices, + instruction_ra_virtual_d, + transcript, + ) +} + +pub fn stage6_opening_inputs_from_artifacts( + program: &'static stage6::Stage6CpuProgramPlan, + stage1_artifacts: &stage1::Stage1ExecutionArtifacts, + stage2_artifacts: &stage2::Stage2ExecutionArtifacts, + stage3_artifacts: &stage3::Stage3ExecutionArtifacts, + stage4_artifacts: &stage4::Stage4ExecutionArtifacts, + stage5_artifacts: &stage5::Stage5ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = match input.source_stage { + "stage1" => stage1_opening_claim(stage1_artifacts, input.source_claim)?, + "stage2" => stage2_opening_claim(stage2_artifacts, input.source_claim)?, + "stage3" => stage3_opening_claim(stage3_artifacts, input.source_claim)?, + "stage4" => stage4_opening_claim(stage4_artifacts, input.source_claim)?, + "stage5" => stage5_opening_claim(stage5_artifacts, input.source_claim)?, + source_stage => { + return Err(JoltOpeningInputError::UnsupportedOpeningInputSource { + stage: "stage6", + symbol: input.symbol, + source_stage, + }); + } + }; + opening_input_value(input.symbol, input.point_arity, point, eval) + }) + .collect() +} + +pub fn stage6_kernel_proof(proof: &JoltStageProof) -> stage6::Stage6Proof { + stage6::Stage6Proof { + sumchecks: proof + .sumchecks + .iter() + .map(stage6_kernel_sumcheck_output) + .collect(), + } +} + +fn stage6_kernel_sumcheck_output( + output: &JoltSumcheckOutput, +) -> stage6::Stage6SumcheckOutput { + stage6::Stage6SumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage6_kernel_eval).collect(), + opening_claims: Vec::new(), + proof: output.proof.clone(), + } +} + +fn stage6_kernel_eval(eval: &JoltNamedEval) -> stage6::Stage6NamedEval { + stage6::Stage6NamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage6_execution_artifacts( + artifacts: &stage6::Stage6ExecutionArtifacts, +) -> JoltStageExecutionArtifacts { + JoltStageExecutionArtifacts { + challenge_vectors: artifacts + .challenge_vectors + .iter() + .map(|challenge| JoltStageChallengeVector { + symbol: challenge.symbol, + values: challenge.values.clone(), + }) + .collect(), + sumchecks: stage6_proof(artifacts).sumchecks, + opening_batches: Vec::new(), + } +} + +pub fn replay_stage6_proof_with_program<'a, T>( + program: &'static stage6::Stage6CpuProgramPlan, + proof: &'a stage6::Stage6Proof, + opening_inputs: &'a [stage6::Stage6OpeningInputValue], + bytecode_data: Option>, + transcript: &mut T, +) -> Result, stage6::Stage6KernelError> +where + T: Transcript, +{ + let mut executor = stage6::Stage6ProofCarryingKernelExecutor::new(proof, opening_inputs); + if let Some(bytecode_data) = bytecode_data { + executor = executor.with_bytecode_read_raf_data(bytecode_data); + } + stage6_stage::execute_stage6_prover_with_program(program, &mut executor, transcript) +} + +pub fn stage7_prover_inputs<'a>( + opening_inputs: &'a [stage7::Stage7OpeningInputValue], + slices: &'a Stage6WitnessSlices<'a, Fr>, +) -> stage7::Stage7ProverInputs<'a, Fr> { + stage7::Stage7ProverInputs::new(opening_inputs).with_stage6_witness_indices(slices) +} + +pub fn prove_stage7_inputs_with_program( + program: &'static stage7::Stage7CpuProgramPlan, + inputs: stage7::Stage7ProverInputs<'_, Fr>, + transcript: &mut T, +) -> Result, stage7::Stage7KernelError> +where + T: Transcript, +{ + let mut executor = stage7::Stage7ProverKernelExecutor::new(inputs); + stage7_stage::execute_stage7_prover_with_program(program, &mut executor, transcript) +} + +pub fn prove_stage7_with_witness_inputs( + program: &'static stage7::Stage7CpuProgramPlan, + opening_inputs: &[stage7::Stage7OpeningInputValue], + slices: &Stage6WitnessSlices<'_, Fr>, + transcript: &mut T, +) -> Result, stage7::Stage7KernelError> +where + T: Transcript, +{ + let inputs = stage7_prover_inputs(opening_inputs, slices); + prove_stage7_inputs_with_program(program, inputs, transcript) +} + +pub fn prove_stage7_with_trace_witness_inputs( + program: &'static stage7::Stage7CpuProgramPlan, + opening_inputs: &[stage7::Stage7OpeningInputValue], + witness_params: Stage6WitnessParams, + cycle_inputs: &[CycleInput], + stage6_openings: &[stage6::Stage6OpeningInputValue], + transcript: &mut T, +) -> Result, stage7::Stage7KernelError> +where + T: Transcript, +{ + let witness = stage6_witness_from_opening_inputs(witness_params, cycle_inputs, stage6_openings); + let slices = witness.slices(); + prove_stage7_with_witness_inputs(program, opening_inputs, &slices, transcript) +} + +pub fn stage7_kernel_proof(proof: &JoltStageProof) -> stage7::Stage7Proof { + stage7::Stage7Proof { + sumchecks: proof + .sumchecks + .iter() + .map(stage7_kernel_sumcheck_output) + .collect(), + } +} + +fn stage7_kernel_sumcheck_output( + output: &JoltSumcheckOutput, +) -> stage7::Stage7SumcheckOutput { + stage7::Stage7SumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage7_kernel_eval).collect(), + opening_claims: Vec::new(), + proof: output.proof.clone(), + } +} + +fn stage7_kernel_eval(eval: &JoltNamedEval) -> stage7::Stage7NamedEval { + stage7::Stage7NamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage7_execution_artifacts( + artifacts: &stage7::Stage7ExecutionArtifacts, +) -> JoltStageExecutionArtifacts { + JoltStageExecutionArtifacts { + challenge_vectors: artifacts + .challenge_vectors + .iter() + .map(|challenge| JoltStageChallengeVector { + symbol: challenge.symbol, + values: challenge.values.clone(), + }) + .collect(), + sumchecks: stage7_proof(artifacts).sumchecks, + opening_batches: Vec::new(), + } +} + +pub fn replay_stage7_proof_with_program( + program: &'static stage7::Stage7CpuProgramPlan, + proof: &stage7::Stage7Proof, + opening_inputs: &[stage7::Stage7OpeningInputValue], + transcript: &mut T, +) -> Result, stage7::Stage7KernelError> +where + T: Transcript, +{ + let mut executor = stage7::Stage7ProofCarryingKernelExecutor::new(proof, opening_inputs); + stage7_stage::execute_stage7_prover_with_program(program, &mut executor, transcript) +} + +pub fn stage7_opening_inputs_from_stage6_artifacts( + artifacts: &stage6::Stage6ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + stage7_opening_inputs_from_stage6_artifacts_with_program(&stage7_stage::STAGE7_PROGRAM, artifacts) +} + +pub fn stage7_opening_inputs_from_stage6_artifacts_with_program( + program: &'static stage7::Stage7CpuProgramPlan, + artifacts: &stage6::Stage6ExecutionArtifacts, +) -> Result>, JoltOpeningInputError> { + program + .opening_inputs + .iter() + .map(|input| { + let (point, eval) = stage6_opening_claim(artifacts, input.symbol, input.source_stage, input.source_claim, input.point_arity)?; + Ok(stage7::Stage7OpeningInputValue { + symbol: input.symbol, + point, + eval, + }) + }) + .collect() +} + +fn stage6_opening_claim( + artifacts: &stage6::Stage6ExecutionArtifacts, + symbol: &'static str, + source_stage: &'static str, + source_claim: &'static str, + point_arity: usize, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + if source_stage != "stage6" { + return Err(JoltOpeningInputError::UnsupportedStage7InputSource { + symbol, + source_stage, + }); + } + let opening = artifacts + .opening_claims + .iter() + .find(|opening| opening.symbol == source_claim) + .ok_or(JoltOpeningInputError::MissingStage6OpeningClaim { source_claim })?; + if opening.point.len() != point_arity { + return Err(JoltOpeningInputError::InvalidPointLength { + symbol, + expected: point_arity, + actual: opening.point.len(), + }); + } + Ok((opening.point.clone(), opening.eval)) +} + +fn opening_input_value( + symbol: &'static str, + point_arity: usize, + point: Vec, + eval: Fr, +) -> Result, JoltOpeningInputError> { + validate_point_len(symbol, point_arity, point.len())?; + Ok(stage4::Stage4OpeningInputValue { + symbol, + point, + eval, + }) +} + +fn validate_point_len( + symbol: &'static str, + expected: usize, + actual: usize, +) -> Result<(), JoltOpeningInputError> { + if actual != expected { + return Err(JoltOpeningInputError::InvalidPointLength { + symbol, + expected, + actual, + }); + } + Ok(()) +} + +fn stage1_opening_claim( + artifacts: &stage1::Stage1ExecutionArtifacts, + source_claim: &'static str, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + let opening = artifacts.opening_value(source_claim).ok_or( + JoltOpeningInputError::MissingOpeningClaim { + stage: "stage1", + source_claim, + }, + )?; + Ok((opening.point.clone(), opening.eval)) +} + +fn stage2_opening_claim( + artifacts: &stage2::Stage2ExecutionArtifacts, + source_claim: &'static str, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + artifacts + .opening_claims + .iter() + .find(|opening| opening.symbol == source_claim) + .map(|opening| (opening.point.clone(), opening.eval)) + .ok_or(JoltOpeningInputError::MissingOpeningClaim { + stage: "stage2", + source_claim, + }) +} + +fn stage3_opening_claim( + artifacts: &stage3::Stage3ExecutionArtifacts, + source_claim: &'static str, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + artifacts + .opening_claims + .iter() + .find(|opening| opening.symbol == source_claim) + .map(|opening| (opening.point.clone(), opening.eval)) + .ok_or(JoltOpeningInputError::MissingOpeningClaim { + stage: "stage3", + source_claim, + }) +} + +fn stage4_opening_claim( + artifacts: &stage4::Stage4ExecutionArtifacts, + source_claim: &'static str, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + artifacts + .opening_claims + .iter() + .find(|opening| opening.symbol == source_claim) + .map(|opening| (opening.point.clone(), opening.eval)) + .ok_or(JoltOpeningInputError::MissingOpeningClaim { + stage: "stage4", + source_claim, + }) +} + +fn stage5_opening_claim( + artifacts: &stage5::Stage5ExecutionArtifacts, + source_claim: &'static str, +) -> Result<(Vec, Fr), JoltOpeningInputError> { + artifacts + .opening_claims + .iter() + .find(|opening| opening.symbol == source_claim) + .map(|opening| (opening.point.clone(), opening.eval)) + .ok_or(JoltOpeningInputError::MissingOpeningClaim { + stage: "stage5", + source_claim, + }) +} + +pub fn stage1_outer_proof(artifacts: &stage1::Stage1ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage1_outer_sumcheck).collect(), + } +} + +fn stage1_outer_sumcheck(output: &stage1::Stage1SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage1_outer_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage1_outer_eval(eval: &stage1::Stage1NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage2_proof(artifacts: &stage2::Stage2ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage2_sumcheck).collect(), + } +} + +fn stage2_sumcheck(output: &stage2::Stage2SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage2_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage2_eval(eval: &stage2::Stage2NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage3_proof(artifacts: &stage3::Stage3ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage3_sumcheck).collect(), + } +} + +fn stage3_sumcheck(output: &stage3::Stage3SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage3_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage3_eval(eval: &stage3::Stage3NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage4_proof(artifacts: &stage4::Stage4ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage4_sumcheck).collect(), + } +} + +fn stage4_sumcheck(output: &stage4::Stage4SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage4_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage4_eval(eval: &stage4::Stage4NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage5_proof(artifacts: &stage5::Stage5ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage5_sumcheck).collect(), + } +} + +fn stage5_sumcheck(output: &stage5::Stage5SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage5_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage5_eval(eval: &stage5::Stage5NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage6_proof(artifacts: &stage6::Stage6ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage6_sumcheck).collect(), + } +} + +fn stage6_sumcheck(output: &stage6::Stage6SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage6_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage6_eval(eval: &stage6::Stage6NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} + +pub fn stage7_proof(artifacts: &stage7::Stage7ExecutionArtifacts) -> JoltStageProof { + JoltStageProof { + sumchecks: artifacts.sumchecks.iter().map(stage7_sumcheck).collect(), + } +} + +fn stage7_sumcheck(output: &stage7::Stage7SumcheckOutput) -> JoltSumcheckOutput { + JoltSumcheckOutput { + driver: output.driver, + point: output.point.clone(), + evals: output.evals.iter().map(stage7_eval).collect(), + proof: output.proof.clone(), + } +} + +fn stage7_eval(eval: &stage7::Stage7NamedEval) -> JoltNamedEval { + JoltNamedEval { + name: eval.name, + oracle: eval.oracle, + value: eval.value, + } +} diff --git a/crates/jolt-prover/src/stages/commitment.rs b/crates/jolt-prover/src/stages/commitment.rs new file mode 100644 index 0000000000..eb744d8c88 --- /dev/null +++ b/crates/jolt-prover/src/stages/commitment.rs @@ -0,0 +1,1075 @@ +#![allow(dead_code)] + +use std::borrow::Cow; + +use jolt_dory::{DoryCommitment, DoryHint, DoryProverSetup, DoryScheme}; +use jolt_field::Fr; +use jolt_openings::CommitmentScheme as _; +use jolt_poly::{EqPolynomial, MultilinearPoly}; +use jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript}; +use jolt_witness::{dense_i128_column_to_field, one_hot_chunk_address_major, one_hot_chunk_indices, optional_field_oracle, CommitmentTraceSources}; +use rayon::prelude::*; + +pub type DefaultCommitmentTranscript = Blake2bTranscript; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentParams { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OraclePlan { + pub oracle: &'static str, + pub domain: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentBatchPlan { + pub artifact: &'static str, + pub pcs: &'static str, + pub oracle_family: &'static str, + pub label: &'static str, + pub oracles: &'static [&'static str], + pub count: usize, + pub domain: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OptionalSkipPolicy { + MissingOrZero, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OptionalCommitmentPlan { + pub artifact: &'static str, + pub pcs: &'static str, + pub oracle: &'static str, + pub label: &'static str, + pub domain: &'static str, + pub num_vars: usize, + pub skip_policy: OptionalSkipPolicy, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TranscriptStep { + pub label: &'static str, + pub source: &'static str, + pub optional: bool, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentProverProgramPlan { + pub params: CommitmentParams, + pub oracle_plans: &'static [OraclePlan], + pub batch_plans: &'static [CommitmentBatchPlan], + pub optional_plans: &'static [OptionalCommitmentPlan], + pub transcript_steps: &'static [TranscriptStep], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentRecord { + pub artifact: &'static str, + pub oracle: &'static str, + pub label: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Debug)] +pub struct OracleOpeningHint { + pub oracle: &'static str, + pub hint: DoryHint, +} + +#[derive(Clone, Debug)] +pub struct CommittedOracle { + pub commitment: Option, + pub record: CommitmentRecord, + pub hint: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct CommitmentArtifacts { + pub commitments: Vec>, + pub records: Vec, + pub hints: Vec, +} + +pub trait CommitmentInputProvider { + fn materialize(&mut self, oracle: &'static str) -> Option>; + + fn materialize_with_num_vars( + &mut self, + oracle: &'static str, + _num_vars: usize, + ) -> Option> { + self.materialize(oracle) + } + + fn commit_batch( + &mut self, + _program: &CommitmentProverProgramPlan, + _plan: &CommitmentBatchPlan, + _prover_setup: &DoryProverSetup, + ) -> Option, CommitmentPhaseError>> { + None + } + + fn add_scaled_to_joint( + &mut self, + _oracle: &'static str, + _joint: &mut [Fr], + _num_vars: usize, + _limit: usize, + _scalar: Fr, + ) -> bool { + false + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CommitmentPhaseError { + MissingOracle { oracle: &'static str }, + MissingTranscriptSource { source: &'static str }, + PlanCountMismatch { artifact: &'static str, expected: usize, actual: usize }, + OracleTooLarge { oracle: &'static str, len: usize, target_len: usize }, + TargetSizeOverflow { num_vars: usize }, +} + +pub struct CommitmentOracleInputs<'a> { + pub rd_inc: &'a [i128], + pub ram_inc: &'a [i128], + pub instruction_keys: &'a [Option], + pub ram_addresses: &'a [Option], + pub bytecode_indices: &'a [Option], + pub untrusted_advice: Option<&'a [Fr]>, + pub trusted_advice: Option<&'a [Fr]>, +} + +impl<'a> CommitmentOracleInputs<'a> { + pub fn from_trace_sources( + sources: &'a CommitmentTraceSources, + untrusted_advice: Option<&'a [Fr]>, + trusted_advice: Option<&'a [Fr]>, + ) -> Self { + Self { + rd_inc: &sources.rd_inc, + ram_inc: &sources.ram_inc, + instruction_keys: &sources.instruction_keys, + ram_addresses: &sources.ram_addresses, + bytecode_indices: &sources.bytecode_indices, + untrusted_advice, + trusted_advice, + } + } +} + + +struct AddressMajorOneHotPolynomial { + trace_len: usize, + chunk_domain: usize, + indices: Vec>, + num_vars: usize, +} + +impl AddressMajorOneHotPolynomial { + fn new( + trace_len: usize, + chunk_domain: usize, + indices: Vec>, + num_vars: usize, + ) -> Result { + let active_len = trace_len + .checked_mul(chunk_domain) + .ok_or(CommitmentPhaseError::TargetSizeOverflow { num_vars })?; + let target_len = target_len(num_vars)?; + if active_len > target_len { + return Err(CommitmentPhaseError::OracleTooLarge { + oracle: "one_hot", + len: active_len, + target_len, + }); + } + Ok(Self { + trace_len, + chunk_domain, + indices, + num_vars, + }) + } + + fn nonzero_flat_indices(&self) -> impl Iterator + '_ { + self.indices + .iter() + .enumerate() + .filter_map(|(cycle, &index)| { + index.map(|index| { + let index = index as usize; + assert!( + index < self.chunk_domain, + "one-hot index {index} exceeds domain {}", + self.chunk_domain + ); + index * self.trace_len + cycle + }) + }) + } +} + +impl MultilinearPoly for AddressMajorOneHotPolynomial { + fn num_vars(&self) -> usize { + self.num_vars + } + + fn evaluate(&self, point: &[Fr]) -> Fr { + assert_eq!(point.len(), self.num_vars); + let eq_evals = EqPolynomial::new(point.to_vec()).evaluations(); + self.nonzero_flat_indices() + .fold(Fr::from_u64(0), |acc, flat| acc + eq_evals[flat]) + } + + fn for_each_row(&self, sigma: usize, f: &mut dyn FnMut(usize, &[Fr])) { + let num_cols = 1usize << sigma; + let num_rows = 1usize << (self.num_vars - sigma); + let mut entries = Vec::with_capacity(self.indices.len()); + for flat in self.nonzero_flat_indices() { + entries.push((flat / num_cols, flat % num_cols)); + } + entries.sort_unstable_by_key(|(row, _)| *row); + + let mut cursor = 0; + let mut row = vec![Fr::from_u64(0); num_cols]; + for row_index in 0..num_rows { + row.fill(Fr::from_u64(0)); + while cursor < entries.len() && entries[cursor].0 == row_index { + row[entries[cursor].1] = Fr::from_u64(1); + cursor += 1; + } + f(row_index, &row); + } + } + + fn fold_rows(&self, left: &[Fr], sigma: usize) -> Vec { + let num_cols = 1usize << sigma; + let num_rows = 1usize << (self.num_vars - sigma); + assert_eq!(left.len(), num_rows); + let mut result = vec![Fr::from_u64(0); num_cols]; + for flat in self.nonzero_flat_indices() { + result[flat % num_cols] += left[flat / num_cols]; + } + result + } + + fn is_one_hot(&self) -> bool { + true + } + + fn for_each_one(&self, f: &mut dyn FnMut(usize)) { + for flat in self.nonzero_flat_indices() { + f(flat); + } + } +} + +pub struct SparseCommitmentInputs<'a> { + pub inputs: CommitmentOracleInputs<'a>, + cache: std::collections::BTreeMap<(&'static str, usize), Option>>, + chunk_counts: OneHotChunkCounts, +} + +impl<'a> SparseCommitmentInputs<'a> { + pub fn new(inputs: CommitmentOracleInputs<'a>) -> Self { + Self { + inputs, + cache: std::collections::BTreeMap::new(), + chunk_counts: OneHotChunkCounts::default(), + } + } + + fn update_chunk_counts(&mut self, program: &CommitmentProverProgramPlan) { + let mut counts = OneHotChunkCounts::default(); + let mut instruction = 0; + let mut ram = 0; + let mut bytecode = 0; + for plan in program.oracle_plans { + if plan.oracle.strip_prefix("InstructionRa_").is_some() { + instruction += 1; + } else if plan.oracle.strip_prefix("RamRa_").is_some() { + ram += 1; + } else if plan.oracle.strip_prefix("BytecodeRa_").is_some() { + bytecode += 1; + } + } + if instruction > 0 { + counts.instruction = instruction; + } + if ram > 0 { + counts.ram = ram; + } + if bytecode > 0 { + counts.bytecode = bytecode; + } + self.chunk_counts = counts; + } + + fn one_hot_spec(&self, oracle: &'static str) -> Option { + let (prefix, num_chunks, values, padding) = + if let Some(suffix) = oracle.strip_prefix("InstructionRa_") { + ( + suffix, + self.chunk_counts.instruction, + OneHotSource::InstructionKeys, + Some(0), + ) + } else if let Some(suffix) = oracle.strip_prefix("RamRa_") { + ( + suffix, + self.chunk_counts.ram, + OneHotSource::RamAddresses, + None, + ) + } else if let Some(suffix) = oracle.strip_prefix("BytecodeRa_") { + ( + suffix, + self.chunk_counts.bytecode, + OneHotSource::BytecodeIndices, + Some(0), + ) + } else { + return None; + }; + let chunk = prefix.parse::().ok()?; + if chunk >= num_chunks { + return None; + } + Some(OneHotSpec { + source: values, + chunk, + num_chunks, + chunk_bits: 4, + padding, + }) + } + + fn source_values(&self, source: OneHotSource) -> &'a [Option] { + match source { + OneHotSource::InstructionKeys => self.inputs.instruction_keys, + OneHotSource::RamAddresses => self.inputs.ram_addresses, + OneHotSource::BytecodeIndices => self.inputs.bytecode_indices, + } + } + + fn one_hot_indices( + &self, + oracle: &'static str, + trace_len: usize, + ) -> Option>> { + let spec = self.one_hot_spec(oracle)?; + let values = self.source_values(spec.source); + Some(one_hot_chunk_indices( + values, + spec.chunk, + spec.num_chunks, + spec.chunk_bits, + trace_len, + spec.padding, + )) + } + + #[expect( + clippy::option_option, + reason = "distinguishes missing oracle from present optional oracle" + )] + fn materialize_oracle( + &self, + oracle: &'static str, + num_vars: usize, + ) -> Option>> { + let materialized = match oracle { + "RdInc" => Some(dense_i128_column_to_field( + self.inputs.rd_inc, + target_len(num_vars).ok()?, + )), + "RamInc" => Some(dense_i128_column_to_field( + self.inputs.ram_inc, + target_len(num_vars).ok()?, + )), + "UntrustedAdvice" => optional_field_oracle( + self.inputs.untrusted_advice, + target_len(num_vars).ok()?, + ), + "TrustedAdvice" => { + optional_field_oracle(self.inputs.trusted_advice, target_len(num_vars).ok()?) + } + _ => { + let spec = self.one_hot_spec(oracle)?; + let trace_len = target_len(num_vars.checked_sub(spec.chunk_bits)?).ok()?; + let values = self.source_values(spec.source); + Some(one_hot_chunk_address_major( + values, + spec.chunk, + spec.num_chunks, + spec.chunk_bits, + trace_len, + spec.padding, + )) + } + }; + Some(materialized) + } + + fn commit_oracle( + &self, + program: &CommitmentProverProgramPlan, + oracle: &'static str, + layout_num_vars: usize, + prover_setup: &DoryProverSetup, + ) -> Result<(DoryCommitment, DoryHint), CommitmentPhaseError> { + let oracle_num_vars = oracle_num_vars(program, oracle, layout_num_vars); + if let Some(spec) = self.one_hot_spec(oracle) { + let trace_len = target_len(oracle_num_vars - spec.chunk_bits)?; + let chunk_domain = target_len(spec.chunk_bits)?; + let indices = self + .one_hot_indices(oracle, trace_len) + .ok_or(CommitmentPhaseError::MissingOracle { oracle })?; + let poly = AddressMajorOneHotPolynomial::new( + trace_len, + chunk_domain, + indices, + layout_num_vars, + )?; + let _dory_commit_span = tracing::info_span!("bolt.commitment.dory_commit").entered(); + Ok(DoryScheme::commit(&poly, prover_setup)) + } else { + let data = self + .materialize_oracle(oracle, oracle_num_vars) + .flatten() + .ok_or(CommitmentPhaseError::MissingOracle { oracle })?; + let data = into_padded_oracle(oracle, oracle_num_vars, Cow::Owned(data))?; + commit_with_layout(&data, layout_num_vars, prover_setup) + } + } +} + +impl CommitmentInputProvider for SparseCommitmentInputs<'_> { + fn materialize(&mut self, oracle: &'static str) -> Option> { + let num_vars = match oracle { + "RdInc" | "RamInc" | "UntrustedAdvice" | "TrustedAdvice" => 16, + _ if self.one_hot_spec(oracle).is_some() => 20, + _ => return None, + }; + self.materialize_with_num_vars(oracle, num_vars) + } + + fn materialize_with_num_vars( + &mut self, + oracle: &'static str, + num_vars: usize, + ) -> Option> { + if !self.cache.contains_key(&(oracle, num_vars)) { + let materialized = self.materialize_oracle(oracle, num_vars).flatten(); + let _ = self.cache.insert((oracle, num_vars), materialized); + } + self.cache + .get(&(oracle, num_vars)) + .and_then(|values| values.as_ref()) + .map(|values| Cow::Borrowed(values.as_slice())) + } + + fn commit_batch( + &mut self, + program: &CommitmentProverProgramPlan, + plan: &CommitmentBatchPlan, + prover_setup: &DoryProverSetup, + ) -> Option, CommitmentPhaseError>> { + self.update_chunk_counts(program); + Some( + plan.oracles + .par_iter() + .map(|&oracle| { + let oracle_num_vars = oracle_num_vars(program, oracle, plan.num_vars); + let (commitment, hint) = + self.commit_oracle(program, oracle, plan.num_vars, prover_setup)?; + Ok(CommittedOracle { + commitment: Some(commitment), + record: CommitmentRecord { + artifact: plan.artifact, + oracle, + label: plan.label, + num_vars: oracle_num_vars, + }, + hint: Some(OracleOpeningHint { oracle, hint }), + }) + }) + .collect(), + ) + } + + fn add_scaled_to_joint( + &mut self, + oracle: &'static str, + joint: &mut [Fr], + num_vars: usize, + limit: usize, + scalar: Fr, + ) -> bool { + let dense = match oracle { + "RdInc" => Some(self.inputs.rd_inc), + "RamInc" => Some(self.inputs.ram_inc), + _ => None, + }; + if let Some(values) = dense { + let Ok(target_len) = target_len(num_vars) else { + return false; + }; + let len = limit.min(joint.len()).min(values.len()).min(target_len); + for (dst, &value) in joint.iter_mut().take(len).zip(values.iter()) { + if value != 0 { + *dst += Fr::from_i128(value) * scalar; + } + } + return true; + } + + let Some(spec) = self.one_hot_spec(oracle) else { + return false; + }; + let Some(trace_num_vars) = num_vars.checked_sub(spec.chunk_bits) else { + return false; + }; + let Ok(trace_len) = target_len(trace_num_vars) else { + return false; + }; + let Ok(chunk_domain) = target_len(spec.chunk_bits) else { + return false; + }; + let Some(active_len) = trace_len.checked_mul(chunk_domain) else { + return false; + }; + let max_flat = limit.min(joint.len()).min(active_len); + let Some(indices) = self.one_hot_indices(oracle, trace_len) else { + return false; + }; + for (cycle, index) in indices.into_iter().enumerate() { + let Some(index) = index else { + continue; + }; + let flat = index as usize * trace_len + cycle; + if flat < max_flat { + joint[flat] += scalar; + } + } + true + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum OneHotSource { + InstructionKeys, + RamAddresses, + BytecodeIndices, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct OneHotSpec { + source: OneHotSource, + chunk: usize, + num_chunks: usize, + chunk_bits: usize, + padding: Option, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct OneHotChunkCounts { + instruction: usize, + ram: usize, + bytecode: usize, +} + +impl Default for OneHotChunkCounts { + fn default() -> Self { + Self { + instruction: 32, + ram: 4, + bytecode: 3, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct CommitmentOracles { + pub rd_inc: Vec, + pub ram_inc: Vec, + pub instruction_ra_0: Vec, + pub instruction_ra_1: Vec, + pub instruction_ra_2: Vec, + pub instruction_ra_3: Vec, + pub instruction_ra_4: Vec, + pub instruction_ra_5: Vec, + pub instruction_ra_6: Vec, + pub instruction_ra_7: Vec, + pub instruction_ra_8: Vec, + pub instruction_ra_9: Vec, + pub instruction_ra_10: Vec, + pub instruction_ra_11: Vec, + pub instruction_ra_12: Vec, + pub instruction_ra_13: Vec, + pub instruction_ra_14: Vec, + pub instruction_ra_15: Vec, + pub instruction_ra_16: Vec, + pub instruction_ra_17: Vec, + pub instruction_ra_18: Vec, + pub instruction_ra_19: Vec, + pub instruction_ra_20: Vec, + pub instruction_ra_21: Vec, + pub instruction_ra_22: Vec, + pub instruction_ra_23: Vec, + pub instruction_ra_24: Vec, + pub instruction_ra_25: Vec, + pub instruction_ra_26: Vec, + pub instruction_ra_27: Vec, + pub instruction_ra_28: Vec, + pub instruction_ra_29: Vec, + pub instruction_ra_30: Vec, + pub instruction_ra_31: Vec, + pub ram_ra_0: Vec, + pub ram_ra_1: Vec, + pub ram_ra_2: Vec, + pub ram_ra_3: Vec, + pub bytecode_ra_0: Vec, + pub bytecode_ra_1: Vec, + pub bytecode_ra_2: Vec, + pub untrusted_advice: Option>, + pub trusted_advice: Option>, +} + +impl CommitmentInputProvider for CommitmentOracles { + fn materialize(&mut self, oracle: &'static str) -> Option> { + match oracle { + "RdInc" => Some(Cow::Borrowed(&self.rd_inc)), + "RamInc" => Some(Cow::Borrowed(&self.ram_inc)), + "InstructionRa_0" => Some(Cow::Borrowed(&self.instruction_ra_0)), + "InstructionRa_1" => Some(Cow::Borrowed(&self.instruction_ra_1)), + "InstructionRa_2" => Some(Cow::Borrowed(&self.instruction_ra_2)), + "InstructionRa_3" => Some(Cow::Borrowed(&self.instruction_ra_3)), + "InstructionRa_4" => Some(Cow::Borrowed(&self.instruction_ra_4)), + "InstructionRa_5" => Some(Cow::Borrowed(&self.instruction_ra_5)), + "InstructionRa_6" => Some(Cow::Borrowed(&self.instruction_ra_6)), + "InstructionRa_7" => Some(Cow::Borrowed(&self.instruction_ra_7)), + "InstructionRa_8" => Some(Cow::Borrowed(&self.instruction_ra_8)), + "InstructionRa_9" => Some(Cow::Borrowed(&self.instruction_ra_9)), + "InstructionRa_10" => Some(Cow::Borrowed(&self.instruction_ra_10)), + "InstructionRa_11" => Some(Cow::Borrowed(&self.instruction_ra_11)), + "InstructionRa_12" => Some(Cow::Borrowed(&self.instruction_ra_12)), + "InstructionRa_13" => Some(Cow::Borrowed(&self.instruction_ra_13)), + "InstructionRa_14" => Some(Cow::Borrowed(&self.instruction_ra_14)), + "InstructionRa_15" => Some(Cow::Borrowed(&self.instruction_ra_15)), + "InstructionRa_16" => Some(Cow::Borrowed(&self.instruction_ra_16)), + "InstructionRa_17" => Some(Cow::Borrowed(&self.instruction_ra_17)), + "InstructionRa_18" => Some(Cow::Borrowed(&self.instruction_ra_18)), + "InstructionRa_19" => Some(Cow::Borrowed(&self.instruction_ra_19)), + "InstructionRa_20" => Some(Cow::Borrowed(&self.instruction_ra_20)), + "InstructionRa_21" => Some(Cow::Borrowed(&self.instruction_ra_21)), + "InstructionRa_22" => Some(Cow::Borrowed(&self.instruction_ra_22)), + "InstructionRa_23" => Some(Cow::Borrowed(&self.instruction_ra_23)), + "InstructionRa_24" => Some(Cow::Borrowed(&self.instruction_ra_24)), + "InstructionRa_25" => Some(Cow::Borrowed(&self.instruction_ra_25)), + "InstructionRa_26" => Some(Cow::Borrowed(&self.instruction_ra_26)), + "InstructionRa_27" => Some(Cow::Borrowed(&self.instruction_ra_27)), + "InstructionRa_28" => Some(Cow::Borrowed(&self.instruction_ra_28)), + "InstructionRa_29" => Some(Cow::Borrowed(&self.instruction_ra_29)), + "InstructionRa_30" => Some(Cow::Borrowed(&self.instruction_ra_30)), + "InstructionRa_31" => Some(Cow::Borrowed(&self.instruction_ra_31)), + "RamRa_0" => Some(Cow::Borrowed(&self.ram_ra_0)), + "RamRa_1" => Some(Cow::Borrowed(&self.ram_ra_1)), + "RamRa_2" => Some(Cow::Borrowed(&self.ram_ra_2)), + "RamRa_3" => Some(Cow::Borrowed(&self.ram_ra_3)), + "BytecodeRa_0" => Some(Cow::Borrowed(&self.bytecode_ra_0)), + "BytecodeRa_1" => Some(Cow::Borrowed(&self.bytecode_ra_1)), + "BytecodeRa_2" => Some(Cow::Borrowed(&self.bytecode_ra_2)), + "UntrustedAdvice" => self.untrusted_advice.as_deref().map(Cow::Borrowed), + "TrustedAdvice" => self.trusted_advice.as_deref().map(Cow::Borrowed), + _ => None, + } + } +} + +pub fn build_commitment_oracles( + inputs: &CommitmentOracleInputs<'_>, +) -> Result { + Ok(CommitmentOracles { + rd_inc: dense_i128_column_to_field(inputs.rd_inc, target_len(16)?), + ram_inc: dense_i128_column_to_field(inputs.ram_inc, target_len(16)?), + instruction_ra_0: one_hot_chunk_address_major(inputs.instruction_keys, 0, 32, 4, target_len(16)?, Some(0)), + instruction_ra_1: one_hot_chunk_address_major(inputs.instruction_keys, 1, 32, 4, target_len(16)?, Some(0)), + instruction_ra_2: one_hot_chunk_address_major(inputs.instruction_keys, 2, 32, 4, target_len(16)?, Some(0)), + instruction_ra_3: one_hot_chunk_address_major(inputs.instruction_keys, 3, 32, 4, target_len(16)?, Some(0)), + instruction_ra_4: one_hot_chunk_address_major(inputs.instruction_keys, 4, 32, 4, target_len(16)?, Some(0)), + instruction_ra_5: one_hot_chunk_address_major(inputs.instruction_keys, 5, 32, 4, target_len(16)?, Some(0)), + instruction_ra_6: one_hot_chunk_address_major(inputs.instruction_keys, 6, 32, 4, target_len(16)?, Some(0)), + instruction_ra_7: one_hot_chunk_address_major(inputs.instruction_keys, 7, 32, 4, target_len(16)?, Some(0)), + instruction_ra_8: one_hot_chunk_address_major(inputs.instruction_keys, 8, 32, 4, target_len(16)?, Some(0)), + instruction_ra_9: one_hot_chunk_address_major(inputs.instruction_keys, 9, 32, 4, target_len(16)?, Some(0)), + instruction_ra_10: one_hot_chunk_address_major(inputs.instruction_keys, 10, 32, 4, target_len(16)?, Some(0)), + instruction_ra_11: one_hot_chunk_address_major(inputs.instruction_keys, 11, 32, 4, target_len(16)?, Some(0)), + instruction_ra_12: one_hot_chunk_address_major(inputs.instruction_keys, 12, 32, 4, target_len(16)?, Some(0)), + instruction_ra_13: one_hot_chunk_address_major(inputs.instruction_keys, 13, 32, 4, target_len(16)?, Some(0)), + instruction_ra_14: one_hot_chunk_address_major(inputs.instruction_keys, 14, 32, 4, target_len(16)?, Some(0)), + instruction_ra_15: one_hot_chunk_address_major(inputs.instruction_keys, 15, 32, 4, target_len(16)?, Some(0)), + instruction_ra_16: one_hot_chunk_address_major(inputs.instruction_keys, 16, 32, 4, target_len(16)?, Some(0)), + instruction_ra_17: one_hot_chunk_address_major(inputs.instruction_keys, 17, 32, 4, target_len(16)?, Some(0)), + instruction_ra_18: one_hot_chunk_address_major(inputs.instruction_keys, 18, 32, 4, target_len(16)?, Some(0)), + instruction_ra_19: one_hot_chunk_address_major(inputs.instruction_keys, 19, 32, 4, target_len(16)?, Some(0)), + instruction_ra_20: one_hot_chunk_address_major(inputs.instruction_keys, 20, 32, 4, target_len(16)?, Some(0)), + instruction_ra_21: one_hot_chunk_address_major(inputs.instruction_keys, 21, 32, 4, target_len(16)?, Some(0)), + instruction_ra_22: one_hot_chunk_address_major(inputs.instruction_keys, 22, 32, 4, target_len(16)?, Some(0)), + instruction_ra_23: one_hot_chunk_address_major(inputs.instruction_keys, 23, 32, 4, target_len(16)?, Some(0)), + instruction_ra_24: one_hot_chunk_address_major(inputs.instruction_keys, 24, 32, 4, target_len(16)?, Some(0)), + instruction_ra_25: one_hot_chunk_address_major(inputs.instruction_keys, 25, 32, 4, target_len(16)?, Some(0)), + instruction_ra_26: one_hot_chunk_address_major(inputs.instruction_keys, 26, 32, 4, target_len(16)?, Some(0)), + instruction_ra_27: one_hot_chunk_address_major(inputs.instruction_keys, 27, 32, 4, target_len(16)?, Some(0)), + instruction_ra_28: one_hot_chunk_address_major(inputs.instruction_keys, 28, 32, 4, target_len(16)?, Some(0)), + instruction_ra_29: one_hot_chunk_address_major(inputs.instruction_keys, 29, 32, 4, target_len(16)?, Some(0)), + instruction_ra_30: one_hot_chunk_address_major(inputs.instruction_keys, 30, 32, 4, target_len(16)?, Some(0)), + instruction_ra_31: one_hot_chunk_address_major(inputs.instruction_keys, 31, 32, 4, target_len(16)?, Some(0)), + ram_ra_0: one_hot_chunk_address_major(inputs.ram_addresses, 0, 4, 4, target_len(16)?, None), + ram_ra_1: one_hot_chunk_address_major(inputs.ram_addresses, 1, 4, 4, target_len(16)?, None), + ram_ra_2: one_hot_chunk_address_major(inputs.ram_addresses, 2, 4, 4, target_len(16)?, None), + ram_ra_3: one_hot_chunk_address_major(inputs.ram_addresses, 3, 4, 4, target_len(16)?, None), + bytecode_ra_0: one_hot_chunk_address_major(inputs.bytecode_indices, 0, 3, 4, target_len(16)?, Some(0)), + bytecode_ra_1: one_hot_chunk_address_major(inputs.bytecode_indices, 1, 3, 4, target_len(16)?, Some(0)), + bytecode_ra_2: one_hot_chunk_address_major(inputs.bytecode_indices, 2, 3, 4, target_len(16)?, Some(0)), + untrusted_advice: optional_field_oracle(inputs.untrusted_advice, target_len(16)?), + trusted_advice: optional_field_oracle(inputs.trusted_advice, target_len(16)?), + }) +} + +pub const COMMITMENT_PARAMS: CommitmentParams = CommitmentParams { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const ORACLE_PLANS: &[OraclePlan] = &[ + OraclePlan { oracle: "RdInc", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "RamInc", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "UntrustedAdvice", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "TrustedAdvice", domain: "jolt.trace_domain", num_vars: 16 }, +]; +pub const COMMITMENT_BATCH_0_ORACLES: &[&str] = &[ + "RdInc", + "RamInc", + "InstructionRa_0", + "InstructionRa_1", + "InstructionRa_2", + "InstructionRa_3", + "InstructionRa_4", + "InstructionRa_5", + "InstructionRa_6", + "InstructionRa_7", + "InstructionRa_8", + "InstructionRa_9", + "InstructionRa_10", + "InstructionRa_11", + "InstructionRa_12", + "InstructionRa_13", + "InstructionRa_14", + "InstructionRa_15", + "InstructionRa_16", + "InstructionRa_17", + "InstructionRa_18", + "InstructionRa_19", + "InstructionRa_20", + "InstructionRa_21", + "InstructionRa_22", + "InstructionRa_23", + "InstructionRa_24", + "InstructionRa_25", + "InstructionRa_26", + "InstructionRa_27", + "InstructionRa_28", + "InstructionRa_29", + "InstructionRa_30", + "InstructionRa_31", + "RamRa_0", + "RamRa_1", + "RamRa_2", + "RamRa_3", + "BytecodeRa_0", + "BytecodeRa_1", + "BytecodeRa_2", +]; +pub const COMMITMENT_BATCH_PLANS: &[CommitmentBatchPlan] = &[ + CommitmentBatchPlan { artifact: "jolt.main_witness_commitments", pcs: "dory", oracle_family: "jolt.main_witness_polys", label: "commitment", oracles: COMMITMENT_BATCH_0_ORACLES, count: 41, domain: "jolt.main_witness_commit_domain", num_vars: 20 }, +]; +pub const OPTIONAL_COMMITMENT_PLANS: &[OptionalCommitmentPlan] = &[ + OptionalCommitmentPlan { artifact: "jolt.untrusted_advice_commitment", pcs: "dory", oracle: "UntrustedAdvice", label: "untrusted_advice", domain: "jolt.trace_domain", num_vars: 16, skip_policy: OptionalSkipPolicy::MissingOrZero }, + OptionalCommitmentPlan { artifact: "jolt.trusted_advice_commitment", pcs: "dory", oracle: "TrustedAdvice", label: "trusted_advice", domain: "jolt.trace_domain", num_vars: 16, skip_policy: OptionalSkipPolicy::MissingOrZero }, +]; +pub const TRANSCRIPT_PLAN: &[TranscriptStep] = &[ + TranscriptStep { label: "commitment", source: "jolt.main_witness_commitments", optional: false }, + TranscriptStep { label: "untrusted_advice", source: "jolt.untrusted_advice_commitment", optional: true }, + TranscriptStep { label: "trusted_advice", source: "jolt.trusted_advice_commitment", optional: true }, +]; +pub const COMMITMENT_PROGRAM: CommitmentProverProgramPlan = CommitmentProverProgramPlan { + params: COMMITMENT_PARAMS, + oracle_plans: ORACLE_PLANS, + batch_plans: COMMITMENT_BATCH_PLANS, + optional_plans: OPTIONAL_COMMITMENT_PLANS, + transcript_steps: TRANSCRIPT_PLAN, +}; + +pub fn prove_commitment_phase( + inputs: &mut I, + prover_setup: &DoryProverSetup, + transcript: &mut T, +) -> Result +where + I: CommitmentInputProvider, + T: Transcript, +{ + prove_commitment_phase_with_program(&COMMITMENT_PROGRAM, inputs, prover_setup, transcript) +} + +pub fn prove_commitment_phase_with_program( + program: &'static CommitmentProverProgramPlan, + inputs: &mut I, + prover_setup: &DoryProverSetup, + transcript: &mut T, +) -> Result +where + I: CommitmentInputProvider, + T: Transcript, +{ + let mut artifacts = CommitmentArtifacts::default(); + for plan in program.batch_plans { + let _batch_span = tracing::info_span!("bolt.commitment.batch").entered(); + commit_batch(program, inputs, prover_setup, &mut artifacts, plan)?; + } + for plan in program.optional_plans { + let _optional_span = tracing::info_span!("bolt.commitment.optional").entered(); + commit_optional(program, inputs, prover_setup, &mut artifacts, plan)?; + } + absorb_transcript(program, &artifacts, transcript)?; + Ok(artifacts) +} + +fn commit_batch( + program: &CommitmentProverProgramPlan, + inputs: &mut I, + prover_setup: &DoryProverSetup, + artifacts: &mut CommitmentArtifacts, + plan: &CommitmentBatchPlan, +) -> Result<(), CommitmentPhaseError> +where + I: CommitmentInputProvider, +{ + if plan.count != plan.oracles.len() { + return Err(CommitmentPhaseError::PlanCountMismatch { + artifact: plan.artifact, + expected: plan.count, + actual: plan.oracles.len(), + }); + } + if let Some(committed) = inputs.commit_batch(program, plan, prover_setup) { + for committed in committed? { + artifacts.records.push(committed.record); + artifacts.commitments.push(committed.commitment); + if let Some(hint) = committed.hint { + artifacts.hints.push(hint); + } + } + return Ok(()); + } + for &oracle in plan.oracles { + let data = inputs + .materialize_with_num_vars(oracle, oracle_num_vars(program, oracle, plan.num_vars)) + .ok_or(CommitmentPhaseError::MissingOracle { oracle })?; + let oracle_num_vars = oracle_num_vars(program, oracle, plan.num_vars); + let data = into_padded_oracle(oracle, oracle_num_vars, data)?; + let (commitment, hint) = commit_with_layout(&data, plan.num_vars, prover_setup)?; + artifacts.records.push(CommitmentRecord { + artifact: plan.artifact, + oracle, + label: plan.label, + num_vars: oracle_num_vars, + }); + artifacts.commitments.push(Some(commitment)); + artifacts.hints.push(OracleOpeningHint { oracle, hint }); + } + Ok(()) +} + +fn commit_optional( + program: &CommitmentProverProgramPlan, + inputs: &mut I, + prover_setup: &DoryProverSetup, + artifacts: &mut CommitmentArtifacts, + plan: &OptionalCommitmentPlan, +) -> Result<(), CommitmentPhaseError> +where + I: CommitmentInputProvider, +{ + let Some(data) = inputs.materialize_with_num_vars(plan.oracle, plan.num_vars) else { + return push_skipped_optional(program, artifacts, plan); + }; + if should_skip_optional(plan.skip_policy, data.as_ref()) { + return push_skipped_optional(program, artifacts, plan); + } + let data = into_padded_oracle(plan.oracle, plan.num_vars, data)?; + let (commitment, hint) = commit_with_layout(&data, plan.num_vars, prover_setup)?; + artifacts.records.push(CommitmentRecord { + artifact: plan.artifact, + oracle: plan.oracle, + label: plan.label, + num_vars: oracle_num_vars(program, plan.oracle, plan.num_vars), + }); + artifacts.commitments.push(Some(commitment)); + artifacts.hints.push(OracleOpeningHint { + oracle: plan.oracle, + hint, + }); + Ok(()) +} + +fn push_skipped_optional( + program: &CommitmentProverProgramPlan, + artifacts: &mut CommitmentArtifacts, + plan: &OptionalCommitmentPlan, +) -> Result<(), CommitmentPhaseError> { + artifacts.records.push(CommitmentRecord { + artifact: plan.artifact, + oracle: plan.oracle, + label: plan.label, + num_vars: oracle_num_vars(program, plan.oracle, plan.num_vars), + }); + artifacts.commitments.push(None); + Ok(()) +} + +fn should_skip_optional(policy: OptionalSkipPolicy, data: &[Fr]) -> bool { + match policy { + OptionalSkipPolicy::MissingOrZero => data.iter().all(|value| *value == Fr::from_u64(0)), + } +} + +fn into_padded_oracle( + oracle: &'static str, + num_vars: usize, + data: Cow<'_, [Fr]>, +) -> Result, CommitmentPhaseError> { + let target_len = target_len(num_vars)?; + if data.len() > target_len { + return Err(CommitmentPhaseError::OracleTooLarge { + oracle, + len: data.len(), + target_len, + }); + } + let mut data = data.into_owned(); + data.resize(target_len, Fr::from_u64(0)); + Ok(data) +} + +fn oracle_num_vars( + program: &CommitmentProverProgramPlan, + oracle: &'static str, + fallback: usize, +) -> usize { + program + .oracle_plans + .iter() + .find(|plan| plan.oracle == oracle) + .map_or(fallback, |plan| plan.num_vars) +} + +fn commit_with_layout( + data: &[Fr], + layout_num_vars: usize, + prover_setup: &DoryProverSetup, +) -> Result<(DoryCommitment, DoryHint), CommitmentPhaseError> { + let row_len = target_len(layout_num_vars.div_ceil(2))?; + let _dory_commit_span = tracing::info_span!("bolt.commitment.dory_commit").entered(); + Ok(DoryScheme::commit_evaluations_with_row_len( + data, + row_len, + prover_setup, + )) +} + +fn target_len(num_vars: usize) -> Result { + if num_vars >= usize::BITS as usize { + return Err(CommitmentPhaseError::TargetSizeOverflow { num_vars }); + } + Ok(1usize << num_vars) +} + +fn absorb_transcript( + program: &CommitmentProverProgramPlan, + artifacts: &CommitmentArtifacts, + transcript: &mut T, +) -> Result<(), CommitmentPhaseError> +where + T: Transcript, +{ + for step in program.transcript_steps { + let mut appended = false; + for (record, commitment) in artifacts.records.iter().zip(&artifacts.commitments) { + if record.artifact != step.source { + continue; + } + if let Some(commitment) = commitment { + transcript.append(&LabelWithCount(step.label.as_bytes(), commitment.serialized_len())); + commitment.append_to_transcript(transcript); + appended = true; + } + } + if !step.optional && !appended { + return Err(CommitmentPhaseError::MissingTranscriptSource { + source: step.source, + }); + } + } + Ok(()) +} diff --git a/crates/jolt-prover/src/stages/mod.rs b/crates/jolt-prover/src/stages/mod.rs new file mode 100644 index 0000000000..c8242a4f47 --- /dev/null +++ b/crates/jolt-prover/src/stages/mod.rs @@ -0,0 +1,18 @@ +#[rustfmt::skip] +pub mod commitment; +#[rustfmt::skip] +pub mod stage1_outer; +#[rustfmt::skip] +pub mod stage2; +#[rustfmt::skip] +pub mod stage3; +#[rustfmt::skip] +pub mod stage4; +#[rustfmt::skip] +pub mod stage5; +#[rustfmt::skip] +pub mod stage6; +#[rustfmt::skip] +pub mod stage7; +#[rustfmt::skip] +pub mod stage8; diff --git a/crates/jolt-prover/src/stages/stage1_outer.rs b/crates/jolt-prover/src/stages/stage1_outer.rs new file mode 100644 index 0000000000..e31d49a81e --- /dev/null +++ b/crates/jolt-prover/src/stages/stage1_outer.rs @@ -0,0 +1,264 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage1::{execute_stage1_program, Stage1CpuProgramPlan, Stage1ExecutionArtifacts, Stage1ExecutionMode, Stage1KernelError, Stage1KernelExecutor, Stage1KernelPlan, Stage1OpeningBatchPlan, Stage1OpeningClaimPlan, Stage1Params, Stage1SumcheckBatchPlan, Stage1SumcheckClaimPlan, Stage1SumcheckDriverPlan, Stage1SumcheckEvalPlan, Stage1SumcheckInstanceResultPlan, Stage1TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage1Transcript = Blake2bTranscript; + +pub const STAGE1_PARAMS: Stage1Params = Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE1_TRANSCRIPT_SQUEEZES: &[Stage1TranscriptSqueezePlan] = &[ + Stage1TranscriptSqueezePlan { symbol: "stage1.tau", label: "outer_tau", kind: "challenge_vector", count: 18 }, +]; + +pub const STAGE1_KERNELS: &[Stage1KernelPlan] = &[ + Stage1KernelPlan { symbol: "jolt.cpu.stage1.outer.uniskip", relation: "jolt.stage1.outer.uniskip", kind: "sumcheck", backend: "cpu", abi: "jolt_stage1_outer_uniskip" }, + Stage1KernelPlan { symbol: "jolt.cpu.stage1.outer.remaining", relation: "jolt.stage1.outer.remaining", kind: "sumcheck", backend: "cpu", abi: "jolt_stage1_outer_remaining" }, +]; + +pub const STAGE1_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[]; + +pub const STAGE1_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &["stage1.uniskip.opening"]; + +pub const STAGE1_SUMCHECK_CLAIMS: &[Stage1SumcheckClaimPlan] = &[ + Stage1SumcheckClaimPlan { symbol: "stage1.uniskip.input", stage: "stage1", domain: "jolt.stage1_uniskip_domain", num_rounds: 1, degree: 27, claim: "stage1.zero", kernel: Some("jolt.cpu.stage1.outer.uniskip"), relation: None, claim_value: "stage1.zero", input_openings: STAGE1_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage1SumcheckClaimPlan { symbol: "stage1.outer_remaining.input", stage: "stage1", domain: "jolt.trace_domain", num_rounds: 17, degree: 3, claim: "stage1.uniskip.eval", kernel: Some("jolt.cpu.stage1.outer.remaining"), relation: None, claim_value: "stage1.uniskip.eval", input_openings: STAGE1_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, +]; +pub const STAGE1_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &["stage1.uniskip.input"]; + +pub const STAGE1_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &["stage1.uniskip.input"]; + +pub const STAGE1_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE1_SUMCHECK_BATCH_1_ORDERED_CLAIMS: &[&str] = &["stage1.outer_remaining.input"]; + +pub const STAGE1_SUMCHECK_BATCH_1_CLAIM_OPERANDS: &[&str] = &["stage1.outer_remaining.input"]; + +pub const STAGE1_SUMCHECK_BATCH_1_ROUND_SCHEDULE: &[usize] = &[ + 17, +]; + +pub const STAGE1_SUMCHECK_BATCHES: &[Stage1SumcheckBatchPlan] = &[ + Stage1SumcheckBatchPlan { symbol: "stage1.uniskip.batch", stage: "stage1", proof_slot: "stage1.uni_skip_first_round", policy: "single_instance", count: 1, ordered_claims: STAGE1_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE1_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "uniskip_claim", round_label: "uniskip_poly", round_schedule: STAGE1_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, + Stage1SumcheckBatchPlan { symbol: "stage1.outer_remaining.batch", stage: "stage1", proof_slot: "stage1.sumcheck", policy: "jolt_core_front_loaded", count: 1, ordered_claims: STAGE1_SUMCHECK_BATCH_1_ORDERED_CLAIMS, claim_operands: STAGE1_SUMCHECK_BATCH_1_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE1_SUMCHECK_BATCH_1_ROUND_SCHEDULE }, +]; +pub const STAGE1_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE1_SUMCHECK_DRIVER_1_ROUND_SCHEDULE: &[usize] = &[ + 17, +]; + +pub const STAGE1_SUMCHECK_DRIVERS: &[Stage1SumcheckDriverPlan] = &[ + Stage1SumcheckDriverPlan { symbol: "stage1.uniskip.sumcheck", stage: "stage1", proof_slot: "stage1.uni_skip_first_round", kernel: Some("jolt.cpu.stage1.outer.uniskip"), relation: None, batch: "stage1.uniskip.batch", policy: "univariate_skip", round_schedule: STAGE1_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "uniskip_claim", round_label: "uniskip_poly", num_rounds: 1, degree: 27 }, + Stage1SumcheckDriverPlan { symbol: "stage1.outer_remaining.sumcheck", stage: "stage1", proof_slot: "stage1.sumcheck", kernel: Some("jolt.cpu.stage1.outer.remaining"), relation: None, batch: "stage1.outer_remaining.batch", policy: "jolt_core_front_loaded", round_schedule: STAGE1_SUMCHECK_DRIVER_1_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 17, degree: 3 }, +]; +pub const STAGE1_SUMCHECK_INSTANCE_RESULTS: &[Stage1SumcheckInstanceResultPlan] = &[ + Stage1SumcheckInstanceResultPlan { symbol: "stage1.uniskip.instance", source: "stage1.uniskip.sumcheck", claim: "stage1.uniskip.input", relation: "jolt.stage1.outer.uniskip", index: 0, point_arity: 1, num_rounds: 1, round_offset: 0, point_order: "as_is", degree: 27 }, + Stage1SumcheckInstanceResultPlan { symbol: "stage1.outer_remaining.instance", source: "stage1.outer_remaining.sumcheck", claim: "stage1.outer_remaining.input", relation: "jolt.stage1.outer.remaining", index: 0, point_arity: 16, num_rounds: 17, round_offset: 1, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE1_SUMCHECK_EVALS: &[Stage1SumcheckEvalPlan] = &[ + Stage1SumcheckEvalPlan { symbol: "stage1.uniskip.eval", source: "stage1.uniskip.sumcheck", name: "stage1.uniskip.eval", index: 0, oracle: "UnivariateSkip" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LeftInstructionInput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LeftInstructionInput", index: 0, oracle: "LeftInstructionInput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RightInstructionInput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RightInstructionInput", index: 1, oracle: "RightInstructionInput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Product", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Product", index: 2, oracle: "Product" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.ShouldBranch", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.ShouldBranch", index: 3, oracle: "ShouldBranch" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.PC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.PC", index: 4, oracle: "PC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.UnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.UnexpandedPC", index: 5, oracle: "UnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Imm", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Imm", index: 6, oracle: "Imm" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamAddress", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamAddress", index: 7, oracle: "RamAddress" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Rs1Value", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Rs1Value", index: 8, oracle: "Rs1Value" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Rs2Value", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Rs2Value", index: 9, oracle: "Rs2Value" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RdWriteValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RdWriteValue", index: 10, oracle: "RdWriteValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamReadValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamReadValue", index: 11, oracle: "RamReadValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamWriteValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamWriteValue", index: 12, oracle: "RamWriteValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LeftLookupOperand", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LeftLookupOperand", index: 13, oracle: "LeftLookupOperand" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RightLookupOperand", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RightLookupOperand", index: 14, oracle: "RightLookupOperand" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextUnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextUnexpandedPC", index: 15, oracle: "NextUnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextPC", index: 16, oracle: "NextPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextIsVirtual", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextIsVirtual", index: 17, oracle: "NextIsVirtual" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextIsFirstInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextIsFirstInSequence", index: 18, oracle: "NextIsFirstInSequence" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LookupOutput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LookupOutput", index: 19, oracle: "LookupOutput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.ShouldJump", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.ShouldJump", index: 20, oracle: "ShouldJump" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAddOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAddOperands", index: 21, oracle: "OpFlagAddOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagSubtractOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagSubtractOperands", index: 22, oracle: "OpFlagSubtractOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagMultiplyOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagMultiplyOperands", index: 23, oracle: "OpFlagMultiplyOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagLoad", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagLoad", index: 24, oracle: "OpFlagLoad" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagStore", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagStore", index: 25, oracle: "OpFlagStore" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagJump", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagJump", index: 26, oracle: "OpFlagJump" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD", index: 27, oracle: "OpFlagWriteLookupOutputToRD" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagVirtualInstruction", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagVirtualInstruction", index: 28, oracle: "OpFlagVirtualInstruction" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAssert", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAssert", index: 29, oracle: "OpFlagAssert" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC", index: 30, oracle: "OpFlagDoNotUpdateUnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAdvice", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAdvice", index: 31, oracle: "OpFlagAdvice" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsCompressed", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsCompressed", index: 32, oracle: "OpFlagIsCompressed" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence", index: 33, oracle: "OpFlagIsFirstInSequence" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsLastInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsLastInSequence", index: 34, oracle: "OpFlagIsLastInSequence" }, +]; + +pub const STAGE1_OPENING_CLAIMS: &[Stage1OpeningClaimPlan] = &[ + Stage1OpeningClaimPlan { symbol: "stage1.uniskip.opening", oracle: "UnivariateSkip", domain: "jolt.stage1_uniskip_domain", point_arity: 1, claim_kind: "virtual", point_source: "stage1.uniskip.instance", eval_source: "stage1.uniskip.eval" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LeftInstructionInput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RightInstructionInput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Product", oracle: "Product", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Product" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.ShouldBranch", oracle: "ShouldBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.ShouldBranch" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.PC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.UnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Imm" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamAddress", oracle: "RamAddress", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamAddress" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Rs1Value" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Rs2Value" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RdWriteValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamReadValue", oracle: "RamReadValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamReadValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamWriteValue", oracle: "RamWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamWriteValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LeftLookupOperand" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RightLookupOperand" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextUnexpandedPC", oracle: "NextUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextUnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextPC", oracle: "NextPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextIsVirtual", oracle: "NextIsVirtual", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextIsVirtual" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextIsFirstInSequence", oracle: "NextIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextIsFirstInSequence" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LookupOutput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.ShouldJump", oracle: "ShouldJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.ShouldJump" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAddOperands", oracle: "OpFlagAddOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAddOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagSubtractOperands", oracle: "OpFlagSubtractOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagSubtractOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagMultiplyOperands", oracle: "OpFlagMultiplyOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagMultiplyOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagLoad", oracle: "OpFlagLoad", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagLoad" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagStore", oracle: "OpFlagStore", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagStore" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagJump" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagVirtualInstruction" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAssert", oracle: "OpFlagAssert", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAssert" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", oracle: "OpFlagDoNotUpdateUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAdvice", oracle: "OpFlagAdvice", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAdvice" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsCompressed", oracle: "OpFlagIsCompressed", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsCompressed" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsLastInSequence", oracle: "OpFlagIsLastInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsLastInSequence" }, +]; + +pub const STAGE1_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage1.outer_remaining.opening.LeftInstructionInput", + "stage1.outer_remaining.opening.RightInstructionInput", + "stage1.outer_remaining.opening.Product", + "stage1.outer_remaining.opening.ShouldBranch", + "stage1.outer_remaining.opening.PC", + "stage1.outer_remaining.opening.UnexpandedPC", + "stage1.outer_remaining.opening.Imm", + "stage1.outer_remaining.opening.RamAddress", + "stage1.outer_remaining.opening.Rs1Value", + "stage1.outer_remaining.opening.Rs2Value", + "stage1.outer_remaining.opening.RdWriteValue", + "stage1.outer_remaining.opening.RamReadValue", + "stage1.outer_remaining.opening.RamWriteValue", + "stage1.outer_remaining.opening.LeftLookupOperand", + "stage1.outer_remaining.opening.RightLookupOperand", + "stage1.outer_remaining.opening.NextUnexpandedPC", + "stage1.outer_remaining.opening.NextPC", + "stage1.outer_remaining.opening.NextIsVirtual", + "stage1.outer_remaining.opening.NextIsFirstInSequence", + "stage1.outer_remaining.opening.LookupOutput", + "stage1.outer_remaining.opening.ShouldJump", + "stage1.outer_remaining.opening.OpFlagAddOperands", + "stage1.outer_remaining.opening.OpFlagSubtractOperands", + "stage1.outer_remaining.opening.OpFlagMultiplyOperands", + "stage1.outer_remaining.opening.OpFlagLoad", + "stage1.outer_remaining.opening.OpFlagStore", + "stage1.outer_remaining.opening.OpFlagJump", + "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", + "stage1.outer_remaining.opening.OpFlagVirtualInstruction", + "stage1.outer_remaining.opening.OpFlagAssert", + "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", + "stage1.outer_remaining.opening.OpFlagAdvice", + "stage1.outer_remaining.opening.OpFlagIsCompressed", + "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", + "stage1.outer_remaining.opening.OpFlagIsLastInSequence", +]; + +pub const STAGE1_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage1.outer_remaining.opening.LeftInstructionInput", + "stage1.outer_remaining.opening.RightInstructionInput", + "stage1.outer_remaining.opening.Product", + "stage1.outer_remaining.opening.ShouldBranch", + "stage1.outer_remaining.opening.PC", + "stage1.outer_remaining.opening.UnexpandedPC", + "stage1.outer_remaining.opening.Imm", + "stage1.outer_remaining.opening.RamAddress", + "stage1.outer_remaining.opening.Rs1Value", + "stage1.outer_remaining.opening.Rs2Value", + "stage1.outer_remaining.opening.RdWriteValue", + "stage1.outer_remaining.opening.RamReadValue", + "stage1.outer_remaining.opening.RamWriteValue", + "stage1.outer_remaining.opening.LeftLookupOperand", + "stage1.outer_remaining.opening.RightLookupOperand", + "stage1.outer_remaining.opening.NextUnexpandedPC", + "stage1.outer_remaining.opening.NextPC", + "stage1.outer_remaining.opening.NextIsVirtual", + "stage1.outer_remaining.opening.NextIsFirstInSequence", + "stage1.outer_remaining.opening.LookupOutput", + "stage1.outer_remaining.opening.ShouldJump", + "stage1.outer_remaining.opening.OpFlagAddOperands", + "stage1.outer_remaining.opening.OpFlagSubtractOperands", + "stage1.outer_remaining.opening.OpFlagMultiplyOperands", + "stage1.outer_remaining.opening.OpFlagLoad", + "stage1.outer_remaining.opening.OpFlagStore", + "stage1.outer_remaining.opening.OpFlagJump", + "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", + "stage1.outer_remaining.opening.OpFlagVirtualInstruction", + "stage1.outer_remaining.opening.OpFlagAssert", + "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", + "stage1.outer_remaining.opening.OpFlagAdvice", + "stage1.outer_remaining.opening.OpFlagIsCompressed", + "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", + "stage1.outer_remaining.opening.OpFlagIsLastInSequence", +]; + +pub const STAGE1_OPENING_BATCHES: &[Stage1OpeningBatchPlan] = &[ + Stage1OpeningBatchPlan { symbol: "stage1.outer_remaining.openings", stage: "stage1", proof_slot: "stage1.virtual_openings", policy: "jolt_r1cs_input_order", count: 35, ordered_claims: STAGE1_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE1_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE1_PROGRAM: Stage1CpuProgramPlan = Stage1CpuProgramPlan { + params: STAGE1_PARAMS, + transcript_squeezes: STAGE1_TRANSCRIPT_SQUEEZES, + kernels: STAGE1_KERNELS, + claims: STAGE1_SUMCHECK_CLAIMS, + batches: STAGE1_SUMCHECK_BATCHES, + drivers: STAGE1_SUMCHECK_DRIVERS, + instance_results: STAGE1_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE1_SUMCHECK_EVALS, + opening_claims: STAGE1_OPENING_CLAIMS, + opening_batches: STAGE1_OPENING_BATCHES, +}; + +pub fn prove_stage1_outer( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage1KernelError> +where + E: Stage1KernelExecutor, + T: Transcript, +{ + prove_stage1_outer_with_program(&STAGE1_PROGRAM, executor, transcript) +} + +pub fn prove_stage1_outer_with_program( + program: &'static Stage1CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage1KernelError> +where + E: Stage1KernelExecutor, + T: Transcript, +{ + execute_stage1_program( + program, + Stage1ExecutionMode::Prover, + executor, + transcript, + ) +} diff --git a/crates/jolt-prover/src/stages/stage2.rs b/crates/jolt-prover/src/stages/stage2.rs new file mode 100644 index 0000000000..ece68d1c0b --- /dev/null +++ b/crates/jolt-prover/src/stages/stage2.rs @@ -0,0 +1,402 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage2::{execute_stage2_program, Stage2CpuProgramPlan, Stage2ExecutionArtifacts, Stage2ExecutionMode, Stage2FieldConstantPlan, Stage2FieldExprPlan, Stage2KernelError, Stage2KernelExecutor, Stage2KernelPlan, Stage2OpeningBatchPlan, Stage2OpeningClaimPlan, Stage2OpeningInputPlan, Stage2Params, Stage2PointConcatPlan, Stage2PointSlicePlan, Stage2ProgramStepPlan, Stage2SumcheckBatchPlan, Stage2SumcheckClaimPlan, Stage2SumcheckDriverPlan, Stage2SumcheckEvalPlan, Stage2SumcheckInstanceResultPlan, Stage2TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage2Transcript = Blake2bTranscript; + +pub const STAGE2_PARAMS: Stage2Params = Stage2Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE2_PROGRAM_STEPS: &[Stage2ProgramStepPlan] = &[ + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.product_virtual.tau_high" }, + Stage2ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage2.product_virtual.uniskip.sumcheck" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.ram_read_write.gamma" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.instruction_lookup.gamma" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.ram_output.r_address" }, + Stage2ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage2.sumcheck" }, +]; + +pub const STAGE2_TRANSCRIPT_SQUEEZES: &[Stage2TranscriptSqueezePlan] = &[ + Stage2TranscriptSqueezePlan { symbol: "stage2.product_virtual.tau_high", label: "product_virtual_tau_high", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.ram_read_write.gamma", label: "ram_read_write_gamma", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.instruction_lookup.gamma", label: "instruction_lookup_gamma", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.ram_output.r_address", label: "ram_output_r_address", kind: "challenge_vector", count: 16 }, +]; + +pub const STAGE2_OPENING_INPUTS: &[Stage2OpeningInputPlan] = &[ + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.Product", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Product", oracle: "Product", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.ShouldBranch", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.ShouldBranch", oracle: "ShouldBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.ShouldJump", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.ShouldJump", oracle: "ShouldJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamReadValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamReadValue", oracle: "RamReadValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamWriteValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamWriteValue", oracle: "RamWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LookupOutput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LeftLookupOperand", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RightLookupOperand", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LeftInstructionInput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RightInstructionInput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamAddress", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamAddress", oracle: "RamAddress", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE2_FIELD_CONSTANTS: &[Stage2FieldConstantPlan] = &[ + Stage2FieldConstantPlan { symbol: "stage2.ram_output.zero", field: "bn254_fr", value: 0 }, +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage2.product_virtual.tau_high"]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_1: &[&str] = &[ + "stage2.product_virtual.uniskip.weight.Product", + "stage2.input.stage1.Product", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage2.product_virtual.uniskip.weight.ShouldBranch", + "stage2.input.stage1.ShouldBranch", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage2.product_virtual.uniskip.weight.ShouldJump", + "stage2.input.stage1.ShouldJump", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage2.product_virtual.uniskip.term.Product", + "stage2.product_virtual.uniskip.term.ShouldBranch", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_5: &[&str] = &[ + "stage2.product_virtual.uniskip.partial.ProductShouldBranch", + "stage2.product_virtual.uniskip.term.ShouldJump", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage2.ram_read_write.gamma", + "stage2.input.stage1.RamWriteValue", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage2.input.stage1.RamReadValue", + "stage2.ram_read_write.term.RamWriteValue", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage2.instruction_lookup.gamma", + "stage2.instruction_lookup.gamma", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_9: &[&str] = &[ + "stage2.instruction_lookup.gamma2", + "stage2.instruction_lookup.gamma", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_10: &[&str] = &[ + "stage2.instruction_lookup.gamma2", + "stage2.instruction_lookup.gamma2", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_11: &[&str] = &[ + "stage2.instruction_lookup.gamma", + "stage2.input.stage1.LeftLookupOperand", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_12: &[&str] = &[ + "stage2.instruction_lookup.gamma2", + "stage2.input.stage1.RightLookupOperand", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_13: &[&str] = &[ + "stage2.instruction_lookup.gamma3", + "stage2.input.stage1.LeftInstructionInput", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_14: &[&str] = &[ + "stage2.instruction_lookup.gamma4", + "stage2.input.stage1.RightInstructionInput", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_15: &[&str] = &[ + "stage2.input.stage1.LookupOutput", + "stage2.instruction_lookup.term.LeftLookupOperand", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_16: &[&str] = &[ + "stage2.instruction_lookup.partial.LookupOutputLeftOperand", + "stage2.instruction_lookup.term.RightLookupOperand", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_17: &[&str] = &[ + "stage2.instruction_lookup.partial.RightOperand", + "stage2.instruction_lookup.term.LeftInstructionInput", +]; + +pub const STAGE2_FIELD_EXPR_OPERANDS_18: &[&str] = &[ + "stage2.instruction_lookup.partial.LeftInstructionInput", + "stage2.instruction_lookup.term.RightInstructionInput", +]; + +pub const STAGE2_FIELD_EXPRS: &[Stage2FieldExprPlan] = &[ + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.Product", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:0", operand_names: STAGE2_FIELD_EXPR_OPERANDS_0, operands: STAGE2_FIELD_EXPR_OPERANDS_0 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.ShouldBranch", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:1", operand_names: STAGE2_FIELD_EXPR_OPERANDS_0, operands: STAGE2_FIELD_EXPR_OPERANDS_0 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.ShouldJump", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:2", operand_names: STAGE2_FIELD_EXPR_OPERANDS_0, operands: STAGE2_FIELD_EXPR_OPERANDS_0 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.Product", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_1, operands: STAGE2_FIELD_EXPR_OPERANDS_1 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.ShouldBranch", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_2, operands: STAGE2_FIELD_EXPR_OPERANDS_2 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.ShouldJump", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_3, operands: STAGE2_FIELD_EXPR_OPERANDS_3 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.partial.ProductShouldBranch", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_4, operands: STAGE2_FIELD_EXPR_OPERANDS_4 }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_5, operands: STAGE2_FIELD_EXPR_OPERANDS_5 }, + Stage2FieldExprPlan { symbol: "stage2.ram_read_write.term.RamWriteValue", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_6, operands: STAGE2_FIELD_EXPR_OPERANDS_6 }, + Stage2FieldExprPlan { symbol: "stage2.ram_read_write.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_7, operands: STAGE2_FIELD_EXPR_OPERANDS_7 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma2", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_8, operands: STAGE2_FIELD_EXPR_OPERANDS_8 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma3", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_9, operands: STAGE2_FIELD_EXPR_OPERANDS_9 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma4", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_10, operands: STAGE2_FIELD_EXPR_OPERANDS_10 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.LeftLookupOperand", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_11, operands: STAGE2_FIELD_EXPR_OPERANDS_11 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.RightLookupOperand", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_12, operands: STAGE2_FIELD_EXPR_OPERANDS_12 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.LeftInstructionInput", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_13, operands: STAGE2_FIELD_EXPR_OPERANDS_13 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.RightInstructionInput", kind: "op", formula: "field.mul", operand_names: STAGE2_FIELD_EXPR_OPERANDS_14, operands: STAGE2_FIELD_EXPR_OPERANDS_14 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.LookupOutputLeftOperand", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_15, operands: STAGE2_FIELD_EXPR_OPERANDS_15 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.RightOperand", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_16, operands: STAGE2_FIELD_EXPR_OPERANDS_16 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.LeftInstructionInput", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_17, operands: STAGE2_FIELD_EXPR_OPERANDS_17 }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.claim_reduction.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE2_FIELD_EXPR_OPERANDS_18, operands: STAGE2_FIELD_EXPR_OPERANDS_18 }, +]; +pub const STAGE2_KERNELS: &[Stage2KernelPlan] = &[ + Stage2KernelPlan { symbol: "jolt.cpu.stage2.product_virtual.uniskip", relation: "jolt.stage2.product_virtual.uniskip", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_product_virtual_uniskip" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.ram.read_write", relation: "jolt.stage2.ram.read_write", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_ram_read_write" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.product_virtual.remainder", relation: "jolt.stage2.product_virtual.remainder", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_product_virtual_remainder" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.instruction_lookup.claim_reduction", relation: "jolt.stage2.instruction_lookup.claim_reduction", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_instruction_lookup_claim_reduction" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.ram.raf_evaluation", relation: "jolt.stage2.ram.raf_evaluation", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_ram_raf_evaluation" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.ram.output_check", relation: "jolt.stage2.ram.output_check", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_ram_output_check" }, + Stage2KernelPlan { symbol: "jolt.cpu.stage2.batched", relation: "jolt.stage2.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage2_batched" }, +]; + +pub const STAGE2_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage2.input.stage1.Product", + "stage2.input.stage1.ShouldBranch", + "stage2.input.stage1.ShouldJump", +]; + +pub const STAGE2_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &[ + "stage2.input.stage1.RamReadValue", + "stage2.input.stage1.RamWriteValue", +]; + +pub const STAGE2_SUMCHECK_CLAIM_2_INPUT_OPENINGS: &[&str] = &["stage2.product_virtual.uniskip.opening.UnivariateSkip"]; + +pub const STAGE2_SUMCHECK_CLAIM_3_INPUT_OPENINGS: &[&str] = &[ + "stage2.input.stage1.LookupOutput", + "stage2.input.stage1.LeftLookupOperand", + "stage2.input.stage1.RightLookupOperand", + "stage2.input.stage1.LeftInstructionInput", + "stage2.input.stage1.RightInstructionInput", +]; + +pub const STAGE2_SUMCHECK_CLAIM_4_INPUT_OPENINGS: &[&str] = &["stage2.input.stage1.RamAddress"]; + +pub const STAGE2_SUMCHECK_CLAIM_5_INPUT_OPENINGS: &[&str] = &[]; + +pub const STAGE2_SUMCHECK_CLAIMS: &[Stage2SumcheckClaimPlan] = &[ + Stage2SumcheckClaimPlan { symbol: "stage2.product_virtual.uniskip.input", stage: "stage2", domain: "jolt.stage2_uniskip_domain", num_rounds: 1, degree: 6, claim: "stage2.product_virtual.weighted_stage1_outputs", kernel: Some("jolt.cpu.stage2.product_virtual.uniskip"), relation: None, claim_value: "stage2.product_virtual.uniskip.claim_expr", input_openings: STAGE2_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_read_write.input", stage: "stage2", domain: "jolt.stage2_ram_rw_domain", num_rounds: 32, degree: 3, claim: "stage2.ram_read_write.weighted_values", kernel: Some("jolt.cpu.stage2.ram.read_write"), relation: None, claim_value: "stage2.ram_read_write.claim_expr", input_openings: STAGE2_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, + Stage2SumcheckClaimPlan { symbol: "stage2.product_virtual.remainder.input", stage: "stage2", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage2.product_virtual.uniskip.opening", kernel: Some("jolt.cpu.stage2.product_virtual.remainder"), relation: None, claim_value: "stage2.product_virtual.uniskip.eval.UnivariateSkip", input_openings: STAGE2_SUMCHECK_CLAIM_2_INPUT_OPENINGS }, + Stage2SumcheckClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.input", stage: "stage2", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage2.instruction_lookup.weighted_operands", kernel: Some("jolt.cpu.stage2.instruction_lookup.claim_reduction"), relation: None, claim_value: "stage2.instruction_lookup.claim_reduction.claim_expr", input_openings: STAGE2_SUMCHECK_CLAIM_3_INPUT_OPENINGS }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_raf.input", stage: "stage2", domain: "jolt.ram_address_domain", num_rounds: 16, degree: 2, claim: "stage2.ram_raf.ram_address", kernel: Some("jolt.cpu.stage2.ram.raf_evaluation"), relation: None, claim_value: "stage2.input.stage1.RamAddress", input_openings: STAGE2_SUMCHECK_CLAIM_4_INPUT_OPENINGS }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_output.input", stage: "stage2", domain: "jolt.ram_address_domain", num_rounds: 16, degree: 3, claim: "zero", kernel: Some("jolt.cpu.stage2.ram.output_check"), relation: None, claim_value: "stage2.ram_output.zero", input_openings: STAGE2_SUMCHECK_CLAIM_5_INPUT_OPENINGS }, +]; +pub const STAGE2_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &["stage2.product_virtual.uniskip.input"]; + +pub const STAGE2_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &["stage2.product_virtual.uniskip.input"]; + +pub const STAGE2_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE2_SUMCHECK_BATCH_1_ORDERED_CLAIMS: &[&str] = &[ + "stage2.ram_read_write.input", + "stage2.product_virtual.remainder.input", + "stage2.instruction_lookup.claim_reduction.input", + "stage2.ram_raf.input", + "stage2.ram_output.input", +]; + +pub const STAGE2_SUMCHECK_BATCH_1_CLAIM_OPERANDS: &[&str] = &[ + "stage2.ram_read_write.input", + "stage2.product_virtual.remainder.input", + "stage2.instruction_lookup.claim_reduction.input", + "stage2.ram_raf.input", + "stage2.ram_output.input", +]; + +pub const STAGE2_SUMCHECK_BATCH_1_ROUND_SCHEDULE: &[usize] = &[ + 16, + 16, +]; + +pub const STAGE2_SUMCHECK_BATCHES: &[Stage2SumcheckBatchPlan] = &[ + Stage2SumcheckBatchPlan { symbol: "stage2.product_virtual.uniskip.batch", stage: "stage2", proof_slot: "stage2.product_virtual.uni_skip_first_round", policy: "single_instance", count: 1, ordered_claims: STAGE2_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE2_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "uniskip_claim", round_label: "uniskip_poly", round_schedule: STAGE2_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, + Stage2SumcheckBatchPlan { symbol: "stage2.batch", stage: "stage2", proof_slot: "stage2.sumcheck", policy: "jolt_core_stage2_aligned", count: 5, ordered_claims: STAGE2_SUMCHECK_BATCH_1_ORDERED_CLAIMS, claim_operands: STAGE2_SUMCHECK_BATCH_1_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE2_SUMCHECK_BATCH_1_ROUND_SCHEDULE }, +]; +pub const STAGE2_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE2_SUMCHECK_DRIVER_1_ROUND_SCHEDULE: &[usize] = &[ + 16, + 16, +]; + +pub const STAGE2_SUMCHECK_DRIVERS: &[Stage2SumcheckDriverPlan] = &[ + Stage2SumcheckDriverPlan { symbol: "stage2.product_virtual.uniskip.sumcheck", stage: "stage2", proof_slot: "stage2.product_virtual.uni_skip_first_round", kernel: Some("jolt.cpu.stage2.product_virtual.uniskip"), relation: None, batch: "stage2.product_virtual.uniskip.batch", policy: "univariate_skip", round_schedule: STAGE2_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "uniskip_claim", round_label: "uniskip_poly", num_rounds: 1, degree: 6 }, + Stage2SumcheckDriverPlan { symbol: "stage2.sumcheck", stage: "stage2", proof_slot: "stage2.sumcheck", kernel: Some("jolt.cpu.stage2.batched"), relation: None, batch: "stage2.batch", policy: "jolt_core_stage2_aligned", round_schedule: STAGE2_SUMCHECK_DRIVER_1_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 32, degree: 3 }, +]; +pub const STAGE2_SUMCHECK_INSTANCE_RESULTS: &[Stage2SumcheckInstanceResultPlan] = &[ + Stage2SumcheckInstanceResultPlan { symbol: "stage2.product_virtual.uniskip.instance", source: "stage2.product_virtual.uniskip.sumcheck", claim: "stage2.product_virtual.uniskip.input", relation: "jolt.stage2.product_virtual.uniskip", index: 0, point_arity: 1, num_rounds: 1, round_offset: 0, point_order: "as_is", degree: 6 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_read_write.instance", source: "stage2.sumcheck", claim: "stage2.ram_read_write.input", relation: "jolt.stage2.ram.read_write", index: 0, point_arity: 32, num_rounds: 32, round_offset: 0, point_order: "reverse", degree: 3 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.product_virtual.remainder.instance", source: "stage2.sumcheck", claim: "stage2.product_virtual.remainder.input", relation: "jolt.stage2.product_virtual.remainder", index: 1, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 3 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.instruction_lookup.claim_reduction.instance", source: "stage2.sumcheck", claim: "stage2.instruction_lookup.claim_reduction.input", relation: "jolt.stage2.instruction_lookup.claim_reduction", index: 2, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 2 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_raf.instance", source: "stage2.sumcheck", claim: "stage2.ram_raf.input", relation: "jolt.stage2.ram.raf_evaluation", index: 3, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 2 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_output.instance", source: "stage2.sumcheck", claim: "stage2.ram_output.input", relation: "jolt.stage2.ram.output_check", index: 4, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE2_SUMCHECK_EVALS: &[Stage2SumcheckEvalPlan] = &[ + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.uniskip.eval.UnivariateSkip", source: "stage2.product_virtual.uniskip.sumcheck", name: "stage2.product_virtual.uniskip.eval.UnivariateSkip", index: 0, oracle: "UnivariateSkip" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamVal", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamVal", index: 0, oracle: "RamVal" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamRa", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamRa", index: 1, oracle: "RamRa" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamInc", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamInc", index: 2, oracle: "RamInc" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.LeftInstructionInput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.LeftInstructionInput", index: 0, oracle: "LeftInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.RightInstructionInput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.RightInstructionInput", index: 1, oracle: "RightInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagJump", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagJump", index: 2, oracle: "OpFlagJump" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD", index: 3, oracle: "OpFlagWriteLookupOutputToRD" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.LookupOutput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.LookupOutput", index: 4, oracle: "LookupOutput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.InstructionFlagBranch", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.InstructionFlagBranch", index: 5, oracle: "InstructionFlagBranch" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.NextIsNoop", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.NextIsNoop", index: 6, oracle: "NextIsNoop" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction", index: 7, oracle: "OpFlagVirtualInstruction" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", index: 0, oracle: "LookupOutput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", index: 1, oracle: "LeftLookupOperand" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", index: 2, oracle: "RightLookupOperand" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", index: 3, oracle: "LeftInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", index: 4, oracle: "RightInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_raf.eval.RamRa", source: "stage2.sumcheck", name: "stage2.ram_raf.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_output.eval.RamValFinal", source: "stage2.sumcheck", name: "stage2.ram_output.eval.RamValFinal", index: 0, oracle: "RamValFinal" }, +]; + +pub const STAGE2_POINT_SLICES: &[Stage2PointSlicePlan] = &[ + Stage2PointSlicePlan { symbol: "stage2.ram_read_write.point.RamInc", source: "stage2.ram_read_write.instance", offset: 16, length: 16, input: "stage2.ram_read_write.instance" }, +]; + +pub const STAGE2_POINT_CONCAT_0_INPUTS: &[&str] = &[ + "stage2.ram_raf.instance", + "stage2.input.stage1.RamAddress", +]; + +pub const STAGE2_POINT_CONCATS: &[Stage2PointConcatPlan] = &[ + Stage2PointConcatPlan { symbol: "stage2.ram_raf.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: STAGE2_POINT_CONCAT_0_INPUTS }, +]; +pub const STAGE2_OPENING_CLAIMS: &[Stage2OpeningClaimPlan] = &[ + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.uniskip.opening.UnivariateSkip", oracle: "UnivariateSkip", domain: "jolt.stage2_uniskip_domain", point_arity: 1, claim_kind: "virtual", point_source: "stage2.product_virtual.uniskip.instance", eval_source: "stage2.product_virtual.uniskip.eval.UnivariateSkip" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamVal", oracle: "RamVal", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_read_write.instance", eval_source: "stage2.ram_read_write.eval.RamVal" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_read_write.instance", eval_source: "stage2.ram_read_write.eval.RamRa" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage2.ram_read_write.point.RamInc", eval_source: "stage2.ram_read_write.eval.RamInc" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.LeftInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.RightInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagJump" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.LookupOutput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.InstructionFlagBranch", oracle: "InstructionFlagBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.InstructionFlagBranch" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.NextIsNoop", oracle: "NextIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.NextIsNoop" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_raf.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_raf.point.RamRa", eval_source: "stage2.ram_raf.eval.RamRa" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_output.opening.RamValFinal", oracle: "RamValFinal", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.ram_output.instance", eval_source: "stage2.ram_output.eval.RamValFinal" }, +]; + +pub const STAGE2_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage2.ram_read_write.opening.RamVal", + "stage2.ram_read_write.opening.RamRa", + "stage2.ram_read_write.opening.RamInc", + "stage2.product_virtual.remainder.opening.LeftInstructionInput", + "stage2.product_virtual.remainder.opening.RightInstructionInput", + "stage2.product_virtual.remainder.opening.OpFlagJump", + "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", + "stage2.product_virtual.remainder.opening.LookupOutput", + "stage2.product_virtual.remainder.opening.InstructionFlagBranch", + "stage2.product_virtual.remainder.opening.NextIsNoop", + "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", + "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", + "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", + "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", + "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", + "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", + "stage2.ram_raf.opening.RamRa", + "stage2.ram_output.opening.RamValFinal", +]; + +pub const STAGE2_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage2.ram_read_write.opening.RamVal", + "stage2.ram_read_write.opening.RamRa", + "stage2.ram_read_write.opening.RamInc", + "stage2.product_virtual.remainder.opening.LeftInstructionInput", + "stage2.product_virtual.remainder.opening.RightInstructionInput", + "stage2.product_virtual.remainder.opening.OpFlagJump", + "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", + "stage2.product_virtual.remainder.opening.LookupOutput", + "stage2.product_virtual.remainder.opening.InstructionFlagBranch", + "stage2.product_virtual.remainder.opening.NextIsNoop", + "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", + "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", + "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", + "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", + "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", + "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", + "stage2.ram_raf.opening.RamRa", + "stage2.ram_output.opening.RamValFinal", +]; + +pub const STAGE2_OPENING_BATCHES: &[Stage2OpeningBatchPlan] = &[ + Stage2OpeningBatchPlan { symbol: "stage2.openings", stage: "stage2", proof_slot: "stage2.openings", policy: "jolt_stage2_output_order", count: 18, ordered_claims: STAGE2_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE2_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE2_PROGRAM: Stage2CpuProgramPlan = Stage2CpuProgramPlan { + params: STAGE2_PARAMS, + steps: STAGE2_PROGRAM_STEPS, + transcript_squeezes: STAGE2_TRANSCRIPT_SQUEEZES, + opening_inputs: STAGE2_OPENING_INPUTS, + field_constants: STAGE2_FIELD_CONSTANTS, + field_exprs: STAGE2_FIELD_EXPRS, + kernels: STAGE2_KERNELS, + claims: STAGE2_SUMCHECK_CLAIMS, + batches: STAGE2_SUMCHECK_BATCHES, + drivers: STAGE2_SUMCHECK_DRIVERS, + instance_results: STAGE2_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE2_SUMCHECK_EVALS, + point_slices: STAGE2_POINT_SLICES, + point_concats: STAGE2_POINT_CONCATS, + opening_claims: STAGE2_OPENING_CLAIMS, + opening_batches: STAGE2_OPENING_BATCHES, +}; + +pub fn execute_stage2_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + E: Stage2KernelExecutor, + T: Transcript, +{ + execute_stage2_prover_with_program(&STAGE2_PROGRAM, executor, transcript) +} + +pub fn execute_stage2_prover_with_program( + program: &'static Stage2CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage2KernelError> +where + E: Stage2KernelExecutor, + T: Transcript, +{ + execute_stage2_program(program, Stage2ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage3.rs b/crates/jolt-prover/src/stages/stage3.rs new file mode 100644 index 0000000000..f1ca47494b --- /dev/null +++ b/crates/jolt-prover/src/stages/stage3.rs @@ -0,0 +1,351 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage3::{execute_stage3_program, Stage3CpuProgramPlan, Stage3ExecutionArtifacts, Stage3ExecutionMode, Stage3FieldConstantPlan, Stage3FieldExprPlan, Stage3KernelError, Stage3KernelExecutor, Stage3KernelPlan, Stage3OpeningBatchPlan, Stage3OpeningClaimEqualityPlan, Stage3OpeningClaimPlan, Stage3OpeningInputPlan, Stage3Params, Stage3PointConcatPlan, Stage3PointSlicePlan, Stage3ProgramStepPlan, Stage3SumcheckBatchPlan, Stage3SumcheckClaimPlan, Stage3SumcheckDriverPlan, Stage3SumcheckEvalPlan, Stage3SumcheckInstanceResultPlan, Stage3TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage3Transcript = Blake2bTranscript; + +pub const STAGE3_PARAMS: Stage3Params = Stage3Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE3_PROGRAM_STEPS: &[Stage3ProgramStepPlan] = &[ + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.spartan_shift.gamma" }, + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.instruction_input.gamma" }, + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.registers.gamma" }, + Stage3ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage3.sumcheck" }, +]; + +pub const STAGE3_TRANSCRIPT_SQUEEZES: &[Stage3TranscriptSqueezePlan] = &[ + Stage3TranscriptSqueezePlan { symbol: "stage3.spartan_shift.gamma", label: "spartan_shift_gamma", kind: "challenge_scalar", count: 1 }, + Stage3TranscriptSqueezePlan { symbol: "stage3.instruction_input.gamma", label: "instruction_input_gamma", kind: "challenge_scalar", count: 1 }, + Stage3TranscriptSqueezePlan { symbol: "stage3.registers.gamma", label: "registers_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE3_OPENING_INPUTS: &[Stage3OpeningInputPlan] = &[ + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextUnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextUnexpandedPC", oracle: "NextUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextPC", oracle: "NextPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextIsVirtual", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextIsVirtual", oracle: "NextIsVirtual", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextIsFirstInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextIsFirstInSequence", oracle: "NextIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.NextIsNoop", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.NextIsNoop", oracle: "NextIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.LeftInstructionInput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.RightInstructionInput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.instruction_lookup.LeftInstructionInput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.instruction_lookup.RightInstructionInput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.RdWriteValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.Rs1Value", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.Rs2Value", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE3_FIELD_CONSTANTS: &[Stage3FieldConstantPlan] = &[ + Stage3FieldConstantPlan { symbol: "stage3.field.one", field: "bn254_fr", value: 1 }, +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage3.spartan_shift.gamma"]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_1: &[&str] = &[ + "stage3.spartan_shift.gamma2", + "stage3.spartan_shift.gamma", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage3.spartan_shift.gamma2", + "stage3.spartan_shift.gamma2", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage3.spartan_shift.gamma", + "stage3.input.stage1.NextPC", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage3.spartan_shift.gamma2", + "stage3.input.stage1.NextIsVirtual", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_5: &[&str] = &[ + "stage3.spartan_shift.gamma3", + "stage3.input.stage1.NextIsFirstInSequence", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage3.field.one", + "stage3.input.stage2.product_virtual.NextIsNoop", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage3.spartan_shift.gamma4", + "stage3.spartan_shift.one_minus.NextIsNoop", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage3.input.stage1.NextUnexpandedPC", + "stage3.spartan_shift.term.NextPC", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_9: &[&str] = &[ + "stage3.spartan_shift.partial.NextUnexpandedPCNextPC", + "stage3.spartan_shift.term.NextIsVirtual", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_10: &[&str] = &[ + "stage3.spartan_shift.partial.NextIsVirtual", + "stage3.spartan_shift.term.NextIsFirstInSequence", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_11: &[&str] = &[ + "stage3.spartan_shift.partial.NextIsFirstInSequence", + "stage3.spartan_shift.term.NextIsNoop", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_12: &[&str] = &[ + "stage3.instruction_input.gamma", + "stage3.input.stage2.product_virtual.LeftInstructionInput", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_13: &[&str] = &[ + "stage3.input.stage2.product_virtual.RightInstructionInput", + "stage3.instruction_input.term.LeftInstructionInput", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_14: &[&str] = &["stage3.registers.gamma"]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_15: &[&str] = &[ + "stage3.registers.gamma", + "stage3.input.stage1.Rs1Value", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_16: &[&str] = &[ + "stage3.registers.gamma2", + "stage3.input.stage1.Rs2Value", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_17: &[&str] = &[ + "stage3.input.stage1.RdWriteValue", + "stage3.registers.term.Rs1Value", +]; + +pub const STAGE3_FIELD_EXPR_OPERANDS_18: &[&str] = &[ + "stage3.registers.partial.RdWriteValueRs1Value", + "stage3.registers.term.Rs2Value", +]; + +pub const STAGE3_FIELD_EXPRS: &[Stage3FieldExprPlan] = &[ + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma2", kind: "op", formula: "field.pow:2", operand_names: STAGE3_FIELD_EXPR_OPERANDS_0, operands: STAGE3_FIELD_EXPR_OPERANDS_0 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma3", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_1, operands: STAGE3_FIELD_EXPR_OPERANDS_1 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma4", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_2, operands: STAGE3_FIELD_EXPR_OPERANDS_2 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextPC", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_3, operands: STAGE3_FIELD_EXPR_OPERANDS_3 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsVirtual", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_4, operands: STAGE3_FIELD_EXPR_OPERANDS_4 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsFirstInSequence", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_5, operands: STAGE3_FIELD_EXPR_OPERANDS_5 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.one_minus.NextIsNoop", kind: "op", formula: "field.sub", operand_names: STAGE3_FIELD_EXPR_OPERANDS_6, operands: STAGE3_FIELD_EXPR_OPERANDS_6 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsNoop", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_7, operands: STAGE3_FIELD_EXPR_OPERANDS_7 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextUnexpandedPCNextPC", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_8, operands: STAGE3_FIELD_EXPR_OPERANDS_8 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextIsVirtual", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_9, operands: STAGE3_FIELD_EXPR_OPERANDS_9 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextIsFirstInSequence", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_10, operands: STAGE3_FIELD_EXPR_OPERANDS_10 }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_11, operands: STAGE3_FIELD_EXPR_OPERANDS_11 }, + Stage3FieldExprPlan { symbol: "stage3.instruction_input.term.LeftInstructionInput", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_12, operands: STAGE3_FIELD_EXPR_OPERANDS_12 }, + Stage3FieldExprPlan { symbol: "stage3.instruction_input.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_13, operands: STAGE3_FIELD_EXPR_OPERANDS_13 }, + Stage3FieldExprPlan { symbol: "stage3.registers.gamma2", kind: "op", formula: "field.pow:2", operand_names: STAGE3_FIELD_EXPR_OPERANDS_14, operands: STAGE3_FIELD_EXPR_OPERANDS_14 }, + Stage3FieldExprPlan { symbol: "stage3.registers.term.Rs1Value", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_15, operands: STAGE3_FIELD_EXPR_OPERANDS_15 }, + Stage3FieldExprPlan { symbol: "stage3.registers.term.Rs2Value", kind: "op", formula: "field.mul", operand_names: STAGE3_FIELD_EXPR_OPERANDS_16, operands: STAGE3_FIELD_EXPR_OPERANDS_16 }, + Stage3FieldExprPlan { symbol: "stage3.registers.partial.RdWriteValueRs1Value", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_17, operands: STAGE3_FIELD_EXPR_OPERANDS_17 }, + Stage3FieldExprPlan { symbol: "stage3.registers.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE3_FIELD_EXPR_OPERANDS_18, operands: STAGE3_FIELD_EXPR_OPERANDS_18 }, +]; +pub const STAGE3_KERNELS: &[Stage3KernelPlan] = &[ + Stage3KernelPlan { symbol: "jolt.cpu.stage3.spartan_shift", relation: "jolt.stage3.spartan_shift", kind: "sumcheck", backend: "cpu", abi: "jolt_stage3_spartan_shift" }, + Stage3KernelPlan { symbol: "jolt.cpu.stage3.instruction_input", relation: "jolt.stage3.instruction_input", kind: "sumcheck", backend: "cpu", abi: "jolt_stage3_instruction_input" }, + Stage3KernelPlan { symbol: "jolt.cpu.stage3.registers_claim_reduction", relation: "jolt.stage3.registers_claim_reduction", kind: "sumcheck", backend: "cpu", abi: "jolt_stage3_registers_claim_reduction" }, + Stage3KernelPlan { symbol: "jolt.cpu.stage3.batched", relation: "jolt.stage3.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage3_batched" }, +]; + +pub const STAGE3_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage3.input.stage1.NextUnexpandedPC", + "stage3.input.stage1.NextPC", + "stage3.input.stage1.NextIsVirtual", + "stage3.input.stage1.NextIsFirstInSequence", + "stage3.input.stage2.product_virtual.NextIsNoop", +]; + +pub const STAGE3_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &[ + "stage3.input.stage2.product_virtual.RightInstructionInput", + "stage3.input.stage2.product_virtual.LeftInstructionInput", +]; + +pub const STAGE3_SUMCHECK_CLAIM_2_INPUT_OPENINGS: &[&str] = &[ + "stage3.input.stage1.RdWriteValue", + "stage3.input.stage1.Rs1Value", + "stage3.input.stage1.Rs2Value", +]; + +pub const STAGE3_SUMCHECK_CLAIMS: &[Stage3SumcheckClaimPlan] = &[ + Stage3SumcheckClaimPlan { symbol: "stage3.spartan_shift.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage3.spartan_shift.weighted_next_values", kernel: Some("jolt.cpu.stage3.spartan_shift"), relation: None, claim_value: "stage3.spartan_shift.claim_expr", input_openings: STAGE3_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage3SumcheckClaimPlan { symbol: "stage3.instruction_input.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage3.instruction_input.weighted_inputs", kernel: Some("jolt.cpu.stage3.instruction_input"), relation: None, claim_value: "stage3.instruction_input.claim_expr", input_openings: STAGE3_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, + Stage3SumcheckClaimPlan { symbol: "stage3.registers_claim_reduction.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage3.registers.weighted_register_values", kernel: Some("jolt.cpu.stage3.registers_claim_reduction"), relation: None, claim_value: "stage3.registers.claim_expr", input_openings: STAGE3_SUMCHECK_CLAIM_2_INPUT_OPENINGS }, +]; +pub const STAGE3_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage3.spartan_shift.input", + "stage3.instruction_input.input", + "stage3.registers_claim_reduction.input", +]; + +pub const STAGE3_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage3.spartan_shift.input", + "stage3.instruction_input.input", + "stage3.registers_claim_reduction.input", +]; + +pub const STAGE3_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 16, +]; + +pub const STAGE3_SUMCHECK_BATCHES: &[Stage3SumcheckBatchPlan] = &[ + Stage3SumcheckBatchPlan { symbol: "stage3.batch", stage: "stage3", proof_slot: "stage3.sumcheck", policy: "jolt_core_stage3_aligned", count: 3, ordered_claims: STAGE3_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE3_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE3_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE3_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 16, +]; + +pub const STAGE3_SUMCHECK_DRIVERS: &[Stage3SumcheckDriverPlan] = &[ + Stage3SumcheckDriverPlan { symbol: "stage3.sumcheck", stage: "stage3", proof_slot: "stage3.sumcheck", kernel: Some("jolt.cpu.stage3.batched"), relation: None, batch: "stage3.batch", policy: "jolt_core_stage3_aligned", round_schedule: STAGE3_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 16, degree: 3 }, +]; +pub const STAGE3_SUMCHECK_INSTANCE_RESULTS: &[Stage3SumcheckInstanceResultPlan] = &[ + Stage3SumcheckInstanceResultPlan { symbol: "stage3.spartan_shift.instance", source: "stage3.sumcheck", claim: "stage3.spartan_shift.input", relation: "jolt.stage3.spartan_shift", index: 0, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 2 }, + Stage3SumcheckInstanceResultPlan { symbol: "stage3.instruction_input.instance", source: "stage3.sumcheck", claim: "stage3.instruction_input.input", relation: "jolt.stage3.instruction_input", index: 1, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 3 }, + Stage3SumcheckInstanceResultPlan { symbol: "stage3.registers_claim_reduction.instance", source: "stage3.sumcheck", claim: "stage3.registers_claim_reduction.input", relation: "jolt.stage3.registers_claim_reduction", index: 2, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 2 }, +]; + +pub const STAGE3_SUMCHECK_EVALS: &[Stage3SumcheckEvalPlan] = &[ + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.UnexpandedPC", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.UnexpandedPC", index: 0, oracle: "UnexpandedPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.PC", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.PC", index: 1, oracle: "PC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.OpFlagVirtualInstruction", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.OpFlagVirtualInstruction", index: 2, oracle: "OpFlagVirtualInstruction" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", index: 3, oracle: "OpFlagIsFirstInSequence" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.InstructionFlagIsNoop", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.InstructionFlagIsNoop", index: 4, oracle: "InstructionFlagIsNoop" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", index: 5, oracle: "InstructionFlagLeftOperandIsRs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Rs1Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Rs1Value", index: 6, oracle: "Rs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", index: 7, oracle: "InstructionFlagLeftOperandIsPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.UnexpandedPC", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.UnexpandedPC", index: 8, oracle: "UnexpandedPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", index: 9, oracle: "InstructionFlagRightOperandIsRs2Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Rs2Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Rs2Value", index: 10, oracle: "Rs2Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", index: 11, oracle: "InstructionFlagRightOperandIsImm" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Imm", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Imm", index: 12, oracle: "Imm" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.RdWriteValue", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.RdWriteValue", index: 13, oracle: "RdWriteValue" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.Rs1Value", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.Rs1Value", index: 14, oracle: "Rs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.Rs2Value", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.Rs2Value", index: 15, oracle: "Rs2Value" }, +]; + +pub const STAGE3_POINT_SLICES: &[Stage3PointSlicePlan] = &[ + +]; + +pub const STAGE3_POINT_CONCATS: &[Stage3PointConcatPlan] = &[ + +]; +pub const STAGE3_OPENING_CLAIMS: &[Stage3OpeningClaimPlan] = &[ + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.UnexpandedPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.PC" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.OpFlagVirtualInstruction" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.InstructionFlagIsNoop", oracle: "InstructionFlagIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.InstructionFlagIsNoop" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", oracle: "InstructionFlagLeftOperandIsRs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Rs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", oracle: "InstructionFlagLeftOperandIsPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.UnexpandedPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", oracle: "InstructionFlagRightOperandIsRs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Rs2Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", oracle: "InstructionFlagRightOperandIsImm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Imm" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.RdWriteValue" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.Rs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.Rs2Value" }, +]; + +pub const STAGE3_OPENING_EQUALITIES: &[Stage3OpeningClaimEqualityPlan] = &[ + Stage3OpeningClaimEqualityPlan { symbol: "stage3.instruction_input.left_claim_consistency", mode: "point_and_eval", lhs: "stage3.input.stage2.product_virtual.LeftInstructionInput", rhs: "stage3.input.stage2.instruction_lookup.LeftInstructionInput" }, + Stage3OpeningClaimEqualityPlan { symbol: "stage3.instruction_input.right_claim_consistency", mode: "point_and_eval", lhs: "stage3.input.stage2.product_virtual.RightInstructionInput", rhs: "stage3.input.stage2.instruction_lookup.RightInstructionInput" }, +]; + +pub const STAGE3_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage3.spartan_shift.opening.UnexpandedPC", + "stage3.spartan_shift.opening.PC", + "stage3.spartan_shift.opening.OpFlagVirtualInstruction", + "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", + "stage3.spartan_shift.opening.InstructionFlagIsNoop", + "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", + "stage3.instruction_input.opening.Rs1Value", + "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", + "stage3.instruction_input.opening.UnexpandedPC", + "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", + "stage3.instruction_input.opening.Rs2Value", + "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", + "stage3.instruction_input.opening.Imm", + "stage3.registers_claim_reduction.opening.RdWriteValue", + "stage3.registers_claim_reduction.opening.Rs1Value", + "stage3.registers_claim_reduction.opening.Rs2Value", +]; + +pub const STAGE3_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage3.spartan_shift.opening.UnexpandedPC", + "stage3.spartan_shift.opening.PC", + "stage3.spartan_shift.opening.OpFlagVirtualInstruction", + "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", + "stage3.spartan_shift.opening.InstructionFlagIsNoop", + "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", + "stage3.instruction_input.opening.Rs1Value", + "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", + "stage3.instruction_input.opening.UnexpandedPC", + "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", + "stage3.instruction_input.opening.Rs2Value", + "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", + "stage3.instruction_input.opening.Imm", + "stage3.registers_claim_reduction.opening.RdWriteValue", + "stage3.registers_claim_reduction.opening.Rs1Value", + "stage3.registers_claim_reduction.opening.Rs2Value", +]; + +pub const STAGE3_OPENING_BATCHES: &[Stage3OpeningBatchPlan] = &[ + Stage3OpeningBatchPlan { symbol: "stage3.openings", stage: "stage3", proof_slot: "stage3.openings", policy: "jolt_stage3_output_order", count: 16, ordered_claims: STAGE3_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE3_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE3_PROGRAM: Stage3CpuProgramPlan = Stage3CpuProgramPlan { + params: STAGE3_PARAMS, + steps: STAGE3_PROGRAM_STEPS, + transcript_squeezes: STAGE3_TRANSCRIPT_SQUEEZES, + opening_inputs: STAGE3_OPENING_INPUTS, + field_constants: STAGE3_FIELD_CONSTANTS, + field_exprs: STAGE3_FIELD_EXPRS, + kernels: STAGE3_KERNELS, + claims: STAGE3_SUMCHECK_CLAIMS, + batches: STAGE3_SUMCHECK_BATCHES, + drivers: STAGE3_SUMCHECK_DRIVERS, + instance_results: STAGE3_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE3_SUMCHECK_EVALS, + point_slices: STAGE3_POINT_SLICES, + point_concats: STAGE3_POINT_CONCATS, + opening_claims: STAGE3_OPENING_CLAIMS, + opening_equalities: STAGE3_OPENING_EQUALITIES, + opening_batches: STAGE3_OPENING_BATCHES, +}; + +pub fn execute_stage3_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + E: Stage3KernelExecutor, + T: Transcript, +{ + execute_stage3_prover_with_program(&STAGE3_PROGRAM, executor, transcript) +} + +pub fn execute_stage3_prover_with_program( + program: &'static Stage3CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage3KernelError> +where + E: Stage3KernelExecutor, + T: Transcript, +{ + execute_stage3_program(program, Stage3ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage4.rs b/crates/jolt-prover/src/stages/stage4.rs new file mode 100644 index 0000000000..03a8258a94 --- /dev/null +++ b/crates/jolt-prover/src/stages/stage4.rs @@ -0,0 +1,255 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage4::{execute_stage4_program, Stage4CpuProgramPlan, Stage4ExecutionArtifacts, Stage4ExecutionMode, Stage4FieldConstantPlan, Stage4FieldExprPlan, Stage4KernelError, Stage4KernelExecutor, Stage4KernelPlan, Stage4OpeningBatchPlan, Stage4OpeningClaimEqualityPlan, Stage4OpeningClaimPlan, Stage4OpeningInputPlan, Stage4Params, Stage4PointConcatPlan, Stage4PointSlicePlan, Stage4ProgramStepPlan, Stage4SumcheckBatchPlan, Stage4SumcheckClaimPlan, Stage4SumcheckDriverPlan, Stage4SumcheckEvalPlan, Stage4SumcheckInstanceResultPlan, Stage4TranscriptAbsorbBytesPlan, Stage4TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage4Transcript = Blake2bTranscript; + +pub const STAGE4_PARAMS: Stage4Params = Stage4Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE4_PROGRAM_STEPS: &[Stage4ProgramStepPlan] = &[ + Stage4ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage4.registers_read_write.gamma" }, + Stage4ProgramStepPlan { kind: "transcript_absorb_bytes", symbol: "stage4.ram_val_check.domain_separator" }, + Stage4ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage4.ram_val_check.gamma" }, + Stage4ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage4.sumcheck" }, +]; + +pub const STAGE4_TRANSCRIPT_SQUEEZES: &[Stage4TranscriptSqueezePlan] = &[ + Stage4TranscriptSqueezePlan { symbol: "stage4.registers_read_write.gamma", label: "registers_read_write_gamma", kind: "challenge_scalar", count: 1 }, + Stage4TranscriptSqueezePlan { symbol: "stage4.ram_val_check.gamma", label: "ram_val_check_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE4_TRANSCRIPT_ABSORB_BYTES: &[Stage4TranscriptAbsorbBytesPlan] = &[ + Stage4TranscriptAbsorbBytesPlan { symbol: "stage4.ram_val_check.domain_separator", label: "ram_val_check_gamma", payload: "" }, +]; + +pub const STAGE4_OPENING_INPUTS: &[Stage4OpeningInputPlan] = &[ + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.RdWriteValue", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.Rs1Value", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.Rs2Value", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.instruction.Rs1Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.instruction.Rs2Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage2.RamVal", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamVal", oracle: "RamVal", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage2.RamValFinal", source_stage: "stage2", source_claim: "stage2.ram_output.opening.RamValFinal", oracle: "RamValFinal", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.initial_ram.RamValInit", source_stage: "stage4_precomputed", source_claim: "stage4.ram_val_check.initial_ram_eval", oracle: "RamValInit", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE4_FIELD_CONSTANTS: &[Stage4FieldConstantPlan] = &[ + +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage4.registers_read_write.gamma"]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_1: &[&str] = &[ + "stage4.registers_read_write.gamma", + "stage4.input.stage3.registers.Rs1Value", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage4.registers_read_write.gamma2", + "stage4.input.stage3.registers.Rs2Value", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage4.input.stage3.registers.RdWriteValue", + "stage4.registers_read_write.term.Rs1Value", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage4.registers_read_write.partial.RdWriteValueRs1Value", + "stage4.registers_read_write.term.Rs2Value", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_5: &[&str] = &[ + "stage4.input.stage2.RamVal", + "stage4.input.initial_ram.RamValInit", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage4.input.stage2.RamValFinal", + "stage4.input.initial_ram.RamValInit", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage4.ram_val_check.gamma", + "stage4.ram_val_check.delta.RamValFinal", +]; + +pub const STAGE4_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage4.ram_val_check.delta.RamVal", + "stage4.ram_val_check.term.RamValFinal", +]; + +pub const STAGE4_FIELD_EXPRS: &[Stage4FieldExprPlan] = &[ + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.gamma2", kind: "op", formula: "field.pow:2", operand_names: STAGE4_FIELD_EXPR_OPERANDS_0, operands: STAGE4_FIELD_EXPR_OPERANDS_0 }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.term.Rs1Value", kind: "op", formula: "field.mul", operand_names: STAGE4_FIELD_EXPR_OPERANDS_1, operands: STAGE4_FIELD_EXPR_OPERANDS_1 }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.term.Rs2Value", kind: "op", formula: "field.mul", operand_names: STAGE4_FIELD_EXPR_OPERANDS_2, operands: STAGE4_FIELD_EXPR_OPERANDS_2 }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.partial.RdWriteValueRs1Value", kind: "op", formula: "field.add", operand_names: STAGE4_FIELD_EXPR_OPERANDS_3, operands: STAGE4_FIELD_EXPR_OPERANDS_3 }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE4_FIELD_EXPR_OPERANDS_4, operands: STAGE4_FIELD_EXPR_OPERANDS_4 }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.delta.RamVal", kind: "op", formula: "field.sub", operand_names: STAGE4_FIELD_EXPR_OPERANDS_5, operands: STAGE4_FIELD_EXPR_OPERANDS_5 }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.delta.RamValFinal", kind: "op", formula: "field.sub", operand_names: STAGE4_FIELD_EXPR_OPERANDS_6, operands: STAGE4_FIELD_EXPR_OPERANDS_6 }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.term.RamValFinal", kind: "op", formula: "field.mul", operand_names: STAGE4_FIELD_EXPR_OPERANDS_7, operands: STAGE4_FIELD_EXPR_OPERANDS_7 }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE4_FIELD_EXPR_OPERANDS_8, operands: STAGE4_FIELD_EXPR_OPERANDS_8 }, +]; +pub const STAGE4_KERNELS: &[Stage4KernelPlan] = &[ + Stage4KernelPlan { symbol: "jolt.cpu.stage4.registers_read_write", relation: "jolt.stage4.registers_read_write", kind: "sumcheck", backend: "cpu", abi: "jolt_stage4_registers_read_write" }, + Stage4KernelPlan { symbol: "jolt.cpu.stage4.ram_val_check", relation: "jolt.stage4.ram_val_check", kind: "sumcheck", backend: "cpu", abi: "jolt_stage4_ram_val_check" }, + Stage4KernelPlan { symbol: "jolt.cpu.stage4.batched", relation: "jolt.stage4.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage4_batched" }, +]; + +pub const STAGE4_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage4.input.stage3.registers.RdWriteValue", + "stage4.input.stage3.registers.Rs1Value", + "stage4.input.stage3.registers.Rs2Value", +]; + +pub const STAGE4_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &[ + "stage4.input.stage2.RamVal", + "stage4.input.stage2.RamValFinal", + "stage4.input.initial_ram.RamValInit", +]; + +pub const STAGE4_SUMCHECK_CLAIMS: &[Stage4SumcheckClaimPlan] = &[ + Stage4SumcheckClaimPlan { symbol: "stage4.registers_read_write.input", stage: "stage4", domain: "jolt.stage4_registers_rw_domain", num_rounds: 23, degree: 3, claim: "stage4.registers_read_write.weighted_values", kernel: Some("jolt.cpu.stage4.registers_read_write"), relation: None, claim_value: "stage4.registers_read_write.claim_expr", input_openings: STAGE4_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage4SumcheckClaimPlan { symbol: "stage4.ram_val_check.input", stage: "stage4", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage4.ram_val_check.weighted_values", kernel: Some("jolt.cpu.stage4.ram_val_check"), relation: None, claim_value: "stage4.ram_val_check.claim_expr", input_openings: STAGE4_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, +]; +pub const STAGE4_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage4.registers_read_write.input", + "stage4.ram_val_check.input", +]; + +pub const STAGE4_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage4.registers_read_write.input", + "stage4.ram_val_check.input", +]; + +pub const STAGE4_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 16, + 7, +]; + +pub const STAGE4_SUMCHECK_BATCHES: &[Stage4SumcheckBatchPlan] = &[ + Stage4SumcheckBatchPlan { symbol: "stage4.batch", stage: "stage4", proof_slot: "stage4.sumcheck", policy: "jolt_core_stage4_aligned", count: 2, ordered_claims: STAGE4_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE4_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE4_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE4_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 16, + 7, +]; + +pub const STAGE4_SUMCHECK_DRIVERS: &[Stage4SumcheckDriverPlan] = &[ + Stage4SumcheckDriverPlan { symbol: "stage4.sumcheck", stage: "stage4", proof_slot: "stage4.sumcheck", kernel: Some("jolt.cpu.stage4.batched"), relation: None, batch: "stage4.batch", policy: "jolt_core_stage4_aligned", round_schedule: STAGE4_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 23, degree: 3 }, +]; +pub const STAGE4_SUMCHECK_INSTANCE_RESULTS: &[Stage4SumcheckInstanceResultPlan] = &[ + Stage4SumcheckInstanceResultPlan { symbol: "stage4.registers_read_write.instance", source: "stage4.sumcheck", claim: "stage4.registers_read_write.input", relation: "jolt.stage4.registers_read_write", index: 0, point_arity: 23, num_rounds: 23, round_offset: 0, point_order: "stage4_registers_rw", degree: 3 }, + Stage4SumcheckInstanceResultPlan { symbol: "stage4.ram_val_check.instance", source: "stage4.sumcheck", claim: "stage4.ram_val_check.input", relation: "jolt.stage4.ram_val_check", index: 1, point_arity: 16, num_rounds: 16, round_offset: 7, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE4_SUMCHECK_EVALS: &[Stage4SumcheckEvalPlan] = &[ + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RegistersVal", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RegistersVal", index: 0, oracle: "RegistersVal" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.Rs1Ra", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.Rs1Ra", index: 1, oracle: "Rs1Ra" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.Rs2Ra", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.Rs2Ra", index: 2, oracle: "Rs2Ra" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RdWa", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RdWa", index: 3, oracle: "RdWa" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RdInc", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RdInc", index: 4, oracle: "RdInc" }, + Stage4SumcheckEvalPlan { symbol: "stage4.ram_val_check.eval.RamRa", source: "stage4.sumcheck", name: "stage4.ram_val_check.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage4SumcheckEvalPlan { symbol: "stage4.ram_val_check.eval.RamInc", source: "stage4.sumcheck", name: "stage4.ram_val_check.eval.RamInc", index: 1, oracle: "RamInc" }, +]; + +pub const STAGE4_POINT_SLICES: &[Stage4PointSlicePlan] = &[ + Stage4PointSlicePlan { symbol: "stage4.registers_read_write.point.RdInc", source: "stage4.registers_read_write.instance", offset: 7, length: 16, input: "stage4.registers_read_write.instance" }, + Stage4PointSlicePlan { symbol: "stage4.ram_val_check.point.RamAddress", source: "stage4.input.stage2.RamVal", offset: 0, length: 16, input: "stage4.input.stage2.RamVal" }, +]; + +pub const STAGE4_POINT_CONCAT_0_INPUTS: &[&str] = &[ + "stage4.ram_val_check.point.RamAddress", + "stage4.ram_val_check.instance", +]; + +pub const STAGE4_POINT_CONCATS: &[Stage4PointConcatPlan] = &[ + Stage4PointConcatPlan { symbol: "stage4.ram_val_check.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: STAGE4_POINT_CONCAT_0_INPUTS }, +]; +pub const STAGE4_OPENING_CLAIMS: &[Stage4OpeningClaimPlan] = &[ + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RegistersVal", oracle: "RegistersVal", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.RegistersVal" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.Rs1Ra", oracle: "Rs1Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.Rs1Ra" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.Rs2Ra", oracle: "Rs2Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.Rs2Ra" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.RdWa" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage4.registers_read_write.point.RdInc", eval_source: "stage4.registers_read_write.eval.RdInc" }, + Stage4OpeningClaimPlan { symbol: "stage4.ram_val_check.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage4.ram_val_check.point.RamRa", eval_source: "stage4.ram_val_check.eval.RamRa" }, + Stage4OpeningClaimPlan { symbol: "stage4.ram_val_check.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage4.ram_val_check.instance", eval_source: "stage4.ram_val_check.eval.RamInc" }, +]; + +pub const STAGE4_OPENING_EQUALITIES: &[Stage4OpeningClaimEqualityPlan] = &[ + Stage4OpeningClaimEqualityPlan { symbol: "stage4.registers.rs1_claim_consistency", mode: "point_and_eval", lhs: "stage4.input.stage3.registers.Rs1Value", rhs: "stage4.input.stage3.instruction.Rs1Value" }, + Stage4OpeningClaimEqualityPlan { symbol: "stage4.registers.rs2_claim_consistency", mode: "point_and_eval", lhs: "stage4.input.stage3.registers.Rs2Value", rhs: "stage4.input.stage3.instruction.Rs2Value" }, +]; + +pub const STAGE4_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage4.registers_read_write.opening.RegistersVal", + "stage4.registers_read_write.opening.Rs1Ra", + "stage4.registers_read_write.opening.Rs2Ra", + "stage4.registers_read_write.opening.RdWa", + "stage4.registers_read_write.opening.RdInc", + "stage4.ram_val_check.opening.RamRa", + "stage4.ram_val_check.opening.RamInc", +]; + +pub const STAGE4_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage4.registers_read_write.opening.RegistersVal", + "stage4.registers_read_write.opening.Rs1Ra", + "stage4.registers_read_write.opening.Rs2Ra", + "stage4.registers_read_write.opening.RdWa", + "stage4.registers_read_write.opening.RdInc", + "stage4.ram_val_check.opening.RamRa", + "stage4.ram_val_check.opening.RamInc", +]; + +pub const STAGE4_OPENING_BATCHES: &[Stage4OpeningBatchPlan] = &[ + Stage4OpeningBatchPlan { symbol: "stage4.openings", stage: "stage4", proof_slot: "stage4.openings", policy: "jolt_stage4_output_order", count: 7, ordered_claims: STAGE4_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE4_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE4_PROGRAM: Stage4CpuProgramPlan = Stage4CpuProgramPlan { + role: "prover", + params: STAGE4_PARAMS, + steps: STAGE4_PROGRAM_STEPS, + transcript_squeezes: STAGE4_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE4_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE4_OPENING_INPUTS, + field_constants: STAGE4_FIELD_CONSTANTS, + field_exprs: STAGE4_FIELD_EXPRS, + kernels: STAGE4_KERNELS, + claims: STAGE4_SUMCHECK_CLAIMS, + batches: STAGE4_SUMCHECK_BATCHES, + drivers: STAGE4_SUMCHECK_DRIVERS, + instance_results: STAGE4_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE4_SUMCHECK_EVALS, + point_slices: STAGE4_POINT_SLICES, + point_concats: STAGE4_POINT_CONCATS, + opening_claims: STAGE4_OPENING_CLAIMS, + opening_equalities: STAGE4_OPENING_EQUALITIES, + opening_batches: STAGE4_OPENING_BATCHES, +}; + +pub fn execute_stage4_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + E: Stage4KernelExecutor, + T: Transcript, +{ + execute_stage4_prover_with_program(&STAGE4_PROGRAM, executor, transcript) +} + +pub fn execute_stage4_prover_with_program( + program: &'static Stage4CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage4KernelError> +where + E: Stage4KernelExecutor, + T: Transcript, +{ + execute_stage4_program(program, Stage4ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage5.rs b/crates/jolt-prover/src/stages/stage5.rs new file mode 100644 index 0000000000..22604c721f --- /dev/null +++ b/crates/jolt-prover/src/stages/stage5.rs @@ -0,0 +1,510 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage5::{execute_stage5_program, Stage5CpuProgramPlan, Stage5ExecutionArtifacts, Stage5ExecutionMode, Stage5FieldConstantPlan, Stage5FieldExprPlan, Stage5KernelError, Stage5KernelExecutor, Stage5KernelPlan, Stage5OpeningBatchPlan, Stage5OpeningClaimEqualityPlan, Stage5OpeningClaimPlan, Stage5OpeningInputPlan, Stage5Params, Stage5PointConcatPlan, Stage5PointSlicePlan, Stage5ProgramStepPlan, Stage5SumcheckBatchPlan, Stage5SumcheckClaimPlan, Stage5SumcheckDriverPlan, Stage5SumcheckEvalPlan, Stage5SumcheckInstanceResultPlan, Stage5TranscriptAbsorbBytesPlan, Stage5TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage5Transcript = Blake2bTranscript; + +pub const STAGE5_PARAMS: Stage5Params = Stage5Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE5_PROGRAM_STEPS: &[Stage5ProgramStepPlan] = &[ + Stage5ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage5.instruction_read_raf.gamma" }, + Stage5ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage5.ram_ra_claim_reduction.gamma" }, + Stage5ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage5.sumcheck" }, +]; + +pub const STAGE5_TRANSCRIPT_SQUEEZES: &[Stage5TranscriptSqueezePlan] = &[ + Stage5TranscriptSqueezePlan { symbol: "stage5.instruction_read_raf.gamma", label: "instruction_read_raf_gamma", kind: "challenge_scalar", count: 1 }, + Stage5TranscriptSqueezePlan { symbol: "stage5.ram_ra_claim_reduction.gamma", label: "ram_ra_claim_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE5_TRANSCRIPT_ABSORB_BYTES: &[Stage5TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE5_OPENING_INPUTS: &[Stage5OpeningInputPlan] = &[ + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.LookupOutput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.product_virtual.LookupOutput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.LeftLookupOperand", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.RightLookupOperand", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.ram_raf.RamRa", source_stage: "stage2", source_claim: "stage2.ram_raf.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.ram_read_write.RamRa", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage4.ram_val_check.RamRa", source_stage: "stage4", source_claim: "stage4.ram_val_check.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage4.registers.RegistersVal", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RegistersVal", oracle: "RegistersVal", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, +]; + +pub const STAGE5_FIELD_CONSTANTS: &[Stage5FieldConstantPlan] = &[ + +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage5.instruction_read_raf.gamma"]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_1: &[&str] = &[ + "stage5.instruction_read_raf.gamma", + "stage5.input.stage2.instruction.LeftLookupOperand", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage5.instruction_read_raf.gamma2", + "stage5.input.stage2.instruction.RightLookupOperand", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage5.input.stage2.instruction.LookupOutput", + "stage5.instruction_read_raf.term.LeftLookupOperand", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage5.instruction_read_raf.partial.LookupOutputLeftOperand", + "stage5.instruction_read_raf.term.RightLookupOperand", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_5: &[&str] = &["stage5.ram_ra_claim_reduction.gamma"]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage5.ram_ra_claim_reduction.gamma", + "stage5.input.stage2.ram_read_write.RamRa", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage5.ram_ra_claim_reduction.gamma2", + "stage5.input.stage4.ram_val_check.RamRa", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage5.input.stage2.ram_raf.RamRa", + "stage5.ram_ra_claim_reduction.term.RamRaReadWrite", +]; + +pub const STAGE5_FIELD_EXPR_OPERANDS_9: &[&str] = &[ + "stage5.ram_ra_claim_reduction.partial.RafReadWrite", + "stage5.ram_ra_claim_reduction.term.RamRaValCheck", +]; + +pub const STAGE5_FIELD_EXPRS: &[Stage5FieldExprPlan] = &[ + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.gamma2", kind: "op", formula: "field.pow:2", operand_names: STAGE5_FIELD_EXPR_OPERANDS_0, operands: STAGE5_FIELD_EXPR_OPERANDS_0 }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.term.LeftLookupOperand", kind: "op", formula: "field.mul", operand_names: STAGE5_FIELD_EXPR_OPERANDS_1, operands: STAGE5_FIELD_EXPR_OPERANDS_1 }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.term.RightLookupOperand", kind: "op", formula: "field.mul", operand_names: STAGE5_FIELD_EXPR_OPERANDS_2, operands: STAGE5_FIELD_EXPR_OPERANDS_2 }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.partial.LookupOutputLeftOperand", kind: "op", formula: "field.add", operand_names: STAGE5_FIELD_EXPR_OPERANDS_3, operands: STAGE5_FIELD_EXPR_OPERANDS_3 }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE5_FIELD_EXPR_OPERANDS_4, operands: STAGE5_FIELD_EXPR_OPERANDS_4 }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.gamma2", kind: "op", formula: "field.pow:2", operand_names: STAGE5_FIELD_EXPR_OPERANDS_5, operands: STAGE5_FIELD_EXPR_OPERANDS_5 }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.term.RamRaReadWrite", kind: "op", formula: "field.mul", operand_names: STAGE5_FIELD_EXPR_OPERANDS_6, operands: STAGE5_FIELD_EXPR_OPERANDS_6 }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.term.RamRaValCheck", kind: "op", formula: "field.mul", operand_names: STAGE5_FIELD_EXPR_OPERANDS_7, operands: STAGE5_FIELD_EXPR_OPERANDS_7 }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.partial.RafReadWrite", kind: "op", formula: "field.add", operand_names: STAGE5_FIELD_EXPR_OPERANDS_8, operands: STAGE5_FIELD_EXPR_OPERANDS_8 }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.claim_expr", kind: "op", formula: "field.add", operand_names: STAGE5_FIELD_EXPR_OPERANDS_9, operands: STAGE5_FIELD_EXPR_OPERANDS_9 }, +]; +pub const STAGE5_KERNELS: &[Stage5KernelPlan] = &[ + Stage5KernelPlan { symbol: "jolt.cpu.stage5.instruction_read_raf", relation: "jolt.stage5.instruction_read_raf", kind: "sumcheck", backend: "cpu", abi: "jolt_stage5_instruction_read_raf" }, + Stage5KernelPlan { symbol: "jolt.cpu.stage5.ram_ra_claim_reduction", relation: "jolt.stage5.ram_ra_claim_reduction", kind: "sumcheck", backend: "cpu", abi: "jolt_stage5_ram_ra_claim_reduction" }, + Stage5KernelPlan { symbol: "jolt.cpu.stage5.registers_val_evaluation", relation: "jolt.stage5.registers_val_evaluation", kind: "sumcheck", backend: "cpu", abi: "jolt_stage5_registers_val_evaluation" }, + Stage5KernelPlan { symbol: "jolt.cpu.stage5.batched", relation: "jolt.stage5.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage5_batched" }, +]; + +pub const STAGE5_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage5.input.stage2.instruction.LookupOutput", + "stage5.input.stage2.instruction.LeftLookupOperand", + "stage5.input.stage2.instruction.RightLookupOperand", +]; + +pub const STAGE5_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &[ + "stage5.input.stage2.ram_raf.RamRa", + "stage5.input.stage2.ram_read_write.RamRa", + "stage5.input.stage4.ram_val_check.RamRa", +]; + +pub const STAGE5_SUMCHECK_CLAIM_2_INPUT_OPENINGS: &[&str] = &["stage5.input.stage4.registers.RegistersVal"]; + +pub const STAGE5_SUMCHECK_CLAIMS: &[Stage5SumcheckClaimPlan] = &[ + Stage5SumcheckClaimPlan { symbol: "stage5.instruction_read_raf.input", stage: "stage5", domain: "jolt.stage5_instruction_read_raf_domain", num_rounds: 144, degree: 10, claim: "stage5.instruction_read_raf.weighted_lookup_values", kernel: Some("jolt.cpu.stage5.instruction_read_raf"), relation: None, claim_value: "stage5.instruction_read_raf.claim_expr", input_openings: STAGE5_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage5SumcheckClaimPlan { symbol: "stage5.ram_ra_claim_reduction.input", stage: "stage5", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage5.ram_ra_claim_reduction.weighted_ram_ra", kernel: Some("jolt.cpu.stage5.ram_ra_claim_reduction"), relation: None, claim_value: "stage5.ram_ra_claim_reduction.claim_expr", input_openings: STAGE5_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, + Stage5SumcheckClaimPlan { symbol: "stage5.registers_val_evaluation.input", stage: "stage5", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage5.registers_val_evaluation.registers_val", kernel: Some("jolt.cpu.stage5.registers_val_evaluation"), relation: None, claim_value: "stage5.input.stage4.registers.RegistersVal", input_openings: STAGE5_SUMCHECK_CLAIM_2_INPUT_OPENINGS }, +]; +pub const STAGE5_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage5.instruction_read_raf.input", + "stage5.ram_ra_claim_reduction.input", + "stage5.registers_val_evaluation.input", +]; + +pub const STAGE5_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage5.instruction_read_raf.input", + "stage5.ram_ra_claim_reduction.input", + "stage5.registers_val_evaluation.input", +]; + +pub const STAGE5_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 128, + 16, +]; + +pub const STAGE5_SUMCHECK_BATCHES: &[Stage5SumcheckBatchPlan] = &[ + Stage5SumcheckBatchPlan { symbol: "stage5.batch", stage: "stage5", proof_slot: "stage5.sumcheck", policy: "jolt_core_stage5_aligned", count: 3, ordered_claims: STAGE5_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE5_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE5_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE5_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 128, + 16, +]; + +pub const STAGE5_SUMCHECK_DRIVERS: &[Stage5SumcheckDriverPlan] = &[ + Stage5SumcheckDriverPlan { symbol: "stage5.sumcheck", stage: "stage5", proof_slot: "stage5.sumcheck", kernel: Some("jolt.cpu.stage5.batched"), relation: None, batch: "stage5.batch", policy: "jolt_core_stage5_aligned", round_schedule: STAGE5_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 144, degree: 10 }, +]; +pub const STAGE5_SUMCHECK_INSTANCE_RESULTS: &[Stage5SumcheckInstanceResultPlan] = &[ + Stage5SumcheckInstanceResultPlan { symbol: "stage5.instruction_read_raf.instance", source: "stage5.sumcheck", claim: "stage5.instruction_read_raf.input", relation: "jolt.stage5.instruction_read_raf", index: 0, point_arity: 144, num_rounds: 144, round_offset: 0, point_order: "instruction_read_raf", degree: 10 }, + Stage5SumcheckInstanceResultPlan { symbol: "stage5.ram_ra_claim_reduction.instance", source: "stage5.sumcheck", claim: "stage5.ram_ra_claim_reduction.input", relation: "jolt.stage5.ram_ra_claim_reduction", index: 1, point_arity: 16, num_rounds: 16, round_offset: 128, point_order: "reverse", degree: 2 }, + Stage5SumcheckInstanceResultPlan { symbol: "stage5.registers_val_evaluation.instance", source: "stage5.sumcheck", claim: "stage5.registers_val_evaluation.input", relation: "jolt.stage5.registers_val_evaluation", index: 2, point_arity: 16, num_rounds: 16, round_offset: 128, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE5_SUMCHECK_EVALS: &[Stage5SumcheckEvalPlan] = &[ + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_0", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_0", index: 0, oracle: "LookupTableFlag_0" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_1", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_1", index: 1, oracle: "LookupTableFlag_1" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_2", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_2", index: 2, oracle: "LookupTableFlag_2" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_3", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_3", index: 3, oracle: "LookupTableFlag_3" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_4", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_4", index: 4, oracle: "LookupTableFlag_4" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_5", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_5", index: 5, oracle: "LookupTableFlag_5" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_6", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_6", index: 6, oracle: "LookupTableFlag_6" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_7", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_7", index: 7, oracle: "LookupTableFlag_7" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_8", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_8", index: 8, oracle: "LookupTableFlag_8" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_9", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_9", index: 9, oracle: "LookupTableFlag_9" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_10", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_10", index: 10, oracle: "LookupTableFlag_10" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_11", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_11", index: 11, oracle: "LookupTableFlag_11" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_12", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_12", index: 12, oracle: "LookupTableFlag_12" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_13", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_13", index: 13, oracle: "LookupTableFlag_13" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_14", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_14", index: 14, oracle: "LookupTableFlag_14" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_15", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_15", index: 15, oracle: "LookupTableFlag_15" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_16", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_16", index: 16, oracle: "LookupTableFlag_16" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_17", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_17", index: 17, oracle: "LookupTableFlag_17" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_18", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_18", index: 18, oracle: "LookupTableFlag_18" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_19", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_19", index: 19, oracle: "LookupTableFlag_19" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_20", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_20", index: 20, oracle: "LookupTableFlag_20" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_21", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_21", index: 21, oracle: "LookupTableFlag_21" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_22", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_22", index: 22, oracle: "LookupTableFlag_22" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_23", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_23", index: 23, oracle: "LookupTableFlag_23" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_24", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_24", index: 24, oracle: "LookupTableFlag_24" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_25", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_25", index: 25, oracle: "LookupTableFlag_25" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_26", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_26", index: 26, oracle: "LookupTableFlag_26" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_27", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_27", index: 27, oracle: "LookupTableFlag_27" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_28", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_28", index: 28, oracle: "LookupTableFlag_28" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_29", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_29", index: 29, oracle: "LookupTableFlag_29" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_30", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_30", index: 30, oracle: "LookupTableFlag_30" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_31", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_31", index: 31, oracle: "LookupTableFlag_31" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_32", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_32", index: 32, oracle: "LookupTableFlag_32" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_33", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_33", index: 33, oracle: "LookupTableFlag_33" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_34", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_34", index: 34, oracle: "LookupTableFlag_34" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_35", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_35", index: 35, oracle: "LookupTableFlag_35" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_36", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_36", index: 36, oracle: "LookupTableFlag_36" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_37", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_37", index: 37, oracle: "LookupTableFlag_37" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_38", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_38", index: 38, oracle: "LookupTableFlag_38" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_39", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_39", index: 39, oracle: "LookupTableFlag_39" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_40", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_40", index: 40, oracle: "LookupTableFlag_40" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_0", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_0", index: 41, oracle: "InstructionRa_0" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_1", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_1", index: 42, oracle: "InstructionRa_1" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_2", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_2", index: 43, oracle: "InstructionRa_2" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_3", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_3", index: 44, oracle: "InstructionRa_3" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_4", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_4", index: 45, oracle: "InstructionRa_4" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_5", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_5", index: 46, oracle: "InstructionRa_5" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_6", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_6", index: 47, oracle: "InstructionRa_6" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_7", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_7", index: 48, oracle: "InstructionRa_7" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRafFlag", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRafFlag", index: 49, oracle: "InstructionRafFlag" }, + Stage5SumcheckEvalPlan { symbol: "stage5.ram_ra_claim_reduction.eval.RamRa", source: "stage5.sumcheck", name: "stage5.ram_ra_claim_reduction.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage5SumcheckEvalPlan { symbol: "stage5.registers_val_evaluation.eval.RdInc", source: "stage5.sumcheck", name: "stage5.registers_val_evaluation.eval.RdInc", index: 0, oracle: "RdInc" }, + Stage5SumcheckEvalPlan { symbol: "stage5.registers_val_evaluation.eval.RdWa", source: "stage5.sumcheck", name: "stage5.registers_val_evaluation.eval.RdWa", index: 1, oracle: "RdWa" }, +]; + +pub const STAGE5_POINT_SLICES: &[Stage5PointSlicePlan] = &[ + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.Cycle", source: "stage5.instruction_read_raf.instance", offset: 128, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_0.address", source: "stage5.instruction_read_raf.instance", offset: 0, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_1.address", source: "stage5.instruction_read_raf.instance", offset: 16, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_2.address", source: "stage5.instruction_read_raf.instance", offset: 32, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_3.address", source: "stage5.instruction_read_raf.instance", offset: 48, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_4.address", source: "stage5.instruction_read_raf.instance", offset: 64, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_5.address", source: "stage5.instruction_read_raf.instance", offset: 80, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_6.address", source: "stage5.instruction_read_raf.instance", offset: 96, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_7.address", source: "stage5.instruction_read_raf.instance", offset: 112, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.ram_ra_claim_reduction.point.RamAddress", source: "stage5.input.stage2.ram_raf.RamRa", offset: 0, length: 16, input: "stage5.input.stage2.ram_raf.RamRa" }, + Stage5PointSlicePlan { symbol: "stage5.registers_val_evaluation.point.RegisterAddress", source: "stage5.input.stage4.registers.RegistersVal", offset: 0, length: 7, input: "stage5.input.stage4.registers.RegistersVal" }, +]; + +pub const STAGE5_POINT_CONCAT_0_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_0.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_1_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_1.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_2_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_2.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_3_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_3.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_4_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_4.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_5_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_5.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_6_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_6.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_7_INPUTS: &[&str] = &[ + "stage5.instruction_read_raf.point.InstructionRa_7.address", + "stage5.instruction_read_raf.point.Cycle", +]; + +pub const STAGE5_POINT_CONCAT_8_INPUTS: &[&str] = &[ + "stage5.ram_ra_claim_reduction.point.RamAddress", + "stage5.ram_ra_claim_reduction.instance", +]; + +pub const STAGE5_POINT_CONCAT_9_INPUTS: &[&str] = &[ + "stage5.registers_val_evaluation.point.RegisterAddress", + "stage5.registers_val_evaluation.instance", +]; + +pub const STAGE5_POINT_CONCATS: &[Stage5PointConcatPlan] = &[ + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_0", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_0_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_1", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_1_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_2", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_2_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_3", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_3_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_4", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_4_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_5", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_5_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_6", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_6_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_7", layout: "address_chunk_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_7_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.ram_ra_claim_reduction.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: STAGE5_POINT_CONCAT_8_INPUTS }, + Stage5PointConcatPlan { symbol: "stage5.registers_val_evaluation.point.RdWa", layout: "register_address_then_cycle", arity: 23, inputs: STAGE5_POINT_CONCAT_9_INPUTS }, +]; +pub const STAGE5_OPENING_CLAIMS: &[Stage5OpeningClaimPlan] = &[ + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_0", oracle: "LookupTableFlag_0", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_0" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_1", oracle: "LookupTableFlag_1", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_1" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_2", oracle: "LookupTableFlag_2", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_2" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_3", oracle: "LookupTableFlag_3", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_3" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_4", oracle: "LookupTableFlag_4", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_4" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_5", oracle: "LookupTableFlag_5", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_5" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_6", oracle: "LookupTableFlag_6", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_6" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_7", oracle: "LookupTableFlag_7", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_7" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_8", oracle: "LookupTableFlag_8", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_8" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_9", oracle: "LookupTableFlag_9", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_9" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_10", oracle: "LookupTableFlag_10", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_10" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_11", oracle: "LookupTableFlag_11", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_11" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_12", oracle: "LookupTableFlag_12", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_12" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_13", oracle: "LookupTableFlag_13", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_13" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_14", oracle: "LookupTableFlag_14", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_14" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_15", oracle: "LookupTableFlag_15", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_15" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_16", oracle: "LookupTableFlag_16", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_16" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_17", oracle: "LookupTableFlag_17", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_17" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_18", oracle: "LookupTableFlag_18", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_18" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_19", oracle: "LookupTableFlag_19", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_19" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_20", oracle: "LookupTableFlag_20", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_20" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_21", oracle: "LookupTableFlag_21", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_21" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_22", oracle: "LookupTableFlag_22", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_22" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_23", oracle: "LookupTableFlag_23", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_23" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_24", oracle: "LookupTableFlag_24", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_24" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_25", oracle: "LookupTableFlag_25", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_25" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_26", oracle: "LookupTableFlag_26", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_26" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_27", oracle: "LookupTableFlag_27", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_27" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_28", oracle: "LookupTableFlag_28", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_28" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_29", oracle: "LookupTableFlag_29", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_29" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_30", oracle: "LookupTableFlag_30", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_30" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_31", oracle: "LookupTableFlag_31", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_31" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_32", oracle: "LookupTableFlag_32", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_32" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_33", oracle: "LookupTableFlag_33", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_33" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_34", oracle: "LookupTableFlag_34", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_34" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_35", oracle: "LookupTableFlag_35", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_35" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_36", oracle: "LookupTableFlag_36", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_36" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_37", oracle: "LookupTableFlag_37", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_37" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_38", oracle: "LookupTableFlag_38", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_38" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_39", oracle: "LookupTableFlag_39", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_39" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_40", oracle: "LookupTableFlag_40", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_40" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_0", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_0" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_1", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_1" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_2", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_2" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_3", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_3" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_4", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_4" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_5", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_5" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_6", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_6" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_7", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_7" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRafFlag", oracle: "InstructionRafFlag", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.InstructionRafFlag" }, + Stage5OpeningClaimPlan { symbol: "stage5.ram_ra_claim_reduction.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.ram_ra_claim_reduction.point.RamRa", eval_source: "stage5.ram_ra_claim_reduction.eval.RamRa" }, + Stage5OpeningClaimPlan { symbol: "stage5.registers_val_evaluation.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage5.registers_val_evaluation.instance", eval_source: "stage5.registers_val_evaluation.eval.RdInc" }, + Stage5OpeningClaimPlan { symbol: "stage5.registers_val_evaluation.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage5.registers_val_evaluation.point.RdWa", eval_source: "stage5.registers_val_evaluation.eval.RdWa" }, +]; + +pub const STAGE5_OPENING_EQUALITIES: &[Stage5OpeningClaimEqualityPlan] = &[ + Stage5OpeningClaimEqualityPlan { symbol: "stage5.instruction.lookup_output_claim_consistency", mode: "point_and_eval", lhs: "stage5.input.stage2.instruction.LookupOutput", rhs: "stage5.input.stage2.product_virtual.LookupOutput" }, +]; + +pub const STAGE5_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage5.instruction_read_raf.opening.LookupTableFlag_0", + "stage5.instruction_read_raf.opening.LookupTableFlag_1", + "stage5.instruction_read_raf.opening.LookupTableFlag_2", + "stage5.instruction_read_raf.opening.LookupTableFlag_3", + "stage5.instruction_read_raf.opening.LookupTableFlag_4", + "stage5.instruction_read_raf.opening.LookupTableFlag_5", + "stage5.instruction_read_raf.opening.LookupTableFlag_6", + "stage5.instruction_read_raf.opening.LookupTableFlag_7", + "stage5.instruction_read_raf.opening.LookupTableFlag_8", + "stage5.instruction_read_raf.opening.LookupTableFlag_9", + "stage5.instruction_read_raf.opening.LookupTableFlag_10", + "stage5.instruction_read_raf.opening.LookupTableFlag_11", + "stage5.instruction_read_raf.opening.LookupTableFlag_12", + "stage5.instruction_read_raf.opening.LookupTableFlag_13", + "stage5.instruction_read_raf.opening.LookupTableFlag_14", + "stage5.instruction_read_raf.opening.LookupTableFlag_15", + "stage5.instruction_read_raf.opening.LookupTableFlag_16", + "stage5.instruction_read_raf.opening.LookupTableFlag_17", + "stage5.instruction_read_raf.opening.LookupTableFlag_18", + "stage5.instruction_read_raf.opening.LookupTableFlag_19", + "stage5.instruction_read_raf.opening.LookupTableFlag_20", + "stage5.instruction_read_raf.opening.LookupTableFlag_21", + "stage5.instruction_read_raf.opening.LookupTableFlag_22", + "stage5.instruction_read_raf.opening.LookupTableFlag_23", + "stage5.instruction_read_raf.opening.LookupTableFlag_24", + "stage5.instruction_read_raf.opening.LookupTableFlag_25", + "stage5.instruction_read_raf.opening.LookupTableFlag_26", + "stage5.instruction_read_raf.opening.LookupTableFlag_27", + "stage5.instruction_read_raf.opening.LookupTableFlag_28", + "stage5.instruction_read_raf.opening.LookupTableFlag_29", + "stage5.instruction_read_raf.opening.LookupTableFlag_30", + "stage5.instruction_read_raf.opening.LookupTableFlag_31", + "stage5.instruction_read_raf.opening.LookupTableFlag_32", + "stage5.instruction_read_raf.opening.LookupTableFlag_33", + "stage5.instruction_read_raf.opening.LookupTableFlag_34", + "stage5.instruction_read_raf.opening.LookupTableFlag_35", + "stage5.instruction_read_raf.opening.LookupTableFlag_36", + "stage5.instruction_read_raf.opening.LookupTableFlag_37", + "stage5.instruction_read_raf.opening.LookupTableFlag_38", + "stage5.instruction_read_raf.opening.LookupTableFlag_39", + "stage5.instruction_read_raf.opening.LookupTableFlag_40", + "stage5.instruction_read_raf.opening.InstructionRa_0", + "stage5.instruction_read_raf.opening.InstructionRa_1", + "stage5.instruction_read_raf.opening.InstructionRa_2", + "stage5.instruction_read_raf.opening.InstructionRa_3", + "stage5.instruction_read_raf.opening.InstructionRa_4", + "stage5.instruction_read_raf.opening.InstructionRa_5", + "stage5.instruction_read_raf.opening.InstructionRa_6", + "stage5.instruction_read_raf.opening.InstructionRa_7", + "stage5.instruction_read_raf.opening.InstructionRafFlag", + "stage5.ram_ra_claim_reduction.opening.RamRa", + "stage5.registers_val_evaluation.opening.RdInc", + "stage5.registers_val_evaluation.opening.RdWa", +]; + +pub const STAGE5_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage5.instruction_read_raf.opening.LookupTableFlag_0", + "stage5.instruction_read_raf.opening.LookupTableFlag_1", + "stage5.instruction_read_raf.opening.LookupTableFlag_2", + "stage5.instruction_read_raf.opening.LookupTableFlag_3", + "stage5.instruction_read_raf.opening.LookupTableFlag_4", + "stage5.instruction_read_raf.opening.LookupTableFlag_5", + "stage5.instruction_read_raf.opening.LookupTableFlag_6", + "stage5.instruction_read_raf.opening.LookupTableFlag_7", + "stage5.instruction_read_raf.opening.LookupTableFlag_8", + "stage5.instruction_read_raf.opening.LookupTableFlag_9", + "stage5.instruction_read_raf.opening.LookupTableFlag_10", + "stage5.instruction_read_raf.opening.LookupTableFlag_11", + "stage5.instruction_read_raf.opening.LookupTableFlag_12", + "stage5.instruction_read_raf.opening.LookupTableFlag_13", + "stage5.instruction_read_raf.opening.LookupTableFlag_14", + "stage5.instruction_read_raf.opening.LookupTableFlag_15", + "stage5.instruction_read_raf.opening.LookupTableFlag_16", + "stage5.instruction_read_raf.opening.LookupTableFlag_17", + "stage5.instruction_read_raf.opening.LookupTableFlag_18", + "stage5.instruction_read_raf.opening.LookupTableFlag_19", + "stage5.instruction_read_raf.opening.LookupTableFlag_20", + "stage5.instruction_read_raf.opening.LookupTableFlag_21", + "stage5.instruction_read_raf.opening.LookupTableFlag_22", + "stage5.instruction_read_raf.opening.LookupTableFlag_23", + "stage5.instruction_read_raf.opening.LookupTableFlag_24", + "stage5.instruction_read_raf.opening.LookupTableFlag_25", + "stage5.instruction_read_raf.opening.LookupTableFlag_26", + "stage5.instruction_read_raf.opening.LookupTableFlag_27", + "stage5.instruction_read_raf.opening.LookupTableFlag_28", + "stage5.instruction_read_raf.opening.LookupTableFlag_29", + "stage5.instruction_read_raf.opening.LookupTableFlag_30", + "stage5.instruction_read_raf.opening.LookupTableFlag_31", + "stage5.instruction_read_raf.opening.LookupTableFlag_32", + "stage5.instruction_read_raf.opening.LookupTableFlag_33", + "stage5.instruction_read_raf.opening.LookupTableFlag_34", + "stage5.instruction_read_raf.opening.LookupTableFlag_35", + "stage5.instruction_read_raf.opening.LookupTableFlag_36", + "stage5.instruction_read_raf.opening.LookupTableFlag_37", + "stage5.instruction_read_raf.opening.LookupTableFlag_38", + "stage5.instruction_read_raf.opening.LookupTableFlag_39", + "stage5.instruction_read_raf.opening.LookupTableFlag_40", + "stage5.instruction_read_raf.opening.InstructionRa_0", + "stage5.instruction_read_raf.opening.InstructionRa_1", + "stage5.instruction_read_raf.opening.InstructionRa_2", + "stage5.instruction_read_raf.opening.InstructionRa_3", + "stage5.instruction_read_raf.opening.InstructionRa_4", + "stage5.instruction_read_raf.opening.InstructionRa_5", + "stage5.instruction_read_raf.opening.InstructionRa_6", + "stage5.instruction_read_raf.opening.InstructionRa_7", + "stage5.instruction_read_raf.opening.InstructionRafFlag", + "stage5.ram_ra_claim_reduction.opening.RamRa", + "stage5.registers_val_evaluation.opening.RdInc", + "stage5.registers_val_evaluation.opening.RdWa", +]; + +pub const STAGE5_OPENING_BATCHES: &[Stage5OpeningBatchPlan] = &[ + Stage5OpeningBatchPlan { symbol: "stage5.openings", stage: "stage5", proof_slot: "stage5.openings", policy: "jolt_stage5_output_order", count: 53, ordered_claims: STAGE5_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE5_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE5_PROGRAM: Stage5CpuProgramPlan = Stage5CpuProgramPlan { + role: "prover", + params: STAGE5_PARAMS, + steps: STAGE5_PROGRAM_STEPS, + transcript_squeezes: STAGE5_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE5_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE5_OPENING_INPUTS, + field_constants: STAGE5_FIELD_CONSTANTS, + field_exprs: STAGE5_FIELD_EXPRS, + kernels: STAGE5_KERNELS, + claims: STAGE5_SUMCHECK_CLAIMS, + batches: STAGE5_SUMCHECK_BATCHES, + drivers: STAGE5_SUMCHECK_DRIVERS, + instance_results: STAGE5_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE5_SUMCHECK_EVALS, + point_slices: STAGE5_POINT_SLICES, + point_concats: STAGE5_POINT_CONCATS, + opening_claims: STAGE5_OPENING_CLAIMS, + opening_equalities: STAGE5_OPENING_EQUALITIES, + opening_batches: STAGE5_OPENING_BATCHES, +}; + +pub fn execute_stage5_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + E: Stage5KernelExecutor, + T: Transcript, +{ + execute_stage5_prover_with_program(&STAGE5_PROGRAM, executor, transcript) +} + +pub fn execute_stage5_prover_with_program( + program: &'static Stage5CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage5KernelError> +where + E: Stage5KernelExecutor, + T: Transcript, +{ + execute_stage5_program(program, Stage5ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage6.rs b/crates/jolt-prover/src/stages/stage6.rs new file mode 100644 index 0000000000..ad59b1a999 --- /dev/null +++ b/crates/jolt-prover/src/stages/stage6.rs @@ -0,0 +1,2537 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage6::{execute_stage6_program, Stage6CpuProgramPlan, Stage6ExecutionArtifacts, Stage6ExecutionMode, Stage6FieldConstantPlan, Stage6FieldExprPlan, Stage6KernelError, Stage6KernelExecutor, Stage6KernelPlan, Stage6OpeningBatchPlan, Stage6OpeningClaimEqualityPlan, Stage6OpeningClaimPlan, Stage6OpeningInputPlan, Stage6Params, Stage6PointConcatPlan, Stage6PointSlicePlan, Stage6PointZeroPlan, Stage6ProgramStepPlan, Stage6SumcheckBatchPlan, Stage6SumcheckClaimPlan, Stage6SumcheckDriverPlan, Stage6SumcheckEvalPlan, Stage6SumcheckInstanceResultPlan, Stage6TranscriptAbsorbBytesPlan, Stage6TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage6Transcript = Blake2bTranscript; + +pub const STAGE6_PARAMS: Stage6Params = Stage6Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE6_PROGRAM_STEPS: &[Stage6ProgramStepPlan] = &[ + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage1_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage2_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage3_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage4_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage5_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.booleanity.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.instruction_ra_virtual.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.inc_claim_reduction.gamma" }, + Stage6ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage6.sumcheck" }, +]; + +pub const STAGE6_TRANSCRIPT_SQUEEZES: &[Stage6TranscriptSqueezePlan] = &[ + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.gamma", label: "bc_raf_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage1_gamma", label: "bc_raf_stage1_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage2_gamma", label: "bc_raf_stage2_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage3_gamma", label: "bc_raf_stage3_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage4_gamma", label: "bc_raf_stage4_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage5_gamma", label: "bc_raf_stage5_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.booleanity.gamma", label: "booleanity_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.instruction_ra_virtual.gamma", label: "inst_ra_virtual_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.inc_claim_reduction.gamma", label: "inc_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE6_TRANSCRIPT_ABSORB_BYTES: &[Stage6TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE6_OPENING_INPUTS: &[Stage6OpeningInputPlan] = &[ + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.UnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.Imm", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAddOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAddOperands", oracle: "OpFlagAddOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagSubtractOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagSubtractOperands", oracle: "OpFlagSubtractOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagMultiplyOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagMultiplyOperands", oracle: "OpFlagMultiplyOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagLoad", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagLoad", oracle: "OpFlagLoad", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagStore", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagStore", oracle: "OpFlagStore", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagJump", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagWriteLookupOutputToRD", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagVirtualInstruction", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAssert", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAssert", oracle: "OpFlagAssert", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", oracle: "OpFlagDoNotUpdateUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAdvice", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAdvice", oracle: "OpFlagAdvice", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsCompressed", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsCompressed", oracle: "OpFlagIsCompressed", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsFirstInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsLastInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsLastInSequence", oracle: "OpFlagIsLastInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagJump", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.InstructionFlagBranch", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.InstructionFlagBranch", oracle: "InstructionFlagBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagWriteLookupOutputToRD", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagVirtualInstruction", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.Imm", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.UnexpandedPC", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", oracle: "InstructionFlagLeftOperandIsRs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", oracle: "InstructionFlagLeftOperandIsPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", oracle: "InstructionFlagRightOperandIsRs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", oracle: "InstructionFlagRightOperandIsImm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.InstructionFlagIsNoop", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.InstructionFlagIsNoop", oracle: "InstructionFlagIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.RdWa", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.Rs1Ra", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.Rs1Ra", oracle: "Rs1Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.Rs2Ra", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.Rs2Ra", oracle: "Rs2Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.registers_val_evaluation.RdWa", source_stage: "stage5", source_claim: "stage5.registers_val_evaluation.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.InstructionRafFlag", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRafFlag", oracle: "InstructionRafFlag", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_0", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_0", oracle: "LookupTableFlag_0", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_1", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_1", oracle: "LookupTableFlag_1", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_2", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_2", oracle: "LookupTableFlag_2", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_3", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_3", oracle: "LookupTableFlag_3", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_4", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_4", oracle: "LookupTableFlag_4", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_5", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_5", oracle: "LookupTableFlag_5", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_6", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_6", oracle: "LookupTableFlag_6", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_7", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_7", oracle: "LookupTableFlag_7", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_8", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_8", oracle: "LookupTableFlag_8", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_9", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_9", oracle: "LookupTableFlag_9", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_10", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_10", oracle: "LookupTableFlag_10", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_11", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_11", oracle: "LookupTableFlag_11", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_12", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_12", oracle: "LookupTableFlag_12", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_13", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_13", oracle: "LookupTableFlag_13", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_14", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_14", oracle: "LookupTableFlag_14", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_15", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_15", oracle: "LookupTableFlag_15", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_16", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_16", oracle: "LookupTableFlag_16", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_17", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_17", oracle: "LookupTableFlag_17", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_18", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_18", oracle: "LookupTableFlag_18", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_19", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_19", oracle: "LookupTableFlag_19", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_20", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_20", oracle: "LookupTableFlag_20", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_21", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_21", oracle: "LookupTableFlag_21", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_22", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_22", oracle: "LookupTableFlag_22", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_23", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_23", oracle: "LookupTableFlag_23", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_24", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_24", oracle: "LookupTableFlag_24", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_25", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_25", oracle: "LookupTableFlag_25", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_26", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_26", oracle: "LookupTableFlag_26", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_27", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_27", oracle: "LookupTableFlag_27", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_28", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_28", oracle: "LookupTableFlag_28", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_29", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_29", oracle: "LookupTableFlag_29", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_30", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_30", oracle: "LookupTableFlag_30", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_31", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_31", oracle: "LookupTableFlag_31", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_32", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_32", oracle: "LookupTableFlag_32", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_33", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_33", oracle: "LookupTableFlag_33", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_34", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_34", oracle: "LookupTableFlag_34", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_35", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_35", oracle: "LookupTableFlag_35", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_36", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_36", oracle: "LookupTableFlag_36", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_37", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_37", oracle: "LookupTableFlag_37", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_38", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_38", oracle: "LookupTableFlag_38", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_39", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_39", oracle: "LookupTableFlag_39", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_40", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_40", oracle: "LookupTableFlag_40", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.PC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.PC", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", source_stage: "stage5", source_claim: "stage5.ram_ra_claim_reduction.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.LookupOutput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.ram_read_write.RamInc", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.ram_val_check.RamInc", source_stage: "stage4", source_claim: "stage4.ram_val_check.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.registers_read_write.RdInc", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.registers_val_evaluation.RdInc", source_stage: "stage5", source_claim: "stage5.registers_val_evaluation.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, +]; + +pub const STAGE6_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[ + Stage6FieldConstantPlan { symbol: "stage6.zero", field: "bn254_fr", value: 0 }, +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage6.booleanity.gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_1: &[&str] = &["stage6.bytecode_read_raf.stage1_gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term1.stage_gamma_pow", + "stage6.input.stage1.Imm", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term2.stage_gamma_pow", + "stage6.input.stage1.OpFlagAddOperands", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term3.stage_gamma_pow", + "stage6.input.stage1.OpFlagSubtractOperands", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_5: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term4.stage_gamma_pow", + "stage6.input.stage1.OpFlagMultiplyOperands", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term5.stage_gamma_pow", + "stage6.input.stage1.OpFlagLoad", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term6.stage_gamma_pow", + "stage6.input.stage1.OpFlagStore", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term7.stage_gamma_pow", + "stage6.input.stage1.OpFlagJump", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_9: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term8.stage_gamma_pow", + "stage6.input.stage1.OpFlagWriteLookupOutputToRD", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_10: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term9.stage_gamma_pow", + "stage6.input.stage1.OpFlagVirtualInstruction", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_11: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term10.stage_gamma_pow", + "stage6.input.stage1.OpFlagAssert", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_12: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term11.stage_gamma_pow", + "stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_13: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term12.stage_gamma_pow", + "stage6.input.stage1.OpFlagAdvice", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_14: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term13.stage_gamma_pow", + "stage6.input.stage1.OpFlagIsCompressed", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_15: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term14.stage_gamma_pow", + "stage6.input.stage1.OpFlagIsFirstInSequence", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_16: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term15.stage_gamma_pow", + "stage6.input.stage1.OpFlagIsLastInSequence", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_17: &[&str] = &["stage6.bytecode_read_raf.gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_18: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term16.gamma_pow", + "stage6.input.stage2.OpFlagJump", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_19: &[&str] = &["stage6.bytecode_read_raf.stage2_gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_20: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term17.stage_gamma_pow", + "stage6.input.stage2.InstructionFlagBranch", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_21: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term17.gamma_pow", + "stage6.bytecode_read_raf.claim.term17.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_22: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term18.stage_gamma_pow", + "stage6.input.stage2.OpFlagWriteLookupOutputToRD", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_23: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term18.gamma_pow", + "stage6.bytecode_read_raf.claim.term18.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_24: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term19.stage_gamma_pow", + "stage6.input.stage2.OpFlagVirtualInstruction", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_25: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term19.gamma_pow", + "stage6.bytecode_read_raf.claim.term19.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_26: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term20.gamma_pow", + "stage6.input.stage3.instruction_input.Imm", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_27: &[&str] = &["stage6.bytecode_read_raf.stage3_gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_28: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term21.stage_gamma_pow", + "stage6.input.stage3.spartan_shift.UnexpandedPC", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_29: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term21.gamma_pow", + "stage6.bytecode_read_raf.claim.term21.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_30: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term22.stage_gamma_pow", + "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_31: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term22.gamma_pow", + "stage6.bytecode_read_raf.claim.term22.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_32: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term23.stage_gamma_pow", + "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_33: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term23.gamma_pow", + "stage6.bytecode_read_raf.claim.term23.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_34: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term24.stage_gamma_pow", + "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_35: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term24.gamma_pow", + "stage6.bytecode_read_raf.claim.term24.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_36: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term25.stage_gamma_pow", + "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_37: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term25.gamma_pow", + "stage6.bytecode_read_raf.claim.term25.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_38: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term26.stage_gamma_pow", + "stage6.input.stage3.spartan_shift.InstructionFlagIsNoop", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_39: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term26.gamma_pow", + "stage6.bytecode_read_raf.claim.term26.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_40: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term27.stage_gamma_pow", + "stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_41: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term27.gamma_pow", + "stage6.bytecode_read_raf.claim.term27.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_42: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term28.stage_gamma_pow", + "stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_43: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term28.gamma_pow", + "stage6.bytecode_read_raf.claim.term28.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_44: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term29.gamma_pow", + "stage6.input.stage4.RdWa", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_45: &[&str] = &["stage6.bytecode_read_raf.stage4_gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_46: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term30.stage_gamma_pow", + "stage6.input.stage4.Rs1Ra", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_47: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term30.gamma_pow", + "stage6.bytecode_read_raf.claim.term30.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_48: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term31.stage_gamma_pow", + "stage6.input.stage4.Rs2Ra", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_49: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term31.gamma_pow", + "stage6.bytecode_read_raf.claim.term31.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_50: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term32.gamma_pow", + "stage6.input.stage5.registers_val_evaluation.RdWa", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_51: &[&str] = &["stage6.bytecode_read_raf.stage5_gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_52: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term33.stage_gamma_pow", + "stage6.input.stage5.InstructionRafFlag", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_53: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term33.gamma_pow", + "stage6.bytecode_read_raf.claim.term33.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_54: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term34.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_0", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_55: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term34.gamma_pow", + "stage6.bytecode_read_raf.claim.term34.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_56: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term35.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_1", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_57: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term35.gamma_pow", + "stage6.bytecode_read_raf.claim.term35.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_58: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term36.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_2", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_59: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term36.gamma_pow", + "stage6.bytecode_read_raf.claim.term36.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_60: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term37.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_3", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_61: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term37.gamma_pow", + "stage6.bytecode_read_raf.claim.term37.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_62: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term38.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_4", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_63: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term38.gamma_pow", + "stage6.bytecode_read_raf.claim.term38.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_64: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term39.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_5", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_65: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term39.gamma_pow", + "stage6.bytecode_read_raf.claim.term39.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_66: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term40.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_6", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_67: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term40.gamma_pow", + "stage6.bytecode_read_raf.claim.term40.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_68: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term41.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_7", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_69: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term41.gamma_pow", + "stage6.bytecode_read_raf.claim.term41.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_70: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term42.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_8", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_71: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term42.gamma_pow", + "stage6.bytecode_read_raf.claim.term42.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_72: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term43.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_9", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_73: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term43.gamma_pow", + "stage6.bytecode_read_raf.claim.term43.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_74: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term44.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_10", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_75: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term44.gamma_pow", + "stage6.bytecode_read_raf.claim.term44.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_76: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term45.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_11", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_77: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term45.gamma_pow", + "stage6.bytecode_read_raf.claim.term45.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_78: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term46.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_12", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_79: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term46.gamma_pow", + "stage6.bytecode_read_raf.claim.term46.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_80: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term47.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_13", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_81: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term47.gamma_pow", + "stage6.bytecode_read_raf.claim.term47.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_82: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term48.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_14", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_83: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term48.gamma_pow", + "stage6.bytecode_read_raf.claim.term48.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_84: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term49.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_15", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_85: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term49.gamma_pow", + "stage6.bytecode_read_raf.claim.term49.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_86: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term50.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_16", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_87: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term50.gamma_pow", + "stage6.bytecode_read_raf.claim.term50.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_88: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term51.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_17", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_89: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term51.gamma_pow", + "stage6.bytecode_read_raf.claim.term51.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_90: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term52.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_18", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_91: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term52.gamma_pow", + "stage6.bytecode_read_raf.claim.term52.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_92: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term53.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_19", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_93: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term53.gamma_pow", + "stage6.bytecode_read_raf.claim.term53.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_94: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term54.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_20", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_95: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term54.gamma_pow", + "stage6.bytecode_read_raf.claim.term54.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_96: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term55.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_21", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_97: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term55.gamma_pow", + "stage6.bytecode_read_raf.claim.term55.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_98: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term56.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_22", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_99: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term56.gamma_pow", + "stage6.bytecode_read_raf.claim.term56.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_100: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term57.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_23", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_101: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term57.gamma_pow", + "stage6.bytecode_read_raf.claim.term57.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_102: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term58.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_24", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_103: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term58.gamma_pow", + "stage6.bytecode_read_raf.claim.term58.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_104: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term59.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_25", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_105: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term59.gamma_pow", + "stage6.bytecode_read_raf.claim.term59.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_106: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term60.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_26", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_107: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term60.gamma_pow", + "stage6.bytecode_read_raf.claim.term60.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_108: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term61.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_27", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_109: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term61.gamma_pow", + "stage6.bytecode_read_raf.claim.term61.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_110: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term62.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_28", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_111: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term62.gamma_pow", + "stage6.bytecode_read_raf.claim.term62.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_112: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term63.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_29", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_113: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term63.gamma_pow", + "stage6.bytecode_read_raf.claim.term63.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_114: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term64.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_30", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_115: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term64.gamma_pow", + "stage6.bytecode_read_raf.claim.term64.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_116: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term65.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_31", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_117: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term65.gamma_pow", + "stage6.bytecode_read_raf.claim.term65.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_118: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term66.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_32", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_119: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term66.gamma_pow", + "stage6.bytecode_read_raf.claim.term66.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_120: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term67.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_33", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_121: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term67.gamma_pow", + "stage6.bytecode_read_raf.claim.term67.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_122: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term68.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_34", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_123: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term68.gamma_pow", + "stage6.bytecode_read_raf.claim.term68.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_124: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term69.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_35", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_125: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term69.gamma_pow", + "stage6.bytecode_read_raf.claim.term69.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_126: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term70.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_36", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_127: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term70.gamma_pow", + "stage6.bytecode_read_raf.claim.term70.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_128: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term71.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_37", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_129: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term71.gamma_pow", + "stage6.bytecode_read_raf.claim.term71.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_130: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term72.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_38", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_131: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term72.gamma_pow", + "stage6.bytecode_read_raf.claim.term72.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_132: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term73.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_39", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_133: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term73.gamma_pow", + "stage6.bytecode_read_raf.claim.term73.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_134: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term74.stage_gamma_pow", + "stage6.input.stage5.LookupTableFlag_40", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_135: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term74.gamma_pow", + "stage6.bytecode_read_raf.claim.term74.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_136: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term75.gamma_pow", + "stage6.input.stage1.PC", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_137: &[&str] = &[ + "stage6.bytecode_read_raf.claim.term76.gamma_pow", + "stage6.input.stage3.spartan_shift.PC", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_138: &[&str] = &[ + "stage6.input.stage1.UnexpandedPC", + "stage6.bytecode_read_raf.claim.term1.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_139: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial0", + "stage6.bytecode_read_raf.claim.term2.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_140: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial1", + "stage6.bytecode_read_raf.claim.term3.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_141: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial2", + "stage6.bytecode_read_raf.claim.term4.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_142: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial3", + "stage6.bytecode_read_raf.claim.term5.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_143: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial4", + "stage6.bytecode_read_raf.claim.term6.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_144: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial5", + "stage6.bytecode_read_raf.claim.term7.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_145: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial6", + "stage6.bytecode_read_raf.claim.term8.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_146: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial7", + "stage6.bytecode_read_raf.claim.term9.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_147: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial8", + "stage6.bytecode_read_raf.claim.term10.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_148: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial9", + "stage6.bytecode_read_raf.claim.term11.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_149: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial10", + "stage6.bytecode_read_raf.claim.term12.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_150: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial11", + "stage6.bytecode_read_raf.claim.term13.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_151: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial12", + "stage6.bytecode_read_raf.claim.term14.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_152: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial13", + "stage6.bytecode_read_raf.claim.term15.stage_gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_153: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial14", + "stage6.bytecode_read_raf.claim.term16.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_154: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial15", + "stage6.bytecode_read_raf.claim.term17.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_155: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial16", + "stage6.bytecode_read_raf.claim.term18.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_156: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial17", + "stage6.bytecode_read_raf.claim.term19.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_157: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial18", + "stage6.bytecode_read_raf.claim.term20.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_158: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial19", + "stage6.bytecode_read_raf.claim.term21.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_159: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial20", + "stage6.bytecode_read_raf.claim.term22.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_160: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial21", + "stage6.bytecode_read_raf.claim.term23.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_161: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial22", + "stage6.bytecode_read_raf.claim.term24.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_162: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial23", + "stage6.bytecode_read_raf.claim.term25.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_163: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial24", + "stage6.bytecode_read_raf.claim.term26.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_164: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial25", + "stage6.bytecode_read_raf.claim.term27.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_165: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial26", + "stage6.bytecode_read_raf.claim.term28.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_166: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial27", + "stage6.bytecode_read_raf.claim.term29.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_167: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial28", + "stage6.bytecode_read_raf.claim.term30.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_168: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial29", + "stage6.bytecode_read_raf.claim.term31.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_169: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial30", + "stage6.bytecode_read_raf.claim.term32.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_170: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial31", + "stage6.bytecode_read_raf.claim.term33.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_171: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial32", + "stage6.bytecode_read_raf.claim.term34.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_172: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial33", + "stage6.bytecode_read_raf.claim.term35.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_173: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial34", + "stage6.bytecode_read_raf.claim.term36.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_174: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial35", + "stage6.bytecode_read_raf.claim.term37.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_175: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial36", + "stage6.bytecode_read_raf.claim.term38.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_176: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial37", + "stage6.bytecode_read_raf.claim.term39.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_177: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial38", + "stage6.bytecode_read_raf.claim.term40.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_178: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial39", + "stage6.bytecode_read_raf.claim.term41.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_179: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial40", + "stage6.bytecode_read_raf.claim.term42.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_180: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial41", + "stage6.bytecode_read_raf.claim.term43.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_181: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial42", + "stage6.bytecode_read_raf.claim.term44.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_182: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial43", + "stage6.bytecode_read_raf.claim.term45.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_183: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial44", + "stage6.bytecode_read_raf.claim.term46.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_184: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial45", + "stage6.bytecode_read_raf.claim.term47.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_185: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial46", + "stage6.bytecode_read_raf.claim.term48.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_186: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial47", + "stage6.bytecode_read_raf.claim.term49.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_187: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial48", + "stage6.bytecode_read_raf.claim.term50.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_188: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial49", + "stage6.bytecode_read_raf.claim.term51.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_189: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial50", + "stage6.bytecode_read_raf.claim.term52.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_190: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial51", + "stage6.bytecode_read_raf.claim.term53.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_191: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial52", + "stage6.bytecode_read_raf.claim.term54.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_192: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial53", + "stage6.bytecode_read_raf.claim.term55.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_193: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial54", + "stage6.bytecode_read_raf.claim.term56.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_194: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial55", + "stage6.bytecode_read_raf.claim.term57.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_195: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial56", + "stage6.bytecode_read_raf.claim.term58.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_196: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial57", + "stage6.bytecode_read_raf.claim.term59.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_197: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial58", + "stage6.bytecode_read_raf.claim.term60.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_198: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial59", + "stage6.bytecode_read_raf.claim.term61.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_199: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial60", + "stage6.bytecode_read_raf.claim.term62.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_200: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial61", + "stage6.bytecode_read_raf.claim.term63.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_201: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial62", + "stage6.bytecode_read_raf.claim.term64.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_202: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial63", + "stage6.bytecode_read_raf.claim.term65.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_203: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial64", + "stage6.bytecode_read_raf.claim.term66.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_204: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial65", + "stage6.bytecode_read_raf.claim.term67.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_205: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial66", + "stage6.bytecode_read_raf.claim.term68.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_206: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial67", + "stage6.bytecode_read_raf.claim.term69.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_207: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial68", + "stage6.bytecode_read_raf.claim.term70.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_208: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial69", + "stage6.bytecode_read_raf.claim.term71.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_209: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial70", + "stage6.bytecode_read_raf.claim.term72.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_210: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial71", + "stage6.bytecode_read_raf.claim.term73.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_211: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial72", + "stage6.bytecode_read_raf.claim.term74.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_212: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial73", + "stage6.bytecode_read_raf.claim.term75.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_213: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial74", + "stage6.bytecode_read_raf.claim.term76.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_214: &[&str] = &[ + "stage6.bytecode_read_raf.claim_expr.partial75", + "stage6.bytecode_read_raf.claim.entry_constant", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_215: &[&str] = &["stage6.instruction_ra_virtual.gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_216: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term1.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_1", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_217: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term2.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_2", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_218: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term3.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_3", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_219: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term4.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_4", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_220: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term5.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_5", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_221: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term6.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_6", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_222: &[&str] = &[ + "stage6.instruction_ra_virtual.claim.term7.gamma_pow", + "stage6.input.stage5.instruction_read_raf.InstructionRa_7", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_223: &[&str] = &[ + "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + "stage6.instruction_ra_virtual.claim.term1.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_224: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial0", + "stage6.instruction_ra_virtual.claim.term2.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_225: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial1", + "stage6.instruction_ra_virtual.claim.term3.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_226: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial2", + "stage6.instruction_ra_virtual.claim.term4.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_227: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial3", + "stage6.instruction_ra_virtual.claim.term5.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_228: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial4", + "stage6.instruction_ra_virtual.claim.term6.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_229: &[&str] = &[ + "stage6.instruction_ra_virtual.claim_expr.partial5", + "stage6.instruction_ra_virtual.claim.term7.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_230: &[&str] = &["stage6.inc_claim_reduction.gamma"]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_231: &[&str] = &[ + "stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_pow", + "stage6.input.stage4.ram_val_check.RamInc", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_232: &[&str] = &[ + "stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_pow", + "stage6.input.stage4.registers_read_write.RdInc", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_233: &[&str] = &[ + "stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_pow", + "stage6.input.stage5.registers_val_evaluation.RdInc", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_234: &[&str] = &[ + "stage6.input.stage2.ram_read_write.RamInc", + "stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_235: &[&str] = &[ + "stage6.inc_claim_reduction.claim_expr.partial0", + "stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_term", +]; + +pub const STAGE6_FIELD_EXPR_OPERANDS_236: &[&str] = &[ + "stage6.inc_claim_reduction.claim_expr.partial1", + "stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_term", +]; + +pub const STAGE6_FIELD_EXPRS: &[Stage6FieldExprPlan] = &[ + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_0", kind: "op", formula: "field.pow:0", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_1", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_2", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_3", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_4", kind: "op", formula: "field.pow:8", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_5", kind: "op", formula: "field.pow:10", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_6", kind: "op", formula: "field.pow:12", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_7", kind: "op", formula: "field.pow:14", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_8", kind: "op", formula: "field.pow:16", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_9", kind: "op", formula: "field.pow:18", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_10", kind: "op", formula: "field.pow:20", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_11", kind: "op", formula: "field.pow:22", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_12", kind: "op", formula: "field.pow:24", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_13", kind: "op", formula: "field.pow:26", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_14", kind: "op", formula: "field.pow:28", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_15", kind: "op", formula: "field.pow:30", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_16", kind: "op", formula: "field.pow:32", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_17", kind: "op", formula: "field.pow:34", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_18", kind: "op", formula: "field.pow:36", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_19", kind: "op", formula: "field.pow:38", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_20", kind: "op", formula: "field.pow:40", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_21", kind: "op", formula: "field.pow:42", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_22", kind: "op", formula: "field.pow:44", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_23", kind: "op", formula: "field.pow:46", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_24", kind: "op", formula: "field.pow:48", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_25", kind: "op", formula: "field.pow:50", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_26", kind: "op", formula: "field.pow:52", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_27", kind: "op", formula: "field.pow:54", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_28", kind: "op", formula: "field.pow:56", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_29", kind: "op", formula: "field.pow:58", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_30", kind: "op", formula: "field.pow:60", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_31", kind: "op", formula: "field.pow:62", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_32", kind: "op", formula: "field.pow:64", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_33", kind: "op", formula: "field.pow:66", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_34", kind: "op", formula: "field.pow:68", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_35", kind: "op", formula: "field.pow:70", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_36", kind: "op", formula: "field.pow:72", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_37", kind: "op", formula: "field.pow:74", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_sq_38", kind: "op", formula: "field.pow:76", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_0", kind: "op", formula: "field.pow:0", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_1", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_2", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_3", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_4", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_5", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_6", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_7", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_8", kind: "op", formula: "field.pow:8", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_9", kind: "op", formula: "field.pow:9", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_10", kind: "op", formula: "field.pow:10", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_11", kind: "op", formula: "field.pow:11", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_12", kind: "op", formula: "field.pow:12", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_13", kind: "op", formula: "field.pow:13", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_14", kind: "op", formula: "field.pow:14", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_15", kind: "op", formula: "field.pow:15", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_16", kind: "op", formula: "field.pow:16", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_17", kind: "op", formula: "field.pow:17", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_18", kind: "op", formula: "field.pow:18", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_19", kind: "op", formula: "field.pow:19", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_20", kind: "op", formula: "field.pow:20", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_21", kind: "op", formula: "field.pow:21", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_22", kind: "op", formula: "field.pow:22", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_23", kind: "op", formula: "field.pow:23", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_24", kind: "op", formula: "field.pow:24", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_25", kind: "op", formula: "field.pow:25", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_26", kind: "op", formula: "field.pow:26", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_27", kind: "op", formula: "field.pow:27", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_28", kind: "op", formula: "field.pow:28", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_29", kind: "op", formula: "field.pow:29", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_30", kind: "op", formula: "field.pow:30", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_31", kind: "op", formula: "field.pow:31", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_32", kind: "op", formula: "field.pow:32", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_33", kind: "op", formula: "field.pow:33", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_34", kind: "op", formula: "field.pow:34", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_35", kind: "op", formula: "field.pow:35", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_36", kind: "op", formula: "field.pow:36", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_37", kind: "op", formula: "field.pow:37", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.booleanity.gamma_pow_38", kind: "op", formula: "field.pow:38", operand_names: STAGE6_FIELD_EXPR_OPERANDS_0, operands: STAGE6_FIELD_EXPR_OPERANDS_0 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term1.stage_gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term1.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_2, operands: STAGE6_FIELD_EXPR_OPERANDS_2 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term2.stage_gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term2.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_3, operands: STAGE6_FIELD_EXPR_OPERANDS_3 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term3.stage_gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term3.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_4, operands: STAGE6_FIELD_EXPR_OPERANDS_4 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term4.stage_gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term4.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_5, operands: STAGE6_FIELD_EXPR_OPERANDS_5 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term5.stage_gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term5.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_6, operands: STAGE6_FIELD_EXPR_OPERANDS_6 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term6.stage_gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term6.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_7, operands: STAGE6_FIELD_EXPR_OPERANDS_7 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term7.stage_gamma_pow", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term7.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_8, operands: STAGE6_FIELD_EXPR_OPERANDS_8 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term8.stage_gamma_pow", kind: "op", formula: "field.pow:8", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term8.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_9, operands: STAGE6_FIELD_EXPR_OPERANDS_9 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term9.stage_gamma_pow", kind: "op", formula: "field.pow:9", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term9.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_10, operands: STAGE6_FIELD_EXPR_OPERANDS_10 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term10.stage_gamma_pow", kind: "op", formula: "field.pow:10", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term10.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_11, operands: STAGE6_FIELD_EXPR_OPERANDS_11 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term11.stage_gamma_pow", kind: "op", formula: "field.pow:11", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term11.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_12, operands: STAGE6_FIELD_EXPR_OPERANDS_12 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term12.stage_gamma_pow", kind: "op", formula: "field.pow:12", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term12.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_13, operands: STAGE6_FIELD_EXPR_OPERANDS_13 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term13.stage_gamma_pow", kind: "op", formula: "field.pow:13", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term13.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_14, operands: STAGE6_FIELD_EXPR_OPERANDS_14 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term14.stage_gamma_pow", kind: "op", formula: "field.pow:14", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term14.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_15, operands: STAGE6_FIELD_EXPR_OPERANDS_15 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term15.stage_gamma_pow", kind: "op", formula: "field.pow:15", operand_names: STAGE6_FIELD_EXPR_OPERANDS_1, operands: STAGE6_FIELD_EXPR_OPERANDS_1 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term15.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_16, operands: STAGE6_FIELD_EXPR_OPERANDS_16 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term16.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term16.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_18, operands: STAGE6_FIELD_EXPR_OPERANDS_18 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term17.stage_gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_19, operands: STAGE6_FIELD_EXPR_OPERANDS_19 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term17.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_20, operands: STAGE6_FIELD_EXPR_OPERANDS_20 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term17.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term17.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_21, operands: STAGE6_FIELD_EXPR_OPERANDS_21 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term18.stage_gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_19, operands: STAGE6_FIELD_EXPR_OPERANDS_19 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term18.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_22, operands: STAGE6_FIELD_EXPR_OPERANDS_22 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term18.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term18.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_23, operands: STAGE6_FIELD_EXPR_OPERANDS_23 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term19.stage_gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_19, operands: STAGE6_FIELD_EXPR_OPERANDS_19 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term19.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_24, operands: STAGE6_FIELD_EXPR_OPERANDS_24 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term19.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term19.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_25, operands: STAGE6_FIELD_EXPR_OPERANDS_25 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term20.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term20.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_26, operands: STAGE6_FIELD_EXPR_OPERANDS_26 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term21.stage_gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term21.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_28, operands: STAGE6_FIELD_EXPR_OPERANDS_28 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term21.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term21.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_29, operands: STAGE6_FIELD_EXPR_OPERANDS_29 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term22.stage_gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term22.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_30, operands: STAGE6_FIELD_EXPR_OPERANDS_30 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term22.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term22.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_31, operands: STAGE6_FIELD_EXPR_OPERANDS_31 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term23.stage_gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term23.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_32, operands: STAGE6_FIELD_EXPR_OPERANDS_32 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term23.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term23.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_33, operands: STAGE6_FIELD_EXPR_OPERANDS_33 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term24.stage_gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term24.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_34, operands: STAGE6_FIELD_EXPR_OPERANDS_34 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term24.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term24.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_35, operands: STAGE6_FIELD_EXPR_OPERANDS_35 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term25.stage_gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term25.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_36, operands: STAGE6_FIELD_EXPR_OPERANDS_36 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term25.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term25.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_37, operands: STAGE6_FIELD_EXPR_OPERANDS_37 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term26.stage_gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term26.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_38, operands: STAGE6_FIELD_EXPR_OPERANDS_38 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term26.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term26.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_39, operands: STAGE6_FIELD_EXPR_OPERANDS_39 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term27.stage_gamma_pow", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term27.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_40, operands: STAGE6_FIELD_EXPR_OPERANDS_40 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term27.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term27.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_41, operands: STAGE6_FIELD_EXPR_OPERANDS_41 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term28.stage_gamma_pow", kind: "op", formula: "field.pow:8", operand_names: STAGE6_FIELD_EXPR_OPERANDS_27, operands: STAGE6_FIELD_EXPR_OPERANDS_27 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term28.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_42, operands: STAGE6_FIELD_EXPR_OPERANDS_42 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term28.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term28.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_43, operands: STAGE6_FIELD_EXPR_OPERANDS_43 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term29.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term29.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_44, operands: STAGE6_FIELD_EXPR_OPERANDS_44 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term30.stage_gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_45, operands: STAGE6_FIELD_EXPR_OPERANDS_45 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term30.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_46, operands: STAGE6_FIELD_EXPR_OPERANDS_46 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term30.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term30.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_47, operands: STAGE6_FIELD_EXPR_OPERANDS_47 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term31.stage_gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_45, operands: STAGE6_FIELD_EXPR_OPERANDS_45 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term31.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_48, operands: STAGE6_FIELD_EXPR_OPERANDS_48 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term31.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term31.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_49, operands: STAGE6_FIELD_EXPR_OPERANDS_49 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term32.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term32.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_50, operands: STAGE6_FIELD_EXPR_OPERANDS_50 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term33.stage_gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term33.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_52, operands: STAGE6_FIELD_EXPR_OPERANDS_52 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term33.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term33.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_53, operands: STAGE6_FIELD_EXPR_OPERANDS_53 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term34.stage_gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term34.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_54, operands: STAGE6_FIELD_EXPR_OPERANDS_54 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term34.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term34.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_55, operands: STAGE6_FIELD_EXPR_OPERANDS_55 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term35.stage_gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term35.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_56, operands: STAGE6_FIELD_EXPR_OPERANDS_56 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term35.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term35.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_57, operands: STAGE6_FIELD_EXPR_OPERANDS_57 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term36.stage_gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term36.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_58, operands: STAGE6_FIELD_EXPR_OPERANDS_58 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term36.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term36.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_59, operands: STAGE6_FIELD_EXPR_OPERANDS_59 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term37.stage_gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term37.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_60, operands: STAGE6_FIELD_EXPR_OPERANDS_60 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term37.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term37.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_61, operands: STAGE6_FIELD_EXPR_OPERANDS_61 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term38.stage_gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term38.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_62, operands: STAGE6_FIELD_EXPR_OPERANDS_62 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term38.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term38.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_63, operands: STAGE6_FIELD_EXPR_OPERANDS_63 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term39.stage_gamma_pow", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term39.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_64, operands: STAGE6_FIELD_EXPR_OPERANDS_64 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term39.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term39.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_65, operands: STAGE6_FIELD_EXPR_OPERANDS_65 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term40.stage_gamma_pow", kind: "op", formula: "field.pow:8", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term40.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_66, operands: STAGE6_FIELD_EXPR_OPERANDS_66 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term40.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term40.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_67, operands: STAGE6_FIELD_EXPR_OPERANDS_67 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term41.stage_gamma_pow", kind: "op", formula: "field.pow:9", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term41.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_68, operands: STAGE6_FIELD_EXPR_OPERANDS_68 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term41.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term41.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_69, operands: STAGE6_FIELD_EXPR_OPERANDS_69 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term42.stage_gamma_pow", kind: "op", formula: "field.pow:10", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term42.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_70, operands: STAGE6_FIELD_EXPR_OPERANDS_70 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term42.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term42.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_71, operands: STAGE6_FIELD_EXPR_OPERANDS_71 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term43.stage_gamma_pow", kind: "op", formula: "field.pow:11", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term43.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_72, operands: STAGE6_FIELD_EXPR_OPERANDS_72 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term43.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term43.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_73, operands: STAGE6_FIELD_EXPR_OPERANDS_73 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term44.stage_gamma_pow", kind: "op", formula: "field.pow:12", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term44.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_74, operands: STAGE6_FIELD_EXPR_OPERANDS_74 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term44.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term44.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_75, operands: STAGE6_FIELD_EXPR_OPERANDS_75 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term45.stage_gamma_pow", kind: "op", formula: "field.pow:13", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term45.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_76, operands: STAGE6_FIELD_EXPR_OPERANDS_76 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term45.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term45.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_77, operands: STAGE6_FIELD_EXPR_OPERANDS_77 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term46.stage_gamma_pow", kind: "op", formula: "field.pow:14", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term46.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_78, operands: STAGE6_FIELD_EXPR_OPERANDS_78 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term46.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term46.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_79, operands: STAGE6_FIELD_EXPR_OPERANDS_79 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term47.stage_gamma_pow", kind: "op", formula: "field.pow:15", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term47.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_80, operands: STAGE6_FIELD_EXPR_OPERANDS_80 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term47.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term47.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_81, operands: STAGE6_FIELD_EXPR_OPERANDS_81 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term48.stage_gamma_pow", kind: "op", formula: "field.pow:16", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term48.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_82, operands: STAGE6_FIELD_EXPR_OPERANDS_82 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term48.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term48.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_83, operands: STAGE6_FIELD_EXPR_OPERANDS_83 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term49.stage_gamma_pow", kind: "op", formula: "field.pow:17", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term49.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_84, operands: STAGE6_FIELD_EXPR_OPERANDS_84 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term49.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term49.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_85, operands: STAGE6_FIELD_EXPR_OPERANDS_85 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term50.stage_gamma_pow", kind: "op", formula: "field.pow:18", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term50.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_86, operands: STAGE6_FIELD_EXPR_OPERANDS_86 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term50.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term50.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_87, operands: STAGE6_FIELD_EXPR_OPERANDS_87 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term51.stage_gamma_pow", kind: "op", formula: "field.pow:19", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term51.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_88, operands: STAGE6_FIELD_EXPR_OPERANDS_88 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term51.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term51.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_89, operands: STAGE6_FIELD_EXPR_OPERANDS_89 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term52.stage_gamma_pow", kind: "op", formula: "field.pow:20", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term52.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_90, operands: STAGE6_FIELD_EXPR_OPERANDS_90 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term52.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term52.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_91, operands: STAGE6_FIELD_EXPR_OPERANDS_91 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term53.stage_gamma_pow", kind: "op", formula: "field.pow:21", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term53.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_92, operands: STAGE6_FIELD_EXPR_OPERANDS_92 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term53.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term53.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_93, operands: STAGE6_FIELD_EXPR_OPERANDS_93 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term54.stage_gamma_pow", kind: "op", formula: "field.pow:22", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term54.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_94, operands: STAGE6_FIELD_EXPR_OPERANDS_94 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term54.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term54.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_95, operands: STAGE6_FIELD_EXPR_OPERANDS_95 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term55.stage_gamma_pow", kind: "op", formula: "field.pow:23", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term55.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_96, operands: STAGE6_FIELD_EXPR_OPERANDS_96 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term55.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term55.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_97, operands: STAGE6_FIELD_EXPR_OPERANDS_97 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term56.stage_gamma_pow", kind: "op", formula: "field.pow:24", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term56.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_98, operands: STAGE6_FIELD_EXPR_OPERANDS_98 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term56.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term56.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_99, operands: STAGE6_FIELD_EXPR_OPERANDS_99 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term57.stage_gamma_pow", kind: "op", formula: "field.pow:25", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term57.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_100, operands: STAGE6_FIELD_EXPR_OPERANDS_100 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term57.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term57.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_101, operands: STAGE6_FIELD_EXPR_OPERANDS_101 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term58.stage_gamma_pow", kind: "op", formula: "field.pow:26", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term58.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_102, operands: STAGE6_FIELD_EXPR_OPERANDS_102 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term58.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term58.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_103, operands: STAGE6_FIELD_EXPR_OPERANDS_103 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term59.stage_gamma_pow", kind: "op", formula: "field.pow:27", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term59.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_104, operands: STAGE6_FIELD_EXPR_OPERANDS_104 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term59.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term59.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_105, operands: STAGE6_FIELD_EXPR_OPERANDS_105 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term60.stage_gamma_pow", kind: "op", formula: "field.pow:28", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term60.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_106, operands: STAGE6_FIELD_EXPR_OPERANDS_106 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term60.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term60.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_107, operands: STAGE6_FIELD_EXPR_OPERANDS_107 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term61.stage_gamma_pow", kind: "op", formula: "field.pow:29", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term61.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_108, operands: STAGE6_FIELD_EXPR_OPERANDS_108 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term61.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term61.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_109, operands: STAGE6_FIELD_EXPR_OPERANDS_109 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term62.stage_gamma_pow", kind: "op", formula: "field.pow:30", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term62.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_110, operands: STAGE6_FIELD_EXPR_OPERANDS_110 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term62.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term62.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_111, operands: STAGE6_FIELD_EXPR_OPERANDS_111 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term63.stage_gamma_pow", kind: "op", formula: "field.pow:31", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term63.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_112, operands: STAGE6_FIELD_EXPR_OPERANDS_112 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term63.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term63.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_113, operands: STAGE6_FIELD_EXPR_OPERANDS_113 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term64.stage_gamma_pow", kind: "op", formula: "field.pow:32", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term64.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_114, operands: STAGE6_FIELD_EXPR_OPERANDS_114 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term64.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term64.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_115, operands: STAGE6_FIELD_EXPR_OPERANDS_115 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term65.stage_gamma_pow", kind: "op", formula: "field.pow:33", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term65.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_116, operands: STAGE6_FIELD_EXPR_OPERANDS_116 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term65.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term65.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_117, operands: STAGE6_FIELD_EXPR_OPERANDS_117 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term66.stage_gamma_pow", kind: "op", formula: "field.pow:34", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term66.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_118, operands: STAGE6_FIELD_EXPR_OPERANDS_118 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term66.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term66.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_119, operands: STAGE6_FIELD_EXPR_OPERANDS_119 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term67.stage_gamma_pow", kind: "op", formula: "field.pow:35", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term67.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_120, operands: STAGE6_FIELD_EXPR_OPERANDS_120 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term67.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term67.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_121, operands: STAGE6_FIELD_EXPR_OPERANDS_121 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term68.stage_gamma_pow", kind: "op", formula: "field.pow:36", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term68.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_122, operands: STAGE6_FIELD_EXPR_OPERANDS_122 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term68.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term68.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_123, operands: STAGE6_FIELD_EXPR_OPERANDS_123 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term69.stage_gamma_pow", kind: "op", formula: "field.pow:37", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term69.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_124, operands: STAGE6_FIELD_EXPR_OPERANDS_124 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term69.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term69.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_125, operands: STAGE6_FIELD_EXPR_OPERANDS_125 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term70.stage_gamma_pow", kind: "op", formula: "field.pow:38", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term70.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_126, operands: STAGE6_FIELD_EXPR_OPERANDS_126 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term70.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term70.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_127, operands: STAGE6_FIELD_EXPR_OPERANDS_127 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term71.stage_gamma_pow", kind: "op", formula: "field.pow:39", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term71.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_128, operands: STAGE6_FIELD_EXPR_OPERANDS_128 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term71.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term71.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_129, operands: STAGE6_FIELD_EXPR_OPERANDS_129 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term72.stage_gamma_pow", kind: "op", formula: "field.pow:40", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term72.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_130, operands: STAGE6_FIELD_EXPR_OPERANDS_130 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term72.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term72.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_131, operands: STAGE6_FIELD_EXPR_OPERANDS_131 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term73.stage_gamma_pow", kind: "op", formula: "field.pow:41", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term73.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_132, operands: STAGE6_FIELD_EXPR_OPERANDS_132 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term73.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term73.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_133, operands: STAGE6_FIELD_EXPR_OPERANDS_133 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term74.stage_gamma_pow", kind: "op", formula: "field.pow:42", operand_names: STAGE6_FIELD_EXPR_OPERANDS_51, operands: STAGE6_FIELD_EXPR_OPERANDS_51 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term74.stage_gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_134, operands: STAGE6_FIELD_EXPR_OPERANDS_134 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term74.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term74.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_135, operands: STAGE6_FIELD_EXPR_OPERANDS_135 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term75.gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term75.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_136, operands: STAGE6_FIELD_EXPR_OPERANDS_136 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term76.gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.term76.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_137, operands: STAGE6_FIELD_EXPR_OPERANDS_137 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim.entry_constant", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_17, operands: STAGE6_FIELD_EXPR_OPERANDS_17 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial0", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_138, operands: STAGE6_FIELD_EXPR_OPERANDS_138 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial1", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_139, operands: STAGE6_FIELD_EXPR_OPERANDS_139 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial2", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_140, operands: STAGE6_FIELD_EXPR_OPERANDS_140 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial3", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_141, operands: STAGE6_FIELD_EXPR_OPERANDS_141 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial4", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_142, operands: STAGE6_FIELD_EXPR_OPERANDS_142 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial5", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_143, operands: STAGE6_FIELD_EXPR_OPERANDS_143 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial6", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_144, operands: STAGE6_FIELD_EXPR_OPERANDS_144 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial7", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_145, operands: STAGE6_FIELD_EXPR_OPERANDS_145 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial8", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_146, operands: STAGE6_FIELD_EXPR_OPERANDS_146 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial9", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_147, operands: STAGE6_FIELD_EXPR_OPERANDS_147 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial10", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_148, operands: STAGE6_FIELD_EXPR_OPERANDS_148 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial11", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_149, operands: STAGE6_FIELD_EXPR_OPERANDS_149 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial12", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_150, operands: STAGE6_FIELD_EXPR_OPERANDS_150 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial13", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_151, operands: STAGE6_FIELD_EXPR_OPERANDS_151 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial14", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_152, operands: STAGE6_FIELD_EXPR_OPERANDS_152 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial15", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_153, operands: STAGE6_FIELD_EXPR_OPERANDS_153 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial16", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_154, operands: STAGE6_FIELD_EXPR_OPERANDS_154 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial17", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_155, operands: STAGE6_FIELD_EXPR_OPERANDS_155 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial18", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_156, operands: STAGE6_FIELD_EXPR_OPERANDS_156 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial19", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_157, operands: STAGE6_FIELD_EXPR_OPERANDS_157 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial20", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_158, operands: STAGE6_FIELD_EXPR_OPERANDS_158 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial21", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_159, operands: STAGE6_FIELD_EXPR_OPERANDS_159 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial22", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_160, operands: STAGE6_FIELD_EXPR_OPERANDS_160 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial23", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_161, operands: STAGE6_FIELD_EXPR_OPERANDS_161 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial24", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_162, operands: STAGE6_FIELD_EXPR_OPERANDS_162 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial25", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_163, operands: STAGE6_FIELD_EXPR_OPERANDS_163 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial26", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_164, operands: STAGE6_FIELD_EXPR_OPERANDS_164 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial27", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_165, operands: STAGE6_FIELD_EXPR_OPERANDS_165 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial28", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_166, operands: STAGE6_FIELD_EXPR_OPERANDS_166 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial29", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_167, operands: STAGE6_FIELD_EXPR_OPERANDS_167 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial30", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_168, operands: STAGE6_FIELD_EXPR_OPERANDS_168 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial31", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_169, operands: STAGE6_FIELD_EXPR_OPERANDS_169 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial32", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_170, operands: STAGE6_FIELD_EXPR_OPERANDS_170 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial33", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_171, operands: STAGE6_FIELD_EXPR_OPERANDS_171 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial34", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_172, operands: STAGE6_FIELD_EXPR_OPERANDS_172 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial35", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_173, operands: STAGE6_FIELD_EXPR_OPERANDS_173 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial36", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_174, operands: STAGE6_FIELD_EXPR_OPERANDS_174 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial37", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_175, operands: STAGE6_FIELD_EXPR_OPERANDS_175 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial38", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_176, operands: STAGE6_FIELD_EXPR_OPERANDS_176 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial39", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_177, operands: STAGE6_FIELD_EXPR_OPERANDS_177 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial40", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_178, operands: STAGE6_FIELD_EXPR_OPERANDS_178 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial41", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_179, operands: STAGE6_FIELD_EXPR_OPERANDS_179 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial42", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_180, operands: STAGE6_FIELD_EXPR_OPERANDS_180 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial43", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_181, operands: STAGE6_FIELD_EXPR_OPERANDS_181 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial44", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_182, operands: STAGE6_FIELD_EXPR_OPERANDS_182 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial45", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_183, operands: STAGE6_FIELD_EXPR_OPERANDS_183 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial46", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_184, operands: STAGE6_FIELD_EXPR_OPERANDS_184 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial47", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_185, operands: STAGE6_FIELD_EXPR_OPERANDS_185 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial48", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_186, operands: STAGE6_FIELD_EXPR_OPERANDS_186 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial49", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_187, operands: STAGE6_FIELD_EXPR_OPERANDS_187 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial50", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_188, operands: STAGE6_FIELD_EXPR_OPERANDS_188 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial51", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_189, operands: STAGE6_FIELD_EXPR_OPERANDS_189 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial52", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_190, operands: STAGE6_FIELD_EXPR_OPERANDS_190 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial53", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_191, operands: STAGE6_FIELD_EXPR_OPERANDS_191 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial54", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_192, operands: STAGE6_FIELD_EXPR_OPERANDS_192 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial55", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_193, operands: STAGE6_FIELD_EXPR_OPERANDS_193 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial56", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_194, operands: STAGE6_FIELD_EXPR_OPERANDS_194 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial57", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_195, operands: STAGE6_FIELD_EXPR_OPERANDS_195 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial58", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_196, operands: STAGE6_FIELD_EXPR_OPERANDS_196 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial59", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_197, operands: STAGE6_FIELD_EXPR_OPERANDS_197 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial60", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_198, operands: STAGE6_FIELD_EXPR_OPERANDS_198 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial61", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_199, operands: STAGE6_FIELD_EXPR_OPERANDS_199 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial62", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_200, operands: STAGE6_FIELD_EXPR_OPERANDS_200 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial63", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_201, operands: STAGE6_FIELD_EXPR_OPERANDS_201 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial64", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_202, operands: STAGE6_FIELD_EXPR_OPERANDS_202 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial65", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_203, operands: STAGE6_FIELD_EXPR_OPERANDS_203 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial66", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_204, operands: STAGE6_FIELD_EXPR_OPERANDS_204 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial67", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_205, operands: STAGE6_FIELD_EXPR_OPERANDS_205 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial68", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_206, operands: STAGE6_FIELD_EXPR_OPERANDS_206 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial69", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_207, operands: STAGE6_FIELD_EXPR_OPERANDS_207 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial70", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_208, operands: STAGE6_FIELD_EXPR_OPERANDS_208 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial71", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_209, operands: STAGE6_FIELD_EXPR_OPERANDS_209 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial72", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_210, operands: STAGE6_FIELD_EXPR_OPERANDS_210 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial73", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_211, operands: STAGE6_FIELD_EXPR_OPERANDS_211 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial74", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_212, operands: STAGE6_FIELD_EXPR_OPERANDS_212 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial75", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_213, operands: STAGE6_FIELD_EXPR_OPERANDS_213 }, + Stage6FieldExprPlan { symbol: "stage6.bytecode_read_raf.claim_expr.partial76", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_214, operands: STAGE6_FIELD_EXPR_OPERANDS_214 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term1.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term1.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_216, operands: STAGE6_FIELD_EXPR_OPERANDS_216 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term2.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term2.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_217, operands: STAGE6_FIELD_EXPR_OPERANDS_217 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term3.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term3.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_218, operands: STAGE6_FIELD_EXPR_OPERANDS_218 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term4.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term4.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_219, operands: STAGE6_FIELD_EXPR_OPERANDS_219 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term5.gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term5.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_220, operands: STAGE6_FIELD_EXPR_OPERANDS_220 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term6.gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term6.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_221, operands: STAGE6_FIELD_EXPR_OPERANDS_221 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term7.gamma_pow", kind: "op", formula: "field.pow:7", operand_names: STAGE6_FIELD_EXPR_OPERANDS_215, operands: STAGE6_FIELD_EXPR_OPERANDS_215 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim.term7.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_222, operands: STAGE6_FIELD_EXPR_OPERANDS_222 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial0", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_223, operands: STAGE6_FIELD_EXPR_OPERANDS_223 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial1", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_224, operands: STAGE6_FIELD_EXPR_OPERANDS_224 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial2", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_225, operands: STAGE6_FIELD_EXPR_OPERANDS_225 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial3", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_226, operands: STAGE6_FIELD_EXPR_OPERANDS_226 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial4", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_227, operands: STAGE6_FIELD_EXPR_OPERANDS_227 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial5", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_228, operands: STAGE6_FIELD_EXPR_OPERANDS_228 }, + Stage6FieldExprPlan { symbol: "stage6.instruction_ra_virtual.claim_expr.partial6", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_229, operands: STAGE6_FIELD_EXPR_OPERANDS_229 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE6_FIELD_EXPR_OPERANDS_230, operands: STAGE6_FIELD_EXPR_OPERANDS_230 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_231, operands: STAGE6_FIELD_EXPR_OPERANDS_231 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE6_FIELD_EXPR_OPERANDS_230, operands: STAGE6_FIELD_EXPR_OPERANDS_230 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_232, operands: STAGE6_FIELD_EXPR_OPERANDS_232 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE6_FIELD_EXPR_OPERANDS_230, operands: STAGE6_FIELD_EXPR_OPERANDS_230 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE6_FIELD_EXPR_OPERANDS_233, operands: STAGE6_FIELD_EXPR_OPERANDS_233 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim_expr.partial0", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_234, operands: STAGE6_FIELD_EXPR_OPERANDS_234 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim_expr.partial1", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_235, operands: STAGE6_FIELD_EXPR_OPERANDS_235 }, + Stage6FieldExprPlan { symbol: "stage6.inc_claim_reduction.claim_expr.partial2", kind: "op", formula: "field.add", operand_names: STAGE6_FIELD_EXPR_OPERANDS_236, operands: STAGE6_FIELD_EXPR_OPERANDS_236 }, +]; +pub const STAGE6_KERNELS: &[Stage6KernelPlan] = &[ + Stage6KernelPlan { symbol: "jolt.cpu.stage6.bytecode_read_raf", relation: "jolt.stage6.bytecode_read_raf", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_bytecode_read_raf" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.booleanity", relation: "jolt.stage6.booleanity", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_booleanity" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.hamming_booleanity", relation: "jolt.stage6.hamming_booleanity", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_hamming_booleanity" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.ram_ra_virtual", relation: "jolt.stage6.ram_ra_virtual", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_ram_ra_virtual" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.instruction_ra_virtual", relation: "jolt.stage6.instruction_ra_virtual", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_instruction_ra_virtual" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.inc_claim_reduction", relation: "jolt.stage6.inc_claim_reduction", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_inc_claim_reduction" }, + Stage6KernelPlan { symbol: "jolt.cpu.stage6.batched", relation: "jolt.stage6.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage6_batched" }, +]; + +pub const STAGE6_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage6.input.stage1.UnexpandedPC", + "stage6.input.stage1.Imm", + "stage6.input.stage1.OpFlagAddOperands", + "stage6.input.stage1.OpFlagSubtractOperands", + "stage6.input.stage1.OpFlagMultiplyOperands", + "stage6.input.stage1.OpFlagLoad", + "stage6.input.stage1.OpFlagStore", + "stage6.input.stage1.OpFlagJump", + "stage6.input.stage1.OpFlagWriteLookupOutputToRD", + "stage6.input.stage1.OpFlagVirtualInstruction", + "stage6.input.stage1.OpFlagAssert", + "stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC", + "stage6.input.stage1.OpFlagAdvice", + "stage6.input.stage1.OpFlagIsCompressed", + "stage6.input.stage1.OpFlagIsFirstInSequence", + "stage6.input.stage1.OpFlagIsLastInSequence", + "stage6.input.stage2.OpFlagJump", + "stage6.input.stage2.InstructionFlagBranch", + "stage6.input.stage2.OpFlagWriteLookupOutputToRD", + "stage6.input.stage2.OpFlagVirtualInstruction", + "stage6.input.stage3.instruction_input.Imm", + "stage6.input.stage3.spartan_shift.UnexpandedPC", + "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value", + "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC", + "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value", + "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm", + "stage6.input.stage3.spartan_shift.InstructionFlagIsNoop", + "stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction", + "stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence", + "stage6.input.stage4.RdWa", + "stage6.input.stage4.Rs1Ra", + "stage6.input.stage4.Rs2Ra", + "stage6.input.stage5.registers_val_evaluation.RdWa", + "stage6.input.stage5.InstructionRafFlag", + "stage6.input.stage5.LookupTableFlag_0", + "stage6.input.stage5.LookupTableFlag_1", + "stage6.input.stage5.LookupTableFlag_2", + "stage6.input.stage5.LookupTableFlag_3", + "stage6.input.stage5.LookupTableFlag_4", + "stage6.input.stage5.LookupTableFlag_5", + "stage6.input.stage5.LookupTableFlag_6", + "stage6.input.stage5.LookupTableFlag_7", + "stage6.input.stage5.LookupTableFlag_8", + "stage6.input.stage5.LookupTableFlag_9", + "stage6.input.stage5.LookupTableFlag_10", + "stage6.input.stage5.LookupTableFlag_11", + "stage6.input.stage5.LookupTableFlag_12", + "stage6.input.stage5.LookupTableFlag_13", + "stage6.input.stage5.LookupTableFlag_14", + "stage6.input.stage5.LookupTableFlag_15", + "stage6.input.stage5.LookupTableFlag_16", + "stage6.input.stage5.LookupTableFlag_17", + "stage6.input.stage5.LookupTableFlag_18", + "stage6.input.stage5.LookupTableFlag_19", + "stage6.input.stage5.LookupTableFlag_20", + "stage6.input.stage5.LookupTableFlag_21", + "stage6.input.stage5.LookupTableFlag_22", + "stage6.input.stage5.LookupTableFlag_23", + "stage6.input.stage5.LookupTableFlag_24", + "stage6.input.stage5.LookupTableFlag_25", + "stage6.input.stage5.LookupTableFlag_26", + "stage6.input.stage5.LookupTableFlag_27", + "stage6.input.stage5.LookupTableFlag_28", + "stage6.input.stage5.LookupTableFlag_29", + "stage6.input.stage5.LookupTableFlag_30", + "stage6.input.stage5.LookupTableFlag_31", + "stage6.input.stage5.LookupTableFlag_32", + "stage6.input.stage5.LookupTableFlag_33", + "stage6.input.stage5.LookupTableFlag_34", + "stage6.input.stage5.LookupTableFlag_35", + "stage6.input.stage5.LookupTableFlag_36", + "stage6.input.stage5.LookupTableFlag_37", + "stage6.input.stage5.LookupTableFlag_38", + "stage6.input.stage5.LookupTableFlag_39", + "stage6.input.stage5.LookupTableFlag_40", + "stage6.input.stage1.PC", + "stage6.input.stage3.spartan_shift.PC", +]; + +pub const STAGE6_SUMCHECK_CLAIM_1_INPUT_OPENINGS: &[&str] = &[]; + +pub const STAGE6_SUMCHECK_CLAIM_2_INPUT_OPENINGS: &[&str] = &["stage6.input.stage1.LookupOutput"]; + +pub const STAGE6_SUMCHECK_CLAIM_3_INPUT_OPENINGS: &[&str] = &["stage6.input.stage5.ram_ra_claim_reduction.RamRa"]; + +pub const STAGE6_SUMCHECK_CLAIM_4_INPUT_OPENINGS: &[&str] = &[ + "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + "stage6.input.stage5.instruction_read_raf.InstructionRa_1", + "stage6.input.stage5.instruction_read_raf.InstructionRa_2", + "stage6.input.stage5.instruction_read_raf.InstructionRa_3", + "stage6.input.stage5.instruction_read_raf.InstructionRa_4", + "stage6.input.stage5.instruction_read_raf.InstructionRa_5", + "stage6.input.stage5.instruction_read_raf.InstructionRa_6", + "stage6.input.stage5.instruction_read_raf.InstructionRa_7", +]; + +pub const STAGE6_SUMCHECK_CLAIM_5_INPUT_OPENINGS: &[&str] = &[ + "stage6.input.stage2.ram_read_write.RamInc", + "stage6.input.stage4.ram_val_check.RamInc", + "stage6.input.stage4.registers_read_write.RdInc", + "stage6.input.stage5.registers_val_evaluation.RdInc", +]; + +pub const STAGE6_SUMCHECK_CLAIMS: &[Stage6SumcheckClaimPlan] = &[ + Stage6SumcheckClaimPlan { symbol: "stage6.bytecode_read_raf.input", stage: "stage6", domain: "jolt.stage6_bytecode_read_raf_domain", num_rounds: 26, degree: 4, claim: "stage6.bytecode_read_raf.weighted_prior_stage_values", kernel: Some("jolt.cpu.stage6.bytecode_read_raf"), relation: None, claim_value: "stage6.bytecode_read_raf.claim_expr.partial76", input_openings: STAGE6_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, + Stage6SumcheckClaimPlan { symbol: "stage6.booleanity.input", stage: "stage6", domain: "jolt.stage6_booleanity_domain", num_rounds: 20, degree: 3, claim: "stage6.booleanity.zero", kernel: Some("jolt.cpu.stage6.booleanity"), relation: None, claim_value: "stage6.zero", input_openings: STAGE6_SUMCHECK_CLAIM_1_INPUT_OPENINGS }, + Stage6SumcheckClaimPlan { symbol: "stage6.hamming_booleanity.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage6.hamming_booleanity.zero", kernel: Some("jolt.cpu.stage6.hamming_booleanity"), relation: None, claim_value: "stage6.zero", input_openings: STAGE6_SUMCHECK_CLAIM_2_INPUT_OPENINGS }, + Stage6SumcheckClaimPlan { symbol: "stage6.ram_ra_virtual.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 5, claim: "stage6.ram_ra_virtual.weighted_ram_ra", kernel: Some("jolt.cpu.stage6.ram_ra_virtual"), relation: None, claim_value: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", input_openings: STAGE6_SUMCHECK_CLAIM_3_INPUT_OPENINGS }, + Stage6SumcheckClaimPlan { symbol: "stage6.instruction_ra_virtual.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 5, claim: "stage6.instruction_ra_virtual.weighted_instruction_ra", kernel: Some("jolt.cpu.stage6.instruction_ra_virtual"), relation: None, claim_value: "stage6.instruction_ra_virtual.claim_expr.partial6", input_openings: STAGE6_SUMCHECK_CLAIM_4_INPUT_OPENINGS }, + Stage6SumcheckClaimPlan { symbol: "stage6.inc_claim_reduction.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage6.inc_claim_reduction.weighted_increments", kernel: Some("jolt.cpu.stage6.inc_claim_reduction"), relation: None, claim_value: "stage6.inc_claim_reduction.claim_expr.partial2", input_openings: STAGE6_SUMCHECK_CLAIM_5_INPUT_OPENINGS }, +]; +pub const STAGE6_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage6.bytecode_read_raf.input", + "stage6.booleanity.input", + "stage6.hamming_booleanity.input", + "stage6.ram_ra_virtual.input", + "stage6.instruction_ra_virtual.input", + "stage6.inc_claim_reduction.input", +]; + +pub const STAGE6_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage6.bytecode_read_raf.input", + "stage6.booleanity.input", + "stage6.hamming_booleanity.input", + "stage6.ram_ra_virtual.input", + "stage6.instruction_ra_virtual.input", + "stage6.inc_claim_reduction.input", +]; + +pub const STAGE6_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 10, + 16, +]; + +pub const STAGE6_SUMCHECK_BATCHES: &[Stage6SumcheckBatchPlan] = &[ + Stage6SumcheckBatchPlan { symbol: "stage6.batch", stage: "stage6", proof_slot: "stage6.sumcheck", policy: "jolt_core_stage6_aligned", count: 6, ordered_claims: STAGE6_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE6_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE6_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE6_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 10, + 16, +]; + +pub const STAGE6_SUMCHECK_DRIVERS: &[Stage6SumcheckDriverPlan] = &[ + Stage6SumcheckDriverPlan { symbol: "stage6.sumcheck", stage: "stage6", proof_slot: "stage6.sumcheck", kernel: Some("jolt.cpu.stage6.batched"), relation: None, batch: "stage6.batch", policy: "jolt_core_stage6_aligned", round_schedule: STAGE6_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 26, degree: 5 }, +]; +pub const STAGE6_SUMCHECK_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = &[ + Stage6SumcheckInstanceResultPlan { symbol: "stage6.bytecode_read_raf.instance", source: "stage6.sumcheck", claim: "stage6.bytecode_read_raf.input", relation: "jolt.stage6.bytecode_read_raf", index: 0, point_arity: 26, num_rounds: 26, round_offset: 0, point_order: "bytecode_read_raf", degree: 4 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.booleanity.instance", source: "stage6.sumcheck", claim: "stage6.booleanity.input", relation: "jolt.stage6.booleanity", index: 1, point_arity: 20, num_rounds: 20, round_offset: 6, point_order: "stage6_booleanity", degree: 3 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.hamming_booleanity.instance", source: "stage6.sumcheck", claim: "stage6.hamming_booleanity.input", relation: "jolt.stage6.hamming_booleanity", index: 2, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 3 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.ram_ra_virtual.instance", source: "stage6.sumcheck", claim: "stage6.ram_ra_virtual.input", relation: "jolt.stage6.ram_ra_virtual", index: 3, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 5 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.instruction_ra_virtual.instance", source: "stage6.sumcheck", claim: "stage6.instruction_ra_virtual.input", relation: "jolt.stage6.instruction_ra_virtual", index: 4, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 5 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.inc_claim_reduction.instance", source: "stage6.sumcheck", claim: "stage6.inc_claim_reduction.input", relation: "jolt.stage6.inc_claim_reduction", index: 5, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 2 }, +]; + +macro_rules! stage6_sumcheck_eval { + ($symbol:literal, $source:literal, $name:literal, $index:literal, $oracle:literal) => { + Stage6SumcheckEvalPlan { symbol: $symbol, source: $source, name: $name, index: $index, oracle: $oracle } + }; +} + +#[rustfmt::skip] +pub const STAGE6_SUMCHECK_EVALS: &[Stage6SumcheckEvalPlan] = &[ + stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_0", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_0", 0, "BytecodeRa_0"), stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_1", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_1", 1, "BytecodeRa_1"), stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_2", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_2", 2, "BytecodeRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_0", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_0", 0, "InstructionRa_0"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_1", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_1", 1, "InstructionRa_1"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_2", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_2", 2, "InstructionRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_3", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_3", 3, "InstructionRa_3"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_4", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_4", 4, "InstructionRa_4"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_5", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_5", 5, "InstructionRa_5"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_6", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_6", 6, "InstructionRa_6"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_7", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_7", 7, "InstructionRa_7"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_8", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_8", 8, "InstructionRa_8"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_9", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_9", 9, "InstructionRa_9"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_10", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_10", 10, "InstructionRa_10"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_11", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_11", 11, "InstructionRa_11"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_12", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_12", 12, "InstructionRa_12"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_13", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_13", 13, "InstructionRa_13"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_14", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_14", 14, "InstructionRa_14"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_15", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_15", 15, "InstructionRa_15"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_16", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_16", 16, "InstructionRa_16"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_17", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_17", 17, "InstructionRa_17"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_18", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_18", 18, "InstructionRa_18"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_19", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_19", 19, "InstructionRa_19"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_20", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_20", 20, "InstructionRa_20"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_21", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_21", 21, "InstructionRa_21"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_22", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_22", 22, "InstructionRa_22"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_23", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_23", 23, "InstructionRa_23"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_24", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_24", 24, "InstructionRa_24"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_25", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_25", 25, "InstructionRa_25"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_26", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_26", 26, "InstructionRa_26"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_27", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_27", 27, "InstructionRa_27"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_28", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_28", 28, "InstructionRa_28"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_29", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_29", 29, "InstructionRa_29"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_30", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_30", 30, "InstructionRa_30"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_31", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_31", 31, "InstructionRa_31"), stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_0", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_0", 32, "BytecodeRa_0"), + stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_1", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_1", 33, "BytecodeRa_1"), stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_2", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_2", 34, "BytecodeRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_0", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_0", 35, "RamRa_0"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_1", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_1", 36, "RamRa_1"), + stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_2", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_2", 37, "RamRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_3", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_3", 38, "RamRa_3"), stage6_sumcheck_eval!("stage6.hamming_booleanity.eval.HammingWeight", "stage6.sumcheck", "stage6.hamming_booleanity.eval.HammingWeight", 0, "HammingWeight"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_0", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_0", 0, "RamRa_0"), + stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_1", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_1", 1, "RamRa_1"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_2", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_2", 2, "RamRa_2"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_3", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_3", 3, "RamRa_3"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_0", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_0", 0, "InstructionRa_0"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_1", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_1", 1, "InstructionRa_1"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_2", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_2", 2, "InstructionRa_2"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_3", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_3", 3, "InstructionRa_3"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_4", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_4", 4, "InstructionRa_4"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_5", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_5", 5, "InstructionRa_5"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_6", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_6", 6, "InstructionRa_6"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_7", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_7", 7, "InstructionRa_7"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_8", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_8", 8, "InstructionRa_8"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_9", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_9", 9, "InstructionRa_9"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_10", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_10", 10, "InstructionRa_10"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_11", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_11", 11, "InstructionRa_11"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_12", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_12", 12, "InstructionRa_12"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_13", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_13", 13, "InstructionRa_13"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_14", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_14", 14, "InstructionRa_14"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_15", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_15", 15, "InstructionRa_15"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_16", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_16", 16, "InstructionRa_16"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_17", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_17", 17, "InstructionRa_17"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_18", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_18", 18, "InstructionRa_18"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_19", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_19", 19, "InstructionRa_19"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_20", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_20", 20, "InstructionRa_20"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_21", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_21", 21, "InstructionRa_21"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_22", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_22", 22, "InstructionRa_22"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_23", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_23", 23, "InstructionRa_23"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_24", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_24", 24, "InstructionRa_24"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_25", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_25", 25, "InstructionRa_25"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_26", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_26", 26, "InstructionRa_26"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_27", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_27", 27, "InstructionRa_27"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_28", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_28", 28, "InstructionRa_28"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_29", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_29", 29, "InstructionRa_29"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_30", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_30", 30, "InstructionRa_30"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_31", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_31", 31, "InstructionRa_31"), stage6_sumcheck_eval!("stage6.inc_claim_reduction.eval.RamInc", "stage6.sumcheck", "stage6.inc_claim_reduction.eval.RamInc", 0, "RamInc"), + stage6_sumcheck_eval!("stage6.inc_claim_reduction.eval.RdInc", "stage6.sumcheck", "stage6.inc_claim_reduction.eval.RdInc", 1, "RdInc"), +]; + +pub const STAGE6_POINT_ZEROS: &[Stage6PointZeroPlan] = &[ + Stage6PointZeroPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address.zero_pad", field: "bn254_fr", arity: 2 }, +]; + +pub const STAGE6_POINT_SLICES: &[Stage6PointSlicePlan] = &[ + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.Cycle", source: "stage6.bytecode_read_raf.instance", offset: 10, length: 16, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address.source", source: "stage6.bytecode_read_raf.instance", offset: 0, length: 2, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_1.address", source: "stage6.bytecode_read_raf.instance", offset: 2, length: 4, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_2.address", source: "stage6.bytecode_read_raf.instance", offset: 6, length: 4, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_0.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 0, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_1.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 4, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_2.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 8, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_3.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 12, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_0.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_1.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_2.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_3.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_4.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_5.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_6.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_7.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_8.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_9.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_10.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_11.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_12.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_13.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_14.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_15.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_16.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_17.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_18.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_19.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_20.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_21.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_22.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_23.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_24.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_25.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_26.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_27.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_28.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_29.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_30.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_31.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, +]; + +pub const STAGE6_POINT_CONCAT_0_INPUTS: &[&str] = &[ + "stage6.bytecode_read_raf.point.BytecodeRa_0.address.zero_pad", + "stage6.bytecode_read_raf.point.BytecodeRa_0.address.source", +]; + +pub const STAGE6_POINT_CONCAT_1_INPUTS: &[&str] = &[ + "stage6.bytecode_read_raf.point.BytecodeRa_0.address", + "stage6.bytecode_read_raf.point.Cycle", +]; + +pub const STAGE6_POINT_CONCAT_2_INPUTS: &[&str] = &[ + "stage6.bytecode_read_raf.point.BytecodeRa_1.address", + "stage6.bytecode_read_raf.point.Cycle", +]; + +pub const STAGE6_POINT_CONCAT_3_INPUTS: &[&str] = &[ + "stage6.bytecode_read_raf.point.BytecodeRa_2.address", + "stage6.bytecode_read_raf.point.Cycle", +]; + +pub const STAGE6_POINT_CONCAT_4_INPUTS: &[&str] = &[ + "stage6.ram_ra_virtual.point.RamRa_0.address", + "stage6.ram_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_5_INPUTS: &[&str] = &[ + "stage6.ram_ra_virtual.point.RamRa_1.address", + "stage6.ram_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_6_INPUTS: &[&str] = &[ + "stage6.ram_ra_virtual.point.RamRa_2.address", + "stage6.ram_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_7_INPUTS: &[&str] = &[ + "stage6.ram_ra_virtual.point.RamRa_3.address", + "stage6.ram_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_8_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_0.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_9_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_1.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_10_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_2.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_11_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_3.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_12_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_4.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_13_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_5.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_14_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_6.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_15_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_7.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_16_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_8.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_17_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_9.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_18_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_10.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_19_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_11.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_20_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_12.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_21_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_13.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_22_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_14.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_23_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_15.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_24_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_16.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_25_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_17.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_26_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_18.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_27_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_19.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_28_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_20.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_29_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_21.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_30_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_22.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_31_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_23.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_32_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_24.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_33_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_25.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_34_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_26.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_35_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_27.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_36_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_28.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_37_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_29.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_38_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_30.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCAT_39_INPUTS: &[&str] = &[ + "stage6.instruction_ra_virtual.point.InstructionRa_31.address", + "stage6.instruction_ra_virtual.instance", +]; + +pub const STAGE6_POINT_CONCATS: &[Stage6PointConcatPlan] = &[ + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address", layout: "left_zero_padded_address_chunk", arity: 4, inputs: STAGE6_POINT_CONCAT_0_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_1_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_2_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_3_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_4_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_5_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_6_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_3", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_7_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_8_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_9_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_10_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_3", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_11_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_4", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_12_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_5", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_13_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_6", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_14_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_7", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_15_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_8", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_16_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_9", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_17_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_10", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_18_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_11", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_19_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_12", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_20_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_13", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_21_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_14", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_22_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_15", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_23_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_16", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_24_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_17", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_25_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_18", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_26_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_19", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_27_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_20", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_28_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_21", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_29_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_22", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_30_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_23", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_31_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_24", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_32_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_25", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_33_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_26", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_34_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_27", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_35_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_28", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_36_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_29", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_37_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_30", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_38_INPUTS }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_31", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE6_POINT_CONCAT_39_INPUTS }, +]; +pub const STAGE6_OPENING_CLAIMS: &[Stage6OpeningClaimPlan] = &[ + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_0", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_1", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_2", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_4" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_5" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_6" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_7" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_8" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_9" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_10" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_11" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_12" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_13" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_14" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_15" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_16" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_17" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_18" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_19" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_20" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_21" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_22" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_23" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_24" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_25" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_26" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_27" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_28" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_29" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_30" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_31" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.hamming_booleanity.opening.HammingWeight", oracle: "HammingWeight", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage6.hamming_booleanity.instance", eval_source: "stage6.hamming_booleanity.eval.HammingWeight" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_0", eval_source: "stage6.ram_ra_virtual.eval.RamRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_1", eval_source: "stage6.ram_ra_virtual.eval.RamRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_2", eval_source: "stage6.ram_ra_virtual.eval.RamRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_3", eval_source: "stage6.ram_ra_virtual.eval.RamRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_0", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_1", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_2", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_3", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_4", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_4" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_5", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_5" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_6", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_6" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_7", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_7" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_8", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_8" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_9", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_9" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_10", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_10" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_11", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_11" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_12", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_12" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_13", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_13" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_14", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_14" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_15", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_15" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_16", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_16" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_17", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_17" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_18", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_18" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_19", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_19" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_20", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_20" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_21", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_21" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_22", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_22" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_23", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_23" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_24", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_24" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_25", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_25" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_26", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_26" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_27", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_27" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_28", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_28" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_29", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_29" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_30", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_30" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_31", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_31" }, + Stage6OpeningClaimPlan { symbol: "stage6.inc_claim_reduction.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage6.inc_claim_reduction.instance", eval_source: "stage6.inc_claim_reduction.eval.RamInc" }, + Stage6OpeningClaimPlan { symbol: "stage6.inc_claim_reduction.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage6.inc_claim_reduction.instance", eval_source: "stage6.inc_claim_reduction.eval.RdInc" }, +]; + +pub const STAGE6_OPENING_EQUALITIES: &[Stage6OpeningClaimEqualityPlan] = &[ + +]; + +pub const STAGE6_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage6.bytecode_read_raf.opening.BytecodeRa_0", + "stage6.bytecode_read_raf.opening.BytecodeRa_1", + "stage6.bytecode_read_raf.opening.BytecodeRa_2", + "stage6.booleanity.opening.InstructionRa_0", + "stage6.booleanity.opening.InstructionRa_1", + "stage6.booleanity.opening.InstructionRa_2", + "stage6.booleanity.opening.InstructionRa_3", + "stage6.booleanity.opening.InstructionRa_4", + "stage6.booleanity.opening.InstructionRa_5", + "stage6.booleanity.opening.InstructionRa_6", + "stage6.booleanity.opening.InstructionRa_7", + "stage6.booleanity.opening.InstructionRa_8", + "stage6.booleanity.opening.InstructionRa_9", + "stage6.booleanity.opening.InstructionRa_10", + "stage6.booleanity.opening.InstructionRa_11", + "stage6.booleanity.opening.InstructionRa_12", + "stage6.booleanity.opening.InstructionRa_13", + "stage6.booleanity.opening.InstructionRa_14", + "stage6.booleanity.opening.InstructionRa_15", + "stage6.booleanity.opening.InstructionRa_16", + "stage6.booleanity.opening.InstructionRa_17", + "stage6.booleanity.opening.InstructionRa_18", + "stage6.booleanity.opening.InstructionRa_19", + "stage6.booleanity.opening.InstructionRa_20", + "stage6.booleanity.opening.InstructionRa_21", + "stage6.booleanity.opening.InstructionRa_22", + "stage6.booleanity.opening.InstructionRa_23", + "stage6.booleanity.opening.InstructionRa_24", + "stage6.booleanity.opening.InstructionRa_25", + "stage6.booleanity.opening.InstructionRa_26", + "stage6.booleanity.opening.InstructionRa_27", + "stage6.booleanity.opening.InstructionRa_28", + "stage6.booleanity.opening.InstructionRa_29", + "stage6.booleanity.opening.InstructionRa_30", + "stage6.booleanity.opening.InstructionRa_31", + "stage6.booleanity.opening.BytecodeRa_0", + "stage6.booleanity.opening.BytecodeRa_1", + "stage6.booleanity.opening.BytecodeRa_2", + "stage6.booleanity.opening.RamRa_0", + "stage6.booleanity.opening.RamRa_1", + "stage6.booleanity.opening.RamRa_2", + "stage6.booleanity.opening.RamRa_3", + "stage6.hamming_booleanity.opening.HammingWeight", + "stage6.ram_ra_virtual.opening.RamRa_0", + "stage6.ram_ra_virtual.opening.RamRa_1", + "stage6.ram_ra_virtual.opening.RamRa_2", + "stage6.ram_ra_virtual.opening.RamRa_3", + "stage6.instruction_ra_virtual.opening.InstructionRa_0", + "stage6.instruction_ra_virtual.opening.InstructionRa_1", + "stage6.instruction_ra_virtual.opening.InstructionRa_2", + "stage6.instruction_ra_virtual.opening.InstructionRa_3", + "stage6.instruction_ra_virtual.opening.InstructionRa_4", + "stage6.instruction_ra_virtual.opening.InstructionRa_5", + "stage6.instruction_ra_virtual.opening.InstructionRa_6", + "stage6.instruction_ra_virtual.opening.InstructionRa_7", + "stage6.instruction_ra_virtual.opening.InstructionRa_8", + "stage6.instruction_ra_virtual.opening.InstructionRa_9", + "stage6.instruction_ra_virtual.opening.InstructionRa_10", + "stage6.instruction_ra_virtual.opening.InstructionRa_11", + "stage6.instruction_ra_virtual.opening.InstructionRa_12", + "stage6.instruction_ra_virtual.opening.InstructionRa_13", + "stage6.instruction_ra_virtual.opening.InstructionRa_14", + "stage6.instruction_ra_virtual.opening.InstructionRa_15", + "stage6.instruction_ra_virtual.opening.InstructionRa_16", + "stage6.instruction_ra_virtual.opening.InstructionRa_17", + "stage6.instruction_ra_virtual.opening.InstructionRa_18", + "stage6.instruction_ra_virtual.opening.InstructionRa_19", + "stage6.instruction_ra_virtual.opening.InstructionRa_20", + "stage6.instruction_ra_virtual.opening.InstructionRa_21", + "stage6.instruction_ra_virtual.opening.InstructionRa_22", + "stage6.instruction_ra_virtual.opening.InstructionRa_23", + "stage6.instruction_ra_virtual.opening.InstructionRa_24", + "stage6.instruction_ra_virtual.opening.InstructionRa_25", + "stage6.instruction_ra_virtual.opening.InstructionRa_26", + "stage6.instruction_ra_virtual.opening.InstructionRa_27", + "stage6.instruction_ra_virtual.opening.InstructionRa_28", + "stage6.instruction_ra_virtual.opening.InstructionRa_29", + "stage6.instruction_ra_virtual.opening.InstructionRa_30", + "stage6.instruction_ra_virtual.opening.InstructionRa_31", + "stage6.inc_claim_reduction.opening.RamInc", + "stage6.inc_claim_reduction.opening.RdInc", +]; + +pub const STAGE6_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage6.bytecode_read_raf.opening.BytecodeRa_0", + "stage6.bytecode_read_raf.opening.BytecodeRa_1", + "stage6.bytecode_read_raf.opening.BytecodeRa_2", + "stage6.booleanity.opening.InstructionRa_0", + "stage6.booleanity.opening.InstructionRa_1", + "stage6.booleanity.opening.InstructionRa_2", + "stage6.booleanity.opening.InstructionRa_3", + "stage6.booleanity.opening.InstructionRa_4", + "stage6.booleanity.opening.InstructionRa_5", + "stage6.booleanity.opening.InstructionRa_6", + "stage6.booleanity.opening.InstructionRa_7", + "stage6.booleanity.opening.InstructionRa_8", + "stage6.booleanity.opening.InstructionRa_9", + "stage6.booleanity.opening.InstructionRa_10", + "stage6.booleanity.opening.InstructionRa_11", + "stage6.booleanity.opening.InstructionRa_12", + "stage6.booleanity.opening.InstructionRa_13", + "stage6.booleanity.opening.InstructionRa_14", + "stage6.booleanity.opening.InstructionRa_15", + "stage6.booleanity.opening.InstructionRa_16", + "stage6.booleanity.opening.InstructionRa_17", + "stage6.booleanity.opening.InstructionRa_18", + "stage6.booleanity.opening.InstructionRa_19", + "stage6.booleanity.opening.InstructionRa_20", + "stage6.booleanity.opening.InstructionRa_21", + "stage6.booleanity.opening.InstructionRa_22", + "stage6.booleanity.opening.InstructionRa_23", + "stage6.booleanity.opening.InstructionRa_24", + "stage6.booleanity.opening.InstructionRa_25", + "stage6.booleanity.opening.InstructionRa_26", + "stage6.booleanity.opening.InstructionRa_27", + "stage6.booleanity.opening.InstructionRa_28", + "stage6.booleanity.opening.InstructionRa_29", + "stage6.booleanity.opening.InstructionRa_30", + "stage6.booleanity.opening.InstructionRa_31", + "stage6.booleanity.opening.BytecodeRa_0", + "stage6.booleanity.opening.BytecodeRa_1", + "stage6.booleanity.opening.BytecodeRa_2", + "stage6.booleanity.opening.RamRa_0", + "stage6.booleanity.opening.RamRa_1", + "stage6.booleanity.opening.RamRa_2", + "stage6.booleanity.opening.RamRa_3", + "stage6.hamming_booleanity.opening.HammingWeight", + "stage6.ram_ra_virtual.opening.RamRa_0", + "stage6.ram_ra_virtual.opening.RamRa_1", + "stage6.ram_ra_virtual.opening.RamRa_2", + "stage6.ram_ra_virtual.opening.RamRa_3", + "stage6.instruction_ra_virtual.opening.InstructionRa_0", + "stage6.instruction_ra_virtual.opening.InstructionRa_1", + "stage6.instruction_ra_virtual.opening.InstructionRa_2", + "stage6.instruction_ra_virtual.opening.InstructionRa_3", + "stage6.instruction_ra_virtual.opening.InstructionRa_4", + "stage6.instruction_ra_virtual.opening.InstructionRa_5", + "stage6.instruction_ra_virtual.opening.InstructionRa_6", + "stage6.instruction_ra_virtual.opening.InstructionRa_7", + "stage6.instruction_ra_virtual.opening.InstructionRa_8", + "stage6.instruction_ra_virtual.opening.InstructionRa_9", + "stage6.instruction_ra_virtual.opening.InstructionRa_10", + "stage6.instruction_ra_virtual.opening.InstructionRa_11", + "stage6.instruction_ra_virtual.opening.InstructionRa_12", + "stage6.instruction_ra_virtual.opening.InstructionRa_13", + "stage6.instruction_ra_virtual.opening.InstructionRa_14", + "stage6.instruction_ra_virtual.opening.InstructionRa_15", + "stage6.instruction_ra_virtual.opening.InstructionRa_16", + "stage6.instruction_ra_virtual.opening.InstructionRa_17", + "stage6.instruction_ra_virtual.opening.InstructionRa_18", + "stage6.instruction_ra_virtual.opening.InstructionRa_19", + "stage6.instruction_ra_virtual.opening.InstructionRa_20", + "stage6.instruction_ra_virtual.opening.InstructionRa_21", + "stage6.instruction_ra_virtual.opening.InstructionRa_22", + "stage6.instruction_ra_virtual.opening.InstructionRa_23", + "stage6.instruction_ra_virtual.opening.InstructionRa_24", + "stage6.instruction_ra_virtual.opening.InstructionRa_25", + "stage6.instruction_ra_virtual.opening.InstructionRa_26", + "stage6.instruction_ra_virtual.opening.InstructionRa_27", + "stage6.instruction_ra_virtual.opening.InstructionRa_28", + "stage6.instruction_ra_virtual.opening.InstructionRa_29", + "stage6.instruction_ra_virtual.opening.InstructionRa_30", + "stage6.instruction_ra_virtual.opening.InstructionRa_31", + "stage6.inc_claim_reduction.opening.RamInc", + "stage6.inc_claim_reduction.opening.RdInc", +]; + +pub const STAGE6_OPENING_BATCHES: &[Stage6OpeningBatchPlan] = &[ + Stage6OpeningBatchPlan { symbol: "stage6.openings", stage: "stage6", proof_slot: "stage6.openings", policy: "jolt_stage6_output_order", count: 81, ordered_claims: STAGE6_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE6_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE6_PROGRAM: Stage6CpuProgramPlan = Stage6CpuProgramPlan { + role: "prover", + params: STAGE6_PARAMS, + steps: STAGE6_PROGRAM_STEPS, + transcript_squeezes: STAGE6_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE6_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE6_OPENING_INPUTS, + field_constants: STAGE6_FIELD_CONSTANTS, + field_exprs: STAGE6_FIELD_EXPRS, + kernels: STAGE6_KERNELS, + claims: STAGE6_SUMCHECK_CLAIMS, + batches: STAGE6_SUMCHECK_BATCHES, + drivers: STAGE6_SUMCHECK_DRIVERS, + instance_results: STAGE6_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE6_SUMCHECK_EVALS, + point_zeros: STAGE6_POINT_ZEROS, + point_slices: STAGE6_POINT_SLICES, + point_concats: STAGE6_POINT_CONCATS, + opening_claims: STAGE6_OPENING_CLAIMS, + opening_equalities: STAGE6_OPENING_EQUALITIES, + opening_batches: STAGE6_OPENING_BATCHES, +}; + +pub fn execute_stage6_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + E: Stage6KernelExecutor, + T: Transcript, +{ + execute_stage6_prover_with_program(&STAGE6_PROGRAM, executor, transcript) +} + +pub fn execute_stage6_prover_with_program( + program: &'static Stage6CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage6KernelError> +where + E: Stage6KernelExecutor, + T: Transcript, +{ + execute_stage6_program(program, Stage6ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage7.rs b/crates/jolt-prover/src/stages/stage7.rs new file mode 100644 index 0000000000..831534a4b9 --- /dev/null +++ b/crates/jolt-prover/src/stages/stage7.rs @@ -0,0 +1,1950 @@ +#![allow(dead_code)] + +use jolt_field::Fr; +use jolt_kernels::stage7::{execute_stage7_program, Stage7CpuProgramPlan, Stage7ExecutionArtifacts, Stage7ExecutionMode, Stage7FieldConstantPlan, Stage7FieldExprPlan, Stage7KernelError, Stage7KernelExecutor, Stage7KernelPlan, Stage7OpeningBatchPlan, Stage7OpeningClaimEqualityPlan, Stage7OpeningClaimPlan, Stage7OpeningInputPlan, Stage7Params, Stage7PointConcatPlan, Stage7PointSlicePlan, Stage7PointZeroPlan, Stage7ProgramStepPlan, Stage7SumcheckBatchPlan, Stage7SumcheckClaimPlan, Stage7SumcheckDriverPlan, Stage7SumcheckEvalPlan, Stage7SumcheckInstanceResultPlan, Stage7TranscriptAbsorbBytesPlan, Stage7TranscriptSqueezePlan}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage7Transcript = Blake2bTranscript; + +pub const STAGE7_PARAMS: Stage7Params = Stage7Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE7_PROGRAM_STEPS: &[Stage7ProgramStepPlan] = &[ + Stage7ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage7.hamming_weight_claim_reduction.gamma" }, + Stage7ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage7.sumcheck" }, +]; + +pub const STAGE7_TRANSCRIPT_SQUEEZES: &[Stage7TranscriptSqueezePlan] = &[ + Stage7TranscriptSqueezePlan { symbol: "stage7.hamming_weight_claim_reduction.gamma", label: "hamming_weight_claim_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE7_TRANSCRIPT_ABSORB_BYTES: &[Stage7TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE7_OPENING_INPUTS: &[Stage7OpeningInputPlan] = &[ + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.hamming_booleanity.HammingWeight", source_stage: "stage6", source_claim: "stage6.hamming_booleanity.opening.HammingWeight", oracle: "HammingWeight", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_1", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_2", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_3", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_3", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_4", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_4", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_5", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_5", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_6", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_6", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_7", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_7", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_8", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_8", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_9", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_9", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_10", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_10", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_11", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_11", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_12", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_12", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_13", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_13", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_14", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_14", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_15", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_15", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_16", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_16", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_17", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_17", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_18", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_18", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_19", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_19", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_20", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_20", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_21", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_21", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_22", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_22", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_23", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_23", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_24", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_24", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_25", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_25", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_26", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_26", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_27", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_27", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_28", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_28", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_29", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_29", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_30", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_30", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_31", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_31", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_0", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_1", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_2", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_0", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_1", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_2", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_3", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_3", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, +]; + +pub const STAGE7_FIELD_CONSTANTS: &[Stage7FieldConstantPlan] = &[ + Stage7FieldConstantPlan { symbol: "stage7.field.one", field: "bn254_fr", value: 1 }, +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_0: &[&str] = &["stage7.hamming_weight_claim_reduction.gamma"]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_1: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_2: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_3: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_4: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_5: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_6: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_7: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_8: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_9: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_10: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_3", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_11: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_3", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_12: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_13: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_4", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_14: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_4", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_15: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_16: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_5", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_17: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_5", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_18: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_19: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_6", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_20: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_6", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_21: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_22: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_7", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_23: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_7", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_24: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_25: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_8", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_26: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_8", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_27: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_28: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_9", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_29: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_9", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_30: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_31: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_10", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_32: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_10", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_33: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_34: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_11", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_35: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_11", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_36: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_37: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_12", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_38: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_12", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_39: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_40: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_13", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_41: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_13", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_42: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_43: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_14", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_44: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_14", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_45: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_46: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_15", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_47: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_15", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_48: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_49: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_16", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_50: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_16", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_51: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_52: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_17", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_53: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_17", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_54: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_55: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_18", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_56: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_18", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_57: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_58: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_19", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_59: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_19", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_60: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_61: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_20", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_62: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_20", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_63: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_64: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_21", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_65: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_21", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_66: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_67: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_22", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_68: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_22", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_69: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_70: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_23", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_71: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_23", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_72: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_73: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_24", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_74: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_24", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_75: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_76: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_25", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_77: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_25", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_78: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_79: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_26", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_80: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_26", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_81: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_82: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_27", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_83: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_27", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_84: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_85: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_28", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_86: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_28", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_87: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_88: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_29", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_89: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_29", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_90: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_91: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_30", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_92: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_30", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_93: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_94: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.InstructionRa_31", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_95: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_pow", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_31", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_96: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_97: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.BytecodeRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_98: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_pow", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_99: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_100: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.BytecodeRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_101: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_pow", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_102: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_pow", + "stage7.field.one", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_103: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.BytecodeRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_104: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_pow", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_105: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_pow", + "stage7.input.stage6.hamming_booleanity.HammingWeight", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_106: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.RamRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_107: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_pow", + "stage7.input.stage6.ram_ra_virtual.RamRa_0", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_108: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_pow", + "stage7.input.stage6.hamming_booleanity.HammingWeight", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_109: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.RamRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_110: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_pow", + "stage7.input.stage6.ram_ra_virtual.RamRa_1", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_111: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_pow", + "stage7.input.stage6.hamming_booleanity.HammingWeight", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_112: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.RamRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_113: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_pow", + "stage7.input.stage6.ram_ra_virtual.RamRa_2", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_114: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_pow", + "stage7.input.stage6.hamming_booleanity.HammingWeight", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_115: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_pow", + "stage7.input.stage6.booleanity.RamRa_3", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_116: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_pow", + "stage7.input.stage6.ram_ra_virtual.RamRa_3", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_117: &[&str] = &[ + "stage7.field.one", + "stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_118: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial0", + "stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_119: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial1", + "stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_120: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial2", + "stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_121: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial3", + "stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_122: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial4", + "stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_123: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial5", + "stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_124: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial6", + "stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_125: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial7", + "stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_126: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial8", + "stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_127: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial9", + "stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_128: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial10", + "stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_129: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial11", + "stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_130: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial12", + "stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_131: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial13", + "stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_132: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial14", + "stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_133: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial15", + "stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_134: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial16", + "stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_135: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial17", + "stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_136: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial18", + "stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_137: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial19", + "stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_138: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial20", + "stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_139: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial21", + "stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_140: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial22", + "stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_141: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial23", + "stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_142: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial24", + "stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_143: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial25", + "stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_144: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial26", + "stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_145: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial27", + "stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_146: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial28", + "stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_147: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial29", + "stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_148: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial30", + "stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_149: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial31", + "stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_150: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial32", + "stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_151: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial33", + "stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_152: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial34", + "stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_153: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial35", + "stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_154: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial36", + "stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_155: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial37", + "stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_156: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial38", + "stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_157: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial39", + "stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_158: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial40", + "stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_159: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial41", + "stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_160: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial42", + "stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_161: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial43", + "stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_162: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial44", + "stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_163: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial45", + "stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_164: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial46", + "stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_165: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial47", + "stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_166: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial48", + "stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_167: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial49", + "stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_168: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial50", + "stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_169: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial51", + "stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_170: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial52", + "stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_171: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial53", + "stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_172: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial54", + "stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_173: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial55", + "stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_174: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial56", + "stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_175: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial57", + "stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_176: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial58", + "stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_177: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial59", + "stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_178: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial60", + "stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_179: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial61", + "stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_180: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial62", + "stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_181: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial63", + "stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_182: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial64", + "stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_183: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial65", + "stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_184: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial66", + "stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_185: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial67", + "stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_186: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial68", + "stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_187: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial69", + "stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_188: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial70", + "stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_189: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial71", + "stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_190: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial72", + "stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_191: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial73", + "stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_192: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial74", + "stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_193: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial75", + "stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_194: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial76", + "stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_195: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial77", + "stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_196: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial78", + "stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_197: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial79", + "stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_198: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial80", + "stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_199: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial81", + "stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_200: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial82", + "stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_201: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial83", + "stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_202: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial84", + "stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_203: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial85", + "stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_204: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial86", + "stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_205: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial87", + "stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_206: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial88", + "stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_207: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial89", + "stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_208: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial90", + "stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_209: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial91", + "stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_210: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial92", + "stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_211: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial93", + "stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_212: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial94", + "stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_213: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial95", + "stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_214: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial96", + "stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_215: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial97", + "stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_216: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial98", + "stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_217: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial99", + "stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_218: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial100", + "stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_219: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial101", + "stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_220: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial102", + "stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_221: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial103", + "stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_222: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial104", + "stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_223: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial105", + "stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_224: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial106", + "stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_225: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial107", + "stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_226: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial108", + "stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_227: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial109", + "stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_228: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial110", + "stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_229: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial111", + "stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_230: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial112", + "stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_231: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial113", + "stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_term", +]; + +pub const STAGE7_FIELD_EXPR_OPERANDS_232: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.claim_expr.partial114", + "stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_term", +]; + +pub const STAGE7_FIELD_EXPRS: &[Stage7FieldExprPlan] = &[ + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_pow", kind: "op", formula: "field.pow:1", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_1, operands: STAGE7_FIELD_EXPR_OPERANDS_1 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_pow", kind: "op", formula: "field.pow:2", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_2, operands: STAGE7_FIELD_EXPR_OPERANDS_2 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_pow", kind: "op", formula: "field.pow:3", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_3, operands: STAGE7_FIELD_EXPR_OPERANDS_3 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_pow", kind: "op", formula: "field.pow:4", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_4, operands: STAGE7_FIELD_EXPR_OPERANDS_4 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_pow", kind: "op", formula: "field.pow:5", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_5, operands: STAGE7_FIELD_EXPR_OPERANDS_5 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_pow", kind: "op", formula: "field.pow:6", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_6, operands: STAGE7_FIELD_EXPR_OPERANDS_6 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_pow", kind: "op", formula: "field.pow:7", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_7, operands: STAGE7_FIELD_EXPR_OPERANDS_7 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_pow", kind: "op", formula: "field.pow:8", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_8, operands: STAGE7_FIELD_EXPR_OPERANDS_8 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_pow", kind: "op", formula: "field.pow:9", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_9, operands: STAGE7_FIELD_EXPR_OPERANDS_9 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_pow", kind: "op", formula: "field.pow:10", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_10, operands: STAGE7_FIELD_EXPR_OPERANDS_10 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_pow", kind: "op", formula: "field.pow:11", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_11, operands: STAGE7_FIELD_EXPR_OPERANDS_11 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_pow", kind: "op", formula: "field.pow:12", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_12, operands: STAGE7_FIELD_EXPR_OPERANDS_12 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_pow", kind: "op", formula: "field.pow:13", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_13, operands: STAGE7_FIELD_EXPR_OPERANDS_13 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_pow", kind: "op", formula: "field.pow:14", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_14, operands: STAGE7_FIELD_EXPR_OPERANDS_14 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_pow", kind: "op", formula: "field.pow:15", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_15, operands: STAGE7_FIELD_EXPR_OPERANDS_15 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_pow", kind: "op", formula: "field.pow:16", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_16, operands: STAGE7_FIELD_EXPR_OPERANDS_16 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_pow", kind: "op", formula: "field.pow:17", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_17, operands: STAGE7_FIELD_EXPR_OPERANDS_17 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_pow", kind: "op", formula: "field.pow:18", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_18, operands: STAGE7_FIELD_EXPR_OPERANDS_18 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_pow", kind: "op", formula: "field.pow:19", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_19, operands: STAGE7_FIELD_EXPR_OPERANDS_19 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_pow", kind: "op", formula: "field.pow:20", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_20, operands: STAGE7_FIELD_EXPR_OPERANDS_20 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_pow", kind: "op", formula: "field.pow:21", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_21, operands: STAGE7_FIELD_EXPR_OPERANDS_21 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_pow", kind: "op", formula: "field.pow:22", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_22, operands: STAGE7_FIELD_EXPR_OPERANDS_22 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_pow", kind: "op", formula: "field.pow:23", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_23, operands: STAGE7_FIELD_EXPR_OPERANDS_23 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_pow", kind: "op", formula: "field.pow:24", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_24, operands: STAGE7_FIELD_EXPR_OPERANDS_24 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_pow", kind: "op", formula: "field.pow:25", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_25, operands: STAGE7_FIELD_EXPR_OPERANDS_25 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_pow", kind: "op", formula: "field.pow:26", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_26, operands: STAGE7_FIELD_EXPR_OPERANDS_26 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_pow", kind: "op", formula: "field.pow:27", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_27, operands: STAGE7_FIELD_EXPR_OPERANDS_27 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_pow", kind: "op", formula: "field.pow:28", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_28, operands: STAGE7_FIELD_EXPR_OPERANDS_28 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_pow", kind: "op", formula: "field.pow:29", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_29, operands: STAGE7_FIELD_EXPR_OPERANDS_29 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_pow", kind: "op", formula: "field.pow:30", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_30, operands: STAGE7_FIELD_EXPR_OPERANDS_30 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_pow", kind: "op", formula: "field.pow:31", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_31, operands: STAGE7_FIELD_EXPR_OPERANDS_31 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_pow", kind: "op", formula: "field.pow:32", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_32, operands: STAGE7_FIELD_EXPR_OPERANDS_32 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_pow", kind: "op", formula: "field.pow:33", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_33, operands: STAGE7_FIELD_EXPR_OPERANDS_33 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_pow", kind: "op", formula: "field.pow:34", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_34, operands: STAGE7_FIELD_EXPR_OPERANDS_34 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_pow", kind: "op", formula: "field.pow:35", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_35, operands: STAGE7_FIELD_EXPR_OPERANDS_35 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_pow", kind: "op", formula: "field.pow:36", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_36, operands: STAGE7_FIELD_EXPR_OPERANDS_36 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_pow", kind: "op", formula: "field.pow:37", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_37, operands: STAGE7_FIELD_EXPR_OPERANDS_37 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_pow", kind: "op", formula: "field.pow:38", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_38, operands: STAGE7_FIELD_EXPR_OPERANDS_38 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_pow", kind: "op", formula: "field.pow:39", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_39, operands: STAGE7_FIELD_EXPR_OPERANDS_39 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_pow", kind: "op", formula: "field.pow:40", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_40, operands: STAGE7_FIELD_EXPR_OPERANDS_40 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_pow", kind: "op", formula: "field.pow:41", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_41, operands: STAGE7_FIELD_EXPR_OPERANDS_41 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_pow", kind: "op", formula: "field.pow:42", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_42, operands: STAGE7_FIELD_EXPR_OPERANDS_42 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_pow", kind: "op", formula: "field.pow:43", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_43, operands: STAGE7_FIELD_EXPR_OPERANDS_43 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_pow", kind: "op", formula: "field.pow:44", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_44, operands: STAGE7_FIELD_EXPR_OPERANDS_44 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_pow", kind: "op", formula: "field.pow:45", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_45, operands: STAGE7_FIELD_EXPR_OPERANDS_45 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_pow", kind: "op", formula: "field.pow:46", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_46, operands: STAGE7_FIELD_EXPR_OPERANDS_46 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_pow", kind: "op", formula: "field.pow:47", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_47, operands: STAGE7_FIELD_EXPR_OPERANDS_47 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_pow", kind: "op", formula: "field.pow:48", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_48, operands: STAGE7_FIELD_EXPR_OPERANDS_48 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_pow", kind: "op", formula: "field.pow:49", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_49, operands: STAGE7_FIELD_EXPR_OPERANDS_49 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_pow", kind: "op", formula: "field.pow:50", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_50, operands: STAGE7_FIELD_EXPR_OPERANDS_50 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_pow", kind: "op", formula: "field.pow:51", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_51, operands: STAGE7_FIELD_EXPR_OPERANDS_51 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_pow", kind: "op", formula: "field.pow:52", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_52, operands: STAGE7_FIELD_EXPR_OPERANDS_52 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_pow", kind: "op", formula: "field.pow:53", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_53, operands: STAGE7_FIELD_EXPR_OPERANDS_53 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_pow", kind: "op", formula: "field.pow:54", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_54, operands: STAGE7_FIELD_EXPR_OPERANDS_54 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_pow", kind: "op", formula: "field.pow:55", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_55, operands: STAGE7_FIELD_EXPR_OPERANDS_55 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_pow", kind: "op", formula: "field.pow:56", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_56, operands: STAGE7_FIELD_EXPR_OPERANDS_56 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_pow", kind: "op", formula: "field.pow:57", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_57, operands: STAGE7_FIELD_EXPR_OPERANDS_57 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_pow", kind: "op", formula: "field.pow:58", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_58, operands: STAGE7_FIELD_EXPR_OPERANDS_58 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_pow", kind: "op", formula: "field.pow:59", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_59, operands: STAGE7_FIELD_EXPR_OPERANDS_59 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_pow", kind: "op", formula: "field.pow:60", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_60, operands: STAGE7_FIELD_EXPR_OPERANDS_60 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_pow", kind: "op", formula: "field.pow:61", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_61, operands: STAGE7_FIELD_EXPR_OPERANDS_61 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_pow", kind: "op", formula: "field.pow:62", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_62, operands: STAGE7_FIELD_EXPR_OPERANDS_62 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_pow", kind: "op", formula: "field.pow:63", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_63, operands: STAGE7_FIELD_EXPR_OPERANDS_63 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_pow", kind: "op", formula: "field.pow:64", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_64, operands: STAGE7_FIELD_EXPR_OPERANDS_64 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_pow", kind: "op", formula: "field.pow:65", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_65, operands: STAGE7_FIELD_EXPR_OPERANDS_65 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_pow", kind: "op", formula: "field.pow:66", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_66, operands: STAGE7_FIELD_EXPR_OPERANDS_66 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_pow", kind: "op", formula: "field.pow:67", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_67, operands: STAGE7_FIELD_EXPR_OPERANDS_67 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_pow", kind: "op", formula: "field.pow:68", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_68, operands: STAGE7_FIELD_EXPR_OPERANDS_68 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_pow", kind: "op", formula: "field.pow:69", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_69, operands: STAGE7_FIELD_EXPR_OPERANDS_69 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_pow", kind: "op", formula: "field.pow:70", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_70, operands: STAGE7_FIELD_EXPR_OPERANDS_70 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_pow", kind: "op", formula: "field.pow:71", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_71, operands: STAGE7_FIELD_EXPR_OPERANDS_71 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_pow", kind: "op", formula: "field.pow:72", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_72, operands: STAGE7_FIELD_EXPR_OPERANDS_72 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_pow", kind: "op", formula: "field.pow:73", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_73, operands: STAGE7_FIELD_EXPR_OPERANDS_73 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_pow", kind: "op", formula: "field.pow:74", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_74, operands: STAGE7_FIELD_EXPR_OPERANDS_74 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_pow", kind: "op", formula: "field.pow:75", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_75, operands: STAGE7_FIELD_EXPR_OPERANDS_75 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_pow", kind: "op", formula: "field.pow:76", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_76, operands: STAGE7_FIELD_EXPR_OPERANDS_76 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_pow", kind: "op", formula: "field.pow:77", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_77, operands: STAGE7_FIELD_EXPR_OPERANDS_77 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_pow", kind: "op", formula: "field.pow:78", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_78, operands: STAGE7_FIELD_EXPR_OPERANDS_78 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_pow", kind: "op", formula: "field.pow:79", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_79, operands: STAGE7_FIELD_EXPR_OPERANDS_79 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_pow", kind: "op", formula: "field.pow:80", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_80, operands: STAGE7_FIELD_EXPR_OPERANDS_80 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_pow", kind: "op", formula: "field.pow:81", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_81, operands: STAGE7_FIELD_EXPR_OPERANDS_81 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_pow", kind: "op", formula: "field.pow:82", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_82, operands: STAGE7_FIELD_EXPR_OPERANDS_82 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_pow", kind: "op", formula: "field.pow:83", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_83, operands: STAGE7_FIELD_EXPR_OPERANDS_83 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_pow", kind: "op", formula: "field.pow:84", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_84, operands: STAGE7_FIELD_EXPR_OPERANDS_84 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_pow", kind: "op", formula: "field.pow:85", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_85, operands: STAGE7_FIELD_EXPR_OPERANDS_85 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_pow", kind: "op", formula: "field.pow:86", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_86, operands: STAGE7_FIELD_EXPR_OPERANDS_86 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_pow", kind: "op", formula: "field.pow:87", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_87, operands: STAGE7_FIELD_EXPR_OPERANDS_87 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_pow", kind: "op", formula: "field.pow:88", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_88, operands: STAGE7_FIELD_EXPR_OPERANDS_88 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_pow", kind: "op", formula: "field.pow:89", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_89, operands: STAGE7_FIELD_EXPR_OPERANDS_89 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_pow", kind: "op", formula: "field.pow:90", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_90, operands: STAGE7_FIELD_EXPR_OPERANDS_90 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_pow", kind: "op", formula: "field.pow:91", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_91, operands: STAGE7_FIELD_EXPR_OPERANDS_91 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_pow", kind: "op", formula: "field.pow:92", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_92, operands: STAGE7_FIELD_EXPR_OPERANDS_92 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_pow", kind: "op", formula: "field.pow:93", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_93, operands: STAGE7_FIELD_EXPR_OPERANDS_93 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_pow", kind: "op", formula: "field.pow:94", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_94, operands: STAGE7_FIELD_EXPR_OPERANDS_94 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_pow", kind: "op", formula: "field.pow:95", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_95, operands: STAGE7_FIELD_EXPR_OPERANDS_95 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_pow", kind: "op", formula: "field.pow:96", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_96, operands: STAGE7_FIELD_EXPR_OPERANDS_96 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_pow", kind: "op", formula: "field.pow:97", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_97, operands: STAGE7_FIELD_EXPR_OPERANDS_97 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_pow", kind: "op", formula: "field.pow:98", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_98, operands: STAGE7_FIELD_EXPR_OPERANDS_98 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_pow", kind: "op", formula: "field.pow:99", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_99, operands: STAGE7_FIELD_EXPR_OPERANDS_99 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_pow", kind: "op", formula: "field.pow:100", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_100, operands: STAGE7_FIELD_EXPR_OPERANDS_100 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_pow", kind: "op", formula: "field.pow:101", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_101, operands: STAGE7_FIELD_EXPR_OPERANDS_101 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_pow", kind: "op", formula: "field.pow:102", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_102, operands: STAGE7_FIELD_EXPR_OPERANDS_102 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_pow", kind: "op", formula: "field.pow:103", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_103, operands: STAGE7_FIELD_EXPR_OPERANDS_103 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_pow", kind: "op", formula: "field.pow:104", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_104, operands: STAGE7_FIELD_EXPR_OPERANDS_104 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_pow", kind: "op", formula: "field.pow:105", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_105, operands: STAGE7_FIELD_EXPR_OPERANDS_105 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_pow", kind: "op", formula: "field.pow:106", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_106, operands: STAGE7_FIELD_EXPR_OPERANDS_106 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_pow", kind: "op", formula: "field.pow:107", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_107, operands: STAGE7_FIELD_EXPR_OPERANDS_107 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_pow", kind: "op", formula: "field.pow:108", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_108, operands: STAGE7_FIELD_EXPR_OPERANDS_108 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_pow", kind: "op", formula: "field.pow:109", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_109, operands: STAGE7_FIELD_EXPR_OPERANDS_109 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_pow", kind: "op", formula: "field.pow:110", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_110, operands: STAGE7_FIELD_EXPR_OPERANDS_110 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_pow", kind: "op", formula: "field.pow:111", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_111, operands: STAGE7_FIELD_EXPR_OPERANDS_111 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_pow", kind: "op", formula: "field.pow:112", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_112, operands: STAGE7_FIELD_EXPR_OPERANDS_112 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_pow", kind: "op", formula: "field.pow:113", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_113, operands: STAGE7_FIELD_EXPR_OPERANDS_113 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_pow", kind: "op", formula: "field.pow:114", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_114, operands: STAGE7_FIELD_EXPR_OPERANDS_114 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_pow", kind: "op", formula: "field.pow:115", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_115, operands: STAGE7_FIELD_EXPR_OPERANDS_115 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_pow", kind: "op", formula: "field.pow:116", operand_names: STAGE7_FIELD_EXPR_OPERANDS_0, operands: STAGE7_FIELD_EXPR_OPERANDS_0 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_term", kind: "op", formula: "field.mul", operand_names: STAGE7_FIELD_EXPR_OPERANDS_116, operands: STAGE7_FIELD_EXPR_OPERANDS_116 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial0", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_117, operands: STAGE7_FIELD_EXPR_OPERANDS_117 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial1", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_118, operands: STAGE7_FIELD_EXPR_OPERANDS_118 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial2", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_119, operands: STAGE7_FIELD_EXPR_OPERANDS_119 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial3", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_120, operands: STAGE7_FIELD_EXPR_OPERANDS_120 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial4", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_121, operands: STAGE7_FIELD_EXPR_OPERANDS_121 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial5", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_122, operands: STAGE7_FIELD_EXPR_OPERANDS_122 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial6", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_123, operands: STAGE7_FIELD_EXPR_OPERANDS_123 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial7", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_124, operands: STAGE7_FIELD_EXPR_OPERANDS_124 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial8", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_125, operands: STAGE7_FIELD_EXPR_OPERANDS_125 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial9", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_126, operands: STAGE7_FIELD_EXPR_OPERANDS_126 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial10", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_127, operands: STAGE7_FIELD_EXPR_OPERANDS_127 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial11", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_128, operands: STAGE7_FIELD_EXPR_OPERANDS_128 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial12", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_129, operands: STAGE7_FIELD_EXPR_OPERANDS_129 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial13", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_130, operands: STAGE7_FIELD_EXPR_OPERANDS_130 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial14", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_131, operands: STAGE7_FIELD_EXPR_OPERANDS_131 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial15", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_132, operands: STAGE7_FIELD_EXPR_OPERANDS_132 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial16", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_133, operands: STAGE7_FIELD_EXPR_OPERANDS_133 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial17", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_134, operands: STAGE7_FIELD_EXPR_OPERANDS_134 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial18", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_135, operands: STAGE7_FIELD_EXPR_OPERANDS_135 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial19", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_136, operands: STAGE7_FIELD_EXPR_OPERANDS_136 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial20", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_137, operands: STAGE7_FIELD_EXPR_OPERANDS_137 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial21", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_138, operands: STAGE7_FIELD_EXPR_OPERANDS_138 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial22", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_139, operands: STAGE7_FIELD_EXPR_OPERANDS_139 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial23", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_140, operands: STAGE7_FIELD_EXPR_OPERANDS_140 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial24", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_141, operands: STAGE7_FIELD_EXPR_OPERANDS_141 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial25", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_142, operands: STAGE7_FIELD_EXPR_OPERANDS_142 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial26", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_143, operands: STAGE7_FIELD_EXPR_OPERANDS_143 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial27", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_144, operands: STAGE7_FIELD_EXPR_OPERANDS_144 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial28", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_145, operands: STAGE7_FIELD_EXPR_OPERANDS_145 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial29", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_146, operands: STAGE7_FIELD_EXPR_OPERANDS_146 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial30", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_147, operands: STAGE7_FIELD_EXPR_OPERANDS_147 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial31", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_148, operands: STAGE7_FIELD_EXPR_OPERANDS_148 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial32", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_149, operands: STAGE7_FIELD_EXPR_OPERANDS_149 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial33", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_150, operands: STAGE7_FIELD_EXPR_OPERANDS_150 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial34", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_151, operands: STAGE7_FIELD_EXPR_OPERANDS_151 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial35", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_152, operands: STAGE7_FIELD_EXPR_OPERANDS_152 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial36", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_153, operands: STAGE7_FIELD_EXPR_OPERANDS_153 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial37", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_154, operands: STAGE7_FIELD_EXPR_OPERANDS_154 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial38", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_155, operands: STAGE7_FIELD_EXPR_OPERANDS_155 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial39", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_156, operands: STAGE7_FIELD_EXPR_OPERANDS_156 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial40", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_157, operands: STAGE7_FIELD_EXPR_OPERANDS_157 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial41", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_158, operands: STAGE7_FIELD_EXPR_OPERANDS_158 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial42", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_159, operands: STAGE7_FIELD_EXPR_OPERANDS_159 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial43", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_160, operands: STAGE7_FIELD_EXPR_OPERANDS_160 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial44", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_161, operands: STAGE7_FIELD_EXPR_OPERANDS_161 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial45", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_162, operands: STAGE7_FIELD_EXPR_OPERANDS_162 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial46", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_163, operands: STAGE7_FIELD_EXPR_OPERANDS_163 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial47", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_164, operands: STAGE7_FIELD_EXPR_OPERANDS_164 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial48", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_165, operands: STAGE7_FIELD_EXPR_OPERANDS_165 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial49", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_166, operands: STAGE7_FIELD_EXPR_OPERANDS_166 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial50", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_167, operands: STAGE7_FIELD_EXPR_OPERANDS_167 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial51", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_168, operands: STAGE7_FIELD_EXPR_OPERANDS_168 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial52", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_169, operands: STAGE7_FIELD_EXPR_OPERANDS_169 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial53", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_170, operands: STAGE7_FIELD_EXPR_OPERANDS_170 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial54", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_171, operands: STAGE7_FIELD_EXPR_OPERANDS_171 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial55", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_172, operands: STAGE7_FIELD_EXPR_OPERANDS_172 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial56", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_173, operands: STAGE7_FIELD_EXPR_OPERANDS_173 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial57", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_174, operands: STAGE7_FIELD_EXPR_OPERANDS_174 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial58", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_175, operands: STAGE7_FIELD_EXPR_OPERANDS_175 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial59", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_176, operands: STAGE7_FIELD_EXPR_OPERANDS_176 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial60", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_177, operands: STAGE7_FIELD_EXPR_OPERANDS_177 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial61", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_178, operands: STAGE7_FIELD_EXPR_OPERANDS_178 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial62", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_179, operands: STAGE7_FIELD_EXPR_OPERANDS_179 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial63", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_180, operands: STAGE7_FIELD_EXPR_OPERANDS_180 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial64", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_181, operands: STAGE7_FIELD_EXPR_OPERANDS_181 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial65", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_182, operands: STAGE7_FIELD_EXPR_OPERANDS_182 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial66", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_183, operands: STAGE7_FIELD_EXPR_OPERANDS_183 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial67", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_184, operands: STAGE7_FIELD_EXPR_OPERANDS_184 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial68", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_185, operands: STAGE7_FIELD_EXPR_OPERANDS_185 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial69", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_186, operands: STAGE7_FIELD_EXPR_OPERANDS_186 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial70", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_187, operands: STAGE7_FIELD_EXPR_OPERANDS_187 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial71", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_188, operands: STAGE7_FIELD_EXPR_OPERANDS_188 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial72", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_189, operands: STAGE7_FIELD_EXPR_OPERANDS_189 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial73", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_190, operands: STAGE7_FIELD_EXPR_OPERANDS_190 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial74", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_191, operands: STAGE7_FIELD_EXPR_OPERANDS_191 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial75", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_192, operands: STAGE7_FIELD_EXPR_OPERANDS_192 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial76", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_193, operands: STAGE7_FIELD_EXPR_OPERANDS_193 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial77", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_194, operands: STAGE7_FIELD_EXPR_OPERANDS_194 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial78", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_195, operands: STAGE7_FIELD_EXPR_OPERANDS_195 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial79", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_196, operands: STAGE7_FIELD_EXPR_OPERANDS_196 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial80", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_197, operands: STAGE7_FIELD_EXPR_OPERANDS_197 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial81", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_198, operands: STAGE7_FIELD_EXPR_OPERANDS_198 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial82", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_199, operands: STAGE7_FIELD_EXPR_OPERANDS_199 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial83", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_200, operands: STAGE7_FIELD_EXPR_OPERANDS_200 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial84", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_201, operands: STAGE7_FIELD_EXPR_OPERANDS_201 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial85", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_202, operands: STAGE7_FIELD_EXPR_OPERANDS_202 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial86", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_203, operands: STAGE7_FIELD_EXPR_OPERANDS_203 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial87", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_204, operands: STAGE7_FIELD_EXPR_OPERANDS_204 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial88", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_205, operands: STAGE7_FIELD_EXPR_OPERANDS_205 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial89", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_206, operands: STAGE7_FIELD_EXPR_OPERANDS_206 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial90", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_207, operands: STAGE7_FIELD_EXPR_OPERANDS_207 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial91", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_208, operands: STAGE7_FIELD_EXPR_OPERANDS_208 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial92", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_209, operands: STAGE7_FIELD_EXPR_OPERANDS_209 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial93", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_210, operands: STAGE7_FIELD_EXPR_OPERANDS_210 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial94", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_211, operands: STAGE7_FIELD_EXPR_OPERANDS_211 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial95", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_212, operands: STAGE7_FIELD_EXPR_OPERANDS_212 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial96", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_213, operands: STAGE7_FIELD_EXPR_OPERANDS_213 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial97", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_214, operands: STAGE7_FIELD_EXPR_OPERANDS_214 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial98", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_215, operands: STAGE7_FIELD_EXPR_OPERANDS_215 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial99", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_216, operands: STAGE7_FIELD_EXPR_OPERANDS_216 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial100", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_217, operands: STAGE7_FIELD_EXPR_OPERANDS_217 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial101", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_218, operands: STAGE7_FIELD_EXPR_OPERANDS_218 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial102", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_219, operands: STAGE7_FIELD_EXPR_OPERANDS_219 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial103", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_220, operands: STAGE7_FIELD_EXPR_OPERANDS_220 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial104", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_221, operands: STAGE7_FIELD_EXPR_OPERANDS_221 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial105", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_222, operands: STAGE7_FIELD_EXPR_OPERANDS_222 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial106", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_223, operands: STAGE7_FIELD_EXPR_OPERANDS_223 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial107", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_224, operands: STAGE7_FIELD_EXPR_OPERANDS_224 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial108", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_225, operands: STAGE7_FIELD_EXPR_OPERANDS_225 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial109", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_226, operands: STAGE7_FIELD_EXPR_OPERANDS_226 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial110", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_227, operands: STAGE7_FIELD_EXPR_OPERANDS_227 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial111", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_228, operands: STAGE7_FIELD_EXPR_OPERANDS_228 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial112", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_229, operands: STAGE7_FIELD_EXPR_OPERANDS_229 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial113", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_230, operands: STAGE7_FIELD_EXPR_OPERANDS_230 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial114", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_231, operands: STAGE7_FIELD_EXPR_OPERANDS_231 }, + Stage7FieldExprPlan { symbol: "stage7.hamming_weight_claim_reduction.claim_expr.partial115", kind: "op", formula: "field.add", operand_names: STAGE7_FIELD_EXPR_OPERANDS_232, operands: STAGE7_FIELD_EXPR_OPERANDS_232 }, +]; +pub const STAGE7_KERNELS: &[Stage7KernelPlan] = &[ + Stage7KernelPlan { symbol: "jolt.cpu.stage7.hamming_weight_claim_reduction", relation: "jolt.stage7.hamming_weight_claim_reduction", kind: "sumcheck", backend: "cpu", abi: "jolt_stage7_hamming_weight_claim_reduction" }, + Stage7KernelPlan { symbol: "jolt.cpu.stage7.batched", relation: "jolt.stage7.batched", kind: "sumcheck", backend: "cpu", abi: "jolt_stage7_batched" }, +]; + +pub const STAGE7_SUMCHECK_CLAIM_0_INPUT_OPENINGS: &[&str] = &[ + "stage7.input.stage6.hamming_booleanity.HammingWeight", + "stage7.input.stage6.booleanity.InstructionRa_0", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", + "stage7.input.stage6.booleanity.InstructionRa_1", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_1", + "stage7.input.stage6.booleanity.InstructionRa_2", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_2", + "stage7.input.stage6.booleanity.InstructionRa_3", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_3", + "stage7.input.stage6.booleanity.InstructionRa_4", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_4", + "stage7.input.stage6.booleanity.InstructionRa_5", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_5", + "stage7.input.stage6.booleanity.InstructionRa_6", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_6", + "stage7.input.stage6.booleanity.InstructionRa_7", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_7", + "stage7.input.stage6.booleanity.InstructionRa_8", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_8", + "stage7.input.stage6.booleanity.InstructionRa_9", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_9", + "stage7.input.stage6.booleanity.InstructionRa_10", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_10", + "stage7.input.stage6.booleanity.InstructionRa_11", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_11", + "stage7.input.stage6.booleanity.InstructionRa_12", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_12", + "stage7.input.stage6.booleanity.InstructionRa_13", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_13", + "stage7.input.stage6.booleanity.InstructionRa_14", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_14", + "stage7.input.stage6.booleanity.InstructionRa_15", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_15", + "stage7.input.stage6.booleanity.InstructionRa_16", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_16", + "stage7.input.stage6.booleanity.InstructionRa_17", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_17", + "stage7.input.stage6.booleanity.InstructionRa_18", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_18", + "stage7.input.stage6.booleanity.InstructionRa_19", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_19", + "stage7.input.stage6.booleanity.InstructionRa_20", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_20", + "stage7.input.stage6.booleanity.InstructionRa_21", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_21", + "stage7.input.stage6.booleanity.InstructionRa_22", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_22", + "stage7.input.stage6.booleanity.InstructionRa_23", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_23", + "stage7.input.stage6.booleanity.InstructionRa_24", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_24", + "stage7.input.stage6.booleanity.InstructionRa_25", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_25", + "stage7.input.stage6.booleanity.InstructionRa_26", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_26", + "stage7.input.stage6.booleanity.InstructionRa_27", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_27", + "stage7.input.stage6.booleanity.InstructionRa_28", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_28", + "stage7.input.stage6.booleanity.InstructionRa_29", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_29", + "stage7.input.stage6.booleanity.InstructionRa_30", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_30", + "stage7.input.stage6.booleanity.InstructionRa_31", + "stage7.input.stage6.instruction_ra_virtual.InstructionRa_31", + "stage7.input.stage6.booleanity.BytecodeRa_0", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_0", + "stage7.input.stage6.booleanity.BytecodeRa_1", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_1", + "stage7.input.stage6.booleanity.BytecodeRa_2", + "stage7.input.stage6.bytecode_read_raf.BytecodeRa_2", + "stage7.input.stage6.booleanity.RamRa_0", + "stage7.input.stage6.ram_ra_virtual.RamRa_0", + "stage7.input.stage6.booleanity.RamRa_1", + "stage7.input.stage6.ram_ra_virtual.RamRa_1", + "stage7.input.stage6.booleanity.RamRa_2", + "stage7.input.stage6.ram_ra_virtual.RamRa_2", + "stage7.input.stage6.booleanity.RamRa_3", + "stage7.input.stage6.ram_ra_virtual.RamRa_3", +]; + +pub const STAGE7_SUMCHECK_CLAIMS: &[Stage7SumcheckClaimPlan] = &[ + Stage7SumcheckClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.input", stage: "stage7", domain: "jolt.stage7_hamming_weight_claim_reduction_domain", num_rounds: 4, degree: 2, claim: "stage7.hamming_weight_claim_reduction.weighted_stage6_claims", kernel: Some("jolt.cpu.stage7.hamming_weight_claim_reduction"), relation: None, claim_value: "stage7.hamming_weight_claim_reduction.claim_expr.partial115", input_openings: STAGE7_SUMCHECK_CLAIM_0_INPUT_OPENINGS }, +]; +pub const STAGE7_SUMCHECK_BATCH_0_ORDERED_CLAIMS: &[&str] = &["stage7.hamming_weight_claim_reduction.input"]; + +pub const STAGE7_SUMCHECK_BATCH_0_CLAIM_OPERANDS: &[&str] = &["stage7.hamming_weight_claim_reduction.input"]; + +pub const STAGE7_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 4, +]; + +pub const STAGE7_SUMCHECK_BATCHES: &[Stage7SumcheckBatchPlan] = &[ + Stage7SumcheckBatchPlan { symbol: "stage7.batch", stage: "stage7", proof_slot: "stage7.sumcheck", policy: "jolt_core_stage7_aligned", count: 1, ordered_claims: STAGE7_SUMCHECK_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE7_SUMCHECK_BATCH_0_CLAIM_OPERANDS, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE7_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE7_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 4, +]; + +pub const STAGE7_SUMCHECK_DRIVERS: &[Stage7SumcheckDriverPlan] = &[ + Stage7SumcheckDriverPlan { symbol: "stage7.sumcheck", stage: "stage7", proof_slot: "stage7.sumcheck", kernel: Some("jolt.cpu.stage7.batched"), relation: None, batch: "stage7.batch", policy: "jolt_core_stage7_aligned", round_schedule: STAGE7_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 4, degree: 2 }, +]; +pub const STAGE7_SUMCHECK_INSTANCE_RESULTS: &[Stage7SumcheckInstanceResultPlan] = &[ + Stage7SumcheckInstanceResultPlan { symbol: "stage7.hamming_weight_claim_reduction.instance", source: "stage7.sumcheck", claim: "stage7.hamming_weight_claim_reduction.input", relation: "jolt.stage7.hamming_weight_claim_reduction", index: 0, point_arity: 4, num_rounds: 4, round_offset: 0, point_order: "reverse", degree: 2 }, +]; + +macro_rules! stage7_sumcheck_eval { + ($symbol:literal, $source:literal, $name:literal, $index:literal, $oracle:literal) => { + Stage7SumcheckEvalPlan { symbol: $symbol, source: $source, name: $name, index: $index, oracle: $oracle } + }; +} + +#[rustfmt::skip] +pub const STAGE7_SUMCHECK_EVALS: &[Stage7SumcheckEvalPlan] = &[ + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", 0, "InstructionRa_0"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", 1, "InstructionRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", 2, "InstructionRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", 3, "InstructionRa_3"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", 4, "InstructionRa_4"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", 5, "InstructionRa_5"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", 6, "InstructionRa_6"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", 7, "InstructionRa_7"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", 8, "InstructionRa_8"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", 9, "InstructionRa_9"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", 10, "InstructionRa_10"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", 11, "InstructionRa_11"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", 12, "InstructionRa_12"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", 13, "InstructionRa_13"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", 14, "InstructionRa_14"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", 15, "InstructionRa_15"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", 16, "InstructionRa_16"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", 17, "InstructionRa_17"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", 18, "InstructionRa_18"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", 19, "InstructionRa_19"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", 20, "InstructionRa_20"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", 21, "InstructionRa_21"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", 22, "InstructionRa_22"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", 23, "InstructionRa_23"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", 24, "InstructionRa_24"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", 25, "InstructionRa_25"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", 26, "InstructionRa_26"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", 27, "InstructionRa_27"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", 28, "InstructionRa_28"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", 29, "InstructionRa_29"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", 30, "InstructionRa_30"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", 31, "InstructionRa_31"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", 32, "BytecodeRa_0"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", 33, "BytecodeRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", 34, "BytecodeRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_0", 35, "RamRa_0"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_1", 36, "RamRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_2", 37, "RamRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_3", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_3", 38, "RamRa_3"), +]; + +pub const STAGE7_POINT_ZEROS: &[Stage7PointZeroPlan] = &[ + +]; + +pub const STAGE7_POINT_SLICES: &[Stage7PointSlicePlan] = &[ + Stage7PointSlicePlan { symbol: "stage7.hamming_weight_claim_reduction.point.cycle", source: "stage7.input.stage6.booleanity.InstructionRa_0", offset: 4, length: 16, input: "stage7.input.stage6.booleanity.InstructionRa_0" }, +]; + +pub const STAGE7_POINT_CONCAT_0_INPUTS: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.instance", + "stage7.hamming_weight_claim_reduction.point.cycle", +]; + +pub const STAGE7_POINT_CONCATS: &[Stage7PointConcatPlan] = &[ + Stage7PointConcatPlan { symbol: "stage7.hamming_weight_claim_reduction.point", layout: "address_chunk_then_cycle", arity: 20, inputs: STAGE7_POINT_CONCAT_0_INPUTS }, +]; +pub const STAGE7_OPENING_CLAIMS: &[Stage7OpeningClaimPlan] = &[ + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_3" }, +]; + +pub const STAGE7_OPENING_EQUALITIES: &[Stage7OpeningClaimEqualityPlan] = &[ + +]; + +pub const STAGE7_OPENING_BATCH_0_ORDERED_CLAIMS: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_1", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_2", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_3", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_4", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_5", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_6", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_7", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_8", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_9", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_10", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_11", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_12", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_13", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_14", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_15", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_16", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_17", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_18", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_19", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_20", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_21", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_22", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_23", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_24", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_25", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_26", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_27", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_28", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_29", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_30", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_31", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2", + "stage7.hamming_weight_claim_reduction.opening.RamRa_0", + "stage7.hamming_weight_claim_reduction.opening.RamRa_1", + "stage7.hamming_weight_claim_reduction.opening.RamRa_2", + "stage7.hamming_weight_claim_reduction.opening.RamRa_3", +]; + +pub const STAGE7_OPENING_BATCH_0_CLAIM_OPERANDS: &[&str] = &[ + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_1", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_2", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_3", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_4", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_5", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_6", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_7", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_8", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_9", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_10", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_11", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_12", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_13", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_14", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_15", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_16", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_17", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_18", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_19", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_20", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_21", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_22", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_23", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_24", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_25", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_26", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_27", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_28", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_29", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_30", + "stage7.hamming_weight_claim_reduction.opening.InstructionRa_31", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1", + "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2", + "stage7.hamming_weight_claim_reduction.opening.RamRa_0", + "stage7.hamming_weight_claim_reduction.opening.RamRa_1", + "stage7.hamming_weight_claim_reduction.opening.RamRa_2", + "stage7.hamming_weight_claim_reduction.opening.RamRa_3", +]; + +pub const STAGE7_OPENING_BATCHES: &[Stage7OpeningBatchPlan] = &[ + Stage7OpeningBatchPlan { symbol: "stage7.openings", stage: "stage7", proof_slot: "stage7.openings", policy: "jolt_stage7_output_order", count: 39, ordered_claims: STAGE7_OPENING_BATCH_0_ORDERED_CLAIMS, claim_operands: STAGE7_OPENING_BATCH_0_CLAIM_OPERANDS }, +]; +pub const STAGE7_PROGRAM: Stage7CpuProgramPlan = Stage7CpuProgramPlan { + role: "prover", + params: STAGE7_PARAMS, + steps: STAGE7_PROGRAM_STEPS, + transcript_squeezes: STAGE7_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE7_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE7_OPENING_INPUTS, + field_constants: STAGE7_FIELD_CONSTANTS, + field_exprs: STAGE7_FIELD_EXPRS, + kernels: STAGE7_KERNELS, + claims: STAGE7_SUMCHECK_CLAIMS, + batches: STAGE7_SUMCHECK_BATCHES, + drivers: STAGE7_SUMCHECK_DRIVERS, + instance_results: STAGE7_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE7_SUMCHECK_EVALS, + point_zeros: STAGE7_POINT_ZEROS, + point_slices: STAGE7_POINT_SLICES, + point_concats: STAGE7_POINT_CONCATS, + opening_claims: STAGE7_OPENING_CLAIMS, + opening_equalities: STAGE7_OPENING_EQUALITIES, + opening_batches: STAGE7_OPENING_BATCHES, +}; + +pub fn execute_stage7_prover( + executor: &mut E, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + E: Stage7KernelExecutor, + T: Transcript, +{ + execute_stage7_prover_with_program(&STAGE7_PROGRAM, executor, transcript) +} + +pub fn execute_stage7_prover_with_program( + program: &'static Stage7CpuProgramPlan, + executor: &mut E, + transcript: &mut T, +) -> Result, Stage7KernelError> +where + E: Stage7KernelExecutor, + T: Transcript, +{ + execute_stage7_program(program, Stage7ExecutionMode::Prover, executor, transcript) +} diff --git a/crates/jolt-prover/src/stages/stage8.rs b/crates/jolt-prover/src/stages/stage8.rs new file mode 100644 index 0000000000..632dbe3925 --- /dev/null +++ b/crates/jolt-prover/src/stages/stage8.rs @@ -0,0 +1,173 @@ +#![allow(clippy::too_many_lines)] + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub family: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub point_source: &'static str, + pub eval_source: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningBatchPlan { + pub symbol: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8PcsProofPlan { + pub symbol: &'static str, + pub mode: &'static str, + pub pcs: &'static str, + pub proof_slot: &'static str, + pub transcript_label: &'static str, + pub batch: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8EvaluationProgramPlan { + pub role: &'static str, + pub function: &'static str, + pub params: Stage8Params, + pub evaluation_point_source: Stage8OpeningInputPlan, + pub opening_inputs: &'static [Stage8OpeningInputPlan], + pub opening_claims: &'static [Stage8OpeningClaimPlan], + pub opening_batch: Stage8OpeningBatchPlan, + pub pcs_proof: Stage8PcsProofPlan, +} + +pub const STAGE8_PARAMS: Stage8Params = Stage8Params { field: "bn254_fr", pcs: "dory", transcript: "blake2b_transcript" }; + +pub const STAGE8_EVALUATION_POINT_SOURCE: Stage8OpeningInputPlan = Stage8OpeningInputPlan { symbol: "stage8.evaluation.point_source", source_stage: "stage7", source_claim: "stage7.input.stage6.booleanity.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }; + +pub const STAGE8_OPENING_INPUTS: &[Stage8OpeningInputPlan] = &[ + Stage8OpeningInputPlan { symbol: "stage8.evaluation.point_source", source_stage: "stage7", source_claim: "stage7.input.stage6.booleanity.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage6.RamInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RamInc", oracle: "RamInc", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage6.RdInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RdInc", oracle: "RdInc", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_4", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_5", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_6", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_7", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_8", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_9", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_10", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_11", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_12", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_13", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_14", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_15", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_16", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_17", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_18", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_19", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_20", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_21", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_22", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_23", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_24", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_25", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_26", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_27", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_28", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_29", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_30", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_31", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, +]; + +pub const STAGE8_OPENING_CLAIMS: &[Stage8OpeningClaimPlan] = &[ + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamInc", oracle: "RamInc", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage6.RamInc", eval_source: "stage8.input.stage6.RamInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RamInc" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RdInc", oracle: "RdInc", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage6.RdInc", eval_source: "stage8.input.stage6.RdInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RdInc" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_0", oracle: "InstructionRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_0", eval_source: "stage8.input.stage7.InstructionRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_1", oracle: "InstructionRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_1", eval_source: "stage8.input.stage7.InstructionRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_2", oracle: "InstructionRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_2", eval_source: "stage8.input.stage7.InstructionRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_3", oracle: "InstructionRa_3", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_3", eval_source: "stage8.input.stage7.InstructionRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_4", oracle: "InstructionRa_4", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_4", eval_source: "stage8.input.stage7.InstructionRa_4", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_5", oracle: "InstructionRa_5", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_5", eval_source: "stage8.input.stage7.InstructionRa_5", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_6", oracle: "InstructionRa_6", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_6", eval_source: "stage8.input.stage7.InstructionRa_6", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_7", oracle: "InstructionRa_7", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_7", eval_source: "stage8.input.stage7.InstructionRa_7", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_8", oracle: "InstructionRa_8", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_8", eval_source: "stage8.input.stage7.InstructionRa_8", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_9", oracle: "InstructionRa_9", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_9", eval_source: "stage8.input.stage7.InstructionRa_9", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_10", oracle: "InstructionRa_10", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_10", eval_source: "stage8.input.stage7.InstructionRa_10", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_11", oracle: "InstructionRa_11", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_11", eval_source: "stage8.input.stage7.InstructionRa_11", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_12", oracle: "InstructionRa_12", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_12", eval_source: "stage8.input.stage7.InstructionRa_12", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_13", oracle: "InstructionRa_13", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_13", eval_source: "stage8.input.stage7.InstructionRa_13", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_14", oracle: "InstructionRa_14", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_14", eval_source: "stage8.input.stage7.InstructionRa_14", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_15", oracle: "InstructionRa_15", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_15", eval_source: "stage8.input.stage7.InstructionRa_15", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_16", oracle: "InstructionRa_16", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_16", eval_source: "stage8.input.stage7.InstructionRa_16", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_17", oracle: "InstructionRa_17", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_17", eval_source: "stage8.input.stage7.InstructionRa_17", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_18", oracle: "InstructionRa_18", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_18", eval_source: "stage8.input.stage7.InstructionRa_18", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_19", oracle: "InstructionRa_19", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_19", eval_source: "stage8.input.stage7.InstructionRa_19", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_20", oracle: "InstructionRa_20", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_20", eval_source: "stage8.input.stage7.InstructionRa_20", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_21", oracle: "InstructionRa_21", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_21", eval_source: "stage8.input.stage7.InstructionRa_21", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_22", oracle: "InstructionRa_22", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_22", eval_source: "stage8.input.stage7.InstructionRa_22", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_23", oracle: "InstructionRa_23", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_23", eval_source: "stage8.input.stage7.InstructionRa_23", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_24", oracle: "InstructionRa_24", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_24", eval_source: "stage8.input.stage7.InstructionRa_24", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_25", oracle: "InstructionRa_25", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_25", eval_source: "stage8.input.stage7.InstructionRa_25", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_26", oracle: "InstructionRa_26", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_26", eval_source: "stage8.input.stage7.InstructionRa_26", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_27", oracle: "InstructionRa_27", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_27", eval_source: "stage8.input.stage7.InstructionRa_27", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_28", oracle: "InstructionRa_28", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_28", eval_source: "stage8.input.stage7.InstructionRa_28", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_29", oracle: "InstructionRa_29", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_29", eval_source: "stage8.input.stage7.InstructionRa_29", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_30", oracle: "InstructionRa_30", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_30", eval_source: "stage8.input.stage7.InstructionRa_30", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_31", oracle: "InstructionRa_31", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_31", eval_source: "stage8.input.stage7.InstructionRa_31", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_0", oracle: "BytecodeRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_0", eval_source: "stage8.input.stage7.BytecodeRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_1", oracle: "BytecodeRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_1", eval_source: "stage8.input.stage7.BytecodeRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_2", oracle: "BytecodeRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_2", eval_source: "stage8.input.stage7.BytecodeRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_0", oracle: "RamRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_0", eval_source: "stage8.input.stage7.RamRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_1", oracle: "RamRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_1", eval_source: "stage8.input.stage7.RamRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_2", oracle: "RamRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_2", eval_source: "stage8.input.stage7.RamRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_3", oracle: "RamRa_3", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_3", eval_source: "stage8.input.stage7.RamRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_3" }, +]; + +pub const STAGE8_OPENING_BATCH_ORDERED_CLAIMS: &[&str] = &["stage8.evaluation.opening.RamInc", "stage8.evaluation.opening.RdInc", "stage8.evaluation.opening.InstructionRa_0", "stage8.evaluation.opening.InstructionRa_1", "stage8.evaluation.opening.InstructionRa_2", "stage8.evaluation.opening.InstructionRa_3", "stage8.evaluation.opening.InstructionRa_4", "stage8.evaluation.opening.InstructionRa_5", "stage8.evaluation.opening.InstructionRa_6", "stage8.evaluation.opening.InstructionRa_7", "stage8.evaluation.opening.InstructionRa_8", "stage8.evaluation.opening.InstructionRa_9", "stage8.evaluation.opening.InstructionRa_10", "stage8.evaluation.opening.InstructionRa_11", "stage8.evaluation.opening.InstructionRa_12", "stage8.evaluation.opening.InstructionRa_13", "stage8.evaluation.opening.InstructionRa_14", "stage8.evaluation.opening.InstructionRa_15", "stage8.evaluation.opening.InstructionRa_16", "stage8.evaluation.opening.InstructionRa_17", "stage8.evaluation.opening.InstructionRa_18", "stage8.evaluation.opening.InstructionRa_19", "stage8.evaluation.opening.InstructionRa_20", "stage8.evaluation.opening.InstructionRa_21", "stage8.evaluation.opening.InstructionRa_22", "stage8.evaluation.opening.InstructionRa_23", "stage8.evaluation.opening.InstructionRa_24", "stage8.evaluation.opening.InstructionRa_25", "stage8.evaluation.opening.InstructionRa_26", "stage8.evaluation.opening.InstructionRa_27", "stage8.evaluation.opening.InstructionRa_28", "stage8.evaluation.opening.InstructionRa_29", "stage8.evaluation.opening.InstructionRa_30", "stage8.evaluation.opening.InstructionRa_31", "stage8.evaluation.opening.BytecodeRa_0", "stage8.evaluation.opening.BytecodeRa_1", "stage8.evaluation.opening.BytecodeRa_2", "stage8.evaluation.opening.RamRa_0", "stage8.evaluation.opening.RamRa_1", "stage8.evaluation.opening.RamRa_2", "stage8.evaluation.opening.RamRa_3"]; + +pub const STAGE8_OPENING_BATCH: Stage8OpeningBatchPlan = Stage8OpeningBatchPlan { symbol: "stage8.evaluation.openings", proof_slot: "stage8.evaluation", policy: "jolt_stage8_joint_rlc", count: 41, ordered_claims: STAGE8_OPENING_BATCH_ORDERED_CLAIMS }; + +pub const STAGE8_PCS_PROOF: Stage8PcsProofPlan = Stage8PcsProofPlan { symbol: "stage8.evaluation.proof", mode: "open", pcs: "dory", proof_slot: "stage8.evaluation", transcript_label: "rlc_claims", batch: "stage8.evaluation.openings" }; + +pub const STAGE8_PROGRAM: Stage8EvaluationProgramPlan = Stage8EvaluationProgramPlan { + role: "prover", + function: "jolt.stage8", + params: STAGE8_PARAMS, + evaluation_point_source: STAGE8_EVALUATION_POINT_SOURCE, + opening_inputs: STAGE8_OPENING_INPUTS, + opening_claims: STAGE8_OPENING_CLAIMS, + opening_batch: STAGE8_OPENING_BATCH, + pcs_proof: STAGE8_PCS_PROOF, +}; diff --git a/crates/jolt-r1cs/src/constraint.rs b/crates/jolt-r1cs/src/constraint.rs index 7222b4c352..296261f035 100644 --- a/crates/jolt-r1cs/src/constraint.rs +++ b/crates/jolt-r1cs/src/constraint.rs @@ -149,7 +149,7 @@ fn dot(row: &[(usize, F)], witness: &[F]) -> F { #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; #[test] fn satisfied_constraint() { diff --git a/crates/jolt-r1cs/src/constraints/rv64.rs b/crates/jolt-r1cs/src/constraints/rv64.rs index a7d4b63b55..6643b4973a 100644 --- a/crates/jolt-r1cs/src/constraints/rv64.rs +++ b/crates/jolt-r1cs/src/constraints/rv64.rs @@ -388,7 +388,7 @@ pub fn rv64_constraints() -> crate::ConstraintMatrices { #[expect(clippy::expect_used, reason = "tests may unwind via panic")] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; use num_traits::Zero; /// A no-op cycle: const=1, all else zero. All eq-conditional guards diff --git a/crates/jolt-r1cs/src/key.rs b/crates/jolt-r1cs/src/key.rs index 767199a9ef..71731d572e 100644 --- a/crates/jolt-r1cs/src/key.rs +++ b/crates/jolt-r1cs/src/key.rs @@ -280,7 +280,7 @@ impl R1csKey { mod tests { use super::*; use crate::constraint::ConstraintMatrices; - use jolt_field::{Fr, FromPrimitiveInt, RandomSampling}; + use jolt_field::{Fr, RandomSampling}; use num_traits::{One, Zero}; /// x * x = y, y * x = z — 2 constraints, 4 vars [1, x, y, z] diff --git a/crates/jolt-r1cs/src/provider.rs b/crates/jolt-r1cs/src/provider.rs index 79f52c9509..6e0f226a5d 100644 --- a/crates/jolt-r1cs/src/provider.rs +++ b/crates/jolt-r1cs/src/provider.rs @@ -147,7 +147,7 @@ impl<'a, F: Field> R1csSource<'a, F> { mod tests { use super::*; use crate::constraint::ConstraintMatrices; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; use num_traits::{One, Zero}; #[test] diff --git a/crates/jolt-sumcheck/src/tests.rs b/crates/jolt-sumcheck/src/tests.rs index b3cce06f73..a64652ea49 100644 --- a/crates/jolt-sumcheck/src/tests.rs +++ b/crates/jolt-sumcheck/src/tests.rs @@ -6,7 +6,7 @@ reason = "tests may panic on assertion failures" )] -use jolt_field::{Fr, FromPrimitiveInt}; +use jolt_field::Fr; use jolt_poly::UnivariatePoly; use jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript}; diff --git a/crates/jolt-sumcheck/tests/roundtrip.rs b/crates/jolt-sumcheck/tests/roundtrip.rs index 06199c9b4b..bd6ef44bde 100644 --- a/crates/jolt-sumcheck/tests/roundtrip.rs +++ b/crates/jolt-sumcheck/tests/roundtrip.rs @@ -6,7 +6,7 @@ #![expect(clippy::unwrap_used, reason = "tests may panic on assertion failures")] -use jolt_field::{Fr, FromPrimitiveInt, MulPow2}; +use jolt_field::{Fr, MulPow2}; use jolt_poly::{Polynomial, UnivariatePoly}; use jolt_sumcheck::claim::{EvaluationClaim, SumcheckClaim}; use jolt_sumcheck::proof::SumcheckProof; diff --git a/crates/jolt-sumcheck/tests/soundness.rs b/crates/jolt-sumcheck/tests/soundness.rs index b4a78fb8ce..d6d4def81e 100644 --- a/crates/jolt-sumcheck/tests/soundness.rs +++ b/crates/jolt-sumcheck/tests/soundness.rs @@ -6,7 +6,7 @@ #![expect(clippy::unwrap_used, reason = "tests may panic on assertion failures")] -use jolt_field::{Fr, FromPrimitiveInt}; +use jolt_field::Fr; use jolt_poly::{Polynomial, UnivariatePoly}; use jolt_sumcheck::claim::{EvaluationClaim, SumcheckClaim}; use jolt_sumcheck::error::SumcheckError; diff --git a/crates/jolt-transcript/tests/blake2b_tests.rs b/crates/jolt-transcript/tests/blake2b_tests.rs index f2af8920a0..6498d582a2 100644 --- a/crates/jolt-transcript/tests/blake2b_tests.rs +++ b/crates/jolt-transcript/tests/blake2b_tests.rs @@ -3,7 +3,7 @@ mod common; -use jolt_field::{Fr, FromPrimitiveInt}; +use jolt_field::Fr; use jolt_transcript::Blake2bTranscript; use num_traits::Zero; diff --git a/crates/jolt-verifier/Cargo.toml b/crates/jolt-verifier/Cargo.toml new file mode 100644 index 0000000000..3b6ecdafd5 --- /dev/null +++ b/crates/jolt-verifier/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "jolt-verifier" +version = "0.0.0" +edition = "2021" +license = "MIT OR Apache-2.0" +description = "Bolt-generated Jolt verifier role crate" +repository = "https://github.com/a16z/jolt" + +[lints] +workspace = true + +[dependencies] +jolt-dory.workspace = true +jolt-field.workspace = true +jolt-lookup-tables.workspace = true +jolt-openings.workspace = true +jolt-poly.workspace = true +jolt-sumcheck.workspace = true +jolt-transcript.workspace = true +serde.workspace = true +tracing.workspace = true diff --git a/crates/jolt-verifier/src/lib.rs b/crates/jolt-verifier/src/lib.rs new file mode 100644 index 0000000000..c9dfdffc26 --- /dev/null +++ b/crates/jolt-verifier/src/lib.rs @@ -0,0 +1,87 @@ +pub mod stages; +#[rustfmt::skip] +pub mod verifier; + +pub use stages::{ + stage1_outer::{verify_stage1_outer_with_program, Stage1VerifierProgramPlan}, + stage2::{verify_stage2_with_program, Stage2VerifierProgramPlan}, + stage3::{verify_stage3_with_program, Stage3VerifierProgramPlan}, + stage4::{verify_stage4_with_program, Stage4VerifierProgramPlan}, + stage5::{verify_stage5_with_program, Stage5VerifierProgramPlan}, + stage6::{verify_stage6_with_program, Stage6VerifierProgramPlan}, + stage7::{verify_stage7_with_program, Stage7VerifierProgramPlan}, +}; + +pub use verifier::{ + default_verifier_programs, verify_jolt, verify_jolt_evaluation_proof, verify_jolt_prefix, + verify_jolt_prefix_with_programs, verify_jolt_through_stage5, + verify_jolt_through_stage5_with_programs, verify_jolt_through_stage6, + verify_jolt_through_stage6_with_programs, verify_jolt_through_stage7, + verify_jolt_through_stage7_with_programs, verify_jolt_with_programs, JoltEvaluationProof, + JoltEvaluationProofError, JoltNamedEval, JoltProof, JoltStage2RamAccess, JoltStage2RamData, + JoltStage2RamOutputLayout, JoltStage6BytecodeEntry, JoltStage6BytecodeReadRafData, + JoltStage6VerifierData, JoltStageChallengeVector, JoltStageExecutionArtifacts, + JoltStageOpeningInputValue, JoltStageProof, JoltSumcheckOutput, JoltVerificationArtifacts, + JoltVerifierInputs, JoltVerifierPrograms, JoltVerifierTarget, JoltVerifyError, +}; + +pub const TRANSCRIPT_LABEL: &[u8] = b"Jolt"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct GeneratedStage { + pub name: &'static str, + pub module: &'static str, + pub ordinal: usize, +} + +pub const GENERATED_STAGES: &[GeneratedStage] = &[ + GeneratedStage { + name: "commitment", + module: "commitment", + ordinal: 0, + }, + GeneratedStage { + name: "stage1_outer", + module: "stage1_outer", + ordinal: 1, + }, + GeneratedStage { + name: "stage2", + module: "stage2", + ordinal: 2, + }, + GeneratedStage { + name: "stage3", + module: "stage3", + ordinal: 3, + }, + GeneratedStage { + name: "stage4", + module: "stage4", + ordinal: 4, + }, + GeneratedStage { + name: "stage5", + module: "stage5", + ordinal: 5, + }, + GeneratedStage { + name: "stage6", + module: "stage6", + ordinal: 6, + }, + GeneratedStage { + name: "stage7", + module: "stage7", + ordinal: 7, + }, + GeneratedStage { + name: "stage8", + module: "stage8", + ordinal: 8, + }, +]; + +pub fn generated_stage_names() -> impl Iterator { + GENERATED_STAGES.iter().map(|stage| stage.name) +} diff --git a/crates/jolt-verifier/src/stages/commitment.rs b/crates/jolt-verifier/src/stages/commitment.rs new file mode 100644 index 0000000000..ea31591867 --- /dev/null +++ b/crates/jolt-verifier/src/stages/commitment.rs @@ -0,0 +1,343 @@ +#![allow(dead_code)] + +use jolt_dory::DoryCommitment; +use jolt_field::Fr; +use jolt_transcript::{AppendToTranscript, Blake2bTranscript, LabelWithCount, Transcript}; + +pub type DefaultCommitmentTranscript = Blake2bTranscript; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentParams { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OraclePlan { + pub oracle: &'static str, + pub domain: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentBatchPlan { + pub artifact: &'static str, + pub pcs: &'static str, + pub oracle_family: &'static str, + pub label: &'static str, + pub oracles: &'static [&'static str], + pub count: usize, + pub domain: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OptionalSkipPolicy { + MissingOrZero, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OptionalCommitmentPlan { + pub artifact: &'static str, + pub pcs: &'static str, + pub oracle: &'static str, + pub label: &'static str, + pub domain: &'static str, + pub num_vars: usize, + pub skip_policy: OptionalSkipPolicy, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TranscriptStep { + pub label: &'static str, + pub source: &'static str, + pub optional: bool, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentVerifierProgramPlan { + pub params: CommitmentParams, + pub oracle_plans: &'static [OraclePlan], + pub batch_plans: &'static [CommitmentBatchPlan], + pub optional_plans: &'static [OptionalCommitmentPlan], + pub transcript_steps: &'static [TranscriptStep], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CommitmentRecord { + pub artifact: &'static str, + pub oracle: &'static str, + pub label: &'static str, + pub num_vars: usize, +} + +#[derive(Clone, Debug, Default)] +pub struct CommitmentArtifacts { + pub commitments: Vec>, + pub records: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CommitmentPhaseError { + MissingProofCommitment { oracle: &'static str }, + MissingProofCommitmentSlot { artifact: &'static str, oracle: &'static str }, + MissingTranscriptSource { source: &'static str }, + PlanCountMismatch { artifact: &'static str, expected: usize, actual: usize }, + ProofCommitmentCountMismatch { expected: usize, actual: usize }, +} +pub const COMMITMENT_PARAMS: CommitmentParams = CommitmentParams { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const ORACLE_PLANS: &[OraclePlan] = &[ + OraclePlan { oracle: "RdInc", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "RamInc", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", num_vars: 20 }, + OraclePlan { oracle: "UntrustedAdvice", domain: "jolt.trace_domain", num_vars: 16 }, + OraclePlan { oracle: "TrustedAdvice", domain: "jolt.trace_domain", num_vars: 16 }, +]; +pub const COMMITMENT_BATCH_0_ORACLES: &[&str] = &[ + "RdInc", + "RamInc", + "InstructionRa_0", + "InstructionRa_1", + "InstructionRa_2", + "InstructionRa_3", + "InstructionRa_4", + "InstructionRa_5", + "InstructionRa_6", + "InstructionRa_7", + "InstructionRa_8", + "InstructionRa_9", + "InstructionRa_10", + "InstructionRa_11", + "InstructionRa_12", + "InstructionRa_13", + "InstructionRa_14", + "InstructionRa_15", + "InstructionRa_16", + "InstructionRa_17", + "InstructionRa_18", + "InstructionRa_19", + "InstructionRa_20", + "InstructionRa_21", + "InstructionRa_22", + "InstructionRa_23", + "InstructionRa_24", + "InstructionRa_25", + "InstructionRa_26", + "InstructionRa_27", + "InstructionRa_28", + "InstructionRa_29", + "InstructionRa_30", + "InstructionRa_31", + "RamRa_0", + "RamRa_1", + "RamRa_2", + "RamRa_3", + "BytecodeRa_0", + "BytecodeRa_1", + "BytecodeRa_2", +]; +pub const COMMITMENT_BATCH_PLANS: &[CommitmentBatchPlan] = &[ + CommitmentBatchPlan { artifact: "jolt.main_witness_commitments", pcs: "dory", oracle_family: "jolt.main_witness_polys", label: "commitment", oracles: COMMITMENT_BATCH_0_ORACLES, count: 41, domain: "jolt.main_witness_commit_domain", num_vars: 20 }, +]; +pub const OPTIONAL_COMMITMENT_PLANS: &[OptionalCommitmentPlan] = &[ + OptionalCommitmentPlan { artifact: "jolt.untrusted_advice_commitment", pcs: "dory", oracle: "UntrustedAdvice", label: "untrusted_advice", domain: "jolt.trace_domain", num_vars: 16, skip_policy: OptionalSkipPolicy::MissingOrZero }, + OptionalCommitmentPlan { artifact: "jolt.trusted_advice_commitment", pcs: "dory", oracle: "TrustedAdvice", label: "trusted_advice", domain: "jolt.trace_domain", num_vars: 16, skip_policy: OptionalSkipPolicy::MissingOrZero }, +]; +pub const TRANSCRIPT_PLAN: &[TranscriptStep] = &[ + TranscriptStep { label: "commitment", source: "jolt.main_witness_commitments", optional: false }, + TranscriptStep { label: "untrusted_advice", source: "jolt.untrusted_advice_commitment", optional: true }, + TranscriptStep { label: "trusted_advice", source: "jolt.trusted_advice_commitment", optional: true }, +]; +pub const COMMITMENT_PROGRAM: CommitmentVerifierProgramPlan = CommitmentVerifierProgramPlan { + params: COMMITMENT_PARAMS, + oracle_plans: ORACLE_PLANS, + batch_plans: COMMITMENT_BATCH_PLANS, + optional_plans: OPTIONAL_COMMITMENT_PLANS, + transcript_steps: TRANSCRIPT_PLAN, +}; + +pub fn verify_commitment_phase( + proof_commitments: &[Option], + transcript: &mut T, +) -> Result +where + T: Transcript, +{ + verify_commitment_phase_with_program(&COMMITMENT_PROGRAM, proof_commitments, transcript) +} + +pub fn verify_commitment_phase_with_program( + program: &'static CommitmentVerifierProgramPlan, + proof_commitments: &[Option], + transcript: &mut T, +) -> Result +where + T: Transcript, +{ + let mut artifacts = CommitmentArtifacts::default(); + let mut cursor = 0usize; + for plan in program.batch_plans { + receive_batch(program, proof_commitments, &mut cursor, &mut artifacts, plan)?; + } + for plan in program.optional_plans { + receive_optional(program, proof_commitments, &mut cursor, &mut artifacts, plan)?; + } + if cursor != proof_commitments.len() { + return Err(CommitmentPhaseError::ProofCommitmentCountMismatch { + expected: cursor, + actual: proof_commitments.len(), + }); + } + absorb_transcript(program, &artifacts, transcript)?; + Ok(artifacts) +} + +fn receive_batch( + program: &'static CommitmentVerifierProgramPlan, + proof_commitments: &[Option], + cursor: &mut usize, + artifacts: &mut CommitmentArtifacts, + plan: &CommitmentBatchPlan, +) -> Result<(), CommitmentPhaseError> { + if plan.count != plan.oracles.len() { + return Err(CommitmentPhaseError::PlanCountMismatch { + artifact: plan.artifact, + expected: plan.count, + actual: plan.oracles.len(), + }); + } + for &oracle in plan.oracles { + let commitment = proof_commitments + .get(*cursor) + .ok_or(CommitmentPhaseError::MissingProofCommitmentSlot { + artifact: plan.artifact, + oracle, + })? + .as_ref() + .ok_or(CommitmentPhaseError::MissingProofCommitment { oracle })? + .clone(); + *cursor += 1; + let oracle_num_vars = oracle_num_vars(program, oracle, plan.num_vars); + artifacts.records.push(CommitmentRecord { + artifact: plan.artifact, + oracle, + label: plan.label, + num_vars: oracle_num_vars, + }); + artifacts.commitments.push(Some(commitment)); + } + Ok(()) +} + +fn receive_optional( + program: &'static CommitmentVerifierProgramPlan, + proof_commitments: &[Option], + cursor: &mut usize, + artifacts: &mut CommitmentArtifacts, + plan: &OptionalCommitmentPlan, +) -> Result<(), CommitmentPhaseError> { + let commitment = proof_commitments + .get(*cursor) + .ok_or(CommitmentPhaseError::MissingProofCommitmentSlot { + artifact: plan.artifact, + oracle: plan.oracle, + })? + .clone(); + *cursor += 1; + artifacts.records.push(CommitmentRecord { + artifact: plan.artifact, + oracle: plan.oracle, + label: plan.label, + num_vars: oracle_num_vars(program, plan.oracle, plan.num_vars), + }); + artifacts.commitments.push(commitment); + Ok(()) +} + +pub fn commitment_verifier_program() -> &'static CommitmentVerifierProgramPlan { + &COMMITMENT_PROGRAM +} + +fn oracle_num_vars( + program: &'static CommitmentVerifierProgramPlan, + oracle: &'static str, + fallback: usize, +) -> usize { + program + .oracle_plans + .iter() + .find(|plan| plan.oracle == oracle) + .map_or(fallback, |plan| plan.num_vars) +} + +fn absorb_transcript( + program: &'static CommitmentVerifierProgramPlan, + artifacts: &CommitmentArtifacts, + transcript: &mut T, +) -> Result<(), CommitmentPhaseError> +where + T: Transcript, +{ + for step in program.transcript_steps { + let mut appended = false; + for (record, commitment) in artifacts.records.iter().zip(&artifacts.commitments) { + if record.artifact != step.source { + continue; + } + if let Some(commitment) = commitment { + transcript.append(&LabelWithCount(step.label.as_bytes(), commitment.serialized_len())); + commitment.append_to_transcript(transcript); + appended = true; + } + } + if !step.optional && !appended { + return Err(CommitmentPhaseError::MissingTranscriptSource { + source: step.source, + }); + } + } + Ok(()) +} diff --git a/crates/jolt-verifier/src/stages/common.rs b/crates/jolt-verifier/src/stages/common.rs new file mode 100644 index 0000000000..340d4f9d52 --- /dev/null +++ b/crates/jolt-verifier/src/stages/common.rs @@ -0,0 +1,1789 @@ +#![expect( + clippy::too_many_arguments, + reason = "generated verifier helpers mirror staged protocol ABIs" +)] + +use jolt_field::{Field, Fr, MulPow2, RingCore}; +use jolt_poly::EqPolynomial; +use jolt_sumcheck::{ + CompressedLabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckProof, SumcheckVerifier, +}; +use jolt_transcript::{Label, Transcript}; +use serde::Serialize; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StageParams { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct KernelPlan { + pub symbol: &'static str, + pub relation: &'static str, + pub kind: &'static str, + pub backend: &'static str, + pub abi: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TranscriptSqueezePlan { + pub symbol: &'static str, + pub label: &'static str, + pub kind: &'static str, + pub count: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TranscriptAbsorbBytesPlan { + pub symbol: &'static str, + pub label: &'static str, + pub payload: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ProgramStepPlan { + pub kind: &'static str, + pub symbol: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FieldConstantPlan { + pub symbol: &'static str, + pub field: &'static str, + pub value: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FieldExprPlan { + pub symbol: &'static str, + pub kind: &'static str, + pub formula: &'static str, + pub operands: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SumcheckClaimPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub domain: &'static str, + pub num_rounds: usize, + pub degree: usize, + pub claim: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub claim_value: &'static str, + pub input_openings: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SumcheckBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static str, + pub claim_operands: &'static str, + pub claim_label: &'static str, + pub round_label: &'static str, + pub round_schedule: &'static [usize], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SumcheckDriverPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub kernel: Option<&'static str>, + pub relation: Option<&'static str>, + pub batch: &'static str, + pub policy: &'static str, + pub round_schedule: &'static [usize], + pub claim_label: &'static str, + pub round_label: &'static str, + pub num_rounds: usize, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SumcheckInstanceResultPlan { + pub symbol: &'static str, + pub source: &'static str, + pub claim: &'static str, + pub relation: &'static str, + pub index: usize, + pub point_arity: usize, + pub num_rounds: usize, + pub round_offset: usize, + pub point_order: &'static str, + pub degree: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SumcheckEvalPlan { + pub symbol: &'static str, + pub source: &'static str, + pub name: &'static str, + pub index: usize, + pub oracle: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PointZeroPlan { + pub symbol: &'static str, + pub field: &'static str, + pub arity: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PointSlicePlan { + pub symbol: &'static str, + pub source: &'static str, + pub offset: usize, + pub length: usize, + pub input: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PointConcatPlan { + pub symbol: &'static str, + pub layout: &'static str, + pub arity: usize, + pub inputs: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, + pub point_source: &'static str, + pub eval_source: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OpeningClaimEqualityPlan { + pub symbol: &'static str, + pub mode: &'static str, + pub lhs: &'static str, + pub rhs: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct OpeningBatchPlan { + pub symbol: &'static str, + pub stage: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static str, + pub claim_operands: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StageProgramPlan { + pub role: &'static str, + pub params: StageParams, + pub steps: &'static [ProgramStepPlan], + pub transcript_squeezes: &'static [TranscriptSqueezePlan], + pub transcript_absorb_bytes: &'static [TranscriptAbsorbBytesPlan], + pub opening_inputs: &'static [OpeningInputPlan], + pub field_constants: &'static [FieldConstantPlan], + pub field_exprs: &'static [FieldExprPlan], + pub kernels: &'static [KernelPlan], + pub claims: &'static [SumcheckClaimPlan], + pub batches: &'static [SumcheckBatchPlan], + pub drivers: &'static [SumcheckDriverPlan], + pub instance_results: &'static [SumcheckInstanceResultPlan], + pub evals: &'static [SumcheckEvalPlan], + pub point_zeros: &'static [PointZeroPlan], + pub point_slices: &'static [PointSlicePlan], + pub point_concats: &'static [PointConcatPlan], + pub opening_claims: &'static [OpeningClaimPlan], + pub opening_equalities: &'static [OpeningClaimEqualityPlan], + pub opening_batches: &'static [OpeningBatchPlan], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StageProgramPlanNoPointZeros { + pub role: &'static str, + pub params: StageParams, + pub steps: &'static [ProgramStepPlan], + pub transcript_squeezes: &'static [TranscriptSqueezePlan], + pub transcript_absorb_bytes: &'static [TranscriptAbsorbBytesPlan], + pub opening_inputs: &'static [OpeningInputPlan], + pub field_constants: &'static [FieldConstantPlan], + pub field_exprs: &'static [FieldExprPlan], + pub kernels: &'static [KernelPlan], + pub claims: &'static [SumcheckClaimPlan], + pub batches: &'static [SumcheckBatchPlan], + pub drivers: &'static [SumcheckDriverPlan], + pub instance_results: &'static [SumcheckInstanceResultPlan], + pub evals: &'static [SumcheckEvalPlan], + pub point_slices: &'static [PointSlicePlan], + pub point_concats: &'static [PointConcatPlan], + pub opening_claims: &'static [OpeningClaimPlan], + pub opening_equalities: &'static [OpeningClaimEqualityPlan], + pub opening_batches: &'static [OpeningBatchPlan], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StageVerifierProgramPlan { + pub params: StageParams, + pub steps: &'static [ProgramStepPlan], + pub transcript_squeezes: &'static [TranscriptSqueezePlan], + pub opening_inputs: &'static [OpeningInputPlan], + pub field_constants: &'static [FieldConstantPlan], + pub field_exprs: &'static [FieldExprPlan], + pub claims: &'static [SumcheckClaimPlan], + pub batches: &'static [SumcheckBatchPlan], + pub drivers: &'static [SumcheckDriverPlan], + pub instance_results: &'static [SumcheckInstanceResultPlan], + pub evals: &'static [SumcheckEvalPlan], + pub point_slices: &'static [PointSlicePlan], + pub point_concats: &'static [PointConcatPlan], + pub opening_claims: &'static [OpeningClaimPlan], + pub opening_equalities: &'static [OpeningClaimEqualityPlan], + pub opening_batches: &'static [OpeningBatchPlan], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StageVerifierProgramPlanNoEqualities { + pub params: StageParams, + pub steps: &'static [ProgramStepPlan], + pub transcript_squeezes: &'static [TranscriptSqueezePlan], + pub opening_inputs: &'static [OpeningInputPlan], + pub field_constants: &'static [FieldConstantPlan], + pub field_exprs: &'static [FieldExprPlan], + pub claims: &'static [SumcheckClaimPlan], + pub batches: &'static [SumcheckBatchPlan], + pub drivers: &'static [SumcheckDriverPlan], + pub instance_results: &'static [SumcheckInstanceResultPlan], + pub evals: &'static [SumcheckEvalPlan], + pub point_slices: &'static [PointSlicePlan], + pub point_concats: &'static [PointConcatPlan], + pub opening_claims: &'static [OpeningClaimPlan], + pub opening_batches: &'static [OpeningBatchPlan], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct VerifierProgramPlanMinimal { + pub params: StageParams, + pub transcript_squeezes: &'static [TranscriptSqueezePlan], + pub claims: &'static [SumcheckClaimPlan], + pub batches: &'static [SumcheckBatchPlan], + pub drivers: &'static [SumcheckDriverPlan], + pub instance_results: &'static [SumcheckInstanceResultPlan], + pub evals: &'static [SumcheckEvalPlan], + pub opening_claims: &'static [OpeningClaimPlan], + pub opening_batches: &'static [OpeningBatchPlan], +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct StageNamedEval { + pub name: &'static str, + pub oracle: &'static str, + pub value: F, +} + +#[derive(Clone, Debug, Serialize)] +pub struct StageSumcheckOutput { + pub driver: &'static str, + pub point: Vec, + pub evals: Vec>, + pub proof: SumcheckProof, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StageChallengeVector { + pub symbol: &'static str, + pub values: Vec, +} + +#[derive(Clone, Debug)] +pub struct StageExecutionArtifacts { + pub challenge_vectors: Vec>, + pub sumchecks: Vec>, + pub opening_batches: Vec<&'static OpeningBatchPlan>, +} + +impl Default for StageExecutionArtifacts { + fn default() -> Self { + Self { + challenge_vectors: Vec::new(), + sumchecks: Vec::new(), + opening_batches: Vec::new(), + } + } +} + +#[derive(Clone, Debug, Default, Serialize)] +pub struct StageProof { + pub sumchecks: Vec>, +} + +#[derive(Clone, Debug)] +pub struct StageOpeningInputValue { + pub symbol: &'static str, + pub point: Vec, + pub eval: F, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RuntimePlanError { + MissingBatch { + driver: &'static str, + batch: &'static str, + }, + MissingClaim { + batch: &'static str, + claim: &'static str, + }, + MissingValue { + symbol: &'static str, + }, + InvalidInputLength { + input: &'static str, + expected: usize, + actual: usize, + }, + InvalidProof { + driver: &'static str, + reason: &'static str, + }, + UnsupportedFieldExpr { + symbol: &'static str, + formula: &'static str, + }, +} + +macro_rules! impl_runtime_plan_error_conversion { + ($error:ident) => { + impl From for $error { + fn from(error: super::common::RuntimePlanError) -> Self { + match error { + super::common::RuntimePlanError::MissingBatch { driver, batch } => { + Self::MissingBatch { driver, batch } + } + super::common::RuntimePlanError::MissingClaim { batch, claim } => { + Self::MissingClaim { batch, claim } + } + super::common::RuntimePlanError::MissingValue { symbol } => { + Self::MissingValue { symbol } + } + super::common::RuntimePlanError::InvalidInputLength { + input, + expected, + actual, + } => Self::InvalidInputLength { + input, + expected, + actual, + }, + super::common::RuntimePlanError::InvalidProof { driver, reason } => { + Self::InvalidProof { driver, reason } + } + super::common::RuntimePlanError::UnsupportedFieldExpr { symbol, formula } => { + Self::UnsupportedFieldExpr { symbol, formula } + } + } + } + } + }; +} + +pub(crate) use impl_runtime_plan_error_conversion; + +pub trait SymbolPlan { + fn symbol(&self) -> &'static str; +} + +impl SymbolPlan for TranscriptSqueezePlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +impl SymbolPlan for TranscriptAbsorbBytesPlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +impl SymbolPlan for SumcheckBatchPlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +impl SymbolPlan for SumcheckClaimPlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +impl SymbolPlan for SumcheckDriverPlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +impl SymbolPlan for OpeningClaimPlan { + fn symbol(&self) -> &'static str { + self.symbol + } +} + +pub trait SumcheckClaimInfo: SymbolPlan { + fn num_rounds(&self) -> usize; + fn claim_value(&self) -> &'static str; +} + +impl SumcheckClaimInfo for SumcheckClaimPlan { + fn num_rounds(&self) -> usize { + self.num_rounds + } + + fn claim_value(&self) -> &'static str { + self.claim_value + } +} + +pub trait SumcheckDriverInfo: SymbolPlan { + fn batch(&self) -> &'static str; + fn num_rounds(&self) -> usize; + fn degree(&self) -> usize; + fn round_label(&self) -> &'static str; +} + +impl SumcheckDriverInfo for SumcheckDriverPlan { + fn batch(&self) -> &'static str { + self.batch + } + + fn num_rounds(&self) -> usize { + self.num_rounds + } + + fn degree(&self) -> usize { + self.degree + } + + fn round_label(&self) -> &'static str { + self.round_label + } +} + +#[derive(Clone, Debug, Default)] +pub struct ValueStore { + scalars: Vec<(&'static str, F)>, + points: Vec<(&'static str, Vec)>, +} + +impl ValueStore { + pub fn with_opening_inputs( + inputs: &[StageOpeningInputValue], + expected_inputs: &[OpeningInputPlan], + ) -> Result { + if inputs.len() != expected_inputs.len() { + return Err(RuntimePlanError::InvalidInputLength { + input: "opening_inputs", + expected: expected_inputs.len(), + actual: inputs.len(), + }); + } + for expected in expected_inputs { + let matching_count = inputs + .iter() + .filter(|input| input.symbol == expected.symbol) + .count(); + if matching_count != 1 { + return Err(RuntimePlanError::InvalidInputLength { + input: expected.symbol, + expected: 1, + actual: matching_count, + }); + } + if let Some(input) = inputs.iter().find(|input| input.symbol == expected.symbol) { + if input.point.len() != expected.point_arity { + return Err(RuntimePlanError::InvalidInputLength { + input: expected.symbol, + expected: expected.point_arity, + actual: input.point.len(), + }); + } + } + } + let mut store = Self::default(); + for input in inputs { + store.insert_scalar(input.symbol, input.eval); + store.insert_point(input.symbol, input.point.clone()); + } + Ok(store) + } + + pub fn seed_constants(&mut self, constants: &[FieldConstantPlan]) { + for constant in constants { + self.insert_scalar(constant.symbol, F::from_u64(constant.value as u64)); + } + } + + pub fn seed_point_zeros(&mut self, point_zeros: &[PointZeroPlan]) { + for zero in point_zeros { + self.insert_point(zero.symbol, vec![F::from_u64(0); zero.arity]); + } + } + + pub fn observe_challenge_vector( + &mut self, + plan: &TranscriptSqueezePlan, + values: &[F], + invalid_input_length: impl Fn(&'static str, usize, usize) -> E, + ) -> Result<(), E> { + self.insert_point(plan.symbol, values.to_vec()); + if matches!(plan.kind, "challenge_scalar" | "scalar") { + if values.len() != 1 { + return Err(invalid_input_length(plan.symbol, 1, values.len())); + } + self.insert_scalar(plan.symbol, values[0]); + } + Ok(()) + } + + pub fn observe_sumcheck_output( + &mut self, + instance_results: &[SumcheckInstanceResultPlan], + evals: &[SumcheckEvalPlan], + output: &StageSumcheckOutput, + normalize_point: impl Fn(&SumcheckInstanceResultPlan, Vec) -> Result, E>, + invalid_input_length: impl Fn(&'static str, usize, usize) -> E, + missing_value: impl Fn(&'static str) -> E, + ) -> Result<(), E> { + self.insert_point(output.driver, output.point.clone()); + for instance in instance_results + .iter() + .filter(|instance| instance.source == output.driver) + { + let end = instance.round_offset + instance.point_arity; + let point = output + .point + .get(instance.round_offset..end) + .ok_or_else(|| invalid_input_length(instance.symbol, end, output.point.len()))? + .to_vec(); + self.insert_point(instance.symbol, normalize_point(instance, point)?); + } + for eval in evals.iter().filter(|eval| eval.source == output.driver) { + let value = output + .evals + .iter() + .find(|value| value.name == eval.name) + .or_else(|| output.evals.get(eval.index)) + .ok_or_else(|| missing_value(eval.symbol))? + .value; + self.insert_scalar(eval.symbol, value); + self.insert_scalar(eval.name, value); + } + Ok(()) + } + + pub fn evaluate_available_points( + &mut self, + point_slices: &[PointSlicePlan], + point_concats: &[PointConcatPlan], + invalid_input_length: impl Fn(&'static str, usize, usize) -> E, + ) -> Result<(), E> { + loop { + let mut progress = 0usize; + for slice in point_slices { + if self.try_point(slice.symbol).is_some() { + continue; + } + let Some(input) = self.try_point(slice.input) else { + continue; + }; + let end = slice.offset + slice.length; + let point = input + .get(slice.offset..end) + .ok_or_else(|| invalid_input_length(slice.symbol, end, input.len()))? + .to_vec(); + self.insert_point(slice.symbol, point); + progress += 1; + } + for concat in point_concats { + if self.try_point(concat.symbol).is_some() { + continue; + } + let Some(point) = self.try_concat_point(concat) else { + continue; + }; + if point.len() != concat.arity { + return Err(invalid_input_length( + concat.symbol, + concat.arity, + point.len(), + )); + } + self.insert_point(concat.symbol, point); + progress += 1; + } + if progress == 0 { + return Ok(()); + } + } + } + + pub fn evaluate_available_field_exprs( + &mut self, + field_exprs: &[FieldExprPlan], + evaluate: impl Fn(&FieldExprPlan, &[F]) -> Result, + ) -> Result<(), E> { + loop { + let mut progress = 0usize; + for expr in field_exprs { + if self.try_scalar(expr.symbol).is_some() { + continue; + } + let Some(operands) = self.try_expr_operands(expr) else { + continue; + }; + self.insert_scalar(expr.symbol, evaluate(expr, &operands)?); + progress += 1; + } + if progress == 0 { + return Ok(()); + } + } + } + + pub fn verify_opening_equalities( + &self, + opening_equalities: &[OpeningClaimEqualityPlan], + invalid_proof: impl Fn(&'static str, &'static str) -> E, + missing_value: impl Fn(&'static str) -> E, + ) -> Result<(), E> { + for equality in opening_equalities { + match equality.mode { + "point_and_eval" => { + if self.point_or(equality.lhs, &missing_value)? + != self.point_or(equality.rhs, &missing_value)? + || self.scalar_or(equality.lhs, &missing_value)? + != self.scalar_or(equality.rhs, &missing_value)? + { + return Err(invalid_proof( + equality.symbol, + "opening claim equality failed", + )); + } + } + _ => { + return Err(invalid_proof( + equality.symbol, + "unsupported opening equality mode", + )); + } + } + } + Ok(()) + } + + pub fn insert_scalar(&mut self, symbol: &'static str, value: F) { + if let Some((_, existing)) = self.scalars.iter_mut().find(|(name, _)| *name == symbol) { + *existing = value; + } else { + self.scalars.push((symbol, value)); + } + } + + pub fn insert_point(&mut self, symbol: &'static str, point: Vec) { + if let Some((_, existing)) = self.points.iter_mut().find(|(name, _)| *name == symbol) { + *existing = point; + } else { + self.points.push((symbol, point)); + } + } + + pub fn scalar_or( + &self, + symbol: &'static str, + missing_value: impl FnOnce(&'static str) -> E, + ) -> Result { + self.try_scalar(symbol).ok_or_else(|| missing_value(symbol)) + } + + pub fn try_scalar(&self, symbol: &str) -> Option { + self.scalars + .iter() + .find(|(name, _)| *name == symbol) + .map(|(_, value)| *value) + } + + pub fn point_or( + &self, + symbol: &'static str, + missing_value: impl FnOnce(&'static str) -> E, + ) -> Result<&[F], E> { + self.try_point(symbol).ok_or_else(|| missing_value(symbol)) + } + + pub fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.points + .iter() + .find(|(name, _)| *name == symbol) + .map(|(_, point)| point.as_slice()) + } + + fn try_expr_operands(&self, expr: &FieldExprPlan) -> Option> { + if expr.operands.is_empty() { + return Some(Vec::new()); + } + expr.operands + .split('|') + .map(|operand| self.try_scalar(operand)) + .collect() + } + + fn try_concat_point(&self, concat: &PointConcatPlan) -> Option> { + let mut point = Vec::with_capacity(concat.arity); + for input in symbol_list(concat.inputs) { + point.extend_from_slice(self.try_point(input)?); + } + Some(point) + } +} + +pub fn symbol_list(symbols: &'static str) -> impl Iterator { + symbols.split('|').filter(|symbol| !symbol.is_empty()) +} + +pub fn find_plan<'a, T: SymbolPlan>(plans: &'a [T], symbol: &str) -> Option<&'a T> { + plans.iter().find(|plan| plan.symbol() == symbol) +} + +pub fn find_batch<'a>( + batches: &'a [SumcheckBatchPlan], + driver: &'static str, + batch: &'static str, +) -> Result<&'a SumcheckBatchPlan, RuntimePlanError> { + find_plan(batches, batch).ok_or(RuntimePlanError::MissingBatch { driver, batch }) +} + +pub fn batch_claims<'a, C: SymbolPlan>( + claims: &'a [C], + batch: &SumcheckBatchPlan, +) -> Result, RuntimePlanError> { + symbol_list(batch.claim_operands) + .map(|symbol| { + find_plan(claims, symbol).ok_or(RuntimePlanError::MissingClaim { + batch: batch.symbol, + claim: symbol, + }) + }) + .collect() +} + +pub fn batch_claim_values( + claims: &[&C], + field_exprs: &[FieldExprPlan], + store: &mut ValueStore, +) -> Result, RuntimePlanError> { + claims + .iter() + .map(|claim| { + store.evaluate_available_field_exprs(field_exprs, evaluate_field_expr)?; + store.scalar_or(claim.claim_value(), |symbol| { + RuntimePlanError::MissingValue { symbol } + }) + }) + .collect() +} + +pub fn verify_batched_sumcheck( + driver: &'static D, + proof: &StageSumcheckOutput, + claims: &'static [C], + batches: &'static [SumcheckBatchPlan], + field_exprs: &'static [FieldExprPlan], + opening_inputs: &'static [OpeningInputPlan], + opening_claims: &'static [OpeningClaimPlan], + opening_batches: &'static [OpeningBatchPlan], + store: &mut ValueStore, + transcript: &mut T, + expected_output: Expected, + observe_output: Observe, + map_sumcheck: MapSumcheck, +) -> Result, E> +where + T: Transcript, + E: From, + C: SumcheckClaimInfo, + D: SumcheckDriverInfo, + Expected: FnOnce(&ValueStore, &[StageNamedEval], &[Fr], &[Fr]) -> Result, + Observe: FnOnce(&mut ValueStore, &StageSumcheckOutput) -> Result<(), E>, + MapSumcheck: FnOnce(&'static str, SumcheckError) -> E, +{ + if proof.driver != driver.symbol() { + return Err(RuntimePlanError::InvalidProof { + driver: driver.symbol(), + reason: "driver symbol mismatch", + } + .into()); + } + let batch = find_batch(batches, driver.symbol(), driver.batch())?; + let claims = batch_claims(claims, batch)?; + let input_claims = batch_claim_values(&claims, field_exprs, store)?; + for claim in &input_claims { + append_labeled_scalar(transcript, batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let claimed_sum = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), coefficient)| { + claim.mul_pow_2(driver.num_rounds() - plan.num_rounds()) * *coefficient + }) + .sum::(); + let claim = SumcheckClaim::new(driver.num_rounds(), driver.degree(), claimed_sum); + let round_proofs = proof + .proof + .round_polynomials + .iter() + .map(|poly| CompressedLabeledRoundPoly::new(poly, driver.round_label().as_bytes())) + .collect::>(); + let output = SumcheckVerifier::verify(&claim, &round_proofs, transcript) + .map_err(|error| map_sumcheck(driver.symbol(), error))?; + if !proof.point.is_empty() && proof.point != output.point { + return Err(RuntimePlanError::InvalidProof { + driver: driver.symbol(), + reason: "batched point mismatch", + } + .into()); + } + let expected = expected_output(store, &proof.evals, &output.point, &batching_coeffs)?; + if output.value != expected { + return Err(RuntimePlanError::InvalidProof { + driver: driver.symbol(), + reason: "batched output claim mismatch", + } + .into()); + } + let verified = StageSumcheckOutput { + driver: driver.symbol(), + point: output.point, + evals: proof.evals.clone(), + proof: proof.proof.clone(), + }; + observe_output(store, &verified)?; + append_opening_claims( + opening_inputs, + opening_claims, + opening_batches, + store, + transcript, + &verified.evals, + |batch, claim| RuntimePlanError::MissingClaim { batch, claim }, + |symbol| RuntimePlanError::MissingValue { symbol }, + )?; + Ok(verified) +} + +pub fn eval_by_name( + evals: &[StageNamedEval], + name: &'static str, +) -> Result { + evals + .iter() + .find(|eval| eval.name == name) + .map(|eval| eval.value) + .ok_or(RuntimePlanError::MissingValue { symbol: name }) +} + +pub fn indexed_evals_by_prefix( + evals: &[StageNamedEval], + prefix: &'static str, + count: usize, +) -> Result, RuntimePlanError> { + let mut values = vec![None; count]; + for eval in evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| RuntimePlanError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if index >= count || values[index].is_some() { + return Err(RuntimePlanError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval", + }); + } + values[index] = Some(eval.value); + } + values + .into_iter() + .map(|value| value.ok_or(RuntimePlanError::MissingValue { symbol: prefix })) + .collect() +} + +pub fn indexed_evals_by_prefix_any( + evals: &[StageNamedEval], + prefix: &'static str, +) -> Result, RuntimePlanError> { + let mut indexed_values = Vec::new(); + for eval in evals { + let Some(suffix) = eval.name.strip_prefix(prefix) else { + continue; + }; + let index = suffix + .parse::() + .map_err(|_| RuntimePlanError::InvalidProof { + driver: prefix, + reason: "invalid indexed eval suffix", + })?; + if indexed_values + .iter() + .any(|(existing_index, _)| *existing_index == index) + { + return Err(RuntimePlanError::InvalidProof { + driver: prefix, + reason: "duplicate indexed eval", + }); + } + indexed_values.push((index, eval.value)); + } + if indexed_values.is_empty() { + return Err(RuntimePlanError::MissingValue { symbol: prefix }); + } + indexed_values.sort_by_key(|(index, _)| *index); + for (expected, (actual, _)) in indexed_values.iter().enumerate() { + if *actual != expected { + return Err(RuntimePlanError::InvalidProof { + driver: prefix, + reason: "non-contiguous indexed eval", + }); + } + } + Ok(indexed_values.into_iter().map(|(_, value)| value).collect()) +} + +pub fn single_operand( + symbol: &'static str, + operands: &[F], +) -> Result { + require_operand_count(symbol, 1, operands.len())?; + Ok(operands[0]) +} + +pub fn require_operand_count( + input: &'static str, + expected: usize, + actual: usize, +) -> Result<(), RuntimePlanError> { + if expected == actual { + Ok(()) + } else { + Err(RuntimePlanError::InvalidInputLength { + input, + expected, + actual, + }) + } +} + +pub fn evaluate_field_expr( + expr: &FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => Ok(single_operand(expr.symbol, operands)?), + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + formula => { + if let Some(exponent) = formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + RuntimePlanError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + Err(RuntimePlanError::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }) + } + } +} + +pub fn bytecode_gamma_powers(gamma: Fr) -> [Fr; 8] { + let mut powers = [Fr::from_u64(1); 8]; + for index in 1..powers.len() { + powers[index] = powers[index - 1] * gamma; + } + powers +} + +pub fn indexed_boolean_eq(index: usize, point: &[Fr]) -> Fr { + point + .iter() + .enumerate() + .map(|(bit, value)| { + if (index >> (point.len() - 1 - bit)) & 1 == 1 { + *value + } else { + Fr::from_u64(1) - *value + } + }) + .product() +} + +pub fn field_powers(base: Fr, count: usize) -> Vec { + let mut powers = Vec::with_capacity(count); + let mut power = Fr::from_u64(1); + for _ in 0..count { + powers.push(power); + power *= base; + } + powers +} + +pub fn prefix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], RuntimePlanError> { + point + .get(..length) + .filter(|prefix| prefix.len() == length) + .ok_or(RuntimePlanError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +pub fn suffix_point<'a, F: Field>( + point: &'a [F], + length: usize, + input: &'static str, +) -> Result<&'a [F], RuntimePlanError> { + point + .get(point.len().saturating_sub(length)..) + .filter(|suffix| suffix.len() == length) + .ok_or(RuntimePlanError::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +pub fn normalize_bytecode_read_raf_point( + point: &[F], + log_t: usize, + input: &'static str, +) -> Result, RuntimePlanError> { + let log_k = point + .len() + .checked_sub(log_t) + .ok_or(RuntimePlanError::InvalidInputLength { + input, + expected: log_t, + actual: point.len(), + })?; + let mut normalized = point.to_vec(); + normalized[..log_k].reverse(); + normalized[log_k..].reverse(); + Ok(normalized) +} + +pub fn normalize_instruction_read_raf_point( + point: &[F], + input: &'static str, +) -> Result, RuntimePlanError> { + const LOG_K: usize = 128; + if point.len() < LOG_K { + return Err(RuntimePlanError::InvalidInputLength { + input, + expected: LOG_K, + actual: point.len(), + }); + } + let mut normalized = point.to_vec(); + normalized[LOG_K..].reverse(); + Ok(normalized) +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage67RelationSymbols { + pub hamming_booleanity_relation: &'static str, + pub hamming_booleanity_instance: &'static str, + pub booleanity_point: &'static str, + pub stage5_instruction_ra0: &'static str, + pub booleanity_combined_point: &'static str, + pub booleanity_gamma: &'static str, + pub booleanity_instruction_ra_prefix: &'static str, + pub booleanity_bytecode_ra_prefix: &'static str, + pub booleanity_ram_ra_prefix: &'static str, + pub hamming_weight_eval: &'static str, + pub hamming_lookup_output: &'static str, + pub ram_ra_virtual_cycle: &'static str, + pub ram_ra_virtual_eval_prefix: &'static str, + pub instruction_ra_virtual_cycle: &'static str, + pub instruction_ra_virtual_eval_prefix: &'static str, + pub instruction_ra_virtual_input_prefix: &'static str, + pub instruction_ra_virtual_gamma: &'static str, + pub inc_ram_stage2: &'static str, + pub inc_ram_stage4: &'static str, + pub inc_rd_stage4: &'static str, + pub inc_rd_stage5: &'static str, + pub inc_gamma: &'static str, + pub inc_ram_eval: &'static str, + pub inc_rd_eval: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage67BytecodeSymbols { + pub point: &'static str, + pub gamma: &'static str, + pub bytecode_ra_eval_prefix: &'static str, + pub entries: &'static str, + pub entry_bytecode_index: &'static str, + pub stage_gammas: [&'static str; 5], + pub stage_cycle_points: [&'static str; 5], + pub stage4_register_point: &'static str, + pub stage5_register_point: &'static str, + pub entry_rd: &'static str, + pub entry_rs1: &'static str, + pub entry_rs2: &'static str, + pub entry_lookup_table: &'static str, +} + +pub trait Stage67BytecodeEntry { + fn address(&self) -> Fr; + fn imm(&self) -> Fr; + fn circuit_flags(&self) -> &[bool; 14]; + fn rd(&self) -> Option; + fn rs1(&self) -> Option; + fn rs2(&self) -> Option; + fn lookup_table(&self) -> Option; + fn is_interleaved(&self) -> bool; + fn is_branch(&self) -> bool; + fn left_is_rs1(&self) -> bool; + fn left_is_pc(&self) -> bool; + fn right_is_rs2(&self) -> bool; + fn right_is_imm(&self) -> bool; + fn is_noop(&self) -> bool; +} + +pub fn store_scalar(store: &ValueStore, symbol: &'static str) -> Result { + store.scalar_or(symbol, |symbol| RuntimePlanError::MissingValue { symbol }) +} + +pub fn store_point<'a>( + store: &'a ValueStore, + symbol: &'static str, +) -> Result<&'a [Fr], RuntimePlanError> { + store.point_or(symbol, |symbol| RuntimePlanError::MissingValue { symbol }) +} + +pub fn stage67_trace_rounds( + instance_results: &[SumcheckInstanceResultPlan], + symbols: &Stage67RelationSymbols, +) -> Result { + instance_results + .iter() + .find(|instance| instance.relation == symbols.hamming_booleanity_relation) + .map(|instance| instance.num_rounds) + .ok_or(RuntimePlanError::MissingValue { + symbol: symbols.hamming_booleanity_instance, + }) +} + +pub fn expected_stage67_bytecode_read_raf( + entries: &[E], + entry_bytecode_index: usize, + num_lookup_tables: usize, + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + log_t: usize, + symbols: &Stage67BytecodeSymbols, +) -> Result { + let opening_point = normalize_bytecode_read_raf_point(local_point, log_t, symbols.point)?; + let log_k = opening_point.len() - log_t; + let (r_address_prime, r_cycle_prime) = opening_point.split_at(log_k); + + let gamma = store_scalar(store, symbols.gamma)?; + let gamma_powers = bytecode_gamma_powers(gamma); + let int_eval = identity_polynomial_eval(r_address_prime); + let stage_value_evals = stage67_bytecode_stage_value_evals( + entries, + entry_bytecode_index, + num_lookup_tables, + store, + r_address_prime, + r_cycle_prime.len(), + symbols, + )?; + let stage_cycle_points = + stage67_bytecode_stage_cycle_points(store, r_cycle_prime.len(), symbols)?; + let int_contrib = [ + gamma_powers[5] * int_eval, + Fr::from_u64(0), + gamma_powers[4] * int_eval, + Fr::from_u64(0), + Fr::from_u64(0), + ]; + + let mut val = Fr::from_u64(0); + for index in 0..stage_value_evals.len() { + val += (stage_value_evals[index] + int_contrib[index]) + * EqPolynomial::::mle(&stage_cycle_points[index], r_cycle_prime) + * gamma_powers[index]; + } + + let entry_bits = (0..log_k) + .map(|index| Fr::from_u64(((entry_bytecode_index >> (log_k - 1 - index)) & 1) as u64)) + .collect::>(); + let zero_cycle = vec![Fr::from_u64(0); r_cycle_prime.len()]; + let entry_contrib = gamma_powers[7] + * EqPolynomial::::mle(&entry_bits, r_address_prime) + * EqPolynomial::::mle(&zero_cycle, r_cycle_prime); + let bytecode_ra = indexed_evals_by_prefix_any(evals, symbols.bytecode_ra_eval_prefix)? + .into_iter() + .product::(); + Ok((val + entry_contrib) * bytecode_ra) +} + +pub fn expected_stage67_booleanity( + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + log_t: usize, + symbols: &Stage67RelationSymbols, +) -> Result { + let log_k_chunk = + local_point + .len() + .checked_sub(log_t) + .ok_or(RuntimePlanError::InvalidInputLength { + input: symbols.booleanity_point, + expected: log_t, + actual: local_point.len(), + })?; + let stage5_point = store_point(store, symbols.stage5_instruction_ra0)?; + let stage5_address_len = + stage5_point + .len() + .checked_sub(log_t) + .ok_or(RuntimePlanError::InvalidInputLength { + input: symbols.stage5_instruction_ra0, + expected: log_t, + actual: stage5_point.len(), + })?; + if stage5_address_len < log_k_chunk { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.stage5_instruction_ra0, + expected: log_k_chunk + log_t, + actual: stage5_point.len(), + }); + } + + let mut stage5_addr = stage5_point[..stage5_address_len].to_vec(); + stage5_addr.reverse(); + let mut combined_r = stage5_addr[stage5_address_len - log_k_chunk..].to_vec(); + combined_r.extend(stage5_point[stage5_address_len..].iter().rev().copied()); + if combined_r.len() != local_point.len() { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.booleanity_combined_point, + expected: local_point.len(), + actual: combined_r.len(), + }); + } + let mut verifier_point = combined_r[..log_k_chunk].to_vec(); + verifier_point.reverse(); + verifier_point.extend(combined_r[log_k_chunk..].iter().rev().copied()); + let eq_eval = EqPolynomial::::mle(local_point, &verifier_point); + + let gamma = store_scalar(store, symbols.booleanity_gamma)?; + let gamma_sq = gamma.square(); + let mut gamma_power = Fr::from_u64(1); + let mut booleanity = Fr::from_u64(0); + for ra in stage67_booleanity_evals(evals, symbols)? { + booleanity += gamma_power * (ra.square() - ra); + gamma_power *= gamma_sq; + } + Ok(eq_eval * booleanity) +} + +pub fn expected_stage67_hamming_booleanity( + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + symbols: &Stage67RelationSymbols, +) -> Result { + let hamming = eval_by_name(evals, symbols.hamming_weight_eval)?; + let lookup_output_point = reverse_slice(store_point(store, symbols.hamming_lookup_output)?); + if lookup_output_point.len() != local_point.len() { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.hamming_lookup_output, + expected: local_point.len(), + actual: lookup_output_point.len(), + }); + } + let eq_eval = EqPolynomial::::mle(local_point, &lookup_output_point); + Ok((hamming.square() - hamming) * eq_eval) +} + +pub fn expected_stage67_ram_ra_virtual( + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + symbols: &Stage67RelationSymbols, +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle = suffix_point( + store_point(store, symbols.ram_ra_virtual_cycle)?, + r_cycle_reduced.len(), + symbols.ram_ra_virtual_cycle, + )?; + let eq_eval = EqPolynomial::::mle(r_cycle, &r_cycle_reduced); + let ram_ra = indexed_evals_by_prefix_any(evals, symbols.ram_ra_virtual_eval_prefix)? + .into_iter() + .product::(); + Ok(eq_eval * ram_ra) +} + +pub fn expected_stage67_instruction_ra_virtual( + opening_inputs: &[OpeningInputPlan], + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + symbols: &Stage67RelationSymbols, +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle = suffix_point( + store_point(store, symbols.instruction_ra_virtual_cycle)?, + r_cycle_reduced.len(), + symbols.instruction_ra_virtual_cycle, + )?; + let eq_eval = EqPolynomial::::mle(r_cycle, &r_cycle_reduced); + let committed_ra = + indexed_evals_by_prefix_any(evals, symbols.instruction_ra_virtual_eval_prefix)?; + let virtual_count = opening_inputs + .iter() + .filter(|input| { + input + .symbol + .starts_with(symbols.instruction_ra_virtual_input_prefix) + }) + .count(); + if virtual_count == 0 || committed_ra.len() % virtual_count != 0 { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.instruction_ra_virtual_eval_prefix, + expected: virtual_count, + actual: committed_ra.len(), + }); + } + let committed_per_virtual = committed_ra.len() / virtual_count; + let gamma = store_scalar(store, symbols.instruction_ra_virtual_gamma)?; + let mut gamma_power = Fr::from_u64(1); + let mut value = Fr::from_u64(0); + for chunk in committed_ra.chunks(committed_per_virtual) { + value += gamma_power * chunk.iter().copied().product::(); + gamma_power *= gamma; + } + Ok(eq_eval * value) +} + +pub fn expected_stage67_inc_claim_reduction( + store: &ValueStore, + evals: &[StageNamedEval], + local_point: &[Fr], + symbols: &Stage67RelationSymbols, +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let ram_inc_stage2 = suffix_point( + store_point(store, symbols.inc_ram_stage2)?, + r_cycle_reduced.len(), + symbols.inc_ram_stage2, + )?; + let ram_inc_stage4 = suffix_point( + store_point(store, symbols.inc_ram_stage4)?, + r_cycle_reduced.len(), + symbols.inc_ram_stage4, + )?; + let rd_inc_stage4 = suffix_point( + store_point(store, symbols.inc_rd_stage4)?, + r_cycle_reduced.len(), + symbols.inc_rd_stage4, + )?; + let rd_inc_stage5 = suffix_point( + store_point(store, symbols.inc_rd_stage5)?, + r_cycle_reduced.len(), + symbols.inc_rd_stage5, + )?; + let gamma = store_scalar(store, symbols.inc_gamma)?; + let eq_ram_combined = EqPolynomial::::mle(ram_inc_stage2, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(ram_inc_stage4, &r_cycle_reduced); + let eq_rd_combined = EqPolynomial::::mle(rd_inc_stage4, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(rd_inc_stage5, &r_cycle_reduced); + let ram_inc = eval_by_name(evals, symbols.inc_ram_eval)?; + let rd_inc = eval_by_name(evals, symbols.inc_rd_eval)?; + Ok(ram_inc * eq_ram_combined + gamma.square() * rd_inc * eq_rd_combined) +} + +fn stage67_booleanity_evals( + evals: &[StageNamedEval], + symbols: &Stage67RelationSymbols, +) -> Result, RuntimePlanError> { + let mut values = indexed_evals_by_prefix_any(evals, symbols.booleanity_instruction_ra_prefix)?; + values.extend(indexed_evals_by_prefix_any( + evals, + symbols.booleanity_bytecode_ra_prefix, + )?); + values.extend(indexed_evals_by_prefix_any( + evals, + symbols.booleanity_ram_ra_prefix, + )?); + Ok(values) +} + +fn stage67_bytecode_stage_cycle_points( + store: &ValueStore, + log_t: usize, + symbols: &Stage67BytecodeSymbols, +) -> Result<[Vec; 5], RuntimePlanError> { + let point = |index| { + let symbol = symbols.stage_cycle_points[index]; + suffix_point(store_point(store, symbol)?, log_t, symbol).map(|point| point.to_vec()) + }; + Ok([point(0)?, point(1)?, point(2)?, point(3)?, point(4)?]) +} + +fn stage67_bytecode_stage_value_evals( + entries: &[E], + entry_bytecode_index: usize, + num_lookup_tables: usize, + store: &ValueStore, + r_address: &[Fr], + log_t: usize, + symbols: &Stage67BytecodeSymbols, +) -> Result<[Fr; 5], RuntimePlanError> { + let expected_len = + 1usize + .checked_shl(r_address.len() as u32) + .ok_or(RuntimePlanError::InvalidInputLength { + input: symbols.entries, + expected: usize::BITS as usize, + actual: r_address.len(), + })?; + if entries.len() != expected_len { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.entries, + expected: expected_len, + actual: entries.len(), + }); + } + if entry_bytecode_index >= expected_len { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.entry_bytecode_index, + expected: expected_len, + actual: entry_bytecode_index + 1, + }); + } + + let stage1_gamma_powers = field_powers(store_scalar(store, symbols.stage_gammas[0])?, 16); + let stage2_gamma_powers = field_powers(store_scalar(store, symbols.stage_gammas[1])?, 4); + let stage3_gamma_powers = field_powers(store_scalar(store, symbols.stage_gammas[2])?, 9); + let stage4_gamma_powers = field_powers(store_scalar(store, symbols.stage_gammas[3])?, 3); + let stage5_gamma_powers = field_powers( + store_scalar(store, symbols.stage_gammas[4])?, + num_lookup_tables + 2, + ); + + let stage4_register_point = + stage67_register_prefix_point(store, symbols.stage4_register_point, log_t)?; + let stage5_register_point = + stage67_register_prefix_point(store, symbols.stage5_register_point, log_t)?; + + let mut evals = [Fr::from_u64(0); 5]; + for (index, entry) in entries.iter().enumerate() { + let eq = indexed_boolean_eq(index, r_address); + let values = stage67_bytecode_entry_stage_values( + entry, + num_lookup_tables, + stage4_register_point, + stage5_register_point, + &stage1_gamma_powers, + &stage2_gamma_powers, + &stage3_gamma_powers, + &stage4_gamma_powers, + &stage5_gamma_powers, + symbols, + )?; + for stage in 0..evals.len() { + evals[stage] += eq * values[stage]; + } + } + Ok(evals) +} + +fn stage67_bytecode_entry_stage_values( + entry: &E, + num_lookup_tables: usize, + stage4_register_point: &[Fr], + stage5_register_point: &[Fr], + stage1_gamma_powers: &[Fr], + stage2_gamma_powers: &[Fr], + stage3_gamma_powers: &[Fr], + stage4_gamma_powers: &[Fr], + stage5_gamma_powers: &[Fr], + symbols: &Stage67BytecodeSymbols, +) -> Result<[Fr; 5], RuntimePlanError> { + let flags = entry.circuit_flags(); + let mut stage1 = entry.address() + entry.imm() * stage1_gamma_powers[1]; + for (flag, gamma) in flags.iter().zip(stage1_gamma_powers.iter().skip(2)) { + if *flag { + stage1 += *gamma; + } + } + + let mut stage2 = Fr::from_u64(0); + if flags[5] { + stage2 += stage2_gamma_powers[0]; + } + if entry.is_branch() { + stage2 += stage2_gamma_powers[1]; + } + if flags[6] { + stage2 += stage2_gamma_powers[2]; + } + if flags[7] { + stage2 += stage2_gamma_powers[3]; + } + + let mut stage3 = entry.imm() + entry.address() * stage3_gamma_powers[1]; + if entry.left_is_rs1() { + stage3 += stage3_gamma_powers[2]; + } + if entry.left_is_pc() { + stage3 += stage3_gamma_powers[3]; + } + if entry.right_is_rs2() { + stage3 += stage3_gamma_powers[4]; + } + if entry.right_is_imm() { + stage3 += stage3_gamma_powers[5]; + } + if entry.is_noop() { + stage3 += stage3_gamma_powers[6]; + } + if flags[7] { + stage3 += stage3_gamma_powers[7]; + } + if flags[12] { + stage3 += stage3_gamma_powers[8]; + } + + let stage4 = stage67_register_eq(entry.rd(), stage4_register_point, symbols.entry_rd)? + * stage4_gamma_powers[0] + + stage67_register_eq(entry.rs1(), stage4_register_point, symbols.entry_rs1)? + * stage4_gamma_powers[1] + + stage67_register_eq(entry.rs2(), stage4_register_point, symbols.entry_rs2)? + * stage4_gamma_powers[2]; + + let mut stage5 = stage67_register_eq(entry.rd(), stage5_register_point, symbols.entry_rd)? + * stage5_gamma_powers[0]; + if !entry.is_interleaved() { + stage5 += stage5_gamma_powers[1]; + } + if let Some(table) = entry.lookup_table() { + if table >= num_lookup_tables { + return Err(RuntimePlanError::InvalidInputLength { + input: symbols.entry_lookup_table, + expected: num_lookup_tables, + actual: table + 1, + }); + } + stage5 += stage5_gamma_powers[2 + table]; + } + + Ok([stage1, stage2, stage3, stage4, stage5]) +} + +fn stage67_register_eq( + index: Option, + point: &[Fr], + input: &'static str, +) -> Result { + let Some(index) = index else { + return Ok(Fr::from_u64(0)); + }; + let register_count = + 1usize + .checked_shl(point.len() as u32) + .ok_or(RuntimePlanError::InvalidInputLength { + input, + expected: usize::BITS as usize, + actual: point.len(), + })?; + if index >= register_count { + return Err(RuntimePlanError::InvalidInputLength { + input, + expected: register_count, + actual: index + 1, + }); + } + Ok(indexed_boolean_eq(index, point)) +} + +fn stage67_register_prefix_point<'a>( + store: &'a ValueStore, + symbol: &'static str, + log_t: usize, +) -> Result<&'a [Fr], RuntimePlanError> { + let point = store_point(store, symbol)?; + let register_len = + point + .len() + .checked_sub(log_t) + .ok_or(RuntimePlanError::InvalidInputLength { + input: symbol, + expected: log_t, + actual: point.len(), + })?; + prefix_point(point, register_len, symbol) +} + +pub fn operand_polynomial_eval(point: &[Fr], left: bool) -> Fr { + let stride_offset = usize::from(!left); + let operand_bits = point.len() / 2; + (0..operand_bits) + .map(|index| point[2 * index + stride_offset].mul_pow_2(operand_bits - 1 - index)) + .sum() +} + +pub fn identity_polynomial_eval(point: &[Fr]) -> Fr { + point + .iter() + .enumerate() + .map(|(index, value)| value.mul_pow_2(point.len() - 1 - index)) + .sum() +} + +pub fn append_labeled_scalar(transcript: &mut T, label: &'static str, scalar: &Fr) +where + T: Transcript, +{ + transcript.append(&Label(label.as_bytes())); + transcript.append(scalar); +} + +pub fn append_opening_claims( + opening_inputs: &[OpeningInputPlan], + opening_claims: &[OpeningClaimPlan], + opening_batches: &[OpeningBatchPlan], + store: &mut ValueStore, + transcript: &mut T, + evals: &[StageNamedEval], + missing_claim: impl Fn(&'static str, &'static str) -> E, + missing_value: impl Fn(&'static str) -> E, +) -> Result<(), E> +where + T: Transcript, +{ + if opening_batches.is_empty() { + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } + return Ok(()); + } + let mut seen = opening_inputs + .iter() + .filter_map(|input| { + store + .try_point(input.symbol) + .map(|point| (input.claim_kind, input.oracle, point.to_vec())) + }) + .collect::>(); + for batch in opening_batches { + for symbol in symbol_list(batch.claim_operands) { + let claim = opening_claims + .iter() + .find(|claim| claim.symbol == symbol) + .ok_or_else(|| missing_claim(batch.symbol, symbol))?; + let point = store.point_or(claim.point_source, &missing_value)?.to_vec(); + if seen.iter().any(|(kind, oracle, seen_point)| { + *kind == claim.claim_kind && *oracle == claim.oracle && seen_point == &point + }) { + continue; + } + let value = store.scalar_or(claim.eval_source, &missing_value)?; + append_labeled_scalar(transcript, "opening_claim", &value); + seen.push((claim.claim_kind, claim.oracle, point)); + } + } + Ok(()) +} + +pub fn lt_polynomial_eval(x: &[Fr], y: &[Fr]) -> Fr { + let mut lt_eval = Fr::from_u64(0); + let mut eq_term = Fr::from_u64(1); + for (x_i, y_i) in x.iter().zip(y.iter()) { + lt_eval += (Fr::from_u64(1) - *x_i) * *y_i * eq_term; + eq_term *= Fr::from_u64(1) - *x_i - *y_i + *x_i * *y_i + *x_i * *y_i; + } + lt_eval +} + +pub fn pow_field(base: F, mut exponent: usize) -> F { + let mut result = F::one(); + let mut power = base; + while exponent != 0 { + if exponent & 1 == 1 { + result *= power; + } + power = power.square(); + exponent >>= 1; + } + result +} + +pub fn reverse_slice(values: &[Fr]) -> Vec { + values.iter().rev().copied().collect() +} diff --git a/crates/jolt-verifier/src/stages/mod.rs b/crates/jolt-verifier/src/stages/mod.rs new file mode 100644 index 0000000000..14f741edaa --- /dev/null +++ b/crates/jolt-verifier/src/stages/mod.rs @@ -0,0 +1,19 @@ +pub mod common; +#[rustfmt::skip] +pub mod commitment; +#[rustfmt::skip] +pub mod stage1_outer; +#[rustfmt::skip] +pub mod stage2; +#[rustfmt::skip] +pub mod stage3; +#[rustfmt::skip] +pub mod stage4; +#[rustfmt::skip] +pub mod stage5; +#[rustfmt::skip] +pub mod stage6; +#[rustfmt::skip] +pub mod stage7; +#[rustfmt::skip] +pub mod stage8; diff --git a/crates/jolt-verifier/src/stages/stage1_outer.rs b/crates/jolt-verifier/src/stages/stage1_outer.rs new file mode 100644 index 0000000000..53eac61c4d --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage1_outer.rs @@ -0,0 +1,406 @@ +#![allow(dead_code)] + +use super::common::append_labeled_scalar; +use jolt_field::Fr; +use jolt_sumcheck::{CompressedLabeledRoundPoly, LabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckVerifier}; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage1Transcript = Blake2bTranscript; + +pub type Stage1Params = super::common::StageParams; +pub type Stage1NamedEval = super::common::StageNamedEval; +pub type Stage1SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage1ChallengeVector = super::common::StageChallengeVector; +pub type Stage1ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage1Proof = super::common::StageProof; +pub type Stage1VerifierProgramPlan = super::common::VerifierProgramPlanMinimal; + +pub use super::common::{ + OpeningBatchPlan as Stage1OpeningBatchPlan, OpeningClaimPlan as Stage1OpeningClaimPlan, + SumcheckBatchPlan as Stage1SumcheckBatchPlan, SumcheckEvalPlan as Stage1SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage1SumcheckInstanceResultPlan, + TranscriptSqueezePlan as Stage1TranscriptSqueezePlan, + SumcheckClaimPlan as Stage1SumcheckClaimPlan, + SumcheckDriverPlan as Stage1SumcheckDriverPlan, +}; + +#[derive(Debug)] +pub enum VerifyStage1Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { driver: &'static str, claim: &'static str }, + MissingDependency { driver: &'static str, dependency: &'static str }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +pub const STAGE1_PARAMS: Stage1Params = Stage1Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE1_TRANSCRIPT_SQUEEZES: &[Stage1TranscriptSqueezePlan] = &[ + Stage1TranscriptSqueezePlan { symbol: "stage1.tau", label: "outer_tau", kind: "challenge_vector", count: 18 }, +]; + +pub const STAGE1_SUMCHECK_CLAIMS: &[Stage1SumcheckClaimPlan] = &[ + Stage1SumcheckClaimPlan { symbol: "stage1.uniskip.input", stage: "stage1", domain: "jolt.stage1_uniskip_domain", num_rounds: 1, degree: 27, claim: "stage1.zero", kernel: None, relation: Some("jolt.stage1.outer.uniskip"), claim_value: "stage1.zero", input_openings: "" }, + Stage1SumcheckClaimPlan { symbol: "stage1.outer_remaining.input", stage: "stage1", domain: "jolt.trace_domain", num_rounds: 17, degree: 3, claim: "stage1.uniskip.eval", kernel: None, relation: Some("jolt.stage1.outer.remaining"), claim_value: "stage1.uniskip.eval", input_openings: "stage1.uniskip.opening" }, +]; +pub const STAGE1_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE1_SUMCHECK_BATCH_1_ROUND_SCHEDULE: &[usize] = &[ + 17, +]; + +pub const STAGE1_SUMCHECK_BATCHES: &[Stage1SumcheckBatchPlan] = &[ + Stage1SumcheckBatchPlan { symbol: "stage1.uniskip.batch", stage: "stage1", proof_slot: "stage1.uni_skip_first_round", policy: "single_instance", count: 1, ordered_claims: "stage1.uniskip.input", claim_operands: "stage1.uniskip.input", claim_label: "uniskip_claim", round_label: "uniskip_poly", round_schedule: STAGE1_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, + Stage1SumcheckBatchPlan { symbol: "stage1.outer_remaining.batch", stage: "stage1", proof_slot: "stage1.sumcheck", policy: "jolt_core_front_loaded", count: 1, ordered_claims: "stage1.outer_remaining.input", claim_operands: "stage1.outer_remaining.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE1_SUMCHECK_BATCH_1_ROUND_SCHEDULE }, +]; +pub const STAGE1_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE1_SUMCHECK_DRIVER_1_ROUND_SCHEDULE: &[usize] = &[ + 17, +]; + +pub const STAGE1_SUMCHECK_DRIVERS: &[Stage1SumcheckDriverPlan] = &[ + Stage1SumcheckDriverPlan { symbol: "stage1.uniskip.sumcheck", stage: "stage1", proof_slot: "stage1.uni_skip_first_round", kernel: None, relation: Some("jolt.stage1.outer.uniskip"), batch: "stage1.uniskip.batch", policy: "univariate_skip", round_schedule: STAGE1_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "uniskip_claim", round_label: "uniskip_poly", num_rounds: 1, degree: 27 }, + Stage1SumcheckDriverPlan { symbol: "stage1.outer_remaining.sumcheck", stage: "stage1", proof_slot: "stage1.sumcheck", kernel: None, relation: Some("jolt.stage1.outer.remaining"), batch: "stage1.outer_remaining.batch", policy: "jolt_core_front_loaded", round_schedule: STAGE1_SUMCHECK_DRIVER_1_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 17, degree: 3 }, +]; +pub const STAGE1_SUMCHECK_INSTANCE_RESULTS: &[Stage1SumcheckInstanceResultPlan] = &[ + Stage1SumcheckInstanceResultPlan { symbol: "stage1.uniskip.instance", source: "stage1.uniskip.sumcheck", claim: "stage1.uniskip.input", relation: "jolt.stage1.outer.uniskip", index: 0, point_arity: 1, num_rounds: 1, round_offset: 0, point_order: "as_is", degree: 27 }, + Stage1SumcheckInstanceResultPlan { symbol: "stage1.outer_remaining.instance", source: "stage1.outer_remaining.sumcheck", claim: "stage1.outer_remaining.input", relation: "jolt.stage1.outer.remaining", index: 0, point_arity: 16, num_rounds: 17, round_offset: 1, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE1_SUMCHECK_EVALS: &[Stage1SumcheckEvalPlan] = &[ + Stage1SumcheckEvalPlan { symbol: "stage1.uniskip.eval", source: "stage1.uniskip.sumcheck", name: "stage1.uniskip.eval", index: 0, oracle: "UnivariateSkip" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LeftInstructionInput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LeftInstructionInput", index: 0, oracle: "LeftInstructionInput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RightInstructionInput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RightInstructionInput", index: 1, oracle: "RightInstructionInput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Product", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Product", index: 2, oracle: "Product" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.ShouldBranch", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.ShouldBranch", index: 3, oracle: "ShouldBranch" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.PC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.PC", index: 4, oracle: "PC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.UnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.UnexpandedPC", index: 5, oracle: "UnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Imm", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Imm", index: 6, oracle: "Imm" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamAddress", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamAddress", index: 7, oracle: "RamAddress" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Rs1Value", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Rs1Value", index: 8, oracle: "Rs1Value" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.Rs2Value", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.Rs2Value", index: 9, oracle: "Rs2Value" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RdWriteValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RdWriteValue", index: 10, oracle: "RdWriteValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamReadValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamReadValue", index: 11, oracle: "RamReadValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RamWriteValue", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RamWriteValue", index: 12, oracle: "RamWriteValue" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LeftLookupOperand", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LeftLookupOperand", index: 13, oracle: "LeftLookupOperand" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.RightLookupOperand", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.RightLookupOperand", index: 14, oracle: "RightLookupOperand" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextUnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextUnexpandedPC", index: 15, oracle: "NextUnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextPC", index: 16, oracle: "NextPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextIsVirtual", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextIsVirtual", index: 17, oracle: "NextIsVirtual" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.NextIsFirstInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.NextIsFirstInSequence", index: 18, oracle: "NextIsFirstInSequence" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.LookupOutput", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.LookupOutput", index: 19, oracle: "LookupOutput" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.ShouldJump", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.ShouldJump", index: 20, oracle: "ShouldJump" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAddOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAddOperands", index: 21, oracle: "OpFlagAddOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagSubtractOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagSubtractOperands", index: 22, oracle: "OpFlagSubtractOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagMultiplyOperands", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagMultiplyOperands", index: 23, oracle: "OpFlagMultiplyOperands" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagLoad", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagLoad", index: 24, oracle: "OpFlagLoad" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagStore", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagStore", index: 25, oracle: "OpFlagStore" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagJump", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagJump", index: 26, oracle: "OpFlagJump" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD", index: 27, oracle: "OpFlagWriteLookupOutputToRD" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagVirtualInstruction", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagVirtualInstruction", index: 28, oracle: "OpFlagVirtualInstruction" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAssert", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAssert", index: 29, oracle: "OpFlagAssert" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC", index: 30, oracle: "OpFlagDoNotUpdateUnexpandedPC" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagAdvice", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagAdvice", index: 31, oracle: "OpFlagAdvice" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsCompressed", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsCompressed", index: 32, oracle: "OpFlagIsCompressed" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence", index: 33, oracle: "OpFlagIsFirstInSequence" }, + Stage1SumcheckEvalPlan { symbol: "stage1.outer_remaining.eval.OpFlagIsLastInSequence", source: "stage1.outer_remaining.sumcheck", name: "stage1.outer_remaining.eval.OpFlagIsLastInSequence", index: 34, oracle: "OpFlagIsLastInSequence" }, +]; + +pub const STAGE1_OPENING_CLAIMS: &[Stage1OpeningClaimPlan] = &[ + Stage1OpeningClaimPlan { symbol: "stage1.uniskip.opening", oracle: "UnivariateSkip", domain: "jolt.stage1_uniskip_domain", point_arity: 1, claim_kind: "virtual", point_source: "stage1.uniskip.instance", eval_source: "stage1.uniskip.eval" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LeftInstructionInput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RightInstructionInput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Product", oracle: "Product", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Product" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.ShouldBranch", oracle: "ShouldBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.ShouldBranch" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.PC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.UnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Imm" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamAddress", oracle: "RamAddress", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamAddress" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Rs1Value" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.Rs2Value" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RdWriteValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamReadValue", oracle: "RamReadValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamReadValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RamWriteValue", oracle: "RamWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RamWriteValue" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LeftLookupOperand" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.RightLookupOperand" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextUnexpandedPC", oracle: "NextUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextUnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextPC", oracle: "NextPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextIsVirtual", oracle: "NextIsVirtual", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextIsVirtual" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.NextIsFirstInSequence", oracle: "NextIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.NextIsFirstInSequence" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.LookupOutput" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.ShouldJump", oracle: "ShouldJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.ShouldJump" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAddOperands", oracle: "OpFlagAddOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAddOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagSubtractOperands", oracle: "OpFlagSubtractOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagSubtractOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagMultiplyOperands", oracle: "OpFlagMultiplyOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagMultiplyOperands" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagLoad", oracle: "OpFlagLoad", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagLoad" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagStore", oracle: "OpFlagStore", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagStore" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagJump" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagWriteLookupOutputToRD" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagVirtualInstruction" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAssert", oracle: "OpFlagAssert", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAssert" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", oracle: "OpFlagDoNotUpdateUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagDoNotUpdateUnexpandedPC" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagAdvice", oracle: "OpFlagAdvice", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagAdvice" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsCompressed", oracle: "OpFlagIsCompressed", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsCompressed" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsFirstInSequence" }, + Stage1OpeningClaimPlan { symbol: "stage1.outer_remaining.opening.OpFlagIsLastInSequence", oracle: "OpFlagIsLastInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage1.outer_remaining.instance", eval_source: "stage1.outer_remaining.eval.OpFlagIsLastInSequence" }, +]; + +pub const STAGE1_OPENING_BATCHES: &[Stage1OpeningBatchPlan] = &[ + Stage1OpeningBatchPlan { symbol: "stage1.outer_remaining.openings", stage: "stage1", proof_slot: "stage1.virtual_openings", policy: "jolt_r1cs_input_order", count: 35, ordered_claims: "stage1.outer_remaining.opening.LeftInstructionInput|stage1.outer_remaining.opening.RightInstructionInput|stage1.outer_remaining.opening.Product|stage1.outer_remaining.opening.ShouldBranch|stage1.outer_remaining.opening.PC|stage1.outer_remaining.opening.UnexpandedPC|stage1.outer_remaining.opening.Imm|stage1.outer_remaining.opening.RamAddress|stage1.outer_remaining.opening.Rs1Value|stage1.outer_remaining.opening.Rs2Value|stage1.outer_remaining.opening.RdWriteValue|stage1.outer_remaining.opening.RamReadValue|stage1.outer_remaining.opening.RamWriteValue|stage1.outer_remaining.opening.LeftLookupOperand|stage1.outer_remaining.opening.RightLookupOperand|stage1.outer_remaining.opening.NextUnexpandedPC|stage1.outer_remaining.opening.NextPC|stage1.outer_remaining.opening.NextIsVirtual|stage1.outer_remaining.opening.NextIsFirstInSequence|stage1.outer_remaining.opening.LookupOutput|stage1.outer_remaining.opening.ShouldJump|stage1.outer_remaining.opening.OpFlagAddOperands|stage1.outer_remaining.opening.OpFlagSubtractOperands|stage1.outer_remaining.opening.OpFlagMultiplyOperands|stage1.outer_remaining.opening.OpFlagLoad|stage1.outer_remaining.opening.OpFlagStore|stage1.outer_remaining.opening.OpFlagJump|stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD|stage1.outer_remaining.opening.OpFlagVirtualInstruction|stage1.outer_remaining.opening.OpFlagAssert|stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC|stage1.outer_remaining.opening.OpFlagAdvice|stage1.outer_remaining.opening.OpFlagIsCompressed|stage1.outer_remaining.opening.OpFlagIsFirstInSequence|stage1.outer_remaining.opening.OpFlagIsLastInSequence", claim_operands: "stage1.outer_remaining.opening.LeftInstructionInput|stage1.outer_remaining.opening.RightInstructionInput|stage1.outer_remaining.opening.Product|stage1.outer_remaining.opening.ShouldBranch|stage1.outer_remaining.opening.PC|stage1.outer_remaining.opening.UnexpandedPC|stage1.outer_remaining.opening.Imm|stage1.outer_remaining.opening.RamAddress|stage1.outer_remaining.opening.Rs1Value|stage1.outer_remaining.opening.Rs2Value|stage1.outer_remaining.opening.RdWriteValue|stage1.outer_remaining.opening.RamReadValue|stage1.outer_remaining.opening.RamWriteValue|stage1.outer_remaining.opening.LeftLookupOperand|stage1.outer_remaining.opening.RightLookupOperand|stage1.outer_remaining.opening.NextUnexpandedPC|stage1.outer_remaining.opening.NextPC|stage1.outer_remaining.opening.NextIsVirtual|stage1.outer_remaining.opening.NextIsFirstInSequence|stage1.outer_remaining.opening.LookupOutput|stage1.outer_remaining.opening.ShouldJump|stage1.outer_remaining.opening.OpFlagAddOperands|stage1.outer_remaining.opening.OpFlagSubtractOperands|stage1.outer_remaining.opening.OpFlagMultiplyOperands|stage1.outer_remaining.opening.OpFlagLoad|stage1.outer_remaining.opening.OpFlagStore|stage1.outer_remaining.opening.OpFlagJump|stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD|stage1.outer_remaining.opening.OpFlagVirtualInstruction|stage1.outer_remaining.opening.OpFlagAssert|stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC|stage1.outer_remaining.opening.OpFlagAdvice|stage1.outer_remaining.opening.OpFlagIsCompressed|stage1.outer_remaining.opening.OpFlagIsFirstInSequence|stage1.outer_remaining.opening.OpFlagIsLastInSequence" }, +]; +pub const STAGE1_PROGRAM: Stage1VerifierProgramPlan = Stage1VerifierProgramPlan { + params: STAGE1_PARAMS, + transcript_squeezes: STAGE1_TRANSCRIPT_SQUEEZES, + claims: STAGE1_SUMCHECK_CLAIMS, + batches: STAGE1_SUMCHECK_BATCHES, + drivers: STAGE1_SUMCHECK_DRIVERS, + instance_results: STAGE1_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE1_SUMCHECK_EVALS, + opening_claims: STAGE1_OPENING_CLAIMS, + opening_batches: STAGE1_OPENING_BATCHES, +}; + +pub fn verify_stage1_outer( + proof: &Stage1Proof, + transcript: &mut T, +) -> Result, VerifyStage1Error> +where + T: Transcript, +{ + verify_stage1_outer_with_program(&STAGE1_PROGRAM, proof, transcript) +} + +pub fn verify_stage1_outer_with_program( + program: &'static Stage1VerifierProgramPlan, + proof: &Stage1Proof, + transcript: &mut T, +) -> Result, VerifyStage1Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage1Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut artifacts = Stage1ExecutionArtifacts::default(); + for squeeze in program.transcript_squeezes { + let values = transcript.challenge_vector(squeeze.count); + artifacts.challenge_vectors.push(Stage1ChallengeVector { + symbol: squeeze.symbol, + values, + }); + } + for (index, driver) in program.drivers.iter().enumerate() { + let proof = proof.sumchecks.get(index).ok_or(VerifyStage1Error::MissingProof { + driver: driver.symbol, + })?; + let output = verify_stage1_driver(program, driver, proof, &artifacts.sumchecks, transcript)?; + artifacts.sumchecks.push(output); + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage1_outer_verifier_program() -> &'static Stage1VerifierProgramPlan { + &STAGE1_PROGRAM +} + +fn verify_stage1_driver( + program: &'static Stage1VerifierProgramPlan, + driver: &'static Stage1SumcheckDriverPlan, + proof: &Stage1SumcheckOutput, + completed: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, VerifyStage1Error> +where + T: Transcript, +{ + if proof.driver != driver.symbol { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "driver symbol mismatch", + }); + } + let relation = driver.relation.unwrap_or(""); + match relation { + "jolt.stage1.outer.uniskip" => verify_outer_uniskip(program, driver, proof, transcript), + "jolt.stage1.outer.remaining" => { + verify_outer_remaining(program, driver, proof, completed, transcript) + } + relation => Err(VerifyStage1Error::UnsupportedRelation { relation }), + } +} + +fn verify_outer_uniskip( + program: &'static Stage1VerifierProgramPlan, + driver: &'static Stage1SumcheckDriverPlan, + proof: &Stage1SumcheckOutput, + transcript: &mut T, +) -> Result, VerifyStage1Error> +where + T: Transcript, +{ + let claim = SumcheckClaim::new(driver.num_rounds, driver.degree, Fr::from_u64(0)); + let round_proofs = proof + .proof + .round_polynomials + .iter() + .map(|poly| LabeledRoundPoly::new(poly, driver.round_label.as_bytes())) + .collect::>(); + let output = SumcheckVerifier::verify(&claim, &round_proofs, transcript) + .map_err(|error| VerifyStage1Error::Sumcheck { + driver: driver.symbol, + error, + })?; + let eval = output.value; + let point = output.point; + if !proof.point.is_empty() && proof.point != point { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "uniskip point mismatch", + }); + } + validate_eval_shape(program, driver, &proof.evals, Some(eval))?; + append_labeled_scalar(transcript, "opening_claim", &eval); + Ok(Stage1SumcheckOutput { + driver: driver.symbol, + point, + evals: driver_evals(program, driver.symbol, eval), + proof: proof.proof.clone(), + }) +} + +fn verify_outer_remaining( + program: &'static Stage1VerifierProgramPlan, + driver: &'static Stage1SumcheckDriverPlan, + proof: &Stage1SumcheckOutput, + completed: &[Stage1SumcheckOutput], + transcript: &mut T, +) -> Result, VerifyStage1Error> +where + T: Transcript, +{ + let input_claim = completed + .iter() + .find(|output| output.driver == "stage1.uniskip.sumcheck") + .and_then(|output| output.evals.first()) + .map(|eval| eval.value) + .ok_or(VerifyStage1Error::MissingDependency { + driver: driver.symbol, + dependency: "stage1.uniskip.eval", + })?; + append_labeled_scalar(transcript, driver.claim_label, &input_claim); + let batching_coeff = transcript.challenge(); + let claim = SumcheckClaim::new( + driver.num_rounds, + driver.degree, + input_claim * batching_coeff, + ); + let round_proofs = proof + .proof + .round_polynomials + .iter() + .map(|poly| CompressedLabeledRoundPoly::new(poly, driver.round_label.as_bytes())) + .collect::>(); + let output = SumcheckVerifier::verify(&claim, &round_proofs, transcript) + .map_err(|error| VerifyStage1Error::Sumcheck { + driver: driver.symbol, + error, + })?; + let point = output.point; + if !proof.point.is_empty() && proof.point != point { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "outer remaining point mismatch", + }); + } + validate_eval_shape(program, driver, &proof.evals, None)?; + append_opening_claims(transcript, &proof.evals); + Ok(Stage1SumcheckOutput { + driver: driver.symbol, + point, + evals: proof.evals.clone(), + proof: proof.proof.clone(), + }) +} + +fn driver_evals( + program: &'static Stage1VerifierProgramPlan, + driver: &'static str, + value: Fr, +) -> Vec> { + program + .evals + .iter() + .filter(|eval| eval.source == driver) + .map(|eval| Stage1NamedEval { + name: eval.name, + oracle: eval.oracle, + value, + }) + .collect() +} + +fn validate_eval_shape( + program: &'static Stage1VerifierProgramPlan, + driver: &'static Stage1SumcheckDriverPlan, + actual: &[Stage1NamedEval], + expected_value: Option, +) -> Result<(), VerifyStage1Error> { + let expected = program + .evals + .iter() + .filter(|eval| eval.source == driver.symbol) + .collect::>(); + if actual.len() != expected.len() { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "eval count mismatch", + }); + } + for (actual, expected) in actual.iter().zip(expected) { + if actual.name != expected.name { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "eval name mismatch", + }); + } + if actual.oracle != expected.oracle { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "eval oracle mismatch", + }); + } + if expected_value.is_some_and(|value| actual.value != value) { + return Err(VerifyStage1Error::InvalidProof { + driver: driver.symbol, + reason: "eval value mismatch", + }); + } + } + Ok(()) +} + +fn append_opening_claims(transcript: &mut T, evals: &[Stage1NamedEval]) +where + T: Transcript, +{ + for eval in evals { + append_labeled_scalar(transcript, "opening_claim", &eval.value); + } +} diff --git a/crates/jolt-verifier/src/stages/stage2.rs b/crates/jolt-verifier/src/stages/stage2.rs new file mode 100644 index 0000000000..9517f1530e --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage2.rs @@ -0,0 +1,1050 @@ +#![allow(dead_code)] + +use super::common::{append_labeled_scalar, batch_claims, eval_by_name, find_batch, find_plan, pow_field, require_operand_count, reverse_slice, single_operand}; +use jolt_field::{Field, Fr, MulPow2, MulPrimitiveInt, RingCore}; +use jolt_poly::lagrange::{lagrange_evals, lagrange_kernel_eval}; +use jolt_poly::{EqPolynomial, UnivariatePoly}; +use jolt_sumcheck::{CompressedLabeledRoundPoly, SumcheckClaim, SumcheckError, SumcheckVerifier}; +use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript}; + +pub type DefaultStage2Transcript = Blake2bTranscript; + +pub type Stage2NamedEval = super::common::StageNamedEval; +pub type Stage2SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage2ChallengeVector = super::common::StageChallengeVector; +pub type Stage2ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage2Proof = super::common::StageProof; +pub type Stage2OpeningInputValue = super::common::StageOpeningInputValue; +pub type Stage2VerifierProgramPlan = super::common::StageVerifierProgramPlanNoEqualities; + +pub use super::common::{ + FieldConstantPlan as Stage2FieldConstantPlan, FieldExprPlan as Stage2FieldExprPlan, + OpeningBatchPlan as Stage2OpeningBatchPlan, OpeningClaimPlan as Stage2OpeningClaimPlan, + OpeningInputPlan as Stage2OpeningInputPlan, PointConcatPlan as Stage2PointConcatPlan, + PointSlicePlan as Stage2PointSlicePlan, ProgramStepPlan as Stage2ProgramStepPlan, + StageParams as Stage2Params, SumcheckBatchPlan as Stage2SumcheckBatchPlan, + SumcheckEvalPlan as Stage2SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage2SumcheckInstanceResultPlan, + TranscriptSqueezePlan as Stage2TranscriptSqueezePlan, + SumcheckClaimPlan as Stage2SumcheckClaimPlan, + SumcheckDriverPlan as Stage2SumcheckDriverPlan, +}; + +#[derive(Clone, Copy, Debug)] +pub struct Stage2RamAccess { + pub remapped_address: Option, + pub read_value: u64, + pub write_value: u64, +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage2RamOutputLayout { + pub io_start: usize, + pub io_end: usize, +} + +#[derive(Clone, Copy, Debug)] +pub struct Stage2RamData<'a> { + pub log_k: usize, + pub start_address: u64, + pub initial_ram: &'a [u64], + pub final_ram: &'a [u64], + pub accesses: &'a [Stage2RamAccess], + pub output_layout: Option, +} + +#[derive(Clone, Debug, Default)] +struct Stage2ValueStore(super::common::ValueStore); + +#[derive(Debug)] +pub enum VerifyStage2Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + MissingRam { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage2Error); + +pub const STAGE2_PARAMS: Stage2Params = Stage2Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE2_PROGRAM_STEPS: &[Stage2ProgramStepPlan] = &[ + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.product_virtual.tau_high" }, + Stage2ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage2.product_virtual.uniskip.sumcheck" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.ram_read_write.gamma" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.instruction_lookup.gamma" }, + Stage2ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage2.ram_output.r_address" }, + Stage2ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage2.sumcheck" }, +]; + +pub const STAGE2_TRANSCRIPT_SQUEEZES: &[Stage2TranscriptSqueezePlan] = &[ + Stage2TranscriptSqueezePlan { symbol: "stage2.product_virtual.tau_high", label: "product_virtual_tau_high", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.ram_read_write.gamma", label: "ram_read_write_gamma", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.instruction_lookup.gamma", label: "instruction_lookup_gamma", kind: "challenge_scalar", count: 1 }, + Stage2TranscriptSqueezePlan { symbol: "stage2.ram_output.r_address", label: "ram_output_r_address", kind: "challenge_vector", count: 16 }, +]; + +pub const STAGE2_OPENING_INPUTS: &[Stage2OpeningInputPlan] = &[ + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.Product", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Product", oracle: "Product", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.ShouldBranch", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.ShouldBranch", oracle: "ShouldBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.ShouldJump", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.ShouldJump", oracle: "ShouldJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamReadValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamReadValue", oracle: "RamReadValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamWriteValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamWriteValue", oracle: "RamWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LookupOutput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LeftLookupOperand", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RightLookupOperand", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.LeftInstructionInput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RightInstructionInput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage2OpeningInputPlan { symbol: "stage2.input.stage1.RamAddress", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RamAddress", oracle: "RamAddress", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE2_FIELD_CONSTANTS: &[Stage2FieldConstantPlan] = &[ + Stage2FieldConstantPlan { symbol: "stage2.ram_output.zero", field: "bn254_fr", value: 0 }, +]; + +pub const STAGE2_FIELD_EXPRS: &[Stage2FieldExprPlan] = &[ + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.Product", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:0", operands: "stage2.product_virtual.tau_high" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.ShouldBranch", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:1", operands: "stage2.product_virtual.tau_high" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.weight.ShouldJump", kind: "op", formula: "poly.lagrange_basis_eval:-1:3:2", operands: "stage2.product_virtual.tau_high" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.Product", kind: "op", formula: "field.mul", operands: "stage2.product_virtual.uniskip.weight.Product|stage2.input.stage1.Product" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.ShouldBranch", kind: "op", formula: "field.mul", operands: "stage2.product_virtual.uniskip.weight.ShouldBranch|stage2.input.stage1.ShouldBranch" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.term.ShouldJump", kind: "op", formula: "field.mul", operands: "stage2.product_virtual.uniskip.weight.ShouldJump|stage2.input.stage1.ShouldJump" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.partial.ProductShouldBranch", kind: "op", formula: "field.add", operands: "stage2.product_virtual.uniskip.term.Product|stage2.product_virtual.uniskip.term.ShouldBranch" }, + Stage2FieldExprPlan { symbol: "stage2.product_virtual.uniskip.claim_expr", kind: "op", formula: "field.add", operands: "stage2.product_virtual.uniskip.partial.ProductShouldBranch|stage2.product_virtual.uniskip.term.ShouldJump" }, + Stage2FieldExprPlan { symbol: "stage2.ram_read_write.term.RamWriteValue", kind: "op", formula: "field.mul", operands: "stage2.ram_read_write.gamma|stage2.input.stage1.RamWriteValue" }, + Stage2FieldExprPlan { symbol: "stage2.ram_read_write.claim_expr", kind: "op", formula: "field.add", operands: "stage2.input.stage1.RamReadValue|stage2.ram_read_write.term.RamWriteValue" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma2", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma|stage2.instruction_lookup.gamma" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma3", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma2|stage2.instruction_lookup.gamma" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.gamma4", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma2|stage2.instruction_lookup.gamma2" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.LeftLookupOperand", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma|stage2.input.stage1.LeftLookupOperand" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.RightLookupOperand", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma2|stage2.input.stage1.RightLookupOperand" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.LeftInstructionInput", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma3|stage2.input.stage1.LeftInstructionInput" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.term.RightInstructionInput", kind: "op", formula: "field.mul", operands: "stage2.instruction_lookup.gamma4|stage2.input.stage1.RightInstructionInput" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.LookupOutputLeftOperand", kind: "op", formula: "field.add", operands: "stage2.input.stage1.LookupOutput|stage2.instruction_lookup.term.LeftLookupOperand" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.RightOperand", kind: "op", formula: "field.add", operands: "stage2.instruction_lookup.partial.LookupOutputLeftOperand|stage2.instruction_lookup.term.RightLookupOperand" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.partial.LeftInstructionInput", kind: "op", formula: "field.add", operands: "stage2.instruction_lookup.partial.RightOperand|stage2.instruction_lookup.term.LeftInstructionInput" }, + Stage2FieldExprPlan { symbol: "stage2.instruction_lookup.claim_reduction.claim_expr", kind: "op", formula: "field.add", operands: "stage2.instruction_lookup.partial.LeftInstructionInput|stage2.instruction_lookup.term.RightInstructionInput" }, +]; +pub const STAGE2_SUMCHECK_CLAIMS: &[Stage2SumcheckClaimPlan] = &[ + Stage2SumcheckClaimPlan { symbol: "stage2.product_virtual.uniskip.input", stage: "stage2", domain: "jolt.stage2_uniskip_domain", num_rounds: 1, degree: 6, claim: "stage2.product_virtual.weighted_stage1_outputs", kernel: None, relation: Some("jolt.stage2.product_virtual.uniskip"), claim_value: "stage2.product_virtual.uniskip.claim_expr", input_openings: "stage2.input.stage1.Product|stage2.input.stage1.ShouldBranch|stage2.input.stage1.ShouldJump" }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_read_write.input", stage: "stage2", domain: "jolt.stage2_ram_rw_domain", num_rounds: 32, degree: 3, claim: "stage2.ram_read_write.weighted_values", kernel: None, relation: Some("jolt.stage2.ram.read_write"), claim_value: "stage2.ram_read_write.claim_expr", input_openings: "stage2.input.stage1.RamReadValue|stage2.input.stage1.RamWriteValue" }, + Stage2SumcheckClaimPlan { symbol: "stage2.product_virtual.remainder.input", stage: "stage2", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage2.product_virtual.uniskip.opening", kernel: None, relation: Some("jolt.stage2.product_virtual.remainder"), claim_value: "stage2.product_virtual.uniskip.eval.UnivariateSkip", input_openings: "stage2.product_virtual.uniskip.opening.UnivariateSkip" }, + Stage2SumcheckClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.input", stage: "stage2", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage2.instruction_lookup.weighted_operands", kernel: None, relation: Some("jolt.stage2.instruction_lookup.claim_reduction"), claim_value: "stage2.instruction_lookup.claim_reduction.claim_expr", input_openings: "stage2.input.stage1.LookupOutput|stage2.input.stage1.LeftLookupOperand|stage2.input.stage1.RightLookupOperand|stage2.input.stage1.LeftInstructionInput|stage2.input.stage1.RightInstructionInput" }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_raf.input", stage: "stage2", domain: "jolt.ram_address_domain", num_rounds: 16, degree: 2, claim: "stage2.ram_raf.ram_address", kernel: None, relation: Some("jolt.stage2.ram.raf_evaluation"), claim_value: "stage2.input.stage1.RamAddress", input_openings: "stage2.input.stage1.RamAddress" }, + Stage2SumcheckClaimPlan { symbol: "stage2.ram_output.input", stage: "stage2", domain: "jolt.ram_address_domain", num_rounds: 16, degree: 3, claim: "zero", kernel: None, relation: Some("jolt.stage2.ram.output_check"), claim_value: "stage2.ram_output.zero", input_openings: "" }, +]; +pub const STAGE2_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE2_SUMCHECK_BATCH_1_ROUND_SCHEDULE: &[usize] = &[ + 16, + 16, +]; + +pub const STAGE2_SUMCHECK_BATCHES: &[Stage2SumcheckBatchPlan] = &[ + Stage2SumcheckBatchPlan { symbol: "stage2.product_virtual.uniskip.batch", stage: "stage2", proof_slot: "stage2.product_virtual.uni_skip_first_round", policy: "single_instance", count: 1, ordered_claims: "stage2.product_virtual.uniskip.input", claim_operands: "stage2.product_virtual.uniskip.input", claim_label: "uniskip_claim", round_label: "uniskip_poly", round_schedule: STAGE2_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, + Stage2SumcheckBatchPlan { symbol: "stage2.batch", stage: "stage2", proof_slot: "stage2.sumcheck", policy: "jolt_core_stage2_aligned", count: 5, ordered_claims: "stage2.ram_read_write.input|stage2.product_virtual.remainder.input|stage2.instruction_lookup.claim_reduction.input|stage2.ram_raf.input|stage2.ram_output.input", claim_operands: "stage2.ram_read_write.input|stage2.product_virtual.remainder.input|stage2.instruction_lookup.claim_reduction.input|stage2.ram_raf.input|stage2.ram_output.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE2_SUMCHECK_BATCH_1_ROUND_SCHEDULE }, +]; +pub const STAGE2_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 1, +]; + +pub const STAGE2_SUMCHECK_DRIVER_1_ROUND_SCHEDULE: &[usize] = &[ + 16, + 16, +]; + +pub const STAGE2_SUMCHECK_DRIVERS: &[Stage2SumcheckDriverPlan] = &[ + Stage2SumcheckDriverPlan { symbol: "stage2.product_virtual.uniskip.sumcheck", stage: "stage2", proof_slot: "stage2.product_virtual.uni_skip_first_round", kernel: None, relation: Some("jolt.stage2.product_virtual.uniskip"), batch: "stage2.product_virtual.uniskip.batch", policy: "univariate_skip", round_schedule: STAGE2_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "uniskip_claim", round_label: "uniskip_poly", num_rounds: 1, degree: 6 }, + Stage2SumcheckDriverPlan { symbol: "stage2.sumcheck", stage: "stage2", proof_slot: "stage2.sumcheck", kernel: None, relation: Some("jolt.stage2.batched"), batch: "stage2.batch", policy: "jolt_core_stage2_aligned", round_schedule: STAGE2_SUMCHECK_DRIVER_1_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 32, degree: 3 }, +]; +pub const STAGE2_SUMCHECK_INSTANCE_RESULTS: &[Stage2SumcheckInstanceResultPlan] = &[ + Stage2SumcheckInstanceResultPlan { symbol: "stage2.product_virtual.uniskip.instance", source: "stage2.product_virtual.uniskip.sumcheck", claim: "stage2.product_virtual.uniskip.input", relation: "jolt.stage2.product_virtual.uniskip", index: 0, point_arity: 1, num_rounds: 1, round_offset: 0, point_order: "as_is", degree: 6 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_read_write.instance", source: "stage2.sumcheck", claim: "stage2.ram_read_write.input", relation: "jolt.stage2.ram.read_write", index: 0, point_arity: 32, num_rounds: 32, round_offset: 0, point_order: "reverse", degree: 3 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.product_virtual.remainder.instance", source: "stage2.sumcheck", claim: "stage2.product_virtual.remainder.input", relation: "jolt.stage2.product_virtual.remainder", index: 1, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 3 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.instruction_lookup.claim_reduction.instance", source: "stage2.sumcheck", claim: "stage2.instruction_lookup.claim_reduction.input", relation: "jolt.stage2.instruction_lookup.claim_reduction", index: 2, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 2 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_raf.instance", source: "stage2.sumcheck", claim: "stage2.ram_raf.input", relation: "jolt.stage2.ram.raf_evaluation", index: 3, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 2 }, + Stage2SumcheckInstanceResultPlan { symbol: "stage2.ram_output.instance", source: "stage2.sumcheck", claim: "stage2.ram_output.input", relation: "jolt.stage2.ram.output_check", index: 4, point_arity: 16, num_rounds: 16, round_offset: 16, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE2_SUMCHECK_EVALS: &[Stage2SumcheckEvalPlan] = &[ + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.uniskip.eval.UnivariateSkip", source: "stage2.product_virtual.uniskip.sumcheck", name: "stage2.product_virtual.uniskip.eval.UnivariateSkip", index: 0, oracle: "UnivariateSkip" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamVal", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamVal", index: 0, oracle: "RamVal" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamRa", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamRa", index: 1, oracle: "RamRa" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_read_write.eval.RamInc", source: "stage2.sumcheck", name: "stage2.ram_read_write.eval.RamInc", index: 2, oracle: "RamInc" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.LeftInstructionInput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.LeftInstructionInput", index: 0, oracle: "LeftInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.RightInstructionInput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.RightInstructionInput", index: 1, oracle: "RightInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagJump", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagJump", index: 2, oracle: "OpFlagJump" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD", index: 3, oracle: "OpFlagWriteLookupOutputToRD" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.LookupOutput", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.LookupOutput", index: 4, oracle: "LookupOutput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.InstructionFlagBranch", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.InstructionFlagBranch", index: 5, oracle: "InstructionFlagBranch" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.NextIsNoop", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.NextIsNoop", index: 6, oracle: "NextIsNoop" }, + Stage2SumcheckEvalPlan { symbol: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction", source: "stage2.sumcheck", name: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction", index: 7, oracle: "OpFlagVirtualInstruction" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", index: 0, oracle: "LookupOutput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", index: 1, oracle: "LeftLookupOperand" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", index: 2, oracle: "RightLookupOperand" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", index: 3, oracle: "LeftInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", source: "stage2.sumcheck", name: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", index: 4, oracle: "RightInstructionInput" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_raf.eval.RamRa", source: "stage2.sumcheck", name: "stage2.ram_raf.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage2SumcheckEvalPlan { symbol: "stage2.ram_output.eval.RamValFinal", source: "stage2.sumcheck", name: "stage2.ram_output.eval.RamValFinal", index: 0, oracle: "RamValFinal" }, +]; + +pub const STAGE2_POINT_SLICES: &[Stage2PointSlicePlan] = &[ + Stage2PointSlicePlan { symbol: "stage2.ram_read_write.point.RamInc", source: "stage2.ram_read_write.instance", offset: 16, length: 16, input: "stage2.ram_read_write.instance" }, +]; + +pub const STAGE2_POINT_CONCATS: &[Stage2PointConcatPlan] = &[ + Stage2PointConcatPlan { symbol: "stage2.ram_raf.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: "stage2.ram_raf.instance|stage2.input.stage1.RamAddress" }, +]; +pub const STAGE2_OPENING_CLAIMS: &[Stage2OpeningClaimPlan] = &[ + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.uniskip.opening.UnivariateSkip", oracle: "UnivariateSkip", domain: "jolt.stage2_uniskip_domain", point_arity: 1, claim_kind: "virtual", point_source: "stage2.product_virtual.uniskip.instance", eval_source: "stage2.product_virtual.uniskip.eval.UnivariateSkip" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamVal", oracle: "RamVal", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_read_write.instance", eval_source: "stage2.ram_read_write.eval.RamVal" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_read_write.instance", eval_source: "stage2.ram_read_write.eval.RamRa" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_read_write.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage2.ram_read_write.point.RamInc", eval_source: "stage2.ram_read_write.eval.RamInc" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.LeftInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.RightInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagJump" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagWriteLookupOutputToRD" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.LookupOutput" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.InstructionFlagBranch", oracle: "InstructionFlagBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.InstructionFlagBranch" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.NextIsNoop", oracle: "NextIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.NextIsNoop" }, + Stage2OpeningClaimPlan { symbol: "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.product_virtual.remainder.instance", eval_source: "stage2.product_virtual.remainder.eval.OpFlagVirtualInstruction" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LookupOutput" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.instruction_lookup.claim_reduction.instance", eval_source: "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_raf.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage2.ram_raf.point.RamRa", eval_source: "stage2.ram_raf.eval.RamRa" }, + Stage2OpeningClaimPlan { symbol: "stage2.ram_output.opening.RamValFinal", oracle: "RamValFinal", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage2.ram_output.instance", eval_source: "stage2.ram_output.eval.RamValFinal" }, +]; + +pub const STAGE2_OPENING_BATCHES: &[Stage2OpeningBatchPlan] = &[ + Stage2OpeningBatchPlan { symbol: "stage2.openings", stage: "stage2", proof_slot: "stage2.openings", policy: "jolt_stage2_output_order", count: 18, ordered_claims: "stage2.ram_read_write.opening.RamVal|stage2.ram_read_write.opening.RamRa|stage2.ram_read_write.opening.RamInc|stage2.product_virtual.remainder.opening.LeftInstructionInput|stage2.product_virtual.remainder.opening.RightInstructionInput|stage2.product_virtual.remainder.opening.OpFlagJump|stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD|stage2.product_virtual.remainder.opening.LookupOutput|stage2.product_virtual.remainder.opening.InstructionFlagBranch|stage2.product_virtual.remainder.opening.NextIsNoop|stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction|stage2.instruction_lookup.claim_reduction.opening.LookupOutput|stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand|stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand|stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput|stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput|stage2.ram_raf.opening.RamRa|stage2.ram_output.opening.RamValFinal", claim_operands: "stage2.ram_read_write.opening.RamVal|stage2.ram_read_write.opening.RamRa|stage2.ram_read_write.opening.RamInc|stage2.product_virtual.remainder.opening.LeftInstructionInput|stage2.product_virtual.remainder.opening.RightInstructionInput|stage2.product_virtual.remainder.opening.OpFlagJump|stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD|stage2.product_virtual.remainder.opening.LookupOutput|stage2.product_virtual.remainder.opening.InstructionFlagBranch|stage2.product_virtual.remainder.opening.NextIsNoop|stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction|stage2.instruction_lookup.claim_reduction.opening.LookupOutput|stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand|stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand|stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput|stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput|stage2.ram_raf.opening.RamRa|stage2.ram_output.opening.RamValFinal" }, +]; +pub const STAGE2_PROGRAM: Stage2VerifierProgramPlan = Stage2VerifierProgramPlan { + params: STAGE2_PARAMS, + steps: STAGE2_PROGRAM_STEPS, + transcript_squeezes: STAGE2_TRANSCRIPT_SQUEEZES, + opening_inputs: STAGE2_OPENING_INPUTS, + field_constants: STAGE2_FIELD_CONSTANTS, + field_exprs: STAGE2_FIELD_EXPRS, + claims: STAGE2_SUMCHECK_CLAIMS, + batches: STAGE2_SUMCHECK_BATCHES, + drivers: STAGE2_SUMCHECK_DRIVERS, + instance_results: STAGE2_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE2_SUMCHECK_EVALS, + point_slices: STAGE2_POINT_SLICES, + point_concats: STAGE2_POINT_CONCATS, + opening_claims: STAGE2_OPENING_CLAIMS, + opening_batches: STAGE2_OPENING_BATCHES, +}; + +const PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START: i64 = -1; +const PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE: usize = 3; + +pub fn verify_stage2( + proof: &Stage2Proof, + opening_inputs: &[Stage2OpeningInputValue], + ram: Option<&Stage2RamData<'_>>, + transcript: &mut T, +) -> Result, VerifyStage2Error> +where + T: Transcript, +{ + verify_stage2_with_program(&STAGE2_PROGRAM, proof, opening_inputs, ram, transcript) +} + +pub fn verify_stage2_with_program( + program: &'static Stage2VerifierProgramPlan, + proof: &Stage2Proof, + opening_inputs: &[Stage2OpeningInputValue], + ram: Option<&Stage2RamData<'_>>, + transcript: &mut T, +) -> Result, VerifyStage2Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage2Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = Stage2ValueStore::with_opening_inputs(program, opening_inputs)?; + store.seed_constants(program); + let mut artifacts = Stage2ExecutionArtifacts::default(); + if program.steps.is_empty() { + for squeeze in program.transcript_squeezes { + verify_stage2_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + for driver in program.drivers { + verify_stage2_driver(program, driver, proof, ram, &mut store, transcript, &mut artifacts)?; + } + } else { + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage2Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage2_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "sumcheck_driver" => { + let driver = find_plan(program.drivers, step.symbol).ok_or(VerifyStage2Error::MissingProof { + driver: step.symbol, + })?; + verify_stage2_driver(program, driver, proof, ram, &mut store, transcript, &mut artifacts)?; + } + _ => { + return Err(VerifyStage2Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage2 program step", + }); + } + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage2_verifier_program() -> &'static Stage2VerifierProgramPlan { + &STAGE2_PROGRAM +} + +fn verify_stage2_squeeze( + program: &'static Stage2VerifierProgramPlan, + squeeze: &'static Stage2TranscriptSqueezePlan, + store: &mut Stage2ValueStore, + transcript: &mut T, + artifacts: &mut Stage2ExecutionArtifacts, +) -> Result<(), VerifyStage2Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(program, squeeze, &values)?; + artifacts.challenge_vectors.push(Stage2ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn verify_stage2_driver( + program: &'static Stage2VerifierProgramPlan, + driver: &'static Stage2SumcheckDriverPlan, + proof: &Stage2Proof, + ram: Option<&Stage2RamData<'_>>, + store: &mut Stage2ValueStore, + transcript: &mut T, + artifacts: &mut Stage2ExecutionArtifacts, +) -> Result<(), VerifyStage2Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage2Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage2.product_virtual.uniskip" => { + verify_product_virtual_uniskip(program, driver, proof, store, transcript)? + } + "jolt.stage2.batched" => verify_batched_stage2(program, driver, proof, ram, store, transcript)?, + relation => return Err(VerifyStage2Error::UnsupportedRelation { relation }), + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_product_virtual_uniskip( + program: &'static Stage2VerifierProgramPlan, + driver: &'static Stage2SumcheckDriverPlan, + proof: &Stage2SumcheckOutput, + store: &mut Stage2ValueStore, + transcript: &mut T, +) -> Result, VerifyStage2Error> +where + T: Transcript, +{ + validate_driver_symbol(driver, proof)?; + let [poly] = proof.proof.round_polynomials.as_slice() else { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "unexpected product uniskip round count", + }); + }; + if polynomial_degree(poly) > driver.degree { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "product uniskip polynomial exceeds degree bound", + }); + } + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claim = batch_claims(program.claims, batch)? + .into_iter() + .next() + .ok_or(VerifyStage2Error::MissingClaim { + batch: batch.symbol, + claim: "stage2.product_virtual.uniskip.input", + })?; + let input_claim = store.claim_value(program, claim)?; + if !product_uniskip_sum_matches(poly, input_claim) { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "product uniskip input claim mismatch", + }); + } + append_univariate_poly(transcript, driver.round_label, poly); + let r0 = transcript.challenge(); + if !proof.point.is_empty() && proof.point != [r0] { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "product uniskip point mismatch", + }); + } + let eval = poly.evaluate(r0); + append_labeled_scalar(transcript, "opening_claim", &eval); + let output = Stage2SumcheckOutput { + driver: driver.symbol, + point: vec![r0], + evals: driver_evals(program, driver.symbol, eval), + proof: proof.proof.clone(), + }; + verify_named_evals(driver.symbol, &output.evals, &proof.evals)?; + store.observe_sumcheck_output(program, &output)?; + Ok(output) +} + +fn verify_batched_stage2( + program: &'static Stage2VerifierProgramPlan, + driver: &'static Stage2SumcheckDriverPlan, + proof: &Stage2SumcheckOutput, + ram: Option<&Stage2RamData<'_>>, + store: &mut Stage2ValueStore, + transcript: &mut T, +) -> Result, VerifyStage2Error> +where + T: Transcript, +{ + validate_driver_symbol(driver, proof)?; + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let input_claims = store.batch_claim_values(program, batch)?; + for claim in &input_claims { + append_labeled_scalar(transcript, batch.claim_label, claim); + } + let batching_coeffs = transcript.challenge_vector(claims.len()); + let claimed_sum = input_claims + .iter() + .zip(claims.iter()) + .zip(&batching_coeffs) + .map(|((claim, plan), coefficient)| { + claim.mul_pow_2(driver.num_rounds - plan.num_rounds) * *coefficient + }) + .sum::(); + let claim = SumcheckClaim::new(driver.num_rounds, driver.degree, claimed_sum); + let round_proofs = proof + .proof + .round_polynomials + .iter() + .map(|poly| CompressedLabeledRoundPoly::new(poly, driver.round_label.as_bytes())) + .collect::>(); + let output = SumcheckVerifier::verify(&claim, &round_proofs, transcript) + .map_err(|error| VerifyStage2Error::Sumcheck { + driver: driver.symbol, + error, + })?; + if !proof.point.is_empty() && proof.point != output.point { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "batched point mismatch", + }); + } + let expected = + expected_batched_output_claim(program, driver, &*store, &proof.evals, &output.point, &batching_coeffs, ram)?; + if output.value != expected { + return Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "batched output claim mismatch", + }); + } + let verified = Stage2SumcheckOutput { + driver: driver.symbol, + point: output.point, + evals: proof.evals.clone(), + proof: proof.proof.clone(), + }; + store.observe_sumcheck_output(program, &verified)?; + super::common::append_opening_claims( + program.opening_inputs, + program.opening_claims, + program.opening_batches, + &mut store.0, + transcript, + &verified.evals, + |batch, claim| VerifyStage2Error::MissingClaim { batch, claim }, + |symbol| VerifyStage2Error::MissingValue { symbol }, + )?; + Ok(verified) +} + +impl Stage2ValueStore { + fn with_opening_inputs( + program: &'static Stage2VerifierProgramPlan, + inputs: &[Stage2OpeningInputValue], + ) -> Result { + Ok(Self(super::common::ValueStore::with_opening_inputs( + inputs, + program.opening_inputs, + )?)) + } + + fn seed_constants(&mut self, program: &'static Stage2VerifierProgramPlan) { + self.0.seed_constants(program.field_constants); + } + + fn observe_challenge_vector( + &mut self, + program: &'static Stage2VerifierProgramPlan, + plan: &'static Stage2TranscriptSqueezePlan, + values: &[F], + ) -> Result<(), VerifyStage2Error> { + self.0.observe_challenge_vector(plan, values, |input, expected, actual| { + VerifyStage2Error::InvalidInputLength { input, expected, actual } + })?; + self.evaluate_available_points(program)?; + self.evaluate_available_field_exprs(program)?; + Ok(()) + } + + fn observe_sumcheck_output( + &mut self, + program: &'static Stage2VerifierProgramPlan, + output: &Stage2SumcheckOutput, + ) -> Result<(), VerifyStage2Error> { + self.0.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + _ => { + return Err(VerifyStage2Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage2Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage2Error::MissingValue { symbol }, + )?; + self.evaluate_available_points(program)?; + self.evaluate_available_field_exprs(program)?; + Ok(()) + } + + fn claim_value( + &mut self, + program: &'static Stage2VerifierProgramPlan, + claim: &Stage2SumcheckClaimPlan, + ) -> Result { + self.evaluate_available_field_exprs(program)?; + self.scalar(claim.claim_value) + } + + fn batch_claim_values( + &mut self, + program: &'static Stage2VerifierProgramPlan, + batch: &Stage2SumcheckBatchPlan, + ) -> Result, VerifyStage2Error> { + super::common::symbol_list(batch.claim_operands) + .map(|symbol| { + let claim = find_plan(program.claims, symbol).ok_or(VerifyStage2Error::MissingClaim { + batch: batch.symbol, + claim: symbol, + })?; + self.claim_value(program, claim) + }) + .collect() + } + + fn evaluate_available_points( + &mut self, + program: &'static Stage2VerifierProgramPlan, + ) -> Result<(), VerifyStage2Error> { + self.0.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage2Error::InvalidInputLength { + input, + expected, + actual, + }, + ) + } + + fn evaluate_available_field_exprs( + &mut self, + program: &'static Stage2VerifierProgramPlan, + ) -> Result<(), VerifyStage2Error> { + self.0 + .evaluate_available_field_exprs(program.field_exprs, evaluate_stage2_field_expr) + } + + fn scalar(&self, symbol: &'static str) -> Result { + self.0 + .scalar_or(symbol, |symbol| VerifyStage2Error::MissingValue { symbol }) + } + + fn point(&self, symbol: &'static str) -> Result<&[F], VerifyStage2Error> { + self.0 + .point_or(symbol, |symbol| VerifyStage2Error::MissingValue { symbol }) + } + + fn try_point(&self, symbol: &str) -> Option<&[F]> { + self.0.try_point(symbol) + } +} + +fn evaluate_stage2_field_expr( + expr: &Stage2FieldExprPlan, + operands: &[F], +) -> Result { + match expr.formula { + "opening_eval" => Ok(single_operand(expr.symbol, operands)?), + "jolt_stage2_product_virtual_uniskip_input" => { + require_operand_count(expr.symbol, 4, operands.len())?; + let weights = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + operands[0], + ); + Ok(weights[0] * operands[1] + weights[1] * operands[2] + weights[2] * operands[3]) + } + "jolt_stage2_ram_read_write_input" => { + require_operand_count(expr.symbol, 3, operands.len())?; + Ok(operands[1] + operands[0] * operands[2]) + } + "jolt_stage2_instruction_lookup_input" => { + require_operand_count(expr.symbol, 6, operands.len())?; + let gamma = operands[0]; + let gamma2 = gamma.square(); + let gamma3 = gamma2 * gamma; + let gamma4 = gamma2.square(); + Ok(operands[1] + + gamma * operands[2] + + gamma2 * operands[3] + + gamma3 * operands[4] + + gamma4 * operands[5]) + } + "field.add" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] + operands[1]) + } + "field.sub" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] - operands[1]) + } + "field.mul" => { + require_operand_count(expr.symbol, 2, operands.len())?; + Ok(operands[0] * operands[1]) + } + "field.neg" => { + require_operand_count(expr.symbol, 1, operands.len())?; + Ok(-operands[0]) + } + formula => { + if let Some(exponent) = formula.strip_prefix("field.pow:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let exponent = exponent.parse::().map_err(|_| { + VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + return Ok(pow_field(operands[0], exponent)); + } + if let Some(spec) = formula.strip_prefix("poly.lagrange_basis_eval:") { + require_operand_count(expr.symbol, 1, operands.len())?; + let parts = spec.split(':').collect::>(); + if parts.len() != 3 { + return Err(VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }); + } + let domain_start = parts[0].parse::().map_err(|_| { + VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + let domain_size = parts[1].parse::().map_err(|_| { + VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + let index = parts[2].parse::().map_err(|_| { + VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + } + })?; + let weights = lagrange_evals(domain_start, domain_size, operands[0]); + return weights + .get(index) + .copied() + .ok_or(VerifyStage2Error::InvalidInputLength { + input: expr.symbol, + expected: index + 1, + actual: weights.len(), + }); + } + Err(VerifyStage2Error::UnsupportedFieldExpr { + symbol: expr.symbol, + formula, + }) + } + } +} + +fn expected_batched_output_claim( + program: &'static Stage2VerifierProgramPlan, + driver: &'static Stage2SumcheckDriverPlan, + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage2Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage2Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let value = match instance.relation { + "jolt.stage2.ram.read_write" => expected_ram_read_write(store, evals, local_point)?, + "jolt.stage2.product_virtual.remainder" => { + expected_product_remainder(store, evals, local_point)? + } + "jolt.stage2.instruction_lookup.claim_reduction" => { + expected_instruction_lookup(store, evals, local_point)? + } + "jolt.stage2.ram.raf_evaluation" => expected_ram_raf(evals, local_point, ram)?, + "jolt.stage2.ram.output_check" => expected_ram_output(store, evals, local_point, ram)?, + relation => return Err(VerifyStage2Error::UnsupportedRelation { relation }), + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_ram_read_write( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[Fr], +) -> Result { + let r_cycle_stage1 = store.point("stage2.input.stage1.RamReadValue")?; + let log_t = r_cycle_stage1.len(); + let r_cycle = reverse_slice(&local_point[..log_t]); + let eq_eval = EqPolynomial::::mle(r_cycle_stage1, &r_cycle); + let gamma = store.scalar("stage2.ram_read_write.gamma")?; + let val = eval_by_name(evals, "stage2.ram_read_write.eval.RamVal")?; + let ra = eval_by_name(evals, "stage2.ram_read_write.eval.RamRa")?; + let inc = eval_by_name(evals, "stage2.ram_read_write.eval.RamInc")?; + Ok(eq_eval * ra * (val + gamma * (val + inc))) +} + +fn expected_product_remainder( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[Fr], +) -> Result { + let tau_low = store.point("stage2.input.stage1.Product")?; + let tau_high = store.scalar("stage2.product_virtual.tau_high")?; + let r0 = *store + .point("stage2.product_virtual.uniskip.sumcheck")? + .first() + .ok_or(VerifyStage2Error::MissingValue { + symbol: "stage2.product_virtual.uniskip.sumcheck", + })?; + let r_tail = reverse_slice(local_point); + let low = EqPolynomial::::mle(tau_low, &r_tail); + let high = lagrange_kernel_eval( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + tau_high, + r0, + ); + let weights = lagrange_evals( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START, + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE, + r0, + ); + let left = weights[0] + * eval_by_name(evals, "stage2.product_virtual.remainder.eval.LeftInstructionInput")? + + weights[1] * eval_by_name(evals, "stage2.product_virtual.remainder.eval.LookupOutput")? + + weights[2] * eval_by_name(evals, "stage2.product_virtual.remainder.eval.OpFlagJump")?; + let right = weights[0] + * eval_by_name(evals, "stage2.product_virtual.remainder.eval.RightInstructionInput")? + + weights[1] + * eval_by_name(evals, "stage2.product_virtual.remainder.eval.InstructionFlagBranch")? + + weights[2] + * (Fr::from_u64(1) + - eval_by_name(evals, "stage2.product_virtual.remainder.eval.NextIsNoop")?); + Ok(high * low * left * right) +} + +fn expected_instruction_lookup( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[Fr], +) -> Result { + let opening_point = reverse_slice(local_point); + let r_spartan = store.point("stage2.input.stage1.LookupOutput")?; + let eq_eval = EqPolynomial::::mle(&opening_point, r_spartan); + let gamma = store.scalar("stage2.instruction_lookup.gamma")?; + let gamma2 = gamma.square(); + let gamma3 = gamma2 * gamma; + let gamma4 = gamma2.square(); + let weighted = eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LookupOutput", + )? + gamma + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LeftLookupOperand", + )? + + gamma2 + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.RightLookupOperand", + )? + + gamma3 + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.LeftInstructionInput", + )? + + gamma4 + * eval_by_name( + evals, + "stage2.instruction_lookup.claim_reduction.eval.RightInstructionInput", + )?; + Ok(eq_eval * weighted) +} + +fn expected_ram_raf( + evals: &[Stage2NamedEval], + local_point: &[Fr], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let ram = ram.ok_or(VerifyStage2Error::MissingRam { + relation: "jolt.stage2.ram.raf_evaluation", + })?; + let address = reverse_slice(local_point); + let unmap = unmap_eval(ram.log_k, ram.start_address, &address); + Ok(unmap * eval_by_name(evals, "stage2.ram_raf.eval.RamRa")?) +} + +fn expected_ram_output( + store: &Stage2ValueStore, + evals: &[Stage2NamedEval], + local_point: &[Fr], + ram: Option<&Stage2RamData<'_>>, +) -> Result { + let ram = ram.ok_or(VerifyStage2Error::MissingRam { + relation: "jolt.stage2.ram.output_check", + })?; + let layout = ram.output_layout.ok_or(VerifyStage2Error::MissingRam { + relation: "jolt.stage2.ram.output_check.layout", + })?; + let r_address = store.point("stage2.ram_output.r_address")?; + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle(r_address, &opening_point); + let io_mask = range_mask_eval(layout.io_start, layout.io_end, &opening_point); + let val_io = sparse_final_ram_eval( + ram.final_ram, + layout.io_start, + layout.io_end, + &opening_point, + ); + let val_final = eval_by_name(evals, "stage2.ram_output.eval.RamValFinal")?; + Ok(eq_eval * io_mask * (val_final - val_io)) +} + +fn driver_evals( + program: &'static Stage2VerifierProgramPlan, + driver: &'static str, + value: Fr, +) -> Vec> { + program + .evals + .iter() + .filter(|eval| eval.source == driver) + .map(|eval| Stage2NamedEval { + name: eval.name, + oracle: eval.oracle, + value, + }) + .collect() +} + +fn verify_named_evals( + driver: &'static str, + expected: &[Stage2NamedEval], + actual: &[Stage2NamedEval], +) -> Result<(), VerifyStage2Error> { + if expected.len() != actual.len() { + return Err(VerifyStage2Error::InvalidProof { + driver, + reason: "eval count mismatch", + }); + } + for (expected, actual) in expected.iter().zip(actual) { + if expected.name != actual.name || expected.oracle != actual.oracle || expected.value != actual.value { + return Err(VerifyStage2Error::InvalidProof { + driver, + reason: "eval mismatch", + }); + } + } + Ok(()) +} + +fn validate_driver_symbol( + driver: &'static Stage2SumcheckDriverPlan, + proof: &Stage2SumcheckOutput, +) -> Result<(), VerifyStage2Error> { + if proof.driver == driver.symbol { + Ok(()) + } else { + Err(VerifyStage2Error::InvalidProof { + driver: driver.symbol, + reason: "driver symbol mismatch", + }) + } +} + +fn append_univariate_poly(transcript: &mut T, label: &'static str, poly: &UnivariatePoly) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + label.as_bytes(), + poly.coefficients().len() as u64, + )); + for coefficient in poly.coefficients() { + transcript.append(coefficient); + } +} + +fn product_uniskip_sum_matches(poly: &UnivariatePoly, claim: Fr) -> bool { + (0..PRODUCT_VIRTUAL_UNISKIP_DOMAIN_SIZE) + .map(|index| { + poly.evaluate(Fr::from_i64( + PRODUCT_VIRTUAL_UNISKIP_DOMAIN_START + index as i64, + )) + }) + .sum::() + == claim +} + +fn polynomial_degree(poly: &UnivariatePoly) -> usize { + poly.coefficients() + .iter() + .rposition(|coefficient| *coefficient != Fr::from_u64(0)) + .unwrap_or(0) +} + +fn unmap_eval(log_k: usize, start_address: u64, point: &[Fr]) -> Fr { + point + .iter() + .enumerate() + .fold(Fr::from_u64(start_address), |acc, (index, value)| { + acc + value.mul_pow_2(log_k - 1 - index).mul_u64(8) + }) +} + +fn range_mask_eval(start: usize, end: usize, point: &[Fr]) -> Fr { + eq_prefix_sum(end, point) - eq_prefix_sum(start, point) +} + +fn sparse_final_ram_eval(values: &[u64], start: usize, end: usize, point: &[Fr]) -> Fr { + values[start..end] + .iter() + .enumerate() + .filter(|(_, value)| **value != 0) + .map(|(offset, value)| Fr::from_u64(*value) * eq_eval_at_index(start + offset, point)) + .sum() +} + +fn eq_prefix_sum(end: usize, point: &[Fr]) -> Fr { + let domain_len = 1usize << point.len(); + if end >= domain_len { + return Fr::from_u64(1); + } + let mut sum = Fr::from_u64(0); + let mut prefix = Fr::from_u64(1); + for (bit, r) in point.iter().enumerate() { + let mask = 1usize << (point.len() - 1 - bit); + if end & mask == 0 { + prefix *= Fr::from_u64(1) - *r; + } else { + sum += prefix * (Fr::from_u64(1) - *r); + prefix *= *r; + } + } + sum +} + +fn eq_eval_at_index(index: usize, point: &[Fr]) -> Fr { + point.iter().enumerate().fold(Fr::from_u64(1), |acc, (bit, r)| { + let mask = 1usize << (point.len() - 1 - bit); + if index & mask == 0 { + acc * (Fr::from_u64(1) - *r) + } else { + acc * *r + } + }) +} diff --git a/crates/jolt-verifier/src/stages/stage3.rs b/crates/jolt-verifier/src/stages/stage3.rs new file mode 100644 index 0000000000..d22851483a --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage3.rs @@ -0,0 +1,526 @@ +#![allow(dead_code)] + +use super::common::{batch_claims, eval_by_name, find_batch, find_plan, reverse_slice}; +use jolt_field::{Field, Fr}; +use jolt_poly::{EqPlusOnePolynomial, EqPolynomial}; +use jolt_sumcheck::SumcheckError; +use jolt_transcript::{Blake2bTranscript, Transcript}; + +pub type DefaultStage3Transcript = Blake2bTranscript; + +pub type Stage3NamedEval = super::common::StageNamedEval; +pub type Stage3SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage3ChallengeVector = super::common::StageChallengeVector; +pub type Stage3ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage3Proof = super::common::StageProof; +pub type Stage3OpeningInputValue = super::common::StageOpeningInputValue; +pub type Stage3VerifierProgramPlan = super::common::StageVerifierProgramPlan; + +pub use super::common::{ + FieldConstantPlan as Stage3FieldConstantPlan, FieldExprPlan as Stage3FieldExprPlan, + OpeningBatchPlan as Stage3OpeningBatchPlan, + OpeningClaimEqualityPlan as Stage3OpeningClaimEqualityPlan, + OpeningClaimPlan as Stage3OpeningClaimPlan, OpeningInputPlan as Stage3OpeningInputPlan, + PointConcatPlan as Stage3PointConcatPlan, PointSlicePlan as Stage3PointSlicePlan, + ProgramStepPlan as Stage3ProgramStepPlan, StageParams as Stage3Params, + SumcheckBatchPlan as Stage3SumcheckBatchPlan, SumcheckEvalPlan as Stage3SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage3SumcheckInstanceResultPlan, + TranscriptSqueezePlan as Stage3TranscriptSqueezePlan, + SumcheckClaimPlan as Stage3SumcheckClaimPlan, + SumcheckDriverPlan as Stage3SumcheckDriverPlan, +}; + +#[derive(Debug)] +pub enum VerifyStage3Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage3Error); + +pub const STAGE3_PARAMS: Stage3Params = Stage3Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE3_PROGRAM_STEPS: &[Stage3ProgramStepPlan] = &[ + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.spartan_shift.gamma" }, + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.instruction_input.gamma" }, + Stage3ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage3.registers.gamma" }, + Stage3ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage3.sumcheck" }, +]; + +pub const STAGE3_TRANSCRIPT_SQUEEZES: &[Stage3TranscriptSqueezePlan] = &[ + Stage3TranscriptSqueezePlan { symbol: "stage3.spartan_shift.gamma", label: "spartan_shift_gamma", kind: "challenge_scalar", count: 1 }, + Stage3TranscriptSqueezePlan { symbol: "stage3.instruction_input.gamma", label: "instruction_input_gamma", kind: "challenge_scalar", count: 1 }, + Stage3TranscriptSqueezePlan { symbol: "stage3.registers.gamma", label: "registers_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE3_OPENING_INPUTS: &[Stage3OpeningInputPlan] = &[ + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextUnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextUnexpandedPC", oracle: "NextUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextPC", oracle: "NextPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextIsVirtual", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextIsVirtual", oracle: "NextIsVirtual", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.NextIsFirstInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.NextIsFirstInSequence", oracle: "NextIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.NextIsNoop", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.NextIsNoop", oracle: "NextIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.LeftInstructionInput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.product_virtual.RightInstructionInput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.instruction_lookup.LeftInstructionInput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LeftInstructionInput", oracle: "LeftInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage2.instruction_lookup.RightInstructionInput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.RightInstructionInput", oracle: "RightInstructionInput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.RdWriteValue", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.Rs1Value", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage3OpeningInputPlan { symbol: "stage3.input.stage1.Rs2Value", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE3_FIELD_CONSTANTS: &[Stage3FieldConstantPlan] = &[ + Stage3FieldConstantPlan { symbol: "stage3.field.one", field: "bn254_fr", value: 1 }, +]; + +pub const STAGE3_FIELD_EXPRS: &[Stage3FieldExprPlan] = &[ + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma2", kind: "op", formula: "field.pow:2", operands: "stage3.spartan_shift.gamma" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma3", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma2|stage3.spartan_shift.gamma" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.gamma4", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma2|stage3.spartan_shift.gamma2" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextPC", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma|stage3.input.stage1.NextPC" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsVirtual", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma2|stage3.input.stage1.NextIsVirtual" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsFirstInSequence", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma3|stage3.input.stage1.NextIsFirstInSequence" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.one_minus.NextIsNoop", kind: "op", formula: "field.sub", operands: "stage3.field.one|stage3.input.stage2.product_virtual.NextIsNoop" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.term.NextIsNoop", kind: "op", formula: "field.mul", operands: "stage3.spartan_shift.gamma4|stage3.spartan_shift.one_minus.NextIsNoop" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextUnexpandedPCNextPC", kind: "op", formula: "field.add", operands: "stage3.input.stage1.NextUnexpandedPC|stage3.spartan_shift.term.NextPC" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextIsVirtual", kind: "op", formula: "field.add", operands: "stage3.spartan_shift.partial.NextUnexpandedPCNextPC|stage3.spartan_shift.term.NextIsVirtual" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.partial.NextIsFirstInSequence", kind: "op", formula: "field.add", operands: "stage3.spartan_shift.partial.NextIsVirtual|stage3.spartan_shift.term.NextIsFirstInSequence" }, + Stage3FieldExprPlan { symbol: "stage3.spartan_shift.claim_expr", kind: "op", formula: "field.add", operands: "stage3.spartan_shift.partial.NextIsFirstInSequence|stage3.spartan_shift.term.NextIsNoop" }, + Stage3FieldExprPlan { symbol: "stage3.instruction_input.term.LeftInstructionInput", kind: "op", formula: "field.mul", operands: "stage3.instruction_input.gamma|stage3.input.stage2.product_virtual.LeftInstructionInput" }, + Stage3FieldExprPlan { symbol: "stage3.instruction_input.claim_expr", kind: "op", formula: "field.add", operands: "stage3.input.stage2.product_virtual.RightInstructionInput|stage3.instruction_input.term.LeftInstructionInput" }, + Stage3FieldExprPlan { symbol: "stage3.registers.gamma2", kind: "op", formula: "field.pow:2", operands: "stage3.registers.gamma" }, + Stage3FieldExprPlan { symbol: "stage3.registers.term.Rs1Value", kind: "op", formula: "field.mul", operands: "stage3.registers.gamma|stage3.input.stage1.Rs1Value" }, + Stage3FieldExprPlan { symbol: "stage3.registers.term.Rs2Value", kind: "op", formula: "field.mul", operands: "stage3.registers.gamma2|stage3.input.stage1.Rs2Value" }, + Stage3FieldExprPlan { symbol: "stage3.registers.partial.RdWriteValueRs1Value", kind: "op", formula: "field.add", operands: "stage3.input.stage1.RdWriteValue|stage3.registers.term.Rs1Value" }, + Stage3FieldExprPlan { symbol: "stage3.registers.claim_expr", kind: "op", formula: "field.add", operands: "stage3.registers.partial.RdWriteValueRs1Value|stage3.registers.term.Rs2Value" }, +]; +pub const STAGE3_SUMCHECK_CLAIMS: &[Stage3SumcheckClaimPlan] = &[ + Stage3SumcheckClaimPlan { symbol: "stage3.spartan_shift.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage3.spartan_shift.weighted_next_values", kernel: None, relation: Some("jolt.stage3.spartan_shift"), claim_value: "stage3.spartan_shift.claim_expr", input_openings: "stage3.input.stage1.NextUnexpandedPC|stage3.input.stage1.NextPC|stage3.input.stage1.NextIsVirtual|stage3.input.stage1.NextIsFirstInSequence|stage3.input.stage2.product_virtual.NextIsNoop" }, + Stage3SumcheckClaimPlan { symbol: "stage3.instruction_input.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage3.instruction_input.weighted_inputs", kernel: None, relation: Some("jolt.stage3.instruction_input"), claim_value: "stage3.instruction_input.claim_expr", input_openings: "stage3.input.stage2.product_virtual.RightInstructionInput|stage3.input.stage2.product_virtual.LeftInstructionInput" }, + Stage3SumcheckClaimPlan { symbol: "stage3.registers_claim_reduction.input", stage: "stage3", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage3.registers.weighted_register_values", kernel: None, relation: Some("jolt.stage3.registers_claim_reduction"), claim_value: "stage3.registers.claim_expr", input_openings: "stage3.input.stage1.RdWriteValue|stage3.input.stage1.Rs1Value|stage3.input.stage1.Rs2Value" }, +]; +pub const STAGE3_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 16, +]; + +pub const STAGE3_SUMCHECK_BATCHES: &[Stage3SumcheckBatchPlan] = &[ + Stage3SumcheckBatchPlan { symbol: "stage3.batch", stage: "stage3", proof_slot: "stage3.sumcheck", policy: "jolt_core_stage3_aligned", count: 3, ordered_claims: "stage3.spartan_shift.input|stage3.instruction_input.input|stage3.registers_claim_reduction.input", claim_operands: "stage3.spartan_shift.input|stage3.instruction_input.input|stage3.registers_claim_reduction.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE3_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE3_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 16, +]; + +pub const STAGE3_SUMCHECK_DRIVERS: &[Stage3SumcheckDriverPlan] = &[ + Stage3SumcheckDriverPlan { symbol: "stage3.sumcheck", stage: "stage3", proof_slot: "stage3.sumcheck", kernel: None, relation: Some("jolt.stage3.batched"), batch: "stage3.batch", policy: "jolt_core_stage3_aligned", round_schedule: STAGE3_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 16, degree: 3 }, +]; +pub const STAGE3_SUMCHECK_INSTANCE_RESULTS: &[Stage3SumcheckInstanceResultPlan] = &[ + Stage3SumcheckInstanceResultPlan { symbol: "stage3.spartan_shift.instance", source: "stage3.sumcheck", claim: "stage3.spartan_shift.input", relation: "jolt.stage3.spartan_shift", index: 0, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 2 }, + Stage3SumcheckInstanceResultPlan { symbol: "stage3.instruction_input.instance", source: "stage3.sumcheck", claim: "stage3.instruction_input.input", relation: "jolt.stage3.instruction_input", index: 1, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 3 }, + Stage3SumcheckInstanceResultPlan { symbol: "stage3.registers_claim_reduction.instance", source: "stage3.sumcheck", claim: "stage3.registers_claim_reduction.input", relation: "jolt.stage3.registers_claim_reduction", index: 2, point_arity: 16, num_rounds: 16, round_offset: 0, point_order: "reverse", degree: 2 }, +]; + +pub const STAGE3_SUMCHECK_EVALS: &[Stage3SumcheckEvalPlan] = &[ + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.UnexpandedPC", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.UnexpandedPC", index: 0, oracle: "UnexpandedPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.PC", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.PC", index: 1, oracle: "PC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.OpFlagVirtualInstruction", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.OpFlagVirtualInstruction", index: 2, oracle: "OpFlagVirtualInstruction" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence", index: 3, oracle: "OpFlagIsFirstInSequence" }, + Stage3SumcheckEvalPlan { symbol: "stage3.spartan_shift.eval.InstructionFlagIsNoop", source: "stage3.sumcheck", name: "stage3.spartan_shift.eval.InstructionFlagIsNoop", index: 4, oracle: "InstructionFlagIsNoop" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", index: 5, oracle: "InstructionFlagLeftOperandIsRs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Rs1Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Rs1Value", index: 6, oracle: "Rs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", index: 7, oracle: "InstructionFlagLeftOperandIsPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.UnexpandedPC", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.UnexpandedPC", index: 8, oracle: "UnexpandedPC" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", index: 9, oracle: "InstructionFlagRightOperandIsRs2Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Rs2Value", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Rs2Value", index: 10, oracle: "Rs2Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", index: 11, oracle: "InstructionFlagRightOperandIsImm" }, + Stage3SumcheckEvalPlan { symbol: "stage3.instruction_input.eval.Imm", source: "stage3.sumcheck", name: "stage3.instruction_input.eval.Imm", index: 12, oracle: "Imm" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.RdWriteValue", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.RdWriteValue", index: 13, oracle: "RdWriteValue" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.Rs1Value", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.Rs1Value", index: 14, oracle: "Rs1Value" }, + Stage3SumcheckEvalPlan { symbol: "stage3.registers_claim_reduction.eval.Rs2Value", source: "stage3.sumcheck", name: "stage3.registers_claim_reduction.eval.Rs2Value", index: 15, oracle: "Rs2Value" }, +]; + +pub const STAGE3_POINT_SLICES: &[Stage3PointSlicePlan] = &[ + +]; + +pub const STAGE3_POINT_CONCATS: &[Stage3PointConcatPlan] = &[ + +]; +pub const STAGE3_OPENING_CLAIMS: &[Stage3OpeningClaimPlan] = &[ + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.UnexpandedPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.PC" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.OpFlagVirtualInstruction" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.OpFlagIsFirstInSequence" }, + Stage3OpeningClaimPlan { symbol: "stage3.spartan_shift.opening.InstructionFlagIsNoop", oracle: "InstructionFlagIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.spartan_shift.instance", eval_source: "stage3.spartan_shift.eval.InstructionFlagIsNoop" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", oracle: "InstructionFlagLeftOperandIsRs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Rs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", oracle: "InstructionFlagLeftOperandIsPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.UnexpandedPC" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", oracle: "InstructionFlagRightOperandIsRs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Rs2Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", oracle: "InstructionFlagRightOperandIsImm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm" }, + Stage3OpeningClaimPlan { symbol: "stage3.instruction_input.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.instruction_input.instance", eval_source: "stage3.instruction_input.eval.Imm" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.RdWriteValue" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.Rs1Value" }, + Stage3OpeningClaimPlan { symbol: "stage3.registers_claim_reduction.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage3.registers_claim_reduction.instance", eval_source: "stage3.registers_claim_reduction.eval.Rs2Value" }, +]; + +pub const STAGE3_OPENING_EQUALITIES: &[Stage3OpeningClaimEqualityPlan] = &[ + Stage3OpeningClaimEqualityPlan { symbol: "stage3.instruction_input.left_claim_consistency", mode: "point_and_eval", lhs: "stage3.input.stage2.product_virtual.LeftInstructionInput", rhs: "stage3.input.stage2.instruction_lookup.LeftInstructionInput" }, + Stage3OpeningClaimEqualityPlan { symbol: "stage3.instruction_input.right_claim_consistency", mode: "point_and_eval", lhs: "stage3.input.stage2.product_virtual.RightInstructionInput", rhs: "stage3.input.stage2.instruction_lookup.RightInstructionInput" }, +]; + +pub const STAGE3_OPENING_BATCHES: &[Stage3OpeningBatchPlan] = &[ + Stage3OpeningBatchPlan { symbol: "stage3.openings", stage: "stage3", proof_slot: "stage3.openings", policy: "jolt_stage3_output_order", count: 16, ordered_claims: "stage3.spartan_shift.opening.UnexpandedPC|stage3.spartan_shift.opening.PC|stage3.spartan_shift.opening.OpFlagVirtualInstruction|stage3.spartan_shift.opening.OpFlagIsFirstInSequence|stage3.spartan_shift.opening.InstructionFlagIsNoop|stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value|stage3.instruction_input.opening.Rs1Value|stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC|stage3.instruction_input.opening.UnexpandedPC|stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value|stage3.instruction_input.opening.Rs2Value|stage3.instruction_input.opening.InstructionFlagRightOperandIsImm|stage3.instruction_input.opening.Imm|stage3.registers_claim_reduction.opening.RdWriteValue|stage3.registers_claim_reduction.opening.Rs1Value|stage3.registers_claim_reduction.opening.Rs2Value", claim_operands: "stage3.spartan_shift.opening.UnexpandedPC|stage3.spartan_shift.opening.PC|stage3.spartan_shift.opening.OpFlagVirtualInstruction|stage3.spartan_shift.opening.OpFlagIsFirstInSequence|stage3.spartan_shift.opening.InstructionFlagIsNoop|stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value|stage3.instruction_input.opening.Rs1Value|stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC|stage3.instruction_input.opening.UnexpandedPC|stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value|stage3.instruction_input.opening.Rs2Value|stage3.instruction_input.opening.InstructionFlagRightOperandIsImm|stage3.instruction_input.opening.Imm|stage3.registers_claim_reduction.opening.RdWriteValue|stage3.registers_claim_reduction.opening.Rs1Value|stage3.registers_claim_reduction.opening.Rs2Value" }, +]; +pub const STAGE3_PROGRAM: Stage3VerifierProgramPlan = Stage3VerifierProgramPlan { + params: STAGE3_PARAMS, + steps: STAGE3_PROGRAM_STEPS, + transcript_squeezes: STAGE3_TRANSCRIPT_SQUEEZES, + opening_inputs: STAGE3_OPENING_INPUTS, + field_constants: STAGE3_FIELD_CONSTANTS, + field_exprs: STAGE3_FIELD_EXPRS, + claims: STAGE3_SUMCHECK_CLAIMS, + batches: STAGE3_SUMCHECK_BATCHES, + drivers: STAGE3_SUMCHECK_DRIVERS, + instance_results: STAGE3_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE3_SUMCHECK_EVALS, + point_slices: STAGE3_POINT_SLICES, + point_concats: STAGE3_POINT_CONCATS, + opening_claims: STAGE3_OPENING_CLAIMS, + opening_equalities: STAGE3_OPENING_EQUALITIES, + opening_batches: STAGE3_OPENING_BATCHES, +}; + +pub fn verify_stage3( + proof: &Stage3Proof, + opening_inputs: &[Stage3OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage3Error> +where + T: Transcript, +{ + verify_stage3_with_program(&STAGE3_PROGRAM, proof, opening_inputs, transcript) +} + +pub fn verify_stage3_with_program( + program: &'static Stage3VerifierProgramPlan, + proof: &Stage3Proof, + opening_inputs: &[Stage3OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage3Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage3Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = + super::common::ValueStore::with_opening_inputs(opening_inputs, program.opening_inputs)?; + store.seed_constants(program.field_constants); + let mut artifacts = Stage3ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage3Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage3_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "sumcheck_driver" => { + let driver = + find_plan(program.drivers, step.symbol).ok_or(VerifyStage3Error::MissingProof { + driver: step.symbol, + })?; + verify_stage3_driver(program, driver, proof, &mut store, transcript, &mut artifacts)?; + } + _ => { + return Err(VerifyStage3Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage3 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage3_verifier_program() -> &'static Stage3VerifierProgramPlan { + &STAGE3_PROGRAM +} + +fn verify_stage3_squeeze( + program: &'static Stage3VerifierProgramPlan, + squeeze: &'static Stage3TranscriptSqueezePlan, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage3ExecutionArtifacts, +) -> Result<(), VerifyStage3Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(squeeze, &values, |input, expected, actual| { + VerifyStage3Error::InvalidInputLength { + input, + expected, + actual, + } + })?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage3Error::from)?; + artifacts.challenge_vectors.push(Stage3ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn verify_stage3_driver( + program: &'static Stage3VerifierProgramPlan, + driver: &'static Stage3SumcheckDriverPlan, + proof: &Stage3Proof, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage3ExecutionArtifacts, +) -> Result<(), VerifyStage3Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage3Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage3.batched" => { + verify_batched_stage3(program, driver, proof, store, transcript)? + } + _ => { + return Err(VerifyStage3Error::UnsupportedRelation { + relation, + }); + } + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_batched_stage3( + program: &'static Stage3VerifierProgramPlan, + driver: &'static Stage3SumcheckDriverPlan, + proof: &Stage3SumcheckOutput, + store: &mut super::common::ValueStore, + transcript: &mut T, +) -> Result, VerifyStage3Error> +where + T: Transcript, +{ + super::common::verify_batched_sumcheck( + driver, + proof, + program.claims, + program.batches, + program.field_exprs, + program.opening_inputs, + program.opening_claims, + program.opening_batches, + store, + transcript, + |store, evals, point, batching_coeffs| { + expected_batched_output_claim(program, driver, store, evals, point, batching_coeffs) + }, + |store, verified| observe_stage3_sumcheck_output(program, store, verified), + |driver, error| VerifyStage3Error::Sumcheck { driver, error }, + ) +} + +fn observe_stage3_sumcheck_output( + program: &'static Stage3VerifierProgramPlan, + store: &mut super::common::ValueStore, + output: &Stage3SumcheckOutput, +) -> Result<(), VerifyStage3Error> { + store.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + _ => { + return Err(VerifyStage3Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage3Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage3Error::MissingValue { symbol }, + )?; + store.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage3Error::InvalidInputLength { + input, + expected, + actual, + }, + )?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage3Error::from)?; + store.verify_opening_equalities( + program.opening_equalities, + |driver, reason| VerifyStage3Error::InvalidProof { driver, reason }, + |symbol| VerifyStage3Error::MissingValue { symbol }, + ) +} + +fn expected_batched_output_claim( + program: &'static Stage3VerifierProgramPlan, + driver: &'static Stage3SumcheckDriverPlan, + store: &super::common::ValueStore, + evals: &[Stage3NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage3Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage3Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let value = match instance.relation { + "jolt.stage3.spartan_shift" => { + expected_spartan_shift(store, evals, local_point)? + } + "jolt.stage3.instruction_input" => { + expected_instruction_input(store, evals, local_point)? + } + "jolt.stage3.registers_claim_reduction" => { + expected_registers(store, evals, local_point)? + } + _ => { + return Err(VerifyStage3Error::UnsupportedRelation { + relation: instance.relation, + }); + } + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_spartan_shift( + store: &super::common::ValueStore, + evals: &[Stage3NamedEval], + local_point: &[Fr], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_outer = + EqPlusOnePolynomial::::new(super::common::store_point(store, "stage3.input.stage1.NextPC")?.to_vec()) + .evaluate(&opening_point); + let eq_product = EqPlusOnePolynomial::::new( + super::common::store_point(store, "stage3.input.stage2.product_virtual.NextIsNoop")? + .to_vec(), + ) + .evaluate(&opening_point); + let weighted_outer = eval_by_name(evals, "stage3.spartan_shift.eval.UnexpandedPC")? + + super::common::store_scalar(store, "stage3.spartan_shift.gamma")? + * eval_by_name(evals, "stage3.spartan_shift.eval.PC")? + + super::common::store_scalar(store, "stage3.spartan_shift.gamma2")? + * eval_by_name(evals, "stage3.spartan_shift.eval.OpFlagVirtualInstruction")? + + super::common::store_scalar(store, "stage3.spartan_shift.gamma3")? + * eval_by_name(evals, "stage3.spartan_shift.eval.OpFlagIsFirstInSequence")?; + Ok(eq_outer * weighted_outer + + super::common::store_scalar(store, "stage3.spartan_shift.gamma4")? + * eq_product + * (Fr::from_u64(1) + - eval_by_name(evals, "stage3.spartan_shift.eval.InstructionFlagIsNoop")?)) +} + +fn expected_instruction_input( + store: &super::common::ValueStore, + evals: &[Stage3NamedEval], + local_point: &[Fr], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle( + &opening_point, + super::common::store_point(store, "stage3.input.stage2.product_virtual.LeftInstructionInput")?, + ); + let left = eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsRs1Value", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Rs1Value")? + + eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagLeftOperandIsPC", + )? * eval_by_name(evals, "stage3.instruction_input.eval.UnexpandedPC")?; + let right = eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagRightOperandIsRs2Value", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Rs2Value")? + + eval_by_name( + evals, + "stage3.instruction_input.eval.InstructionFlagRightOperandIsImm", + )? * eval_by_name(evals, "stage3.instruction_input.eval.Imm")?; + Ok(eq_eval * (right + super::common::store_scalar(store, "stage3.instruction_input.gamma")? * left)) +} + +fn expected_registers( + store: &super::common::ValueStore, + evals: &[Stage3NamedEval], + local_point: &[Fr], +) -> Result { + let opening_point = reverse_slice(local_point); + let eq_eval = EqPolynomial::::mle( + &opening_point, + super::common::store_point(store, "stage3.input.stage1.RdWriteValue")?, + ); + Ok(eq_eval + * (eval_by_name(evals, "stage3.registers_claim_reduction.eval.RdWriteValue")? + + super::common::store_scalar(store, "stage3.registers.gamma")? + * eval_by_name(evals, "stage3.registers_claim_reduction.eval.Rs1Value")? + + super::common::store_scalar(store, "stage3.registers.gamma2")? + * eval_by_name(evals, "stage3.registers_claim_reduction.eval.Rs2Value")?)) +} diff --git a/crates/jolt-verifier/src/stages/stage4.rs b/crates/jolt-verifier/src/stages/stage4.rs new file mode 100644 index 0000000000..3367e34d96 --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage4.rs @@ -0,0 +1,552 @@ +#![allow(dead_code)] + +use super::common::{batch_claims, eval_by_name, find_batch, find_plan, lt_polynomial_eval, reverse_slice}; +use jolt_field::{Field, Fr}; +use jolt_poly::EqPolynomial; +use jolt_sumcheck::SumcheckError; +use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript}; + +pub type Stage4NamedEval = super::common::StageNamedEval; +pub type Stage4SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage4ChallengeVector = super::common::StageChallengeVector; +pub type Stage4ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage4Proof = super::common::StageProof; +pub type Stage4OpeningInputValue = super::common::StageOpeningInputValue; + +pub use super::common::{ + FieldConstantPlan as Stage4FieldConstantPlan, FieldExprPlan as Stage4FieldExprPlan, + KernelPlan as Stage4KernelPlan, OpeningBatchPlan as Stage4OpeningBatchPlan, + OpeningClaimEqualityPlan as Stage4OpeningClaimEqualityPlan, + OpeningClaimPlan as Stage4OpeningClaimPlan, OpeningInputPlan as Stage4OpeningInputPlan, + PointConcatPlan as Stage4PointConcatPlan, PointSlicePlan as Stage4PointSlicePlan, + ProgramStepPlan as Stage4ProgramStepPlan, StageParams as Stage4Params, + StageProgramPlanNoPointZeros as Stage4CpuProgramPlan, + SumcheckBatchPlan as Stage4SumcheckBatchPlan, + SumcheckClaimPlan as Stage4SumcheckClaimPlan, SumcheckDriverPlan as Stage4SumcheckDriverPlan, + SumcheckEvalPlan as Stage4SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage4SumcheckInstanceResultPlan, + TranscriptAbsorbBytesPlan as Stage4TranscriptAbsorbBytesPlan, + TranscriptSqueezePlan as Stage4TranscriptSqueezePlan, +}; + +pub type DefaultStage4Transcript = Blake2bTranscript; +pub type Stage4VerifierProgramPlan = Stage4CpuProgramPlan; + +#[derive(Debug)] +pub enum VerifyStage4Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage4Error); + +pub const STAGE4_PARAMS: Stage4Params = Stage4Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE4_PROGRAM_STEPS: &[Stage4ProgramStepPlan] = &[ + Stage4ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage4.registers_read_write.gamma" }, + Stage4ProgramStepPlan { kind: "transcript_absorb_bytes", symbol: "stage4.ram_val_check.domain_separator" }, + Stage4ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage4.ram_val_check.gamma" }, + Stage4ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage4.sumcheck" }, +]; + +pub const STAGE4_TRANSCRIPT_SQUEEZES: &[Stage4TranscriptSqueezePlan] = &[ + Stage4TranscriptSqueezePlan { symbol: "stage4.registers_read_write.gamma", label: "registers_read_write_gamma", kind: "challenge_scalar", count: 1 }, + Stage4TranscriptSqueezePlan { symbol: "stage4.ram_val_check.gamma", label: "ram_val_check_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE4_TRANSCRIPT_ABSORB_BYTES: &[Stage4TranscriptAbsorbBytesPlan] = &[ + Stage4TranscriptAbsorbBytesPlan { symbol: "stage4.ram_val_check.domain_separator", label: "ram_val_check_gamma", payload: "" }, +]; + +pub const STAGE4_OPENING_INPUTS: &[Stage4OpeningInputPlan] = &[ + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.RdWriteValue", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.RdWriteValue", oracle: "RdWriteValue", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.Rs1Value", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.registers.Rs2Value", source_stage: "stage3", source_claim: "stage3.registers_claim_reduction.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.instruction.Rs1Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Rs1Value", oracle: "Rs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage3.instruction.Rs2Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Rs2Value", oracle: "Rs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage2.RamVal", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamVal", oracle: "RamVal", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.stage2.RamValFinal", source_stage: "stage2", source_claim: "stage2.ram_output.opening.RamValFinal", oracle: "RamValFinal", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual" }, + Stage4OpeningInputPlan { symbol: "stage4.input.initial_ram.RamValInit", source_stage: "stage4_precomputed", source_claim: "stage4.ram_val_check.initial_ram_eval", oracle: "RamValInit", domain: "jolt.ram_address_domain", point_arity: 16, claim_kind: "virtual" }, +]; + +pub const STAGE4_FIELD_CONSTANTS: &[Stage4FieldConstantPlan] = &[ + +]; + +pub const STAGE4_FIELD_EXPRS: &[Stage4FieldExprPlan] = &[ + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.gamma2", kind: "op", formula: "field.pow:2", operands: "stage4.registers_read_write.gamma" }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.term.Rs1Value", kind: "op", formula: "field.mul", operands: "stage4.registers_read_write.gamma|stage4.input.stage3.registers.Rs1Value" }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.term.Rs2Value", kind: "op", formula: "field.mul", operands: "stage4.registers_read_write.gamma2|stage4.input.stage3.registers.Rs2Value" }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.partial.RdWriteValueRs1Value", kind: "op", formula: "field.add", operands: "stage4.input.stage3.registers.RdWriteValue|stage4.registers_read_write.term.Rs1Value" }, + Stage4FieldExprPlan { symbol: "stage4.registers_read_write.claim_expr", kind: "op", formula: "field.add", operands: "stage4.registers_read_write.partial.RdWriteValueRs1Value|stage4.registers_read_write.term.Rs2Value" }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.delta.RamVal", kind: "op", formula: "field.sub", operands: "stage4.input.stage2.RamVal|stage4.input.initial_ram.RamValInit" }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.delta.RamValFinal", kind: "op", formula: "field.sub", operands: "stage4.input.stage2.RamValFinal|stage4.input.initial_ram.RamValInit" }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.term.RamValFinal", kind: "op", formula: "field.mul", operands: "stage4.ram_val_check.gamma|stage4.ram_val_check.delta.RamValFinal" }, + Stage4FieldExprPlan { symbol: "stage4.ram_val_check.claim_expr", kind: "op", formula: "field.add", operands: "stage4.ram_val_check.delta.RamVal|stage4.ram_val_check.term.RamValFinal" }, +]; +pub const STAGE4_KERNELS: &[Stage4KernelPlan] = &[ + +]; + +pub const STAGE4_SUMCHECK_CLAIMS: &[Stage4SumcheckClaimPlan] = &[ + Stage4SumcheckClaimPlan { symbol: "stage4.registers_read_write.input", stage: "stage4", domain: "jolt.stage4_registers_rw_domain", num_rounds: 23, degree: 3, claim: "stage4.registers_read_write.weighted_values", kernel: None, relation: Some("jolt.stage4.registers_read_write"), claim_value: "stage4.registers_read_write.claim_expr", input_openings: "stage4.input.stage3.registers.RdWriteValue|stage4.input.stage3.registers.Rs1Value|stage4.input.stage3.registers.Rs2Value" }, + Stage4SumcheckClaimPlan { symbol: "stage4.ram_val_check.input", stage: "stage4", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage4.ram_val_check.weighted_values", kernel: None, relation: Some("jolt.stage4.ram_val_check"), claim_value: "stage4.ram_val_check.claim_expr", input_openings: "stage4.input.stage2.RamVal|stage4.input.stage2.RamValFinal|stage4.input.initial_ram.RamValInit" }, +]; +pub const STAGE4_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 16, + 7, +]; + +pub const STAGE4_SUMCHECK_BATCHES: &[Stage4SumcheckBatchPlan] = &[ + Stage4SumcheckBatchPlan { symbol: "stage4.batch", stage: "stage4", proof_slot: "stage4.sumcheck", policy: "jolt_core_stage4_aligned", count: 2, ordered_claims: "stage4.registers_read_write.input|stage4.ram_val_check.input", claim_operands: "stage4.registers_read_write.input|stage4.ram_val_check.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE4_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE4_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 16, + 7, +]; + +pub const STAGE4_SUMCHECK_DRIVERS: &[Stage4SumcheckDriverPlan] = &[ + Stage4SumcheckDriverPlan { symbol: "stage4.sumcheck", stage: "stage4", proof_slot: "stage4.sumcheck", kernel: None, relation: Some("jolt.stage4.batched"), batch: "stage4.batch", policy: "jolt_core_stage4_aligned", round_schedule: STAGE4_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 23, degree: 3 }, +]; +pub const STAGE4_SUMCHECK_INSTANCE_RESULTS: &[Stage4SumcheckInstanceResultPlan] = &[ + Stage4SumcheckInstanceResultPlan { symbol: "stage4.registers_read_write.instance", source: "stage4.sumcheck", claim: "stage4.registers_read_write.input", relation: "jolt.stage4.registers_read_write", index: 0, point_arity: 23, num_rounds: 23, round_offset: 0, point_order: "stage4_registers_rw", degree: 3 }, + Stage4SumcheckInstanceResultPlan { symbol: "stage4.ram_val_check.instance", source: "stage4.sumcheck", claim: "stage4.ram_val_check.input", relation: "jolt.stage4.ram_val_check", index: 1, point_arity: 16, num_rounds: 16, round_offset: 7, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE4_SUMCHECK_EVALS: &[Stage4SumcheckEvalPlan] = &[ + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RegistersVal", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RegistersVal", index: 0, oracle: "RegistersVal" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.Rs1Ra", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.Rs1Ra", index: 1, oracle: "Rs1Ra" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.Rs2Ra", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.Rs2Ra", index: 2, oracle: "Rs2Ra" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RdWa", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RdWa", index: 3, oracle: "RdWa" }, + Stage4SumcheckEvalPlan { symbol: "stage4.registers_read_write.eval.RdInc", source: "stage4.sumcheck", name: "stage4.registers_read_write.eval.RdInc", index: 4, oracle: "RdInc" }, + Stage4SumcheckEvalPlan { symbol: "stage4.ram_val_check.eval.RamRa", source: "stage4.sumcheck", name: "stage4.ram_val_check.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage4SumcheckEvalPlan { symbol: "stage4.ram_val_check.eval.RamInc", source: "stage4.sumcheck", name: "stage4.ram_val_check.eval.RamInc", index: 1, oracle: "RamInc" }, +]; + +pub const STAGE4_POINT_SLICES: &[Stage4PointSlicePlan] = &[ + Stage4PointSlicePlan { symbol: "stage4.registers_read_write.point.RdInc", source: "stage4.registers_read_write.instance", offset: 7, length: 16, input: "stage4.registers_read_write.instance" }, + Stage4PointSlicePlan { symbol: "stage4.ram_val_check.point.RamAddress", source: "stage4.input.stage2.RamVal", offset: 0, length: 16, input: "stage4.input.stage2.RamVal" }, +]; + +pub const STAGE4_POINT_CONCATS: &[Stage4PointConcatPlan] = &[ + Stage4PointConcatPlan { symbol: "stage4.ram_val_check.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: "stage4.ram_val_check.point.RamAddress|stage4.ram_val_check.instance" }, +]; +pub const STAGE4_OPENING_CLAIMS: &[Stage4OpeningClaimPlan] = &[ + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RegistersVal", oracle: "RegistersVal", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.RegistersVal" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.Rs1Ra", oracle: "Rs1Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.Rs1Ra" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.Rs2Ra", oracle: "Rs2Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.Rs2Ra" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage4.registers_read_write.instance", eval_source: "stage4.registers_read_write.eval.RdWa" }, + Stage4OpeningClaimPlan { symbol: "stage4.registers_read_write.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage4.registers_read_write.point.RdInc", eval_source: "stage4.registers_read_write.eval.RdInc" }, + Stage4OpeningClaimPlan { symbol: "stage4.ram_val_check.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage4.ram_val_check.point.RamRa", eval_source: "stage4.ram_val_check.eval.RamRa" }, + Stage4OpeningClaimPlan { symbol: "stage4.ram_val_check.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage4.ram_val_check.instance", eval_source: "stage4.ram_val_check.eval.RamInc" }, +]; + +pub const STAGE4_OPENING_EQUALITIES: &[Stage4OpeningClaimEqualityPlan] = &[ + Stage4OpeningClaimEqualityPlan { symbol: "stage4.registers.rs1_claim_consistency", mode: "point_and_eval", lhs: "stage4.input.stage3.registers.Rs1Value", rhs: "stage4.input.stage3.instruction.Rs1Value" }, + Stage4OpeningClaimEqualityPlan { symbol: "stage4.registers.rs2_claim_consistency", mode: "point_and_eval", lhs: "stage4.input.stage3.registers.Rs2Value", rhs: "stage4.input.stage3.instruction.Rs2Value" }, +]; + +pub const STAGE4_OPENING_BATCHES: &[Stage4OpeningBatchPlan] = &[ + Stage4OpeningBatchPlan { symbol: "stage4.openings", stage: "stage4", proof_slot: "stage4.openings", policy: "jolt_stage4_output_order", count: 7, ordered_claims: "stage4.registers_read_write.opening.RegistersVal|stage4.registers_read_write.opening.Rs1Ra|stage4.registers_read_write.opening.Rs2Ra|stage4.registers_read_write.opening.RdWa|stage4.registers_read_write.opening.RdInc|stage4.ram_val_check.opening.RamRa|stage4.ram_val_check.opening.RamInc", claim_operands: "stage4.registers_read_write.opening.RegistersVal|stage4.registers_read_write.opening.Rs1Ra|stage4.registers_read_write.opening.Rs2Ra|stage4.registers_read_write.opening.RdWa|stage4.registers_read_write.opening.RdInc|stage4.ram_val_check.opening.RamRa|stage4.ram_val_check.opening.RamInc" }, +]; +pub const STAGE4_PROGRAM: Stage4VerifierProgramPlan = Stage4CpuProgramPlan { + role: "verifier", + params: STAGE4_PARAMS, + steps: STAGE4_PROGRAM_STEPS, + transcript_squeezes: STAGE4_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE4_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE4_OPENING_INPUTS, + field_constants: STAGE4_FIELD_CONSTANTS, + field_exprs: STAGE4_FIELD_EXPRS, + kernels: STAGE4_KERNELS, + claims: STAGE4_SUMCHECK_CLAIMS, + batches: STAGE4_SUMCHECK_BATCHES, + drivers: STAGE4_SUMCHECK_DRIVERS, + instance_results: STAGE4_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE4_SUMCHECK_EVALS, + point_slices: STAGE4_POINT_SLICES, + point_concats: STAGE4_POINT_CONCATS, + opening_claims: STAGE4_OPENING_CLAIMS, + opening_equalities: STAGE4_OPENING_EQUALITIES, + opening_batches: STAGE4_OPENING_BATCHES, +}; + +pub fn verify_stage4( + proof: &Stage4Proof, + opening_inputs: &[Stage4OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage4Error> +where + T: Transcript, +{ + verify_stage4_with_program(&STAGE4_PROGRAM, proof, opening_inputs, transcript) +} + +pub fn verify_stage4_with_program( + program: &'static Stage4VerifierProgramPlan, + proof: &Stage4Proof, + opening_inputs: &[Stage4OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage4Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage4Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = + super::common::ValueStore::with_opening_inputs(opening_inputs, program.opening_inputs)?; + store.seed_constants(program.field_constants); + let mut artifacts = Stage4ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage4Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage4_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "transcript_absorb_bytes" => { + let absorb = find_plan(program.transcript_absorb_bytes, step.symbol).ok_or( + VerifyStage4Error::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage4_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_plan(program.drivers, step.symbol).ok_or(VerifyStage4Error::MissingProof { + driver: step.symbol, + })?; + verify_stage4_driver(program, driver, proof, &mut store, transcript, &mut artifacts)?; + } + _ => { + return Err(VerifyStage4Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage4 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage4_verifier_program() -> &'static Stage4VerifierProgramPlan { + &STAGE4_PROGRAM +} + +fn verify_stage4_squeeze( + program: &'static Stage4VerifierProgramPlan, + squeeze: &'static Stage4TranscriptSqueezePlan, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage4ExecutionArtifacts, +) -> Result<(), VerifyStage4Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(squeeze, &values, |input, expected, actual| { + VerifyStage4Error::InvalidInputLength { + input, + expected, + actual, + } + })?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage4Error::from)?; + artifacts.challenge_vectors.push(Stage4ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn absorb_stage4_bytes(absorb: &'static Stage4TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn verify_stage4_driver( + program: &'static Stage4VerifierProgramPlan, + driver: &'static Stage4SumcheckDriverPlan, + proof: &Stage4Proof, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage4ExecutionArtifacts, +) -> Result<(), VerifyStage4Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage4Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage4.batched" => { + verify_batched_stage4(program, driver, proof, store, transcript)? + } + _ => return Err(VerifyStage4Error::UnsupportedRelation { relation }), + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_batched_stage4( + program: &'static Stage4VerifierProgramPlan, + driver: &'static Stage4SumcheckDriverPlan, + proof: &Stage4SumcheckOutput, + store: &mut super::common::ValueStore, + transcript: &mut T, +) -> Result, VerifyStage4Error> +where + T: Transcript, +{ + super::common::verify_batched_sumcheck( + driver, + proof, + program.claims, + program.batches, + program.field_exprs, + program.opening_inputs, + program.opening_claims, + program.opening_batches, + store, + transcript, + |store, evals, point, batching_coeffs| { + expected_batched_output_claim(program, driver, store, evals, point, batching_coeffs) + }, + |store, verified| observe_stage4_sumcheck_output(program, store, verified), + |driver, error| VerifyStage4Error::Sumcheck { driver, error }, + ) +} + +fn observe_stage4_sumcheck_output( + program: &'static Stage4VerifierProgramPlan, + store: &mut super::common::ValueStore, + output: &Stage4SumcheckOutput, +) -> Result<(), VerifyStage4Error> { + store.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + "stage4_registers_rw" => { + point = normalize_stage4_registers_rw_point(program, output.driver, &point)?; + } + _ => { + return Err(VerifyStage4Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage4Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage4Error::MissingValue { symbol }, + )?; + store.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage4Error::InvalidInputLength { + input, + expected, + actual, + }, + )?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage4Error::from)?; + store.verify_opening_equalities( + program.opening_equalities, + |driver, reason| VerifyStage4Error::InvalidProof { driver, reason }, + |symbol| VerifyStage4Error::MissingValue { symbol }, + ) +} + +fn expected_batched_output_claim( + program: &'static Stage4VerifierProgramPlan, + driver: &'static Stage4SumcheckDriverPlan, + store: &super::common::ValueStore, + evals: &[Stage4NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage4Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage4Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let relation = claim.relation.unwrap_or(""); + let value = match relation { + "jolt.stage4.registers_read_write" => { + expected_registers_read_write(store, evals, local_point)? + } + "jolt.stage4.ram_val_check" => { + expected_ram_val_check(store, evals, local_point)? + } + _ => return Err(VerifyStage4Error::UnsupportedRelation { relation }), + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_registers_read_write( + store: &super::common::ValueStore, + evals: &[Stage4NamedEval], + local_point: &[Fr], +) -> Result { + let trace_point = super::common::store_point(store, "stage4.input.stage3.registers.RdWriteValue")?; + let r_cycle = normalize_stage4_registers_rw_cycle_point( + local_point, + trace_point.len(), + "stage4.registers_read_write.instance", + )?; + let eq_eval = EqPolynomial::::mle(&r_cycle, trace_point); + let registers_val = eval_by_name( + evals, + "stage4.registers_read_write.eval.RegistersVal", + )?; + let rs1_ra = eval_by_name(evals, "stage4.registers_read_write.eval.Rs1Ra")?; + let rs2_ra = eval_by_name(evals, "stage4.registers_read_write.eval.Rs2Ra")?; + let rd_wa = eval_by_name(evals, "stage4.registers_read_write.eval.RdWa")?; + let rd_inc = eval_by_name(evals, "stage4.registers_read_write.eval.RdInc")?; + let gamma = super::common::store_scalar(store, "stage4.registers_read_write.gamma")?; + Ok(eq_eval + * (rd_wa * (registers_val + rd_inc) + + gamma * (rs1_ra * registers_val + gamma * rs2_ra * registers_val))) +} + +fn expected_ram_val_check( + store: &super::common::ValueStore, + evals: &[Stage4NamedEval], + local_point: &[Fr], +) -> Result { + let ram_val_point = super::common::store_point(store, "stage4.input.stage2.RamVal")?; + let r_cycle_prime = reverse_slice(local_point); + let r_cycle = suffix_point( + ram_val_point, + r_cycle_prime.len(), + "stage4.input.stage2.RamVal", + )?; + let lt_eval = lt_polynomial_eval(&r_cycle_prime, r_cycle); + let gamma = super::common::store_scalar(store, "stage4.ram_val_check.gamma")?; + let ram_ra = eval_by_name(evals, "stage4.ram_val_check.eval.RamRa")?; + let ram_inc = eval_by_name(evals, "stage4.ram_val_check.eval.RamInc")?; + Ok(ram_inc * ram_ra * (lt_eval + gamma)) +} + +fn suffix_point<'a>( + point: &'a [Fr], + length: usize, + input: &'static str, +) -> Result<&'a [Fr], VerifyStage4Error> { + point + .get(point.len().saturating_sub(length)..) + .filter(|suffix| suffix.len() == length) + .ok_or(VerifyStage4Error::InvalidInputLength { + input, + expected: length, + actual: point.len(), + }) +} + +fn normalize_stage4_registers_rw_point( + program: &'static Stage4VerifierProgramPlan, + driver: &'static str, + point: &[F], +) -> Result, VerifyStage4Error> { + let driver_plan = find_plan(program.drivers, driver).ok_or(VerifyStage4Error::MissingProof { + driver, + })?; + if driver_plan.round_schedule.len() != 2 { + return Err(VerifyStage4Error::InvalidProof { + driver, + reason: "stage4 registers point normalization requires [cycle, address] schedule", + }); + } + let cycle_rounds = driver_plan.round_schedule[0]; + let address_rounds = driver_plan.round_schedule[1]; + if point.len() != cycle_rounds + address_rounds { + return Err(VerifyStage4Error::InvalidInputLength { + input: "stage4.registers_read_write.instance", + expected: cycle_rounds + address_rounds, + actual: point.len(), + }); + } + let (cycle, address) = point.split_at(cycle_rounds); + Ok(address + .iter() + .rev() + .copied() + .chain(cycle.iter().rev().copied()) + .collect()) +} + +fn normalize_stage4_registers_rw_cycle_point( + point: &[F], + cycle_rounds: usize, + input: &'static str, +) -> Result, VerifyStage4Error> { + let cycle = point + .get(..cycle_rounds) + .filter(|cycle| cycle.len() == cycle_rounds) + .ok_or(VerifyStage4Error::InvalidInputLength { + input, + expected: cycle_rounds, + actual: point.len(), + })?; + Ok(cycle.iter().rev().copied().collect()) +} diff --git a/crates/jolt-verifier/src/stages/stage5.rs b/crates/jolt-verifier/src/stages/stage5.rs new file mode 100644 index 0000000000..954e7d7228 --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage5.rs @@ -0,0 +1,664 @@ +#![allow(dead_code)] + +use super::common::{batch_claims, eval_by_name, find_batch, find_plan, identity_polynomial_eval, indexed_evals_by_prefix, indexed_evals_by_prefix_any, lt_polynomial_eval, normalize_instruction_read_raf_point, operand_polynomial_eval, reverse_slice, suffix_point}; +use jolt_field::{Field, Fr, RingCore}; +use jolt_lookup_tables::LookupTableKind; +use jolt_poly::EqPolynomial; +use jolt_sumcheck::SumcheckError; +use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript}; + +pub type Stage5NamedEval = super::common::StageNamedEval; +pub type Stage5SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage5ChallengeVector = super::common::StageChallengeVector; +pub type Stage5ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage5Proof = super::common::StageProof; +pub type Stage5OpeningInputValue = super::common::StageOpeningInputValue; + +pub use super::common::{ + FieldConstantPlan as Stage5FieldConstantPlan, FieldExprPlan as Stage5FieldExprPlan, + KernelPlan as Stage5KernelPlan, OpeningBatchPlan as Stage5OpeningBatchPlan, + OpeningClaimEqualityPlan as Stage5OpeningClaimEqualityPlan, + OpeningClaimPlan as Stage5OpeningClaimPlan, OpeningInputPlan as Stage5OpeningInputPlan, + PointConcatPlan as Stage5PointConcatPlan, PointSlicePlan as Stage5PointSlicePlan, + ProgramStepPlan as Stage5ProgramStepPlan, StageParams as Stage5Params, + StageProgramPlanNoPointZeros as Stage5CpuProgramPlan, + SumcheckBatchPlan as Stage5SumcheckBatchPlan, + SumcheckClaimPlan as Stage5SumcheckClaimPlan, SumcheckDriverPlan as Stage5SumcheckDriverPlan, + SumcheckEvalPlan as Stage5SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage5SumcheckInstanceResultPlan, + TranscriptAbsorbBytesPlan as Stage5TranscriptAbsorbBytesPlan, + TranscriptSqueezePlan as Stage5TranscriptSqueezePlan, +}; + +pub type DefaultStage5Transcript = Blake2bTranscript; +pub type Stage5VerifierProgramPlan = Stage5CpuProgramPlan; + +#[derive(Debug)] +pub enum VerifyStage5Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage5Error); + +pub const STAGE5_PARAMS: Stage5Params = Stage5Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE5_PROGRAM_STEPS: &[Stage5ProgramStepPlan] = &[ + Stage5ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage5.instruction_read_raf.gamma" }, + Stage5ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage5.ram_ra_claim_reduction.gamma" }, + Stage5ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage5.sumcheck" }, +]; + +pub const STAGE5_TRANSCRIPT_SQUEEZES: &[Stage5TranscriptSqueezePlan] = &[ + Stage5TranscriptSqueezePlan { symbol: "stage5.instruction_read_raf.gamma", label: "instruction_read_raf_gamma", kind: "challenge_scalar", count: 1 }, + Stage5TranscriptSqueezePlan { symbol: "stage5.ram_ra_claim_reduction.gamma", label: "ram_ra_claim_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE5_TRANSCRIPT_ABSORB_BYTES: &[Stage5TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE5_OPENING_INPUTS: &[Stage5OpeningInputPlan] = &[ + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.LookupOutput", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.product_virtual.LookupOutput", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.LeftLookupOperand", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.LeftLookupOperand", oracle: "LeftLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.instruction.RightLookupOperand", source_stage: "stage2", source_claim: "stage2.instruction_lookup.claim_reduction.opening.RightLookupOperand", oracle: "RightLookupOperand", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.ram_raf.RamRa", source_stage: "stage2", source_claim: "stage2.ram_raf.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage2.ram_read_write.RamRa", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage4.ram_val_check.RamRa", source_stage: "stage4", source_claim: "stage4.ram_val_check.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage5OpeningInputPlan { symbol: "stage5.input.stage4.registers.RegistersVal", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RegistersVal", oracle: "RegistersVal", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, +]; + +pub const STAGE5_FIELD_CONSTANTS: &[Stage5FieldConstantPlan] = &[ + +]; + +pub const STAGE5_FIELD_EXPRS: &[Stage5FieldExprPlan] = &[ + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.gamma2", kind: "op", formula: "field.pow:2", operands: "stage5.instruction_read_raf.gamma" }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.term.LeftLookupOperand", kind: "op", formula: "field.mul", operands: "stage5.instruction_read_raf.gamma|stage5.input.stage2.instruction.LeftLookupOperand" }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.term.RightLookupOperand", kind: "op", formula: "field.mul", operands: "stage5.instruction_read_raf.gamma2|stage5.input.stage2.instruction.RightLookupOperand" }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.partial.LookupOutputLeftOperand", kind: "op", formula: "field.add", operands: "stage5.input.stage2.instruction.LookupOutput|stage5.instruction_read_raf.term.LeftLookupOperand" }, + Stage5FieldExprPlan { symbol: "stage5.instruction_read_raf.claim_expr", kind: "op", formula: "field.add", operands: "stage5.instruction_read_raf.partial.LookupOutputLeftOperand|stage5.instruction_read_raf.term.RightLookupOperand" }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.gamma2", kind: "op", formula: "field.pow:2", operands: "stage5.ram_ra_claim_reduction.gamma" }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.term.RamRaReadWrite", kind: "op", formula: "field.mul", operands: "stage5.ram_ra_claim_reduction.gamma|stage5.input.stage2.ram_read_write.RamRa" }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.term.RamRaValCheck", kind: "op", formula: "field.mul", operands: "stage5.ram_ra_claim_reduction.gamma2|stage5.input.stage4.ram_val_check.RamRa" }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.partial.RafReadWrite", kind: "op", formula: "field.add", operands: "stage5.input.stage2.ram_raf.RamRa|stage5.ram_ra_claim_reduction.term.RamRaReadWrite" }, + Stage5FieldExprPlan { symbol: "stage5.ram_ra_claim_reduction.claim_expr", kind: "op", formula: "field.add", operands: "stage5.ram_ra_claim_reduction.partial.RafReadWrite|stage5.ram_ra_claim_reduction.term.RamRaValCheck" }, +]; +pub const STAGE5_KERNELS: &[Stage5KernelPlan] = &[ + +]; + +pub const STAGE5_SUMCHECK_CLAIMS: &[Stage5SumcheckClaimPlan] = &[ + Stage5SumcheckClaimPlan { symbol: "stage5.instruction_read_raf.input", stage: "stage5", domain: "jolt.stage5_instruction_read_raf_domain", num_rounds: 144, degree: 10, claim: "stage5.instruction_read_raf.weighted_lookup_values", kernel: None, relation: Some("jolt.stage5.instruction_read_raf"), claim_value: "stage5.instruction_read_raf.claim_expr", input_openings: "stage5.input.stage2.instruction.LookupOutput|stage5.input.stage2.instruction.LeftLookupOperand|stage5.input.stage2.instruction.RightLookupOperand" }, + Stage5SumcheckClaimPlan { symbol: "stage5.ram_ra_claim_reduction.input", stage: "stage5", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage5.ram_ra_claim_reduction.weighted_ram_ra", kernel: None, relation: Some("jolt.stage5.ram_ra_claim_reduction"), claim_value: "stage5.ram_ra_claim_reduction.claim_expr", input_openings: "stage5.input.stage2.ram_raf.RamRa|stage5.input.stage2.ram_read_write.RamRa|stage5.input.stage4.ram_val_check.RamRa" }, + Stage5SumcheckClaimPlan { symbol: "stage5.registers_val_evaluation.input", stage: "stage5", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage5.registers_val_evaluation.registers_val", kernel: None, relation: Some("jolt.stage5.registers_val_evaluation"), claim_value: "stage5.input.stage4.registers.RegistersVal", input_openings: "stage5.input.stage4.registers.RegistersVal" }, +]; +pub const STAGE5_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 128, + 16, +]; + +pub const STAGE5_SUMCHECK_BATCHES: &[Stage5SumcheckBatchPlan] = &[ + Stage5SumcheckBatchPlan { symbol: "stage5.batch", stage: "stage5", proof_slot: "stage5.sumcheck", policy: "jolt_core_stage5_aligned", count: 3, ordered_claims: "stage5.instruction_read_raf.input|stage5.ram_ra_claim_reduction.input|stage5.registers_val_evaluation.input", claim_operands: "stage5.instruction_read_raf.input|stage5.ram_ra_claim_reduction.input|stage5.registers_val_evaluation.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE5_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE5_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 128, + 16, +]; + +pub const STAGE5_SUMCHECK_DRIVERS: &[Stage5SumcheckDriverPlan] = &[ + Stage5SumcheckDriverPlan { symbol: "stage5.sumcheck", stage: "stage5", proof_slot: "stage5.sumcheck", kernel: None, relation: Some("jolt.stage5.batched"), batch: "stage5.batch", policy: "jolt_core_stage5_aligned", round_schedule: STAGE5_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 144, degree: 10 }, +]; +pub const STAGE5_SUMCHECK_INSTANCE_RESULTS: &[Stage5SumcheckInstanceResultPlan] = &[ + Stage5SumcheckInstanceResultPlan { symbol: "stage5.instruction_read_raf.instance", source: "stage5.sumcheck", claim: "stage5.instruction_read_raf.input", relation: "jolt.stage5.instruction_read_raf", index: 0, point_arity: 144, num_rounds: 144, round_offset: 0, point_order: "instruction_read_raf", degree: 10 }, + Stage5SumcheckInstanceResultPlan { symbol: "stage5.ram_ra_claim_reduction.instance", source: "stage5.sumcheck", claim: "stage5.ram_ra_claim_reduction.input", relation: "jolt.stage5.ram_ra_claim_reduction", index: 1, point_arity: 16, num_rounds: 16, round_offset: 128, point_order: "reverse", degree: 2 }, + Stage5SumcheckInstanceResultPlan { symbol: "stage5.registers_val_evaluation.instance", source: "stage5.sumcheck", claim: "stage5.registers_val_evaluation.input", relation: "jolt.stage5.registers_val_evaluation", index: 2, point_arity: 16, num_rounds: 16, round_offset: 128, point_order: "reverse", degree: 3 }, +]; + +pub const STAGE5_SUMCHECK_EVALS: &[Stage5SumcheckEvalPlan] = &[ + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_0", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_0", index: 0, oracle: "LookupTableFlag_0" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_1", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_1", index: 1, oracle: "LookupTableFlag_1" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_2", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_2", index: 2, oracle: "LookupTableFlag_2" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_3", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_3", index: 3, oracle: "LookupTableFlag_3" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_4", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_4", index: 4, oracle: "LookupTableFlag_4" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_5", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_5", index: 5, oracle: "LookupTableFlag_5" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_6", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_6", index: 6, oracle: "LookupTableFlag_6" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_7", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_7", index: 7, oracle: "LookupTableFlag_7" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_8", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_8", index: 8, oracle: "LookupTableFlag_8" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_9", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_9", index: 9, oracle: "LookupTableFlag_9" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_10", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_10", index: 10, oracle: "LookupTableFlag_10" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_11", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_11", index: 11, oracle: "LookupTableFlag_11" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_12", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_12", index: 12, oracle: "LookupTableFlag_12" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_13", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_13", index: 13, oracle: "LookupTableFlag_13" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_14", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_14", index: 14, oracle: "LookupTableFlag_14" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_15", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_15", index: 15, oracle: "LookupTableFlag_15" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_16", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_16", index: 16, oracle: "LookupTableFlag_16" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_17", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_17", index: 17, oracle: "LookupTableFlag_17" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_18", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_18", index: 18, oracle: "LookupTableFlag_18" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_19", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_19", index: 19, oracle: "LookupTableFlag_19" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_20", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_20", index: 20, oracle: "LookupTableFlag_20" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_21", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_21", index: 21, oracle: "LookupTableFlag_21" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_22", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_22", index: 22, oracle: "LookupTableFlag_22" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_23", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_23", index: 23, oracle: "LookupTableFlag_23" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_24", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_24", index: 24, oracle: "LookupTableFlag_24" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_25", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_25", index: 25, oracle: "LookupTableFlag_25" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_26", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_26", index: 26, oracle: "LookupTableFlag_26" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_27", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_27", index: 27, oracle: "LookupTableFlag_27" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_28", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_28", index: 28, oracle: "LookupTableFlag_28" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_29", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_29", index: 29, oracle: "LookupTableFlag_29" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_30", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_30", index: 30, oracle: "LookupTableFlag_30" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_31", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_31", index: 31, oracle: "LookupTableFlag_31" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_32", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_32", index: 32, oracle: "LookupTableFlag_32" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_33", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_33", index: 33, oracle: "LookupTableFlag_33" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_34", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_34", index: 34, oracle: "LookupTableFlag_34" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_35", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_35", index: 35, oracle: "LookupTableFlag_35" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_36", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_36", index: 36, oracle: "LookupTableFlag_36" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_37", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_37", index: 37, oracle: "LookupTableFlag_37" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_38", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_38", index: 38, oracle: "LookupTableFlag_38" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_39", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_39", index: 39, oracle: "LookupTableFlag_39" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.LookupTableFlag_40", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.LookupTableFlag_40", index: 40, oracle: "LookupTableFlag_40" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_0", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_0", index: 41, oracle: "InstructionRa_0" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_1", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_1", index: 42, oracle: "InstructionRa_1" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_2", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_2", index: 43, oracle: "InstructionRa_2" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_3", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_3", index: 44, oracle: "InstructionRa_3" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_4", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_4", index: 45, oracle: "InstructionRa_4" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_5", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_5", index: 46, oracle: "InstructionRa_5" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_6", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_6", index: 47, oracle: "InstructionRa_6" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRa_7", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRa_7", index: 48, oracle: "InstructionRa_7" }, + Stage5SumcheckEvalPlan { symbol: "stage5.instruction_read_raf.eval.InstructionRafFlag", source: "stage5.sumcheck", name: "stage5.instruction_read_raf.eval.InstructionRafFlag", index: 49, oracle: "InstructionRafFlag" }, + Stage5SumcheckEvalPlan { symbol: "stage5.ram_ra_claim_reduction.eval.RamRa", source: "stage5.sumcheck", name: "stage5.ram_ra_claim_reduction.eval.RamRa", index: 0, oracle: "RamRa" }, + Stage5SumcheckEvalPlan { symbol: "stage5.registers_val_evaluation.eval.RdInc", source: "stage5.sumcheck", name: "stage5.registers_val_evaluation.eval.RdInc", index: 0, oracle: "RdInc" }, + Stage5SumcheckEvalPlan { symbol: "stage5.registers_val_evaluation.eval.RdWa", source: "stage5.sumcheck", name: "stage5.registers_val_evaluation.eval.RdWa", index: 1, oracle: "RdWa" }, +]; + +pub const STAGE5_POINT_SLICES: &[Stage5PointSlicePlan] = &[ + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.Cycle", source: "stage5.instruction_read_raf.instance", offset: 128, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_0.address", source: "stage5.instruction_read_raf.instance", offset: 0, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_1.address", source: "stage5.instruction_read_raf.instance", offset: 16, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_2.address", source: "stage5.instruction_read_raf.instance", offset: 32, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_3.address", source: "stage5.instruction_read_raf.instance", offset: 48, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_4.address", source: "stage5.instruction_read_raf.instance", offset: 64, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_5.address", source: "stage5.instruction_read_raf.instance", offset: 80, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_6.address", source: "stage5.instruction_read_raf.instance", offset: 96, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_7.address", source: "stage5.instruction_read_raf.instance", offset: 112, length: 16, input: "stage5.instruction_read_raf.instance" }, + Stage5PointSlicePlan { symbol: "stage5.ram_ra_claim_reduction.point.RamAddress", source: "stage5.input.stage2.ram_raf.RamRa", offset: 0, length: 16, input: "stage5.input.stage2.ram_raf.RamRa" }, + Stage5PointSlicePlan { symbol: "stage5.registers_val_evaluation.point.RegisterAddress", source: "stage5.input.stage4.registers.RegistersVal", offset: 0, length: 7, input: "stage5.input.stage4.registers.RegistersVal" }, +]; + +pub const STAGE5_POINT_CONCATS: &[Stage5PointConcatPlan] = &[ + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_0", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_0.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_1", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_1.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_2", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_2.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_3", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_3.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_4", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_4.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_5", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_5.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_6", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_6.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.instruction_read_raf.point.InstructionRa_7", layout: "address_chunk_then_cycle", arity: 32, inputs: "stage5.instruction_read_raf.point.InstructionRa_7.address|stage5.instruction_read_raf.point.Cycle" }, + Stage5PointConcatPlan { symbol: "stage5.ram_ra_claim_reduction.point.RamRa", layout: "address_then_cycle", arity: 32, inputs: "stage5.ram_ra_claim_reduction.point.RamAddress|stage5.ram_ra_claim_reduction.instance" }, + Stage5PointConcatPlan { symbol: "stage5.registers_val_evaluation.point.RdWa", layout: "register_address_then_cycle", arity: 23, inputs: "stage5.registers_val_evaluation.point.RegisterAddress|stage5.registers_val_evaluation.instance" }, +]; +pub const STAGE5_OPENING_CLAIMS: &[Stage5OpeningClaimPlan] = &[ + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_0", oracle: "LookupTableFlag_0", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_0" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_1", oracle: "LookupTableFlag_1", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_1" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_2", oracle: "LookupTableFlag_2", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_2" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_3", oracle: "LookupTableFlag_3", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_3" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_4", oracle: "LookupTableFlag_4", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_4" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_5", oracle: "LookupTableFlag_5", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_5" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_6", oracle: "LookupTableFlag_6", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_6" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_7", oracle: "LookupTableFlag_7", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_7" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_8", oracle: "LookupTableFlag_8", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_8" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_9", oracle: "LookupTableFlag_9", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_9" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_10", oracle: "LookupTableFlag_10", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_10" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_11", oracle: "LookupTableFlag_11", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_11" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_12", oracle: "LookupTableFlag_12", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_12" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_13", oracle: "LookupTableFlag_13", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_13" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_14", oracle: "LookupTableFlag_14", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_14" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_15", oracle: "LookupTableFlag_15", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_15" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_16", oracle: "LookupTableFlag_16", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_16" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_17", oracle: "LookupTableFlag_17", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_17" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_18", oracle: "LookupTableFlag_18", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_18" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_19", oracle: "LookupTableFlag_19", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_19" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_20", oracle: "LookupTableFlag_20", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_20" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_21", oracle: "LookupTableFlag_21", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_21" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_22", oracle: "LookupTableFlag_22", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_22" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_23", oracle: "LookupTableFlag_23", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_23" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_24", oracle: "LookupTableFlag_24", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_24" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_25", oracle: "LookupTableFlag_25", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_25" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_26", oracle: "LookupTableFlag_26", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_26" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_27", oracle: "LookupTableFlag_27", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_27" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_28", oracle: "LookupTableFlag_28", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_28" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_29", oracle: "LookupTableFlag_29", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_29" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_30", oracle: "LookupTableFlag_30", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_30" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_31", oracle: "LookupTableFlag_31", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_31" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_32", oracle: "LookupTableFlag_32", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_32" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_33", oracle: "LookupTableFlag_33", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_33" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_34", oracle: "LookupTableFlag_34", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_34" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_35", oracle: "LookupTableFlag_35", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_35" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_36", oracle: "LookupTableFlag_36", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_36" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_37", oracle: "LookupTableFlag_37", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_37" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_38", oracle: "LookupTableFlag_38", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_38" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_39", oracle: "LookupTableFlag_39", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_39" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.LookupTableFlag_40", oracle: "LookupTableFlag_40", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.LookupTableFlag_40" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_0", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_0" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_1", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_1" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_2", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_2" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_3", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_3" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_4", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_4" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_5", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_5" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_6", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_6" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.InstructionRa_7", eval_source: "stage5.instruction_read_raf.eval.InstructionRa_7" }, + Stage5OpeningClaimPlan { symbol: "stage5.instruction_read_raf.opening.InstructionRafFlag", oracle: "InstructionRafFlag", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage5.instruction_read_raf.point.Cycle", eval_source: "stage5.instruction_read_raf.eval.InstructionRafFlag" }, + Stage5OpeningClaimPlan { symbol: "stage5.ram_ra_claim_reduction.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual", point_source: "stage5.ram_ra_claim_reduction.point.RamRa", eval_source: "stage5.ram_ra_claim_reduction.eval.RamRa" }, + Stage5OpeningClaimPlan { symbol: "stage5.registers_val_evaluation.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage5.registers_val_evaluation.instance", eval_source: "stage5.registers_val_evaluation.eval.RdInc" }, + Stage5OpeningClaimPlan { symbol: "stage5.registers_val_evaluation.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual", point_source: "stage5.registers_val_evaluation.point.RdWa", eval_source: "stage5.registers_val_evaluation.eval.RdWa" }, +]; + +pub const STAGE5_OPENING_EQUALITIES: &[Stage5OpeningClaimEqualityPlan] = &[ + Stage5OpeningClaimEqualityPlan { symbol: "stage5.instruction.lookup_output_claim_consistency", mode: "point_and_eval", lhs: "stage5.input.stage2.instruction.LookupOutput", rhs: "stage5.input.stage2.product_virtual.LookupOutput" }, +]; + +pub const STAGE5_OPENING_BATCHES: &[Stage5OpeningBatchPlan] = &[ + Stage5OpeningBatchPlan { symbol: "stage5.openings", stage: "stage5", proof_slot: "stage5.openings", policy: "jolt_stage5_output_order", count: 53, ordered_claims: "stage5.instruction_read_raf.opening.LookupTableFlag_0|stage5.instruction_read_raf.opening.LookupTableFlag_1|stage5.instruction_read_raf.opening.LookupTableFlag_2|stage5.instruction_read_raf.opening.LookupTableFlag_3|stage5.instruction_read_raf.opening.LookupTableFlag_4|stage5.instruction_read_raf.opening.LookupTableFlag_5|stage5.instruction_read_raf.opening.LookupTableFlag_6|stage5.instruction_read_raf.opening.LookupTableFlag_7|stage5.instruction_read_raf.opening.LookupTableFlag_8|stage5.instruction_read_raf.opening.LookupTableFlag_9|stage5.instruction_read_raf.opening.LookupTableFlag_10|stage5.instruction_read_raf.opening.LookupTableFlag_11|stage5.instruction_read_raf.opening.LookupTableFlag_12|stage5.instruction_read_raf.opening.LookupTableFlag_13|stage5.instruction_read_raf.opening.LookupTableFlag_14|stage5.instruction_read_raf.opening.LookupTableFlag_15|stage5.instruction_read_raf.opening.LookupTableFlag_16|stage5.instruction_read_raf.opening.LookupTableFlag_17|stage5.instruction_read_raf.opening.LookupTableFlag_18|stage5.instruction_read_raf.opening.LookupTableFlag_19|stage5.instruction_read_raf.opening.LookupTableFlag_20|stage5.instruction_read_raf.opening.LookupTableFlag_21|stage5.instruction_read_raf.opening.LookupTableFlag_22|stage5.instruction_read_raf.opening.LookupTableFlag_23|stage5.instruction_read_raf.opening.LookupTableFlag_24|stage5.instruction_read_raf.opening.LookupTableFlag_25|stage5.instruction_read_raf.opening.LookupTableFlag_26|stage5.instruction_read_raf.opening.LookupTableFlag_27|stage5.instruction_read_raf.opening.LookupTableFlag_28|stage5.instruction_read_raf.opening.LookupTableFlag_29|stage5.instruction_read_raf.opening.LookupTableFlag_30|stage5.instruction_read_raf.opening.LookupTableFlag_31|stage5.instruction_read_raf.opening.LookupTableFlag_32|stage5.instruction_read_raf.opening.LookupTableFlag_33|stage5.instruction_read_raf.opening.LookupTableFlag_34|stage5.instruction_read_raf.opening.LookupTableFlag_35|stage5.instruction_read_raf.opening.LookupTableFlag_36|stage5.instruction_read_raf.opening.LookupTableFlag_37|stage5.instruction_read_raf.opening.LookupTableFlag_38|stage5.instruction_read_raf.opening.LookupTableFlag_39|stage5.instruction_read_raf.opening.LookupTableFlag_40|stage5.instruction_read_raf.opening.InstructionRa_0|stage5.instruction_read_raf.opening.InstructionRa_1|stage5.instruction_read_raf.opening.InstructionRa_2|stage5.instruction_read_raf.opening.InstructionRa_3|stage5.instruction_read_raf.opening.InstructionRa_4|stage5.instruction_read_raf.opening.InstructionRa_5|stage5.instruction_read_raf.opening.InstructionRa_6|stage5.instruction_read_raf.opening.InstructionRa_7|stage5.instruction_read_raf.opening.InstructionRafFlag|stage5.ram_ra_claim_reduction.opening.RamRa|stage5.registers_val_evaluation.opening.RdInc|stage5.registers_val_evaluation.opening.RdWa", claim_operands: "stage5.instruction_read_raf.opening.LookupTableFlag_0|stage5.instruction_read_raf.opening.LookupTableFlag_1|stage5.instruction_read_raf.opening.LookupTableFlag_2|stage5.instruction_read_raf.opening.LookupTableFlag_3|stage5.instruction_read_raf.opening.LookupTableFlag_4|stage5.instruction_read_raf.opening.LookupTableFlag_5|stage5.instruction_read_raf.opening.LookupTableFlag_6|stage5.instruction_read_raf.opening.LookupTableFlag_7|stage5.instruction_read_raf.opening.LookupTableFlag_8|stage5.instruction_read_raf.opening.LookupTableFlag_9|stage5.instruction_read_raf.opening.LookupTableFlag_10|stage5.instruction_read_raf.opening.LookupTableFlag_11|stage5.instruction_read_raf.opening.LookupTableFlag_12|stage5.instruction_read_raf.opening.LookupTableFlag_13|stage5.instruction_read_raf.opening.LookupTableFlag_14|stage5.instruction_read_raf.opening.LookupTableFlag_15|stage5.instruction_read_raf.opening.LookupTableFlag_16|stage5.instruction_read_raf.opening.LookupTableFlag_17|stage5.instruction_read_raf.opening.LookupTableFlag_18|stage5.instruction_read_raf.opening.LookupTableFlag_19|stage5.instruction_read_raf.opening.LookupTableFlag_20|stage5.instruction_read_raf.opening.LookupTableFlag_21|stage5.instruction_read_raf.opening.LookupTableFlag_22|stage5.instruction_read_raf.opening.LookupTableFlag_23|stage5.instruction_read_raf.opening.LookupTableFlag_24|stage5.instruction_read_raf.opening.LookupTableFlag_25|stage5.instruction_read_raf.opening.LookupTableFlag_26|stage5.instruction_read_raf.opening.LookupTableFlag_27|stage5.instruction_read_raf.opening.LookupTableFlag_28|stage5.instruction_read_raf.opening.LookupTableFlag_29|stage5.instruction_read_raf.opening.LookupTableFlag_30|stage5.instruction_read_raf.opening.LookupTableFlag_31|stage5.instruction_read_raf.opening.LookupTableFlag_32|stage5.instruction_read_raf.opening.LookupTableFlag_33|stage5.instruction_read_raf.opening.LookupTableFlag_34|stage5.instruction_read_raf.opening.LookupTableFlag_35|stage5.instruction_read_raf.opening.LookupTableFlag_36|stage5.instruction_read_raf.opening.LookupTableFlag_37|stage5.instruction_read_raf.opening.LookupTableFlag_38|stage5.instruction_read_raf.opening.LookupTableFlag_39|stage5.instruction_read_raf.opening.LookupTableFlag_40|stage5.instruction_read_raf.opening.InstructionRa_0|stage5.instruction_read_raf.opening.InstructionRa_1|stage5.instruction_read_raf.opening.InstructionRa_2|stage5.instruction_read_raf.opening.InstructionRa_3|stage5.instruction_read_raf.opening.InstructionRa_4|stage5.instruction_read_raf.opening.InstructionRa_5|stage5.instruction_read_raf.opening.InstructionRa_6|stage5.instruction_read_raf.opening.InstructionRa_7|stage5.instruction_read_raf.opening.InstructionRafFlag|stage5.ram_ra_claim_reduction.opening.RamRa|stage5.registers_val_evaluation.opening.RdInc|stage5.registers_val_evaluation.opening.RdWa" }, +]; +pub const STAGE5_PROGRAM: Stage5VerifierProgramPlan = Stage5CpuProgramPlan { + role: "verifier", + params: STAGE5_PARAMS, + steps: STAGE5_PROGRAM_STEPS, + transcript_squeezes: STAGE5_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE5_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE5_OPENING_INPUTS, + field_constants: STAGE5_FIELD_CONSTANTS, + field_exprs: STAGE5_FIELD_EXPRS, + kernels: STAGE5_KERNELS, + claims: STAGE5_SUMCHECK_CLAIMS, + batches: STAGE5_SUMCHECK_BATCHES, + drivers: STAGE5_SUMCHECK_DRIVERS, + instance_results: STAGE5_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE5_SUMCHECK_EVALS, + point_slices: STAGE5_POINT_SLICES, + point_concats: STAGE5_POINT_CONCATS, + opening_claims: STAGE5_OPENING_CLAIMS, + opening_equalities: STAGE5_OPENING_EQUALITIES, + opening_batches: STAGE5_OPENING_BATCHES, +}; + +pub fn verify_stage5( + proof: &Stage5Proof, + opening_inputs: &[Stage5OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage5Error> +where + T: Transcript, +{ + verify_stage5_with_program(&STAGE5_PROGRAM, proof, opening_inputs, transcript) +} + +pub fn verify_stage5_with_program( + program: &'static Stage5VerifierProgramPlan, + proof: &Stage5Proof, + opening_inputs: &[Stage5OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage5Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage5Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = + super::common::ValueStore::with_opening_inputs(opening_inputs, program.opening_inputs)?; + store.seed_constants(program.field_constants); + let mut artifacts = Stage5ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage5Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage5_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "transcript_absorb_bytes" => { + let absorb = find_plan(program.transcript_absorb_bytes, step.symbol).ok_or( + VerifyStage5Error::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage5_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_plan(program.drivers, step.symbol).ok_or(VerifyStage5Error::MissingProof { + driver: step.symbol, + })?; + verify_stage5_driver(program, driver, proof, &mut store, transcript, &mut artifacts)?; + } + _ => { + return Err(VerifyStage5Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage5 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage5_verifier_program() -> &'static Stage5VerifierProgramPlan { + &STAGE5_PROGRAM +} + +fn verify_stage5_squeeze( + program: &'static Stage5VerifierProgramPlan, + squeeze: &'static Stage5TranscriptSqueezePlan, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage5ExecutionArtifacts, +) -> Result<(), VerifyStage5Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(squeeze, &values, |input, expected, actual| { + VerifyStage5Error::InvalidInputLength { + input, + expected, + actual, + } + })?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage5Error::from)?; + artifacts.challenge_vectors.push(Stage5ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn absorb_stage5_bytes(absorb: &'static Stage5TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn verify_stage5_driver( + program: &'static Stage5VerifierProgramPlan, + driver: &'static Stage5SumcheckDriverPlan, + proof: &Stage5Proof, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage5ExecutionArtifacts, +) -> Result<(), VerifyStage5Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage5Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage5.batched" => { + verify_batched_stage5(program, driver, proof, store, transcript)? + } + _ => return Err(VerifyStage5Error::UnsupportedRelation { relation }), + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_batched_stage5( + program: &'static Stage5VerifierProgramPlan, + driver: &'static Stage5SumcheckDriverPlan, + proof: &Stage5SumcheckOutput, + store: &mut super::common::ValueStore, + transcript: &mut T, +) -> Result, VerifyStage5Error> +where + T: Transcript, +{ + super::common::verify_batched_sumcheck( + driver, + proof, + program.claims, + program.batches, + program.field_exprs, + program.opening_inputs, + program.opening_claims, + program.opening_batches, + store, + transcript, + |store, evals, point, batching_coeffs| { + expected_batched_output_claim(program, driver, store, evals, point, batching_coeffs) + }, + |store, verified| observe_stage5_sumcheck_output(program, store, verified), + |driver, error| VerifyStage5Error::Sumcheck { driver, error }, + ) +} + +fn observe_stage5_sumcheck_output( + program: &'static Stage5VerifierProgramPlan, + store: &mut super::common::ValueStore, + output: &Stage5SumcheckOutput, +) -> Result<(), VerifyStage5Error> { + store.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + "instruction_read_raf" => { + point = normalize_instruction_read_raf_point(&point, "stage5.instruction_read_raf.point")?; + } + _ => { + return Err(VerifyStage5Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage5Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage5Error::MissingValue { symbol }, + )?; + store.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage5Error::InvalidInputLength { + input, + expected, + actual, + }, + )?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage5Error::from)?; + store.verify_opening_equalities( + program.opening_equalities, + |driver, reason| VerifyStage5Error::InvalidProof { driver, reason }, + |symbol| VerifyStage5Error::MissingValue { symbol }, + ) +} + +fn expected_batched_output_claim( + program: &'static Stage5VerifierProgramPlan, + driver: &'static Stage5SumcheckDriverPlan, + store: &super::common::ValueStore, + evals: &[Stage5NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage5Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage5Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let relation = claim.relation.unwrap_or(""); + let value = match relation { + "jolt.stage5.instruction_read_raf" => { + expected_instruction_read_raf(store, evals, local_point)? + } + "jolt.stage5.ram_ra_claim_reduction" => { + expected_ram_ra_claim_reduction(store, evals, local_point)? + } + "jolt.stage5.registers_val_evaluation" => { + expected_registers_val_evaluation(store, evals, local_point)? + } + _ => return Err(VerifyStage5Error::UnsupportedRelation { relation }), + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_instruction_read_raf( + store: &super::common::ValueStore, + evals: &[Stage5NamedEval], + local_point: &[Fr], +) -> Result { + const LOG_K: usize = 128; + const XLEN: usize = 64; + + if local_point.len() < LOG_K { + return Err(VerifyStage5Error::InvalidInputLength { + input: "stage5.instruction_read_raf.point", + expected: LOG_K, + actual: local_point.len(), + }); + } + + let (r_address_prime, r_cycle) = local_point.split_at(LOG_K); + let r_cycle_prime = reverse_slice(r_cycle); + let r_reduction = super::common::store_point(store, "stage5.input.stage2.instruction.LookupOutput")?; + let eq_eval_r_reduction = EqPolynomial::::mle(r_reduction, &r_cycle_prime); + + let left_operand_eval = operand_polynomial_eval(r_address_prime, true); + let right_operand_eval = operand_polynomial_eval(r_address_prime, false); + let identity_poly_eval = identity_polynomial_eval(r_address_prime); + + let table_values = LookupTableKind::::all() + .iter() + .map(|table| table.evaluate_mle::(r_address_prime)) + .collect::>(); + let table_flag_claims = indexed_evals_by_prefix( + evals, + "stage5.instruction_read_raf.eval.LookupTableFlag_", + table_values.len(), + )?; + let val_claim = table_values + .into_iter() + .zip(table_flag_claims) + .map(|(table_value, flag_claim)| table_value * flag_claim) + .sum::(); + + let ra_claim = indexed_evals_by_prefix_any( + evals, + "stage5.instruction_read_raf.eval.InstructionRa_", + )? + .into_iter() + .product::(); + let raf_flag_claim = eval_by_name( + evals, + "stage5.instruction_read_raf.eval.InstructionRafFlag", + )?; + let gamma = super::common::store_scalar(store, "stage5.instruction_read_raf.gamma")?; + + let raf_claim = (Fr::from_u64(1) - raf_flag_claim) + * (left_operand_eval + gamma * right_operand_eval) + + raf_flag_claim * gamma * identity_poly_eval; + Ok(eq_eval_r_reduction * ra_claim * (val_claim + gamma * raf_claim)) +} + +fn expected_ram_ra_claim_reduction( + store: &super::common::ValueStore, + evals: &[Stage5NamedEval], + local_point: &[Fr], +) -> Result { + let r_cycle_reduced = reverse_slice(local_point); + let r_cycle_raf = suffix_point( + super::common::store_point(store, "stage5.input.stage2.ram_raf.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage2.ram_raf.RamRa", + )?; + let r_cycle_rw = suffix_point( + super::common::store_point(store, "stage5.input.stage2.ram_read_write.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage2.ram_read_write.RamRa", + )?; + let r_cycle_val = suffix_point( + super::common::store_point(store, "stage5.input.stage4.ram_val_check.RamRa")?, + r_cycle_reduced.len(), + "stage5.input.stage4.ram_val_check.RamRa", + )?; + let gamma = super::common::store_scalar(store, "stage5.ram_ra_claim_reduction.gamma")?; + let eq_combined = EqPolynomial::::mle(r_cycle_raf, &r_cycle_reduced) + + gamma * EqPolynomial::::mle(r_cycle_rw, &r_cycle_reduced) + + gamma.square() * EqPolynomial::::mle(r_cycle_val, &r_cycle_reduced); + let ram_ra = eval_by_name(evals, "stage5.ram_ra_claim_reduction.eval.RamRa")?; + Ok(eq_combined * ram_ra) +} + +fn expected_registers_val_evaluation( + store: &super::common::ValueStore, + evals: &[Stage5NamedEval], + local_point: &[Fr], +) -> Result { + let registers_val_point = super::common::store_point(store, "stage5.input.stage4.registers.RegistersVal")?; + let r_cycle = suffix_point( + registers_val_point, + local_point.len(), + "stage5.input.stage4.registers.RegistersVal", + )?; + let r_reduced = reverse_slice(local_point); + let lt_eval = lt_polynomial_eval(&r_reduced, r_cycle); + let rd_inc = eval_by_name(evals, "stage5.registers_val_evaluation.eval.RdInc")?; + let rd_wa = eval_by_name(evals, "stage5.registers_val_evaluation.eval.RdWa")?; + Ok(rd_inc * rd_wa * lt_eval) +} diff --git a/crates/jolt-verifier/src/stages/stage6.rs b/crates/jolt-verifier/src/stages/stage6.rs new file mode 100644 index 0000000000..f65ada3fc1 --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage6.rs @@ -0,0 +1,988 @@ +#![allow(dead_code)] + +use super::common::{batch_claims, expected_stage67_booleanity, expected_stage67_bytecode_read_raf, expected_stage67_hamming_booleanity, expected_stage67_inc_claim_reduction, expected_stage67_instruction_ra_virtual, expected_stage67_ram_ra_virtual, find_batch, find_plan, normalize_bytecode_read_raf_point, normalize_instruction_read_raf_point, stage67_trace_rounds, Stage67BytecodeEntry, Stage67BytecodeSymbols, Stage67RelationSymbols}; +use jolt_field::{Field, Fr}; +use jolt_sumcheck::SumcheckError; +use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript}; + +pub type Stage6NamedEval = super::common::StageNamedEval; +pub type Stage6SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage6ChallengeVector = super::common::StageChallengeVector; +pub type Stage6ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage6Proof = super::common::StageProof; +pub type Stage6OpeningInputValue = super::common::StageOpeningInputValue; + +pub use super::common::{ + FieldConstantPlan as Stage6FieldConstantPlan, FieldExprPlan as Stage6FieldExprPlan, + KernelPlan as Stage6KernelPlan, OpeningBatchPlan as Stage6OpeningBatchPlan, + OpeningClaimEqualityPlan as Stage6OpeningClaimEqualityPlan, + OpeningClaimPlan as Stage6OpeningClaimPlan, OpeningInputPlan as Stage6OpeningInputPlan, + PointConcatPlan as Stage6PointConcatPlan, PointSlicePlan as Stage6PointSlicePlan, + PointZeroPlan as Stage6PointZeroPlan, ProgramStepPlan as Stage6ProgramStepPlan, + StageParams as Stage6Params, StageProgramPlan as Stage6CpuProgramPlan, + SumcheckBatchPlan as Stage6SumcheckBatchPlan, + SumcheckClaimPlan as Stage6SumcheckClaimPlan, SumcheckDriverPlan as Stage6SumcheckDriverPlan, + SumcheckEvalPlan as Stage6SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage6SumcheckInstanceResultPlan, + TranscriptAbsorbBytesPlan as Stage6TranscriptAbsorbBytesPlan, + TranscriptSqueezePlan as Stage6TranscriptSqueezePlan, +}; + +pub type DefaultStage6Transcript = Blake2bTranscript; +pub type Stage6VerifierProgramPlan = Stage6CpuProgramPlan; + +#[derive(Clone, Debug)] +pub struct Stage6BytecodeEntry { + pub address: Fr, + pub imm: Fr, + pub circuit_flags: [bool; 14], + pub rd: Option, + pub rs1: Option, + pub rs2: Option, + pub lookup_table: Option, + pub is_interleaved: bool, + pub is_branch: bool, + pub left_is_rs1: bool, + pub left_is_pc: bool, + pub right_is_rs2: bool, + pub right_is_imm: bool, + pub is_noop: bool, +} + +impl Stage67BytecodeEntry for Stage6BytecodeEntry { + fn address(&self) -> Fr { self.address } + fn imm(&self) -> Fr { self.imm } + fn circuit_flags(&self) -> &[bool; 14] { &self.circuit_flags } + fn rd(&self) -> Option { self.rd } + fn rs1(&self) -> Option { self.rs1 } + fn rs2(&self) -> Option { self.rs2 } + fn lookup_table(&self) -> Option { self.lookup_table } + fn is_interleaved(&self) -> bool { self.is_interleaved } + fn is_branch(&self) -> bool { self.is_branch } + fn left_is_rs1(&self) -> bool { self.left_is_rs1 } + fn left_is_pc(&self) -> bool { self.left_is_pc } + fn right_is_rs2(&self) -> bool { self.right_is_rs2 } + fn right_is_imm(&self) -> bool { self.right_is_imm } + fn is_noop(&self) -> bool { self.is_noop } +} + + +#[derive(Clone, Debug)] +pub struct Stage6BytecodeReadRafData { + pub entries: Vec, + pub entry_bytecode_index: usize, + pub num_lookup_tables: usize, +} + +#[derive(Clone, Debug)] +pub struct Stage6VerifierData { + pub bytecode_read_raf: Option, +} + +const STAGE6_RELATION_SYMBOLS: Stage67RelationSymbols = Stage67RelationSymbols { + hamming_booleanity_relation: "jolt.stage6.hamming_booleanity", + hamming_booleanity_instance: "stage6.hamming_booleanity.instance", + booleanity_point: "stage6.booleanity.point", + stage5_instruction_ra0: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + booleanity_combined_point: "stage6.booleanity.combined_point", + booleanity_gamma: "stage6.booleanity.gamma", + booleanity_instruction_ra_prefix: "stage6.booleanity.eval.InstructionRa_", + booleanity_bytecode_ra_prefix: "stage6.booleanity.eval.BytecodeRa_", + booleanity_ram_ra_prefix: "stage6.booleanity.eval.RamRa_", + hamming_weight_eval: "stage6.hamming_booleanity.eval.HammingWeight", + hamming_lookup_output: "stage6.input.stage1.LookupOutput", + ram_ra_virtual_cycle: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", + ram_ra_virtual_eval_prefix: "stage6.ram_ra_virtual.eval.RamRa_", + instruction_ra_virtual_cycle: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", + instruction_ra_virtual_eval_prefix: "stage6.instruction_ra_virtual.eval.InstructionRa_", + instruction_ra_virtual_input_prefix: "stage6.input.stage5.instruction_read_raf.InstructionRa_", + instruction_ra_virtual_gamma: "stage6.instruction_ra_virtual.gamma", + inc_ram_stage2: "stage6.input.stage2.ram_read_write.RamInc", + inc_ram_stage4: "stage6.input.stage4.ram_val_check.RamInc", + inc_rd_stage4: "stage6.input.stage4.registers_read_write.RdInc", + inc_rd_stage5: "stage6.input.stage5.registers_val_evaluation.RdInc", + inc_gamma: "stage6.inc_claim_reduction.gamma", + inc_ram_eval: "stage6.inc_claim_reduction.eval.RamInc", + inc_rd_eval: "stage6.inc_claim_reduction.eval.RdInc", +}; + +const STAGE6_BYTECODE_SYMBOLS: Stage67BytecodeSymbols = Stage67BytecodeSymbols { + point: "stage6.bytecode_read_raf.point", + gamma: "stage6.bytecode_read_raf.gamma", + bytecode_ra_eval_prefix: "stage6.bytecode_read_raf.eval.BytecodeRa_", + entries: "stage6.bytecode_read_raf.entries", + entry_bytecode_index: "stage6.bytecode_read_raf.entry_bytecode_index", + stage_gammas: [ + "stage6.bytecode_read_raf.stage1_gamma", + "stage6.bytecode_read_raf.stage2_gamma", + "stage6.bytecode_read_raf.stage3_gamma", + "stage6.bytecode_read_raf.stage4_gamma", + "stage6.bytecode_read_raf.stage5_gamma", + ], + stage_cycle_points: [ + "stage6.input.stage1.Imm", + "stage6.input.stage2.OpFlagJump", + "stage6.input.stage3.spartan_shift.UnexpandedPC", + "stage6.input.stage4.Rs1Ra", + "stage6.input.stage5.registers_val_evaluation.RdWa", + ], + stage4_register_point: "stage6.input.stage4.Rs1Ra", + stage5_register_point: "stage6.input.stage5.registers_val_evaluation.RdWa", + entry_rd: "stage6.bytecode.entry.rd", + entry_rs1: "stage6.bytecode.entry.rs1", + entry_rs2: "stage6.bytecode.entry.rs2", + entry_lookup_table: "stage6.bytecode.entry.lookup_table", +}; + +#[derive(Debug)] +pub enum VerifyStage6Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage6Error); + +pub const STAGE6_PARAMS: Stage6Params = Stage6Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE6_PROGRAM_STEPS: &[Stage6ProgramStepPlan] = &[ + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage1_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage2_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage3_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage4_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.bytecode_read_raf.stage5_gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.booleanity.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.instruction_ra_virtual.gamma" }, + Stage6ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage6.inc_claim_reduction.gamma" }, + Stage6ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage6.sumcheck" }, +]; + +pub const STAGE6_TRANSCRIPT_SQUEEZES: &[Stage6TranscriptSqueezePlan] = &[ + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.gamma", label: "bc_raf_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage1_gamma", label: "bc_raf_stage1_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage2_gamma", label: "bc_raf_stage2_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage3_gamma", label: "bc_raf_stage3_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage4_gamma", label: "bc_raf_stage4_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.bytecode_read_raf.stage5_gamma", label: "bc_raf_stage5_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.booleanity.gamma", label: "booleanity_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.instruction_ra_virtual.gamma", label: "inst_ra_virtual_gamma", kind: "challenge_scalar", count: 1 }, + Stage6TranscriptSqueezePlan { symbol: "stage6.inc_claim_reduction.gamma", label: "inc_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE6_TRANSCRIPT_ABSORB_BYTES: &[Stage6TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE6_OPENING_INPUTS: &[Stage6OpeningInputPlan] = &[ + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.UnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.Imm", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAddOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAddOperands", oracle: "OpFlagAddOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagSubtractOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagSubtractOperands", oracle: "OpFlagSubtractOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagMultiplyOperands", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagMultiplyOperands", oracle: "OpFlagMultiplyOperands", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagLoad", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagLoad", oracle: "OpFlagLoad", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagStore", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagStore", oracle: "OpFlagStore", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagJump", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagWriteLookupOutputToRD", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagVirtualInstruction", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAssert", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAssert", oracle: "OpFlagAssert", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagDoNotUpdateUnexpandedPC", oracle: "OpFlagDoNotUpdateUnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagAdvice", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagAdvice", oracle: "OpFlagAdvice", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsCompressed", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsCompressed", oracle: "OpFlagIsCompressed", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsFirstInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.OpFlagIsLastInSequence", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.OpFlagIsLastInSequence", oracle: "OpFlagIsLastInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagJump", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagJump", oracle: "OpFlagJump", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.InstructionFlagBranch", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.InstructionFlagBranch", oracle: "InstructionFlagBranch", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagWriteLookupOutputToRD", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagWriteLookupOutputToRD", oracle: "OpFlagWriteLookupOutputToRD", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.OpFlagVirtualInstruction", source_stage: "stage2", source_claim: "stage2.product_virtual.remainder.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.Imm", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.Imm", oracle: "Imm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.UnexpandedPC", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.UnexpandedPC", oracle: "UnexpandedPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsRs1Value", oracle: "InstructionFlagLeftOperandIsRs1Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagLeftOperandIsPC", oracle: "InstructionFlagLeftOperandIsPC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagRightOperandIsRs2Value", oracle: "InstructionFlagRightOperandIsRs2Value", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm", source_stage: "stage3", source_claim: "stage3.instruction_input.opening.InstructionFlagRightOperandIsImm", oracle: "InstructionFlagRightOperandIsImm", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.InstructionFlagIsNoop", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.InstructionFlagIsNoop", oracle: "InstructionFlagIsNoop", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.OpFlagVirtualInstruction", oracle: "OpFlagVirtualInstruction", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.OpFlagIsFirstInSequence", oracle: "OpFlagIsFirstInSequence", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.RdWa", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.Rs1Ra", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.Rs1Ra", oracle: "Rs1Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.Rs2Ra", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.Rs2Ra", oracle: "Rs2Ra", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.registers_val_evaluation.RdWa", source_stage: "stage5", source_claim: "stage5.registers_val_evaluation.opening.RdWa", oracle: "RdWa", domain: "jolt.stage4_registers_rw_domain", point_arity: 23, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.InstructionRafFlag", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRafFlag", oracle: "InstructionRafFlag", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_0", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_0", oracle: "LookupTableFlag_0", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_1", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_1", oracle: "LookupTableFlag_1", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_2", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_2", oracle: "LookupTableFlag_2", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_3", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_3", oracle: "LookupTableFlag_3", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_4", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_4", oracle: "LookupTableFlag_4", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_5", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_5", oracle: "LookupTableFlag_5", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_6", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_6", oracle: "LookupTableFlag_6", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_7", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_7", oracle: "LookupTableFlag_7", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_8", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_8", oracle: "LookupTableFlag_8", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_9", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_9", oracle: "LookupTableFlag_9", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_10", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_10", oracle: "LookupTableFlag_10", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_11", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_11", oracle: "LookupTableFlag_11", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_12", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_12", oracle: "LookupTableFlag_12", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_13", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_13", oracle: "LookupTableFlag_13", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_14", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_14", oracle: "LookupTableFlag_14", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_15", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_15", oracle: "LookupTableFlag_15", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_16", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_16", oracle: "LookupTableFlag_16", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_17", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_17", oracle: "LookupTableFlag_17", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_18", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_18", oracle: "LookupTableFlag_18", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_19", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_19", oracle: "LookupTableFlag_19", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_20", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_20", oracle: "LookupTableFlag_20", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_21", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_21", oracle: "LookupTableFlag_21", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_22", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_22", oracle: "LookupTableFlag_22", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_23", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_23", oracle: "LookupTableFlag_23", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_24", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_24", oracle: "LookupTableFlag_24", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_25", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_25", oracle: "LookupTableFlag_25", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_26", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_26", oracle: "LookupTableFlag_26", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_27", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_27", oracle: "LookupTableFlag_27", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_28", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_28", oracle: "LookupTableFlag_28", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_29", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_29", oracle: "LookupTableFlag_29", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_30", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_30", oracle: "LookupTableFlag_30", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_31", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_31", oracle: "LookupTableFlag_31", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_32", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_32", oracle: "LookupTableFlag_32", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_33", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_33", oracle: "LookupTableFlag_33", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_34", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_34", oracle: "LookupTableFlag_34", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_35", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_35", oracle: "LookupTableFlag_35", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_36", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_36", oracle: "LookupTableFlag_36", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_37", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_37", oracle: "LookupTableFlag_37", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_38", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_38", oracle: "LookupTableFlag_38", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_39", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_39", oracle: "LookupTableFlag_39", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.LookupTableFlag_40", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.LookupTableFlag_40", oracle: "LookupTableFlag_40", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.PC", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage3.spartan_shift.PC", source_stage: "stage3", source_claim: "stage3.spartan_shift.opening.PC", oracle: "PC", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", source_stage: "stage5", source_claim: "stage5.ram_ra_claim_reduction.opening.RamRa", oracle: "RamRa", domain: "jolt.stage2_ram_rw_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", source_stage: "stage5", source_claim: "stage5.instruction_read_raf.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.stage5_instruction_ra_chunk_domain", point_arity: 32, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage1.LookupOutput", source_stage: "stage1", source_claim: "stage1.outer_remaining.opening.LookupOutput", oracle: "LookupOutput", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage2.ram_read_write.RamInc", source_stage: "stage2", source_claim: "stage2.ram_read_write.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.ram_val_check.RamInc", source_stage: "stage4", source_claim: "stage4.ram_val_check.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage4.registers_read_write.RdInc", source_stage: "stage4", source_claim: "stage4.registers_read_write.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, + Stage6OpeningInputPlan { symbol: "stage6.input.stage5.registers_val_evaluation.RdInc", source_stage: "stage5", source_claim: "stage5.registers_val_evaluation.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed" }, +]; + +pub const STAGE6_FIELD_CONSTANTS: &[Stage6FieldConstantPlan] = &[ + Stage6FieldConstantPlan { symbol: "stage6.zero", field: "bn254_fr", value: 0 }, +]; + +macro_rules! stage6_field_expr { + ($symbol:literal, $formula:literal, $operands:literal) => { + Stage6FieldExprPlan { symbol: $symbol, kind: "op", formula: $formula, operands: $operands } + }; +} + +#[rustfmt::skip] +pub const STAGE6_FIELD_EXPRS: &[Stage6FieldExprPlan] = &[ + stage6_field_expr!("stage6.booleanity.gamma_sq_0", "field.pow:0", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_1", "field.pow:2", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_2", "field.pow:4", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_3", "field.pow:6", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_4", "field.pow:8", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_5", "field.pow:10", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_6", "field.pow:12", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_7", "field.pow:14", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_sq_8", "field.pow:16", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_9", "field.pow:18", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_10", "field.pow:20", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_11", "field.pow:22", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_12", "field.pow:24", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_13", "field.pow:26", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_14", "field.pow:28", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_15", "field.pow:30", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_sq_16", "field.pow:32", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_17", "field.pow:34", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_18", "field.pow:36", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_19", "field.pow:38", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_20", "field.pow:40", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_21", "field.pow:42", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_22", "field.pow:44", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_23", "field.pow:46", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_sq_24", "field.pow:48", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_25", "field.pow:50", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_26", "field.pow:52", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_27", "field.pow:54", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_28", "field.pow:56", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_29", "field.pow:58", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_30", "field.pow:60", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_31", "field.pow:62", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_sq_32", "field.pow:64", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_33", "field.pow:66", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_34", "field.pow:68", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_35", "field.pow:70", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_36", "field.pow:72", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_37", "field.pow:74", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_sq_38", "field.pow:76", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_0", "field.pow:0", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_pow_1", "field.pow:1", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_2", "field.pow:2", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_3", "field.pow:3", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_4", "field.pow:4", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_5", "field.pow:5", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_6", "field.pow:6", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_7", "field.pow:7", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_8", "field.pow:8", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_pow_9", "field.pow:9", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_10", "field.pow:10", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_11", "field.pow:11", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_12", "field.pow:12", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_13", "field.pow:13", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_14", "field.pow:14", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_15", "field.pow:15", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_16", "field.pow:16", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_pow_17", "field.pow:17", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_18", "field.pow:18", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_19", "field.pow:19", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_20", "field.pow:20", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_21", "field.pow:21", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_22", "field.pow:22", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_23", "field.pow:23", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_24", "field.pow:24", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_pow_25", "field.pow:25", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_26", "field.pow:26", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_27", "field.pow:27", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_28", "field.pow:28", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_29", "field.pow:29", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_30", "field.pow:30", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_31", "field.pow:31", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_32", "field.pow:32", "stage6.booleanity.gamma"), + stage6_field_expr!("stage6.booleanity.gamma_pow_33", "field.pow:33", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_34", "field.pow:34", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_35", "field.pow:35", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_36", "field.pow:36", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_37", "field.pow:37", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.booleanity.gamma_pow_38", "field.pow:38", "stage6.booleanity.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term1.stage_gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term1.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term1.stage_gamma_pow|stage6.input.stage1.Imm"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term2.stage_gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term2.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term2.stage_gamma_pow|stage6.input.stage1.OpFlagAddOperands"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term3.stage_gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term3.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term3.stage_gamma_pow|stage6.input.stage1.OpFlagSubtractOperands"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term4.stage_gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term4.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term4.stage_gamma_pow|stage6.input.stage1.OpFlagMultiplyOperands"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term5.stage_gamma_pow", "field.pow:5", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term5.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term5.stage_gamma_pow|stage6.input.stage1.OpFlagLoad"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term6.stage_gamma_pow", "field.pow:6", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term6.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term6.stage_gamma_pow|stage6.input.stage1.OpFlagStore"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term7.stage_gamma_pow", "field.pow:7", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term7.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term7.stage_gamma_pow|stage6.input.stage1.OpFlagJump"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term8.stage_gamma_pow", "field.pow:8", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term8.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term8.stage_gamma_pow|stage6.input.stage1.OpFlagWriteLookupOutputToRD"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term9.stage_gamma_pow", "field.pow:9", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term9.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term9.stage_gamma_pow|stage6.input.stage1.OpFlagVirtualInstruction"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term10.stage_gamma_pow", "field.pow:10", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term10.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term10.stage_gamma_pow|stage6.input.stage1.OpFlagAssert"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term11.stage_gamma_pow", "field.pow:11", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term11.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term11.stage_gamma_pow|stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term12.stage_gamma_pow", "field.pow:12", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term12.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term12.stage_gamma_pow|stage6.input.stage1.OpFlagAdvice"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term13.stage_gamma_pow", "field.pow:13", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term13.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term13.stage_gamma_pow|stage6.input.stage1.OpFlagIsCompressed"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term14.stage_gamma_pow", "field.pow:14", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term14.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term14.stage_gamma_pow|stage6.input.stage1.OpFlagIsFirstInSequence"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term15.stage_gamma_pow", "field.pow:15", "stage6.bytecode_read_raf.stage1_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term15.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term15.stage_gamma_pow|stage6.input.stage1.OpFlagIsLastInSequence"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term16.gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term16.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term16.gamma_pow|stage6.input.stage2.OpFlagJump"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term17.stage_gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.stage2_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term17.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term17.stage_gamma_pow|stage6.input.stage2.InstructionFlagBranch"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term17.gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term17.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term17.gamma_pow|stage6.bytecode_read_raf.claim.term17.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term18.stage_gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.stage2_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term18.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term18.stage_gamma_pow|stage6.input.stage2.OpFlagWriteLookupOutputToRD"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term18.gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term18.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term18.gamma_pow|stage6.bytecode_read_raf.claim.term18.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term19.stage_gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.stage2_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term19.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term19.stage_gamma_pow|stage6.input.stage2.OpFlagVirtualInstruction"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term19.gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term19.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term19.gamma_pow|stage6.bytecode_read_raf.claim.term19.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term20.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term20.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term20.gamma_pow|stage6.input.stage3.instruction_input.Imm"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term21.stage_gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term21.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term21.stage_gamma_pow|stage6.input.stage3.spartan_shift.UnexpandedPC"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term21.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term21.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term21.gamma_pow|stage6.bytecode_read_raf.claim.term21.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term22.stage_gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term22.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term22.stage_gamma_pow|stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term22.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term22.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term22.gamma_pow|stage6.bytecode_read_raf.claim.term22.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term23.stage_gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term23.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term23.stage_gamma_pow|stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term23.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term23.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term23.gamma_pow|stage6.bytecode_read_raf.claim.term23.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term24.stage_gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term24.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term24.stage_gamma_pow|stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term24.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term24.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term24.gamma_pow|stage6.bytecode_read_raf.claim.term24.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term25.stage_gamma_pow", "field.pow:5", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term25.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term25.stage_gamma_pow|stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term25.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term25.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term25.gamma_pow|stage6.bytecode_read_raf.claim.term25.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term26.stage_gamma_pow", "field.pow:6", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term26.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term26.stage_gamma_pow|stage6.input.stage3.spartan_shift.InstructionFlagIsNoop"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term26.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term26.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term26.gamma_pow|stage6.bytecode_read_raf.claim.term26.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term27.stage_gamma_pow", "field.pow:7", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term27.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term27.stage_gamma_pow|stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term27.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term27.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term27.gamma_pow|stage6.bytecode_read_raf.claim.term27.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term28.stage_gamma_pow", "field.pow:8", "stage6.bytecode_read_raf.stage3_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term28.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term28.stage_gamma_pow|stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term28.gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term28.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term28.gamma_pow|stage6.bytecode_read_raf.claim.term28.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term29.gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term29.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term29.gamma_pow|stage6.input.stage4.RdWa"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term30.stage_gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.stage4_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term30.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term30.stage_gamma_pow|stage6.input.stage4.Rs1Ra"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term30.gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term30.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term30.gamma_pow|stage6.bytecode_read_raf.claim.term30.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term31.stage_gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.stage4_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term31.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term31.stage_gamma_pow|stage6.input.stage4.Rs2Ra"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term31.gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term31.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term31.gamma_pow|stage6.bytecode_read_raf.claim.term31.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term32.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term32.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term32.gamma_pow|stage6.input.stage5.registers_val_evaluation.RdWa"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term33.stage_gamma_pow", "field.pow:1", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term33.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term33.stage_gamma_pow|stage6.input.stage5.InstructionRafFlag"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term33.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term33.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term33.gamma_pow|stage6.bytecode_read_raf.claim.term33.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term34.stage_gamma_pow", "field.pow:2", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term34.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term34.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_0"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term34.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term34.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term34.gamma_pow|stage6.bytecode_read_raf.claim.term34.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term35.stage_gamma_pow", "field.pow:3", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term35.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term35.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_1"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term35.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term35.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term35.gamma_pow|stage6.bytecode_read_raf.claim.term35.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term36.stage_gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term36.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term36.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_2"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term36.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term36.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term36.gamma_pow|stage6.bytecode_read_raf.claim.term36.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term37.stage_gamma_pow", "field.pow:5", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term37.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term37.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_3"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term37.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term37.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term37.gamma_pow|stage6.bytecode_read_raf.claim.term37.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term38.stage_gamma_pow", "field.pow:6", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term38.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term38.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_4"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term38.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term38.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term38.gamma_pow|stage6.bytecode_read_raf.claim.term38.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term39.stage_gamma_pow", "field.pow:7", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term39.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term39.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_5"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term39.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term39.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term39.gamma_pow|stage6.bytecode_read_raf.claim.term39.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term40.stage_gamma_pow", "field.pow:8", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term40.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term40.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_6"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term40.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term40.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term40.gamma_pow|stage6.bytecode_read_raf.claim.term40.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term41.stage_gamma_pow", "field.pow:9", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term41.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term41.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_7"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term41.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term41.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term41.gamma_pow|stage6.bytecode_read_raf.claim.term41.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term42.stage_gamma_pow", "field.pow:10", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term42.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term42.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_8"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term42.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term42.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term42.gamma_pow|stage6.bytecode_read_raf.claim.term42.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term43.stage_gamma_pow", "field.pow:11", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term43.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term43.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_9"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term43.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term43.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term43.gamma_pow|stage6.bytecode_read_raf.claim.term43.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term44.stage_gamma_pow", "field.pow:12", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term44.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term44.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_10"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term44.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term44.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term44.gamma_pow|stage6.bytecode_read_raf.claim.term44.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term45.stage_gamma_pow", "field.pow:13", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term45.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term45.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_11"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term45.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term45.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term45.gamma_pow|stage6.bytecode_read_raf.claim.term45.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term46.stage_gamma_pow", "field.pow:14", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term46.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term46.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_12"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term46.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term46.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term46.gamma_pow|stage6.bytecode_read_raf.claim.term46.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term47.stage_gamma_pow", "field.pow:15", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term47.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term47.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_13"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term47.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term47.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term47.gamma_pow|stage6.bytecode_read_raf.claim.term47.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term48.stage_gamma_pow", "field.pow:16", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term48.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term48.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_14"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term48.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term48.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term48.gamma_pow|stage6.bytecode_read_raf.claim.term48.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term49.stage_gamma_pow", "field.pow:17", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term49.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term49.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_15"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term49.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term49.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term49.gamma_pow|stage6.bytecode_read_raf.claim.term49.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term50.stage_gamma_pow", "field.pow:18", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term50.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term50.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_16"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term50.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term50.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term50.gamma_pow|stage6.bytecode_read_raf.claim.term50.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term51.stage_gamma_pow", "field.pow:19", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term51.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term51.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_17"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term51.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term51.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term51.gamma_pow|stage6.bytecode_read_raf.claim.term51.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term52.stage_gamma_pow", "field.pow:20", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term52.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term52.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_18"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term52.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term52.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term52.gamma_pow|stage6.bytecode_read_raf.claim.term52.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term53.stage_gamma_pow", "field.pow:21", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term53.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term53.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_19"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term53.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term53.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term53.gamma_pow|stage6.bytecode_read_raf.claim.term53.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term54.stage_gamma_pow", "field.pow:22", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term54.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term54.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_20"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term54.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term54.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term54.gamma_pow|stage6.bytecode_read_raf.claim.term54.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term55.stage_gamma_pow", "field.pow:23", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term55.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term55.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_21"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term55.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term55.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term55.gamma_pow|stage6.bytecode_read_raf.claim.term55.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term56.stage_gamma_pow", "field.pow:24", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term56.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term56.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_22"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term56.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term56.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term56.gamma_pow|stage6.bytecode_read_raf.claim.term56.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term57.stage_gamma_pow", "field.pow:25", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term57.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term57.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_23"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term57.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term57.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term57.gamma_pow|stage6.bytecode_read_raf.claim.term57.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term58.stage_gamma_pow", "field.pow:26", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term58.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term58.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_24"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term58.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term58.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term58.gamma_pow|stage6.bytecode_read_raf.claim.term58.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term59.stage_gamma_pow", "field.pow:27", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term59.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term59.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_25"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term59.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term59.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term59.gamma_pow|stage6.bytecode_read_raf.claim.term59.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term60.stage_gamma_pow", "field.pow:28", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term60.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term60.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_26"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term60.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term60.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term60.gamma_pow|stage6.bytecode_read_raf.claim.term60.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term61.stage_gamma_pow", "field.pow:29", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term61.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term61.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_27"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term61.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term61.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term61.gamma_pow|stage6.bytecode_read_raf.claim.term61.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term62.stage_gamma_pow", "field.pow:30", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term62.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term62.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_28"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term62.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term62.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term62.gamma_pow|stage6.bytecode_read_raf.claim.term62.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term63.stage_gamma_pow", "field.pow:31", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term63.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term63.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_29"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term63.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term63.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term63.gamma_pow|stage6.bytecode_read_raf.claim.term63.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term64.stage_gamma_pow", "field.pow:32", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term64.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term64.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_30"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term64.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term64.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term64.gamma_pow|stage6.bytecode_read_raf.claim.term64.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term65.stage_gamma_pow", "field.pow:33", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term65.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term65.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_31"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term65.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term65.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term65.gamma_pow|stage6.bytecode_read_raf.claim.term65.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term66.stage_gamma_pow", "field.pow:34", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term66.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term66.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_32"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term66.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term66.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term66.gamma_pow|stage6.bytecode_read_raf.claim.term66.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term67.stage_gamma_pow", "field.pow:35", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term67.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term67.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_33"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term67.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term67.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term67.gamma_pow|stage6.bytecode_read_raf.claim.term67.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term68.stage_gamma_pow", "field.pow:36", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term68.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term68.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_34"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term68.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term68.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term68.gamma_pow|stage6.bytecode_read_raf.claim.term68.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term69.stage_gamma_pow", "field.pow:37", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term69.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term69.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_35"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term69.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term69.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term69.gamma_pow|stage6.bytecode_read_raf.claim.term69.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term70.stage_gamma_pow", "field.pow:38", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term70.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term70.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_36"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term70.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term70.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term70.gamma_pow|stage6.bytecode_read_raf.claim.term70.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term71.stage_gamma_pow", "field.pow:39", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term71.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term71.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_37"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term71.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term71.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term71.gamma_pow|stage6.bytecode_read_raf.claim.term71.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term72.stage_gamma_pow", "field.pow:40", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term72.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term72.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_38"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term72.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term72.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term72.gamma_pow|stage6.bytecode_read_raf.claim.term72.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term73.stage_gamma_pow", "field.pow:41", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term73.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term73.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_39"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term73.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term73.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term73.gamma_pow|stage6.bytecode_read_raf.claim.term73.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term74.stage_gamma_pow", "field.pow:42", "stage6.bytecode_read_raf.stage5_gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term74.stage_gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term74.stage_gamma_pow|stage6.input.stage5.LookupTableFlag_40"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term74.gamma_pow", "field.pow:4", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term74.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term74.gamma_pow|stage6.bytecode_read_raf.claim.term74.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim.term75.gamma_pow", "field.pow:5", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term75.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term75.gamma_pow|stage6.input.stage1.PC"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term76.gamma_pow", "field.pow:6", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim.term76.gamma_term", "field.mul", "stage6.bytecode_read_raf.claim.term76.gamma_pow|stage6.input.stage3.spartan_shift.PC"), stage6_field_expr!("stage6.bytecode_read_raf.claim.entry_constant", "field.pow:7", "stage6.bytecode_read_raf.gamma"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial0", "field.add", "stage6.input.stage1.UnexpandedPC|stage6.bytecode_read_raf.claim.term1.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial1", "field.add", "stage6.bytecode_read_raf.claim_expr.partial0|stage6.bytecode_read_raf.claim.term2.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial2", "field.add", "stage6.bytecode_read_raf.claim_expr.partial1|stage6.bytecode_read_raf.claim.term3.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial3", "field.add", "stage6.bytecode_read_raf.claim_expr.partial2|stage6.bytecode_read_raf.claim.term4.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial4", "field.add", "stage6.bytecode_read_raf.claim_expr.partial3|stage6.bytecode_read_raf.claim.term5.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial5", "field.add", "stage6.bytecode_read_raf.claim_expr.partial4|stage6.bytecode_read_raf.claim.term6.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial6", "field.add", "stage6.bytecode_read_raf.claim_expr.partial5|stage6.bytecode_read_raf.claim.term7.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial7", "field.add", "stage6.bytecode_read_raf.claim_expr.partial6|stage6.bytecode_read_raf.claim.term8.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial8", "field.add", "stage6.bytecode_read_raf.claim_expr.partial7|stage6.bytecode_read_raf.claim.term9.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial9", "field.add", "stage6.bytecode_read_raf.claim_expr.partial8|stage6.bytecode_read_raf.claim.term10.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial10", "field.add", "stage6.bytecode_read_raf.claim_expr.partial9|stage6.bytecode_read_raf.claim.term11.stage_gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial11", "field.add", "stage6.bytecode_read_raf.claim_expr.partial10|stage6.bytecode_read_raf.claim.term12.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial12", "field.add", "stage6.bytecode_read_raf.claim_expr.partial11|stage6.bytecode_read_raf.claim.term13.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial13", "field.add", "stage6.bytecode_read_raf.claim_expr.partial12|stage6.bytecode_read_raf.claim.term14.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial14", "field.add", "stage6.bytecode_read_raf.claim_expr.partial13|stage6.bytecode_read_raf.claim.term15.stage_gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial15", "field.add", "stage6.bytecode_read_raf.claim_expr.partial14|stage6.bytecode_read_raf.claim.term16.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial16", "field.add", "stage6.bytecode_read_raf.claim_expr.partial15|stage6.bytecode_read_raf.claim.term17.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial17", "field.add", "stage6.bytecode_read_raf.claim_expr.partial16|stage6.bytecode_read_raf.claim.term18.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial18", "field.add", "stage6.bytecode_read_raf.claim_expr.partial17|stage6.bytecode_read_raf.claim.term19.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial19", "field.add", "stage6.bytecode_read_raf.claim_expr.partial18|stage6.bytecode_read_raf.claim.term20.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial20", "field.add", "stage6.bytecode_read_raf.claim_expr.partial19|stage6.bytecode_read_raf.claim.term21.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial21", "field.add", "stage6.bytecode_read_raf.claim_expr.partial20|stage6.bytecode_read_raf.claim.term22.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial22", "field.add", "stage6.bytecode_read_raf.claim_expr.partial21|stage6.bytecode_read_raf.claim.term23.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial23", "field.add", "stage6.bytecode_read_raf.claim_expr.partial22|stage6.bytecode_read_raf.claim.term24.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial24", "field.add", "stage6.bytecode_read_raf.claim_expr.partial23|stage6.bytecode_read_raf.claim.term25.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial25", "field.add", "stage6.bytecode_read_raf.claim_expr.partial24|stage6.bytecode_read_raf.claim.term26.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial26", "field.add", "stage6.bytecode_read_raf.claim_expr.partial25|stage6.bytecode_read_raf.claim.term27.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial27", "field.add", "stage6.bytecode_read_raf.claim_expr.partial26|stage6.bytecode_read_raf.claim.term28.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial28", "field.add", "stage6.bytecode_read_raf.claim_expr.partial27|stage6.bytecode_read_raf.claim.term29.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial29", "field.add", "stage6.bytecode_read_raf.claim_expr.partial28|stage6.bytecode_read_raf.claim.term30.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial30", "field.add", "stage6.bytecode_read_raf.claim_expr.partial29|stage6.bytecode_read_raf.claim.term31.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial31", "field.add", "stage6.bytecode_read_raf.claim_expr.partial30|stage6.bytecode_read_raf.claim.term32.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial32", "field.add", "stage6.bytecode_read_raf.claim_expr.partial31|stage6.bytecode_read_raf.claim.term33.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial33", "field.add", "stage6.bytecode_read_raf.claim_expr.partial32|stage6.bytecode_read_raf.claim.term34.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial34", "field.add", "stage6.bytecode_read_raf.claim_expr.partial33|stage6.bytecode_read_raf.claim.term35.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial35", "field.add", "stage6.bytecode_read_raf.claim_expr.partial34|stage6.bytecode_read_raf.claim.term36.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial36", "field.add", "stage6.bytecode_read_raf.claim_expr.partial35|stage6.bytecode_read_raf.claim.term37.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial37", "field.add", "stage6.bytecode_read_raf.claim_expr.partial36|stage6.bytecode_read_raf.claim.term38.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial38", "field.add", "stage6.bytecode_read_raf.claim_expr.partial37|stage6.bytecode_read_raf.claim.term39.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial39", "field.add", "stage6.bytecode_read_raf.claim_expr.partial38|stage6.bytecode_read_raf.claim.term40.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial40", "field.add", "stage6.bytecode_read_raf.claim_expr.partial39|stage6.bytecode_read_raf.claim.term41.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial41", "field.add", "stage6.bytecode_read_raf.claim_expr.partial40|stage6.bytecode_read_raf.claim.term42.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial42", "field.add", "stage6.bytecode_read_raf.claim_expr.partial41|stage6.bytecode_read_raf.claim.term43.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial43", "field.add", "stage6.bytecode_read_raf.claim_expr.partial42|stage6.bytecode_read_raf.claim.term44.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial44", "field.add", "stage6.bytecode_read_raf.claim_expr.partial43|stage6.bytecode_read_raf.claim.term45.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial45", "field.add", "stage6.bytecode_read_raf.claim_expr.partial44|stage6.bytecode_read_raf.claim.term46.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial46", "field.add", "stage6.bytecode_read_raf.claim_expr.partial45|stage6.bytecode_read_raf.claim.term47.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial47", "field.add", "stage6.bytecode_read_raf.claim_expr.partial46|stage6.bytecode_read_raf.claim.term48.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial48", "field.add", "stage6.bytecode_read_raf.claim_expr.partial47|stage6.bytecode_read_raf.claim.term49.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial49", "field.add", "stage6.bytecode_read_raf.claim_expr.partial48|stage6.bytecode_read_raf.claim.term50.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial50", "field.add", "stage6.bytecode_read_raf.claim_expr.partial49|stage6.bytecode_read_raf.claim.term51.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial51", "field.add", "stage6.bytecode_read_raf.claim_expr.partial50|stage6.bytecode_read_raf.claim.term52.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial52", "field.add", "stage6.bytecode_read_raf.claim_expr.partial51|stage6.bytecode_read_raf.claim.term53.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial53", "field.add", "stage6.bytecode_read_raf.claim_expr.partial52|stage6.bytecode_read_raf.claim.term54.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial54", "field.add", "stage6.bytecode_read_raf.claim_expr.partial53|stage6.bytecode_read_raf.claim.term55.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial55", "field.add", "stage6.bytecode_read_raf.claim_expr.partial54|stage6.bytecode_read_raf.claim.term56.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial56", "field.add", "stage6.bytecode_read_raf.claim_expr.partial55|stage6.bytecode_read_raf.claim.term57.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial57", "field.add", "stage6.bytecode_read_raf.claim_expr.partial56|stage6.bytecode_read_raf.claim.term58.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial58", "field.add", "stage6.bytecode_read_raf.claim_expr.partial57|stage6.bytecode_read_raf.claim.term59.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial59", "field.add", "stage6.bytecode_read_raf.claim_expr.partial58|stage6.bytecode_read_raf.claim.term60.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial60", "field.add", "stage6.bytecode_read_raf.claim_expr.partial59|stage6.bytecode_read_raf.claim.term61.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial61", "field.add", "stage6.bytecode_read_raf.claim_expr.partial60|stage6.bytecode_read_raf.claim.term62.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial62", "field.add", "stage6.bytecode_read_raf.claim_expr.partial61|stage6.bytecode_read_raf.claim.term63.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial63", "field.add", "stage6.bytecode_read_raf.claim_expr.partial62|stage6.bytecode_read_raf.claim.term64.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial64", "field.add", "stage6.bytecode_read_raf.claim_expr.partial63|stage6.bytecode_read_raf.claim.term65.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial65", "field.add", "stage6.bytecode_read_raf.claim_expr.partial64|stage6.bytecode_read_raf.claim.term66.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial66", "field.add", "stage6.bytecode_read_raf.claim_expr.partial65|stage6.bytecode_read_raf.claim.term67.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial67", "field.add", "stage6.bytecode_read_raf.claim_expr.partial66|stage6.bytecode_read_raf.claim.term68.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial68", "field.add", "stage6.bytecode_read_raf.claim_expr.partial67|stage6.bytecode_read_raf.claim.term69.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial69", "field.add", "stage6.bytecode_read_raf.claim_expr.partial68|stage6.bytecode_read_raf.claim.term70.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial70", "field.add", "stage6.bytecode_read_raf.claim_expr.partial69|stage6.bytecode_read_raf.claim.term71.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial71", "field.add", "stage6.bytecode_read_raf.claim_expr.partial70|stage6.bytecode_read_raf.claim.term72.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial72", "field.add", "stage6.bytecode_read_raf.claim_expr.partial71|stage6.bytecode_read_raf.claim.term73.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial73", "field.add", "stage6.bytecode_read_raf.claim_expr.partial72|stage6.bytecode_read_raf.claim.term74.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial74", "field.add", "stage6.bytecode_read_raf.claim_expr.partial73|stage6.bytecode_read_raf.claim.term75.gamma_term"), + stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial75", "field.add", "stage6.bytecode_read_raf.claim_expr.partial74|stage6.bytecode_read_raf.claim.term76.gamma_term"), stage6_field_expr!("stage6.bytecode_read_raf.claim_expr.partial76", "field.add", "stage6.bytecode_read_raf.claim_expr.partial75|stage6.bytecode_read_raf.claim.entry_constant"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term1.gamma_pow", "field.pow:1", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term1.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term1.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_1"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term2.gamma_pow", "field.pow:2", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term2.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term2.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_2"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term3.gamma_pow", "field.pow:3", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term3.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term3.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_3"), + stage6_field_expr!("stage6.instruction_ra_virtual.claim.term4.gamma_pow", "field.pow:4", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term4.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term4.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_4"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term5.gamma_pow", "field.pow:5", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term5.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term5.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_5"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term6.gamma_pow", "field.pow:6", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term6.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term6.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_6"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term7.gamma_pow", "field.pow:7", "stage6.instruction_ra_virtual.gamma"), stage6_field_expr!("stage6.instruction_ra_virtual.claim.term7.gamma_term", "field.mul", "stage6.instruction_ra_virtual.claim.term7.gamma_pow|stage6.input.stage5.instruction_read_raf.InstructionRa_7"), + stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial0", "field.add", "stage6.input.stage5.instruction_read_raf.InstructionRa_0|stage6.instruction_ra_virtual.claim.term1.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial1", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial0|stage6.instruction_ra_virtual.claim.term2.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial2", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial1|stage6.instruction_ra_virtual.claim.term3.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial3", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial2|stage6.instruction_ra_virtual.claim.term4.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial4", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial3|stage6.instruction_ra_virtual.claim.term5.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial5", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial4|stage6.instruction_ra_virtual.claim.term6.gamma_term"), stage6_field_expr!("stage6.instruction_ra_virtual.claim_expr.partial6", "field.add", "stage6.instruction_ra_virtual.claim_expr.partial5|stage6.instruction_ra_virtual.claim.term7.gamma_term"), stage6_field_expr!("stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_pow", "field.pow:1", "stage6.inc_claim_reduction.gamma"), + stage6_field_expr!("stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_term", "field.mul", "stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_pow|stage6.input.stage4.ram_val_check.RamInc"), stage6_field_expr!("stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_pow", "field.pow:2", "stage6.inc_claim_reduction.gamma"), stage6_field_expr!("stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_term", "field.mul", "stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_pow|stage6.input.stage4.registers_read_write.RdInc"), stage6_field_expr!("stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_pow", "field.pow:3", "stage6.inc_claim_reduction.gamma"), stage6_field_expr!("stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_term", "field.mul", "stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_pow|stage6.input.stage5.registers_val_evaluation.RdInc"), stage6_field_expr!("stage6.inc_claim_reduction.claim_expr.partial0", "field.add", "stage6.input.stage2.ram_read_write.RamInc|stage6.inc_claim_reduction.claim.ram_inc_stage4.gamma_term"), stage6_field_expr!("stage6.inc_claim_reduction.claim_expr.partial1", "field.add", "stage6.inc_claim_reduction.claim_expr.partial0|stage6.inc_claim_reduction.claim.rd_inc_stage4.gamma_term"), stage6_field_expr!("stage6.inc_claim_reduction.claim_expr.partial2", "field.add", "stage6.inc_claim_reduction.claim_expr.partial1|stage6.inc_claim_reduction.claim.rd_inc_stage5.gamma_term"), +]; +pub const STAGE6_KERNELS: &[Stage6KernelPlan] = &[ + +]; + +pub const STAGE6_SUMCHECK_CLAIMS: &[Stage6SumcheckClaimPlan] = &[ + Stage6SumcheckClaimPlan { symbol: "stage6.bytecode_read_raf.input", stage: "stage6", domain: "jolt.stage6_bytecode_read_raf_domain", num_rounds: 26, degree: 4, claim: "stage6.bytecode_read_raf.weighted_prior_stage_values", kernel: None, relation: Some("jolt.stage6.bytecode_read_raf"), claim_value: "stage6.bytecode_read_raf.claim_expr.partial76", input_openings: "stage6.input.stage1.UnexpandedPC|stage6.input.stage1.Imm|stage6.input.stage1.OpFlagAddOperands|stage6.input.stage1.OpFlagSubtractOperands|stage6.input.stage1.OpFlagMultiplyOperands|stage6.input.stage1.OpFlagLoad|stage6.input.stage1.OpFlagStore|stage6.input.stage1.OpFlagJump|stage6.input.stage1.OpFlagWriteLookupOutputToRD|stage6.input.stage1.OpFlagVirtualInstruction|stage6.input.stage1.OpFlagAssert|stage6.input.stage1.OpFlagDoNotUpdateUnexpandedPC|stage6.input.stage1.OpFlagAdvice|stage6.input.stage1.OpFlagIsCompressed|stage6.input.stage1.OpFlagIsFirstInSequence|stage6.input.stage1.OpFlagIsLastInSequence|stage6.input.stage2.OpFlagJump|stage6.input.stage2.InstructionFlagBranch|stage6.input.stage2.OpFlagWriteLookupOutputToRD|stage6.input.stage2.OpFlagVirtualInstruction|stage6.input.stage3.instruction_input.Imm|stage6.input.stage3.spartan_shift.UnexpandedPC|stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsRs1Value|stage6.input.stage3.instruction_input.InstructionFlagLeftOperandIsPC|stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsRs2Value|stage6.input.stage3.instruction_input.InstructionFlagRightOperandIsImm|stage6.input.stage3.spartan_shift.InstructionFlagIsNoop|stage6.input.stage3.spartan_shift.OpFlagVirtualInstruction|stage6.input.stage3.spartan_shift.OpFlagIsFirstInSequence|stage6.input.stage4.RdWa|stage6.input.stage4.Rs1Ra|stage6.input.stage4.Rs2Ra|stage6.input.stage5.registers_val_evaluation.RdWa|stage6.input.stage5.InstructionRafFlag|stage6.input.stage5.LookupTableFlag_0|stage6.input.stage5.LookupTableFlag_1|stage6.input.stage5.LookupTableFlag_2|stage6.input.stage5.LookupTableFlag_3|stage6.input.stage5.LookupTableFlag_4|stage6.input.stage5.LookupTableFlag_5|stage6.input.stage5.LookupTableFlag_6|stage6.input.stage5.LookupTableFlag_7|stage6.input.stage5.LookupTableFlag_8|stage6.input.stage5.LookupTableFlag_9|stage6.input.stage5.LookupTableFlag_10|stage6.input.stage5.LookupTableFlag_11|stage6.input.stage5.LookupTableFlag_12|stage6.input.stage5.LookupTableFlag_13|stage6.input.stage5.LookupTableFlag_14|stage6.input.stage5.LookupTableFlag_15|stage6.input.stage5.LookupTableFlag_16|stage6.input.stage5.LookupTableFlag_17|stage6.input.stage5.LookupTableFlag_18|stage6.input.stage5.LookupTableFlag_19|stage6.input.stage5.LookupTableFlag_20|stage6.input.stage5.LookupTableFlag_21|stage6.input.stage5.LookupTableFlag_22|stage6.input.stage5.LookupTableFlag_23|stage6.input.stage5.LookupTableFlag_24|stage6.input.stage5.LookupTableFlag_25|stage6.input.stage5.LookupTableFlag_26|stage6.input.stage5.LookupTableFlag_27|stage6.input.stage5.LookupTableFlag_28|stage6.input.stage5.LookupTableFlag_29|stage6.input.stage5.LookupTableFlag_30|stage6.input.stage5.LookupTableFlag_31|stage6.input.stage5.LookupTableFlag_32|stage6.input.stage5.LookupTableFlag_33|stage6.input.stage5.LookupTableFlag_34|stage6.input.stage5.LookupTableFlag_35|stage6.input.stage5.LookupTableFlag_36|stage6.input.stage5.LookupTableFlag_37|stage6.input.stage5.LookupTableFlag_38|stage6.input.stage5.LookupTableFlag_39|stage6.input.stage5.LookupTableFlag_40|stage6.input.stage1.PC|stage6.input.stage3.spartan_shift.PC" }, + Stage6SumcheckClaimPlan { symbol: "stage6.booleanity.input", stage: "stage6", domain: "jolt.stage6_booleanity_domain", num_rounds: 20, degree: 3, claim: "stage6.booleanity.zero", kernel: None, relation: Some("jolt.stage6.booleanity"), claim_value: "stage6.zero", input_openings: "" }, + Stage6SumcheckClaimPlan { symbol: "stage6.hamming_booleanity.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 3, claim: "stage6.hamming_booleanity.zero", kernel: None, relation: Some("jolt.stage6.hamming_booleanity"), claim_value: "stage6.zero", input_openings: "stage6.input.stage1.LookupOutput" }, + Stage6SumcheckClaimPlan { symbol: "stage6.ram_ra_virtual.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 5, claim: "stage6.ram_ra_virtual.weighted_ram_ra", kernel: None, relation: Some("jolt.stage6.ram_ra_virtual"), claim_value: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", input_openings: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6SumcheckClaimPlan { symbol: "stage6.instruction_ra_virtual.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 5, claim: "stage6.instruction_ra_virtual.weighted_instruction_ra", kernel: None, relation: Some("jolt.stage6.instruction_ra_virtual"), claim_value: "stage6.instruction_ra_virtual.claim_expr.partial6", input_openings: "stage6.input.stage5.instruction_read_raf.InstructionRa_0|stage6.input.stage5.instruction_read_raf.InstructionRa_1|stage6.input.stage5.instruction_read_raf.InstructionRa_2|stage6.input.stage5.instruction_read_raf.InstructionRa_3|stage6.input.stage5.instruction_read_raf.InstructionRa_4|stage6.input.stage5.instruction_read_raf.InstructionRa_5|stage6.input.stage5.instruction_read_raf.InstructionRa_6|stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6SumcheckClaimPlan { symbol: "stage6.inc_claim_reduction.input", stage: "stage6", domain: "jolt.trace_domain", num_rounds: 16, degree: 2, claim: "stage6.inc_claim_reduction.weighted_increments", kernel: None, relation: Some("jolt.stage6.inc_claim_reduction"), claim_value: "stage6.inc_claim_reduction.claim_expr.partial2", input_openings: "stage6.input.stage2.ram_read_write.RamInc|stage6.input.stage4.ram_val_check.RamInc|stage6.input.stage4.registers_read_write.RdInc|stage6.input.stage5.registers_val_evaluation.RdInc" }, +]; +pub const STAGE6_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 10, + 16, +]; + +pub const STAGE6_SUMCHECK_BATCHES: &[Stage6SumcheckBatchPlan] = &[ + Stage6SumcheckBatchPlan { symbol: "stage6.batch", stage: "stage6", proof_slot: "stage6.sumcheck", policy: "jolt_core_stage6_aligned", count: 6, ordered_claims: "stage6.bytecode_read_raf.input|stage6.booleanity.input|stage6.hamming_booleanity.input|stage6.ram_ra_virtual.input|stage6.instruction_ra_virtual.input|stage6.inc_claim_reduction.input", claim_operands: "stage6.bytecode_read_raf.input|stage6.booleanity.input|stage6.hamming_booleanity.input|stage6.ram_ra_virtual.input|stage6.instruction_ra_virtual.input|stage6.inc_claim_reduction.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE6_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE6_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 10, + 16, +]; + +pub const STAGE6_SUMCHECK_DRIVERS: &[Stage6SumcheckDriverPlan] = &[ + Stage6SumcheckDriverPlan { symbol: "stage6.sumcheck", stage: "stage6", proof_slot: "stage6.sumcheck", kernel: None, relation: Some("jolt.stage6.batched"), batch: "stage6.batch", policy: "jolt_core_stage6_aligned", round_schedule: STAGE6_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 26, degree: 5 }, +]; +pub const STAGE6_SUMCHECK_INSTANCE_RESULTS: &[Stage6SumcheckInstanceResultPlan] = &[ + Stage6SumcheckInstanceResultPlan { symbol: "stage6.bytecode_read_raf.instance", source: "stage6.sumcheck", claim: "stage6.bytecode_read_raf.input", relation: "jolt.stage6.bytecode_read_raf", index: 0, point_arity: 26, num_rounds: 26, round_offset: 0, point_order: "bytecode_read_raf", degree: 4 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.booleanity.instance", source: "stage6.sumcheck", claim: "stage6.booleanity.input", relation: "jolt.stage6.booleanity", index: 1, point_arity: 20, num_rounds: 20, round_offset: 6, point_order: "stage6_booleanity", degree: 3 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.hamming_booleanity.instance", source: "stage6.sumcheck", claim: "stage6.hamming_booleanity.input", relation: "jolt.stage6.hamming_booleanity", index: 2, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 3 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.ram_ra_virtual.instance", source: "stage6.sumcheck", claim: "stage6.ram_ra_virtual.input", relation: "jolt.stage6.ram_ra_virtual", index: 3, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 5 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.instruction_ra_virtual.instance", source: "stage6.sumcheck", claim: "stage6.instruction_ra_virtual.input", relation: "jolt.stage6.instruction_ra_virtual", index: 4, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 5 }, + Stage6SumcheckInstanceResultPlan { symbol: "stage6.inc_claim_reduction.instance", source: "stage6.sumcheck", claim: "stage6.inc_claim_reduction.input", relation: "jolt.stage6.inc_claim_reduction", index: 5, point_arity: 16, num_rounds: 16, round_offset: 10, point_order: "reverse", degree: 2 }, +]; + +macro_rules! stage6_sumcheck_eval { + ($symbol:literal, $source:literal, $name:literal, $index:literal, $oracle:literal) => { + Stage6SumcheckEvalPlan { symbol: $symbol, source: $source, name: $name, index: $index, oracle: $oracle } + }; +} + +#[rustfmt::skip] +pub const STAGE6_SUMCHECK_EVALS: &[Stage6SumcheckEvalPlan] = &[ + stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_0", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_0", 0, "BytecodeRa_0"), stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_1", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_1", 1, "BytecodeRa_1"), stage6_sumcheck_eval!("stage6.bytecode_read_raf.eval.BytecodeRa_2", "stage6.sumcheck", "stage6.bytecode_read_raf.eval.BytecodeRa_2", 2, "BytecodeRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_0", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_0", 0, "InstructionRa_0"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_1", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_1", 1, "InstructionRa_1"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_2", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_2", 2, "InstructionRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_3", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_3", 3, "InstructionRa_3"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_4", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_4", 4, "InstructionRa_4"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_5", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_5", 5, "InstructionRa_5"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_6", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_6", 6, "InstructionRa_6"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_7", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_7", 7, "InstructionRa_7"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_8", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_8", 8, "InstructionRa_8"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_9", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_9", 9, "InstructionRa_9"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_10", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_10", 10, "InstructionRa_10"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_11", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_11", 11, "InstructionRa_11"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_12", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_12", 12, "InstructionRa_12"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_13", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_13", 13, "InstructionRa_13"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_14", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_14", 14, "InstructionRa_14"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_15", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_15", 15, "InstructionRa_15"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_16", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_16", 16, "InstructionRa_16"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_17", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_17", 17, "InstructionRa_17"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_18", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_18", 18, "InstructionRa_18"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_19", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_19", 19, "InstructionRa_19"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_20", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_20", 20, "InstructionRa_20"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_21", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_21", 21, "InstructionRa_21"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_22", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_22", 22, "InstructionRa_22"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_23", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_23", 23, "InstructionRa_23"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_24", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_24", 24, "InstructionRa_24"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_25", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_25", 25, "InstructionRa_25"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_26", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_26", 26, "InstructionRa_26"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_27", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_27", 27, "InstructionRa_27"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_28", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_28", 28, "InstructionRa_28"), + stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_29", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_29", 29, "InstructionRa_29"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_30", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_30", 30, "InstructionRa_30"), stage6_sumcheck_eval!("stage6.booleanity.eval.InstructionRa_31", "stage6.sumcheck", "stage6.booleanity.eval.InstructionRa_31", 31, "InstructionRa_31"), stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_0", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_0", 32, "BytecodeRa_0"), + stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_1", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_1", 33, "BytecodeRa_1"), stage6_sumcheck_eval!("stage6.booleanity.eval.BytecodeRa_2", "stage6.sumcheck", "stage6.booleanity.eval.BytecodeRa_2", 34, "BytecodeRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_0", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_0", 35, "RamRa_0"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_1", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_1", 36, "RamRa_1"), + stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_2", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_2", 37, "RamRa_2"), stage6_sumcheck_eval!("stage6.booleanity.eval.RamRa_3", "stage6.sumcheck", "stage6.booleanity.eval.RamRa_3", 38, "RamRa_3"), stage6_sumcheck_eval!("stage6.hamming_booleanity.eval.HammingWeight", "stage6.sumcheck", "stage6.hamming_booleanity.eval.HammingWeight", 0, "HammingWeight"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_0", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_0", 0, "RamRa_0"), + stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_1", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_1", 1, "RamRa_1"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_2", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_2", 2, "RamRa_2"), stage6_sumcheck_eval!("stage6.ram_ra_virtual.eval.RamRa_3", "stage6.sumcheck", "stage6.ram_ra_virtual.eval.RamRa_3", 3, "RamRa_3"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_0", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_0", 0, "InstructionRa_0"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_1", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_1", 1, "InstructionRa_1"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_2", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_2", 2, "InstructionRa_2"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_3", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_3", 3, "InstructionRa_3"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_4", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_4", 4, "InstructionRa_4"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_5", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_5", 5, "InstructionRa_5"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_6", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_6", 6, "InstructionRa_6"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_7", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_7", 7, "InstructionRa_7"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_8", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_8", 8, "InstructionRa_8"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_9", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_9", 9, "InstructionRa_9"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_10", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_10", 10, "InstructionRa_10"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_11", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_11", 11, "InstructionRa_11"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_12", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_12", 12, "InstructionRa_12"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_13", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_13", 13, "InstructionRa_13"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_14", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_14", 14, "InstructionRa_14"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_15", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_15", 15, "InstructionRa_15"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_16", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_16", 16, "InstructionRa_16"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_17", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_17", 17, "InstructionRa_17"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_18", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_18", 18, "InstructionRa_18"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_19", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_19", 19, "InstructionRa_19"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_20", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_20", 20, "InstructionRa_20"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_21", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_21", 21, "InstructionRa_21"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_22", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_22", 22, "InstructionRa_22"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_23", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_23", 23, "InstructionRa_23"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_24", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_24", 24, "InstructionRa_24"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_25", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_25", 25, "InstructionRa_25"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_26", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_26", 26, "InstructionRa_26"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_27", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_27", 27, "InstructionRa_27"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_28", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_28", 28, "InstructionRa_28"), + stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_29", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_29", 29, "InstructionRa_29"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_30", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_30", 30, "InstructionRa_30"), stage6_sumcheck_eval!("stage6.instruction_ra_virtual.eval.InstructionRa_31", "stage6.sumcheck", "stage6.instruction_ra_virtual.eval.InstructionRa_31", 31, "InstructionRa_31"), stage6_sumcheck_eval!("stage6.inc_claim_reduction.eval.RamInc", "stage6.sumcheck", "stage6.inc_claim_reduction.eval.RamInc", 0, "RamInc"), + stage6_sumcheck_eval!("stage6.inc_claim_reduction.eval.RdInc", "stage6.sumcheck", "stage6.inc_claim_reduction.eval.RdInc", 1, "RdInc"), +]; + +pub const STAGE6_POINT_ZEROS: &[Stage6PointZeroPlan] = &[ + Stage6PointZeroPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address.zero_pad", field: "bn254_fr", arity: 2 }, +]; + +pub const STAGE6_POINT_SLICES: &[Stage6PointSlicePlan] = &[ + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.Cycle", source: "stage6.bytecode_read_raf.instance", offset: 10, length: 16, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address.source", source: "stage6.bytecode_read_raf.instance", offset: 0, length: 2, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_1.address", source: "stage6.bytecode_read_raf.instance", offset: 2, length: 4, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_2.address", source: "stage6.bytecode_read_raf.instance", offset: 6, length: 4, input: "stage6.bytecode_read_raf.instance" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_0.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 0, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_1.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 4, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_2.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 8, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.ram_ra_virtual.point.RamRa_3.address", source: "stage6.input.stage5.ram_ra_claim_reduction.RamRa", offset: 12, length: 4, input: "stage6.input.stage5.ram_ra_claim_reduction.RamRa" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_0.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_1.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_2.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_3.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_0", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_0" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_4.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_5.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_6.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_7.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_1", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_1" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_8.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_9.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_10.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_11.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_2", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_2" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_12.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_13.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_14.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_15.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_3", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_3" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_16.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_17.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_18.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_19.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_4", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_4" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_20.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_21.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_22.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_23.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_5", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_5" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_24.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_25.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_26.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_27.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_6", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_6" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_28.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 0, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_29.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 4, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_30.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 8, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, + Stage6PointSlicePlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_31.address", source: "stage6.input.stage5.instruction_read_raf.InstructionRa_7", offset: 12, length: 4, input: "stage6.input.stage5.instruction_read_raf.InstructionRa_7" }, +]; + +pub const STAGE6_POINT_CONCATS: &[Stage6PointConcatPlan] = &[ + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0.address", layout: "left_zero_padded_address_chunk", arity: 4, inputs: "stage6.bytecode_read_raf.point.BytecodeRa_0.address.zero_pad|stage6.bytecode_read_raf.point.BytecodeRa_0.address.source" }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.bytecode_read_raf.point.BytecodeRa_0.address|stage6.bytecode_read_raf.point.Cycle" }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.bytecode_read_raf.point.BytecodeRa_1.address|stage6.bytecode_read_raf.point.Cycle" }, + Stage6PointConcatPlan { symbol: "stage6.bytecode_read_raf.point.BytecodeRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.bytecode_read_raf.point.BytecodeRa_2.address|stage6.bytecode_read_raf.point.Cycle" }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.ram_ra_virtual.point.RamRa_0.address|stage6.ram_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.ram_ra_virtual.point.RamRa_1.address|stage6.ram_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.ram_ra_virtual.point.RamRa_2.address|stage6.ram_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.ram_ra_virtual.point.RamRa_3", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.ram_ra_virtual.point.RamRa_3.address|stage6.ram_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_0", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_0.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_1", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_1.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_2", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_2.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_3", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_3.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_4", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_4.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_5", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_5.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_6", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_6.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_7", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_7.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_8", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_8.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_9", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_9.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_10", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_10.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_11", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_11.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_12", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_12.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_13", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_13.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_14", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_14.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_15", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_15.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_16", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_16.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_17", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_17.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_18", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_18.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_19", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_19.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_20", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_20.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_21", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_21.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_22", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_22.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_23", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_23.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_24", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_24.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_25", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_25.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_26", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_26.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_27", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_27.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_28", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_28.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_29", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_29.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_30", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_30.address|stage6.instruction_ra_virtual.instance" }, + Stage6PointConcatPlan { symbol: "stage6.instruction_ra_virtual.point.InstructionRa_31", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage6.instruction_ra_virtual.point.InstructionRa_31.address|stage6.instruction_ra_virtual.instance" }, +]; +pub const STAGE6_OPENING_CLAIMS: &[Stage6OpeningClaimPlan] = &[ + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_0", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_1", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.bytecode_read_raf.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.bytecode_read_raf.point.BytecodeRa_2", eval_source: "stage6.bytecode_read_raf.eval.BytecodeRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_4" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_5" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_6" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_7" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_8" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_9" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_10" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_11" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_12" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_13" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_14" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_15" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_16" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_17" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_18" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_19" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_20" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_21" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_22" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_23" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_24" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_25" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_26" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_27" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_28" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_29" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_30" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.InstructionRa_31" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.BytecodeRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.booleanity.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.booleanity.instance", eval_source: "stage6.booleanity.eval.RamRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.hamming_booleanity.opening.HammingWeight", oracle: "HammingWeight", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual", point_source: "stage6.hamming_booleanity.instance", eval_source: "stage6.hamming_booleanity.eval.HammingWeight" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_0", eval_source: "stage6.ram_ra_virtual.eval.RamRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_1", eval_source: "stage6.ram_ra_virtual.eval.RamRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_2", eval_source: "stage6.ram_ra_virtual.eval.RamRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.ram_ra_virtual.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.ram_ra_virtual.point.RamRa_3", eval_source: "stage6.ram_ra_virtual.eval.RamRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_0", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_0" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_1", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_1" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_2", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_2" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_3", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_3" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_4", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_4" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_5", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_5" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_6", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_6" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_7", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_7" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_8", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_8" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_9", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_9" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_10", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_10" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_11", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_11" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_12", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_12" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_13", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_13" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_14", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_14" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_15", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_15" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_16", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_16" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_17", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_17" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_18", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_18" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_19", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_19" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_20", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_20" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_21", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_21" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_22", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_22" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_23", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_23" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_24", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_24" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_25", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_25" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_26", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_26" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_27", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_27" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_28", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_28" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_29", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_29" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_30", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_30" }, + Stage6OpeningClaimPlan { symbol: "stage6.instruction_ra_virtual.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage6.instruction_ra_virtual.point.InstructionRa_31", eval_source: "stage6.instruction_ra_virtual.eval.InstructionRa_31" }, + Stage6OpeningClaimPlan { symbol: "stage6.inc_claim_reduction.opening.RamInc", oracle: "RamInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage6.inc_claim_reduction.instance", eval_source: "stage6.inc_claim_reduction.eval.RamInc" }, + Stage6OpeningClaimPlan { symbol: "stage6.inc_claim_reduction.opening.RdInc", oracle: "RdInc", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "committed", point_source: "stage6.inc_claim_reduction.instance", eval_source: "stage6.inc_claim_reduction.eval.RdInc" }, +]; + +pub const STAGE6_OPENING_EQUALITIES: &[Stage6OpeningClaimEqualityPlan] = &[ + +]; + +pub const STAGE6_OPENING_BATCHES: &[Stage6OpeningBatchPlan] = &[ + Stage6OpeningBatchPlan { symbol: "stage6.openings", stage: "stage6", proof_slot: "stage6.openings", policy: "jolt_stage6_output_order", count: 81, ordered_claims: "stage6.bytecode_read_raf.opening.BytecodeRa_0|stage6.bytecode_read_raf.opening.BytecodeRa_1|stage6.bytecode_read_raf.opening.BytecodeRa_2|stage6.booleanity.opening.InstructionRa_0|stage6.booleanity.opening.InstructionRa_1|stage6.booleanity.opening.InstructionRa_2|stage6.booleanity.opening.InstructionRa_3|stage6.booleanity.opening.InstructionRa_4|stage6.booleanity.opening.InstructionRa_5|stage6.booleanity.opening.InstructionRa_6|stage6.booleanity.opening.InstructionRa_7|stage6.booleanity.opening.InstructionRa_8|stage6.booleanity.opening.InstructionRa_9|stage6.booleanity.opening.InstructionRa_10|stage6.booleanity.opening.InstructionRa_11|stage6.booleanity.opening.InstructionRa_12|stage6.booleanity.opening.InstructionRa_13|stage6.booleanity.opening.InstructionRa_14|stage6.booleanity.opening.InstructionRa_15|stage6.booleanity.opening.InstructionRa_16|stage6.booleanity.opening.InstructionRa_17|stage6.booleanity.opening.InstructionRa_18|stage6.booleanity.opening.InstructionRa_19|stage6.booleanity.opening.InstructionRa_20|stage6.booleanity.opening.InstructionRa_21|stage6.booleanity.opening.InstructionRa_22|stage6.booleanity.opening.InstructionRa_23|stage6.booleanity.opening.InstructionRa_24|stage6.booleanity.opening.InstructionRa_25|stage6.booleanity.opening.InstructionRa_26|stage6.booleanity.opening.InstructionRa_27|stage6.booleanity.opening.InstructionRa_28|stage6.booleanity.opening.InstructionRa_29|stage6.booleanity.opening.InstructionRa_30|stage6.booleanity.opening.InstructionRa_31|stage6.booleanity.opening.BytecodeRa_0|stage6.booleanity.opening.BytecodeRa_1|stage6.booleanity.opening.BytecodeRa_2|stage6.booleanity.opening.RamRa_0|stage6.booleanity.opening.RamRa_1|stage6.booleanity.opening.RamRa_2|stage6.booleanity.opening.RamRa_3|stage6.hamming_booleanity.opening.HammingWeight|stage6.ram_ra_virtual.opening.RamRa_0|stage6.ram_ra_virtual.opening.RamRa_1|stage6.ram_ra_virtual.opening.RamRa_2|stage6.ram_ra_virtual.opening.RamRa_3|stage6.instruction_ra_virtual.opening.InstructionRa_0|stage6.instruction_ra_virtual.opening.InstructionRa_1|stage6.instruction_ra_virtual.opening.InstructionRa_2|stage6.instruction_ra_virtual.opening.InstructionRa_3|stage6.instruction_ra_virtual.opening.InstructionRa_4|stage6.instruction_ra_virtual.opening.InstructionRa_5|stage6.instruction_ra_virtual.opening.InstructionRa_6|stage6.instruction_ra_virtual.opening.InstructionRa_7|stage6.instruction_ra_virtual.opening.InstructionRa_8|stage6.instruction_ra_virtual.opening.InstructionRa_9|stage6.instruction_ra_virtual.opening.InstructionRa_10|stage6.instruction_ra_virtual.opening.InstructionRa_11|stage6.instruction_ra_virtual.opening.InstructionRa_12|stage6.instruction_ra_virtual.opening.InstructionRa_13|stage6.instruction_ra_virtual.opening.InstructionRa_14|stage6.instruction_ra_virtual.opening.InstructionRa_15|stage6.instruction_ra_virtual.opening.InstructionRa_16|stage6.instruction_ra_virtual.opening.InstructionRa_17|stage6.instruction_ra_virtual.opening.InstructionRa_18|stage6.instruction_ra_virtual.opening.InstructionRa_19|stage6.instruction_ra_virtual.opening.InstructionRa_20|stage6.instruction_ra_virtual.opening.InstructionRa_21|stage6.instruction_ra_virtual.opening.InstructionRa_22|stage6.instruction_ra_virtual.opening.InstructionRa_23|stage6.instruction_ra_virtual.opening.InstructionRa_24|stage6.instruction_ra_virtual.opening.InstructionRa_25|stage6.instruction_ra_virtual.opening.InstructionRa_26|stage6.instruction_ra_virtual.opening.InstructionRa_27|stage6.instruction_ra_virtual.opening.InstructionRa_28|stage6.instruction_ra_virtual.opening.InstructionRa_29|stage6.instruction_ra_virtual.opening.InstructionRa_30|stage6.instruction_ra_virtual.opening.InstructionRa_31|stage6.inc_claim_reduction.opening.RamInc|stage6.inc_claim_reduction.opening.RdInc", claim_operands: "stage6.bytecode_read_raf.opening.BytecodeRa_0|stage6.bytecode_read_raf.opening.BytecodeRa_1|stage6.bytecode_read_raf.opening.BytecodeRa_2|stage6.booleanity.opening.InstructionRa_0|stage6.booleanity.opening.InstructionRa_1|stage6.booleanity.opening.InstructionRa_2|stage6.booleanity.opening.InstructionRa_3|stage6.booleanity.opening.InstructionRa_4|stage6.booleanity.opening.InstructionRa_5|stage6.booleanity.opening.InstructionRa_6|stage6.booleanity.opening.InstructionRa_7|stage6.booleanity.opening.InstructionRa_8|stage6.booleanity.opening.InstructionRa_9|stage6.booleanity.opening.InstructionRa_10|stage6.booleanity.opening.InstructionRa_11|stage6.booleanity.opening.InstructionRa_12|stage6.booleanity.opening.InstructionRa_13|stage6.booleanity.opening.InstructionRa_14|stage6.booleanity.opening.InstructionRa_15|stage6.booleanity.opening.InstructionRa_16|stage6.booleanity.opening.InstructionRa_17|stage6.booleanity.opening.InstructionRa_18|stage6.booleanity.opening.InstructionRa_19|stage6.booleanity.opening.InstructionRa_20|stage6.booleanity.opening.InstructionRa_21|stage6.booleanity.opening.InstructionRa_22|stage6.booleanity.opening.InstructionRa_23|stage6.booleanity.opening.InstructionRa_24|stage6.booleanity.opening.InstructionRa_25|stage6.booleanity.opening.InstructionRa_26|stage6.booleanity.opening.InstructionRa_27|stage6.booleanity.opening.InstructionRa_28|stage6.booleanity.opening.InstructionRa_29|stage6.booleanity.opening.InstructionRa_30|stage6.booleanity.opening.InstructionRa_31|stage6.booleanity.opening.BytecodeRa_0|stage6.booleanity.opening.BytecodeRa_1|stage6.booleanity.opening.BytecodeRa_2|stage6.booleanity.opening.RamRa_0|stage6.booleanity.opening.RamRa_1|stage6.booleanity.opening.RamRa_2|stage6.booleanity.opening.RamRa_3|stage6.hamming_booleanity.opening.HammingWeight|stage6.ram_ra_virtual.opening.RamRa_0|stage6.ram_ra_virtual.opening.RamRa_1|stage6.ram_ra_virtual.opening.RamRa_2|stage6.ram_ra_virtual.opening.RamRa_3|stage6.instruction_ra_virtual.opening.InstructionRa_0|stage6.instruction_ra_virtual.opening.InstructionRa_1|stage6.instruction_ra_virtual.opening.InstructionRa_2|stage6.instruction_ra_virtual.opening.InstructionRa_3|stage6.instruction_ra_virtual.opening.InstructionRa_4|stage6.instruction_ra_virtual.opening.InstructionRa_5|stage6.instruction_ra_virtual.opening.InstructionRa_6|stage6.instruction_ra_virtual.opening.InstructionRa_7|stage6.instruction_ra_virtual.opening.InstructionRa_8|stage6.instruction_ra_virtual.opening.InstructionRa_9|stage6.instruction_ra_virtual.opening.InstructionRa_10|stage6.instruction_ra_virtual.opening.InstructionRa_11|stage6.instruction_ra_virtual.opening.InstructionRa_12|stage6.instruction_ra_virtual.opening.InstructionRa_13|stage6.instruction_ra_virtual.opening.InstructionRa_14|stage6.instruction_ra_virtual.opening.InstructionRa_15|stage6.instruction_ra_virtual.opening.InstructionRa_16|stage6.instruction_ra_virtual.opening.InstructionRa_17|stage6.instruction_ra_virtual.opening.InstructionRa_18|stage6.instruction_ra_virtual.opening.InstructionRa_19|stage6.instruction_ra_virtual.opening.InstructionRa_20|stage6.instruction_ra_virtual.opening.InstructionRa_21|stage6.instruction_ra_virtual.opening.InstructionRa_22|stage6.instruction_ra_virtual.opening.InstructionRa_23|stage6.instruction_ra_virtual.opening.InstructionRa_24|stage6.instruction_ra_virtual.opening.InstructionRa_25|stage6.instruction_ra_virtual.opening.InstructionRa_26|stage6.instruction_ra_virtual.opening.InstructionRa_27|stage6.instruction_ra_virtual.opening.InstructionRa_28|stage6.instruction_ra_virtual.opening.InstructionRa_29|stage6.instruction_ra_virtual.opening.InstructionRa_30|stage6.instruction_ra_virtual.opening.InstructionRa_31|stage6.inc_claim_reduction.opening.RamInc|stage6.inc_claim_reduction.opening.RdInc" }, +]; +pub const STAGE6_PROGRAM: Stage6VerifierProgramPlan = Stage6CpuProgramPlan { + role: "verifier", + params: STAGE6_PARAMS, + steps: STAGE6_PROGRAM_STEPS, + transcript_squeezes: STAGE6_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE6_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE6_OPENING_INPUTS, + field_constants: STAGE6_FIELD_CONSTANTS, + field_exprs: STAGE6_FIELD_EXPRS, + kernels: STAGE6_KERNELS, + claims: STAGE6_SUMCHECK_CLAIMS, + batches: STAGE6_SUMCHECK_BATCHES, + drivers: STAGE6_SUMCHECK_DRIVERS, + instance_results: STAGE6_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE6_SUMCHECK_EVALS, + point_zeros: STAGE6_POINT_ZEROS, + point_slices: STAGE6_POINT_SLICES, + point_concats: STAGE6_POINT_CONCATS, + opening_claims: STAGE6_OPENING_CLAIMS, + opening_equalities: STAGE6_OPENING_EQUALITIES, + opening_batches: STAGE6_OPENING_BATCHES, +}; + +pub fn verify_stage6( + proof: &Stage6Proof, + opening_inputs: &[Stage6OpeningInputValue], + verifier_data: Option<&Stage6VerifierData>, + transcript: &mut T, +) -> Result, VerifyStage6Error> +where + T: Transcript, +{ + verify_stage6_with_program(&STAGE6_PROGRAM, proof, opening_inputs, verifier_data, transcript) +} + +pub fn verify_stage6_with_program( + program: &'static Stage6VerifierProgramPlan, + proof: &Stage6Proof, + opening_inputs: &[Stage6OpeningInputValue], + verifier_data: Option<&Stage6VerifierData>, + transcript: &mut T, +) -> Result, VerifyStage6Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage6Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = + super::common::ValueStore::with_opening_inputs(opening_inputs, program.opening_inputs)?; + store.seed_constants(program.field_constants); + store.seed_point_zeros(program.point_zeros); + let mut artifacts = Stage6ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage6Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage6_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "transcript_absorb_bytes" => { + let absorb = find_plan(program.transcript_absorb_bytes, step.symbol).ok_or( + VerifyStage6Error::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage6_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_plan(program.drivers, step.symbol).ok_or(VerifyStage6Error::MissingProof { + driver: step.symbol, + })?; + verify_stage6_driver( + program, + driver, + proof, + verifier_data, + &mut store, + transcript, + &mut artifacts, + )?; + } + _ => { + return Err(VerifyStage6Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage6 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage6_verifier_program() -> &'static Stage6VerifierProgramPlan { + &STAGE6_PROGRAM +} + +fn verify_stage6_squeeze( + program: &'static Stage6VerifierProgramPlan, + squeeze: &'static Stage6TranscriptSqueezePlan, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage6ExecutionArtifacts, +) -> Result<(), VerifyStage6Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(squeeze, &values, |input, expected, actual| { + VerifyStage6Error::InvalidInputLength { + input, + expected, + actual, + } + })?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage6Error::from)?; + artifacts.challenge_vectors.push(Stage6ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn absorb_stage6_bytes(absorb: &'static Stage6TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn verify_stage6_driver( + program: &'static Stage6VerifierProgramPlan, + driver: &'static Stage6SumcheckDriverPlan, + proof: &Stage6Proof, + verifier_data: Option<&Stage6VerifierData>, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage6ExecutionArtifacts, +) -> Result<(), VerifyStage6Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage6Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage6.batched" => { + verify_batched_stage6(program, driver, proof, verifier_data, store, transcript)? + } + _ => return Err(VerifyStage6Error::UnsupportedRelation { relation }), + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_batched_stage6( + program: &'static Stage6VerifierProgramPlan, + driver: &'static Stage6SumcheckDriverPlan, + proof: &Stage6SumcheckOutput, + verifier_data: Option<&Stage6VerifierData>, + store: &mut super::common::ValueStore, + transcript: &mut T, +) -> Result, VerifyStage6Error> +where + T: Transcript, +{ + super::common::verify_batched_sumcheck( + driver, + proof, + program.claims, + program.batches, + program.field_exprs, + program.opening_inputs, + program.opening_claims, + program.opening_batches, + store, + transcript, + |store, evals, point, batching_coeffs| { + expected_batched_output_claim( + program, + driver, + verifier_data, + store, + evals, + point, + batching_coeffs, + ) + }, + |store, verified| observe_stage6_sumcheck_output(program, store, verified), + |driver, error| VerifyStage6Error::Sumcheck { driver, error }, + ) +} + +fn observe_stage6_sumcheck_output( + program: &'static Stage6VerifierProgramPlan, + store: &mut super::common::ValueStore, + output: &Stage6SumcheckOutput, +) -> Result<(), VerifyStage6Error> { + store.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + "bytecode_read_raf" => point = normalize_bytecode_read_raf_point(&point, stage6_trace_rounds(program)?, "stage6.bytecode_read_raf.point")?, + "stage6_booleanity" => {} + "instruction_read_raf" => point = normalize_instruction_read_raf_point(&point, "stage6.instruction_read_raf.point")?, + _ => { + return Err(VerifyStage6Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage6Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage6Error::MissingValue { symbol }, + )?; + store.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage6Error::InvalidInputLength { + input, + expected, + actual, + }, + )?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage6Error::from)?; + store.verify_opening_equalities( + program.opening_equalities, + |driver, reason| VerifyStage6Error::InvalidProof { driver, reason }, + |symbol| VerifyStage6Error::MissingValue { symbol }, + ) +} + +fn expected_batched_output_claim( + program: &'static Stage6VerifierProgramPlan, + driver: &'static Stage6SumcheckDriverPlan, + verifier_data: Option<&Stage6VerifierData>, + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage6Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage6Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let relation = claim.relation.unwrap_or(""); + let value = match relation { + "jolt.stage6.bytecode_read_raf" => { + let data = verifier_data + .and_then(|data| data.bytecode_read_raf.as_ref()) + .ok_or(VerifyStage6Error::MissingValue { + symbol: "stage6.bytecode_read_raf.data", + })?; + expected_bytecode_read_raf(program, data, store, evals, local_point)? + } + "jolt.stage6.booleanity" => { + expected_booleanity(program, store, evals, local_point)? + } + "jolt.stage6.hamming_booleanity" => { + expected_hamming_booleanity(store, evals, local_point)? + } + "jolt.stage6.ram_ra_virtual" => { + expected_ram_ra_virtual(store, evals, local_point)? + } + "jolt.stage6.instruction_ra_virtual" => { + expected_instruction_ra_virtual(program, store, evals, local_point)? + } + "jolt.stage6.inc_claim_reduction" => { + expected_inc_claim_reduction(store, evals, local_point)? + } + _ => return Err(VerifyStage6Error::UnsupportedRelation { relation }), + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_bytecode_read_raf( + program: &'static Stage6VerifierProgramPlan, + data: &Stage6BytecodeReadRafData, + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + let log_t = stage6_trace_rounds(program)?; + Ok(expected_stage67_bytecode_read_raf( + &data.entries, + data.entry_bytecode_index, + data.num_lookup_tables, + store, + evals, + local_point, + log_t, + &STAGE6_BYTECODE_SYMBOLS, + )?) +} + +fn expected_booleanity( + program: &'static Stage6VerifierProgramPlan, + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + let log_t = stage6_trace_rounds(program)?; + Ok(expected_stage67_booleanity(store, evals, local_point, log_t, &STAGE6_RELATION_SYMBOLS)?) +} + +fn expected_hamming_booleanity( + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + Ok(expected_stage67_hamming_booleanity(store, evals, local_point, &STAGE6_RELATION_SYMBOLS)?) +} + +fn expected_ram_ra_virtual( + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + Ok(expected_stage67_ram_ra_virtual(store, evals, local_point, &STAGE6_RELATION_SYMBOLS)?) +} + +fn expected_instruction_ra_virtual( + program: &'static Stage6VerifierProgramPlan, + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + Ok(expected_stage67_instruction_ra_virtual(program.opening_inputs, store, evals, local_point, &STAGE6_RELATION_SYMBOLS)?) +} + +fn expected_inc_claim_reduction( + store: &super::common::ValueStore, + evals: &[Stage6NamedEval], + local_point: &[Fr], +) -> Result { + Ok(expected_stage67_inc_claim_reduction(store, evals, local_point, &STAGE6_RELATION_SYMBOLS)?) +} + +fn stage6_trace_rounds( + program: &'static Stage6VerifierProgramPlan, +) -> Result { + Ok(stage67_trace_rounds(program.instance_results, &STAGE6_RELATION_SYMBOLS)?) +} diff --git a/crates/jolt-verifier/src/stages/stage7.rs b/crates/jolt-verifier/src/stages/stage7.rs new file mode 100644 index 0000000000..0f643fe509 --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage7.rs @@ -0,0 +1,682 @@ +#![allow(dead_code)] + +use super::common::{batch_claims, eval_by_name, find_batch, find_plan, normalize_bytecode_read_raf_point, normalize_instruction_read_raf_point, reverse_slice}; +use jolt_field::{Field, Fr, RingCore}; +use jolt_poly::EqPolynomial; +use jolt_sumcheck::SumcheckError; +use jolt_transcript::{Blake2bTranscript, LabelWithCount, Transcript}; + +pub type Stage7NamedEval = super::common::StageNamedEval; +pub type Stage7SumcheckOutput = super::common::StageSumcheckOutput; +pub type Stage7ChallengeVector = super::common::StageChallengeVector; +pub type Stage7ExecutionArtifacts = super::common::StageExecutionArtifacts; +pub type Stage7Proof = super::common::StageProof; +pub type Stage7OpeningInputValue = super::common::StageOpeningInputValue; + +pub use super::common::{ + FieldConstantPlan as Stage7FieldConstantPlan, FieldExprPlan as Stage7FieldExprPlan, + KernelPlan as Stage7KernelPlan, OpeningBatchPlan as Stage7OpeningBatchPlan, + OpeningClaimEqualityPlan as Stage7OpeningClaimEqualityPlan, + OpeningClaimPlan as Stage7OpeningClaimPlan, OpeningInputPlan as Stage7OpeningInputPlan, + PointConcatPlan as Stage7PointConcatPlan, PointSlicePlan as Stage7PointSlicePlan, + PointZeroPlan as Stage7PointZeroPlan, ProgramStepPlan as Stage7ProgramStepPlan, + StageParams as Stage7Params, StageProgramPlan as Stage7CpuProgramPlan, + SumcheckBatchPlan as Stage7SumcheckBatchPlan, + SumcheckClaimPlan as Stage7SumcheckClaimPlan, SumcheckDriverPlan as Stage7SumcheckDriverPlan, + SumcheckEvalPlan as Stage7SumcheckEvalPlan, + SumcheckInstanceResultPlan as Stage7SumcheckInstanceResultPlan, + TranscriptAbsorbBytesPlan as Stage7TranscriptAbsorbBytesPlan, + TranscriptSqueezePlan as Stage7TranscriptSqueezePlan, +}; + +pub type DefaultStage7Transcript = Blake2bTranscript; +pub type Stage7VerifierProgramPlan = Stage7CpuProgramPlan; + +#[derive(Debug)] +pub enum VerifyStage7Error { + UnexpectedProofCount { expected: usize, got: usize }, + MissingProof { driver: &'static str }, + MissingBatch { driver: &'static str, batch: &'static str }, + MissingClaim { batch: &'static str, claim: &'static str }, + MissingValue { symbol: &'static str }, + InvalidInputLength { input: &'static str, expected: usize, actual: usize }, + InvalidProof { driver: &'static str, reason: &'static str }, + UnsupportedFieldExpr { symbol: &'static str, formula: &'static str }, + UnsupportedRelation { relation: &'static str }, + Sumcheck { driver: &'static str, error: SumcheckError }, +} + +super::common::impl_runtime_plan_error_conversion!(VerifyStage7Error); + +pub const STAGE7_PARAMS: Stage7Params = Stage7Params { + field: "bn254_fr", + pcs: "dory", + transcript: "blake2b_transcript", +}; +pub const STAGE7_PROGRAM_STEPS: &[Stage7ProgramStepPlan] = &[ + Stage7ProgramStepPlan { kind: "transcript_squeeze", symbol: "stage7.hamming_weight_claim_reduction.gamma" }, + Stage7ProgramStepPlan { kind: "sumcheck_driver", symbol: "stage7.sumcheck" }, +]; + +pub const STAGE7_TRANSCRIPT_SQUEEZES: &[Stage7TranscriptSqueezePlan] = &[ + Stage7TranscriptSqueezePlan { symbol: "stage7.hamming_weight_claim_reduction.gamma", label: "hamming_weight_claim_reduction_gamma", kind: "challenge_scalar", count: 1 }, +]; + +pub const STAGE7_TRANSCRIPT_ABSORB_BYTES: &[Stage7TranscriptAbsorbBytesPlan] = &[ + +]; + +pub const STAGE7_OPENING_INPUTS: &[Stage7OpeningInputPlan] = &[ + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.hamming_booleanity.HammingWeight", source_stage: "stage6", source_claim: "stage6.hamming_booleanity.opening.HammingWeight", oracle: "HammingWeight", domain: "jolt.trace_domain", point_arity: 16, claim_kind: "virtual" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_0", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_1", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_2", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_3", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_3", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_4", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_4", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_5", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_5", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_6", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_6", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_7", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_7", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_8", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_8", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_9", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_9", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_10", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_10", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_11", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_11", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_12", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_12", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_13", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_13", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_14", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_14", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_15", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_15", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_16", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_16", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_17", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_17", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_18", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_18", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_19", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_19", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_20", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_20", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_21", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_21", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_22", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_22", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_23", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_23", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_24", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_24", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_25", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_25", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_26", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_26", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_27", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_27", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_28", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_28", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_29", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_29", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_30", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_30", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.InstructionRa_31", source_stage: "stage6", source_claim: "stage6.booleanity.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.instruction_ra_virtual.InstructionRa_31", source_stage: "stage6", source_claim: "stage6.instruction_ra_virtual.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_0", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_1", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.BytecodeRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.bytecode_read_raf.BytecodeRa_2", source_stage: "stage6", source_claim: "stage6.bytecode_read_raf.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_0", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_0", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_1", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_1", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_2", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_2", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.booleanity.RamRa_3", source_stage: "stage6", source_claim: "stage6.booleanity.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage7OpeningInputPlan { symbol: "stage7.input.stage6.ram_ra_virtual.RamRa_3", source_stage: "stage6", source_claim: "stage6.ram_ra_virtual.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, +]; + +pub const STAGE7_FIELD_CONSTANTS: &[Stage7FieldConstantPlan] = &[ + Stage7FieldConstantPlan { symbol: "stage7.field.one", field: "bn254_fr", value: 1 }, +]; + +macro_rules! stage7_field_expr { + ($symbol:literal, $formula:literal, $operands:literal) => { + Stage7FieldExprPlan { symbol: $symbol, kind: "op", formula: $formula, operands: $operands } + }; +} + +#[rustfmt::skip] +pub const STAGE7_FIELD_EXPRS: &[Stage7FieldExprPlan] = &[ + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_pow", "field.pow:1", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_pow", "field.pow:2", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_pow", "field.pow:3", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_pow", "field.pow:4", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_1"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_pow", "field.pow:5", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_1"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_pow", "field.pow:6", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_pow", "field.pow:7", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_2"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_pow", "field.pow:8", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_2"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_pow", "field.pow:9", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_pow", "field.pow:10", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_3"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_pow", "field.pow:11", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_3"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_pow", "field.pow:12", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_pow", "field.pow:13", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_4"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_pow", "field.pow:14", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_4"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_pow", "field.pow:15", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_pow", "field.pow:16", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_5"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_pow", "field.pow:17", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_5"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_pow", "field.pow:18", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_pow", "field.pow:19", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_6"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_pow", "field.pow:20", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_6"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_pow", "field.pow:21", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_pow", "field.pow:22", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_7"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_pow", "field.pow:23", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_7"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_pow", "field.pow:24", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_pow", "field.pow:25", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_8"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_pow", "field.pow:26", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_8"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_pow", "field.pow:27", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_pow", "field.pow:28", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_9"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_pow", "field.pow:29", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_9"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_pow", "field.pow:30", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_pow", "field.pow:31", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_10"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_pow", "field.pow:32", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_10"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_pow", "field.pow:33", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_pow", "field.pow:34", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_11"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_pow", "field.pow:35", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_11"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_pow", "field.pow:36", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_pow", "field.pow:37", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_12"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_pow", "field.pow:38", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_12"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_pow", "field.pow:39", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_pow", "field.pow:40", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_13"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_pow", "field.pow:41", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_13"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_pow", "field.pow:42", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_pow", "field.pow:43", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_14"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_pow", "field.pow:44", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_14"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_pow", "field.pow:45", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_pow", "field.pow:46", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_15"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_pow", "field.pow:47", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_15"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_pow", "field.pow:48", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_pow", "field.pow:49", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_16"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_pow", "field.pow:50", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_16"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_pow", "field.pow:51", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_pow", "field.pow:52", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_17"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_pow", "field.pow:53", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_17"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_pow", "field.pow:54", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_pow", "field.pow:55", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_18"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_pow", "field.pow:56", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_18"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_pow", "field.pow:57", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_pow", "field.pow:58", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_19"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_pow", "field.pow:59", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_19"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_pow", "field.pow:60", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_pow", "field.pow:61", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_20"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_pow", "field.pow:62", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_20"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_pow", "field.pow:63", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_pow", "field.pow:64", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_21"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_pow", "field.pow:65", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_21"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_pow", "field.pow:66", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_pow", "field.pow:67", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_22"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_pow", "field.pow:68", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_22"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_pow", "field.pow:69", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_pow", "field.pow:70", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_23"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_pow", "field.pow:71", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_23"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_pow", "field.pow:72", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_pow", "field.pow:73", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_24"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_pow", "field.pow:74", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_24"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_pow", "field.pow:75", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_pow", "field.pow:76", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_25"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_pow", "field.pow:77", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_25"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_pow", "field.pow:78", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_pow", "field.pow:79", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_26"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_pow", "field.pow:80", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_26"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_pow", "field.pow:81", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_pow", "field.pow:82", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_27"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_pow", "field.pow:83", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_27"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_pow", "field.pow:84", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_pow", "field.pow:85", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_28"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_pow", "field.pow:86", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_28"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_pow", "field.pow:87", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_pow", "field.pow:88", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_29"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_pow", "field.pow:89", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_29"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_pow", "field.pow:90", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_pow", "field.pow:91", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_30"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_pow", "field.pow:92", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_30"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_pow", "field.pow:93", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_pow", "field.pow:94", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_pow|stage7.input.stage6.booleanity.InstructionRa_31"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_pow", "field.pow:95", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_pow|stage7.input.stage6.instruction_ra_virtual.InstructionRa_31"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_pow", "field.pow:96", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_pow|stage7.field.one"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_pow", "field.pow:97", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_pow|stage7.input.stage6.booleanity.BytecodeRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_pow", "field.pow:98", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_pow|stage7.input.stage6.bytecode_read_raf.BytecodeRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_pow", "field.pow:99", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_pow", "field.pow:100", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_pow|stage7.input.stage6.booleanity.BytecodeRa_1"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_pow", "field.pow:101", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_pow|stage7.input.stage6.bytecode_read_raf.BytecodeRa_1"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_pow", "field.pow:102", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_pow|stage7.field.one"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_pow", "field.pow:103", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_pow|stage7.input.stage6.booleanity.BytecodeRa_2"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_pow", "field.pow:104", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_pow|stage7.input.stage6.bytecode_read_raf.BytecodeRa_2"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_pow", "field.pow:105", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_pow|stage7.input.stage6.hamming_booleanity.HammingWeight"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_pow", "field.pow:106", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_pow|stage7.input.stage6.booleanity.RamRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_pow", "field.pow:107", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_pow|stage7.input.stage6.ram_ra_virtual.RamRa_0"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_pow", "field.pow:108", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_pow|stage7.input.stage6.hamming_booleanity.HammingWeight"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_pow", "field.pow:109", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_pow|stage7.input.stage6.booleanity.RamRa_1"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_pow", "field.pow:110", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_pow|stage7.input.stage6.ram_ra_virtual.RamRa_1"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_pow", "field.pow:111", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_pow|stage7.input.stage6.hamming_booleanity.HammingWeight"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_pow", "field.pow:112", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_pow|stage7.input.stage6.booleanity.RamRa_2"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_pow", "field.pow:113", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_pow|stage7.input.stage6.ram_ra_virtual.RamRa_2"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_pow", "field.pow:114", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_pow|stage7.input.stage6.hamming_booleanity.HammingWeight"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_pow", "field.pow:115", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_pow|stage7.input.stage6.booleanity.RamRa_3"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_pow", "field.pow:116", "stage7.hamming_weight_claim_reduction.gamma"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_term", "field.mul", "stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_pow|stage7.input.stage6.ram_ra_virtual.RamRa_3"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial0", "field.add", "stage7.field.one|stage7.hamming_weight_claim_reduction.claim.0.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial1", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial0|stage7.hamming_weight_claim_reduction.claim.0.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial2", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial1|stage7.hamming_weight_claim_reduction.claim.1.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial3", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial2|stage7.hamming_weight_claim_reduction.claim.1.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial4", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial3|stage7.hamming_weight_claim_reduction.claim.1.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial5", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial4|stage7.hamming_weight_claim_reduction.claim.2.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial6", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial5|stage7.hamming_weight_claim_reduction.claim.2.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial7", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial6|stage7.hamming_weight_claim_reduction.claim.2.virtualization.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial8", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial7|stage7.hamming_weight_claim_reduction.claim.3.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial9", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial8|stage7.hamming_weight_claim_reduction.claim.3.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial10", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial9|stage7.hamming_weight_claim_reduction.claim.3.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial11", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial10|stage7.hamming_weight_claim_reduction.claim.4.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial12", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial11|stage7.hamming_weight_claim_reduction.claim.4.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial13", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial12|stage7.hamming_weight_claim_reduction.claim.4.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial14", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial13|stage7.hamming_weight_claim_reduction.claim.5.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial15", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial14|stage7.hamming_weight_claim_reduction.claim.5.booleanity.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial16", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial15|stage7.hamming_weight_claim_reduction.claim.5.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial17", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial16|stage7.hamming_weight_claim_reduction.claim.6.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial18", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial17|stage7.hamming_weight_claim_reduction.claim.6.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial19", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial18|stage7.hamming_weight_claim_reduction.claim.6.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial20", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial19|stage7.hamming_weight_claim_reduction.claim.7.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial21", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial20|stage7.hamming_weight_claim_reduction.claim.7.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial22", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial21|stage7.hamming_weight_claim_reduction.claim.7.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial23", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial22|stage7.hamming_weight_claim_reduction.claim.8.hw.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial24", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial23|stage7.hamming_weight_claim_reduction.claim.8.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial25", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial24|stage7.hamming_weight_claim_reduction.claim.8.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial26", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial25|stage7.hamming_weight_claim_reduction.claim.9.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial27", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial26|stage7.hamming_weight_claim_reduction.claim.9.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial28", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial27|stage7.hamming_weight_claim_reduction.claim.9.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial29", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial28|stage7.hamming_weight_claim_reduction.claim.10.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial30", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial29|stage7.hamming_weight_claim_reduction.claim.10.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial31", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial30|stage7.hamming_weight_claim_reduction.claim.10.virtualization.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial32", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial31|stage7.hamming_weight_claim_reduction.claim.11.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial33", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial32|stage7.hamming_weight_claim_reduction.claim.11.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial34", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial33|stage7.hamming_weight_claim_reduction.claim.11.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial35", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial34|stage7.hamming_weight_claim_reduction.claim.12.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial36", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial35|stage7.hamming_weight_claim_reduction.claim.12.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial37", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial36|stage7.hamming_weight_claim_reduction.claim.12.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial38", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial37|stage7.hamming_weight_claim_reduction.claim.13.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial39", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial38|stage7.hamming_weight_claim_reduction.claim.13.booleanity.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial40", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial39|stage7.hamming_weight_claim_reduction.claim.13.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial41", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial40|stage7.hamming_weight_claim_reduction.claim.14.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial42", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial41|stage7.hamming_weight_claim_reduction.claim.14.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial43", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial42|stage7.hamming_weight_claim_reduction.claim.14.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial44", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial43|stage7.hamming_weight_claim_reduction.claim.15.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial45", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial44|stage7.hamming_weight_claim_reduction.claim.15.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial46", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial45|stage7.hamming_weight_claim_reduction.claim.15.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial47", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial46|stage7.hamming_weight_claim_reduction.claim.16.hw.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial48", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial47|stage7.hamming_weight_claim_reduction.claim.16.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial49", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial48|stage7.hamming_weight_claim_reduction.claim.16.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial50", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial49|stage7.hamming_weight_claim_reduction.claim.17.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial51", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial50|stage7.hamming_weight_claim_reduction.claim.17.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial52", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial51|stage7.hamming_weight_claim_reduction.claim.17.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial53", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial52|stage7.hamming_weight_claim_reduction.claim.18.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial54", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial53|stage7.hamming_weight_claim_reduction.claim.18.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial55", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial54|stage7.hamming_weight_claim_reduction.claim.18.virtualization.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial56", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial55|stage7.hamming_weight_claim_reduction.claim.19.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial57", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial56|stage7.hamming_weight_claim_reduction.claim.19.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial58", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial57|stage7.hamming_weight_claim_reduction.claim.19.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial59", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial58|stage7.hamming_weight_claim_reduction.claim.20.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial60", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial59|stage7.hamming_weight_claim_reduction.claim.20.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial61", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial60|stage7.hamming_weight_claim_reduction.claim.20.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial62", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial61|stage7.hamming_weight_claim_reduction.claim.21.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial63", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial62|stage7.hamming_weight_claim_reduction.claim.21.booleanity.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial64", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial63|stage7.hamming_weight_claim_reduction.claim.21.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial65", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial64|stage7.hamming_weight_claim_reduction.claim.22.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial66", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial65|stage7.hamming_weight_claim_reduction.claim.22.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial67", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial66|stage7.hamming_weight_claim_reduction.claim.22.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial68", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial67|stage7.hamming_weight_claim_reduction.claim.23.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial69", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial68|stage7.hamming_weight_claim_reduction.claim.23.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial70", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial69|stage7.hamming_weight_claim_reduction.claim.23.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial71", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial70|stage7.hamming_weight_claim_reduction.claim.24.hw.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial72", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial71|stage7.hamming_weight_claim_reduction.claim.24.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial73", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial72|stage7.hamming_weight_claim_reduction.claim.24.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial74", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial73|stage7.hamming_weight_claim_reduction.claim.25.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial75", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial74|stage7.hamming_weight_claim_reduction.claim.25.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial76", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial75|stage7.hamming_weight_claim_reduction.claim.25.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial77", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial76|stage7.hamming_weight_claim_reduction.claim.26.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial78", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial77|stage7.hamming_weight_claim_reduction.claim.26.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial79", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial78|stage7.hamming_weight_claim_reduction.claim.26.virtualization.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial80", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial79|stage7.hamming_weight_claim_reduction.claim.27.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial81", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial80|stage7.hamming_weight_claim_reduction.claim.27.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial82", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial81|stage7.hamming_weight_claim_reduction.claim.27.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial83", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial82|stage7.hamming_weight_claim_reduction.claim.28.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial84", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial83|stage7.hamming_weight_claim_reduction.claim.28.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial85", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial84|stage7.hamming_weight_claim_reduction.claim.28.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial86", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial85|stage7.hamming_weight_claim_reduction.claim.29.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial87", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial86|stage7.hamming_weight_claim_reduction.claim.29.booleanity.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial88", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial87|stage7.hamming_weight_claim_reduction.claim.29.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial89", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial88|stage7.hamming_weight_claim_reduction.claim.30.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial90", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial89|stage7.hamming_weight_claim_reduction.claim.30.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial91", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial90|stage7.hamming_weight_claim_reduction.claim.30.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial92", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial91|stage7.hamming_weight_claim_reduction.claim.31.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial93", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial92|stage7.hamming_weight_claim_reduction.claim.31.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial94", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial93|stage7.hamming_weight_claim_reduction.claim.31.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial95", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial94|stage7.hamming_weight_claim_reduction.claim.32.hw.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial96", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial95|stage7.hamming_weight_claim_reduction.claim.32.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial97", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial96|stage7.hamming_weight_claim_reduction.claim.32.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial98", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial97|stage7.hamming_weight_claim_reduction.claim.33.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial99", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial98|stage7.hamming_weight_claim_reduction.claim.33.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial100", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial99|stage7.hamming_weight_claim_reduction.claim.33.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial101", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial100|stage7.hamming_weight_claim_reduction.claim.34.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial102", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial101|stage7.hamming_weight_claim_reduction.claim.34.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial103", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial102|stage7.hamming_weight_claim_reduction.claim.34.virtualization.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial104", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial103|stage7.hamming_weight_claim_reduction.claim.35.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial105", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial104|stage7.hamming_weight_claim_reduction.claim.35.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial106", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial105|stage7.hamming_weight_claim_reduction.claim.35.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial107", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial106|stage7.hamming_weight_claim_reduction.claim.36.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial108", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial107|stage7.hamming_weight_claim_reduction.claim.36.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial109", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial108|stage7.hamming_weight_claim_reduction.claim.36.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial110", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial109|stage7.hamming_weight_claim_reduction.claim.37.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial111", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial110|stage7.hamming_weight_claim_reduction.claim.37.booleanity.gamma_term"), + stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial112", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial111|stage7.hamming_weight_claim_reduction.claim.37.virtualization.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial113", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial112|stage7.hamming_weight_claim_reduction.claim.38.hw.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial114", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial113|stage7.hamming_weight_claim_reduction.claim.38.booleanity.gamma_term"), stage7_field_expr!("stage7.hamming_weight_claim_reduction.claim_expr.partial115", "field.add", "stage7.hamming_weight_claim_reduction.claim_expr.partial114|stage7.hamming_weight_claim_reduction.claim.38.virtualization.gamma_term"), +]; +pub const STAGE7_KERNELS: &[Stage7KernelPlan] = &[ + +]; + +pub const STAGE7_SUMCHECK_CLAIMS: &[Stage7SumcheckClaimPlan] = &[ + Stage7SumcheckClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.input", stage: "stage7", domain: "jolt.stage7_hamming_weight_claim_reduction_domain", num_rounds: 4, degree: 2, claim: "stage7.hamming_weight_claim_reduction.weighted_stage6_claims", kernel: None, relation: Some("jolt.stage7.hamming_weight_claim_reduction"), claim_value: "stage7.hamming_weight_claim_reduction.claim_expr.partial115", input_openings: "stage7.input.stage6.hamming_booleanity.HammingWeight|stage7.input.stage6.booleanity.InstructionRa_0|stage7.input.stage6.instruction_ra_virtual.InstructionRa_0|stage7.input.stage6.booleanity.InstructionRa_1|stage7.input.stage6.instruction_ra_virtual.InstructionRa_1|stage7.input.stage6.booleanity.InstructionRa_2|stage7.input.stage6.instruction_ra_virtual.InstructionRa_2|stage7.input.stage6.booleanity.InstructionRa_3|stage7.input.stage6.instruction_ra_virtual.InstructionRa_3|stage7.input.stage6.booleanity.InstructionRa_4|stage7.input.stage6.instruction_ra_virtual.InstructionRa_4|stage7.input.stage6.booleanity.InstructionRa_5|stage7.input.stage6.instruction_ra_virtual.InstructionRa_5|stage7.input.stage6.booleanity.InstructionRa_6|stage7.input.stage6.instruction_ra_virtual.InstructionRa_6|stage7.input.stage6.booleanity.InstructionRa_7|stage7.input.stage6.instruction_ra_virtual.InstructionRa_7|stage7.input.stage6.booleanity.InstructionRa_8|stage7.input.stage6.instruction_ra_virtual.InstructionRa_8|stage7.input.stage6.booleanity.InstructionRa_9|stage7.input.stage6.instruction_ra_virtual.InstructionRa_9|stage7.input.stage6.booleanity.InstructionRa_10|stage7.input.stage6.instruction_ra_virtual.InstructionRa_10|stage7.input.stage6.booleanity.InstructionRa_11|stage7.input.stage6.instruction_ra_virtual.InstructionRa_11|stage7.input.stage6.booleanity.InstructionRa_12|stage7.input.stage6.instruction_ra_virtual.InstructionRa_12|stage7.input.stage6.booleanity.InstructionRa_13|stage7.input.stage6.instruction_ra_virtual.InstructionRa_13|stage7.input.stage6.booleanity.InstructionRa_14|stage7.input.stage6.instruction_ra_virtual.InstructionRa_14|stage7.input.stage6.booleanity.InstructionRa_15|stage7.input.stage6.instruction_ra_virtual.InstructionRa_15|stage7.input.stage6.booleanity.InstructionRa_16|stage7.input.stage6.instruction_ra_virtual.InstructionRa_16|stage7.input.stage6.booleanity.InstructionRa_17|stage7.input.stage6.instruction_ra_virtual.InstructionRa_17|stage7.input.stage6.booleanity.InstructionRa_18|stage7.input.stage6.instruction_ra_virtual.InstructionRa_18|stage7.input.stage6.booleanity.InstructionRa_19|stage7.input.stage6.instruction_ra_virtual.InstructionRa_19|stage7.input.stage6.booleanity.InstructionRa_20|stage7.input.stage6.instruction_ra_virtual.InstructionRa_20|stage7.input.stage6.booleanity.InstructionRa_21|stage7.input.stage6.instruction_ra_virtual.InstructionRa_21|stage7.input.stage6.booleanity.InstructionRa_22|stage7.input.stage6.instruction_ra_virtual.InstructionRa_22|stage7.input.stage6.booleanity.InstructionRa_23|stage7.input.stage6.instruction_ra_virtual.InstructionRa_23|stage7.input.stage6.booleanity.InstructionRa_24|stage7.input.stage6.instruction_ra_virtual.InstructionRa_24|stage7.input.stage6.booleanity.InstructionRa_25|stage7.input.stage6.instruction_ra_virtual.InstructionRa_25|stage7.input.stage6.booleanity.InstructionRa_26|stage7.input.stage6.instruction_ra_virtual.InstructionRa_26|stage7.input.stage6.booleanity.InstructionRa_27|stage7.input.stage6.instruction_ra_virtual.InstructionRa_27|stage7.input.stage6.booleanity.InstructionRa_28|stage7.input.stage6.instruction_ra_virtual.InstructionRa_28|stage7.input.stage6.booleanity.InstructionRa_29|stage7.input.stage6.instruction_ra_virtual.InstructionRa_29|stage7.input.stage6.booleanity.InstructionRa_30|stage7.input.stage6.instruction_ra_virtual.InstructionRa_30|stage7.input.stage6.booleanity.InstructionRa_31|stage7.input.stage6.instruction_ra_virtual.InstructionRa_31|stage7.input.stage6.booleanity.BytecodeRa_0|stage7.input.stage6.bytecode_read_raf.BytecodeRa_0|stage7.input.stage6.booleanity.BytecodeRa_1|stage7.input.stage6.bytecode_read_raf.BytecodeRa_1|stage7.input.stage6.booleanity.BytecodeRa_2|stage7.input.stage6.bytecode_read_raf.BytecodeRa_2|stage7.input.stage6.booleanity.RamRa_0|stage7.input.stage6.ram_ra_virtual.RamRa_0|stage7.input.stage6.booleanity.RamRa_1|stage7.input.stage6.ram_ra_virtual.RamRa_1|stage7.input.stage6.booleanity.RamRa_2|stage7.input.stage6.ram_ra_virtual.RamRa_2|stage7.input.stage6.booleanity.RamRa_3|stage7.input.stage6.ram_ra_virtual.RamRa_3" }, +]; +pub const STAGE7_SUMCHECK_BATCH_0_ROUND_SCHEDULE: &[usize] = &[ + 4, +]; + +pub const STAGE7_SUMCHECK_BATCHES: &[Stage7SumcheckBatchPlan] = &[ + Stage7SumcheckBatchPlan { symbol: "stage7.batch", stage: "stage7", proof_slot: "stage7.sumcheck", policy: "jolt_core_stage7_aligned", count: 1, ordered_claims: "stage7.hamming_weight_claim_reduction.input", claim_operands: "stage7.hamming_weight_claim_reduction.input", claim_label: "sumcheck_claim", round_label: "sumcheck_poly", round_schedule: STAGE7_SUMCHECK_BATCH_0_ROUND_SCHEDULE }, +]; +pub const STAGE7_SUMCHECK_DRIVER_0_ROUND_SCHEDULE: &[usize] = &[ + 4, +]; + +pub const STAGE7_SUMCHECK_DRIVERS: &[Stage7SumcheckDriverPlan] = &[ + Stage7SumcheckDriverPlan { symbol: "stage7.sumcheck", stage: "stage7", proof_slot: "stage7.sumcheck", kernel: None, relation: Some("jolt.stage7.batched"), batch: "stage7.batch", policy: "jolt_core_stage7_aligned", round_schedule: STAGE7_SUMCHECK_DRIVER_0_ROUND_SCHEDULE, claim_label: "sumcheck_claim", round_label: "sumcheck_poly", num_rounds: 4, degree: 2 }, +]; +pub const STAGE7_SUMCHECK_INSTANCE_RESULTS: &[Stage7SumcheckInstanceResultPlan] = &[ + Stage7SumcheckInstanceResultPlan { symbol: "stage7.hamming_weight_claim_reduction.instance", source: "stage7.sumcheck", claim: "stage7.hamming_weight_claim_reduction.input", relation: "jolt.stage7.hamming_weight_claim_reduction", index: 0, point_arity: 4, num_rounds: 4, round_offset: 0, point_order: "reverse", degree: 2 }, +]; + +macro_rules! stage7_sumcheck_eval { + ($symbol:literal, $source:literal, $name:literal, $index:literal, $oracle:literal) => { + Stage7SumcheckEvalPlan { symbol: $symbol, source: $source, name: $name, index: $index, oracle: $oracle } + }; +} + +#[rustfmt::skip] +pub const STAGE7_SUMCHECK_EVALS: &[Stage7SumcheckEvalPlan] = &[ + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", 0, "InstructionRa_0"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", 1, "InstructionRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", 2, "InstructionRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", 3, "InstructionRa_3"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", 4, "InstructionRa_4"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", 5, "InstructionRa_5"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", 6, "InstructionRa_6"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", 7, "InstructionRa_7"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", 8, "InstructionRa_8"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", 9, "InstructionRa_9"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", 10, "InstructionRa_10"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", 11, "InstructionRa_11"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", 12, "InstructionRa_12"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", 13, "InstructionRa_13"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", 14, "InstructionRa_14"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", 15, "InstructionRa_15"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", 16, "InstructionRa_16"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", 17, "InstructionRa_17"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", 18, "InstructionRa_18"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", 19, "InstructionRa_19"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", 20, "InstructionRa_20"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", 21, "InstructionRa_21"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", 22, "InstructionRa_22"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", 23, "InstructionRa_23"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", 24, "InstructionRa_24"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", 25, "InstructionRa_25"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", 26, "InstructionRa_26"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", 27, "InstructionRa_27"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", 28, "InstructionRa_28"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", 29, "InstructionRa_29"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", 30, "InstructionRa_30"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", 31, "InstructionRa_31"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", 32, "BytecodeRa_0"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", 33, "BytecodeRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", 34, "BytecodeRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_0", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_0", 35, "RamRa_0"), + stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_1", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_1", 36, "RamRa_1"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_2", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_2", 37, "RamRa_2"), stage7_sumcheck_eval!("stage7.hamming_weight_claim_reduction.eval.RamRa_3", "stage7.sumcheck", "stage7.hamming_weight_claim_reduction.eval.RamRa_3", 38, "RamRa_3"), +]; + +pub const STAGE7_POINT_ZEROS: &[Stage7PointZeroPlan] = &[ + +]; + +pub const STAGE7_POINT_SLICES: &[Stage7PointSlicePlan] = &[ + Stage7PointSlicePlan { symbol: "stage7.hamming_weight_claim_reduction.point.cycle", source: "stage7.input.stage6.booleanity.InstructionRa_0", offset: 4, length: 16, input: "stage7.input.stage6.booleanity.InstructionRa_0" }, +]; + +pub const STAGE7_POINT_CONCATS: &[Stage7PointConcatPlan] = &[ + Stage7PointConcatPlan { symbol: "stage7.hamming_weight_claim_reduction.point", layout: "address_chunk_then_cycle", arity: 20, inputs: "stage7.hamming_weight_claim_reduction.instance|stage7.hamming_weight_claim_reduction.point.cycle" }, +]; +pub const STAGE7_OPENING_CLAIMS: &[Stage7OpeningClaimPlan] = &[ + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_0" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_1" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_2" }, + Stage7OpeningClaimPlan { symbol: "stage7.hamming_weight_claim_reduction.opening.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed", point_source: "stage7.hamming_weight_claim_reduction.point", eval_source: "stage7.hamming_weight_claim_reduction.eval.RamRa_3" }, +]; + +pub const STAGE7_OPENING_EQUALITIES: &[Stage7OpeningClaimEqualityPlan] = &[ + +]; + +pub const STAGE7_OPENING_BATCHES: &[Stage7OpeningBatchPlan] = &[ + Stage7OpeningBatchPlan { symbol: "stage7.openings", stage: "stage7", proof_slot: "stage7.openings", policy: "jolt_stage7_output_order", count: 39, ordered_claims: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0|stage7.hamming_weight_claim_reduction.opening.InstructionRa_1|stage7.hamming_weight_claim_reduction.opening.InstructionRa_2|stage7.hamming_weight_claim_reduction.opening.InstructionRa_3|stage7.hamming_weight_claim_reduction.opening.InstructionRa_4|stage7.hamming_weight_claim_reduction.opening.InstructionRa_5|stage7.hamming_weight_claim_reduction.opening.InstructionRa_6|stage7.hamming_weight_claim_reduction.opening.InstructionRa_7|stage7.hamming_weight_claim_reduction.opening.InstructionRa_8|stage7.hamming_weight_claim_reduction.opening.InstructionRa_9|stage7.hamming_weight_claim_reduction.opening.InstructionRa_10|stage7.hamming_weight_claim_reduction.opening.InstructionRa_11|stage7.hamming_weight_claim_reduction.opening.InstructionRa_12|stage7.hamming_weight_claim_reduction.opening.InstructionRa_13|stage7.hamming_weight_claim_reduction.opening.InstructionRa_14|stage7.hamming_weight_claim_reduction.opening.InstructionRa_15|stage7.hamming_weight_claim_reduction.opening.InstructionRa_16|stage7.hamming_weight_claim_reduction.opening.InstructionRa_17|stage7.hamming_weight_claim_reduction.opening.InstructionRa_18|stage7.hamming_weight_claim_reduction.opening.InstructionRa_19|stage7.hamming_weight_claim_reduction.opening.InstructionRa_20|stage7.hamming_weight_claim_reduction.opening.InstructionRa_21|stage7.hamming_weight_claim_reduction.opening.InstructionRa_22|stage7.hamming_weight_claim_reduction.opening.InstructionRa_23|stage7.hamming_weight_claim_reduction.opening.InstructionRa_24|stage7.hamming_weight_claim_reduction.opening.InstructionRa_25|stage7.hamming_weight_claim_reduction.opening.InstructionRa_26|stage7.hamming_weight_claim_reduction.opening.InstructionRa_27|stage7.hamming_weight_claim_reduction.opening.InstructionRa_28|stage7.hamming_weight_claim_reduction.opening.InstructionRa_29|stage7.hamming_weight_claim_reduction.opening.InstructionRa_30|stage7.hamming_weight_claim_reduction.opening.InstructionRa_31|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2|stage7.hamming_weight_claim_reduction.opening.RamRa_0|stage7.hamming_weight_claim_reduction.opening.RamRa_1|stage7.hamming_weight_claim_reduction.opening.RamRa_2|stage7.hamming_weight_claim_reduction.opening.RamRa_3", claim_operands: "stage7.hamming_weight_claim_reduction.opening.InstructionRa_0|stage7.hamming_weight_claim_reduction.opening.InstructionRa_1|stage7.hamming_weight_claim_reduction.opening.InstructionRa_2|stage7.hamming_weight_claim_reduction.opening.InstructionRa_3|stage7.hamming_weight_claim_reduction.opening.InstructionRa_4|stage7.hamming_weight_claim_reduction.opening.InstructionRa_5|stage7.hamming_weight_claim_reduction.opening.InstructionRa_6|stage7.hamming_weight_claim_reduction.opening.InstructionRa_7|stage7.hamming_weight_claim_reduction.opening.InstructionRa_8|stage7.hamming_weight_claim_reduction.opening.InstructionRa_9|stage7.hamming_weight_claim_reduction.opening.InstructionRa_10|stage7.hamming_weight_claim_reduction.opening.InstructionRa_11|stage7.hamming_weight_claim_reduction.opening.InstructionRa_12|stage7.hamming_weight_claim_reduction.opening.InstructionRa_13|stage7.hamming_weight_claim_reduction.opening.InstructionRa_14|stage7.hamming_weight_claim_reduction.opening.InstructionRa_15|stage7.hamming_weight_claim_reduction.opening.InstructionRa_16|stage7.hamming_weight_claim_reduction.opening.InstructionRa_17|stage7.hamming_weight_claim_reduction.opening.InstructionRa_18|stage7.hamming_weight_claim_reduction.opening.InstructionRa_19|stage7.hamming_weight_claim_reduction.opening.InstructionRa_20|stage7.hamming_weight_claim_reduction.opening.InstructionRa_21|stage7.hamming_weight_claim_reduction.opening.InstructionRa_22|stage7.hamming_weight_claim_reduction.opening.InstructionRa_23|stage7.hamming_weight_claim_reduction.opening.InstructionRa_24|stage7.hamming_weight_claim_reduction.opening.InstructionRa_25|stage7.hamming_weight_claim_reduction.opening.InstructionRa_26|stage7.hamming_weight_claim_reduction.opening.InstructionRa_27|stage7.hamming_weight_claim_reduction.opening.InstructionRa_28|stage7.hamming_weight_claim_reduction.opening.InstructionRa_29|stage7.hamming_weight_claim_reduction.opening.InstructionRa_30|stage7.hamming_weight_claim_reduction.opening.InstructionRa_31|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_0|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_1|stage7.hamming_weight_claim_reduction.opening.BytecodeRa_2|stage7.hamming_weight_claim_reduction.opening.RamRa_0|stage7.hamming_weight_claim_reduction.opening.RamRa_1|stage7.hamming_weight_claim_reduction.opening.RamRa_2|stage7.hamming_weight_claim_reduction.opening.RamRa_3" }, +]; +pub const STAGE7_PROGRAM: Stage7VerifierProgramPlan = Stage7CpuProgramPlan { + role: "verifier", + params: STAGE7_PARAMS, + steps: STAGE7_PROGRAM_STEPS, + transcript_squeezes: STAGE7_TRANSCRIPT_SQUEEZES, + transcript_absorb_bytes: STAGE7_TRANSCRIPT_ABSORB_BYTES, + opening_inputs: STAGE7_OPENING_INPUTS, + field_constants: STAGE7_FIELD_CONSTANTS, + field_exprs: STAGE7_FIELD_EXPRS, + kernels: STAGE7_KERNELS, + claims: STAGE7_SUMCHECK_CLAIMS, + batches: STAGE7_SUMCHECK_BATCHES, + drivers: STAGE7_SUMCHECK_DRIVERS, + instance_results: STAGE7_SUMCHECK_INSTANCE_RESULTS, + evals: STAGE7_SUMCHECK_EVALS, + point_zeros: STAGE7_POINT_ZEROS, + point_slices: STAGE7_POINT_SLICES, + point_concats: STAGE7_POINT_CONCATS, + opening_claims: STAGE7_OPENING_CLAIMS, + opening_equalities: STAGE7_OPENING_EQUALITIES, + opening_batches: STAGE7_OPENING_BATCHES, +}; + +pub fn verify_stage7( + proof: &Stage7Proof, + opening_inputs: &[Stage7OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage7Error> +where + T: Transcript, +{ + verify_stage7_with_program(&STAGE7_PROGRAM, proof, opening_inputs, transcript) +} + +pub fn verify_stage7_with_program( + program: &'static Stage7VerifierProgramPlan, + proof: &Stage7Proof, + opening_inputs: &[Stage7OpeningInputValue], + transcript: &mut T, +) -> Result, VerifyStage7Error> +where + T: Transcript, +{ + if proof.sumchecks.len() != program.drivers.len() { + return Err(VerifyStage7Error::UnexpectedProofCount { + expected: program.drivers.len(), + got: proof.sumchecks.len(), + }); + } + let mut store = + super::common::ValueStore::with_opening_inputs(opening_inputs, program.opening_inputs)?; + store.seed_constants(program.field_constants); + store.seed_point_zeros(program.point_zeros); + let mut artifacts = Stage7ExecutionArtifacts::default(); + for step in program.steps { + match step.kind { + "transcript_squeeze" => { + let squeeze = + find_plan(program.transcript_squeezes, step.symbol).ok_or(VerifyStage7Error::MissingValue { + symbol: step.symbol, + })?; + verify_stage7_squeeze(program, squeeze, &mut store, transcript, &mut artifacts)?; + } + "transcript_absorb_bytes" => { + let absorb = find_plan(program.transcript_absorb_bytes, step.symbol).ok_or( + VerifyStage7Error::MissingValue { + symbol: step.symbol, + }, + )?; + absorb_stage7_bytes(absorb, transcript); + } + "sumcheck_driver" => { + let driver = + find_plan(program.drivers, step.symbol).ok_or(VerifyStage7Error::MissingProof { + driver: step.symbol, + })?; + verify_stage7_driver( + program, + driver, + proof, + &mut store, + transcript, + &mut artifacts, + )?; + } + _ => { + return Err(VerifyStage7Error::InvalidProof { + driver: step.symbol, + reason: "unsupported stage7 program step", + }); + } + } + } + artifacts + .opening_batches + .extend(program.opening_batches.iter()); + Ok(artifacts) +} + +pub fn stage7_verifier_program() -> &'static Stage7VerifierProgramPlan { + &STAGE7_PROGRAM +} + +fn verify_stage7_squeeze( + program: &'static Stage7VerifierProgramPlan, + squeeze: &'static Stage7TranscriptSqueezePlan, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage7ExecutionArtifacts, +) -> Result<(), VerifyStage7Error> +where + T: Transcript, +{ + let values = transcript.challenge_vector(squeeze.count); + store.observe_challenge_vector(squeeze, &values, |input, expected, actual| { + VerifyStage7Error::InvalidInputLength { + input, + expected, + actual, + } + })?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage7Error::from)?; + artifacts.challenge_vectors.push(Stage7ChallengeVector { + symbol: squeeze.symbol, + values, + }); + Ok(()) +} + +fn absorb_stage7_bytes(absorb: &'static Stage7TranscriptAbsorbBytesPlan, transcript: &mut T) +where + T: Transcript, +{ + transcript.append(&LabelWithCount( + absorb.label.as_bytes(), + absorb.payload.len() as u64, + )); + transcript.append_bytes(absorb.payload.as_bytes()); +} + +fn verify_stage7_driver( + program: &'static Stage7VerifierProgramPlan, + driver: &'static Stage7SumcheckDriverPlan, + proof: &Stage7Proof, + store: &mut super::common::ValueStore, + transcript: &mut T, + artifacts: &mut Stage7ExecutionArtifacts, +) -> Result<(), VerifyStage7Error> +where + T: Transcript, +{ + let proof = proof + .sumchecks + .get(artifacts.sumchecks.len()) + .ok_or(VerifyStage7Error::MissingProof { + driver: driver.symbol, + })?; + let relation = driver.relation.unwrap_or(""); + let output = match relation { + "jolt.stage7.batched" => { + verify_batched_stage7(program, driver, proof, store, transcript)? + } + _ => return Err(VerifyStage7Error::UnsupportedRelation { relation }), + }; + artifacts.sumchecks.push(output); + Ok(()) +} + +fn verify_batched_stage7( + program: &'static Stage7VerifierProgramPlan, + driver: &'static Stage7SumcheckDriverPlan, + proof: &Stage7SumcheckOutput, + store: &mut super::common::ValueStore, + transcript: &mut T, +) -> Result, VerifyStage7Error> +where + T: Transcript, +{ + super::common::verify_batched_sumcheck( + driver, + proof, + program.claims, + program.batches, + program.field_exprs, + program.opening_inputs, + program.opening_claims, + program.opening_batches, + store, + transcript, + |store, evals, point, batching_coeffs| { + expected_batched_output_claim(program, driver, store, evals, point, batching_coeffs) + }, + |store, verified| observe_stage7_sumcheck_output(program, store, verified), + |driver, error| VerifyStage7Error::Sumcheck { driver, error }, + ) +} + +fn observe_stage7_sumcheck_output( + program: &'static Stage7VerifierProgramPlan, + store: &mut super::common::ValueStore, + output: &Stage7SumcheckOutput, +) -> Result<(), VerifyStage7Error> { + store.observe_sumcheck_output( + program.instance_results, + program.evals, + output, + |instance, mut point| { + match instance.point_order { + "as_is" => {} + "reverse" => point.reverse(), + "bytecode_read_raf" => point = normalize_bytecode_read_raf_point(&point, stage7_trace_rounds(program)?, "stage7.bytecode_read_raf.point")?, + "stage7_booleanity" => {} + "instruction_read_raf" => point = normalize_instruction_read_raf_point(&point, "stage7.instruction_read_raf.point")?, + _ => { + return Err(VerifyStage7Error::InvalidProof { + driver: output.driver, + reason: "unsupported point order", + }); + } + } + Ok(point) + }, + |input, expected, actual| VerifyStage7Error::InvalidInputLength { + input, + expected, + actual, + }, + |symbol| VerifyStage7Error::MissingValue { symbol }, + )?; + store.evaluate_available_points( + program.point_slices, + program.point_concats, + |input, expected, actual| VerifyStage7Error::InvalidInputLength { + input, + expected, + actual, + }, + )?; + store + .evaluate_available_field_exprs(program.field_exprs, super::common::evaluate_field_expr) + .map_err(VerifyStage7Error::from)?; + store.verify_opening_equalities( + program.opening_equalities, + |driver, reason| VerifyStage7Error::InvalidProof { driver, reason }, + |symbol| VerifyStage7Error::MissingValue { symbol }, + ) +} + +fn expected_batched_output_claim( + program: &'static Stage7VerifierProgramPlan, + driver: &'static Stage7SumcheckDriverPlan, + store: &super::common::ValueStore, + evals: &[Stage7NamedEval], + point: &[Fr], + batching_coeffs: &[Fr], +) -> Result { + let batch = find_batch(program.batches, driver.symbol, driver.batch)?; + let claims = batch_claims(program.claims, batch)?; + let mut expected = Fr::from_u64(0); + for (claim, coefficient) in claims.iter().zip(batching_coeffs) { + let instance = program + .instance_results + .iter() + .find(|instance| instance.claim == claim.symbol && instance.source == driver.symbol) + .ok_or(VerifyStage7Error::MissingClaim { + batch: batch.symbol, + claim: claim.symbol, + })?; + let local_point = point + .get(instance.round_offset..instance.round_offset + instance.num_rounds) + .ok_or(VerifyStage7Error::InvalidInputLength { + input: instance.symbol, + expected: instance.round_offset + instance.num_rounds, + actual: point.len(), + })?; + let relation = claim.relation.unwrap_or(""); + let value = match relation { + "jolt.stage7.hamming_weight_claim_reduction" => { + expected_hamming_weight_claim_reduction(program, driver, store, evals, local_point)? + } + _ => return Err(VerifyStage7Error::UnsupportedRelation { relation }), + }; + expected += *coefficient * value; + } + Ok(expected) +} + +fn expected_hamming_weight_claim_reduction( + program: &'static Stage7VerifierProgramPlan, + driver: &'static Stage7SumcheckDriverPlan, + store: &super::common::ValueStore, + evals: &[Stage7NamedEval], + local_point: &[Fr], +) -> Result { + let rho_rev = reverse_slice(local_point); + let booleanity_point = super::common::store_point(store, "stage7.input.stage6.booleanity.InstructionRa_0")?; + let r_addr_bool = + booleanity_point + .get(..local_point.len()) + .ok_or(VerifyStage7Error::InvalidInputLength { + input: "stage7.input.stage6.booleanity.InstructionRa_0", + expected: local_point.len(), + actual: booleanity_point.len(), + })?; + let eq_bool = EqPolynomial::::mle(&rho_rev, r_addr_bool); + let gamma = super::common::store_scalar(store, "stage7.hamming_weight_claim_reduction.gamma")?; + let mut gamma_power = Fr::from_u64(1); + let mut expected = Fr::from_u64(0); + let mut eval_plans = program + .evals + .iter() + .filter(|eval| eval.source == driver.symbol) + .collect::>(); + eval_plans.sort_by_key(|eval| eval.index); + for eval_plan in eval_plans { + let g_i = eval_by_name(evals, eval_plan.name)?; + let virt_point = + stage7_virtualization_point(store, eval_plan.oracle, local_point.len())?; + let eq_virt = EqPolynomial::::mle(&rho_rev, virt_point); + expected += g_i * (gamma_power + gamma_power * gamma * eq_bool + + gamma_power * gamma.square() * eq_virt); + gamma_power *= gamma; + gamma_power *= gamma; + gamma_power *= gamma; + } + Ok(expected) +} + +fn stage7_virtualization_point<'a>( + store: &'a super::common::ValueStore, + oracle: &str, + log_k_chunk: usize, +) -> Result<&'a [Fr], VerifyStage7Error> { + let symbol = if oracle.starts_with("InstructionRa_") { + format!("stage7.input.stage6.instruction_ra_virtual.{oracle}") + } else if oracle.starts_with("BytecodeRa_") { + format!("stage7.input.stage6.bytecode_read_raf.{oracle}") + } else if oracle.starts_with("RamRa_") { + format!("stage7.input.stage6.ram_ra_virtual.{oracle}") + } else { + return Err(VerifyStage7Error::MissingValue { + symbol: "stage7.hamming_weight_claim_reduction.oracle", + }); + }; + let point = store.try_point(&symbol).ok_or(VerifyStage7Error::MissingValue { + symbol: "stage7.hamming_weight_claim_reduction.virtualization_point", + })?; + point + .get(..log_k_chunk) + .ok_or(VerifyStage7Error::InvalidInputLength { + input: "stage7.hamming_weight_claim_reduction.virtualization_point", + expected: log_k_chunk, + actual: point.len(), + }) +} + +fn stage7_trace_rounds( + program: &'static Stage7VerifierProgramPlan, +) -> Result { + program + .instance_results + .iter() + .find(|instance| instance.relation == "jolt.stage7.hamming_booleanity") + .map(|instance| instance.num_rounds) + .ok_or(VerifyStage7Error::MissingValue { + symbol: "stage7.hamming_booleanity.instance", + }) +} diff --git a/crates/jolt-verifier/src/stages/stage8.rs b/crates/jolt-verifier/src/stages/stage8.rs new file mode 100644 index 0000000000..6d245c8ba9 --- /dev/null +++ b/crates/jolt-verifier/src/stages/stage8.rs @@ -0,0 +1,173 @@ +#![allow(clippy::too_many_lines)] + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8Params { + pub field: &'static str, + pub pcs: &'static str, + pub transcript: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningInputPlan { + pub symbol: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, + pub oracle: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub claim_kind: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningClaimPlan { + pub symbol: &'static str, + pub oracle: &'static str, + pub family: &'static str, + pub domain: &'static str, + pub point_arity: usize, + pub point_source: &'static str, + pub eval_source: &'static str, + pub source_stage: &'static str, + pub source_claim: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8OpeningBatchPlan { + pub symbol: &'static str, + pub proof_slot: &'static str, + pub policy: &'static str, + pub count: usize, + pub ordered_claims: &'static [&'static str], +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8PcsProofPlan { + pub symbol: &'static str, + pub mode: &'static str, + pub pcs: &'static str, + pub proof_slot: &'static str, + pub transcript_label: &'static str, + pub batch: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Stage8EvaluationProgramPlan { + pub role: &'static str, + pub function: &'static str, + pub params: Stage8Params, + pub evaluation_point_source: Stage8OpeningInputPlan, + pub opening_inputs: &'static [Stage8OpeningInputPlan], + pub opening_claims: &'static [Stage8OpeningClaimPlan], + pub opening_batch: Stage8OpeningBatchPlan, + pub pcs_proof: Stage8PcsProofPlan, +} + +pub const STAGE8_PARAMS: Stage8Params = Stage8Params { field: "bn254_fr", pcs: "dory", transcript: "blake2b_transcript" }; + +pub const STAGE8_EVALUATION_POINT_SOURCE: Stage8OpeningInputPlan = Stage8OpeningInputPlan { symbol: "stage8.evaluation.point_source", source_stage: "stage7", source_claim: "stage7.input.stage6.booleanity.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }; + +pub const STAGE8_OPENING_INPUTS: &[Stage8OpeningInputPlan] = &[ + Stage8OpeningInputPlan { symbol: "stage8.evaluation.point_source", source_stage: "stage7", source_claim: "stage7.input.stage6.booleanity.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage6.RamInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RamInc", oracle: "RamInc", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage6.RdInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RdInc", oracle: "RdInc", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0", oracle: "InstructionRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1", oracle: "InstructionRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2", oracle: "InstructionRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3", oracle: "InstructionRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_4", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4", oracle: "InstructionRa_4", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_5", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5", oracle: "InstructionRa_5", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_6", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6", oracle: "InstructionRa_6", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_7", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7", oracle: "InstructionRa_7", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_8", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8", oracle: "InstructionRa_8", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_9", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9", oracle: "InstructionRa_9", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_10", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10", oracle: "InstructionRa_10", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_11", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11", oracle: "InstructionRa_11", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_12", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12", oracle: "InstructionRa_12", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_13", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13", oracle: "InstructionRa_13", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_14", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14", oracle: "InstructionRa_14", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_15", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15", oracle: "InstructionRa_15", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_16", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16", oracle: "InstructionRa_16", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_17", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17", oracle: "InstructionRa_17", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_18", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18", oracle: "InstructionRa_18", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_19", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19", oracle: "InstructionRa_19", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_20", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20", oracle: "InstructionRa_20", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_21", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21", oracle: "InstructionRa_21", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_22", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22", oracle: "InstructionRa_22", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_23", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23", oracle: "InstructionRa_23", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_24", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24", oracle: "InstructionRa_24", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_25", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25", oracle: "InstructionRa_25", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_26", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26", oracle: "InstructionRa_26", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_27", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27", oracle: "InstructionRa_27", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_28", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28", oracle: "InstructionRa_28", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_29", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29", oracle: "InstructionRa_29", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_30", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30", oracle: "InstructionRa_30", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.InstructionRa_31", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31", oracle: "InstructionRa_31", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0", oracle: "BytecodeRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1", oracle: "BytecodeRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.BytecodeRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2", oracle: "BytecodeRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_0", oracle: "RamRa_0", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_1", oracle: "RamRa_1", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_2", oracle: "RamRa_2", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, + Stage8OpeningInputPlan { symbol: "stage8.input.stage7.RamRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_3", oracle: "RamRa_3", domain: "jolt.main_witness_commit_domain", point_arity: 20, claim_kind: "committed" }, +]; + +pub const STAGE8_OPENING_CLAIMS: &[Stage8OpeningClaimPlan] = &[ + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamInc", oracle: "RamInc", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage6.RamInc", eval_source: "stage8.input.stage6.RamInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RamInc" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RdInc", oracle: "RdInc", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage6.RdInc", eval_source: "stage8.input.stage6.RdInc", source_stage: "stage6", source_claim: "stage6.inc_claim_reduction.eval.RdInc" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_0", oracle: "InstructionRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_0", eval_source: "stage8.input.stage7.InstructionRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_1", oracle: "InstructionRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_1", eval_source: "stage8.input.stage7.InstructionRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_2", oracle: "InstructionRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_2", eval_source: "stage8.input.stage7.InstructionRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_3", oracle: "InstructionRa_3", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_3", eval_source: "stage8.input.stage7.InstructionRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_3" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_4", oracle: "InstructionRa_4", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_4", eval_source: "stage8.input.stage7.InstructionRa_4", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_4" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_5", oracle: "InstructionRa_5", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_5", eval_source: "stage8.input.stage7.InstructionRa_5", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_5" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_6", oracle: "InstructionRa_6", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_6", eval_source: "stage8.input.stage7.InstructionRa_6", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_6" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_7", oracle: "InstructionRa_7", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_7", eval_source: "stage8.input.stage7.InstructionRa_7", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_7" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_8", oracle: "InstructionRa_8", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_8", eval_source: "stage8.input.stage7.InstructionRa_8", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_8" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_9", oracle: "InstructionRa_9", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_9", eval_source: "stage8.input.stage7.InstructionRa_9", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_9" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_10", oracle: "InstructionRa_10", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_10", eval_source: "stage8.input.stage7.InstructionRa_10", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_10" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_11", oracle: "InstructionRa_11", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_11", eval_source: "stage8.input.stage7.InstructionRa_11", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_11" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_12", oracle: "InstructionRa_12", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_12", eval_source: "stage8.input.stage7.InstructionRa_12", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_12" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_13", oracle: "InstructionRa_13", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_13", eval_source: "stage8.input.stage7.InstructionRa_13", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_13" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_14", oracle: "InstructionRa_14", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_14", eval_source: "stage8.input.stage7.InstructionRa_14", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_14" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_15", oracle: "InstructionRa_15", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_15", eval_source: "stage8.input.stage7.InstructionRa_15", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_15" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_16", oracle: "InstructionRa_16", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_16", eval_source: "stage8.input.stage7.InstructionRa_16", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_16" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_17", oracle: "InstructionRa_17", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_17", eval_source: "stage8.input.stage7.InstructionRa_17", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_17" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_18", oracle: "InstructionRa_18", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_18", eval_source: "stage8.input.stage7.InstructionRa_18", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_18" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_19", oracle: "InstructionRa_19", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_19", eval_source: "stage8.input.stage7.InstructionRa_19", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_19" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_20", oracle: "InstructionRa_20", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_20", eval_source: "stage8.input.stage7.InstructionRa_20", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_20" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_21", oracle: "InstructionRa_21", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_21", eval_source: "stage8.input.stage7.InstructionRa_21", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_21" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_22", oracle: "InstructionRa_22", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_22", eval_source: "stage8.input.stage7.InstructionRa_22", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_22" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_23", oracle: "InstructionRa_23", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_23", eval_source: "stage8.input.stage7.InstructionRa_23", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_23" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_24", oracle: "InstructionRa_24", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_24", eval_source: "stage8.input.stage7.InstructionRa_24", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_24" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_25", oracle: "InstructionRa_25", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_25", eval_source: "stage8.input.stage7.InstructionRa_25", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_25" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_26", oracle: "InstructionRa_26", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_26", eval_source: "stage8.input.stage7.InstructionRa_26", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_26" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_27", oracle: "InstructionRa_27", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_27", eval_source: "stage8.input.stage7.InstructionRa_27", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_27" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_28", oracle: "InstructionRa_28", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_28", eval_source: "stage8.input.stage7.InstructionRa_28", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_28" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_29", oracle: "InstructionRa_29", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_29", eval_source: "stage8.input.stage7.InstructionRa_29", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_29" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_30", oracle: "InstructionRa_30", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_30", eval_source: "stage8.input.stage7.InstructionRa_30", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_30" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.InstructionRa_31", oracle: "InstructionRa_31", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.InstructionRa_31", eval_source: "stage8.input.stage7.InstructionRa_31", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.InstructionRa_31" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_0", oracle: "BytecodeRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_0", eval_source: "stage8.input.stage7.BytecodeRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_1", oracle: "BytecodeRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_1", eval_source: "stage8.input.stage7.BytecodeRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.BytecodeRa_2", oracle: "BytecodeRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.BytecodeRa_2", eval_source: "stage8.input.stage7.BytecodeRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.BytecodeRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_0", oracle: "RamRa_0", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_0", eval_source: "stage8.input.stage7.RamRa_0", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_0" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_1", oracle: "RamRa_1", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_1", eval_source: "stage8.input.stage7.RamRa_1", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_1" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_2", oracle: "RamRa_2", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_2", eval_source: "stage8.input.stage7.RamRa_2", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_2" }, + Stage8OpeningClaimPlan { symbol: "stage8.evaluation.opening.RamRa_3", oracle: "RamRa_3", family: "jolt.main_witness_polys", domain: "jolt.main_witness_commit_domain", point_arity: 20, point_source: "stage8.input.stage7.RamRa_3", eval_source: "stage8.input.stage7.RamRa_3", source_stage: "stage7", source_claim: "stage7.hamming_weight_claim_reduction.eval.RamRa_3" }, +]; + +pub const STAGE8_OPENING_BATCH_ORDERED_CLAIMS: &[&str] = &["stage8.evaluation.opening.RamInc", "stage8.evaluation.opening.RdInc", "stage8.evaluation.opening.InstructionRa_0", "stage8.evaluation.opening.InstructionRa_1", "stage8.evaluation.opening.InstructionRa_2", "stage8.evaluation.opening.InstructionRa_3", "stage8.evaluation.opening.InstructionRa_4", "stage8.evaluation.opening.InstructionRa_5", "stage8.evaluation.opening.InstructionRa_6", "stage8.evaluation.opening.InstructionRa_7", "stage8.evaluation.opening.InstructionRa_8", "stage8.evaluation.opening.InstructionRa_9", "stage8.evaluation.opening.InstructionRa_10", "stage8.evaluation.opening.InstructionRa_11", "stage8.evaluation.opening.InstructionRa_12", "stage8.evaluation.opening.InstructionRa_13", "stage8.evaluation.opening.InstructionRa_14", "stage8.evaluation.opening.InstructionRa_15", "stage8.evaluation.opening.InstructionRa_16", "stage8.evaluation.opening.InstructionRa_17", "stage8.evaluation.opening.InstructionRa_18", "stage8.evaluation.opening.InstructionRa_19", "stage8.evaluation.opening.InstructionRa_20", "stage8.evaluation.opening.InstructionRa_21", "stage8.evaluation.opening.InstructionRa_22", "stage8.evaluation.opening.InstructionRa_23", "stage8.evaluation.opening.InstructionRa_24", "stage8.evaluation.opening.InstructionRa_25", "stage8.evaluation.opening.InstructionRa_26", "stage8.evaluation.opening.InstructionRa_27", "stage8.evaluation.opening.InstructionRa_28", "stage8.evaluation.opening.InstructionRa_29", "stage8.evaluation.opening.InstructionRa_30", "stage8.evaluation.opening.InstructionRa_31", "stage8.evaluation.opening.BytecodeRa_0", "stage8.evaluation.opening.BytecodeRa_1", "stage8.evaluation.opening.BytecodeRa_2", "stage8.evaluation.opening.RamRa_0", "stage8.evaluation.opening.RamRa_1", "stage8.evaluation.opening.RamRa_2", "stage8.evaluation.opening.RamRa_3"]; + +pub const STAGE8_OPENING_BATCH: Stage8OpeningBatchPlan = Stage8OpeningBatchPlan { symbol: "stage8.evaluation.openings", proof_slot: "stage8.evaluation", policy: "jolt_stage8_joint_rlc", count: 41, ordered_claims: STAGE8_OPENING_BATCH_ORDERED_CLAIMS }; + +pub const STAGE8_PCS_PROOF: Stage8PcsProofPlan = Stage8PcsProofPlan { symbol: "stage8.evaluation.proof", mode: "verify", pcs: "dory", proof_slot: "stage8.evaluation", transcript_label: "rlc_claims", batch: "stage8.evaluation.openings" }; + +pub const STAGE8_PROGRAM: Stage8EvaluationProgramPlan = Stage8EvaluationProgramPlan { + role: "verifier", + function: "jolt.stage8", + params: STAGE8_PARAMS, + evaluation_point_source: STAGE8_EVALUATION_POINT_SOURCE, + opening_inputs: STAGE8_OPENING_INPUTS, + opening_claims: STAGE8_OPENING_CLAIMS, + opening_batch: STAGE8_OPENING_BATCH, + pcs_proof: STAGE8_PCS_PROOF, +}; diff --git a/crates/jolt-verifier/src/verifier.rs b/crates/jolt-verifier/src/verifier.rs new file mode 100644 index 0000000000..1518cd618c --- /dev/null +++ b/crates/jolt-verifier/src/verifier.rs @@ -0,0 +1,493 @@ +use std::collections::BTreeMap; + +use jolt_dory::{DoryCommitment, DoryProof, DoryScheme, DoryVerifierSetup}; +use jolt_field::Fr; +use jolt_openings::{AdditivelyHomomorphic, CommitmentScheme, OpeningsError}; +use jolt_poly::EqPolynomial; +use jolt_transcript::{AppendToTranscript, LabelWithCount, Transcript}; + +use crate::stages::{commitment as commitment_stage, stage1_outer as stage1_outer_stage, stage2 as stage2_stage, stage3 as stage3_stage, stage4 as stage4_stage, stage5 as stage5_stage, stage6 as stage6_stage, stage7 as stage7_stage, stage8 as stage8_stage}; + +pub type JoltNamedEval = crate::stages::common::StageNamedEval; +pub type JoltSumcheckOutput = crate::stages::common::StageSumcheckOutput; +pub type JoltStageProof = crate::stages::common::StageProof; + +#[derive(Clone, Debug)] +pub struct JoltProof { + pub commitments: Vec>, + pub stage1_outer: JoltStageProof, + pub stage2: JoltStageProof, + pub stage3: JoltStageProof, + pub stage4: JoltStageProof, + pub stage5: JoltStageProof, + pub stage6: JoltStageProof, + pub stage7: JoltStageProof, + pub evaluation: Option, +} + +pub type JoltStage2RamAccess = crate::stages::stage2::Stage2RamAccess; +pub type JoltStage2RamOutputLayout = crate::stages::stage2::Stage2RamOutputLayout; +pub type JoltStage2RamData<'a> = crate::stages::stage2::Stage2RamData<'a>; +pub type JoltStageChallengeVector = crate::stages::common::StageChallengeVector; +pub type JoltStageExecutionArtifacts = crate::stages::common::StageExecutionArtifacts; +pub type JoltStageOpeningInputValue = crate::stages::common::StageOpeningInputValue; + +#[derive(Clone, Debug)] +pub struct JoltEvaluationProof { + pub joint_opening_proof: DoryProof, +} + +#[derive(Clone, Copy)] +pub struct JoltVerifierInputs<'a> { + pub stage2_openings: &'a [stage2_stage::Stage2OpeningInputValue], + pub stage2_ram: Option<&'a stage2_stage::Stage2RamData<'a>>, + pub stage3_openings: &'a [stage3_stage::Stage3OpeningInputValue], + pub stage4_openings: &'a [stage4_stage::Stage4OpeningInputValue], + pub stage5_openings: &'a [stage5_stage::Stage5OpeningInputValue], + pub stage6_openings: &'a [stage6_stage::Stage6OpeningInputValue], + pub stage6_data: Option<&'a stage6_stage::Stage6VerifierData>, + pub stage7_openings: &'a [stage7_stage::Stage7OpeningInputValue], + pub evaluation_setup: Option<&'a DoryVerifierSetup>, +} + +#[derive(Clone, Copy, Debug)] +pub struct JoltVerifierPrograms { + pub commitment: &'static commitment_stage::CommitmentVerifierProgramPlan, + pub stage1_outer: &'static stage1_outer_stage::Stage1VerifierProgramPlan, + pub stage2: &'static stage2_stage::Stage2VerifierProgramPlan, + pub stage3: &'static stage3_stage::Stage3VerifierProgramPlan, + pub stage4: &'static stage4_stage::Stage4VerifierProgramPlan, + pub stage5: &'static stage5_stage::Stage5VerifierProgramPlan, + pub stage6: &'static stage6_stage::Stage6VerifierProgramPlan, + pub stage7: &'static stage7_stage::Stage7VerifierProgramPlan, + pub stage8: &'static stage8_stage::Stage8EvaluationProgramPlan, +} + +pub fn default_verifier_programs() -> JoltVerifierPrograms { + JoltVerifierPrograms { + commitment: &commitment_stage::COMMITMENT_PROGRAM, + stage1_outer: &stage1_outer_stage::STAGE1_PROGRAM, + stage2: &stage2_stage::STAGE2_PROGRAM, + stage3: &stage3_stage::STAGE3_PROGRAM, + stage4: &stage4_stage::STAGE4_PROGRAM, + stage5: &stage5_stage::STAGE5_PROGRAM, + stage6: &stage6_stage::STAGE6_PROGRAM, + stage7: &stage7_stage::STAGE7_PROGRAM, + stage8: &stage8_stage::STAGE8_PROGRAM, + } +} + +#[derive(Clone, Debug)] +pub struct JoltVerificationArtifacts { + pub commitment: commitment_stage::CommitmentArtifacts, + pub stage1_outer: stage1_outer_stage::Stage1ExecutionArtifacts, + pub stage2: stage2_stage::Stage2ExecutionArtifacts, + pub stage3: stage3_stage::Stage3ExecutionArtifacts, + pub stage4: stage4_stage::Stage4ExecutionArtifacts, + pub stage5: stage5_stage::Stage5ExecutionArtifacts, + pub stage6: stage6_stage::Stage6ExecutionArtifacts, + pub stage7: stage7_stage::Stage7ExecutionArtifacts, +} + +#[derive(Debug)] +pub enum JoltVerifyError { + Commitment(commitment_stage::CommitmentPhaseError), + Stage1Outer(stage1_outer_stage::VerifyStage1Error), + Stage2(stage2_stage::VerifyStage2Error), + Stage3(stage3_stage::VerifyStage3Error), + Stage4(stage4_stage::VerifyStage4Error), + Stage5(stage5_stage::VerifyStage5Error), + Stage6(stage6_stage::VerifyStage6Error), + Stage7(stage7_stage::VerifyStage7Error), + Evaluation(JoltEvaluationProofError), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum JoltVerifierTarget { + ThroughStage5, + ThroughStage6, + ThroughStage7, + Full, +} + +impl JoltVerifierTarget { + fn verifies_stage6(self) -> bool { matches!(self, Self::ThroughStage6 | Self::ThroughStage7 | Self::Full) } + fn verifies_stage7(self) -> bool { matches!(self, Self::ThroughStage7 | Self::Full) } + fn verifies_evaluation(self) -> bool { matches!(self, Self::Full) } + fn allows_optional_evaluation(self) -> bool { matches!(self, Self::ThroughStage7 | Self::Full) } +} + +#[derive(Debug)] +pub enum JoltEvaluationProofError { + MissingProof, + MissingVerifierSetup, + MissingStageEval { stage: &'static str, eval: &'static str }, + MissingStage7RaEval, + MissingStage7EvaluationPoint, + MissingCommitment { oracle: &'static str }, + InvalidPointLength { + artifact: &'static str, + expected: usize, + actual: usize, + }, + Opening(OpeningsError), +} + +macro_rules! define_jolt_verify_error_from { + ($module:ident, $error_ty:ident, $variant:ident) => { + impl From<$module::$error_ty> for JoltVerifyError { + fn from(error: $module::$error_ty) -> Self { + Self::$variant(error) + } + } + }; +} + +define_jolt_verify_error_from!(commitment_stage, CommitmentPhaseError, Commitment); +define_jolt_verify_error_from!(stage1_outer_stage, VerifyStage1Error, Stage1Outer); +define_jolt_verify_error_from!(stage2_stage, VerifyStage2Error, Stage2); +define_jolt_verify_error_from!(stage3_stage, VerifyStage3Error, Stage3); +define_jolt_verify_error_from!(stage4_stage, VerifyStage4Error, Stage4); +define_jolt_verify_error_from!(stage5_stage, VerifyStage5Error, Stage5); +define_jolt_verify_error_from!(stage6_stage, VerifyStage6Error, Stage6); +define_jolt_verify_error_from!(stage7_stage, VerifyStage7Error, Stage7); + +impl From for JoltVerifyError { + fn from(error: JoltEvaluationProofError) -> Self { + Self::Evaluation(error) + } +} + +impl From for JoltEvaluationProofError { + fn from(error: OpeningsError) -> Self { + Self::Opening(error) + } +} + +pub fn verify_jolt>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, transcript: &mut T) -> Result { + verify_jolt_with_programs(proof, inputs, default_verifier_programs(), transcript) +} + +pub fn verify_jolt_prefix>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, transcript: &mut T) -> Result { verify_jolt_prefix_with_programs(proof, inputs, default_verifier_programs(), transcript) } + +pub fn verify_jolt_through_stage5>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, transcript: &mut T) -> Result { verify_jolt_through_stage5_with_programs(proof, inputs, default_verifier_programs(), transcript) } + +pub fn verify_jolt_through_stage6>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, transcript: &mut T) -> Result { verify_jolt_through_stage6_with_programs(proof, inputs, default_verifier_programs(), transcript) } + +pub fn verify_jolt_through_stage7>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, transcript: &mut T) -> Result { verify_jolt_through_stage7_with_programs(proof, inputs, default_verifier_programs(), transcript) } + +pub fn verify_jolt_with_programs>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T) -> Result { + verify_jolt_with_programs_inner(proof, inputs, programs, transcript, JoltVerifierTarget::Full) +} + +pub fn verify_jolt_through_stage5_with_programs>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T) -> Result { verify_jolt_with_programs_inner(proof, inputs, programs, transcript, JoltVerifierTarget::ThroughStage5) } + +pub fn verify_jolt_through_stage6_with_programs>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T) -> Result { verify_jolt_with_programs_inner(proof, inputs, programs, transcript, JoltVerifierTarget::ThroughStage6) } + +pub fn verify_jolt_through_stage7_with_programs>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T) -> Result { verify_jolt_with_programs_inner(proof, inputs, programs, transcript, JoltVerifierTarget::ThroughStage7) } + +pub fn verify_jolt_prefix_with_programs>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T) -> Result { verify_jolt_through_stage7_with_programs(proof, inputs, programs, transcript) } + +fn verify_jolt_with_programs_inner>(proof: &JoltProof, inputs: JoltVerifierInputs<'_>, programs: JoltVerifierPrograms, transcript: &mut T, target: JoltVerifierTarget) -> Result { + let _verify_span = tracing::info_span!("bolt.verify").entered(); + let commitment = commitment_stage::verify_commitment_phase_with_program(programs.commitment, &proof.commitments, transcript)?; + let stage1_outer = stage1_outer_stage::verify_stage1_outer_with_program(programs.stage1_outer, &proof.stage1_outer, transcript)?; + let stage2 = stage2_stage::verify_stage2_with_program(programs.stage2, &proof.stage2, inputs.stage2_openings, inputs.stage2_ram, transcript)?; + let stage3 = stage3_stage::verify_stage3_with_program(programs.stage3, &proof.stage3, inputs.stage3_openings, transcript)?; + let stage4 = stage4_stage::verify_stage4_with_program(programs.stage4, &proof.stage4, inputs.stage4_openings, transcript)?; + let stage5 = stage5_stage::verify_stage5_with_program(programs.stage5, &proof.stage5, inputs.stage5_openings, transcript)?; + let stage6 = if target.verifies_stage6() { + stage6_stage::verify_stage6_with_program(programs.stage6, &proof.stage6, inputs.stage6_openings, inputs.stage6_data, transcript)? + } else { + stage6_stage::Stage6ExecutionArtifacts::default() + }; + let stage7 = if target.verifies_stage7() { + stage7_stage::verify_stage7_with_program(programs.stage7, &proof.stage7, inputs.stage7_openings, transcript)? + } else { + stage7_stage::Stage7ExecutionArtifacts::default() + }; + if target.allows_optional_evaluation() { + match (&proof.evaluation, inputs.evaluation_setup) { + (Some(evaluation), Some(setup)) => { + verify_jolt_evaluation_proof( + programs.stage8, + evaluation, + &commitment, + &proof.stage6, + &proof.stage7, + inputs.stage7_openings, + setup, + transcript, + )?; + } + (Some(_), None) => return Err(JoltEvaluationProofError::MissingVerifierSetup.into()), + (None, Some(_)) => return Err(JoltEvaluationProofError::MissingProof.into()), + (None, None) if target.verifies_evaluation() => return Err(JoltEvaluationProofError::MissingProof.into()), + (None, None) => {} + } + } + + Ok(JoltVerificationArtifacts { + commitment, + stage1_outer, + stage2, + stage3, + stage4, + stage5, + stage6, + stage7, + }) +} + +impl<'a> JoltVerifierInputs<'a> { + pub fn through_stage5(mut self) -> Self { self.stage6_openings = &[]; self.stage7_openings = &[]; self.evaluation_setup = None; self } + pub fn through_stage6(mut self) -> Self { self.stage7_openings = &[]; self.evaluation_setup = None; self } + pub fn through_stage7(mut self) -> Self { self.evaluation_setup = None; self } + pub fn full(mut self, evaluation_setup: &'a DoryVerifierSetup) -> Self { self.evaluation_setup = Some(evaluation_setup); self } +} + +pub type JoltStage6BytecodeEntry = crate::stages::stage6::Stage6BytecodeEntry; +pub type JoltStage6BytecodeReadRafData = crate::stages::stage6::Stage6BytecodeReadRafData; +pub type JoltStage6VerifierData = crate::stages::stage6::Stage6VerifierData; + +#[expect( + clippy::too_many_arguments, + reason = "generated verifier entry point follows the Jolt proof artifact boundary" +)] +pub fn verify_jolt_evaluation_proof( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + proof: &JoltEvaluationProof, + commitments: &commitment_stage::CommitmentArtifacts, + stage6: &JoltStageProof, + stage7: &JoltStageProof, + stage7_openings: &[stage7_stage::Stage7OpeningInputValue], + verifier_setup: &DoryVerifierSetup, + transcript: &mut T, +) -> Result<(), JoltEvaluationProofError> +where + T: Transcript, +{ + let _state_span = tracing::info_span!("bolt.verify.evaluation_state").entered(); + let state = + evaluation_proof_state(program, commitments, stage6, stage7, stage7_openings, transcript)?; + drop(_state_span); + let _dory_verify_span = tracing::info_span!("bolt.verify.dory_verify").entered(); + ::verify( + &state.joint_commitment, + &state.opening_point, + state.joint_claim, + &proof.joint_opening_proof, + verifier_setup, + transcript, + )?; + drop(_dory_verify_span); + let _bind_span = tracing::info_span!("bolt.verify.bind_opening_inputs").entered(); + ::bind_opening_inputs( + transcript, + &state.opening_point, + &state.joint_claim, + ); + drop(_bind_span); + Ok(()) +} + +struct EvaluationProofState { + opening_point: Vec, + joint_claim: Fr, + joint_commitment: DoryCommitment, +} + +struct EvaluationClaim { + oracle: &'static str, + value: Fr, +} + +fn evaluation_proof_state( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + commitments: &commitment_stage::CommitmentArtifacts, + stage6: &JoltStageProof, + stage7: &JoltStageProof, + stage7_openings: &[stage7_stage::Stage7OpeningInputValue], + transcript: &mut T, +) -> Result +where + T: Transcript, +{ + let (sumcheck_address_point, stage7_values) = stage7_claim_values(program, stage7)?; + let address_point = reverse_point(&sumcheck_address_point); + let opening_point = stage7_evaluation_opening_point(program, &address_point, stage7_openings)?; + let lagrange_factor = EqPolynomial::::zero_selector(&address_point); + let claims = evaluation_claims(program, stage6, &stage7_values, lagrange_factor)?; + + append_rlc_claims(transcript, &claims); + let gamma_powers = gamma_powers(transcript, claims.len()); + let joint_claim = claims + .iter() + .zip(&gamma_powers) + .map(|(claim, gamma)| claim.value * *gamma) + .sum(); + let joint_commitment = joint_commitment(commitments, &claims, &gamma_powers)?; + + Ok(EvaluationProofState { + opening_point, + joint_claim, + joint_commitment, + }) +} + +fn stage_eval( + proof: &JoltStageProof, + stage: &'static str, + eval_name: &'static str, +) -> Result { + for output in &proof.sumchecks { + if let Some(eval) = output.evals.iter().find(|eval| eval.name == eval_name) { + return Ok(eval.value); + } + } + Err(JoltEvaluationProofError::MissingStageEval { + stage, + eval: eval_name, + }) +} + +fn evaluation_claims( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + stage6: &JoltStageProof, + stage7_values: &BTreeMap<&'static str, Fr>, + lagrange_factor: Fr, +) -> Result, JoltEvaluationProofError> { + let mut claims = Vec::with_capacity(program.opening_claims.len()); + for plan in program.opening_claims { + let value = match plan.source_stage { + "stage6" => stage_eval(stage6, plan.source_stage, plan.source_claim)? * lagrange_factor, + "stage7" => *stage7_values.get(plan.source_claim).ok_or( + JoltEvaluationProofError::MissingStageEval { + stage: plan.source_stage, + eval: plan.source_claim, + }, + )?, + _ => { + return Err(JoltEvaluationProofError::MissingStageEval { + stage: plan.source_stage, + eval: plan.source_claim, + }); + } + }; + claims.push(EvaluationClaim { + oracle: plan.oracle, + value, + }); + } + Ok(claims) +} + +fn stage7_claim_values( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + proof: &JoltStageProof, +) -> Result<(Vec, BTreeMap<&'static str, Fr>), JoltEvaluationProofError> { + let stage7_plans = program + .opening_claims + .iter() + .filter(|plan| plan.source_stage == "stage7") + .collect::>(); + for output in &proof.sumchecks { + let mut values = BTreeMap::new(); + for plan in &stage7_plans { + if let Some(eval) = output.evals.iter().find(|eval| eval.name == plan.source_claim) { + let _ = values.insert(plan.source_claim, eval.value); + } + } + if values.len() == stage7_plans.len() { + return Ok((output.point.clone(), values)); + } + } + Err(JoltEvaluationProofError::MissingStage7RaEval) +} + +fn reverse_point(point: &[Fr]) -> Vec { + point.iter().rev().copied().collect() +} + +fn stage7_evaluation_opening_point( + program: &'static stage8_stage::Stage8EvaluationProgramPlan, + address_point: &[Fr], + stage7_openings: &[stage7_stage::Stage7OpeningInputValue], +) -> Result, JoltEvaluationProofError> { + let cycle_source_symbol = program.evaluation_point_source.source_claim; + let cycle_source = stage7_openings + .iter() + .find(|input| input.symbol == cycle_source_symbol) + .ok_or(JoltEvaluationProofError::MissingStage7EvaluationPoint)?; + if cycle_source.point.len() < address_point.len() { + return Err(JoltEvaluationProofError::InvalidPointLength { + artifact: cycle_source_symbol, + expected: address_point.len(), + actual: cycle_source.point.len(), + }); + } + let mut point = Vec::with_capacity(cycle_source.point.len()); + point.extend_from_slice(address_point); + point.extend_from_slice(&cycle_source.point[address_point.len()..]); + Ok(point) +} + +fn append_rlc_claims(transcript: &mut T, claims: &[EvaluationClaim]) +where + T: Transcript, +{ + transcript.append(&LabelWithCount(b"rlc_claims", claims.len() as u64)); + for claim in claims { + claim.value.append_to_transcript(transcript); + } +} + +fn gamma_powers(transcript: &mut T, count: usize) -> Vec +where + T: Transcript, +{ + let gamma = transcript.challenge(); + let mut powers = Vec::with_capacity(count); + let mut power = Fr::from_u64(1); + for _ in 0..count { + powers.push(power); + power *= gamma; + } + powers +} + +fn joint_commitment( + commitments: &commitment_stage::CommitmentArtifacts, + claims: &[EvaluationClaim], + gamma_powers: &[Fr], +) -> Result { + let mut coefficients = BTreeMap::<&'static str, Fr>::new(); + for (claim, gamma) in claims.iter().zip(gamma_powers) { + let coefficient = coefficients.entry(claim.oracle).or_insert(Fr::from_u64(0)); + *coefficient += *gamma; + } + let mut commitment_values = Vec::with_capacity(coefficients.len()); + let mut scalars = Vec::with_capacity(coefficients.len()); + for (oracle, coefficient) in coefficients { + commitment_values.push(commitment_for_oracle(commitments, oracle)?); + scalars.push(coefficient); + } + Ok(::combine( + &commitment_values, + &scalars, + )) +} + +fn commitment_for_oracle( + commitments: &commitment_stage::CommitmentArtifacts, + oracle: &'static str, +) -> Result { + for (record, commitment) in commitments.records.iter().zip(&commitments.commitments) { + if record.oracle == oracle { + return commitment + .clone() + .ok_or(JoltEvaluationProofError::MissingCommitment { oracle }); + } + } + Err(JoltEvaluationProofError::MissingCommitment { oracle }) +} diff --git a/crates/jolt-witness/src/lib.rs b/crates/jolt-witness/src/lib.rs index 2e4dda0488..ff99b21feb 100644 --- a/crates/jolt-witness/src/lib.rs +++ b/crates/jolt-witness/src/lib.rs @@ -822,7 +822,7 @@ fn stage6_opening_point<'a, F: Field>( #[cfg(test)] mod tests { use super::*; - use jolt_field::{Fr, FromPrimitiveInt}; + use jolt_field::Fr; fn fr(value: u64) -> Fr { Fr::from_u64(value) diff --git a/jolt-eval/src/invariant/field_mul_scalar.rs b/jolt-eval/src/invariant/field_mul_scalar.rs index ed461f1828..a9a8aa00d5 100644 --- a/jolt-eval/src/invariant/field_mul_scalar.rs +++ b/jolt-eval/src/invariant/field_mul_scalar.rs @@ -1,6 +1,6 @@ use arbitrary::{Arbitrary, Unstructured}; use jolt_field::arkworks::bn254::Fr; -use jolt_field::{FromPrimitiveInt, MulPrimitiveInt}; +use jolt_field::MulPrimitiveInt; use crate::invariant::{CheckError, Invariant, InvariantViolation};