From 4f272f041ce54a49a01265b7ebda85525a5502a4 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 17:59:15 +0100 Subject: [PATCH 001/108] Mark PCS fixed windows Permanent in verifier memory planner What: Change the memory lifetime of the four PCS fixed windows (rot_points, x1_powers, q_com, q_eval_set) in VerifierMemoryLayout::new from MemoryLifetime::Phase(MemoryPhase::PcsFixed) to MemoryLifetime::Permanent, and remove the now-unused MemoryPhase::PcsFixed enum variant. Why: These windows are not transient scratch. They are written during PCS preparation and then read across several *later* phases: x1_powers feeds both the rolled q_eval fold (PcsQEvalSourceTable) and the fused final MSM (PcsFinalMsm), while rot_points/q_eval_set feed the f_eval interpolation. Because MemoryLifetime::intersects treats two distinct Phase values as never co-live, tagging these long-lived windows with their own phase made MemoryMap::validate() blind to any overlap between them and the PCS scratch that consumes them. The planner's central non-overlap invariant therefore silently did not cover these windows. They were safe in practice only because their fixed theta-relative addresses (words 52-201) happen to sit below the commitment region while all consuming scratch is allocated above it, a property of the hard-coded address map rather than something the validator guaranteed. How: Nothing ever reuses these byte ranges, so the correct lifetime is Permanent, which forces validate() to reject any future overlap against them. With the four registrations switched over, MemoryPhase::PcsFixed has no remaining users and is deleted. An explanatory comment records the lifetime invariant at the allocation site. No address, size, or rendered output changes; all 28 layout unit tests and the full crate build pass. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/layout/memory.rs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 55bc5acb2..4d8164d05 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -132,8 +132,6 @@ pub(crate) enum MemoryPhase { LagrangeBatchInvert, /// Compact quotient VM temps and stack. QuotientVm, - /// Historical fixed PCS windows rooted at `ROT_POINTS_MPTR`. - PcsFixed, /// Source-address table used by the rolled q_eval fold. PcsQEvalSourceTable, /// Optional trace-only q_com MSM materialization. @@ -695,29 +693,41 @@ impl VerifierMemoryLayout { + meta.num_lookups + meta.num_trashcans; let committed_g1s = non_quotient_g1s + meta.num_quotients; + // The rot_points / x1_powers / q_com / q_eval_set windows are NOT + // transient scratch even though they sit in the theta scratch band. + // They are written during PCS preparation and then read across several + // *later* phases: `x1_powers` feeds both the rolled q_eval fold + // (`PcsQEvalSourceTable`) and the fused final MSM (`PcsFinalMsm`), + // while `rot_points`/`q_eval_set` feed the f_eval interpolation. Because + // `MemoryLifetime::intersects` treats two different `Phase`s as never + // co-live, tagging these as a dedicated phase would make + // `validate()` blind to any overlap between them and the PCS scratch + // that consumes them. Nothing ever reuses these byte ranges, so they + // are `Permanent`: the planner must guarantee they never overlap any + // other live region. let rot_points_mptr = Ptr::memory(arena.alloc_fixed( "rot_points", at_theta(theta_windows.rot_points_word), config.pcs.rot_points_words * WORD_BYTES, - MemoryLifetime::Phase(MemoryPhase::PcsFixed), + MemoryLifetime::Permanent, )); let x1_powers_mptr = Ptr::memory(arena.alloc_fixed( "x1_powers", at_theta(theta_windows.x1_powers_word), config.pcs.x1_powers_words * WORD_BYTES, - MemoryLifetime::Phase(MemoryPhase::PcsFixed), + MemoryLifetime::Permanent, )); let q_com_mptr = Ptr::memory(arena.alloc_fixed( "q_com_fixed_window", at_theta(theta_windows.q_com_word), config.pcs.q_com_words * WORD_BYTES, - MemoryLifetime::Phase(MemoryPhase::PcsFixed), + MemoryLifetime::Permanent, )); let q_eval_set_mptr = Ptr::memory(arena.alloc_fixed( "q_eval_set", at_theta(theta_windows.q_eval_set_word), config.pcs.q_eval_set_words * WORD_BYTES, - MemoryLifetime::Phase(MemoryPhase::PcsFixed), + MemoryLifetime::Permanent, )); let q_eval_cptr_mptr = Ptr::memory(arena.alloc_fixed( "q_eval_cptr_slot", From bb6f46331fd41bb33312d04429f42218615f1c1e Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 18:21:55 +0100 Subject: [PATCH 002/108] Model selector accumulator phase span What: add an inclusive phase-span memory lifetime and tag selector_accumulators as live from QuotientVm through PcsFinalMsm. Why: selector accumulators are written during quotient evaluation and read by later PCS phases, so a single PcsFinalMsm phase let validation miss unsafe overlaps. How: teach MemoryLifetime::intersects about phase spans, apply the span to selector_accumulators, and cover the behavior with memory-layout regression tests. --- .../src/lowering/layout/memory.rs | 76 ++++++++++++++++++- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 4d8164d05..68955229d 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -11,7 +11,7 @@ //! historical addresses in the generated verifier, gives each range a name and //! lifetime, and rejects accidental overlap when two live ranges can coexist. //! Intentional scratch reuse is modeled by assigning the same byte range to -//! disjoint `MemoryPhase`s. +//! disjoint `MemoryPhase`s or non-overlapping phase spans. //! //! This is not a packing allocator yet. The first version is deliberately //! conservative: it names the old layout, validates it, and centralizes all @@ -160,6 +160,11 @@ pub(crate) enum MemoryLifetime { /// Region is live only during the named phase. Regions in different phases /// may reuse the same byte range. Phase(MemoryPhase), + /// Region is written in one phase and read through a later phase. + PhaseSpan { + start: MemoryPhase, + end: MemoryPhase, + }, } impl MemoryLifetime { @@ -168,6 +173,20 @@ impl MemoryLifetime { match (self, other) { (Self::Permanent, _) | (_, Self::Permanent) => true, (Self::Phase(lhs), Self::Phase(rhs)) => lhs == rhs, + (Self::Phase(phase), Self::PhaseSpan { start, end }) + | (Self::PhaseSpan { start, end }, Self::Phase(phase)) => { + start <= phase && phase <= end + } + ( + Self::PhaseSpan { + start: lhs_start, + end: lhs_end, + }, + Self::PhaseSpan { + start: rhs_start, + end: rhs_end, + }, + ) => lhs_start <= rhs_end && rhs_start <= lhs_end, } } } @@ -479,7 +498,7 @@ pub(crate) struct VerifierMemoryLayout { pub(crate) trashcan_comms_mptr_base: Ptr, pub(crate) quotient_limb_comms_mptr_base: Ptr, /// First byte after all decompressed proof commitments. Selector - /// accumulators are live here during final linearization/final MSM. + /// accumulators are written by quotient evaluation and read by PCS MSMs. pub(crate) selector_acc_mptr: usize, /// Reuses selector-accumulator bytes during the earlier Lagrange batch /// inversion phase. @@ -779,7 +798,10 @@ impl VerifierMemoryLayout { comms_mptr_base.value().as_usize(), commitments_len, selector_len, - MemoryLifetime::Phase(MemoryPhase::PcsFinalMsm), + MemoryLifetime::PhaseSpan { + start: MemoryPhase::QuotientVm, + end: MemoryPhase::PcsFinalMsm, + }, ); let batch_invert_scratch_mptr = { let mut scratch = arena.scratch_allocator(selector_acc_mptr); @@ -1111,6 +1133,25 @@ mod tests { map.validate().expect("disjoint scratch lifetimes"); } + #[test] + fn phase_spans_cover_each_phase_in_their_range() { + let lifetime = MemoryLifetime::PhaseSpan { + start: MemoryPhase::QuotientVm, + end: MemoryPhase::PcsFinalMsm, + }; + + for phase in [ + MemoryPhase::QuotientVm, + MemoryPhase::PcsQEvalSourceTable, + MemoryPhase::PcsQComTrace, + MemoryPhase::PcsFinalMsm, + ] { + assert!(lifetime.intersects(&MemoryLifetime::Phase(phase))); + } + assert!(!lifetime.intersects(&MemoryLifetime::Phase(MemoryPhase::LagrangeBatchInvert))); + assert!(!lifetime.intersects(&MemoryLifetime::Phase(MemoryPhase::PcsPairing))); + } + #[test] fn unaligned_regions_fail() { let mut map = MemoryMap::default(); @@ -1423,6 +1464,35 @@ mod tests { assert_eq!(region.len, 4 * G1_MSM_PAIR_BYTES); } + #[test] + fn selector_accumulators_are_live_from_quotient_to_final_msm() { + let meta = ConstraintSystemMeta { + num_simple_selectors: 1, + ..ConstraintSystemMeta::default() + }; + let vk = synthetic_vk(); + let layout = VerifierMemoryLayout::new( + &meta, + &vk, + Ptr::memory(0x1000), + VerifierMemoryLayoutConfig::default(), + ); + let selector = layout + .map + .region("selector_accumulators") + .expect("selector accumulators registered"); + + assert_eq!( + selector.lifetime, + MemoryLifetime::PhaseSpan { + start: MemoryPhase::QuotientVm, + end: MemoryPhase::PcsFinalMsm, + } + ); + assert_eq!(layout.batch_invert_scratch_mptr, layout.selector_acc_mptr); + layout.validate().expect("earlier batch inversion may reuse selector bytes"); + } + #[test] fn trace_log_word_is_registered_after_scratch_regions() { let meta = ConstraintSystemMeta { From 4352a7116214f8816a3e8d4b7bd1c39ac6bea7dc Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 18:22:51 +0100 Subject: [PATCH 003/108] Use pairing batch hash size constant What: size the accumulator pairing batch region with PAIRING_BATCH_HASH_BYTES. Why: the old expression only matched the hash frame because current G2 and G1 encodings have a coincidental ratio. How: import the named accumulator hash-frame constant and keep the existing memory-region alias pointed at it. --- .../src/lowering/layout/memory.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 68955229d..25584983a 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -21,13 +21,13 @@ use std::collections::BTreeMap; pub(crate) use crate::lowering::layout::{ - ACC_MSM_MIN_SCRATCH_BYTES, G1ADD_INPUT_BYTES, G1_BYTES, G1_MSM_PAIR_BYTES, G1_WORDS, - LOW_MEMORY_SCRATCH_START, MODEXP_FRAME_BYTES, MODEXP_SCRATCH_BYTES, - PAIRING_STATIC_WORKING_WORDS, PAIRING_TWO_PAIR_BYTES, PCS_PAIRING_SCRATCH_START, - PCS_STATIC_WORKING_WORDS, QUOTIENT_RETURN_BUFFER_START, SOLIDITY_FREE_MEMORY_POINTER_SLOT, - SOLIDITY_RESERVED_MEMORY_BYTES, SOLIDITY_SCRATCH_SPACE_BYTES, SOLIDITY_ZERO_SLOT, - TRANSCRIPT_BUFFER_START, VERIFIER_RETURN_BUFFER_START, VK_CONSTRUCTOR_PAYLOAD_START, - WORD_BYTES, + accumulator::PAIRING_BATCH_HASH_BYTES, ACC_MSM_MIN_SCRATCH_BYTES, G1ADD_INPUT_BYTES, G1_BYTES, + G1_MSM_PAIR_BYTES, G1_WORDS, LOW_MEMORY_SCRATCH_START, MODEXP_FRAME_BYTES, + MODEXP_SCRATCH_BYTES, PAIRING_STATIC_WORKING_WORDS, PAIRING_TWO_PAIR_BYTES, + PCS_PAIRING_SCRATCH_START, PCS_STATIC_WORKING_WORDS, QUOTIENT_RETURN_BUFFER_START, + SOLIDITY_FREE_MEMORY_POINTER_SLOT, SOLIDITY_RESERVED_MEMORY_BYTES, + SOLIDITY_SCRATCH_SPACE_BYTES, SOLIDITY_ZERO_SLOT, TRANSCRIPT_BUFFER_START, + VERIFIER_RETURN_BUFFER_START, VK_CONSTRUCTOR_PAYLOAD_START, WORD_BYTES, }; use crate::lowering::{ encoding::{ConstraintSystemMeta, Ptr}, @@ -39,8 +39,7 @@ use crate::lowering::{ /// The template starts this frame at `0x100`, writes a one-word domain tag, /// then four G1 points: KZG rhs/lhs and accumulator rhs/lhs. The last copy ends /// at `0x320`, so the registered range is `[0x100, 0x320)`. -const ACCUMULATOR_PAIRING_BATCH_BYTES: usize = - PAIRING_TWO_PAIR_BYTES - G1ADD_INPUT_BYTES + WORD_BYTES; +const ACCUMULATOR_PAIRING_BATCH_BYTES: usize = PAIRING_BATCH_HASH_BYTES; // Fixed word offsets from `THETA_MPTR`. // From bafd8d7f1cf2d677a9cf35eedff44108cd4c3436 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 18:24:02 +0100 Subject: [PATCH 004/108] Account theta windows in trace scratch bound What: include rot_points, x1_powers, q_com, q_eval_set, and q_eval_cptr ends when placing trace_u256_log_word. Why: the trace scratch bound should stay correct if theta-window caps move beyond today's g1_identity guard. How: add each theta-window end to the max-bound list and cover the placement with an oversized-window regression test. --- .../src/lowering/layout/memory.rs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 25584983a..437311cb4 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -875,6 +875,11 @@ impl VerifierMemoryLayout { vk_start + vk.len(), challenge_start + meta.challenge_indices.len() * WORD_BYTES, theta_start + theta_windows.rot_points_word * WORD_BYTES, + rot_points_mptr.value().as_usize() + config.pcs.rot_points_words * WORD_BYTES, + x1_powers_mptr.value().as_usize() + config.pcs.x1_powers_words * WORD_BYTES, + q_com_mptr.value().as_usize() + config.pcs.q_com_words * WORD_BYTES, + q_eval_set_mptr.value().as_usize() + config.pcs.q_eval_set_words * WORD_BYTES, + q_eval_cptr_mptr.value().as_usize() + WORD_BYTES, g1_identity_mptr.value().as_usize() + G1_BYTES, reversed_evals_mptr.value().as_usize() + meta.num_evals * WORD_BYTES, comms_mptr_base.value().as_usize() + commitments_len, @@ -1522,6 +1527,52 @@ mod tests { layout.validate().expect("trace log word must not overlap"); } + #[test] + fn trace_log_word_accounts_for_theta_window_region_ends() { + let meta = ConstraintSystemMeta::default(); + let vk = synthetic_vk(); + let window_words = 4096; + let config = VerifierMemoryLayoutConfig { + pcs: PcsMemoryRequirements { + rot_points_words: window_words, + x1_powers_words: window_words, + q_com_words: window_words, + q_eval_set_words: window_words, + ..PcsMemoryRequirements::default() + }, + ..VerifierMemoryLayoutConfig::default() + }; + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + + for (name, end) in [ + ( + "rot_points", + layout.rot_points_mptr.value().as_usize() + window_words * WORD_BYTES, + ), + ( + "x1_powers", + layout.x1_powers_mptr.value().as_usize() + window_words * WORD_BYTES, + ), + ( + "q_com_fixed_window", + layout.q_com_mptr.value().as_usize() + window_words * WORD_BYTES, + ), + ( + "q_eval_set", + layout.q_eval_set_mptr.value().as_usize() + window_words * WORD_BYTES, + ), + ( + "q_eval_cptr_slot", + layout.q_eval_cptr_mptr.value().as_usize() + WORD_BYTES, + ), + ] { + assert!( + layout.trace_u256_mptr >= end, + "trace log word should be after {name}" + ); + } + } + #[test] fn batch_invert_scratch_region_tracks_instance_shape() { let meta = ConstraintSystemMeta { From de3bd7ea4fce8490578a0c5361d3e58f53a58054 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 18:32:35 +0100 Subject: [PATCH 005/108] Reserve fused add-product constants early What: reserve constant slots for product-add fused opcodes before emitting the base expression. Why: emitting the base can add enough constants to push the product scalar past the u8 slot checked earlier, causing codegen to panic. How: insert the fused product scalar with const_slot before base emission and add a regression with 256 base constants followed by a fused mem*mem*const add. --- .../src/lowering/quotient_numerator/vm/mod.rs | 12 +++++++ .../solidity-verifier/src/lowering/tests.rs | 35 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index affd899a2..babf24f0e 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -1593,6 +1593,7 @@ impl QuotientProgramBuilder { return false; }; + self.reserve_product_add_consts(product); self.emit_expr(base); self.emit_product_add(product); true @@ -1641,6 +1642,17 @@ impl QuotientProgramBuilder { } } + /// Reserve coefficient slots before another expression can grow the table. + fn reserve_product_add_consts(&mut self, product: QuotientProductAdd) { + match product { + QuotientProductAdd::MemMemConstU8 { scalar, .. } + | QuotientProductAdd::ConstU8Mem { scalar, .. } => { + self.const_slot(scalar); + } + QuotientProductAdd::MemMem { .. } => {} + } + } + /// Emit one fused add-mul accumulator operation. fn emit_product_add(&mut self, product: QuotientProductAdd) { match product { diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index d3ea64048..b55384bbd 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -2439,6 +2439,41 @@ fn quotient_vm_pow5_rejects_near_miss_product_shapes() { ); } +#[test] +fn quotient_vm_add_product_reserves_scalar_before_base_constants() { + let lhs = 0xaa0; + let rhs = 0xac0; + let mut values = HashMap::new(); + values.insert(lhs, Fq::from(149u64)); + values.insert(rhs, Fq::from(157u64)); + + let mut base = QuotientExpr::Const(U256::ZERO); + for value in 1..=255u64 { + base = quotient_add_expr(base, QuotientExpr::Const(U256::from(value))); + } + let product = quotient_mul_expr( + quotient_mul_expr( + QuotientExpr::Mem(QuotientMem::Literal(lhs)), + QuotientExpr::Mem(QuotientMem::Literal(rhs)), + ), + QuotientExpr::Const(U256::from(300u64)), + ); + let expr = quotient_add_expr(base, product); + + let expected = eval_quotient_expr_for_test(&expr, &values); + let mut builder = QuotientProgramBuilder::default(); + builder.emit_expr(&expr); + + assert!( + builder.bytes.contains(&Q_OP_ADD_MUL_MEM_MEM_CONST_U8), + "product should stay on the fused add-mul path" + ); + assert_eq!( + eval_quotient_vm_for_test(&builder.bytes, &builder.consts, &values), + expected + ); +} + #[test] fn quotient_vm_limb_subshape_matches_direct_expr_eval() { let mut values = HashMap::new(); From 7b498f75fd2f1c4fa65c452206763b3661a3a3b9 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 18:34:49 +0100 Subject: [PATCH 006/108] Reserve limb decomposition constants early What: reserve limb-shape coefficient slots before emitting the extracted residue expression. Why: residue emission can add enough constants to invalidate the earlier u8-slot preflight and panic in emit_limb_shape. How: call const_slot for each recognized limb coefficient before residue emission and add a regression with a LIN7 subshape plus 256 residue constants. --- .../src/lowering/quotient_numerator/vm/mod.rs | 17 +++++++ .../solidity-verifier/src/lowering/tests.rs | 47 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index babf24f0e..eac35dfbd 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -1363,6 +1363,7 @@ impl QuotientProgramBuilder { if !self.limb_shape_has_u8_const_slots(&shape) { return false; } + self.reserve_limb_shape_consts(&shape); self.emit_expr(&residue); self.emit_limb_shape(shape); self.op_binary(Q_OP_ADD); @@ -1428,6 +1429,22 @@ impl QuotientProgramBuilder { self.peek_u8_const_slots(&coeffs).is_some() } + /// Reserve coefficient slots before residue emission can grow the table. + fn reserve_limb_shape_consts(&mut self, shape: &QuotientLimbShape) { + match shape { + QuotientLimbShape::Lin7 { terms } | QuotientLimbShape::Bilin7Row { terms, .. } => { + for (coeff, _) in terms { + self.const_slot(*coeff); + } + } + QuotientLimbShape::Bilin7Pairwise { coeffs, .. } => { + for coeff in coeffs { + self.const_slot(*coeff); + } + } + } + } + /// Emit the byte-level representation of a pre-validated limb shape. fn emit_limb_shape(&mut self, shape: QuotientLimbShape) { match shape { diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index b55384bbd..dfa3c71ed 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -2521,6 +2521,53 @@ fn quotient_vm_limb_subshape_matches_direct_expr_eval() { ); } +#[test] +fn quotient_vm_limb_decomposition_reserves_shape_coeffs_before_residue() { + let mut values = HashMap::new(); + let mut expr = QuotientExpr::Const(U256::ZERO); + + for i in 0..7u32 { + let ptr = 0xb00 + i * WORD_BYTES as u32; + values.insert(ptr, Fq::from(151 + i as u64)); + expr = quotient_add_expr( + expr, + quotient_scale_expr( + Fq::from(19 + i as u64), + QuotientExpr::Mem(QuotientMem::Literal(ptr)), + ), + ); + } + + for i in 0..256u32 { + let ptr = 0x2000 + i * 0x40; + values.insert(ptr, Fq::from(401 + i as u64)); + expr = quotient_add_expr( + expr, + quotient_scale_expr( + Fq::from(1000 + i as u64), + QuotientExpr::Mem(QuotientMem::Literal(ptr)), + ), + ); + } + + let expected = eval_quotient_expr_for_test(&expr, &values); + let mut builder = QuotientProgramBuilder::with_limb_vm_ops(true); + builder.emit_expr(&expr); + + assert!( + builder.consts.len() > u8::MAX as usize, + "residue should grow the constant table past u8" + ); + assert!( + builder.bytes.contains(&Q_OP_LIN7), + "larger affine sums should still extract LIN7 subshapes" + ); + assert_eq!( + eval_quotient_vm_for_test(&builder.bytes, &builder.consts, &values), + expected + ); +} + #[test] fn quotient_vm_limb_subshape_inside_conditional_product_matches_direct_expr_eval() { let mut values = HashMap::new(); From 5d7afe9b9f94f8ca7882341bb2c8cba423a1e2e6 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 28 Jun 2026 19:04:48 +0100 Subject: [PATCH 007/108] Guard rotated public instance queries in Solidity codegen What: add regression coverage that the Solidity generator rejects rotated non-committed instance queries, and clarify the code comments around the single local public-instance evaluation. How: keep the existing constructor-time Rotation::cur guard, document why non-committed instance_eval is a single word, add a debug assertion in quotient lowering, and replace two trace/layout magic literals with named constants. Why: the lowering path only reconstructs the non-committed public-input polynomial at the current rotation, so rotated instance queries must fail at codegen time instead of producing a verifier that disagrees with native Midfall. --- proofs/solidity-verifier/src/builder/api.rs | 3 + .../src/lowering/encoding/mod.rs | 9 +-- .../solidity-verifier/src/lowering/kzg/mod.rs | 6 +- .../src/lowering/layout/mod.rs | 2 + .../src/lowering/quotient_numerator/vm/mod.rs | 7 +++ .../solidity-verifier/src/lowering/tests.rs | 59 ++++++++++++++++++- 6 files changed, 78 insertions(+), 8 deletions(-) diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 497a59f81..52ae43f99 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -49,6 +49,9 @@ impl<'a> SolidityGenerator<'a> { if let Some(acc_encoding) = config.accumulator { acc_encoding.validate_for_num_instances(config.num_instances)?; } + // Non-committed instance evaluations are reconstructed once from the + // public-input polynomial at the current rotation. Reject rotated + // instance queries until that path is keyed by `(column, rotation)`. if let Some((column, rotation)) = vk .cs() .instance_queries() diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 5ddf9bcdf..6fe3e0b22 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -249,7 +249,9 @@ pub(crate) struct Data { /// User challenge words. pub(crate) challenges: Vec, - /// Locally-computed non-committed instance evaluation. + /// Locally-computed non-committed instance evaluation at `Rotation::cur()`. + /// `SolidityGenerator::try_new` rejects rotated instance queries, so this + /// stays a single word instead of a `(column, rotation)` map. pub(crate) instance_eval: Word, /// Per-(committed-instance-column, rotation): the calldata word for /// that committed instance evaluation. Empty when @@ -273,8 +275,7 @@ pub(crate) struct Data { pub(crate) computed_quotient_eval: Word, /// Word offset (in the verifier's static memory map) of the start of - /// the per-category EIP-2537-padded commitment region. See the - /// `KNOWN BUG` block in `Data::new` for the layout convention. + /// the per-category EIP-2537-padded commitment region. pub(crate) comms_mptr_base: Ptr, /// Memory base of the decoded-evals buffer (Optimisation H3). The /// transcript-side `evaluations` loop spills the decoded scalar value to @@ -795,7 +796,7 @@ impl EcPoint { /// Infinite iterator of consecutive padded G1 points. pub(crate) fn range(base: impl Into) -> impl Iterator { let base = base.into().base; - (0..).map(move |idx| EcPoint::new(base + 4 * idx)) + (0..).map(move |idx| EcPoint::new(base + G1_WORDS * idx)) } /// Return the pointer to the first word. diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 0fb662402..b49763380 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -1189,7 +1189,7 @@ pub(crate) fn computations( )); lines.push(format!( "trace_point({}, {trace_scratch:#x})", - 40000 + set_idx + trace::PCS_Q_COM_BASE + set_idx as u64 )); continue; } @@ -1272,11 +1272,11 @@ pub(crate) fn computations( )); lines.push(format!( "if iszero(q_com_trace_ok_{set_idx}) {{ mstore(TRACE_U256_MPTR, {}) revert(TRACE_U256_MPTR, {WORD_BYTES:#x}) }}", - 40000 + set_idx + trace::PCS_Q_COM_BASE + set_idx as u64 )); lines.push(format!( "trace_point({}, {trace_scratch:#x})", - 40000 + set_idx + trace::PCS_Q_COM_BASE + set_idx as u64 )); } blocks.push(lines); diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 1c885ea67..8612fc319 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -591,6 +591,7 @@ pub(crate) mod trace { pub(crate) const PROOF_COMMIT_BASE: usize = 10_000; // Proof G1 reads. pub(crate) const PROOF_EVAL_BASE: usize = 20_000; // Proof scalar eval reads. pub(crate) const QUOTIENT_IDENTITY_BASE: u64 = 30_000; // Quotient identities. + pub(crate) const PCS_Q_COM_BASE: u64 = 40_000; // PCS q_com points. pub(crate) const PCS_SERIALIZED_POINT_SET_BASE: u64 = 41_000; // PCS point sets. pub(crate) const SELECTOR_FOLD_BASE: usize = 60_000; // Selector accumulators. } @@ -680,6 +681,7 @@ mod tests { assert_eq!(trace::PROOF_COMMIT_BASE, 10_000); assert_eq!(trace::PROOF_EVAL_BASE, 20_000); assert_eq!(trace::QUOTIENT_IDENTITY_BASE, 30_000); + assert_eq!(trace::PCS_Q_COM_BASE, 40_000); assert_eq!(trace::PCS_SERIALIZED_POINT_SET_BASE, 41_000); assert_eq!(trace::SELECTOR_FOLD_BASE, 60_000); } diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index eac35dfbd..426633b7a 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2435,6 +2435,13 @@ impl QuotientExpressionEnv for DataQuotientExpressionEnv<'_> { .expect("committed instance eval present"), ) } else { + // The builder rejects rotated instance queries before lowering, so + // the direct public-input column always uses the one local + // Lagrange evaluation computed for `Rotation::cur()`. + debug_assert_eq!( + rotation, 0, + "rotated public instance query reached lowering" + ); word_to_quotient_expr(self.data.instance_eval) } } diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index dfa3c71ed..81982270a 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -291,6 +291,60 @@ fn lowering_plan_test_vk() -> ( (params, vk) } +#[derive(Clone, Debug)] +struct RotatedPublicInstanceCircuit; + +impl Circuit for RotatedPublicInstanceCircuit { + type Config = (); + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let advice = meta.advice_column(); + let committed_instance = meta.instance_column(); + let public_instance = meta.instance_column(); + + meta.create_gate("rotated public instance", |meta| { + let advice = meta.query_advice(advice, Rotation::cur()); + let committed = meta.query_instance(committed_instance, Rotation::cur()); + let public_next = meta.query_instance(public_instance, Rotation::next()); + Constraints::without_selector(vec![( + "rotated public instance", + advice + committed + public_next, + )]) + }); + } + + fn synthesize( + &self, + _config: Self::Config, + _layouter: impl Layouter, + ) -> Result<(), PlonkError> { + Ok(()) + } +} + +#[test] +fn generator_rejects_rotated_non_committed_instance_queries() { + let mut rng = ChaCha8Rng::seed_from_u64(8); + let params = ParamsKZG::::unsafe_setup(4, &mut rng); + let circuit = RotatedPublicInstanceCircuit; + let vk = keygen_vk_with_k::, _>(¶ms, &circuit, 4) + .expect("test circuit VK should build"); + + assert!(matches!( + SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(1, 1)), + Err(GeneratorError::RotatedInstanceQuery { + column: 1, + rotation: 1, + }) + )); +} + #[test] fn scalar_le_to_be_word_reverses_exactly_one_word() { let mut le = [0u8; 32]; @@ -1432,7 +1486,10 @@ fn differential_trace_hooks_cover_expected_categories() { "serialized PCS point sets", "trace::PCS_SERIALIZED_POINT_SET_BASE + set_idx as u64", ), - ("PCS q_com commitments", "40000 + set_idx"), + ( + "PCS q_com commitments", + "trace::PCS_Q_COM_BASE + set_idx as u64", + ), ] { assert!( pcs_source.contains(needle), From a01b1ea16afe88fec71040e834e65efec9d5c91b Mon Sep 17 00:00:00 2001 From: Julian Date: Fri, 17 Jul 2026 22:05:25 +0100 Subject: [PATCH 008/108] Fix transcript buffer sizing and quotient VM const-table overflow Size the pre-first-squeeze transcript run from every advice phase up to and including the first challenge-bearing phase, not just phase 0, so the valid "advice in an early phase, challenge in a later phase" shape no longer under-sizes the buffer and overruns VK_MPTR. In the quotient VM limb-decomposition and product-add peepholes, re-check that fused opcode coefficients still fit their one-byte constant slots after intervening residue/base emission, falling back to generic ops instead of panicking in the u8::try_from(...).expect(...). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/lowering/abi/proof.rs | 71 +++++++++++++++-- .../src/lowering/quotient_numerator/vm/mod.rs | 77 ++++++++++++++++--- .../solidity-verifier/src/lowering/tests.rs | 40 ++++++++++ proofs/solidity-verifier/src/lowering/vk.rs | 11 ++- 4 files changed, 182 insertions(+), 17 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/abi/proof.rs b/proofs/solidity-verifier/src/lowering/abi/proof.rs index 3e085d1cb..82c32efb8 100644 --- a/proofs/solidity-verifier/src/lowering/abi/proof.rs +++ b/proofs/solidity-verifier/src/lowering/abi/proof.rs @@ -307,18 +307,44 @@ pub(crate) struct TranscriptBufferLayout { impl TranscriptBufferLayout { /// Derive transcript-buffer bounds from proof calldata shape and instances. - pub(crate) fn from_proof_layout(proof: &ProofCalldataLayout, num_instances: usize) -> Self { + /// + /// `phase_challenge_counts[i]` is the number of Fiat-Shamir challenges the + /// native schedule squeezes for user phase `i` (i.e. `num_user_challenges`). + /// It selects which advice commitments share the pre-first-squeeze run: a + /// phase that owns no challenge does not trigger a squeeze, so its advices + /// accumulate into the same run as the following phase's. An empty slice is + /// treated as "no phase owns a challenge", which sums every advice phase as + /// a safe upper bound. + pub(crate) fn from_proof_layout( + proof: &ProofCalldataLayout, + num_instances: usize, + phase_challenge_counts: &[usize], + ) -> Self { let word_absorb = layout::transcript::WORD_ABSORB_BYTES; let g1_absorb = layout::transcript::G1_ABSORB_BYTES; let squeeze_cushion = layout::transcript::POST_SQUEEZE_CUSHION_WORDS * WORD_BYTES; - let phase_1_advices = - proof.advice_phases.first().map(|section| section.item_count).unwrap_or(0); + // Advices absorbed before the first challenge squeeze. The native + // verifier squeezes a challenge only for phases that own one, and the + // unconditional `theta` squeeze follows every user phase, so all advice + // phases up to and INCLUDING the first challenge-bearing phase are + // absorbed into a single streaming run before the first squeeze. + // Counting only the first phase under-sized the buffer for the valid + // "advice in an early phase, challenge in a later phase" shape + // (e.g. a SecondPhase RLC column) and let the G1 absorb loop overrun + // `VK_MPTR`; see `plan_allows_challenge_phase_beyond_advice_phases`. + let mut pre_squeeze_advices = 0usize; + for (phase, section) in proof.advice_phases.iter().enumerate() { + pre_squeeze_advices += section.item_count; + if phase_challenge_counts.get(phase).copied().unwrap_or(0) > 0 { + break; + } + } let initial_run_bytes = word_absorb + g1_absorb + word_absorb + num_instances * word_absorb - + phase_1_advices * g1_absorb + + pre_squeeze_advices * g1_absorb + squeeze_cushion; let eval_run_bytes = proof.quotient_limbs.byte_len @@ -464,7 +490,7 @@ mod tests { fn transcript_layout_matches_current_conservative_bound() { let protocol = protocol_shape(vec![64], vec![], 0, 0, 2); let proof = ProofCalldataLayout::from_protocol(&protocol, 0, 10, 3); - let transcript = TranscriptBufferLayout::from_proof_layout(&proof, 0); + let transcript = TranscriptBufferLayout::from_proof_layout(&proof, 0, &[1]); let first_phase_run = 32 + 128 + 32 + 64 * 128 + 32 * 32; assert!(transcript.words * WORD_BYTES >= first_phase_run); @@ -473,4 +499,39 @@ mod tests { 2 * G1_BYTES + (10 + 3) * WORD_BYTES + 32 * WORD_BYTES ); } + + #[test] + fn transcript_layout_covers_multi_phase_advice_before_first_squeeze() { + // Valid shape (see `plan_allows_challenge_phase_beyond_advice_phases`): + // phase 0 has advice but no challenge, so both phases' advices land in + // the same pre-first-squeeze run alongside a large public-input block. + let protocol = protocol_shape(vec![1, 9], vec![], 0, 0, 1); + let proof = ProofCalldataLayout::from_protocol(&protocol, 0, 12, 2); + let num_instances = 86; + let transcript = + TranscriptBufferLayout::from_proof_layout(&proof, num_instances, &[0, 1]); + + let word = layout::transcript::WORD_ABSORB_BYTES; + let g1 = layout::transcript::G1_ABSORB_BYTES; + let cushion = layout::transcript::POST_SQUEEZE_CUSHION_WORDS * WORD_BYTES; + + // Bytes actually absorbed before the first squeeze: vk_digest, + // committed_pi, num_instances length word, instance words, then BOTH + // phases' advices (phase 0 owns no challenge). + let true_initial_run = + word + g1 + word + num_instances * word + (1 + 9) * g1; + assert!( + transcript.words * WORD_BYTES >= true_initial_run, + "reserved {} bytes < true pre-squeeze run {}", + transcript.words * WORD_BYTES, + true_initial_run + ); + assert_eq!(transcript.initial_run_bytes, true_initial_run + cushion); + + // The old bound counted only phase 0's advice and therefore under-sized + // the buffer below the true run — confirm the fix was load-bearing. + let phase0_only_run = word + g1 + word + num_instances * word + 1 * g1; + assert!(phase0_only_run < true_initial_run); + assert!(phase0_only_run + cushion < true_initial_run); + } } diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 426633b7a..aeb060bee 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -1357,7 +1357,7 @@ impl QuotientProgramBuilder { if !self.limb_vm_ops { return false; } - let Some((shape, residue)) = quotient_limb_subshape(expr) else { + let Some((shape, residue, matched)) = quotient_limb_subshape(expr) else { return false; }; if !self.limb_shape_has_u8_const_slots(&shape) { @@ -1365,11 +1365,39 @@ impl QuotientProgramBuilder { } self.reserve_limb_shape_consts(&shape); self.emit_expr(&residue); - self.emit_limb_shape(shape); + // `limb_shape_has_u8_const_slots` was checked against the constant table + // before `emit_expr(&residue)`. Emitting the residue can insert new + // constants and push a shape coefficient past a one-byte constant slot, + // which would panic in `emit_limb_shape`'s `u8::try_from(...).expect(...)`. + // Re-check against the post-residue table: keep the fused limb opcode + // only while every coefficient still fits, otherwise emit the matched + // terms through the generic path (their sum equals the shape's value). + if self.limb_shape_has_u8_const_slots(&shape) { + self.emit_limb_shape(shape); + } else { + self.emit_affine_terms(&matched); + } self.op_binary(Q_OP_ADD); true } + /// Emit `Σ terms[i]` with generic stack ops, leaving one value on the stack. + /// + /// Each entry is one recognized affine/bilinear term (a scaled memory load + /// or product), so emitting it cannot re-enter the limb-decomposition + /// peephole, and its coefficients use `emit_const`'s u16-capable slots. This + /// is the panic-free fallback for a recognized limb shape whose coefficients + /// no longer fit one-byte constant slots after intervening emission. The + /// slice is always non-empty (a recognized subshape uses at least one term). + fn emit_affine_terms(&mut self, terms: &[QuotientExpr]) { + for (idx, term) in terms.iter().enumerate() { + self.emit_expr(term); + if idx > 0 { + self.op_binary(Q_OP_ADD); + } + } + } + /// Try to replace a full expression with one limb-specialized opcode. /// /// The const-slot preflight is part of the ABI justification: limb opcodes @@ -1606,16 +1634,39 @@ impl QuotientProgramBuilder { if !collect_product_leaves(product, &mut leaves) { return false; } - let Some(product) = self.product_add_macro(&leaves) else { + let Some(fused) = self.product_add_macro(&leaves) else { return false; }; - self.reserve_product_add_consts(product); + self.reserve_product_add_consts(fused); self.emit_expr(base); - self.emit_product_add(product); + // `product_add_macro` checked the fused scalar against the constant + // table as it stood *before* `emit_expr(base)`. Emitting `base` can + // insert new constants and push that scalar past a one-byte constant + // slot, which would panic in `emit_product_add`'s + // `u8::try_from(...).expect(...)`. Re-check against the post-`base` + // table: keep the fused opcode only while the scalar still fits, + // otherwise add the product through the generic path (its lone scalar + // goes through `emit_const`, which falls back to a u16 slot). + if self.product_add_fits_u8_slot(&fused) { + self.emit_product_add(fused); + } else { + self.emit_expr(product); + self.op_binary(Q_OP_ADD); + } true } + /// Whether the fused product-add scalar (if any) still lands in a one-byte + /// constant slot given the current constant table. + fn product_add_fits_u8_slot(&self, product: &QuotientProductAdd) -> bool { + match *product { + QuotientProductAdd::MemMemConstU8 { scalar, .. } + | QuotientProductAdd::ConstU8Mem { scalar, .. } => self.const_fits_u8_slot(scalar), + QuotientProductAdd::MemMem { .. } => true, + } + } + /// Recognize product leaves that can be encoded as one fused add-mul op. /// /// The fused forms require literal `u16` memory pointers and, where a @@ -2690,7 +2741,7 @@ pub(crate) fn quotient_pow5_base(expr: &QuotientExpr) -> Option<&QuotientExpr> { /// Extract one limb shape from a larger affine sum and return the residue. pub(crate) fn quotient_limb_subshape( expr: &QuotientExpr, -) -> Option<(QuotientLimbShape, QuotientExpr)> { +) -> Option<(QuotientLimbShape, QuotientExpr, Vec)> { let mut terms = Vec::new(); let mut constant = Fq::ZERO; if !collect_quotient_affine_terms(expr, Fq::ONE, &mut terms, &mut constant) { @@ -2708,15 +2759,23 @@ pub(crate) fn quotient_limb_subshape( return None; } + // Split the affine terms into the residue (unused terms plus the constant) + // and the matched terms that reconstruct `shape` as a plain sum. The matched + // terms are the panic-free fallback for `emit_limb_shape`: their sum equals + // the fused opcode's value, but each is a single scaled load/product that + // uses u16-capable constant loads. let used = used.into_iter().collect::>(); let mut residue = QuotientExpr::Const(quotient_fq_to_u256(constant)); + let mut matched = Vec::with_capacity(used.len()); for (idx, (coeff, term)) in terms.into_iter().enumerate() { + let scaled = quotient_scaled_term_expr(coeff, (*term).clone()); if used.contains(&idx) { - continue; + matched.push(scaled); + } else { + residue = quotient_sum_expr(residue, scaled); } - residue = quotient_sum_expr(residue, quotient_scaled_term_expr(coeff, (*term).clone())); } - Some((shape, residue)) + Some((shape, residue, matched)) } /// Recognize a whole affine foreign-field/ECC identity that can be evaluated diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 81982270a..7d5203944 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -2445,6 +2445,46 @@ fn quotient_vm_bilin7_pairwise_matches_direct_expr_eval() { ); } +#[test] +fn quotient_vm_limb_decomposition_survives_const_table_overflow() { + // A large affine sum over consecutive limb pointers is emitted as a chain of + // LIN7 opcodes whose coefficients land in the one-byte constant table. With + // more than 256 distinct coefficients the table overflows a `u8` slot + // partway through emission. Before the fix, `emit_limb_shape`'s + // `u8::try_from(slot).expect(...)` panicked once the shape being emitted was + // preceded by enough residue constants; the decomposition path now re-checks + // the post-residue table and falls back to generic ops for the overflowing + // shape. This exercises that fallback and confirms it still evaluates the + // expression correctly. + let term_count = 300u32; + let mut values = HashMap::new(); + let mut expr = QuotientExpr::Const(U256::ZERO); + for k in 0..term_count { + let ptr = 0x1000 + k * 0x20; + values.insert(ptr, Fq::from(17 + k as u64)); + expr = quotient_add_expr( + expr, + // Coefficient `k + 2` keeps every term scaled (coeff 1 would drop the + // constant) and distinct, so the table grows one slot per term. + quotient_scale_expr(Fq::from(k as u64 + 2), QuotientExpr::Mem(QuotientMem::Literal(ptr))), + ); + } + + let expected = eval_quotient_expr_for_test(&expr, &values); + let mut builder = QuotientProgramBuilder::with_limb_vm_ops(true); + // The pre-fix builder panics inside this call for this input. + builder.emit_expr(&expr); + + assert!( + builder.consts.len() > u8::MAX as usize, + "test must overflow the one-byte constant table to exercise the fallback" + ); + assert_eq!( + eval_quotient_vm_for_test(&builder.bytes, &builder.consts, &values), + expected + ); +} + #[test] fn quotient_vm_pow5_matches_direct_expr_eval() { let ptr = 0xa20; diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index 480b68c37..44fd9e730 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -414,8 +414,9 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { // midnight-proofs verifiers the dominating run is whichever of the // following is largest: // (a) initial absorbs (vk_digest + committed_pi + num_instances - // + all instance scalars + all phase-1 advices) before the - // first user-phase challenge squeeze (`theta`), or + // + all instance scalars + every advice commitment up to and + // including the first challenge-bearing phase) before the first + // user-phase challenge squeeze (`theta` at the latest), or // (b) the evaluation block (all `num_evals` scalars) absorbed // after the `y` squeeze and before the next squeeze. // @@ -438,6 +439,10 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { meta.num_evals, meta.num_point_sets, ); - TranscriptBufferLayout::from_proof_layout(&proof_layout, num_instances) + TranscriptBufferLayout::from_proof_layout( + &proof_layout, + num_instances, + &meta.protocol.num_user_challenges, + ) } } From adc589fce1bb5e359eb5e38dd557a905c6475c7c Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:22:14 +0100 Subject: [PATCH 009/108] Bound the Lagrange batch-invert input run in the memory planner The generated Lagrange block writes num_instances + num_neg_lagranges + 1 denominator words in place starting at X_N_MPTR (theta word 26) and batch-inverts them, but the memory planner modeled only the prefix-product scratch half of that call: the input run was never registered as a region or bounded, batch_invert_scratch_bytes sized only the modexp scratch, and validate() capped just the PCS fixed windows. Nothing caps num_instances, so for large enough circuits the run silently overwrote state that is already live at Lagrange time: Q_EVAL_CPTR_MPTR (theta word 201, stored by the proof parser and read by the PCS q_eval fold) at num_instances + num_neg_lagranges >= 175, the virgin-zero G1_IDENTITY_MPTR (word 209, relied on as the committed-instance MSM base) at >= 183, and the decoded proof evaluations (word 220) at >= 194. Codegen succeeded but the deployed verifier rejected every honest proof, a silent memory-safety/completeness break. Extract batch_invert_input_words as the shared source of truth for the run size, record it on VerifierMemoryLayout, and make validate() reject any layout whose run reaches min(Q_EVAL_CPTR_WORD, G1_IDENTITY_WORD, REVERSED_EVALS_WORD), failing codegen with a clear error before any Solidity is rendered. A capacity check is used instead of an arena region because the run intentionally overlays the theta band and PCS fixed windows that are dead at Lagrange time but modeled Permanent, so registering it would produce fake overlaps; the existing benign spill into ROT_POINTS stays allowed. Add a boundary regression test covering the exact pass/fail instance counts. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/layout/memory.rs | 93 ++++++++++++++++--- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 437311cb4..632e7ac20 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -502,6 +502,9 @@ pub(crate) struct VerifierMemoryLayout { /// Reuses selector-accumulator bytes during the earlier Lagrange batch /// inversion phase. pub(crate) batch_invert_scratch_mptr: usize, + /// Number of Fr words the generated Lagrange block writes in place at + /// `X_N_MPTR` as the batch-inversion input run. + pub(crate) batch_invert_input_words: usize, /// First quotient VM temporary. Also the canonical PCS scratch base once /// selector accumulators are accounted for. pub(crate) quotient_tmp_mptr: usize, @@ -620,6 +623,7 @@ impl VerifierMemoryLayout { .max() .expect("constructor G1MSM smoke bounds are non-empty"); let batch_invert_len = batch_invert_scratch_bytes(meta, config.num_instances); + let batch_invert_input_words = batch_invert_input_words(meta, config.num_instances); let quotient_return_len = (2 + meta.num_simple_selectors) * WORD_BYTES; let mut arena = MemoryArena::default(); @@ -961,6 +965,7 @@ impl VerifierMemoryLayout { quotient_limb_comms_mptr_base, selector_acc_mptr, batch_invert_scratch_mptr, + batch_invert_input_words, quotient_tmp_mptr, quotient_stack_mptr, pcs_q_eval_source_table_mptr, @@ -1056,6 +1061,29 @@ impl VerifierMemoryLayout { )); } + // The Lagrange block writes its batch-inversion input run in place at + // `X_N_MPTR` (theta word 26). The run intentionally spills past the + // theta band into the PCS fixed windows, which are written only after + // the Lagrange phase, so it cannot be registered as a region without + // fake overlaps; it is capacity-checked here instead. The first bytes + // that are already live at Lagrange time are the q_eval calldata + // cursor (written by the proof parser), the G1 identity slot (must + // stay virgin zero memory), and the decoded proof evaluations. + let lagrange_run_end = ThetaSlot::XN.word() + self.batch_invert_input_words; + let lagrange_run_cap = windows + .q_eval_cptr_word + .min(windows.g1_identity_word) + .min(windows.reversed_evals_word); + if lagrange_run_end > lagrange_run_cap { + return Err(format!( + "Lagrange batch-inversion input run overflows live verifier memory: \ + [X_N_MPTR, X_N_MPTR + {} word(s)) ends at theta word {lagrange_run_end}, \ + but Q_EVAL_CPTR_MPTR/G1_IDENTITY_MPTR/decoded evaluations are live from \ + theta word {lagrange_run_cap}; reduce the public instance count", + self.batch_invert_input_words + )); + } + self.map.validate()?; Ok(()) @@ -1073,25 +1101,31 @@ pub(crate) fn commitment_g1_count(meta: &ConstraintSystemMeta) -> usize { + meta.num_quotients } +/// Number of Fr words the generated Lagrange block writes in place starting at +/// `X_N_MPTR` as the batch-inversion input run. +/// +/// The input range covers: +/// - num_instances public Lagrange denominators, or one fallback word when +/// there are no public instances; +/// - `abs(rotation_last)` negative-row denominators; +/// - x_n - 1. +fn batch_invert_input_words(meta: &ConstraintSystemMeta, num_instances: usize) -> usize { + if num_instances == 0 { + meta.rotation_last.unsigned_abs() as usize + 2 + } else { + num_instances + meta.rotation_last.unsigned_abs() as usize + 1 + } +} + /// Scratch size required by the batched scalar-inversion helper. fn batch_invert_scratch_bytes(meta: &ConstraintSystemMeta, num_instances: usize) -> usize { // The template calls: // batch_invert(X_N_MPTR, mptr_end + WORD_BYTES, scratch, r) // - // The input range covers: - // - num_instances public Lagrange denominators, or one fallback word when - // there are no public instances; - // - `abs(rotation_last)` negative-row denominators; - // - x_n - 1. - // // For N inputs, the batched inversion stores N-2 prefix products and then // overlays one modexp frame at the current prefix pointer. Singletons use // only the frame. - let input_words = if num_instances == 0 { - meta.rotation_last.unsigned_abs() as usize + 2 - } else { - num_instances + meta.rotation_last.unsigned_abs() as usize + 1 - }; + let input_words = batch_invert_input_words(meta, num_instances); MODEXP_FRAME_BYTES + input_words.saturating_sub(2) * WORD_BYTES } @@ -1595,4 +1629,41 @@ mod tests { MODEXP_FRAME_BYTES + (5 + 3 + 1 - 2) * WORD_BYTES ); } + + #[test] + fn lagrange_batch_invert_input_run_is_bounded_by_live_memory() { + let meta = ConstraintSystemMeta { + rotation_last: -3, + ..ConstraintSystemMeta::default() + }; + let vk = synthetic_vk(); + let windows = ThetaWindowLayout::compatibility(); + let cap_words = windows + .q_eval_cptr_word + .min(windows.g1_identity_word) + .min(windows.reversed_evals_word) + - ThetaSlot::XN.word(); + + // Largest instance count whose denominator run plus `x_n - 1` still + // fits below the q_eval calldata cursor: num + |rotation_last| + 1. + let max_instances = cap_words - 3 - 1; + let config = VerifierMemoryLayoutConfig { + num_instances: max_instances, + ..VerifierMemoryLayoutConfig::default() + }; + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + assert_eq!(layout.batch_invert_input_words, cap_words); + layout.validate().expect("run ending below Q_EVAL_CPTR_MPTR is valid"); + + let config = VerifierMemoryLayoutConfig { + num_instances: max_instances + 1, + ..VerifierMemoryLayoutConfig::default() + }; + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let err = layout.validate().unwrap_err(); + assert!( + err.contains("Lagrange batch-inversion input run"), + "unexpected validation error: {err}" + ); + } } From b24be9e2b7e74b3de120e644945af90c42554974 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:41:49 +0100 Subject: [PATCH 010/108] Reject off-curve points in EIP-2537 G1/G2 encoders g1_to_u256s and g2_to_u256s returned the all-zero EIP-2537 word array whenever coordinates() yielded None. In midnight-curves, coordinates() returns None not only for the point at infinity but for any off-curve point, and the all-zero words are exactly the EIP-2537 encoding of the identity. An off-curve/corrupted point (e.g. an s_g2 from an unchecked deserialization path) was therefore silently baked into the generated verifier as the identity: NEG_S_G2 collapsing to infinity degenerates the e(w, -s*G2) KZG pairing term, and a malformed VK commitment becomes an identity commitment (a different circuit), both with no build error. Distinguish the genuine identity (is_identity()) from an invalid point and assert on the latter, so codegen fails loudly instead of emitting a soundness-broken constant. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/encoding/mod.rs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 6fe3e0b22..9397f8f2a 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -13,6 +13,7 @@ use std::{ }; use ff::PrimeField; +use group::prime::PrimeCurveAffine; use itertools::{izip, Itertools}; use midnight_curves::{Coordinates, CurveAffine, Fq, G1Affine, G2Affine}; use midnight_proofs::plonk::{Any, Column, ConstraintSystem}; @@ -833,8 +834,18 @@ fn fp48_be_to_hi_lo(be: &[u8]) -> (U256, U256) { /// big-endian and split (hi=top 16 bytes padded into u256, lo=bottom 32 /// bytes). pub(crate) fn g1_to_u256s(ec_point: impl Borrow) -> [U256; 4] { - let Some(coords) = Option::>::from(ec_point.borrow().coordinates()) - else { + let point = ec_point.borrow(); + let Some(coords) = Option::>::from(point.coordinates()) else { + // `coordinates()` returns None for the identity *and* for any off-curve + // point. The all-zero words below are the EIP-2537 encoding of the point + // at infinity, so silently returning them for an off-curve input would + // bake an identity commitment into the verifier. Only the identity may + // take this path; anything else is a malformed/corrupted point and must + // fail codegen rather than degrade a soundness-critical constant. + assert!( + bool::from(point.is_identity()), + "refusing to EIP-2537 encode an off-curve G1 point as the identity" + ); return [U256::ZERO; 4]; }; let mut x_be = [0u8; BLS_FP_BYTES]; @@ -855,8 +866,16 @@ pub(crate) fn g1_to_u256s(ec_point: impl Borrow) -> [U256; 4] { /// in big-endian per coord. The midnight-curves convention matches: /// each `Fp` coordinate read via `to_repr()` returns LE bytes. pub(crate) fn g2_to_u256s(ec_point: impl Borrow) -> [U256; 8] { - let Some(coords) = Option::>::from(ec_point.borrow().coordinates()) - else { + let point = ec_point.borrow(); + let Some(coords) = Option::>::from(point.coordinates()) else { + // See `g1_to_u256s`: `coordinates()` also returns None for off-curve G2 + // points, whose all-zero encoding would collapse to the identity (e.g. + // a corrupted `s_g2` degenerating the `e(w, -s*G2)` pairing term). Only + // the genuine identity may be encoded as zeros. + assert!( + bool::from(point.is_identity()), + "refusing to EIP-2537 encode an off-curve G2 point as the identity" + ); return [U256::ZERO; 8]; }; From fc42518db31635f8cc9218d4014c7c43e75b1860 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:42:00 +0100 Subject: [PATCH 011/108] Validate the SRS G1 base equals the canonical generator generate_base_vk emits G1Affine::generator() as the VK header G1_BASE while taking g2/s_g2 from the deployer-supplied params, with nothing asserting params.g[0] == G. midnight-proofs' ParamsKZG accepts arbitrary g vectors, so a params file whose SRS base is c*G (c != 1) built without error. The generated verifier then computes the -v*G term of the KZG combination from G while every proof/VK commitment is over c*G, so the on-chain pairing check enforces a different (scaled) statement than the native Rust verifier: honest proofs are rejected, and accept/reject can diverge from the reference verifier, all silently at build time. g[0] is crate-private in midnight-proofs, but the commitment of the constant-1 polynomial equals g[0], and in the Lagrange basis that commitment is sum(g_lagrange). Assert sum(g_lagrange) == generator at codegen time so a mismatched SRS fails the build instead of producing a verifier that silently diverges from the reference verifier. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/vk.rs | 23 ++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index 44fd9e730..33e173465 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -6,7 +6,7 @@ //! generated verifier contracts. use ff::Field; -use group::{prime::PrimeCurveAffine, Curve}; +use group::{prime::PrimeCurveAffine, Curve, Group}; use itertools::chain; use midnight_curves::{Fq, G1Affine, G1Projective, G2Affine}; use ruint::aliases::U256; @@ -69,6 +69,27 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { // (4 / 8 u256 words respectively). We cannot read `params.g[0]` // directly (the field is crate-private in midnight-proofs), so // we use the canonical BLS12-381 generator. + // + // The generated verifier subtracts `v * G1_BASE` in the final KZG + // linearization while every commitment in the proof/VK is over the + // SRS base `g[0]`. If a deployer-supplied `params` had `g[0] != G`, + // the contract would enforce a different pairing equation than the + // native verifier (bricking honest proofs, or accepting evaluation + // claims for a scaled statement). Validate consistency at build + // time: the commitment of the constant-1 polynomial equals `g[0]`, + // and in the Lagrange basis that commitment is `sum(g_lagrange)`. + let g_lagrange = self.params.g_lagrange(); + let srs_g1_base = g_lagrange + .iter() + .copied() + .fold(G1Projective::identity(), |acc, g| acc + g) + .to_affine(); + assert_eq!( + srs_g1_base, + G1Affine::generator(), + "SRS G1 base (sum of g_lagrange) is not the canonical BLS12-381 \ + generator; the emitted G1_BASE would diverge from the commitment base" + ); let g1_pt: G1Affine = G1Affine::generator(); let g2_pt: G2Affine = self.params.g2().to_affine(); let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); From c80cbc823f1b42b38773678841600765274c66ba Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:42:10 +0100 Subject: [PATCH 012/108] Invalidate reassigned variables in the limb7 chain rewriter record_yul_const_assignment recorded 'let name := literal' bindings for limb7 coefficient recognition but ignored non-let reassignments, because yul_let_assignment returns None for 'x := ...'. A stale literal therefore survived a later runtime reassignment, so a block that binds a variable to a limb7 coefficient literal and then reassigns it to a runtime value could be falsely matched: specialize_limb7_chains would replace the chain with a q_limb7 call baking in the literal while the original code multiplied by the reassigned runtime value, silently miscompiling the quotient identity (no codegen or Yul error). This is unreachable today only because gate-identity lines are SSA, but nothing asserts that and the Evaluator already emits non-let reassignment lines on other paths. Track constants via yul_assignment (let or not) and forget any variable reassigned to a non-constant value, so a stale coefficient can never be matched. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index d77a5e504..1fee3f8c1 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -1262,15 +1262,26 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { yul_const_value(value, const_vars).as_deref() == Some(expected_coeff) } - /// Record `let name := const` bindings for later limb-chain matching. + /// Track constant variable bindings for later limb-chain matching. + /// + /// Records `name := const` (whether or not introduced with `let`), and, + /// crucially, forgets any variable that is reassigned to a non-constant + /// value. Ignoring non-`let` reassignments would leave a stale literal in + /// `const_vars`, so a later `mulmod(name, limb, r)` could be mis-recognized + /// as a fused limb7 coefficient and bake the wrong constant into the + /// generated quotient identity. fn record_yul_const_assignment(line: &str, const_vars: &mut HashMap) { - let Some((dst, rhs)) = yul_let_assignment(line) else { - return; - }; - let Some(value) = yul_const_value(&rhs, const_vars) else { + let Some(assignment) = yul_assignment(line) else { return; }; - const_vars.insert(dst, value); + match yul_const_value(&assignment.expr, const_vars) { + Some(value) => { + const_vars.insert(assignment.dst, value); + } + None => { + const_vars.remove(&assignment.dst); + } + } } /// Trace, advance, and accumulate one main quotient identity value. From 1fa3b41a86629ca84fd0afa65a9a3d4eb38429b3 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:42:19 +0100 Subject: [PATCH 013/108] Content-check embedded VK quotient program against the plan build The VK payload embeds the quotient const table and packed bytecode compiled inside generate_vk, but LoweringPlan recompiles the program from scratch and renders the interpreter (program length, opcode gating, native-callback ordering, stack sizing) from that second build. The only cross-checks were length/reservation inequalities; nothing compared the bytes actually embedded in the VK payload with the second build. Parity rested solely on compile determinism over HashMap/HashSet-backed structures, so an ordering-dependent compile could ship a pinned VK whose bytecode disagrees with the rendered interpreter, permanently rejecting every valid proof (fail-closed on-chain DoS) invisibly at codegen time. Compare vk.constants[quotient_const_offset..] and [quotient_program_offset..] word-for-word against the plan build's consts and PackedProgramCodec::encode_words(bytes) in validate_generator_invariants, failing codegen on any divergence. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/plan.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index e1682f287..b98e7290b 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -279,6 +279,37 @@ impl LoweringPlan { self.vk.quotient_program_words )); } + // The VK payload embeds the const table and packed bytecode compiled + // inside `generate_vk`, but the interpreter is rendered from this + // independently recompiled `self.quotient.build`. Length checks alone + // let a nondeterministic/order-dependent compile ship a pinned VK whose + // bytecode disagrees with the rendered VM. Compare the embedded words + // against the plan build word-for-word so any divergence fails codegen. + if let Some(const_offset) = self.vk.quotient_const_offset_words { + let build_consts = &self.quotient.build.consts; + let embedded = &self.vk.constants[const_offset..const_offset + build_consts.len()]; + if embedded.iter().map(|(_, value)| value).ne(build_consts.iter()) { + return Err( + "quotient const table embedded in the VK payload does not match the \ + plan-rebuilt const table" + .to_string(), + ); + } + } + if let Some(program_offset) = self.vk.quotient_program_offset_words { + let build_words = layout::vk_payload::PackedProgramCodec::encode_words( + &self.quotient.build.bytes, + ); + let embedded = + &self.vk.constants[program_offset..program_offset + build_words.len()]; + if embedded.iter().map(|(_, value)| value).ne(build_words.iter()) { + return Err( + "quotient program bytecode embedded in the VK payload does not match the \ + plan-rebuilt bytecode" + .to_string(), + ); + } + } if self.quotient.program.stack_mptr != self.quotient.stack_mptr { return Err(format!( "quotient stack pointer drifted: model={:#x} planned={:#x}", From 8db58be1f59bc3e1a80a69268d55d266e55a6f32 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:42:31 +0100 Subject: [PATCH 014/108] Bounds-check quotient VM const-table slots in the offline validator validate_quotient_program proved stack effects, instruction lengths, and mem-token bytes, but never checked that decoded const-table indices fall inside the emitted table. An encoder/planner regression emitting an out-of-range const slot (this class already produced one real bug, the quotient VM const-table overflow) would ship a verifier that loads an arbitrary trailing VK word as a gate coefficient, deterministically flipping accept/reject with nothing failing at build or runtime. Add validate_quotient_const_slots, which walks the finalized byte stream and bounds-checks every constant slot across all const-bearing opcodes (push/add/mul const and const_u8, the add-mul const_u8 forms and their runs, LIN7/BILIN7 rows and pairwise coeffs, and the dynamic AFFINE_SUM and MODARITH7 layouts). It runs after validate_quotient_program in QuotientProgramBuilder::finish, whose length validation guarantees the walked layout is in bounds. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/vm/mod.rs | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index aeb060bee..439f70c66 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -1210,6 +1210,8 @@ impl QuotientProgramBuilder { let bytes = compact_quotient_runs(&self.bytes); let validated_max_stack = validate_quotient_program(&bytes) .unwrap_or_else(|err| panic!("invalid finalized quotient VM program: {err}")); + validate_quotient_const_slots(&bytes, self.consts.len()) + .unwrap_or_else(|err| panic!("invalid finalized quotient VM program: {err}")); assert_eq!( validated_max_stack, self.max_stack, "quotient VM physical program stack depth diverged from builder accounting" @@ -2049,6 +2051,139 @@ pub(crate) fn validate_quotient_program(bytes: &[u8]) -> Result { Ok(max_stack) } +/// Bounds-check every constant-table slot referenced by a finalized program. +/// +/// `validate_quotient_program` proves structural and stack safety but never +/// checks that decoded const-table indices fall inside the emitted table. An +/// encoder/planner regression that emits an out-of-range slot (this class has +/// already produced one real bug) would otherwise make the deployed verifier +/// load an arbitrary trailing VK word as a gate coefficient, silently flipping +/// accept/reject. Run this after `validate_quotient_program`, whose byte-length +/// validation guarantees the layout walked here is already in bounds. +pub(crate) fn validate_quotient_const_slots(bytes: &[u8], const_len: usize) -> Result<(), String> { + let check = |slot: usize, idx: usize| -> Result<(), String> { + if slot >= const_len { + return Err(format!( + "quotient VM const slot {slot} at byte {idx} is outside the {const_len}-entry constant table" + )); + } + Ok(()) + }; + let limb_stride = 1 + QUOTIENT_VM_BYTE_U16_BYTES; + + for (idx, op, _len) in quotient_bytecode_ops(bytes) { + match op { + Q_OP_PUSH_CONST | Q_OP_ADD_CONST | Q_OP_MUL_CONST => { + check(read_u16(bytes, idx + 1) as usize, idx)?; + } + Q_OP_PUSH_CONST_U8 | Q_OP_ADD_CONST_U8 | Q_OP_MUL_CONST_U8 => { + check(bytes[idx + 1] as usize, idx)?; + } + Q_OP_ADD_MUL_CONST_U8_MEM_U16 => { + check(bytes[idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + } + Q_OP_ADD_MUL_MEM_MEM_CONST_U8 => { + check(bytes[idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + } + Q_OP_RUN_ADD_MUL_CONST_U8_MEM_U16 => { + let count = read_u16(bytes, idx + 1) as usize; + let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; + let stride = QUOTIENT_VM_BYTE_U16_BYTES + 1; + for k in 0..count { + check(bytes[base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + } + } + Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8 => { + let count = read_u16(bytes, idx + 1) as usize; + let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; + let stride = 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; + for k in 0..count { + check(bytes[base + k * stride + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + } + } + Q_OP_LIN7 => { + for k in 0..QUOTIENT_VM_LIMBS { + check(bytes[idx + 1 + k * limb_stride] as usize, idx)?; + } + } + Q_OP_BILIN7_ROW => { + let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; + for k in 0..QUOTIENT_VM_LIMBS { + check(bytes[base + k * limb_stride] as usize, idx)?; + } + } + Q_OP_BILIN7_PAIRWISE => { + let base = idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES; + for k in 0..QUOTIENT_VM_PAIRWISE_COEFFS { + check(bytes[base + k] as usize, idx)?; + } + } + Q_OP_AFFINE_SUM => { + let lin_count = read_u16(bytes, idx + 1) as usize; + let product_count = read_u16(bytes, idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES) as usize; + let mut cursor = idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES; + for _ in 0..lin_count { + check(bytes[cursor + QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + cursor += QUOTIENT_VM_BYTE_U16_BYTES + 1; + } + for _ in 0..product_count { + check(bytes[cursor + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + cursor += 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; + } + } + Q_OP_MODARITH7 => { + let mut cursor = idx + 1; + let flags = bytes[cursor]; + cursor += 1; + if flags & Q_MODARITH7_FLAG_COND != 0 { + cursor += QUOTIENT_VM_BYTE_U16_BYTES; + } + if flags & Q_MODARITH7_FLAG_CONST != 0 { + check(bytes[cursor] as usize, idx)?; + cursor += 1; + } + let lin_count = bytes[cursor] as usize; + let row_count = bytes[cursor + 1] as usize; + let pairwise_count = bytes[cursor + 2] as usize; + let mem_count = bytes[cursor + 3] as usize; + let product_count = bytes[cursor + 4] as usize; + cursor += 5; + for _ in 0..lin_count { + for _ in 0..QUOTIENT_VM_LIMBS { + check(bytes[cursor] as usize, idx)?; + cursor += limb_stride; + } + } + for _ in 0..row_count { + cursor += QUOTIENT_VM_BYTE_U16_BYTES; + for _ in 0..QUOTIENT_VM_LIMBS { + check(bytes[cursor] as usize, idx)?; + cursor += limb_stride; + } + } + for _ in 0..pairwise_count { + cursor += 2 * QUOTIENT_VM_BYTE_U16_BYTES; + for _ in 0..QUOTIENT_VM_PAIRWISE_COEFFS { + check(bytes[cursor] as usize, idx)?; + cursor += 1; + } + } + for _ in 0..mem_count { + check(bytes[cursor] as usize, idx)?; + cursor += limb_stride; + } + for _ in 0..product_count { + check(bytes[cursor] as usize, idx)?; + cursor += 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES; + } + } + _ => {} + } + } + + Ok(()) +} + /// Decode one instruction and validate token operands. fn decode_byte_quotient_instruction(bytes: &[u8], idx: usize) -> Result<(u8, usize), String> { require_quotient_bytes(bytes, idx, 1, "opcode")?; From 700af6d38ff3acd07601cdd487844511d906d6c8 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:55:52 +0100 Subject: [PATCH 015/108] Fail closed on zero KZG point sets in the PCS emitter What: make kzg::memory_requirements and kzg::computations panic instead of returning a default/empty result when the intermediate-set construction yields zero point sets. How: replace the two `if n_sets == 0 { return ... }` early returns with an assert!(n_sets != 0, ...) carrying the soundness rationale. Why: with zero point sets, computations() emits no Block 6, so PAIRING_LHS_MPTR/PAIRING_RHS_MPTR are never written. Zero-initialized EVM memory is the EIP-2537 encoding of the BLS12-381 point at infinity, so FinalPairing.yul's ec_pairing computes e(inf, G2) * e(inf, -sG2) = 1 and the verifier accepts ANY transcript-parseable proof with no cryptographic checking of the openings. This is unreachable today only because ProtocolPlan::validate requires the schedule to end with the Linearization query (n_sets >= 1); the KZG emitter is the last line of defense for the pairing check and must fail closed rather than silently emit an accept-all verifier. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/kzg/mod.rs | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index b49763380..e8fca397c 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -744,9 +744,17 @@ pub(crate) fn memory_requirements( ) -> PcsMemoryRequirements { let sets = intermediate_sets(meta, data); let n_sets = sets.point_sets.len(); - if n_sets == 0 { - return PcsMemoryRequirements::default(); - } + // Fail closed: zero point sets means the plan carries no PCS queries, which + // would size (and, in `computations`, emit) a verifier with no final + // pairing check. Since zero-initialized PAIRING_{LHS,RHS}_MPTR encode the + // point at infinity, such a verifier accepts any transcript-parseable proof. + // `ProtocolPlan::validate` guarantees at least the Linearization query, so + // this is unreachable; assert it rather than silently return a default. + assert!( + n_sets != 0, + "KZG intermediate-set construction produced zero point sets; refusing to \ + size a verifier with no PCS/pairing check (would be accept-all)" + ); let by_set = commitments_by_set(&sets, n_sets); let commitments_per_set = by_set.iter().map(Vec::len); @@ -819,9 +827,17 @@ pub(crate) fn computations( const TRUNC_MASK_128: &str = "0xffffffffffffffffffffffffffffffff"; let sets = intermediate_sets(meta, data); let n_sets = sets.point_sets.len(); - if n_sets == 0 { - return Vec::new(); - } + // Fail closed: an empty point-set list would emit a verifier with no Block 6, + // so PAIRING_{LHS,RHS}_MPTR stay zero-initialized. Zero memory is the EIP-2537 + // encoding of the BLS12-381 point at infinity, so the final pairing evaluates + // to 1 and the verifier accepts ANY proof with no cryptographic checking. + // `ProtocolPlan::validate` requires the query schedule to end with the + // Linearization query (n_sets >= 1), so reaching here is a generator bug. + assert!( + n_sets != 0, + "KZG intermediate-set construction produced zero point sets; refusing to \ + emit a verifier with no PCS/pairing check (would be accept-all)" + ); // The emitted blocks below adapt the Rust `multi_prepare` flow: // construct/sort point sets, fold q_eval vectors, interpolate at x3, From 6e14bfe13c7d0ead7e1de789cf4993ce532f498c Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 22:57:50 +0100 Subject: [PATCH 016/108] Bound the unrolled PCS rotation-point walk at codegen What: assert the rotation-point walk in kzg::computations does not unroll more than MAX_ROTATION_WALK_STEPS (4096) mulmod steps. How: compute the walk length as |max_rot| + |min_rot| and assert it against a generous cap before emitting the forward/backward omega walks. Why: the block emits one `mulmod` line per unit step across the whole rotation span, so the emitted Yul grows with rotation magnitude, not with the number of distinct rotations (which is separately capped at ROT_POINTS_CAP_WORDS=28). A legitimate circuit using a large rotation (e.g. Rotation(50_000)) would pass every existing capacity check yet emit enough code to exceed the EIP-170 24KB runtime-size limit, producing an undeployable verifier with no diagnostic. The cap fails closed with a clear message well above any realistic circuit's rotation range; the documented remedy is to roll the walk into a Yul loop. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/kzg/mod.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index e8fca397c..4462eec5d 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -887,6 +887,26 @@ pub(crate) fn computations( let max_rot = *distinct_rotations.iter().max().unwrap_or(&0); let min_rot = *distinct_rotations.iter().min().unwrap_or(&0); + // Fail closed on pathological rotation magnitudes. This block unrolls one + // `mulmod` per unit step across the entire rotation span (forward to + // max_rot, backward to min_rot), so the emitted line count scales with + // |max_rot| + |min_rot|, NOT with the (separately capped) number of + // distinct rotations. A circuit using a very large rotation would emit + // enough Yul to exceed the EIP-170 24KB runtime-code limit and produce an + // undeployable verifier with no diagnostic from our own validation. Bound + // the walk here; if this ever fires for a legitimate circuit, roll the + // walk into a Yul loop (as Block 2 does for x1 powers) rather than raising + // the cap. The cap is far above any realistic circuit's rotation range. + const MAX_ROTATION_WALK_STEPS: i64 = 4096; + let walk_steps = i64::from(max_rot).max(0) + (-i64::from(min_rot)).max(0); + assert!( + walk_steps <= MAX_ROTATION_WALK_STEPS, + "PCS rotation-point walk would unroll {walk_steps} mulmod steps \ + (max_rot={max_rot}, min_rot={min_rot}), exceeding the \ + {MAX_ROTATION_WALK_STEPS}-step cap; such a verifier would blow the \ + EIP-170 runtime code-size limit (roll the walk into a Yul loop instead)" + ); + let store_rot = |rot: i32| -> Option { distinct_rotations.iter().position(|r| *r == rot).map(|idx| { format!( From 36fc616a7537824f80b6b3f936db8637a6988ebd Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:00:57 +0100 Subject: [PATCH 017/108] Correct the KZG batch-inversion non-zero soundness comment What: rewrite the misleading soundness note above the Montgomery batch inverse in kzg::computations to state the real lbasis_j != 0 invariant and the actual failure mode. How: comment-only. Document that lbasis_j is non-zero only because distinct rotation *values* map to distinct rotation *points* (which holds because the domain order n=2^k exceeds the rotation span for every supported circuit), and that a degenerate tiny-domain circuit aliasing two rotations fails closed (a zero lbasis product makes scalar_inv revert) rather than producing a wrong f_eval. Add a TODO to thread the domain order in for a codegen-time assert. Why: the previous comment claimed lbasis_j is non-zero simply because construct_intermediate_sets de-duplicates rotations, but that de-dups i32 rotation values, not the points x*omega^rot; two distinct rotations alias when rot_i == rot_j (mod n). The comment also contradicted a sibling finding on scalar_inv: the batch path reverts on a zero product, so the true behavior is fail-closed, not a silent wrong evaluation. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/kzg/mod.rs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 4462eec5d..3b69f28e7 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -1435,11 +1435,27 @@ pub(crate) fn computations( // Soundness: requires every input to be non-zero. dx_j is // non-zero by Fiat-Shamir (x3 is uniform random; the // probability that x3 = p_j for a structured rotation point - // is ~2^-256). lbasis_j is non-zero because the points in a - // set are distinct by construction (`construct_intermediate_sets` - // de-duplicates rotations within each set). Defensive note: - // a malicious prover cannot influence either, so we don't - // need an explicit zero check. + // is ~2^-256). lbasis_j = prod_{k != j} (p_j - p_k) is non-zero + // as long as the rotation points p = x*omega^rot are pairwise + // distinct within the set. `construct_intermediate_sets` + // de-duplicates rotation *values* (i32) per set, and distinct + // values map to distinct points only because the domain order + // n = 2^k exceeds the rotation span for every supported circuit + // (rotations are bounded by the gate/lookup structure, k is + // large). A malicious prover cannot influence either value, so + // no explicit codegen zero check is added here. + // + // Note the failure mode is fail-closed, not silent: if a + // degenerate tiny-domain circuit ever aliased two rotations + // (rot_i == rot_j mod n), the corresponding p_j - p_k would be + // zero, so some lbasis_j and hence the batched product bp_{n-1} + // would be zero, and `scalar_inv` reverts on a zero input + // (AssemblyHelpers.yul). Such a verifier rejects all proofs + // rather than computing a wrong f_eval. + // + // TODO: to surface that misconfiguration at codegen time instead + // of at proof time, thread the domain order n into this emitter + // and assert every point set's rotation span is < n. // // The reference computes lagrange interpolation directly via // full polynomial construction; here we collapse the From 66c32f9526054e0f37ec5938267386a0d5cbf625 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:01:49 +0100 Subject: [PATCH 018/108] Fix inverted pairing-orientation comment in the KZG emitter What: correct the comment claiming PAIRING_LHS = pi is 'paired against G2_BASE' in kzg::computations Block 6. How: comment-only. pi (PAIRING_LHS) is actually paired against NEG_S_G2_BASE: FinalPairing.yul calls ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) with the slots swapped, and ec_pairing pairs arg0 against G2_BASE and arg1 against NEG_S_G2_BASE. The comment now states this and ties it to the KZG identity e(final_com - v*G + x3*pi, [1]_2) = e(pi, [s]_2). Why: the executed code is correct, but the contradictory comment invited a maintainer to 'un-swap' the ec_pairing call (or swap the mcopy destinations) to make code match comment, which would flip the equation to e(pi,[1]) = e(RHS,[s]) and reject all honest proofs (fail-closed completeness break). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/kzg/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 3b69f28e7..d8a447ce1 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -1760,7 +1760,12 @@ pub(crate) fn computations( lines.push("// Scale z*pi - vG before the final pairing check".to_string()); lines.push("// pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi)".to_string()); - // PAIRING_LHS = pi (paired against G2_BASE). + // PAIRING_LHS = pi. FinalPairing.yul calls + // ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) with the + // slots swapped, and ec_pairing pairs its first argument against + // G2_BASE and its second against NEG_S_G2_BASE, so pi (PAIRING_LHS) + // is paired against NEG_S_G2_BASE (the [s]_2 side), matching the KZG + // identity e(final_com - v*G + x3*pi, [1]_2) = e(pi, [s]_2). lines.push(format!("mcopy(PAIRING_LHS_MPTR, PI_MPTR, {G1_BYTES:#x})")); // tmp = (-v) * G => load G into planned scratch, scale by (r - v). From 688efdeee2896bdf35264fc738e047e9eca65a75 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:02:51 +0100 Subject: [PATCH 019/108] Document the pointer-identity KZG query-grouping invariant What: add a TODO(structural) comment in construct_intermediate_sets_impl explaining that KZG query grouping and the duplicate-query eval-consistency assert compare EcPoint/Word handles by memory pointer, not by runtime value. How: comment-only. Records that this diverges from the midnight-proofs prover (groups by polynomial identity) and verifier (groups by commitment value), that it is safe today only because SolidityGenerator supports a single committed-instance column and all consumers depend only on first-appearance order, and that with >= 2 committed-instance columns sharing G1_IDENTITY_MPTR at one rotation the assert would panic at codegen. A value-based grouping is the real fix but is structural and out of scope here. Why: the auditor flagged both a codegen DoS (assert panics for >= 2 shared committed-instance columns) and a prover/verifier grouping divergence rooted in pointer identity; the fix is structural, so the invariant is documented to prevent a future refactor from silently dropping the eval-consistency check. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/kzg/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index d8a447ce1..2a607b6d5 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -320,6 +320,23 @@ fn construct_intermediate_sets_impl(queries: &[Query]) -> IntermediateSets { // when their evals also agree; otherwise the proof claims the // same polynomial opens to two different values, which is a // protocol bug and must be rejected. + // + // TODO(structural): this dedup and the whole intermediate-set + // grouping compare EcPoint/Word handles by *memory pointer* (derived + // PartialEq), not by runtime value, whereas the midnight-proofs + // prover groups queries by polynomial identity and the verifier by + // commitment value. They agree today only because (a) + // SolidityGenerator supports a single committed-instance column (see + // validate_instance_column_shape in builder/api.rs), and (b) every + // downstream consumer depends only on first-appearance order and + // per-commitment point sets. The assert below also compares eval + // Words by pointer: with >= 2 committed-instance columns sharing + // G1_IDENTITY_MPTR at the same rotation it would panic at codegen + // (their eval Words are distinct memory handles) instead of + // collapsing them, and compute_dummy_queries would silently `skip` + // the same pair. Grouping by runtime value would lift both + // restrictions but is a structural change; the invariant is + // documented here rather than fixed. if let Some(existing_pos) = slot.1.iter().position(|pi| *pi == point_idx) { assert_eq!( slot.2[existing_pos], query.eval, From 098f6a1d542664970a976c489dc35032fc55615b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:03:45 +0100 Subject: [PATCH 020/108] Harden rotated-instance guard in the quotient VM lowerer What: promote the debug_assert_eq!(rotation, 0) in DataQuotientExpressionEnv::instance to a hard assert_eq!. How: replace debug_assert_eq! with assert_eq! and document why it must fail closed even in release builds. Why: the non-committed public-instance column is only interpolated at Rotation::cur(), so a rotated query must never reach this arm. debug_assert compiles out in release, so a rotated query slipping past the far-away constructor guard (builder/api.rs) would silently substitute instance(x) for instance(x*omega^k), generating a verifier whose quotient identity differs from the circuit (it could reject valid proofs and accept ones violating the intended constraint). A hard assert matches the fail-closed style of word_to_quotient_expr and ptr_to_quotient_mem in this file. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/vm/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 439f70c66..6ecb0fc2e 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2624,7 +2624,15 @@ impl QuotientExpressionEnv for DataQuotientExpressionEnv<'_> { // The builder rejects rotated instance queries before lowering, so // the direct public-input column always uses the one local // Lagrange evaluation computed for `Rotation::cur()`. - debug_assert_eq!( + // + // Hard assert (not debug_assert): `debug_assert` compiles out in + // release, and this is the last line of defense far from the + // constructor guard (builder/api.rs). Substituting the Rotation::cur + // eval for a rotated query would silently emit a verifier that + // evaluates the gate with instance(x) instead of instance(x*w^k), + // enforcing a different quotient identity than the circuit. Fail + // closed, matching word_to_quotient_expr / ptr_to_quotient_mem. + assert_eq!( rotation, 0, "rotated public instance query reached lowering" ); From 16f43b56ee84a6fabd7c8b9fe27e096ecfee75d7 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:04:19 +0100 Subject: [PATCH 021/108] Use checked u32 conversion for quotient VM memory pointers What: replace the two `offset as u32` casts in ptr_to_quotient_mem with u32::try_from(...).expect(...). How: convert the isize Value offset via u32::try_from, which rejects both negative and > u32::MAX offsets, dropping the now-redundant assert!(offset >= 0) guards. Why: Value::Integer/Identifier carry isize offsets, so `offset as u32` silently wraps a planner offset above u32::MAX, and the generated VM bytecode would mload a wrapped, unrelated address, producing a verifier that computes the quotient numerator from the wrong memory word with no build-time diagnostic. Every other narrowing in this file already uses a checked conversion; this was the one silent cast. Practically unreachable today (EVM gas keeps frames far below 4GiB) but now fails loudly at generation time. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/vm/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 6ecb0fc2e..c653cfb48 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2665,17 +2665,26 @@ pub(crate) fn ptr_to_quotient_mem(ptr: Ptr) -> QuotientMem { ); match ptr.value() { Value::Integer(offset) => { - assert!(offset >= 0, "negative quotient memory pointer"); - QuotientMem::Literal(offset as u32) + // Checked conversion: Value offsets are isize, so `offset as u32` + // would silently wrap for a negative or > u32::MAX offset and make + // the VM mload an unrelated address (a verifier computing the + // quotient numerator from the wrong memory word, with no build-time + // diagnostic). Fail loudly instead, like the other narrowing casts + // in this file (u16::try_from, u8::try_from). + let offset = u32::try_from(offset) + .expect("quotient memory pointer must be a non-negative offset that fits in u32"); + QuotientMem::Literal(offset) } Value::Identifier(name, offset) => { - assert!(offset >= 0, "negative quotient memory token offset"); + let offset = u32::try_from(offset).expect( + "quotient memory token offset must be a non-negative offset that fits in u32", + ); let token = quotient_mem_token_from_name(name) .unwrap_or_else(|| panic!("unsupported quotient memory token: {name}")); if offset == 0 { QuotientMem::Token(token) } else { - QuotientMem::TokenOffset(token, offset as u32) + QuotientMem::TokenOffset(token, offset) } } } From 56f20be1957387e4626d1f56d672e3b068547f1d Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:10:35 +0100 Subject: [PATCH 022/108] Validate quotient VM memory pointers are word-aligned at construction What: assert every quotient memory pointer/token-offset is 32-byte word aligned in ptr_to_quotient_mem. How: at the single QuotientMem construction choke point, assert offset % WORD_BYTES == 0 for both the absolute Literal address and the TokenOffset offset. Why: the offline bytecode safety pass proves structural/stack safety and now bounds-checks const-table slots (validate_quotient_const_slots), but nothing validated the embedded memory operands. Every address the quotient VM reads is a word slot, so a non-word-aligned pointer indicates a truncated/mis-encoded address that would make the interpreter mload a straddling window and fold the wrong value into the numerator, flipping accept/reject with no build-time diagnostic. Guarding at ptr_to_quotient_mem covers all memory pointers in one place; all 151 lib tests pass, confirming the invariant. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/vm/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index c653cfb48..4c3600660 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2673,12 +2673,26 @@ pub(crate) fn ptr_to_quotient_mem(ptr: Ptr) -> QuotientMem { // in this file (u16::try_from, u8::try_from). let offset = u32::try_from(offset) .expect("quotient memory pointer must be a non-negative offset that fits in u32"); + // Every address the quotient VM reads is a 32-byte word slot (the + // layout allocates in WORD_BYTES units and all eval/challenge/VK/ + // scratch handles are word multiples). A non-word-aligned literal + // pointer signals a truncated/mis-encoded address that would make + // the VM mload a straddling window; reject it at the single + // construction choke point rather than emit a corrupt verifier. + assert!( + offset as usize % WORD_BYTES == 0, + "quotient memory pointer {offset:#x} is not 32-byte word aligned" + ); QuotientMem::Literal(offset) } Value::Identifier(name, offset) => { let offset = u32::try_from(offset).expect( "quotient memory token offset must be a non-negative offset that fits in u32", ); + assert!( + offset as usize % WORD_BYTES == 0, + "quotient memory token offset {offset:#x} is not 32-byte word aligned" + ); let token = quotient_mem_token_from_name(name) .unwrap_or_else(|| panic!("unsupported quotient memory token: {name}")); if offset == 0 { From 2286dff78dadd48d5e9e6c4ee16b621ddba310a7 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:12:26 +0100 Subject: [PATCH 023/108] Guard rotated non-committed instance queries in the Yul quotient emitter What: fail closed on a rotated non-committed instance query in instance_eval_at and expression_memory_ptr. How: hard assert_eq!(rotation, 0) in instance_eval_at's non-committed branch (the value resolver), and return None for rotation != 0 in expression_memory_ptr's Instance arm (which only detects consecutive direct memory pointers, so declining is safe). Why: both helpers resolve ANY rotation of a non-committed instance column to the single Rotation::cur() INSTANCE_EVAL word. Commit 5d7afe9 added the guard to the parallel-lookup path in quotient_numerator/vm/mod.rs but not to this file, so the only protection was the constructor-time guard in builder/api.rs. Any future entry point or refactor that lowers a circuit querying the public instance column at rotation +/-1 without going through SolidityGenerator::try_new would silently evaluate instance[rot] as instance[cur], generating a verifier that checks a different polynomial identity than the native Midfall verifier. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../lowering/quotient_numerator/yul_emit.rs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs index bc8242de0..11b94950d 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs @@ -788,6 +788,14 @@ impl<'a> Evaluator<'a> { .get(&(column_index, query.rotation().0)) .copied()? } else { + // The non-committed public-input column only has its local + // Rotation::cur() interpolation at INSTANCE_EVAL_MPTR. + // Decline to treat a rotated query as a direct memory + // pointer; the constructor rejects rotated instance queries + // and instance_eval_at hard-asserts rotation == 0. + if query.rotation().0 != 0 { + return None; + } self.data.instance_eval } } @@ -1103,8 +1111,18 @@ impl<'a> Evaluator<'a> { .to_string() } else { // The current public API supports one non-committed instance - // column, whose Lagrange-combined evaluation is computed by - // the template prologue and stored at INSTANCE_EVAL_MPTR. + // column, whose Lagrange-combined evaluation is computed by the + // template prologue and stored at INSTANCE_EVAL_MPTR for + // Rotation::cur() only. Hard-assert (not debug_assert) so a + // rotated query that ever bypasses the far-away constructor guard + // (builder/api.rs) fails closed in release builds too, instead of + // silently evaluating instance(x) in place of instance(x*omega^k) + // and generating a verifier that checks a different identity than + // the native Midfall verifier. + assert_eq!( + rotation, 0, + "rotated public instance query reached Yul quotient emission" + ); self.data.instance_eval.to_string() } } From d149f96363bb0c3048d6f4a6a95b2fbe29115aa1 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:12:44 +0100 Subject: [PATCH 024/108] Use unsigned_abs in column_eval_var to avoid i32::MIN overflow What: replace rotation.abs() with rotation.unsigned_abs() in column_eval_var. How: one-line change; unsigned_abs returns u32 and is total over all i32. Why: rotation.abs() overflows for rotation == i32::MIN, panicking in debug and wrapping to a colliding/garbage variable name in release. This is only reachable if the constraint system supplied to codegen contains a query at Rotation(i32::MIN), so it is a build-time DoS on codegen inputs, not an on-chain issue, but unsigned_abs makes the conversion total. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/yul_emit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs index 11b94950d..4ca61f5d9 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs @@ -1159,7 +1159,7 @@ fn u256_string(value: U256) -> String { /// Stable variable name for a column evaluation and rotation. fn column_eval_var(prefix: &'static str, column_index: usize, rotation: i32) -> String { match rotation.cmp(&0) { - Ordering::Less => format!("{prefix}_{column_index}_prev_{}", rotation.abs()), + Ordering::Less => format!("{prefix}_{column_index}_prev_{}", rotation.unsigned_abs()), Ordering::Equal => format!("{prefix}_{column_index}"), Ordering::Greater => format!("{prefix}_{column_index}_next_{rotation}"), } From e5f77f8ab3a91b5fd76ef2be22db395d94f32ba7 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:14:25 +0100 Subject: [PATCH 025/108] Emit h_eval, not 0, for an empty lookup input chunk in the Yul emitter What: change the k == 0 empty-input-chunk branch of lookup_computations to emit the helper eval (h_eval) as the identity value instead of a hard-coded 0. How: replace the `let zero := 0` stub with out.push((lines, h_eval.to_string())). Why: the reference verifier (plonk/logup.rs) computes an empty chunk's helper constraint as helper_eval * (empty product = 1) - (empty sum = 0) = helper_eval, which enforces h == 0. Emitting 0 drops that binding while the accumulator constraint still folds the chunk's h_eval into sum_h, so a prover could set the unconstrained h freely and shift selector*sum_h to forge lookup balance. The branch is dead today (chunks are never empty), but emitting the reference-faithful value fails safe if a future chunking refactor ever reaches it. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/yul_emit.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs index 4ca61f5d9..97b758889 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs @@ -479,10 +479,17 @@ impl<'a> Evaluator<'a> { let k = f_plus_beta_vars.len(); if k == 0 { - // Empty chunk shouldn't happen but emit a no-op. - let zero = self.fresh_var(); - lines.push(format!("let {zero} := 0")); - out.push((lines, zero)); + // Unreachable today (BatchedArgument::new requires >= 1 + // parallel lookup and slice::chunks never yields an empty + // chunk), but emit the reference-faithful value rather than + // 0 so a future chunking change cannot silently drop the + // constraint. For an empty chunk the native verifier + // (plonk/logup.rs) computes helper_eval * (empty product = 1) + // - (empty sum = 0) = helper_eval, enforcing h == 0. Emitting + // 0 would leave h unconstrained while the accumulator still + // folds this h_eval into sum_h, letting a prover forge lookup + // balance. + out.push((lines, h_eval.to_string())); continue; } From 33e183e71044d83feccf569f851d65b1cf0357d0 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:14:45 +0100 Subject: [PATCH 026/108] Guard against a lookup with zero helper chunks in the Yul emitter What: make lookup_computations' accumulator block tolerate an empty h_evals vector instead of indexing h_evals[0]. How: replace `let sum_h := h_evals[0]` + slice with a split_first(), emitting `let sum_h := 0` when there are no helper evals. Why: a LogUp argument with no input expressions produces zero helper chunks and an empty h_evals vector; the native verifier folds sum_helpers over the empty set to F::ZERO, but this emitter panicked with an index-out-of-bounds during code generation. This makes the Solidity generator match the native handling (and the structured native path in quotient.rs) instead of crashing at build time on a degenerate but legal circuit. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/quotient_numerator/yul_emit.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs index 97b758889..752387719 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs @@ -578,11 +578,18 @@ impl<'a> Evaluator<'a> { let beta = self.fresh_var(); lines.push(format!("let {beta} := mload(BETA_MPTR)")); - // Σ_h h_eval[c] + // Σ_h h_eval[c]. Empty for a lookup with no input expressions + // (zero helper chunks); the native verifier's sum_helpers folds + // over an empty set to 0, so mirror that instead of indexing + // h_evals[0] out of bounds and panicking at codegen. let sum_h = self.fresh_var(); - lines.push(format!("let {sum_h} := {}", h_evals[0])); - for h in &h_evals[1..] { - lines.push(format!("{sum_h} := addmod({sum_h}, {h}, r)")); + if let Some((first, rest)) = h_evals.split_first() { + lines.push(format!("let {sum_h} := {first}")); + for h in rest { + lines.push(format!("{sum_h} := addmod({sum_h}, {h}, r)")); + } + } else { + lines.push(format!("let {sum_h} := 0")); } // selector eval (full Expression; not necessarily a From 0b561862e729559ac8c7def150c4d46732dc461b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:15:52 +0100 Subject: [PATCH 027/108] Floor quotient stack scratch at one word to cover the eval-scratch write What: make quotient_stack_words_for_build return at least one word. How: add .max(1) to the max_stack/native-scratch computation and document why. Why: every inline/native direct_quotient_block writes one eval-scratch word at eval_scratch_slot == quotient_stack_mptr, but the function could return 0 for a degenerate-but-valid VK whose gates all fit the inline prefix with no permutation sets, lookups, or VM items. That write is only in-bounds today because layout/memory.rs independently sizes the region as max(quotient_stack_len, MODEXP_FRAME_BYTES) for modexp-frame sharing, which is documented as a modexp concern, not as covering the quotient eval scratch. If that clamp is ever refactored away, the inline write would land one word past the registered region. Flooring here keeps the invariant with the code that emits the write; the modexp clamp still dominates real layouts, so this changes no current output (151 lib tests still pass). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/quotient.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index 1fee3f8c1..b3fbfd5fa 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -253,7 +253,17 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { // `build.max_stack` only describes the interpreted operand stack. Some // native callbacks share `quotient_stack_mptr` as a scratch base, so // the registered memory region must cover both possible users. - build.max_stack.max(native_callback_scratch_words) + // + // Floor at one word: every inline/native direct_quotient_block writes + // one eval-scratch word at eval_scratch_slot == quotient_stack_mptr + // (see direct_quotient_block and compact_quotient_computation_blocks), + // so the region is always written even when the interpreted stack and + // native scratch are both empty (a degenerate-but-valid VK whose gates + // all fit the inline prefix with no permutation sets, lookups, or VM + // items). Accounting that word here keeps the in-bounds invariant with + // the code that emits the write, rather than relying on the unrelated + // MODEXP-frame clamp in layout/memory.rs. + build.max_stack.max(native_callback_scratch_words).max(1) } /// Number of persistent VM temp words needed for state plus selector From d67a2e925cba1d79fbc1f6d2617edf8648a0ff14 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:17:02 +0100 Subject: [PATCH 028/108] Emit h_eval, not 0, for an empty lookup chunk in the structured path What: change the k == 0 empty-input-chunk branch of structured_lookup_loop_block to fold h_eval instead of 0 into q_lookup_eval. How: replace `let q_lookup_eval := 0` with `let q_lookup_eval := `, mirroring the Yul emitter fix. Why: same latent constraint-drop as in quotient_numerator/yul_emit.rs. The native verifier computes helper_eval * 1 - 0 = helper_eval for an empty chunk, enforcing h == 0; emitting 0 leaves h unconstrained while the accumulator still folds this h_eval into sum_h, which would let a prover forge lookup balance if a future chunking refactor ever produced an empty chunk. Dead code today but now fails safe in both lookup emission paths. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/quotient.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index b3fbfd5fa..42804784b 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -1617,7 +1617,15 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { block.push("{".to_string()); if k == 0 { - block.push("let q_lookup_eval := 0".to_string()); + // Unreachable today (chunks are never empty), but emit the + // reference-faithful value (h_eval) rather than 0: the + // native verifier (plonk/logup.rs) computes + // helper_eval * (empty product = 1) - (empty sum = 0) + // = helper_eval for an empty chunk, enforcing h == 0. + // Emitting 0 leaves h unconstrained while the accumulator + // still folds this h_eval into sum_h. Mirrors the fix in + // quotient_numerator/yul_emit.rs. + block.push(format!("let q_lookup_eval := {}", h_eval)); Self::push_structured_main_fold( &mut block, "q_lookup_eval", From 63be0298063c6e01a0418c5aa5faea7c3d46743b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:18:00 +0100 Subject: [PATCH 029/108] Assert lookup chunk/helper-eval count parity at both zip sites What: add assert_eq!(input_chunks.len(), h_evals.len()) before the chunk/helper-eval zip in both structured_lookup_loop_block (quotient.rs) and lookup_computations (quotient_numerator/yul_emit.rs). How: assert the two counts match immediately before zipping them. Why: both paths fold one helper identity per element of input_expression_chunks().zip(h_evals). If data.lookup_evals ever carried fewer helper evals than chunk_by_degree produces chunks (e.g. an EvalRead-schedule or protocol drift after a midnight_proofs update), zip would silently drop the excess chunks, removing helper constraints from the y-batched numerator and producing a verifier that accepts proofs with unconstrained h values (forged lookup membership). This is only guarded transitively today via the protocol lookup count check; a direct assert at each zip site fails loudly at codegen. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/quotient.rs | 12 ++++++++++++ .../src/lowering/quotient_numerator/yul_emit.rs | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index 42804784b..8552031c0 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -1610,6 +1610,18 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { Self::push_structured_main_fold(&mut block, "q_lookup_eval", state_slots, trace); block.push("}".to_string()); + // Fail closed on a chunk/helper-eval count mismatch: zip would + // otherwise silently drop the excess chunks, removing helper + // constraints from the y-batched numerator. Guarded indirectly today + // by the protocol lookup count check, but assert it directly at the + // zip site. + assert_eq!( + chunked.input_expression_chunks().len(), + h_evals.len(), + "lookup {lookup_idx}: input chunk count {} != helper eval count {}", + chunked.input_expression_chunks().len(), + h_evals.len(), + ); for (input_chunk, h_eval) in chunked.input_expression_chunks().iter().zip(h_evals.iter()) { diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs index 752387719..1b68231be 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/yul_emit.rs @@ -456,6 +456,16 @@ impl<'a> Evaluator<'a> { // `(Vec, String)` entries. let selector_expr = chunked.selector_expression(); + // Fail closed on a chunk/helper-eval count mismatch: zip would + // otherwise silently drop the excess chunks, removing helper + // constraints from the numerator. + assert_eq!( + chunked.input_expression_chunks().len(), + h_evals.len(), + "lookup {lookup_idx}: input chunk count {} != helper eval count {}", + chunked.input_expression_chunks().len(), + h_evals.len(), + ); for (input_chunk, h_eval) in chunked.input_expression_chunks().iter().zip(h_evals.iter()) { From fd3842c4f7864d3dc206f3ee185afd6c7cb90a42 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:20:49 +0100 Subject: [PATCH 030/108] Document the proxy selector_gap in native_identity_estimate_block What: add a doc comment explaining why native_identity_estimate_block uses a hard-coded selector_gap of Some(1) that differs from the real selector_fold.gap_for(identity) used at emission. How: documentation only; no behavior change. Why: an auditor flagged the gap mismatch between the estimate (Some(1)) and the real native emission in compact_quotient_computation_blocks (gap_for). The estimate feeds only the native-vs-VM gate selection heuristic and runs during native_gate_candidates, before the selector_fold plan exists (the plan is derived from the selection outcome), so the real gap is genuinely unavailable here and the proxy is intentional. The divergence can only shift which gates are promoted to native callbacks, never the correctness of the emitted verifier. Documenting this prevents a future maintainer from mistaking it for a bug or wiring in gap_for where the plan does not yet exist. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/quotient.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index 8552031c0..f1b38498b 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -604,12 +604,27 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { } /// Estimate the generated native callback block for one identity. + /// + /// This is a size/gas PROXY consumed only by the native-vs-VM gate + /// selection heuristic (native_gate_candidates); it is never emitted. The + /// real native blocks are produced by compact_quotient_computation_blocks + /// with `selector_fold.gap_for(identity)`, but that fold plan does not exist + /// yet at selection time (it is derived from the selection outcome), so we + /// use a fixed proxy gap: Some(1) for selector targets, None otherwise. + /// + /// Any divergence between this proxy and the eventual `gap_for` only + /// perturbs which gates get promoted to native callbacks; it can never + /// change the correctness of the generated verifier, because actual emission + /// always uses the real gap. Do not "fix" this to call `gap_for` here: the + /// plan is intentionally unavailable at this point. fn native_identity_estimate_block(identity: &QuotientIdentity) -> Vec { let state_slots = QuotientStateSlots { eval_numer_mptr: 0x2000, trace_id_mptr: 0x2020, selector_power_mptr: 0x2040, }; + // Proxy gap only; see the doc comment above. This deliberately differs + // from selector_fold.gap_for(identity) used at emission time. let selector_gap = matches!(identity.target, QuotientTarget::Selector(_)).then_some(1); Self::direct_quotient_block( &identity.lines, From b8b4c39749075822ec2213beccf288deccbb7e97 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:23:44 +0100 Subject: [PATCH 031/108] Fail closed on negative offset in Value::as_usize What: assert the offset is non-negative in Value::as_usize before casting to usize. How: replace the bare `*int as usize` with an assert!(*int >= 0) guard, then the cast. Why: Value::Integer is stored as isize purely so BLS pointer arithmetic can form negative ptr_end sentinels for lt(ptr_end, ptr) style loops, where any value below the smallest visited address is acceptable. as_usize is a different accessor that yields a concrete memory address; if it were ever called on a negative offset, `*int as usize` would wrap to a near-2^word value and silently corrupt every mload/mstore derived from it. Asserting turns that latent misuse into a loud build-time failure. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/encoding/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 9397f8f2a..1dfdd82cb 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -596,7 +596,19 @@ impl Value { /// Return the concrete offset, panicking for symbolic identifiers. pub(crate) fn as_usize(&self) -> usize { match self { - Value::Integer(int) => *int as usize, + Value::Integer(int) => { + // `Integer` is signed only so BLS pointer math can produce + // negative `ptr_end` sentinels for `lt(ptr_end, ptr)` loops. A + // concrete memory address is never negative; `*int as usize` on + // a negative value would wrap to a near-2^word offset and + // silently corrupt every derived mload/mstore, so fail closed. + assert!( + *int >= 0, + "Value::as_usize on negative offset {int}: signed offsets are \ + only valid as lt()-loop sentinels, not concrete addresses" + ); + *int as usize + } Value::Identifier(..) => unreachable!(), } } From a9032f85cabbe9298b03c47066adbc8bb87161fd Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:24:08 +0100 Subject: [PATCH 032/108] Assert VK fixed-commitment count matches meta in Data::new What: add assert_eq!(vk.fixed_comms.len(), meta.num_fixeds) before deriving the permutation commitment base. How: one assertion between the fixed_comm_mptr and permutation_comm_mptr computations. Why: permutation_comm_mptr is computed as fixed_comm_mptr + G1_WORDS * vk.fixed_comms.len(), but the fixed-commitment region is actually consumed as meta.num_fixeds slots. These two counts are assumed equal but never checked; if a VK ever carried a fixed_comms vector of a different length than the constraint system's fixed-column count, the fixed and permutation commitment memory regions would silently overlap or leave a gap, mapping proof commitments to the wrong memory and producing a verifier that reads garbage points. The assert makes that inconsistency fail loudly at generation time (151 lib tests still pass). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/encoding/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 1dfdd82cb..41ed78f43 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -308,6 +308,16 @@ impl Data { // BLS12-381 G1 commitments occupy 4 words (EIP-2537 padded), so the // stride between consecutive points is 4 instead of the BN254-era 2. let fixed_comm_mptr = memory.vk_mptr + vk.constants.len(); + // The fixed-commitment region is consumed as meta.num_fixeds slots + // (EcPoint::range(fixed_comm_mptr).take(meta.num_fixeds) below), but the + // permutation base is advanced past vk.fixed_comms.len() of them. If the + // two counts ever diverge, the fixed and permutation commitment regions + // would silently overlap or leave a gap, so require them equal here. + assert_eq!( + vk.fixed_comms.len(), + meta.num_fixeds, + "VK fixed commitment count must match constraint-system fixed count" + ); let permutation_comm_mptr = fixed_comm_mptr + G1_WORDS * vk.fixed_comms.len(); let challenge_mptr = memory.challenge_mptr; let theta_mptr = memory.theta_mptr; From 822980e3b2d0c2c0c93c39c41e00bef5b861c4eb Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:24:23 +0100 Subject: [PATCH 033/108] Correct dummy_eval_words address formula in the field doc What: fix the Data::dummy_eval_words doc comment to reference num_main_evals instead of num_evals. How: documentation only; no behavior change. Why: the field doc said dummy_eval_words[i] points at REVERSED_EVALS_MPTR + (num_evals + i) * 0x20, but set_dummy_eval_words offsets by num_main_evals (the eval count before dummies). Since meta.num_evals already includes the dummy evals on the second protocol build, the old wording double-counts them and mis-describes where the dummy slots live. Aligning the doc with the code (and with set_dummy_eval_words' own doc) prevents a future reader from computing the wrong slot address. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/encoding/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 41ed78f43..d99515f00 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -287,7 +287,9 @@ pub(crate) struct Data { /// fewer-point-sets path. Empty when the feature is disabled. The /// dummy buffer is laid out immediately after the main reversed- /// evals buffer; `dummy_eval_words[i]` points at - /// `REVERSED_EVALS_MPTR + (num_evals + i) * 0x20`. The transcript + /// `REVERSED_EVALS_MPTR + (num_main_evals + i) * 0x20`, where + /// `num_main_evals` is the eval count *before* dummies are appended + /// (not `meta.num_evals`, which already includes them). The transcript /// loop reads `num_dummy_evals` extra Fr scalars after the main /// eval block and spills them into this buffer the same way the /// main loop does. From 69889bece29501ead200ef31da1c0c3dab162537 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:27:23 +0100 Subject: [PATCH 034/108] Reject VK runtime exceeding the EIP-170 code-size limit at codegen What: add an EIP-170 (24576-byte) runtime-size check to Halo2VerifyingKey::validate_payload_layout, plus an EIP_170_MAX_RUNTIME_BYTES constant. How: compute runtime_len() and return an Err (which the generator turns into a panic) when it exceeds 0x6000 bytes, before building the constructor memory layout. Why: the VK is shipped as its own data contract whose runtime is [INVALID, ...payload]. Unlike the main verifier (which solc size-checks), this hand-rolled runtime blob had no size guard, so a circuit with enough constants/commitments to push the payload past 24576 bytes would only fail at on-chain deployment with a cryptic max-code-size revert. Checking at generation turns that into an actionable build-time error. All 151 lib fixtures stay well under the limit, so no current output changes. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/render/models.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index 0ff85f228..399d08667 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -257,6 +257,10 @@ pub(crate) struct Halo2VerifyingKey { pub(crate) const VK_RUNTIME_PREFIX: u8 = 0xfe; /// Number of bytes skipped before copying the separate VK payload. pub(crate) const VK_RUNTIME_PREFIX_LEN: usize = 1; +/// EIP-170 deployed-contract runtime code-size limit (24576 bytes). The VK is +/// shipped as its own data contract whose runtime is `[INVALID, ...payload]`, +/// so it must fit under this bound to be deployable on EIP-170 chains. +pub(crate) const EIP_170_MAX_RUNTIME_BYTES: usize = 0x6000; impl Halo2VerifyingKey { /// Reconstruct and validate the typed VK payload layout. @@ -306,7 +310,15 @@ impl Halo2VerifyingKey { self.len() )); } - let constructor_memory = VkConstructorMemoryLayout::new(self.runtime_len()); + let runtime_len = self.runtime_len(); + if runtime_len > EIP_170_MAX_RUNTIME_BYTES { + return Err(format!( + "VK runtime code size {runtime_len} bytes exceeds the EIP-170 limit of \ + {EIP_170_MAX_RUNTIME_BYTES} bytes; the VK data contract would revert at \ + deployment. Reduce the circuit's constant/commitment count." + )); + } + let constructor_memory = VkConstructorMemoryLayout::new(runtime_len); constructor_memory.validate()?; if self.constructor_payload_mptr != constructor_memory.payload_mptr { return Err(format!( From 01f45494af255544540a70a983e0f2ee8ad63cc2 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:27:58 +0100 Subject: [PATCH 035/108] Harden accumulator fixed-base/scalar count check to a release assert What: change the debug_assert_eq! guarding acc_fixed_bases.len() == fixed_scalar_count to a hard assert_eq!. How: one keyword change; message and operands unchanged. Why: acc_fixed_bases supplies the (base, negate) pairs for the accumulator's fixed-base MSM, which must line up one-to-one with the fixed_scalar_count scalars the generated verifier reads. If those counts ever diverged (e.g. an accumulator-encoding change altering fixed_scalar_count without updating the base construction), a debug_assert compiles out in release, so a release-built generator would silently emit an accumulator pairing check over mismatched base/scalar sets. A hard assert fails closed in every build. 151 lib tests pass. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- proofs/solidity-verifier/src/lowering/artifacts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/artifacts.rs b/proofs/solidity-verifier/src/lowering/artifacts.rs index 4dbf611ed..495795ba1 100644 --- a/proofs/solidity-verifier/src/lowering/artifacts.rs +++ b/proofs/solidity-verifier/src/lowering/artifacts.rs @@ -175,7 +175,7 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { })) .collect::>() }; - debug_assert_eq!( + assert_eq!( bases.len(), fixed_scalar_count, "accumulator fixed-base scalar tail must match generated bases" From b2e99e8c0b81dac63ac81dfcd3f5fb9760821a83 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 18 Jul 2026 23:29:41 +0100 Subject: [PATCH 036/108] Use checked arithmetic when reserving VK payload sections What: guard the word-cursor addition in reserve and the commitments*G1_WORDS multiplication in reserve_g1 with checked_add/checked_mul that return a layout error on overflow. How: replace `self.cursor_words += word_len` with checked_add and `commitments * G1_WORDS` with checked_mul, surfacing descriptive Err strings. Why: both reservations do unchecked usize arithmetic on externally-derived counts (constant/program/commitment sizes). An absurdly large count would wrap in release, producing a smaller-than-real cursor and a section map whose offsets overlap prior sections, i.e. a VK payload whose extcodecopy ranges silently alias. Overflow is unreachable for realistic circuits, but reserve/reserve_g1 already return Result, so failing closed here is free and keeps the section map monotonic by construction. 151 lib tests pass. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/layout/vk_payload.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/vk_payload.rs b/proofs/solidity-verifier/src/lowering/layout/vk_payload.rs index c7c21f047..a416d3576 100644 --- a/proofs/solidity-verifier/src/lowering/layout/vk_payload.rs +++ b/proofs/solidity-verifier/src/lowering/layout/vk_payload.rs @@ -111,7 +111,9 @@ impl VkPayloadLayout { word_offset: self.cursor_words, word_len, }; - self.cursor_words += word_len; + self.cursor_words = self.cursor_words.checked_add(word_len).ok_or_else(|| { + format!("VK payload word cursor overflow reserving {kind:?} ({word_len} words)") + })?; self.sections.push(section); Ok(section) } @@ -122,7 +124,10 @@ impl VkPayloadLayout { kind: PayloadSectionKind, commitments: usize, ) -> Result { - self.reserve(kind, commitments * G1_WORDS) + let word_len = commitments.checked_mul(G1_WORDS).ok_or_else(|| { + format!("VK payload G1 word overflow for {kind:?}: {commitments} commitments") + })?; + self.reserve(kind, word_len) } /// Return the section for `kind`, if it has been reserved. From 68adb9070fe8b57446492a8230cd6ed308b68309 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:37:13 +0100 Subject: [PATCH 037/108] Range-check accumulator scalars where they are read `validate_public_accumulator` reads the carried LHS/RHS scalars and every fixed-base tail scalar straight from calldata and feeds them to the EIP-2537 G1MSM precompile without any `< r` check of its own. Two consequences: * G1MSM reduces scalars mod r implicitly, so `s` and `s + r` are indistinguishable inside the helper. * For negated fixed bases the helper computes `mod(sub(r, s), r)`, which for `s >= r` evaluates to `(2^256 + r - s) mod r` -- not `-s mod r`, but that value shifted by the nonzero constant `2^256 mod r`. Nothing in this file rejected such a scalar. Canonicality was inherited from the instance-absorption loop in TranscriptProofParser.yul, which reverts on any instance word `>= r` and provably covers the accumulator region. But that loop runs *later*: validate_public_accumulator is called from VkLoading.yul before the transcript starts, so the invariant was an unstated cross-template ordering dependency. Reordering, weakening, or exempting the accumulator region from that loop would have silently turned the wrapped negation into a forgery vector. Fold `lt(scalar, r)` into the helper's own `out` flag at each of the three read sites, so the negation's precondition is enforced locally by the code that depends on it. Add a template-corpus test pinning the checks, matching how the other accumulator invariants in this file are covered (no fixture currently renders the accumulator branch). Co-Authored-By: Claude Opus 4.8 --- .../solidity-verifier/src/lowering/tests.rs | 20 +++++++++++++++++++ .../partials/verifier/AccumulatorHelpers.yul | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 7d5203944..39551dfb1 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1273,6 +1273,26 @@ fn accumulator_points_are_prevalidated_before_transcript_work() { } } +#[test] +fn accumulator_scalars_are_range_checked_where_they_are_read() { + let verifier_template = verifier_template_corpus(); + + // `validate_public_accumulator` runs before the transcript instance loop + // that rejects non-canonical instance words, and EIP-2537 G1MSM reduces + // scalars mod r implicitly. Canonicality must therefore be enforced at the + // read sites in this helper rather than inherited from a later template. + for required in [ + "out := and(out, lt(lhs_scalar, r))", + "out := and(out, lt(rhs_scalar, r))", + "out := and(out, lt(fixed_scalar_{{ loop.index0 }}, r))", + ] { + assert!( + verifier_template.contains(required), + "accumulator scalars must be range-checked against r where they are read: {required}" + ); + } +} + #[test] fn accumulator_decoder_rejects_noncanonical_infinity() { let verifier_template = verifier_template_corpus(); diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul index 3a5d5eb77..b0f088d47 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul @@ -259,6 +259,11 @@ // Carried-scalar layout: the circuit exposes the scalar // that multiplies the carried LHS point. let lhs_scalar := calldataload(lhs_scalar_ptr) + // Canonicality is enforced here rather than relying on the + // later instance-absorption loop: G1MSM reduces scalars + // mod r implicitly, so s and s+r would be indistinguishable + // inside this helper. + out := and(out, lt(lhs_scalar, r)) {%- else %} // Already-collapsed point-pair layout: carried scalars are // implicit one. @@ -319,6 +324,7 @@ {%- if self.expected_acc_has_carried_scalars %} // Explicit carried RHS scalar. let rhs_scalar := calldataload(rhs_scalar_ptr) + out := and(out, lt(rhs_scalar, r)) {%- else %} // Implicit unit scalar for already-collapsed point pairs. let rhs_scalar := 1 @@ -347,6 +353,9 @@ // corresponding base point is embedded in verifier memory at // {{ base_mptr|hex() }}. let fixed_scalar_{{ loop.index0 }} := calldataload(fixed_scalar_ptr) + // Reject non-canonical tail scalars before the negation below: + // for s >= r, `mod(sub(r, s), r)` is not -s mod r. + out := and(out, lt(fixed_scalar_{{ loop.index0 }}, r)) {%- if negate_scalar %} // Some accumulator bases are represented with a negated scalar // so the MSM can reuse the generated positive base point. From 2e49d03f1a87525fb72de1e46c29c1db3a6f0bdd Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:37:41 +0100 Subject: [PATCH 038/108] Leave batch_invert immediately on a failed modexp On a failed modexp staticcall (or a returndatasize mismatch), batch_invert set `ret := 0` and then kept going: `all_inv := mload(gp_mptr)` read back the stale frame header (0x20, the base-length word -- a failed staticcall writes no output), and the backward pass overwrote every word of memory[mptr_start, mptr_end) with garbage products derived from it before finally returning ret = 0. The current sole caller in Lagrange.yul folds `ret` into `success` and reverts at the section boundary, so the clobbered range is never consumed. But the intermediate loops between the call and that revert already compute and persist L_LAST/L_BLIND/L_0/INSTANCE_EVAL from the clobbered denominators, and any future caller -- or a reordering that moves the success check later -- would read meaningless values while believing memory was left intact. Bail out with `leave` as soon as `ret` is zero, mirroring the early-exit structure the single-element fast path already uses, so a failed inverse leaves the input range untouched. Co-Authored-By: Claude Opus 4.8 --- .../templates/partials/verifier/AssemblyHelpers.yul | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index f3ddbfc73..2f2e4208a 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -188,6 +188,12 @@ mstore(add(gp_mptr, {{ template_constants.modexp.mod_offset|hex() }}), r) ret := staticcall(gas(), {{ template_constants.modexp.address|hex() }}, gp_mptr, {{ template_constants.modexp.frame_bytes|hex() }}, gp_mptr, {{ template_constants.modexp.output_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total From 636c7ecefc17a35bc63d25aae5e895e611530d3e Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:38:32 +0100 Subject: [PATCH 039/108] Make the verifier's accept path fail closed locally The generated verifier's terminal code was `mstore(RETURN_MPTR, 1); return(RETURN_MPTR, 0x20)` and never consulted `success`. That was safe only because of a two-link chain across three files: FinalPairing.yul reverts if `success` is zero before calling ec_pairing, and ec_pairing reverts internally on any pairing or precompile failure. The weak link was ec_pairing's own entry guard, `ret := success; if iszero(ret) { leave }` -- the one exit in that function that returns a zero flag instead of reverting. Every other helper in this codebase is written in success-plumbing style (batch_invert, validate_public_ accumulator return booleans the caller folds in), and the upstream PSE verifier this derives from returns the pairing flag for the caller to fold. So a plausible future refactor -- dropping FinalPairing's pre-revert, or making ec_pairing return its flag "like everything else" -- would have made the verifier return true for any calldata, since FinalPairing assigns the result into `success` and nothing reads it again. Close both ends: * ec_pairing reverts on a zero input flag, so it has no path that returns control with the proof unverified. * TraceReturn.yul reverts on `iszero(success)` before returning true. Redundant today, but it makes acceptance a local property of the file that performs it. Co-Authored-By: Claude Opus 4.8 --- .../templates/partials/verifier/AssemblyHelpers.yul | 7 ++++++- .../templates/partials/verifier/TraceReturn.yul | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index 2f2e4208a..d019b60a2 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -218,7 +218,12 @@ // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to diff --git a/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul b/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul index 5f040942c..7d3f27f40 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul @@ -54,5 +54,11 @@ // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) From d870dd15a933211f7cc40cf5312e2508deda0cf8 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:39:07 +0100 Subject: [PATCH 040/108] Reject non-reduced inputs in the Fr inversion helpers `scalar_inv` and `batch_invert`'s single-element fast path rejected only the literal word 0. Both then call modexp(x, r-2, r), which returns 0 for *any* x congruent to 0 mod r -- x = r being the obvious case. Such an input would be handed back as if it were a valid inverse, and the downstream mulmod chains that reconstruct f_eval and the Lagrange values would silently absorb the zero rather than failing. Every emitted call site today feeds these helpers addmod/mulmod output, which is always < r, so this is not reachable: the barycentric chains in the generated PCS blocks and the Lagrange denominators are all reduced by construction. But that precondition was only implicit, and it is exactly the kind of thing a future emitter passing a raw calldata scalar would violate without any signal. Check the full canonical range at both sites. scalar_inv reverts (its existing failure mode); the batch_invert fast path returns ret = 0, which its caller already folds into `success`. Co-Authored-By: Claude Opus 4.8 --- .../partials/verifier/AssemblyHelpers.yul | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index d019b60a2..43c77cfe7 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -5,7 +5,13 @@ // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } let p := {{ memory.scalar_inv_scratch_mptr|hex() }} // EIP-198 modexp frame: @@ -142,6 +148,13 @@ // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave From b680bf2ffed805d10c0a3ffa560c495d28487bdf Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:39:35 +0100 Subject: [PATCH 041/108] Check spilled-stack balance in the quotient VM epilogue The interpreter's fail-closed epilogue checked that the program counter landed exactly on q_end and that no cached top was left live, but never that q_sp had returned to the base of the operand stack. Those two checks miss precisely one state: a FOLD executed while more than one operand is live consumes only the cached top, leaving abandoned spill words below q_sp with q_has_top clear. Both existing checks pass, the VM reports success, and nu_y(x) has been computed from a truncated expression -- one operand of the identity silently dropped. The result is a verifier that enforces a different polynomial identity than the circuit. This is unreachable today: the offline validator (validate_quotient_ program / apply_quotient_stack_effect) requires depth exactly 1 at every fold and 0 at the end, and the bytecode is VK-pinned. But these runtime checks exist specifically as a backstop for malformed generator output, and per the comment above them they are meant to catch a final opcode that "over-reads operands or leaves a partial expression live". A stack-effect table regression in a future encoder or compactor is exactly what would produce the one state they could not see, and it would produce a wrong-but-accepted verifier rather than a reverting one. Add the q_sp equality check next to the other two; it costs three opcodes once per verification. Co-Authored-By: Claude Opus 4.8 --- .../partials/quotient_numerator/QuotientNumeratorBlock.yul | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul index e206aed4e..92c63217c 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul @@ -1190,6 +1190,12 @@ // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, {{ program.stack_mptr|hex() }})) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled From 3f95c05d462f2afd70b53bdd943aa5f64c8d278c Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:40:12 +0100 Subject: [PATCH 042/108] Initialize the y^0 slot in the selector power table The precompute loop wrote y^i for i in 1..=selector_max_power, leaving word 0 of the table (already reserved -- selector_power_words allocates max_power + 1 words) never written. Nothing read it, but only because of two conventions maintained in a different file: FOLD_SELECTOR guards its read on a nonzero gap, and selector_tail_updates filters out zero tails. The template's tail block has no such guard -- it multiplies the selector bucket by mload(selector_power_mptr + power_offset) unconditionally. If either filter regressed (a tail of 0 emitted for a selector whose last identity is the final one in the stream), the bucket would be scaled by an uninitialized word, corrupting that selector's linearization scalar and flipping the final PCS check on whatever happened to be in memory from an earlier phase. Store 1 into slot 0 during the precompute. One mstore, and the table is then correct for every index a reader could compute. Co-Authored-By: Claude Opus 4.8 --- .../quotient_numerator/QuotientNumeratorBlock.yul | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul index 92c63217c..f4de01c7b 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul @@ -126,7 +126,14 @@ { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore({{ program.selector_power_mptr|hex() }}, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, {{ program.selector_max_power + 1 }}) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) From 14cb772757a811a8f2968abbef15b91a04534ad2 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:40:43 +0100 Subject: [PATCH 043/108] Count quotient limbs in absorb bytes in eval_run_bytes `eval_run_bytes` is a bound on transcript absorb bytes, but it summed `proof.quotient_limbs.byte_len` -- a *calldata* length -- while its two sibling bounds, initial_run_bytes and total_run_bytes, correctly use `layout::transcript::G1_ABSORB_BYTES`. The mixed units are invisible only because G1_ABSORB_BYTES == G1_BYTES == 128 right now. The term is also provably dead: total_run_bytes - eval_run_bytes reduces to word_absorb + (total_g1_count - num_quotients) * 128 + squeeze_cushion, which is non-negative, so eval_run_bytes can never be the max that sets `words`. That makes the wrong units silent -- no test can currently distinguish them. These two facts compound badly. If the transcript G1 absorb encoding ever diverges from the calldata encoding again -- as it did before the fix that stopped absorbing compressed 48/49-byte G1s against padded calldata -- then any refactor that starts trusting eval_run_bytes (using it for a per-run assertion, or dropping the conservative total_run_bytes) inherits a silently undersized keccak buffer, and the absorb loop overruns VK_MPTR, corrupting K_MPTR/OMEGA_MPTR. Count the limbs as `item_count * g1_absorb` so the bound is expressed in the units it claims. Value is unchanged today; the term stays as the per-run documentation of the eval phase. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/lowering/abi/proof.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/abi/proof.rs b/proofs/solidity-verifier/src/lowering/abi/proof.rs index 82c32efb8..e998770ca 100644 --- a/proofs/solidity-verifier/src/lowering/abi/proof.rs +++ b/proofs/solidity-verifier/src/lowering/abi/proof.rs @@ -347,7 +347,13 @@ impl TranscriptBufferLayout { + pre_squeeze_advices * g1_absorb + squeeze_cushion; - let eval_run_bytes = proof.quotient_limbs.byte_len + // Absorb bytes, so the quotient limbs are counted at the transcript's + // G1 absorb width -- NOT `quotient_limbs.byte_len`, which is a + // calldata length. The two happen to be equal today, but they have + // diverged before (a compressed 48/49-byte transcript encoding against + // padded calldata), and that divergence is what overruns the keccak + // buffer into `VK_MPTR`. + let eval_run_bytes = proof.quotient_limbs.item_count * g1_absorb + proof.evals.byte_len + proof.q_evals.byte_len + squeeze_cushion; From 79dd945701009f4bfd154f198ac6ef122db6db33 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:42:11 +0100 Subject: [PATCH 044/108] Assert VK permutation commitment count matches meta in Data::new Companion to the existing fixed-commitment assert. `permutation_comms` is built by zipping `meta.permutation_columns` against `EcPoint::range(permutation_comm_mptr)` with `izip!`, which silently truncates to the shorter side. Nothing checked that the VK actually carries one commitment per permutation column. Both counts derive from the same VerifyingKey and are equal by halo2 construction, so this is not reachable through the public API. But midnight-proofs' `VerifyingKey::read` takes column counts from file-controlled u32s without cross-checking the constraint system, so a crafted or corrupted VK could under-report them. The truncating zip would then quietly drop permutation columns from the generated verifier's permutation argument -- a verifier enforcing a weaker statement than the circuit -- instead of failing at codegen. Assert equality next to the fixed-commitment check that guards the same region's base pointer. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/lowering/encoding/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index d99515f00..5a98f1f97 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -320,6 +320,17 @@ impl Data { meta.num_fixeds, "VK fixed commitment count must match constraint-system fixed count" ); + // Same argument for the permutation region: `permutation_comms` below + // zips `meta.permutation_columns` against `EcPoint::range(...)`, and + // `izip!` silently truncates to the shorter side. A VK carrying fewer + // commitments than the constraint system has permutation columns would + // therefore drop columns from the permutation argument rather than + // fail. + assert_eq!( + vk.permutation_comms.len(), + meta.permutation_columns.len(), + "VK permutation commitment count must match constraint-system permutation column count" + ); let permutation_comm_mptr = fixed_comm_mptr + G1_WORDS * vk.fixed_comms.len(); let challenge_mptr = memory.challenge_mptr; let theta_mptr = memory.theta_mptr; From 9d7081bf091958d48f5305425cc985e2e94fa65b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:44:00 +0100 Subject: [PATCH 045/108] Panic instead of rendering a negative pointer as sub(0, N) `Value::Integer` holds a signed byte offset, and `Display` rendered a negative one as `sub(0, N)`. The doc comment justified this by claiming the result "only ever appears as `ptr_end` in `lt(ptr_end, ptr)` style loops where any value strictly less than the smallest visited address is acceptable". That justification is backwards. `sub(0, N)` in EVM arithmetic is `2^256 - N`, and `lt` is unsigned -- so the value is *larger* than every representable address, not smaller. A descending loop written exactly as the comment describes, for { ptr := start } lt(ptr_end, ptr) { ptr := sub(ptr, 0x20) } { ... } would evaluate `lt(2^256 - N, start)` as false on the first check and run zero iterations, silently skipping whatever proof reads, absorption, or validation the body performs. That is the classic shape of a fail-open bug, and the comment invited a future emitter to rely on it. No emitter produces a negative offset today (no rendered template contains `sub(0,`), so this is latent. Make it stay that way: panic on a negative concrete offset at render time and correct the comment to say why no rendering is possible. The `Sub` impls stay -- they are not dead as the report assumed. The Askama template Constants.sol uses `proof_cptr - 1`, which is exactly the kind of caller the panic now protects. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/encoding/mod.rs | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index 5a98f1f97..ec7e2f086 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -604,11 +604,17 @@ pub(crate) enum Location { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) enum Value { - /// Byte offset stored as signed so that the BLS code-gen can compute - /// `ptr - N` even when `N` exceeds the original offset (the result - /// only ever appears as `ptr_end` in `lt(ptr_end, ptr)` style loops - /// where any value strictly less than the smallest visited address is - /// acceptable). + /// Byte offset. Stored as signed for historical reasons; concrete + /// offsets must be non-negative and `Display` panics otherwise. + /// + /// A negative offset has no correct rendering here. It used to be + /// emitted as `sub(0, N)`, which in EVM unsigned arithmetic is + /// `2^256 - N` -- the *largest* representable word. The previous + /// comment claimed such a value was safe because it "only ever appears + /// as `ptr_end` in `lt(ptr_end, ptr)` style loops where any value + /// strictly less than the smallest visited address is acceptable", but + /// `lt` is unsigned, so it is larger than every address and such a loop + /// runs zero iterations. Integer(isize), /// A symbolic Yul identifier `name`, with an optional byte-offset that /// will be rendered as `add(name, 0xNN)` (or just `name` when zero). @@ -673,7 +679,9 @@ impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Value::Integer(int) if *int >= 0 => write!(f, "{}", fmt_hex(*int)), - Value::Integer(int) => write!(f, "sub(0, {})", fmt_hex(-*int)), + Value::Integer(int) => { + panic!("negative pointer offset {int} has no correct Yul rendering") + } Value::Identifier(ident, 0) => write!(f, "{ident}"), Value::Identifier(ident, off) if *off > 0 => { write!(f, "add({ident}, {})", fmt_hex(*off)) @@ -685,29 +693,29 @@ impl Display for Value { } } -impl Add for Value { - /// Pointer-expression value after word-wise addition. +impl Sub for Value { + /// Pointer-expression value after word-wise subtraction. type Output = Value; - /// Advance by `rhs` EVM words. - fn add(self, rhs: usize) -> Self::Output { + /// Move backward by `rhs` EVM words. + fn sub(self, rhs: usize) -> Self::Output { match self { - Value::Integer(int) => Value::Integer(int + (rhs as isize) * WORD_BYTES as isize), + Value::Integer(int) => Value::Integer(int - (rhs as isize) * WORD_BYTES as isize), Value::Identifier(name, off) => { - Value::Identifier(name, off + (rhs as isize) * WORD_BYTES as isize) + Value::Identifier(name, off - (rhs as isize) * WORD_BYTES as isize) } } } } -impl Sub for Value { - /// Pointer-expression value after word-wise subtraction. +impl Add for Value { + /// Pointer-expression value after word-wise addition. type Output = Value; - /// Move backward by `rhs` EVM words. - fn sub(self, rhs: usize) -> Self::Output { + /// Advance by `rhs` EVM words. + fn add(self, rhs: usize) -> Self::Output { match self { - Value::Integer(int) => Value::Integer(int - (rhs as isize) * WORD_BYTES as isize), + Value::Integer(int) => Value::Integer(int + (rhs as isize) * WORD_BYTES as isize), Value::Identifier(name, off) => { - Value::Identifier(name, off - (rhs as isize) * WORD_BYTES as isize) + Value::Identifier(name, off + (rhs as isize) * WORD_BYTES as isize) } } } @@ -756,16 +764,6 @@ impl Display for Ptr { } } -impl Add for Ptr { - /// Pointer with the same location and advanced value. - type Output = Ptr; - /// Advance by `rhs` EVM words while preserving location. - fn add(mut self, rhs: usize) -> Self::Output { - self.value = self.value + rhs; - self - } -} - impl Sub for Ptr { /// Pointer with the same location and rewound value. type Output = Ptr; @@ -776,6 +774,16 @@ impl Sub for Ptr { } } +impl Add for Ptr { + /// Pointer with the same location and advanced value. + type Output = Ptr; + /// Advance by `rhs` EVM words while preserving location. + fn add(mut self, rhs: usize) -> Self::Output { + self.value = self.value + rhs; + self + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct Word(Ptr); From b4319da6d2c6340e6917e6d61e91064cd0fe7744 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:45:32 +0100 Subject: [PATCH 046/108] Reject non-canonical scalars in the proof repacking shim `repack_proof` validated G1 commitments (rejecting anything that fails subgroup-checked decompression with InvalidCompressedG1) but passed every eval and q_eval word straight through `scalar_le_to_be_word`, which only reverses byte order and never checks the value is < r. A caller feeding a corrupted or hostile native proof whose LE scalar bytes decode to a value >= r therefore got `Ok(calldata)` back from the shim -- calldata that the generated verifier is guaranteed to reject, since TranscriptProofParser.yul reverts on any eval or q_eval that is not a canonical Fr element. The caller pays gas for a doomed transaction and gets an opaque on-chain revert instead of a descriptive host-side error. This is fail-closed, not a soundness gap: the on-chain verifier range-checks every scalar and instance itself, so no forged acceptance was possible through the shim. It is purely about reporting the failure where the diagnostic is useful. Validate each scalar with `Fq::from_repr` -- the same canonicality test the native verifier applies -- and add a RepackError::NonCanonicalScalar variant carrying the byte offset and the offending word, mirroring the existing G1 error. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/api.rs | 12 ++++++++ .../src/lowering/calldata.rs | 28 +++++++++++++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/proofs/solidity-verifier/src/api.rs b/proofs/solidity-verifier/src/api.rs index bbe20325a..e4e6671a2 100644 --- a/proofs/solidity-verifier/src/api.rs +++ b/proofs/solidity-verifier/src/api.rs @@ -389,6 +389,13 @@ pub enum RepackError { /// Hex encoding of the failing 48-byte compressed G1. bytes_hex: String, }, + /// One proof scalar is not a canonical Fr element (`>= r`). + NonCanonicalScalar { + /// Byte offset of the failing scalar in the native proof. + offset: usize, + /// Big-endian hex encoding of the failing 32-byte scalar. + bytes_hex: String, + }, } impl fmt::Display for RepackError { @@ -410,6 +417,11 @@ impl fmt::Display for RepackError { "invalid compressed G1 at compressed[{offset}..{}]: bytes = 0x{bytes_hex}", offset + layout::G1_COMPRESSED_BYTES ), + Self::NonCanonicalScalar { offset, bytes_hex } => write!( + f, + "non-canonical Fr scalar at compressed[{offset}..{}]: bytes = 0x{bytes_hex}", + offset + layout::WORD_BYTES + ), } } } diff --git a/proofs/solidity-verifier/src/lowering/calldata.rs b/proofs/solidity-verifier/src/lowering/calldata.rs index 0a3a462bc..3bafa14af 100644 --- a/proofs/solidity-verifier/src/lowering/calldata.rs +++ b/proofs/solidity-verifier/src/lowering/calldata.rs @@ -6,6 +6,7 @@ //! big-endian scalar words. This module performs that deterministic boundary //! conversion. +use ff::PrimeField; use group::GroupEncoding; use midnight_curves::{Fq, G1Affine}; @@ -84,11 +85,26 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { out.extend_from_slice(&y_be[16..48]); Ok(()) }; - let push_scalar_be = |cursor: &mut usize, out: &mut Vec| { - out.extend_from_slice(&scalar_le_to_be_word( - &compressed[*cursor..*cursor + layout::WORD_BYTES], - )); + let push_scalar_be = |cursor: &mut usize, out: &mut Vec| -> Result<(), RepackError> { + let le = &compressed[*cursor..*cursor + layout::WORD_BYTES]; + // The generated verifier reverts on any eval or q_eval word that + // is not a canonical Fr element, so reject it here rather than + // handing the caller calldata that is guaranteed to revert + // on-chain. Mirrors the G1 validation in `push_g1`. + let mut arr = [0u8; layout::WORD_BYTES]; + arr.copy_from_slice(le); + let repr = ::Repr::from(arr); + if Option::::from(Fq::from_repr(repr)).is_none() { + let mut be = arr; + be.reverse(); + return Err(RepackError::NonCanonicalScalar { + offset: *cursor, + bytes_hex: hex::encode(be), + }); + } + out.extend_from_slice(&scalar_le_to_be_word(le)); *cursor += layout::WORD_BYTES; + Ok(()) }; for &n in &plan.g1_groups { for _ in 0..n { @@ -98,13 +114,13 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { // evals (Fr 32-byte LE in native proof) -> BE calldata words // (incl. dummy slots). for _ in 0..plan.num_evals { - push_scalar_be(&mut cursor, &mut out); + push_scalar_be(&mut cursor, &mut out)?; } // f_com push_g1(&mut cursor, &mut out)?; // q_evals (Fr 32-byte LE in native proof) -> BE calldata words. for _ in 0..plan.num_point_sets { - push_scalar_be(&mut cursor, &mut out); + push_scalar_be(&mut cursor, &mut out)?; } // pi push_g1(&mut cursor, &mut out)?; From 55d548b8c074a951ddf6839a2ebe0c1c26ccc959 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:46:09 +0100 Subject: [PATCH 047/108] Correct the pairing-batch domain tag comment The constant was documented as ASCII "pairing-batch-acc-kzg" right-padded to one EVM word. It is not. The literal is 29 bytes -- 21 ASCII bytes plus 8 trailing zeros -- and FinalPairing.yul writes it with `mstore`, which left-pads numeric literals. The word actually hashed into alpha is 00 00 00 || "pairing-batch-acc-kzg" || 00 * 8 Domain separation is unaffected, since the value is still a fixed unique constant, and no code reads the tag by reconstructing it from the ASCII. But the documented form and the implemented form differ, so any external tool, differential fixture, or future reimplementation that derives alpha from the right-padded spec would compute a different challenge than the deployed verifier and diverge on accept/reject when reproducing a verification. Document the actual hashed word rather than changing the constant -- changing it would alter every derived alpha for no benefit. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/layout/mod.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 8612fc319..6beb93b2d 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -142,7 +142,22 @@ pub(crate) mod accumulator { /// Low-memory hash frame for batching the accumulator pairing with KZG: /// domain tag word, KZG rhs/lhs G1s, then accumulator rhs/lhs G1s. pub(crate) const PAIRING_BATCH_PTR: usize = 0x100; - /// ASCII `"pairing-batch-acc-kzg"` right-padded to one EVM word. + /// Domain-separation word for the accumulator pairing batch. + /// + /// This is a 29-byte numeric literal: ASCII `"pairing-batch-acc-kzg"` + /// (21 bytes) followed by 8 zero bytes. FinalPairing.yul stores it with + /// `mstore`, which left-pads numeric literals to a full word, so the word + /// actually hashed into alpha is + /// + /// ```text + /// 00 00 00 || "pairing-batch-acc-kzg" || 00 * 8 + /// ``` + /// + /// i.e. NOT right-padded ASCII, as this comment previously claimed. The + /// value is still a fixed unique constant, so domain separation is + /// unaffected -- but any reimplementation or differential fixture that + /// derives alpha from the right-padded form will disagree with the + /// deployed verifier on accept/reject. pub(crate) const PAIRING_BATCH_DOMAIN_TAG_HEX: &str = "0x70616972696e672d62617463682d6163632d6b7a670000000000000000"; /// KZG pairing RHS point offset inside the batch hash frame. From a1bb2c4d9505fce97488234d726edb7a3f4bf967 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:58:12 +0100 Subject: [PATCH 048/108] Move final pairing scratch past the accumulator batch frame The accumulator pairing-batch hash frame occupies [PAIRING_BATCH_PTR, PAIRING_BATCH_PTR + PAIRING_BATCH_HASH_BYTES) = [0x100, 0x320), while final_pairing_scratch started at FINAL_PAIRING_SCRATCH_START = PAIRING_TWO_PAIR_BYTES = 0x300. The two regions therefore shared the word [0x300, 0x320) -- the last word of the ACC_LHS copy inside the alpha keccak preimage was physically the same memory as the first word of ec_pairing's input frame. Nothing caught this. The regions carry different MemoryPhases (AccumulatorPairingBatch vs FinalPairing), and MemoryLifetime::intersects returns false for any two distinct phases, so the arena's overlap validation is structurally incapable of reporting it. It was correct only by execution order within a single straight-line file: FinalPairing.yul computes the batch keccak, and makes its last read of the frame, before ec_pairing writes its scratch. Any future change that writes the pairing scratch earlier -- pre-staging the G2 pairs to save an mcopy, or emitting a debug re-hash after the pairing -- would corrupt the y_lo word of ACC_LHS inside the alpha preimage while validate() still passed. A partially-unbound alpha weakens the Fiat-Shamir binding of the randomized batching. Derive FINAL_PAIRING_SCRATCH_START from the batch frame's end so the two cannot overlap by construction (0x300 -> 0x320), and assert disjointness in fixed_low_memory_regions_are_planner_registered, since that assertion is now the only check that can catch a regression. Verified end-to-end: rendered scratch moves to 0x0320 and the fixture verifiers still compile under solc and verify real proofs on revm. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/layout/memory.rs | 23 +++++++++++++++++++ .../src/lowering/layout/mod.rs | 11 ++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 632e7ac20..808af34ce 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -1453,6 +1453,29 @@ mod tests { meta.num_simple_selectors * G1_MSM_PAIR_BYTES ); + // These two regions carry different phases, and `MemoryLifetime:: + // intersects` treats distinct phases as never co-live -- so the arena's + // own overlap validation is structurally blind to an overlap here and + // this assertion is the only thing that catches one. + let batch = layout + .map + .region("accumulator_pairing_batch") + .expect("accumulator pairing batch registered"); + let final_pairing = layout + .map + .region("final_pairing_scratch") + .expect("final pairing scratch registered"); + assert!( + batch.start + batch.len <= final_pairing.start, + "accumulator pairing batch [{:#x}, {:#x}) must not overlap final pairing scratch \ + [{:#x}, {:#x}): the last word of the hashed ACC_LHS copy would share bytes with \ + ec_pairing's input frame", + batch.start, + batch.start + batch.len, + final_pairing.start, + final_pairing.start + final_pairing.len, + ); + let scalar_inv = layout .map .region("scalar_inv_scratch") diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 6beb93b2d..59bc19f1e 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -89,7 +89,16 @@ pub(crate) const PCS_STATIC_WORKING_WORDS: usize = 32; /// Static two-pair KZG pairing scratch plus one return word. pub(crate) const PAIRING_STATIC_WORKING_WORDS: usize = PAIRING_TWO_PAIR_BYTES / WORD_BYTES + 1; /// Low-memory frame used by the final two-pair KZG pairing helper. -pub(crate) const FINAL_PAIRING_SCRATCH_START: usize = PAIRING_TWO_PAIR_BYTES; +/// +/// Placed past the end of the accumulator pairing-batch hash frame, which +/// occupies `[PAIRING_BATCH_PTR, PAIRING_BATCH_PTR + PAIRING_BATCH_HASH_BYTES)` +/// = `[0x100, 0x320)`. Starting at `PAIRING_TWO_PAIR_BYTES` (0x300) instead +/// would put the last word of the hashed ACC_LHS copy inside this scratch. +/// The two regions carry different `MemoryPhase`s, and `MemoryLifetime:: +/// intersects` treats distinct phases as never co-live, so the planner cannot +/// catch that overlap -- it has to be avoided by construction here. +pub(crate) const FINAL_PAIRING_SCRATCH_START: usize = + accumulator::PAIRING_BATCH_PTR + accumulator::PAIRING_BATCH_HASH_BYTES; pub(crate) mod precompile { //! EVM precompile addresses used by the generated verifier. These values From 914c61c6630054c5e1a4898857d155a22c36d14e Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 00:59:56 +0100 Subject: [PATCH 049/108] Order MemoryPhase to match generated-verifier execution order MemoryLifetime::intersects decides whether two memory regions may share bytes by comparing MemoryPhase values with <=, so the enum's declaration order is trusted as the runtime execution order. Two variants were in the wrong place: * AccumulatorMsm was declared after PcsPairing, but its only user -- validate_public_accumulator, the sole consumer of acc_msm_scratch -- is called from VkLoading.yul immediately after the VK payload loads, before the transcript has started. * ScalarInv was declared between Transcript and LagrangeBatchInvert, but scalar_inv is called from the PCS f_eval interpolation. In the rendered verifier its call sites sit after the q_eval source-table fold and before the fused final MSM, nowhere near transcript absorption. No current region pair turns this into corruption -- the arena validates to the correct verdict, but for the wrong reason. The hazard is a future region: a PhaseSpan { start: QuotientVm, end: PcsFinalMsm }, exactly the span the selector accumulators already use, overlapping scalar_inv's scratch at [vk_mptr - 0x100, vk_mptr - 0x40) would have been accepted by validate() (ScalarInv sorted below QuotientVm) while scalar_inv's modexp frames were in fact written in the middle of that span -- corrupting the region and flipping the verification result with no codegen-time error. Move both variants to their true positions and document that this order is load-bearing and must track the include order in Halo2Verifier.sol. The full EVM gate still passes, which confirms the reorder does not expose a real overlap; it only makes the validator ask the right question. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/layout/memory.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 808af34ce..59615e34b 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -117,16 +117,26 @@ impl ThetaWindowLayout { } } +/// Verifier execution phases, in the order the generated code runs them. +/// +/// The derived `Ord` is load-bearing: `MemoryLifetime::intersects` compares +/// phases with `<=` to decide whether a `PhaseSpan` covers a `Phase`, so a +/// variant declared out of runtime order makes the arena's overlap validation +/// answer the wrong question. Keep this list in sync with the include order in +/// `templates/contracts/Halo2Verifier.sol` and the call sites it renders. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub(crate) enum MemoryPhase { /// Generated verifying-key constructor return payload. VkConstructorPayload, /// Constructor-only precompile smoke tests. ConstructorSmoke, + /// Public-accumulator MSM input buffer. + /// + /// `validate_public_accumulator` runs from VkLoading.yul, immediately + /// after the VK payload is loaded and *before* the transcript starts. + AccumulatorMsm, /// Streaming Fiat-Shamir buffer before generated VK memory is live. Transcript, - /// Single scalar inversion scratch used by the modexp wrapper. - ScalarInv, /// Batch inversion for Lagrange denominator terms. LagrangeBatchInvert, /// Compact quotient VM temps and stack. @@ -135,12 +145,16 @@ pub(crate) enum MemoryPhase { PcsQEvalSourceTable, /// Optional trace-only q_com MSM materialization. PcsQComTrace, + /// Single scalar inversion scratch used by the modexp wrapper. + /// + /// `scalar_inv` is called from the PCS f_eval interpolation, i.e. after + /// the q_eval source-table fold and before the fused final MSM -- not + /// during transcript absorption. + ScalarInv, /// Fused final PCS MSM input buffer. PcsFinalMsm, /// Low-memory PCS pairing input helpers. PcsPairing, - /// Public-accumulator MSM input buffer. - AccumulatorMsm, /// Public-accumulator pairing-batch hash and two G1 add/MSM frames. AccumulatorPairingBatch, /// Final two-pair KZG pairing frame. From ed547aed7889fb3fa8a4c5ca063ef882a501e679 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:02:32 +0100 Subject: [PATCH 050/108] Register the trace-only linearization MSM scratch with the arena In trace renders, QuotientAndLinearization.yul expands the linearization terms into a G1MSM frame at `add(SELECTOR_ACC_MPTR, selector_len)` and writes (num_quotients + num_simple_selectors) * 0xa0 bytes there. That byte range was never registered in the MemoryArena: lin_trace_len was computed only to size the constructor's G1MSM smoke maximum, which is allocated at a different base. The write band was therefore in bounds by accident. Its safety rested on an unvalidated coincidence -- that the PCS scratch trio allocated from the same base (quotient_tmp_base) happens to be at least as long, because final_msm.input_bytes covers (num_quotients + nsel + 1) * 0xa0 -- and on the trace log word being placed past the PCS scratch ends. Neither memory.validate() nor validate_layout() could see the region at all, so a future layout change that shrank or relocated the PCS band (moving pcs_final_msm_scratch to a dedicated base, or a scheme change reducing final-MSM terms) would let the trace MSM silently overwrite whatever followed -- first casualty trace_u256_log_word, then unregistered memory -- with no codegen-time diagnostic. Register it as "linearization_trace_msm" under a new LinearizationTrace phase (it runs after the quotient VM and before the PCS blocks reuse the band), feed its end into the trace-log-word placement, and assert its base equals the address the template computes so the two cannot drift. Trace builds are not the production verifier, so there was no path to accepting a bad proof; this closes a blind spot in the planner rather than an exploitable bug. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/layout/memory.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 59615e34b..fe3efd00c 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -141,6 +141,9 @@ pub(crate) enum MemoryPhase { LagrangeBatchInvert, /// Compact quotient VM temps and stack. QuotientVm, + /// Trace-only linearization-commitment MSM, run after the quotient VM and + /// before the PCS blocks reuse the same scratch band. + LinearizationTrace, /// Source-address table used by the rolled q_eval fold. PcsQEvalSourceTable, /// Optional trace-only q_com MSM materialization. @@ -843,6 +846,29 @@ impl VerifierMemoryLayout { ); (quotient_tmp_mptr, quotient_stack_mptr) }; + // Trace renders expand the linearization terms into their own G1MSM + // frame at `SELECTOR_ACC_MPTR + selector_len`, i.e. starting exactly at + // `quotient_tmp_base`. Register it so the write band is visible to the + // arena and to the trace-log-word placement below; without this the + // only thing keeping it in bounds is the incidental fact that the PCS + // scratch allocated from the same base happens to be at least as long. + let linearization_trace_msm_mptr = { + let mut scratch = arena.scratch_allocator(quotient_tmp_base); + scratch.alloc_phase_scratch( + "linearization_trace_msm", + lin_trace_len, + MemoryPhase::LinearizationTrace, + ) + }; + // QuotientAndLinearization.yul derives the frame base as + // `add(SELECTOR_ACC_MPTR, selector_len)`. Pin the equality so the + // registered region cannot drift away from the address the template + // actually writes. + assert_eq!( + linearization_trace_msm_mptr, + selector_acc_mptr + selector_len, + "linearization trace MSM region must start where the template computes lin_scratch" + ); let pcs_scratch_mptr = quotient_tmp_mptr; let ( pcs_q_eval_source_table_mptr, @@ -904,6 +930,7 @@ impl VerifierMemoryLayout { selector_acc_mptr + selector_len, batch_invert_scratch_mptr + batch_invert_len, quotient_stack_mptr + quotient_stack_len.max(MODEXP_FRAME_BYTES), + linearization_trace_msm_mptr + lin_trace_len, pcs_q_eval_source_table_mptr + q_eval_source_len, pcs_q_com_trace_scratch_mptr + q_com_trace_len, pcs_final_msm_scratch_mptr + final_msm_len, From 591206148e2c4432fb30cd4bd8ac51a03b6fa252 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:09:48 +0100 Subject: [PATCH 051/108] Compile the accumulator render arm in the default EVM gate No production fixture enables `with_accumulator`, so the entire `{%- if self.expected_has_accumulator %}` branch of AccumulatorHelpers.yul -- the packed-limb coordinate decoder, the pre-transcript public-accumulator MSM, and the fixed-base scalar tail -- was never handed to solc by the default test gate. The only coverage was the opt-in ivc_keccak_solidity bench, which needs k = 20, a release build, and external SRS assets, so in practice a Yul syntax error or a solc stack-depth regression in that branch could reach a release unnoticed. Rendered-template assertions in lowering/tests.rs pin the source text but never compile it. Render three accumulator shapes against the existing Poseidon VK -- fully collapsed, partially collapsed with a fixed-base scalar tail sized to the VK's own commitments (-G + fixed + permutation), and the point-pair form with implicit unit scalars -- and compile each verifier and VK under the pinned solc. Also pin the accumulator scalar canonicality checks, and assert the point-pair form reads no explicit scalar at all. Verified the coverage is real: injecting a Yul syntax error into the accumulator-only branch fails this test, and it passes again once reverted. This still does not execute the accumulator logic against a real proof. That needs a decider circuit carrying a genuine accumulator in its public inputs, which remains the ivc_keccak_solidity bench's job. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/test.rs | 120 ++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 0c585e179..6caf62614 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -45,9 +45,9 @@ use ruint::aliases::U256; use sha3::Digest; use crate::{ - compile_solidity, encode_calldata, pinned_solc_available, CallOutcome, Evm, GeneratorConfig, - RenderDiagnostics, RenderOptions, RenderQuotient, RenderVk, SolidityGenerator, - FN_SIG_VERIFY_PROOF, + compile_solidity, encode_calldata, pinned_solc_available, AccumulatorEncoding, CallOutcome, + Evm, GeneratorConfig, RenderDiagnostics, RenderOptions, RenderQuotient, RenderVk, + SolidityGenerator, FN_SIG_VERIFY_PROOF, }; /// Scalar field used by the BLS12-381 Poseidon fixtures. @@ -1485,6 +1485,120 @@ fn compile_solidity_is_deterministic_for_same_source() { assert_eq!(bytecode_a, bytecode_b); } +/// Compile the accumulator render arm. +/// +/// No production fixture enables `with_accumulator`, so before this test the +/// whole `{%- if self.expected_has_accumulator %}` branch of +/// AccumulatorHelpers.yul -- the limb decoder, the pre-transcript +/// public-accumulator MSM, and the fixed-base scalar tail -- was never handed +/// to solc by the default gate. Only the opt-in `ivc_keccak_solidity` bench +/// (k = 20, release, external SRS assets) rendered it, so a Yul syntax error +/// or a solc stack-depth regression in that branch could reach a release +/// unnoticed. +/// +/// This does not execute the accumulator logic against a real recursive proof +/// -- that still needs a decider circuit carrying a genuine accumulator in its +/// public inputs. It does guarantee the branch compiles, and it pins the +/// canonicality checks on the scalars the helper feeds to G1MSM. +#[test] +fn accumulator_verifier_variants_compile_with_pinned_solc() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let srs_dir = srs_dir(); + env::set_var("SRS_DIR", &srs_dir); + let relation = PoseidonExample; + let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let vk = setup_vk(&srs, &relation); + + // A fully collapsed accumulator occupies FULLY_COLLAPSED_PUBLIC_INPUT_WORDS + // public inputs and has no fixed-base scalar tail. + let collapsed_words = AccumulatorEncoding::FULLY_COLLAPSED_PUBLIC_INPUT_WORDS; + // The partially collapsed form appends one scalar per generated base: + // `-G`, then every fixed commitment, then every permutation commitment. + let num_fixed_comms = vk.vk().fixed_commitments().len(); + let num_perm_comms = vk.vk().permutation().commitments().len(); + let tail_words = 1 + num_fixed_comms + num_perm_comms; + + let variants = [ + ( + "fully collapsed accumulator", + collapsed_words, + AccumulatorEncoding::new(0, 7, 56), + true, + ), + ( + "accumulator with fixed-base scalar tail", + collapsed_words + tail_words, + AccumulatorEncoding::new(0, 7, 56), + true, + ), + // Point-pair encodings carry no explicit scalars -- both are implicit + // one -- so no calldata scalar is read and none is range-checked. + ( + "point-pair accumulator", + AccumulatorEncoding::POINT_PAIR_PUBLIC_INPUT_WORDS, + AccumulatorEncoding::point_pair(0, 7, 56), + false, + ), + ]; + + for (name, num_instances, acc, has_carried_scalars) in variants { + let generator = SolidityGenerator::new( + &srs, + vk.vk(), + GeneratorConfig::new(num_instances, 1).with_accumulator(acc), + ); + let artifacts = generator + .render(RenderOptions { + vk: RenderVk::Separate, + ..RenderOptions::default() + }) + .unwrap_or_else(|err| panic!("{name} should render: {err}")); + + let verifier = artifacts.verifier; + assert!( + verifier.contains("function validate_public_accumulator"), + "{name} should render the accumulator helper" + ); + // The helper runs before the transcript loop that rejects + // non-canonical instance words, and EIP-2537 G1MSM reduces scalars mod + // r implicitly, so it must reject `s >= r` itself. + if has_carried_scalars { + for required in ["lt(lhs_scalar, r)", "lt(rhs_scalar, r)"] { + assert!( + verifier.contains(required), + "{name} should range-check accumulator scalars: {required}" + ); + } + } else { + assert!( + !verifier.contains("lt(lhs_scalar, r)"), + "{name} carries no explicit scalars, so none should be read or checked" + ); + } + + for (label, source) in [ + (name, verifier.as_str()), + ( + "accumulator VK", + artifacts + .verifying_key + .as_deref() + .expect("separate render includes VK"), + ), + ] { + let bytecode = std::panic::catch_unwind(AssertUnwindSafe(|| compile_solidity(source))) + .unwrap_or_else(|_| panic!("{label} should compile under the pinned solc")); + assert!( + !bytecode.is_empty(), + "{label} should compile to non-empty bytecode" + ); + } + } +} + #[test] fn poseidon_verifier_variants_compile_with_pinned_solc() { if !poseidon_inputs_available_for_evm() { From 48a6f0cf84b110378f54412bf356396d8765194d Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:10:39 +0100 Subject: [PATCH 052/108] Regenerate tracked verifier fixture artifacts The committed fixture dumps under target/*-fixture-dump/ no longer matched what codegen produces. Two independent causes: * They were already stale before this branch's verifier changes. The quotient constant table in the VK dumps is ordered differently because of "Reserve fused add-product constants early" and "Reserve limb decomposition constants early", which legitimately change the order constants are interned -- but the artifacts were not regenerated at the time. Confirmed by regenerating at the parent commit and diffing against the committed file. * This branch's verifier-side hardening (Fr inversion range checks, batch_invert early leave, the ec_pairing/TraceReturn fail-closed guards, the quotient VM stack-balance check, the y^0 selector slot, and the final-pairing scratch move to 0x320) changes the rendered Yul. Codegen itself is deterministic -- regenerating twice on the same tree produces byte-identical output, and that output matches a regeneration at the parent commit -- so this is purely a refresh, not a fix for nondeterminism. Note: target/ivc-keccak-solidity-dump/ is also tracked and is the only dump covering the accumulator render path, but regenerating it requires the opt-in ivc_keccak_solidity bench (k = 20, release build, external SRS assets), so it is left untouched here and remains stale. Co-Authored-By: Claude Opus 4.8 --- .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 53 +++++++++++++++++-- .../Halo2VerifyingKey.sol | 40 +++++++------- .../poseidon-fixture-dump/Halo2Verifier.sol | 51 ++++++++++++++++-- .../Halo2Verifier.sol | 51 ++++++++++++++++-- .../Halo2Verifier.sol | 53 +++++++++++++++++-- .../Halo2VerifyingKey.sol | 32 +++++------ 6 files changed, 226 insertions(+), 54 deletions(-) diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index c0bd92500..3168b1c84 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -43,7 +43,7 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 8640; uint256 internal constant EXPECTED_VK_LENGTH = 8641; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0xaa09cafce41491f57d16b422d0224fa9090c5313065c1edccaf639ecd603e0fa; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0xd85df9a6825e0edb1a2ed376a8a317078c3f98f663d45355679082083fbbd1ad; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -321,7 +321,13 @@ contract Halo2Verifier { // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } let p := 0x1ce0 // EIP-198 modexp frame: @@ -458,6 +464,13 @@ contract Halo2Verifier { // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave @@ -504,6 +517,12 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0xa0), r) ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total @@ -528,14 +547,19 @@ contract Halo2Verifier { // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0300 + let scratch := 0x0320 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1401,7 +1425,14 @@ contract Halo2Verifier { { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0x7100, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 42) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) @@ -2353,6 +2384,12 @@ contract Halo2Verifier { // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0x7640)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -3223,6 +3260,12 @@ contract Halo2Verifier { // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol index 17578c207..986773183 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol @@ -94,8 +94,8 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x03a0), 0x00000000000000000000000000000000006d57f79a18220d1e5ef04bd519e995) // neg_s_g2_y_c1_hi mstore(add(payload, 0x03c0), 0x9a9cc71553bb761b5422a6b6971b75c8d3695bfa07b861c4b1c958da426efc45) // neg_s_g2_y_c1_lo mstore(add(payload, 0x03e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // quotient_const - mstore(add(payload, 0x0400), 0x0000000000000000000000000000000000000000000000000000040000000000) // quotient_const - mstore(add(payload, 0x0420), 0x0000000000000000000000000000000000000000000000000000000000100000) // quotient_const + mstore(add(payload, 0x0400), 0x0000000000000000000000000000000000000000000000000000000000100000) // quotient_const + mstore(add(payload, 0x0420), 0x0000000000000000000000000000000000000000000000000000040000000000) // quotient_const mstore(add(payload, 0x0440), 0x0000000000000000000000000000000000000000000000000000000000000002) // quotient_const mstore(add(payload, 0x0460), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffefff00001) // quotient_const mstore(add(payload, 0x0480), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffe00001) // quotient_const @@ -119,19 +119,19 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x06c0), 0x0000000000000000000000000000000000000000000000000000000000040011) // quotient_const mstore(add(payload, 0x06e0), 0x0000000000000000000000000000000000000000000000000000001100000000) // quotient_const mstore(add(payload, 0x0700), 0x0000000000000000000000000000000000000000000000000000000044000000) // quotient_const - mstore(add(payload, 0x0720), 0x0000000000000000000000000000000000000000000000000000000000200000) // quotient_const - mstore(add(payload, 0x0740), 0x0000000000000000000000000000000000000000000000000000000000000400) // quotient_const - mstore(add(payload, 0x0760), 0x0000000000000000000000000000000000000000000000000000000000400000) // quotient_const + mstore(add(payload, 0x0720), 0x0000000000000000000000000000000000000000000000000000000000000400) // quotient_const + mstore(add(payload, 0x0740), 0x0000000000000000000000000000000000000000000000000000000000200000) // quotient_const + mstore(add(payload, 0x0760), 0x0000000000000000000000000000000000000000000000000000000000000004) // quotient_const mstore(add(payload, 0x0780), 0x0000000000000000000000000000000000000000000000000000000000002000) // quotient_const - mstore(add(payload, 0x07a0), 0x0000000000000000000000000000000000000000000000000000000000000004) // quotient_const - mstore(add(payload, 0x07c0), 0x0000000000000000000000000000000000000000000000000000100000000000) // quotient_const + mstore(add(payload, 0x07a0), 0x0000000000000000000000000000000000000000000000000000000000400000) // quotient_const + mstore(add(payload, 0x07c0), 0x0000000000000000000000000000000000000000000000000000000000000010) // quotient_const mstore(add(payload, 0x07e0), 0x0000000000000000000000000000000000000000000000000000000004000000) // quotient_const - mstore(add(payload, 0x0800), 0x0000000000000000000000000000000000000000000000000000000000000010) // quotient_const - mstore(add(payload, 0x0820), 0x0000000000000000000000000000000000000000000000000000000002000000) // quotient_const + mstore(add(payload, 0x0800), 0x0000000000000000000000000000000000000000000000000000100000000000) // quotient_const + mstore(add(payload, 0x0820), 0x0000000000000000000000000000000000000000000000000000000000000040) // quotient_const mstore(add(payload, 0x0840), 0x0000000000000000000000000000000000000000000000000000000000000800) // quotient_const - mstore(add(payload, 0x0860), 0x0000000000000000000000000000000000000000000000000000000000000040) // quotient_const - mstore(add(payload, 0x0880), 0x0000000000000000000000000000000000000000000000000004000000000000) // quotient_const - mstore(add(payload, 0x08a0), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x0860), 0x0000000000000000000000000000000000000000000000000000000002000000) // quotient_const + mstore(add(payload, 0x0880), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x08a0), 0x0000000000000000000000000000000000000000000000000004000000000000) // quotient_const mstore(add(payload, 0x08c0), 0x0000000000000000000000000000000000000000000000000000000000040000) // quotient_const mstore(add(payload, 0x08e0), 0x0000000000000000000000000000000000000000000000000000000000000080) // quotient_const mstore(add(payload, 0x0900), 0x0000000000000000000000000000000000000000000000000000000000000008) // quotient_const @@ -141,18 +141,18 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x0980), 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140) // quotient_const mstore(add(payload, 0x09a0), 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a) // quotient_const mstore(add(payload, 0x09c0), 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db) // quotient_const - mstore(add(payload, 0x09e0), 0x055b80105ea0055c2008060d000b020001055ca0105cc0105ba00901115d0013) // quotient_program - mstore(add(payload, 0x0a00), 0x5b6002105c000901115ce0135b4002105be00d030608060d000b030000055ca0) // quotient_program - mstore(add(payload, 0x0a20), 0x105cc00901115d00135b6002105c000901115ce0135b4002105be00d03060806) // quotient_program + mstore(add(payload, 0x09e0), 0x055b80105ea0055c2008060d000b020001055ca0105cc0105ba00902115d0013) // quotient_program + mstore(add(payload, 0x0a00), 0x5b6001105c000902115ce0135b4001105be00d030608060d000b030000055ca0) // quotient_program + mstore(add(payload, 0x0a20), 0x105cc00902115d00135b6001105c000902115ce0135b4001105be00d03060806) // quotient_program mstore(add(payload, 0x0a40), 0x0d000b040000055b80105ba0055bc008060d000b0400011b00001b0001210001) // quotient_program mstore(add(payload, 0x0a60), 0x00000700045b40055b60065b80075ba0085bc0095be00a5c000b5c200c5ca00d) // quotient_program mstore(add(payload, 0x0a80), 0x5cc00e5ce00f5d00105d20115d400b07000021000100000700045b40055b6012) // quotient_program mstore(add(payload, 0x0aa0), 0x5b80135ba0145bc0095be00a5c00155c20165ca0175cc00e5ce00f5d00185d20) // quotient_program - mstore(add(payload, 0x0ac0), 0x195d400b080000091a115d60135c601b105d80055da008060d000b090000091c) // quotient_program - mstore(add(payload, 0x0ae0), 0x115d60135dc01d135c601e105c80055da008060d000b0a0000091f115ce0135d) // quotient_program - mstore(add(payload, 0x0b00), 0x0020135b4021105b60055b8008060d000b0a00010922115d60135dc01d135c60) // quotient_program - mstore(add(payload, 0x0b20), 0x23135c8024105d80055da008060d000b0b00000925115ce0135d0020135b401c) // quotient_program - mstore(add(payload, 0x0b40), 0x135b6026105be0055b8008060d000b0b00011c275c40285c60295c80025d601b) // quotient_program + mstore(add(payload, 0x0ac0), 0x195d400b080000091b115d60135c601a105d80055da008060d000b090000091e) // quotient_program + mstore(add(payload, 0x0ae0), 0x115d60135dc01d135c601c105c80055da008060d000b0a00000921115ce0135d) // quotient_program + mstore(add(payload, 0x0b00), 0x0020135b401f105b60055b8008060d000b0a00010924115d60135dc01d135c60) // quotient_program + mstore(add(payload, 0x0b20), 0x23135c8022105d80055da008060d000b0b00000926115ce0135d0020135b401e) // quotient_program + mstore(add(payload, 0x0b40), 0x135b6025105be0055b8008060d000b0b00011c275c40285c60295c80015d601a) // quotient_program mstore(add(payload, 0x0b60), 0x5dc02a5de02b5e00105d80055da008060d000b0c0000090008105de0115de00d) // quotient_program mstore(add(payload, 0x0b80), 0x000b0c0001090008105c40115c400d000b0c0001090008105e00115e000d000b) // quotient_program mstore(add(payload, 0x0ba0), 0x0c00011c005ba0005bc0005c20005ca0005cc0005d20005d40055da0135e202c) // quotient_program diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index 3660c9092..e5f1b4029 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -321,7 +321,13 @@ contract Halo2Verifier { // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } let p := 0x1880 // EIP-198 modexp frame: @@ -458,6 +464,13 @@ contract Halo2Verifier { // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave @@ -504,6 +517,12 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0xa0), r) ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total @@ -528,14 +547,19 @@ contract Halo2Verifier { // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0300 + let scratch := 0x0320 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1385,7 +1409,14 @@ contract Halo2Verifier { { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0x5720, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 22) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) @@ -1943,6 +1974,12 @@ contract Halo2Verifier { // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0x59e0)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2648,6 +2685,12 @@ contract Halo2Verifier { // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index 41513989e..d0caa0941 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -321,7 +321,13 @@ contract Halo2Verifier { // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } let p := 0x15e0 // EIP-198 modexp frame: @@ -458,6 +464,13 @@ contract Halo2Verifier { // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave @@ -504,6 +517,12 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0xa0), r) ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total @@ -528,14 +547,19 @@ contract Halo2Verifier { // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0300 + let scratch := 0x0320 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1357,7 +1381,14 @@ contract Halo2Verifier { { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0x5060, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 15) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) @@ -1761,6 +1792,12 @@ contract Halo2Verifier { // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0x5240)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2251,6 +2288,12 @@ contract Halo2Verifier { // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 2e9d4419e..9a8fd44af 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -43,7 +43,7 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 8032; uint256 internal constant EXPECTED_VK_LENGTH = 8033; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x6200af6d8b2f00ac28582e3c159c74e3e43daf38a03210efc438aa723d3e98bc; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x327e3a0642d1a157521eb891596256086b59006348710f0cd960b89ed35e5854; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -321,7 +321,13 @@ contract Halo2Verifier { // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } let p := 0x1c20 // EIP-198 modexp frame: @@ -458,6 +464,13 @@ contract Halo2Verifier { // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave @@ -504,6 +517,12 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0xa0), r) ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total @@ -528,14 +547,19 @@ contract Halo2Verifier { // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0300 + let scratch := 0x0320 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1373,7 +1397,14 @@ contract Halo2Verifier { { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0x6d00, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 35) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) @@ -2323,6 +2354,12 @@ contract Halo2Verifier { // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0x7160)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2987,6 +3024,12 @@ contract Halo2Verifier { // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol index 0ee83d389..7b15639cf 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol @@ -116,19 +116,19 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x0660), 0x0000000000000000000000000000000000000000000000000000000000040011) // quotient_const mstore(add(payload, 0x0680), 0x0000000000000000000000000000000000000000000000000000001100000000) // quotient_const mstore(add(payload, 0x06a0), 0x0000000000000000000000000000000000000000000000000000000044000000) // quotient_const - mstore(add(payload, 0x06c0), 0x0000000000000000000000000000000000000000000000000000000000200000) // quotient_const - mstore(add(payload, 0x06e0), 0x0000000000000000000000000000000000000000000000000000000000000400) // quotient_const - mstore(add(payload, 0x0700), 0x0000000000000000000000000000000000000000000000000000000000400000) // quotient_const + mstore(add(payload, 0x06c0), 0x0000000000000000000000000000000000000000000000000000000000000400) // quotient_const + mstore(add(payload, 0x06e0), 0x0000000000000000000000000000000000000000000000000000000000200000) // quotient_const + mstore(add(payload, 0x0700), 0x0000000000000000000000000000000000000000000000000000000000000004) // quotient_const mstore(add(payload, 0x0720), 0x0000000000000000000000000000000000000000000000000000000000002000) // quotient_const - mstore(add(payload, 0x0740), 0x0000000000000000000000000000000000000000000000000000000000000004) // quotient_const - mstore(add(payload, 0x0760), 0x0000000000000000000000000000000000000000000000000000100000000000) // quotient_const + mstore(add(payload, 0x0740), 0x0000000000000000000000000000000000000000000000000000000000400000) // quotient_const + mstore(add(payload, 0x0760), 0x0000000000000000000000000000000000000000000000000000000000000010) // quotient_const mstore(add(payload, 0x0780), 0x0000000000000000000000000000000000000000000000000000000004000000) // quotient_const - mstore(add(payload, 0x07a0), 0x0000000000000000000000000000000000000000000000000000000000000010) // quotient_const - mstore(add(payload, 0x07c0), 0x0000000000000000000000000000000000000000000000000000000002000000) // quotient_const + mstore(add(payload, 0x07a0), 0x0000000000000000000000000000000000000000000000000000100000000000) // quotient_const + mstore(add(payload, 0x07c0), 0x0000000000000000000000000000000000000000000000000000000000000040) // quotient_const mstore(add(payload, 0x07e0), 0x0000000000000000000000000000000000000000000000000000000000000800) // quotient_const - mstore(add(payload, 0x0800), 0x0000000000000000000000000000000000000000000000000000000000000040) // quotient_const - mstore(add(payload, 0x0820), 0x0000000000000000000000000000000000000000000000000004000000000000) // quotient_const - mstore(add(payload, 0x0840), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x0800), 0x0000000000000000000000000000000000000000000000000000000002000000) // quotient_const + mstore(add(payload, 0x0820), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x0840), 0x0000000000000000000000000000000000000000000000000004000000000000) // quotient_const mstore(add(payload, 0x0860), 0x0000000000000000000000000000000000000000000000000000000000040000) // quotient_const mstore(add(payload, 0x0880), 0x0000000000000000000000000000000000000000000000000000000000000080) // quotient_const mstore(add(payload, 0x08a0), 0x0000000000000000000000000000000000000000000000000000000000000008) // quotient_const @@ -140,12 +140,12 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x0960), 0x08060d000b0400011b00021b0003210001000007000158200258400358600458) // quotient_program mstore(add(payload, 0x0980), 0x800558a00658c00758e00859000959800a59a00b59c00c59e00d5a000e5a200b) // quotient_program mstore(add(payload, 0x09a0), 0x070000210001000007000158200258400f58601058801158a00658c00758e012) // quotient_program - mstore(add(payload, 0x09c0), 0x59001359801459a00b59c00c59e0155a00165a200b0800000917115a40135940) // quotient_program - mstore(add(payload, 0x09e0), 0x18105a60055a8008060d000b0900000919115a40135aa01a1359401b10596005) // quotient_program - mstore(add(payload, 0x0a00), 0x5a8008060d000b0a0000091c1159c01359e01d1358201e10584005586008060d) // quotient_program - mstore(add(payload, 0x0a20), 0x000b0a0001091f115a40135aa01a1359402013596021105a60055a8008060d00) // quotient_program - mstore(add(payload, 0x0a40), 0x0b0b000009221159c01359e01d13582019135840231058c005586008060d000b) // quotient_program - mstore(add(payload, 0x0a60), 0x0b00011c245920255940265960275a40185aa0285ac0295ae0105a60055a8008) // quotient_program + mstore(add(payload, 0x09c0), 0x59001359801459a00b59c00c59e0155a00165a200b0800000918115a40135940) // quotient_program + mstore(add(payload, 0x09e0), 0x17105a60055a8008060d000b090000091b115a40135aa01a1359401910596005) // quotient_program + mstore(add(payload, 0x0a00), 0x5a8008060d000b0a0000091e1159c01359e01d1358201c10584005586008060d) // quotient_program + mstore(add(payload, 0x0a20), 0x000b0a00010921115a40135aa01a135940201359601f105a60055a8008060d00) // quotient_program + mstore(add(payload, 0x0a40), 0x0b0b000009231159c01359e01d1358201b135840221058c005586008060d000b) // quotient_program + mstore(add(payload, 0x0a60), 0x0b00011c245920255940265960275a40175aa0285ac0295ae0105a60055a8008) // quotient_program mstore(add(payload, 0x0a80), 0x060d000b0c0000090008105ac0115ac00d000b0c00010900081059201159200d) // quotient_program mstore(add(payload, 0x0aa0), 0x000b0c0001090008105ae0115ae00d000b0c00011c0058800058a00059000059) // quotient_program mstore(add(payload, 0x0ac0), 0x800059a0005a00005a20055a80135b002a08060d000b0d0000191f0000000000) // quotient_program From 54907b59709e04326a52837e54776901672df027 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:22:13 +0100 Subject: [PATCH 053/108] Reject an accumulator fixed-base tail the VK cannot supply bases for The accumulator's fixed-base scalar tail is derived from the *instance* vector: fixed_scalar_count = num_instances - (offset + fixed_payload). The bases those scalars multiply are generated from the *verifying key*, as fixed_comm_mptr + i * 0x80 for i in 0..num_fixed_bases, where num_fixed_bases = fixed_scalar_count - (1 + num_permutation_comms) Nothing bounded num_fixed_bases against the VK's actual fixed-commitment count. A tail longer than the VK can supply bases for rendered cleanly and emitted base pointers past the end of the fixed-commitment region, aliasing permutation commitments -- and past those, arbitrary VK payload words -- as accumulator G1 bases. The generated verifier then checks a different accumulator equation than the native verifier, so honest proofs fail on-chain and the drift is discovered only at proof time. The existing assert did not catch this: `bases.len() == fixed_scalar_count` is a tautology, since `bases` is built as `1 + num_fixed_bases + num_perm_bases` with num_fixed_bases defined by subtracting those same terms from fixed_scalar_count. It can never fire. (An earlier commit promoted it from debug_assert to assert, which changed when it runs but not what it can detect.) Reproduced against the Poseidon VK: num_instances chosen for a 32-scalar tail against a VK with 19 fixed and 8 permutation commitments rendered successfully with 23 fixed bases, i.e. 4 pointers into the permutation region. Validate in SolidityGenerator::try_new, where both the encoding and the VK are in scope and a typed error is already the contract. Two tail lengths are rejected: longer than `-G` + permutations + every fixed commitment (the out-of-region case above), and shorter than `-G` + permutations (which underflows the base count in the artifact emitter). A tail inside that range is accepted: it covers a prefix of the fixed commitments and keeps every pointer in region. Nothing documents whether a prefix is meaningful, but it is memory-safe, and rejecting it would invent a stricter contract than the emitter implies. Add GeneratorError::AccumulatorFixedBaseTailMismatch carrying the supported range and both commitment counts, so a misconfigured num_instances reports the values it should have had, and replace the tautological assert in artifacts.rs with a bound that actually constrains num_fixed_bases. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/api.rs | 33 ++++++++ proofs/solidity-verifier/src/builder/api.rs | 29 +++++++ .../src/lowering/artifacts.rs | 16 ++++ proofs/solidity-verifier/src/test.rs | 79 +++++++++++++++++++ 4 files changed, 157 insertions(+) diff --git a/proofs/solidity-verifier/src/api.rs b/proofs/solidity-verifier/src/api.rs index e4e6671a2..0cf0be6e1 100644 --- a/proofs/solidity-verifier/src/api.rs +++ b/proofs/solidity-verifier/src/api.rs @@ -458,6 +458,25 @@ pub enum GeneratorError { num_instances: usize, reason: &'static str, }, + /// The accumulator's fixed-base scalar tail asks for more bases than this + /// verifying key can supply. + /// + /// The tail must be empty (fully collapsed accumulator), or cover `-G` plus + /// every permutation commitment plus at most one scalar per fixed + /// commitment. + AccumulatorFixedBaseTailMismatch { + /// Tail scalars implied by `num_instances` and the encoding. + fixed_scalar_count: usize, + /// Smallest non-empty tail this verifying key supports (`-G` plus every + /// permutation commitment). + min_fixed_scalar_count: usize, + /// Largest tail this verifying key supports. + max_fixed_scalar_count: usize, + /// Fixed commitments in the verifying key. + num_fixed_comms: usize, + /// Permutation commitments in the verifying key. + num_permutation_comms: usize, + }, /// Internal render/layout planning failed before Solidity was emitted. Planning { /// Planning stage. @@ -510,6 +529,20 @@ impl fmt::Display for GeneratorError { f, "unsupported accumulator encoding: offset={offset}, num_limbs={num_limbs}, num_limb_bits={num_limb_bits}, num_instances={num_instances}; {reason}" ), + Self::AccumulatorFixedBaseTailMismatch { + fixed_scalar_count, + min_fixed_scalar_count, + max_fixed_scalar_count, + num_fixed_comms, + num_permutation_comms, + } => write!( + f, + "accumulator fixed-base scalar tail of {fixed_scalar_count} is not supported by \ + this verifying key ({num_fixed_comms} fixed, {num_permutation_comms} permutation \ + commitments): expected 0 (fully collapsed) or \ + {min_fixed_scalar_count}..={max_fixed_scalar_count}; adjust num_instances or the \ + accumulator offset" + ), Self::Planning { stage, message } => { write!(f, "generator planning failed during {stage}: {message}") } diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 52ae43f99..0f0869580 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -48,6 +48,35 @@ impl<'a> SolidityGenerator<'a> { )?; if let Some(acc_encoding) = config.accumulator { acc_encoding.validate_for_num_instances(config.num_instances)?; + // The fixed-base scalar tail is derived from the *instance* length, + // but the bases it multiplies come from this verifying key: `-G`, + // then `fixed_comm_mptr + i * G1_BYTES` per fixed base, then the + // permutation commitments. Two tail lengths break that mapping: + // + // * Too long: the generated fixed-base pointers run past the end + // of the fixed-commitment region, silently aliasing permutation + // commitments and then arbitrary VK payload words as G1 bases. + // * Shorter than `-G` plus the permutation commitments: the base + // count underflows in the artifact emitter. + // + // A tail inside the range is left alone -- it covers a prefix of + // the fixed commitments, which keeps every pointer in region. + let fixed_scalar_count = acc_encoding.fixed_scalar_count(config.num_instances)?; + let num_fixed_comms = vk.fixed_commitments().len(); + let num_permutation_comms = vk.permutation().commitments().len(); + let min_fixed_scalar_count = 1 + num_permutation_comms; + let max_fixed_scalar_count = min_fixed_scalar_count + num_fixed_comms; + if fixed_scalar_count != 0 + && !(min_fixed_scalar_count..=max_fixed_scalar_count).contains(&fixed_scalar_count) + { + return Err(GeneratorError::AccumulatorFixedBaseTailMismatch { + fixed_scalar_count, + min_fixed_scalar_count, + max_fixed_scalar_count, + num_fixed_comms, + num_permutation_comms, + }); + } } // Non-committed instance evaluations are reconstructed once from the // public-input polynomial at the current rotation. Reject rotated diff --git a/proofs/solidity-verifier/src/lowering/artifacts.rs b/proofs/solidity-verifier/src/lowering/artifacts.rs index 495795ba1..fa61fabf8 100644 --- a/proofs/solidity-verifier/src/lowering/artifacts.rs +++ b/proofs/solidity-verifier/src/lowering/artifacts.rs @@ -157,6 +157,19 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { let num_fixed_bases = fixed_scalar_count .checked_sub(1 + num_perm_bases) .expect("accumulator fixed scalar count is smaller than -G + permutations"); + // Each generated base below is `fixed_comm_mptr + i * 0x80`, + // so more bases than the VK has fixed commitments would + // point past the region into the permutation commitments + // and then the rest of the VK payload. SolidityGenerator:: + // try_new rejects this shape with a typed error; fail + // closed here too, since this is where the out-of-region + // pointers would actually be emitted. + assert!( + num_fixed_bases <= plan.vk.fixed_comms.len(), + "accumulator fixed-base count {num_fixed_bases} exceeds the VK \ + fixed-commitment region ({} commitments)", + plan.vk.fixed_comms.len() + ); std::iter::once(("-G".to_string(), g1_base_mptr_byte, true)) .chain((0..num_fixed_bases).map(|i| { @@ -175,6 +188,9 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { })) .collect::>() }; + // Holds by construction of `bases` above; kept as a cheap + // guard on the one-to-one correspondence with the scalars the + // generated verifier reads from calldata. assert_eq!( bases.len(), fixed_scalar_count, diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 6caf62614..5e492d48e 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1485,6 +1485,85 @@ fn compile_solidity_is_deterministic_for_same_source() { assert_eq!(bytecode_a, bytecode_b); } +/// The accumulator fixed-base scalar tail must match the verifying key. +/// +/// `fixed_scalar_count` is derived from `num_instances`, but the bases those +/// scalars multiply are generated as `fixed_comm_mptr + i * 0x80` from the VK. +/// A tail longer than the VK's fixed-commitment count used to render fine and +/// silently emit base pointers past that region, aliasing permutation +/// commitments -- and beyond them arbitrary VK payload words -- as accumulator +/// G1 bases. +#[test] +fn accumulator_fixed_base_tail_must_match_verifying_key() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let srs_dir = srs_dir(); + env::set_var("SRS_DIR", &srs_dir); + let relation = PoseidonExample; + let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let vk = setup_vk(&srs, &relation); + + let num_fixed_comms = vk.vk().fixed_commitments().len(); + let num_permutation_comms = vk.vk().permutation().commitments().len(); + let collapsed = AccumulatorEncoding::FULLY_COLLAPSED_PUBLIC_INPUT_WORDS; + // `-G` plus every permutation commitment, then up to one scalar per fixed + // commitment. + let min_tail = 1 + num_permutation_comms; + let max_tail = min_tail + num_fixed_comms; + + // A tail three scalars longer than the VK can supply bases for. Before the + // guard this rendered a verifier whose last three "fixed bases" were + // permutation commitments. + let err = SolidityGenerator::try_new( + &srs, + vk.vk(), + GeneratorConfig::new(collapsed + max_tail + 3, 1) + .with_accumulator(AccumulatorEncoding::new(0, 7, 56)), + ) + .expect_err("oversized accumulator fixed-base tail should be rejected"); + assert!( + matches!( + err, + crate::GeneratorError::AccumulatorFixedBaseTailMismatch { + fixed_scalar_count, + max_fixed_scalar_count, + .. + } if fixed_scalar_count == max_tail + 3 && max_fixed_scalar_count == max_tail + ), + "unexpected error for oversized tail: {err}" + ); + + // A tail too short to cover `-G` plus the permutation commitments would + // underflow the base count in the artifact emitter. + SolidityGenerator::try_new( + &srs, + vk.vk(), + GeneratorConfig::new(collapsed + min_tail - 1, 1) + .with_accumulator(AccumulatorEncoding::new(0, 7, 56)), + ) + .expect_err("undersized accumulator fixed-base tail should be rejected"); + + // Supported shapes still build: no tail at all, the full base set, and a + // prefix of the fixed commitments in between (every pointer stays inside + // the fixed-commitment region). + for num_instances in [ + collapsed, + collapsed + min_tail, + collapsed + max_tail, + collapsed + (min_tail + max_tail) / 2, + ] { + SolidityGenerator::try_new( + &srs, + vk.vk(), + GeneratorConfig::new(num_instances, 1) + .with_accumulator(AccumulatorEncoding::new(0, 7, 56)), + ) + .unwrap_or_else(|err| panic!("supported accumulator tail should build: {err}")); + } +} + /// Compile the accumulator render arm. /// /// No production fixture enables `with_accumulator`, so before this test the From bea362e787f4d65e90dfb873f36c535874e0e1eb Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:35:10 +0100 Subject: [PATCH 054/108] Fail loudly when the EVM gate is requested but cannot run Setting HALO2_SOLIDITY_RUN_EVM_TESTS=1 without the test SRS or the pinned solc used to print a "skipping ..." line and return, so the run reported every test green while compiling no Solidity and executing no proof. That is the worst possible outcome: the operator explicitly asked for the gate and got a silent no-op that is indistinguishable from a pass. This is not hypothetical. It is how the rendered fixture artifacts under target/*-fixture-dump/ drifted out of date across several commits with no test noticing, and how a round of verifier-template changes in this branch was initially reported as "validated by the full suite" when in fact 28 of the 34 end-to-end tests had returned early. Split the two cases that were conflated: * Not opting in stays a quiet skip. A fresh checkout without the 96 MB SRS still runs `cargo test` cleanly, which is why the skips exist. * Opting in and lacking a prerequisite is now a panic, with the fetch command for the SRS and the SOLC / allow-unpinned escape hatches for the compiler, so the message says how to fix it. Applied to both the in-crate gate helpers and the four fixture integration tests, which each carried their own copy of the skip logic. Verified all four paths: opted out passes quietly (189 tests, no EVM work); opted in with SRS and solc present passes for real; opted in with SRS_DIR pointing nowhere fails with fetch instructions; opted in with a bogus SOLC fails naming the pinned version. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/test.rs | 63 +++++++++++-------- .../tests/hybrid_mt_fixture.rs | 29 +++++---- .../tests/poseidon_fixture.rs | 30 +++++---- .../tests/rsa_signature_fixture.rs | 29 +++++---- .../tests/sha_preimage_fixture.rs | 29 +++++---- 5 files changed, 110 insertions(+), 70 deletions(-) diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 5e492d48e..f3b022548 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -62,6 +62,9 @@ type PoseidonVerifierParams = const POSEIDON_K: u32 = 6; /// Environment flag that opts into expensive EVM/Solidity integration tests. const RUN_EVM_TESTS_ENV: &str = "HALO2_SOLIDITY_RUN_EVM_TESTS"; +/// Source for the test SRS, as documented by `zk_stdlib`'s own loader error. +const SRS_DOWNLOAD_URL: &str = + "https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p19"; /// Minimal caller used to exercise the production verifier under STATICCALL. const STATICCALL_VERIFIER_HARNESS: &str = r#" // SPDX-License-Identifier: CC0-1.0 @@ -972,10 +975,9 @@ fn shape_fuzz_inputs_available_for_evm() -> bool { eprintln!("skipping supported-shape circuit fuzz: set {RUN_EVM_TESTS_ENV}=1 to run it"); return false; } - if !solc_available() { - eprintln!("skipping supported-shape circuit fuzz: solc not found"); - return false; - } + // Requested but unusable is a failure, not a skip. See + // `poseidon_inputs_available_for_evm`. + solc_available(); true } @@ -4131,13 +4133,13 @@ fn poseidon_inputs_available_for_evm() -> bool { eprintln!("skipping Poseidon Solidity property test: set {RUN_EVM_TESTS_ENV}=1 to run it"); return false; } - if !poseidon_srs_available() { - return false; - } - if !solc_available() { - eprintln!("skipping Poseidon Solidity property test: solc not found"); - return false; - } + // Past this point the gate was explicitly requested, so a missing + // prerequisite is a failure rather than a skip. Returning `false` here + // would report a green run that compiled no Solidity and executed no + // proof -- the failure mode that let the rendered fixture artifacts drift + // out of date across several commits without any test noticing. + poseidon_srs_available(); + solc_available(); true } @@ -4153,25 +4155,36 @@ fn env_flag_enabled(name: &str) -> bool { .unwrap_or(false) } -/// Return whether the Poseidon test SRS can be found on disk. -fn poseidon_srs_available() -> bool { +/// Require the Poseidon test SRS on disk. +/// +/// Only called once the EVM gate has been explicitly requested, so a missing +/// asset panics with fetch instructions instead of silently skipping. +fn poseidon_srs_available() { let srs_dir = PathBuf::from(srs_dir()); let exact_srs_path = srs_dir.join(format!("bls_filecoin_2p{POSEIDON_K}")); let fallback_srs_path = srs_dir.join("bls_filecoin_2p19"); - if !exact_srs_path.exists() && !fallback_srs_path.exists() { - eprintln!( - "skipping Poseidon Solidity property test: SRS not found at {} or {}", - exact_srs_path.display(), - fallback_srs_path.display() - ); - return false; - } - true + assert!( + exact_srs_path.exists() || fallback_srs_path.exists(), + "{RUN_EVM_TESTS_ENV}=1 requires the test SRS, but it was not found at {} or {}.\n\ + Fetch it with:\n curl -L -o {} {SRS_DOWNLOAD_URL}\n\ + or point SRS_DIR at an existing copy.", + exact_srs_path.display(), + fallback_srs_path.display(), + fallback_srs_path.display(), + ); } -/// Return whether the configured pinned solc is available. -fn solc_available() -> bool { - pinned_solc_available() +/// Require the pinned solc. +/// +/// Same contract as [`poseidon_srs_available`]: loud once the gate is on. +fn solc_available() { + assert!( + pinned_solc_available(), + "{RUN_EVM_TESTS_ENV}=1 requires solc {}, which was not found or did not match.\n\ + Install it, point SOLC at the binary, or set {}=1 to accept another version.", + crate::PINNED_SOLC_VERSION, + crate::ALLOW_UNPINNED_SOLC_ENV, + ); } /// Resolve the SRS directory used by fixture setup. diff --git a/proofs/solidity-verifier/tests/hybrid_mt_fixture.rs b/proofs/solidity-verifier/tests/hybrid_mt_fixture.rs index 4a94bbdd7..baaa8da6d 100644 --- a/proofs/solidity-verifier/tests/hybrid_mt_fixture.rs +++ b/proofs/solidity-verifier/tests/hybrid_mt_fixture.rs @@ -193,13 +193,17 @@ fn hybrid_mt_renders_compiles_and_verifies() { let srs_dir = srs_dir(); let srs_path = format!("{srs_dir}/bls_filecoin_2p{K}"); let fallback_srs_path = format!("{srs_dir}/bls_filecoin_2p19"); - if !Path::new(&srs_path).exists() && !Path::new(&fallback_srs_path).exists() { - eprintln!( - "skipping hybrid MT Solidity smoke: SRS not found at {srs_path} or \ - {fallback_srs_path}. Set SRS_DIR or fetch the asset under midfall/zk_stdlib." - ); - return; - } + // The gate was explicitly requested, so a missing asset fails rather than + // silently reporting a pass that rendered and compiled nothing. + assert!( + Path::new(&srs_path).exists() || Path::new(&fallback_srs_path).exists(), + "{RUN_EVM_TESTS_ENV}=1 requires the test SRS, but it was not found at {srs_path} or \ + {fallback_srs_path}. +Fetch it with: + curl -L -o {fallback_srs_path} \ + https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p19 +or point SRS_DIR at an existing copy." + ); env::set_var("SRS_DIR", &srs_dir); let relation = HybridMtCircuit; @@ -263,10 +267,13 @@ fn hybrid_mt_renders_compiles_and_verifies() { verifier_solidity.len() ); - if !pinned_solc_available() { - eprintln!("skipping hybrid MT EVM smoke: pinned solc not available"); - return; - } + assert!( + pinned_solc_available(), + "{RUN_EVM_TESTS_ENV}=1 requires the pinned solc, which was not found or did not match. +\ + Install it, point SOLC at the binary, or set \ + HALO2_SOLIDITY_ALLOW_UNPINNED_SOLC=1 to accept another version." + ); let vk_creation_code = compile_solidity(&vk_solidity); let verifier_creation_code = compile_solidity(&verifier_solidity); diff --git a/proofs/solidity-verifier/tests/poseidon_fixture.rs b/proofs/solidity-verifier/tests/poseidon_fixture.rs index 58bfe73a3..36092af7f 100644 --- a/proofs/solidity-verifier/tests/poseidon_fixture.rs +++ b/proofs/solidity-verifier/tests/poseidon_fixture.rs @@ -125,13 +125,17 @@ fn poseidon_renders_compiles_and_verifies() { let srs_dir = srs_dir(); let srs_path = format!("{srs_dir}/bls_filecoin_2p{K}"); let fallback_srs_path = format!("{srs_dir}/bls_filecoin_2p19"); - if !Path::new(&srs_path).exists() && !Path::new(&fallback_srs_path).exists() { - eprintln!( - "skipping poseidon end-to-end smoke: SRS not found at {srs_path} or {fallback_srs_path}. \ - Set SRS_DIR or fetch the asset under midfall/zk_stdlib." - ); - return; - } + // The gate was explicitly requested, so a missing asset fails rather than + // silently reporting a pass that rendered and compiled nothing. + assert!( + Path::new(&srs_path).exists() || Path::new(&fallback_srs_path).exists(), + "{RUN_EVM_TESTS_ENV}=1 requires the test SRS, but it was not found at {srs_path} or \ + {fallback_srs_path}. +Fetch it with: + curl -L -o {fallback_srs_path} \ + https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p19 +or point SRS_DIR at an existing copy." + ); env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; @@ -200,11 +204,13 @@ fn poseidon_renders_compiles_and_verifies() { verifier_solidity.len() ); - // Skip the EVM portion if the pinned solc is not available. - if !pinned_solc_available() { - eprintln!("skipping poseidon end-to-end smoke: pinned solc not available"); - return; - } + assert!( + pinned_solc_available(), + "{RUN_EVM_TESTS_ENV}=1 requires the pinned solc, which was not found or did not match. +\ + Install it, point SOLC at the binary, or set \ + HALO2_SOLIDITY_ALLOW_UNPINNED_SOLC=1 to accept another version." + ); let vk_creation_code = compile_solidity(&vk_solidity); let verifier_creation_code = compile_solidity(&verifier_solidity); diff --git a/proofs/solidity-verifier/tests/rsa_signature_fixture.rs b/proofs/solidity-verifier/tests/rsa_signature_fixture.rs index 132d1e4c0..f37cce3bc 100644 --- a/proofs/solidity-verifier/tests/rsa_signature_fixture.rs +++ b/proofs/solidity-verifier/tests/rsa_signature_fixture.rs @@ -103,13 +103,17 @@ fn rsa_signature_renders_compiles_and_verifies() { let srs_dir = srs_dir(); let srs_path = format!("{srs_dir}/bls_filecoin_2p{K}"); let fallback_srs_path = format!("{srs_dir}/bls_filecoin_2p19"); - if !Path::new(&srs_path).exists() && !Path::new(&fallback_srs_path).exists() { - eprintln!( - "skipping RSA signature Solidity smoke: SRS not found at {srs_path} or \ - {fallback_srs_path}. Set SRS_DIR or fetch the asset under midfall/zk_stdlib." - ); - return; - } + // The gate was explicitly requested, so a missing asset fails rather than + // silently reporting a pass that rendered and compiled nothing. + assert!( + Path::new(&srs_path).exists() || Path::new(&fallback_srs_path).exists(), + "{RUN_EVM_TESTS_ENV}=1 requires the test SRS, but it was not found at {srs_path} or \ + {fallback_srs_path}. +Fetch it with: + curl -L -o {fallback_srs_path} \ + https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p19 +or point SRS_DIR at an existing copy." + ); env::set_var("SRS_DIR", &srs_dir); let relation = RsaSignatureCircuit; @@ -172,10 +176,13 @@ fn rsa_signature_renders_compiles_and_verifies() { verifier_solidity.len() ); - if !pinned_solc_available() { - eprintln!("skipping RSA signature EVM smoke: pinned solc not available"); - return; - } + assert!( + pinned_solc_available(), + "{RUN_EVM_TESTS_ENV}=1 requires the pinned solc, which was not found or did not match. +\ + Install it, point SOLC at the binary, or set \ + HALO2_SOLIDITY_ALLOW_UNPINNED_SOLC=1 to accept another version." + ); let vk_creation_code = compile_solidity(&vk_solidity); let verifier_creation_code = compile_solidity(&verifier_solidity); diff --git a/proofs/solidity-verifier/tests/sha_preimage_fixture.rs b/proofs/solidity-verifier/tests/sha_preimage_fixture.rs index 573038809..3ef8529f2 100644 --- a/proofs/solidity-verifier/tests/sha_preimage_fixture.rs +++ b/proofs/solidity-verifier/tests/sha_preimage_fixture.rs @@ -82,13 +82,17 @@ fn sha_preimage_renders_compiles_and_verifies() { let srs_dir = srs_dir(); let srs_path = format!("{srs_dir}/bls_filecoin_2p{K}"); let fallback_srs_path = format!("{srs_dir}/bls_filecoin_2p19"); - if !Path::new(&srs_path).exists() && !Path::new(&fallback_srs_path).exists() { - eprintln!( - "skipping SHA preimage Solidity smoke: SRS not found at {srs_path} or \ - {fallback_srs_path}. Set SRS_DIR or fetch the asset under midfall/zk_stdlib." - ); - return; - } + // The gate was explicitly requested, so a missing asset fails rather than + // silently reporting a pass that rendered and compiled nothing. + assert!( + Path::new(&srs_path).exists() || Path::new(&fallback_srs_path).exists(), + "{RUN_EVM_TESTS_ENV}=1 requires the test SRS, but it was not found at {srs_path} or \ + {fallback_srs_path}. +Fetch it with: + curl -L -o {fallback_srs_path} \ + https://midnight-s3-fileshare-dev-eu-west-1.s3.eu-west-1.amazonaws.com/bls_filecoin_2p19 +or point SRS_DIR at an existing copy." + ); env::set_var("SRS_DIR", &srs_dir); let relation = ShaPreimageCircuit; @@ -152,10 +156,13 @@ fn sha_preimage_renders_compiles_and_verifies() { verifier_solidity.len() ); - if !pinned_solc_available() { - eprintln!("skipping SHA preimage EVM smoke: pinned solc not available"); - return; - } + assert!( + pinned_solc_available(), + "{RUN_EVM_TESTS_ENV}=1 requires the pinned solc, which was not found or did not match. +\ + Install it, point SOLC at the binary, or set \ + HALO2_SOLIDITY_ALLOW_UNPINNED_SOLC=1 to accept another version." + ); let vk_creation_code = compile_solidity(&vk_solidity); let verifier_creation_code = compile_solidity(&verifier_solidity); From 9e714b7c61736d4bbce5879d53c028c54cea20a9 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:49:58 +0100 Subject: [PATCH 055/108] Require the pairing precompile to return exactly one `ec_pairing` folded the precompile result into its success flag with `ret := and(ret, mload(scratch))`. Because `ret` is already reduced to 0 or 1 by the preceding `returndatasize` check, the bitwise `and` against the full 32-byte result word only tests that word's low bit -- so any odd return value was accepted as a successful pairing, not just the canonical 1. A conformant EIP-2537 pairing precompile returns exactly 0 or 1, so this is hardening rather than a live break. It is worth closing anyway: the threat model explicitly warns that deployers on L2s and alt-EVMs must run their own conformance tests, and the codebase was already inconsistent with itself -- the constructor smoke test in PrecompileSmoke.sol uses the strict `eq(mload(scratch), 1)` form. Compare against 1 in the helper too, and update the template assertion in `production_verifier_documents_revert_or_true_policy`, which pinned the old expression verbatim. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/lowering/tests.rs | 2 +- .../templates/partials/verifier/AssemblyHelpers.yul | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 39551dfb1..942280109 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1793,7 +1793,7 @@ fn production_verifier_documents_revert_or_true_policy() { && verifier_template .contains("ret := success\n if iszero(ret) { leave }") && verifier_template.contains( - "ret := and(ret, mload(scratch))\n if iszero(ret) { revert(0, 0) }\n ret := 1", + "ret := and(ret, eq(mload(scratch), 1))\n if iszero(ret) { revert(0, 0) }\n ret := 1", ), "final pairing helper must revert on pairing failure and normalize success to one" ); diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index 43c77cfe7..589fe1273 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -250,7 +250,11 @@ mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } From 72bc1b2d02df1f43874b72721a6f263ca921f37e Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:50:08 +0100 Subject: [PATCH 056/108] Fix an always-false guard in the accumulator limb decoder `load_acc_coord_shifted` stripped the identity flag from the first packed word under the guard: if and(iszero(div(i, limbs_per_word)), first_adjust) Yul's `and` is bitwise, not logical. `iszero(...)` yields 0 or 1, while `first_adjust` is either 0 or a radix base -- 2^56 for the current BLS12-381 self-emulation parameters. `1 & 2^56` is 0, so the guard was false on every call and `packed := sub(packed, first_adjust)` never executed. The parameter was entirely inert. The visible consequence is that the identity probe in `load_acc_coord` never removed the flag before testing for p-1, so `is_id` was always 0 and the `if is_id` branch in `load_acc_point` was dead. Infinity was still accepted, via the separate canonical constant comparison in `is_acc_encoded_identity`, and a flag-carrying x that did not match that quadruple decoded to (p-1) + 2^56 and failed the base-field range check. So the decoder was fail-closed throughout and no forgery was reachable. What was broken is the canonicality barrier the comment above `is_acc_encoded_identity` claims to enforce -- a barrier that exists so the on-chain verifier need not rely on circuit-side reasoning it cannot itself check. Gate on the word index alone. Subtracting `first_adjust` is already a no-op when it is zero, so the second conjunct was never needed. Co-Authored-By: Claude Opus 4.8 --- .../templates/partials/verifier/AccumulatorHelpers.yul | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul index b0f088d47..448df6991 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul @@ -25,7 +25,13 @@ // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div From 58824e8b30a17d6eec8310eb7e957655ac1607d5 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:55:31 +0100 Subject: [PATCH 057/108] Report unsupported constraint systems from try_new instead of panicking `SolidityGenerator::try_new` documents itself as "returning a typed error when the supplied constraint system is outside the currently supported Midfall verifier shape", and exists precisely so callers can avoid `new`'s panic. It did not hold up its end. After its own checks, try_new called `ConstraintSystemMeta::new`, which reaches `ProtocolPlan::from_constraint_system` and ends in: plan.validate().unwrap_or_else(|err| panic!("invalid protocol plan: {err}")); `ProtocolPlan::validate` has roughly twenty `return Err(...)` arms, every one of which became a panic on the supposedly panic-free path. The most reachable is the absorbed-but-unopened advice check: `advice_indices` has an entry per declared advice column while `advice_queries` holds only the queried ones, so a circuit that calls `cs.advice_column()` without ever querying it -- an ordinary authoring mistake -- panicked inside try_new. The exposure is the opposite way round from what one might assume: `SolidityGenerator::new` has no non-test callers, so its deliberate panic is not on a production path, while try_new is. Split each layer into a fallible variant and a panicking wrapper: `ProtocolPlan::try_from_constraint_system`, `ConstraintSystemMeta::try_new`. try_new now maps the failure onto the existing `GeneratorError::Planning` variant with stage "constraint system"; `new` and the protocol-level tests keep the old panicking entry points, so no caller changes. Adds `generator_reports_unopened_advice_column_as_typed_error`, which builds a VK from a circuit declaring an advice column it never queries and asserts a typed error rather than a panic. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/builder/api.rs | 12 +++- .../src/lowering/abi/proof.rs | 6 +- .../src/lowering/encoding/mod.rs | 18 ++++- proofs/solidity-verifier/src/lowering/plan.rs | 8 +-- .../src/lowering/protocol/mod.rs | 22 ++++++- .../src/lowering/quotient_numerator/vm/mod.rs | 15 ++++- .../solidity-verifier/src/lowering/tests.rs | 66 ++++++++++++++++++- proofs/solidity-verifier/src/test.rs | 5 +- 8 files changed, 129 insertions(+), 23 deletions(-) diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 0f0869580..6eee59cb2 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -93,7 +93,17 @@ impl<'a> SolidityGenerator<'a> { }); } - let meta = ConstraintSystemMeta::new(vk.cs(), config.num_committed_instances); + // Fallible: `ProtocolPlan::validate` rejects a range of unsupported + // constraint-system shapes -- an advice column that is absorbed but + // never opened by a PCS query being the most reachable authoring + // mistake. Panicking here would break this constructor's contract of + // reporting such shapes as a typed error. + let meta = ConstraintSystemMeta::try_new(vk.cs(), config.num_committed_instances).map_err( + |message| GeneratorError::Planning { + stage: "constraint system", + message, + }, + )?; Ok(Self { params, diff --git a/proofs/solidity-verifier/src/lowering/abi/proof.rs b/proofs/solidity-verifier/src/lowering/abi/proof.rs index e998770ca..4a8d061d4 100644 --- a/proofs/solidity-verifier/src/lowering/abi/proof.rs +++ b/proofs/solidity-verifier/src/lowering/abi/proof.rs @@ -514,8 +514,7 @@ mod tests { let protocol = protocol_shape(vec![1, 9], vec![], 0, 0, 1); let proof = ProofCalldataLayout::from_protocol(&protocol, 0, 12, 2); let num_instances = 86; - let transcript = - TranscriptBufferLayout::from_proof_layout(&proof, num_instances, &[0, 1]); + let transcript = TranscriptBufferLayout::from_proof_layout(&proof, num_instances, &[0, 1]); let word = layout::transcript::WORD_ABSORB_BYTES; let g1 = layout::transcript::G1_ABSORB_BYTES; @@ -524,8 +523,7 @@ mod tests { // Bytes actually absorbed before the first squeeze: vk_digest, // committed_pi, num_instances length word, instance words, then BOTH // phases' advices (phase 0 owns no challenge). - let true_initial_run = - word + g1 + word + num_instances * word + (1 + 9) * g1; + let true_initial_run = word + g1 + word + num_instances * word + (1 + 9) * g1; assert!( transcript.words * WORD_BYTES >= true_initial_run, "reserved {} bytes < true pre-squeeze run {}", diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index ec7e2f086..a2ec9c7f4 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -138,10 +138,22 @@ impl ConstraintSystemMeta { /// verifier *reads* from the proof transcript (vs. computes locally /// via Lagrange interpolation). For the poseidon example this is 0; /// for IVC-style fixtures with committed inputs it would be > 0. + /// + /// Panics if the constraint system is outside the supported verifier shape. + /// Use [`ConstraintSystemMeta::try_new`] on fallible paths. pub(crate) fn new(cs: &ConstraintSystem, nb_committed_instances: usize) -> Self { - let protocol = ProtocolPlan::from_constraint_system(cs, nb_committed_instances); + Self::try_new(cs, nb_committed_instances) + .unwrap_or_else(|err| panic!("invalid protocol plan: {err}")) + } - Self { + /// Fallible counterpart of [`ConstraintSystemMeta::new`]. + pub(crate) fn try_new( + cs: &ConstraintSystem, + nb_committed_instances: usize, + ) -> Result { + let protocol = ProtocolPlan::try_from_constraint_system(cs, nb_committed_instances)?; + + Ok(Self { protocol: protocol.clone(), num_fixeds: protocol.num_fixeds, permutation_columns: protocol.permutation_columns.clone(), @@ -164,7 +176,7 @@ impl ConstraintSystemMeta { advice_indices: protocol.advice_indices.clone(), challenge_indices: protocol.challenge_indices.clone(), rotation_last: protocol.rotation_last, - } + }) } /// Check legacy scalar fields against the typed protocol plan. diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index b98e7290b..f8aaea1ad 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -297,11 +297,9 @@ impl LoweringPlan { } } if let Some(program_offset) = self.vk.quotient_program_offset_words { - let build_words = layout::vk_payload::PackedProgramCodec::encode_words( - &self.quotient.build.bytes, - ); - let embedded = - &self.vk.constants[program_offset..program_offset + build_words.len()]; + let build_words = + layout::vk_payload::PackedProgramCodec::encode_words(&self.quotient.build.bytes); + let embedded = &self.vk.constants[program_offset..program_offset + build_words.len()]; if embedded.iter().map(|(_, value)| value).ne(build_words.iter()) { return Err( "quotient program bytecode embedded in the VK payload does not match the \ diff --git a/proofs/solidity-verifier/src/lowering/protocol/mod.rs b/proofs/solidity-verifier/src/lowering/protocol/mod.rs index a035abaf5..41f004e59 100644 --- a/proofs/solidity-verifier/src/lowering/protocol/mod.rs +++ b/proofs/solidity-verifier/src/lowering/protocol/mod.rs @@ -324,10 +324,28 @@ impl ProtocolPlan { /// passed to `partially_evaluate_identities` and KZG `multi_prepare`. /// The plan preserves that order so the Solidity transcript and proof /// cursors stay byte-compatible with the Rust verifier. + /// + /// Panics if the resulting plan fails [`ProtocolPlan::validate`]. Callers on + /// a fallible path — notably [`SolidityGenerator::try_new`], which promises + /// a typed error for unsupported constraint systems — must use + /// [`ProtocolPlan::try_from_constraint_system`] instead. pub(crate) fn from_constraint_system( cs: &ConstraintSystem, nb_committed_instances: usize, ) -> Self { + Self::try_from_constraint_system(cs, nb_committed_instances) + .unwrap_or_else(|err| panic!("invalid protocol plan: {err}")) + } + + /// Fallible counterpart of [`ProtocolPlan::from_constraint_system`]. + /// + /// Returns the validation failure rather than panicking, so constraint + /// systems outside the supported verifier shape can be surfaced as a typed + /// error at the public API boundary. + pub(crate) fn try_from_constraint_system( + cs: &ConstraintSystem, + nb_committed_instances: usize, + ) -> Result { let cs_degree = cs.degree(); let num_fixeds = cs.num_fixed_columns(); let permutation_columns = cs.permutation().get_columns(); @@ -610,8 +628,8 @@ impl ProtocolPlan { common_polys, quotient, }; - plan.validate().unwrap_or_else(|err| panic!("invalid protocol plan: {err}")); - plan + plan.validate()?; + Ok(plan) } /// Number of scalar evaluations in the proof's main eval block. diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 4c3600660..3c26bee4b 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2083,14 +2083,20 @@ pub(crate) fn validate_quotient_const_slots(bytes: &[u8], const_len: usize) -> R check(bytes[idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; } Q_OP_ADD_MUL_MEM_MEM_CONST_U8 => { - check(bytes[idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + check( + bytes[idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, + idx, + )?; } Q_OP_RUN_ADD_MUL_CONST_U8_MEM_U16 => { let count = read_u16(bytes, idx + 1) as usize; let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; let stride = QUOTIENT_VM_BYTE_U16_BYTES + 1; for k in 0..count { - check(bytes[base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + check( + bytes[base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES] as usize, + idx, + )?; } } Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8 => { @@ -2098,7 +2104,10 @@ pub(crate) fn validate_quotient_const_slots(bytes: &[u8], const_len: usize) -> R let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; let stride = 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; for k in 0..count { - check(bytes[base + k * stride + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, idx)?; + check( + bytes[base + k * stride + 2 * QUOTIENT_VM_BYTE_U16_BYTES] as usize, + idx, + )?; } } Q_OP_LIN7 => { diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 942280109..b720000eb 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -345,6 +345,67 @@ fn generator_rejects_rotated_non_committed_instance_queries() { )); } +/// Declares two advice columns but queries only one, so the second is absorbed +/// into the transcript without ever being opened by a PCS query. +struct UnopenedAdviceColumnCircuit; + +impl Circuit for UnopenedAdviceColumnCircuit { + type Config = (); + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let advice = meta.advice_column(); + // Declared and committed, but never queried: this is the shape + // `ProtocolPlan::validate` rejects. + let _unopened = meta.advice_column(); + let committed_instance = meta.instance_column(); + let public_instance = meta.instance_column(); + + meta.create_gate("unopened advice", |meta| { + let advice = meta.query_advice(advice, Rotation::cur()); + let committed = meta.query_instance(committed_instance, Rotation::cur()); + let public = meta.query_instance(public_instance, Rotation::cur()); + Constraints::without_selector(vec![("unopened advice", advice + committed + public)]) + }); + } + + fn synthesize( + &self, + _config: Self::Config, + _layouter: impl Layouter, + ) -> Result<(), PlonkError> { + Ok(()) + } +} + +/// `try_new` documents a typed error for unsupported constraint systems, so an +/// unopened advice column must not reach the `panic!` inside +/// `ProtocolPlan::from_constraint_system`. +#[test] +fn generator_reports_unopened_advice_column_as_typed_error() { + let mut rng = ChaCha8Rng::seed_from_u64(8); + let params = ParamsKZG::::unsafe_setup(4, &mut rng); + let circuit = UnopenedAdviceColumnCircuit; + let vk = keygen_vk_with_k::, _>(¶ms, &circuit, 4) + .expect("test circuit VK should build"); + + let err = SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(1, 1)) + .expect_err("unopened advice column is outside the supported verifier shape"); + let GeneratorError::Planning { stage, message } = err else { + panic!("expected a planning error, got {err:?}"); + }; + assert_eq!(stage, "constraint system"); + assert!( + message.contains("absorbed but never opened"), + "error should name the unopened advice column, got {message}" + ); +} + #[test] fn scalar_le_to_be_word_reverses_exactly_one_word() { let mut le = [0u8; 32]; @@ -2486,7 +2547,10 @@ fn quotient_vm_limb_decomposition_survives_const_table_overflow() { expr, // Coefficient `k + 2` keeps every term scaled (coeff 1 would drop the // constant) and distinct, so the table grows one slot per term. - quotient_scale_expr(Fq::from(k as u64 + 2), QuotientExpr::Mem(QuotientMem::Literal(ptr))), + quotient_scale_expr( + Fq::from(k as u64 + 2), + QuotientExpr::Mem(QuotientMem::Literal(ptr)), + ), ); } diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index f3b022548..a47e14ab6 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1664,10 +1664,7 @@ fn accumulator_verifier_variants_compile_with_pinned_solc() { (name, verifier.as_str()), ( "accumulator VK", - artifacts - .verifying_key - .as_deref() - .expect("separate render includes VK"), + artifacts.verifying_key.as_deref().expect("separate render includes VK"), ), ] { let bytecode = std::panic::catch_unwind(AssertUnwindSafe(|| compile_solidity(source))) From 75f9f992317a86e54d3fcbcad6256ab465508e72 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 01:59:21 +0100 Subject: [PATCH 058/108] Bound the public instance count at generator construction The Lagrange block writes its batch-inversion input run in place from X_N_MPTR, and the run is num_instances + abs(rotation_last) + 1 words long. Nothing in `GeneratorConfig` or `SolidityGenerator::try_new` placed any upper bound on `config.num_instances`, so an oversized count was carried all the way into layout planning. The overrun itself was already caught -- `VerifierMemoryLayout::validate` has a dedicated cap check for this run against the first memory that is live when Lagrange executes (the q_eval calldata cursor, the G1 identity slot, and the decoded evaluations). So this was never a memory-safety hole. What was wrong is where the failure surfaced: a caller passing too many public inputs got an error phrased in theta-word offsets from deep inside layout planning, rather than a typed rejection from the constructor whose job is to validate the requested shape. The asymmetry made the gap easy to miss: `transcript_buffer_layout_for_meta` explicitly sizes the transcript buffer for arbitrary `num_instances`, so large public-input counts look supported, while the Lagrange window silently is not. Reject the count in `try_new` with a new `GeneratorError::TooManyInstances` carrying the requested count, the maximum, and the rotation contribution. The check must sit after `meta` is built, since `rotation_last` is only known then. To keep the early bound and the layout check from drifting apart, both now derive from one source: `batch_invert_input_words` for the run length and a new `theta_window::LAGRANGE_RUN_CAP_WORDS` for the cap. The existing layout test asserts the constant equals the window-derived value. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/api.rs | 24 +++++++++++++++ proofs/solidity-verifier/src/builder/api.rs | 18 ++++++++++++ .../src/lowering/layout/memory.rs | 6 +++- .../src/lowering/layout/mod.rs | 19 ++++++++++++ .../solidity-verifier/src/lowering/tests.rs | 29 +++++++++++++++++++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/api.rs b/proofs/solidity-verifier/src/api.rs index 0cf0be6e1..e2213b9eb 100644 --- a/proofs/solidity-verifier/src/api.rs +++ b/proofs/solidity-verifier/src/api.rs @@ -477,6 +477,19 @@ pub enum GeneratorError { /// Permutation commitments in the verifying key. num_permutation_comms: usize, }, + /// The public instance count pushes the Lagrange batch-inversion input run + /// past the verifier memory that is already live when Lagrange executes. + /// + /// The run is written in place from `X_N_MPTR` and is + /// `num_instances + abs(rotation_last) + 1` words long. + TooManyInstances { + /// Requested public instance count. + num_instances: usize, + /// Largest public instance count this constraint system can support. + max_num_instances: usize, + /// Negative-row denominators contributed by `rotation_last`. + rotation_last_words: usize, + }, /// Internal render/layout planning failed before Solidity was emitted. Planning { /// Planning stage. @@ -543,6 +556,17 @@ impl fmt::Display for GeneratorError { {min_fixed_scalar_count}..={max_fixed_scalar_count}; adjust num_instances or the \ accumulator offset" ), + Self::TooManyInstances { + num_instances, + max_num_instances, + rotation_last_words, + } => write!( + f, + "public instance count {num_instances} is too large: the Lagrange \ + batch-inversion run writes num_instances + {rotation_last_words} + 1 words from \ + X_N_MPTR and would overrun verifier memory that is live at that point; \ + the maximum for this constraint system is {max_num_instances}" + ), Self::Planning { stage, message } => { write!(f, "generator planning failed during {stage}: {message}") } diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 6eee59cb2..7afc789f9 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -6,6 +6,7 @@ //! stable caller-facing knobs before lower-level generation starts. use super::*; +use crate::lowering::layout::{memory::batch_invert_input_words, theta_window}; impl<'a> SolidityGenerator<'a> { /// Number of committed instance columns supported by the generated ABI. @@ -105,6 +106,23 @@ impl<'a> SolidityGenerator<'a> { }, )?; + // Bound the public instance count here rather than leaving it to + // `VerifierMemoryLayout::validate`. The Lagrange block writes its + // batch-inversion input run in place from `X_N_MPTR`, and that run + // grows with `num_instances`; the layout does catch an overrun, but + // only much later and phrased in theta-word offsets. `rotation_last` + // is only known once `meta` is built, hence the position of this check. + let run_words = batch_invert_input_words(&meta, config.num_instances); + if run_words > theta_window::LAGRANGE_RUN_CAP_WORDS { + let rotation_last_words = meta.rotation_last.unsigned_abs() as usize; + return Err(GeneratorError::TooManyInstances { + num_instances: config.num_instances, + max_num_instances: theta_window::LAGRANGE_RUN_CAP_WORDS + .saturating_sub(rotation_last_words + 1), + rotation_last_words, + }); + } + Ok(Self { params, vk, diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index fe3efd00c..07cdcede6 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -1150,7 +1150,7 @@ pub(crate) fn commitment_g1_count(meta: &ConstraintSystemMeta) -> usize { /// there are no public instances; /// - `abs(rotation_last)` negative-row denominators; /// - x_n - 1. -fn batch_invert_input_words(meta: &ConstraintSystemMeta, num_instances: usize) -> usize { +pub(crate) fn batch_invert_input_words(meta: &ConstraintSystemMeta, num_instances: usize) -> usize { if num_instances == 0 { meta.rotation_last.unsigned_abs() as usize + 2 } else { @@ -1707,6 +1707,10 @@ mod tests { .min(windows.g1_identity_word) .min(windows.reversed_evals_word) - ThetaSlot::XN.word(); + // `SolidityGenerator::try_new` rejects oversized instance counts up + // front against the constant form of this cap. The two must agree, or + // the early bound and the layout check would disagree about what fits. + assert_eq!(cap_words, theta_window::LAGRANGE_RUN_CAP_WORDS); // Largest instance count whose denominator run plus `x_n - 1` still // fits below the q_eval calldata cursor: num + |rotation_last| + 1. diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 59bc19f1e..a84bc8236 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -602,6 +602,25 @@ pub(crate) mod theta_window { /// Word offset where reversed proof evaluations begin. pub(crate) const REVERSED_EVALS_WORD: usize = G1_IDENTITY_WORD + G1_WORDS + G1_IDENTITY_PADDING_WORDS; + + /// Largest Lagrange batch-inversion input run that fits below live memory. + /// + /// The run starts in place at `X_N_MPTR` and deliberately spills past the + /// theta band into the rot_points / x1_powers / q_eval_set windows, which + /// are written only after the Lagrange phase. The first words that are + /// already live when Lagrange runs are the q_eval calldata cursor, the G1 + /// identity slot (which must stay virgin zero memory), and the decoded + /// proof evaluations, so the run must end at or before the lowest of those. + pub(crate) const LAGRANGE_RUN_CAP_WORDS: usize = { + let mut cap = Q_EVAL_CPTR_WORD; + if G1_IDENTITY_WORD < cap { + cap = G1_IDENTITY_WORD; + } + if REVERSED_EVALS_WORD < cap { + cap = REVERSED_EVALS_WORD; + } + cap - ThetaSlot::XN.word() + }; } pub(crate) mod trace { diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index b720000eb..8a9942630 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -448,6 +448,35 @@ fn external_quotient_output_uses_planned_return_buffer() { ); } +/// The Lagrange denominator run grows with `num_instances`, so an oversized +/// instance count must be rejected at construction with a typed error rather +/// than surfacing later as a memory-layout failure. +#[test] +fn generator_rejects_instance_counts_that_overrun_the_lagrange_run() { + let (params, vk) = lowering_plan_test_vk(); + let meta = ConstraintSystemMeta::new(vk.cs(), 1); + let rotation_last_words = meta.rotation_last.unsigned_abs() as usize; + let max_num_instances = + crate::lowering::layout::theta_window::LAGRANGE_RUN_CAP_WORDS - rotation_last_words - 1; + + SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(max_num_instances, 1)) + .expect("the largest fitting instance count must still be accepted"); + + let err = + SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(max_num_instances + 1, 1)) + .expect_err("one instance past the cap must be rejected"); + assert!( + matches!( + err, + GeneratorError::TooManyInstances { + max_num_instances: reported, + .. + } if reported == max_num_instances + ), + "unexpected error: {err:?}" + ); +} + #[test] fn lowering_plan_reuses_stable_layout_facts() { let (params, vk) = lowering_plan_test_vk(); From 06e46be52e1879ebea213a3bce05a1c904ccde7d Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 02:02:12 +0100 Subject: [PATCH 059/108] Pin the phase ordering the Lagrange denominator cap depends on The Lagrange batch-inversion input run is written in place from X_N_MPTR and is longer than the 26 words between X_N_MPTR and ROT_POINTS_MPTR -- in the shipped moonlight-wrap render it spans [0x6cc0, 0x7080), four words past ROT_POINTS_MPTR. That is intentional, not an overrun: the rot_points, x1_powers and q_eval_set windows are written only in later phases, so `VerifierMemoryLayout::validate` caps the run against the first memory that is genuinely live at Lagrange time -- the q_eval calldata cursor, the G1 identity slot, and the decoded evaluations. The run is deliberately not registered as a `MemoryRegion`: doing so would make the arena's overlap loop report overlaps that are correct by phase ordering. The cost is that nothing mechanically enforces the ordering the cap relies on. It rested entirely on a source comment, so moving a rot_points access earlier would silently either clobber the denominators mid-flight or read their leftovers -- with no codegen error and no failing test. Add `rot_points_window_is_written_after_the_lagrange_denominator_run`, which renders verifier source and asserts the first ROT_POINTS_MPTR access -- read or write -- occurs after the Lagrange batch_invert call. State the invariant explicitly at the cap check and point it at the test. No behaviour change; this closes the enforcement gap, not a live defect. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/layout/memory.rs | 8 ++++ .../solidity-verifier/src/lowering/tests.rs | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 07cdcede6..b91c70f1d 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -1110,6 +1110,14 @@ impl VerifierMemoryLayout { // that are already live at Lagrange time are the q_eval calldata // cursor (written by the proof parser), the G1 identity slot (must // stay virgin zero memory), and the decoded proof evaluations. + // + // INVARIANT: this cap is sound only while rot_points, x1_powers and + // q_eval_set are first touched *after* the Lagrange phase. The arena's + // overlap loop cannot enforce that, because the run is not a + // registered region -- registering it would report overlaps that are + // correct by phase ordering. The ordering is pinned instead by + // `rot_points_window_is_written_after_the_lagrange_denominator_run`, + // which asserts it against rendered verifier source. let lagrange_run_end = ThetaSlot::XN.word() + self.batch_invert_input_words; let lagrange_run_cap = windows .q_eval_cptr_word diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 8a9942630..75290e373 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -448,6 +448,44 @@ fn external_quotient_output_uses_planned_return_buffer() { ); } +/// The Lagrange denominator run is deliberately allowed to spill out of the +/// theta band into the rot_points / x1_powers / q_eval_set windows, so +/// `VerifierMemoryLayout::validate` caps it against the *live* boundary +/// (`Q_EVAL_CPTR_MPTR`) rather than against `ROT_POINTS_MPTR`. That is only +/// sound while those three windows are written strictly after the Lagrange +/// phase and never read before being rewritten. +/// +/// Because the run is not registered as a `MemoryRegion` -- registering it +/// would report overlaps that are correct by phase ordering -- the arena's +/// overlap loop cannot enforce this. Pin the ordering here instead, so moving +/// a rot_points write earlier fails a test rather than silently corrupting the +/// denominators. +#[test] +fn rot_points_window_is_written_after_the_lagrange_denominator_run() { + let (params, vk) = lowering_plan_test_vk(); + let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); + let source = generator + .render(crate::RenderOptions::default()) + .expect("test verifier should render") + .verifier; + + let lagrange_end = source + .find("batch_invert(success, X_N_MPTR") + .expect("Lagrange block must call batch_invert over the denominator run"); + // Any access at all, read or write: the run leaves garbage in this window, + // so an early read is as wrong as an early write being clobbered. + let first_rot_points_access = source + .find("add(ROT_POINTS_MPTR") + .expect("verifier must access the rot_points window"); + + assert!( + first_rot_points_access > lagrange_end, + "ROT_POINTS_MPTR is accessed at byte {first_rot_points_access}, before the Lagrange \ + batch_invert at byte {lagrange_end}; the denominator run spills into that window, so \ + touching it earlier would either corrupt the denominators or read their leftovers" + ); +} + /// The Lagrange denominator run grows with `num_instances`, so an oversized /// instance count must be rejected at construction with a typed error rather /// than surfacing later as a memory-layout failure. From 896fd04efed9eb8c676be2facec91277e9be3c17 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 02:15:21 +0100 Subject: [PATCH 060/108] Add a known-answer vector to the EIP-2537 constructor smoke test Every EIP-2537 probe in `require_eip2537_precompiles` used the all-zero point-at-infinity encoding: G1ADD(identity, identity), a worst-case G1MSM with all-zero terms, and PAIRING_CHECK over identity pairs. The identity is the one input a precompile can answer correctly without performing any curve arithmetic, so an implementation that simply returns zeros satisfies the G1ADD and G1MSM probes. The soundness-relevant part is narrower and worse: the identity is also the one input on which an implementation that omits the EIP-2537 subgroup check still returns the right answer, and the production verifier leans on G1MSM precisely as its subgroup validator for absorbed commitments. A chain whose G1MSM is present and correctly sized but subgroup-check-less would deploy without complaint and then accept proofs carrying off-subgroup points. Add a G1ADD(G, G) == 2G probe, which no stub can satisfy by echoing its input or returning a constant. The vectors are computed from the curve library at render time rather than hardcoded, and emitted as literals so the deploy cost stays a handful of mstores. Note this narrows but does not close the gap: the pairing and MSM probes are still identity-only, so a subgroup-check-less G1MSM would still pass. Closing that needs an off-subgroup negative vector, which is a larger change. Verified against revm's real EIP-2537 implementation: the constructor deploys, and `verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles` still rejects misrouted precompiles. A full `--features evm` run shows no test regressing relative to 2c77051. `constructor_known_answer_vector_is_the_generator_and_its_double` pins the constants against the curve library, including that the expected output differs from the probe input -- a known-answer test whose answer equals its question tests nothing. Co-Authored-By: Claude Opus 4.8 --- .../src/lowering/render/models.rs | 21 +++++++++++ .../solidity-verifier/src/lowering/tests.rs | 36 +++++++++++++++++++ .../partials/verifier/PrecompileSmoke.sol | 33 +++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index 399d08667..52e54c7c9 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -10,6 +10,8 @@ use std::fmt; use askama::{Error, Template}; +use group::{prime::PrimeCurveAffine, Curve, Group}; +use midnight_curves::{G1Affine, G1Projective}; use ruint::aliases::U256; use crate::lowering::{ @@ -54,6 +56,14 @@ pub(crate) struct Eip2537TemplateConstants { pub(crate) g1msm_address: usize, pub(crate) pairing_address: usize, pub(crate) smoke_scratch_bytes: usize, + /// BLS12-381 G1 generator in EIP-2537 padded encoding. + /// + /// Used with [`Self::g1_double_generator`] as a known-answer vector for the + /// constructor smoke test: identity-only probes are satisfied by + /// implementations that never do any real curve arithmetic. + pub(crate) g1_generator: G1Words, + /// Twice the BLS12-381 G1 generator, in EIP-2537 padded encoding. + pub(crate) g1_double_generator: G1Words, } /// EIP-198 modexp frame constants rendered into templates. @@ -142,6 +152,12 @@ pub(crate) struct QuotientVmTemplateConstants { pub(crate) limb_pairwise_coeffs: usize, } +/// Convert a G1 point into the tuple form the templates render. +fn g1_words(point: G1Affine) -> G1Words { + let [x_hi, x_lo, y_hi, y_lo] = crate::lowering::encoding::g1_to_u256s(point); + (x_hi, x_lo, y_hi, y_lo) +} + impl Default for TemplateConstants { /// Build template constants from the Rust-side layout and VM specs. fn default() -> Self { @@ -158,6 +174,11 @@ impl Default for TemplateConstants { g1msm_address: layout::precompile::G1MSM_ADDRESS, pairing_address: layout::precompile::PAIRING_ADDRESS, smoke_scratch_bytes: layout::PAIRING_TWO_PAIR_BYTES, + g1_generator: g1_words(G1Affine::generator()), + g1_double_generator: { + let g = G1Projective::generator(); + g1_words((g + g).to_affine()) + }, }, modexp: ModexpTemplateConstants { address: layout::precompile::MODEXP_ADDRESS, diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 75290e373..e562978ab 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1197,6 +1197,39 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { ); } +/// The constructor's known-answer probe is only as good as its constants: a +/// wrong 2G would brick every deployment, and a 2G that happened to equal the +/// probe's own input would silently restore the identity-only weakness. Pin +/// both against the curve library rather than against hardcoded literals. +#[test] +fn constructor_known_answer_vector_is_the_generator_and_its_double() { + use group::{prime::PrimeCurveAffine, Curve, Group}; + use midnight_curves::{G1Affine, G1Projective}; + + let constants = crate::lowering::render::TemplateConstants::default().eip2537; + let expected_g = crate::lowering::encoding::g1_to_u256s(G1Affine::generator()); + let g = G1Projective::generator(); + let expected_2g = crate::lowering::encoding::g1_to_u256s((g + g).to_affine()); + + assert_eq!( + constants.g1_generator, + (expected_g[0], expected_g[1], expected_g[2], expected_g[3]) + ); + assert_eq!( + constants.g1_double_generator, + ( + expected_2g[0], + expected_2g[1], + expected_2g[2], + expected_2g[3] + ) + ); + assert_ne!( + constants.g1_generator, constants.g1_double_generator, + "a known-answer probe whose expected output equals its input tests nothing" + ); +} + #[test] fn verifier_constructor_smoke_tests_runtime_prerequisites() { let verifier_template = verifier_template_corpus(); @@ -1211,6 +1244,9 @@ fn verifier_constructor_smoke_tests_runtime_prerequisites() { "eq(mload(add(scratch, {{ template_constants.word_bytes|hex() }})), 0x1234)", "non-Cancun fork fails during deployment", "G1ADD(identity, identity) -> identity", + "Known-answer probe: G1ADD(G, G) == 2G", + "template_constants.eip2537.g1_generator", + "template_constants.eip2537.g1_double_generator", "Worst-case generated G1MSM with all identity/zero terms", "constructor_g1msm_smoke_input_bytes", "PAIRING_CHECK([(identity_g1, identity_g2), (identity_g1, identity_g2)])", diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index baa6e6180..5fed51133 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -27,6 +27,39 @@ revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), {{ template_constants.eip2537.g1_generator.0|hex_padded(64) }}) + mstore(add(scratch, 0x20), {{ template_constants.eip2537.g1_generator.1|hex_padded(64) }}) + mstore(add(scratch, 0x40), {{ template_constants.eip2537.g1_generator.2|hex_padded(64) }}) + mstore(add(scratch, 0x60), {{ template_constants.eip2537.g1_generator.3|hex_padded(64) }}) + mcopy(add(scratch, {{ template_constants.g1_bytes|hex() }}), scratch, {{ template_constants.g1_bytes|hex() }}) + if iszero(staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}, scratch, {{ template_constants.g1add_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), {{ template_constants.eip2537.g1_double_generator.0|hex_padded(64) }}), + eq(mload(add(scratch, 0x20)), {{ template_constants.eip2537.g1_double_generator.1|hex_padded(64) }}) + ), + and( + eq(mload(add(scratch, 0x40)), {{ template_constants.eip2537.g1_double_generator.2|hex_padded(64) }}), + eq(mload(add(scratch, 0x60)), {{ template_constants.eip2537.g1_double_generator.3|hex_padded(64) }}) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, {{ template_constants.eip2537.smoke_scratch_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair From 6333673effe28f9a690378c6b2e6e0b3d85cc435 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 02:38:36 +0100 Subject: [PATCH 061/108] Base the generated layout above solc's via-IR spill reservation The verifier body is wrapped in `assembly ("memory-safe")` while writing absolute addresses from 0x80 upward and never allocating through the free-memory pointer. The annotation is therefore false -- and it is also what enables solc's via-IR stack-to-memory mover, which reserves spill slots upward from 0x80 and records the top in the runtime's `mstore(0x40, ...)` prologue. Both parties then claimed the same bytes. The deployed moonlight-wrap runtime begins `6108e0604052` = mstore(0x40, 0x08e0): solc reserved [0x80, 0x8e0) for itself, while the generated layout put TRANSCRIPT_MPTR and RETURN_MPTR at 0x80. The optimized IR shows a real spill in that window -- `mstore(0x300, mload(0x6a00))` stores the y challenge and reads it back ~600 lines later. This has not misbehaved so far only because the spill placements and the verifier's writes happen not to collide destructively. Nothing enforced that. The reservation is a function of stack pressure, not a constant: 0x80 (ivc-keccak, none), 0xe0 (rsa), 0x3c0 (poseidon), 0x8e0 (moonlight-wrap). A different circuit, solc release, or optimizer schedule can place a live spill slot across a verifier write, corrupting a challenge or pairing input with no source change, no compile error, and no crash -- potentially a false accept produced by recompilation alone. Removing the annotation was tried first and does not work: the block then fails with `Cannot swap Variable usr$f_4 ... too deep in the stack by 1 slots`, and solc itself suggests re-adding it. It is load-bearing. So move the generated layout above the reservation instead. Rooting LOW_MEMORY_SCRATCH_START at 0x1000 makes solc's spill region and the verifier's memory disjoint in space, so their liveness stops mattering. VK_CONSTRUCTOR_PAYLOAD_START is decoupled and stays at 0x80: it belongs to Halo2VerifyingKey, whose assembly is not annotated memory-safe, so no reservation exists there. Being explicit about scope: this removes the consequence, not the false annotation. Making the annotation honest needs runtime mload(0x40)-based re-basing, which costs an ADD per access. Add `compiled_memoryguard_does_not_overlap_generated_layout`, which compiles each rendered variant and reads the free-memory-pointer prologue back out of real bytecode, failing if the reservation ever reaches the layout base. Verified to have teeth: with the base returned to 0x80 it fails with `solc reserved [0x80, 0x3c0) ... overlaps the generated verifier layout based at 0x80`. Size impact is immaterial -- the largest known verifier runtime is 21161 bytes against EIP-170's 24576, and the change only widens some PUSH1 address literals to PUSH2. Full gate green: 194 passed with HALO2_SOLIDITY_RUN_EVM_TESTS=1 and features evm,rust-verifier-trace, including the end-to-end proof verification tests under revm. Co-Authored-By: Claude Opus 4.8 --- .../docs/architecture/MEMORY_LAYOUT.md | 31 ++++++-- .../docs/architecture/MIGRATION.md | 4 ++ proofs/solidity-verifier/docs/audit/AUDIT.md | 27 ++++++- proofs/solidity-verifier/src/evm.rs | 72 +++++++++++++++++++ proofs/solidity-verifier/src/lib.rs | 5 +- .../src/lowering/layout/memory.rs | 26 +++---- .../src/lowering/layout/mod.rs | 32 ++++++++- .../src/lowering/render/models.rs | 8 +-- proofs/solidity-verifier/src/test.rs | 46 +++++++++++- 9 files changed, 220 insertions(+), 31 deletions(-) diff --git a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md index 4550d1607..5ad79c2eb 100644 --- a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md +++ b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md @@ -27,10 +27,33 @@ Solidity reserves the first four words of memory for compiler conventions: The generated verifier intentionally does not follow Solidity allocation by reading and bumping `mload(0x40)`. Instead, every generated absolute memory -region is planned at or above `0x80`. The streaming transcript buffer, the main -verifier return word, the split quotient return frame, the VK constructor -payload buffer, and low-memory precompile scratch all start from named -Rust-side layout constants rooted at `SOLIDITY_ALLOCATABLE_MEMORY_START`. +region is planned from named Rust-side layout constants. + +Those constants are **not** rooted at `0x80`. The verifier body is wrapped in +`assembly ("memory-safe")`, which is load-bearing -- without it the block does +not compile under `--via-ir` (stack too deep) -- but also factually untrue, +since the block writes memory it never obtained from the free-memory pointer. +The annotation is what enables solc's stack-to-memory mover, which reserves +spill slots upward from `0x80` and records the top in the runtime's +`mstore(0x40, ...)` prologue. Observed reservations range from `0x80` (none) to +`0x8e0`, varying with the circuit, the solc release, and the optimizer +schedule. + +Basing the layout at `0x80` therefore put solc's spill slots and the verifier's +own transcript buffer in the same bytes, separated only by live ranges that +nothing enforced -- a recompilation could silently place a live spill across a +verifier write and corrupt a challenge or pairing input. So the streaming +transcript buffer, the main verifier return word, the split quotient return +frame, and low-memory precompile scratch are rooted at +`LOW_MEMORY_SCRATCH_START` (`0x1000`), above the largest observed reservation. +`compiled_memoryguard_does_not_overlap_generated_layout` compiles each rendered +variant and fails the build if a future circuit or compiler pushes the +reservation past that base. + +The VK constructor payload buffer is the exception: it lives in +`Halo2VerifyingKey`, whose assembly carries no `memory-safe` annotation, so +solc reserves nothing there and it stays at +`SOLIDITY_ALLOCATABLE_MEMORY_START`. The code generator treats `[0x00..0x80)` as off limits for generated writes: `VerifierMemoryLayout::validate()` rejects any registered region inside that diff --git a/proofs/solidity-verifier/docs/architecture/MIGRATION.md b/proofs/solidity-verifier/docs/architecture/MIGRATION.md index 5e314d953..237132060 100644 --- a/proofs/solidity-verifier/docs/architecture/MIGRATION.md +++ b/proofs/solidity-verifier/docs/architecture/MIGRATION.md @@ -343,6 +343,10 @@ The `cargo test --lib` suite now stands at 7/7 green: `assembly ("memory-safe") { ... }` to silence the legacy stack-too-deep error path; with `--via-ir` solc 0.8.30 now compiles the full ~117 kB output cleanly. + Note the annotation is not merely cosmetic: it enables solc's + stack-to-memory mover, which reserves spill slots upward from + `0x80`. See AUDIT.md TA-5 and `docs/architecture/MEMORY_LAYOUT.md` + for why the generated layout is based at `0x1000` rather than `0x80`. * `tests/poseidon_fixture.rs` — new integration test (gated behind `feature = "evm"` and currently `#[ignore]`d, see below) that: 1. Configures `SRS_DIR` to point at diff --git a/proofs/solidity-verifier/docs/audit/AUDIT.md b/proofs/solidity-verifier/docs/audit/AUDIT.md index b85c509aa..aba140bf0 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT.md @@ -2314,10 +2314,33 @@ memory-safety rules. If future edits add Solidity code after the block, or if the compiler reasons across the block in an unexpected way, this becomes a miscompilation risk. +**Status: addressed.** The risk was not hypothetical. `solc 0.8.30` with the +pinned flags emits `mstore(0x40, 0x08e0)` for the moonlight-wrap render, i.e. +it reserved `[0x80, 0x8e0)` for via-IR stack-to-memory spill slots -- directly +on top of a generated layout that started at `0x80`. Reservations observed +across renders: `0x80` (ivc-keccak, none), `0xe0` (rsa), `0x3c0` (poseidon), +`0x8e0` (moonlight-wrap). At least one spill (`mstore(0x300, mload(0x6a00))`, +the `y` challenge, re-read ~600 IR lines later) sits in that window. + +The recommendation below to remove the annotation was tested and does not work: +the block then fails to compile with `Cannot swap Variable usr$f_4 ... too deep +in the stack by 1 slots`, and solc itself suggests re-adding the annotation. +The annotation is load-bearing. + +The fix instead moves the generated layout above the reservation +(`LOW_MEMORY_SCRATCH_START = 0x1000`), making the two regions disjoint in space +so their liveness no longer matters, and adds +`compiled_memoryguard_does_not_overlap_generated_layout`, which compiles each +rendered variant and fails if the reservation ever grows past that base. Note +this removes the *consequence*, not the false annotation itself; making the +annotation honest would require runtime `mload(0x40)`-based re-basing at the +cost of an `ADD` per memory access. + Recommendation: -- Prefer removing `"memory-safe"` from the terminal verifier block unless there - is a compiler-specific proof that this pattern is accepted. +- ~~Prefer removing `"memory-safe"` from the terminal verifier block unless + there is a compiler-specific proof that this pattern is accepted.~~ + Superseded: removal does not compile. See status note above. - Pin the exact compiler and EVM version. The Renegade audit's recommendation to use fixed pragmas rather than floating `^0.8.x` is especially relevant for generated verifier code. diff --git a/proofs/solidity-verifier/src/evm.rs b/proofs/solidity-verifier/src/evm.rs index 5a3ae7fec..7f929275e 100644 --- a/proofs/solidity-verifier/src/evm.rs +++ b/proofs/solidity-verifier/src/evm.rs @@ -231,6 +231,78 @@ pub(crate) mod test { } } + /// Read the free-memory-pointer initializer from a runtime bytecode prefix. + /// + /// solc opens every contract by storing the initial free-memory pointer to + /// slot `0x40`. With `memoryguard` active -- which the verifier's + /// `assembly ("memory-safe")` annotation enables -- that value is raised + /// above `0x80` to reserve via-IR stack-to-memory spill slots, so the + /// returned value is the top of the region solc has claimed for itself. + /// + /// Recognises the two prologue encodings solc emits: + /// `PUSH1 v` / `PUSH2 v` followed by `PUSH1 0x40 MSTORE`, allowing an + /// optional `DUP1` between them (used when the value is reused). + /// Returns `None` if the prefix does not match, so callers can distinguish + /// "no reservation found" from "reservation is 0x80". + #[must_use] + pub fn runtime_free_memory_pointer_init(runtime: &[u8]) -> Option { + // PUSH1 v | PUSH2 v_hi v_lo + let (value, mut i) = match *runtime.first()? { + 0x60 => (usize::from(*runtime.get(1)?), 2), + 0x61 => ( + (usize::from(*runtime.get(1)?) << 8) | usize::from(*runtime.get(2)?), + 3, + ), + _ => return None, + }; + // Optional DUP1 when solc reuses the value. + if runtime.get(i) == Some(&0x80) { + i += 1; + } + // PUSH1 0x40 MSTORE + if runtime.get(i) == Some(&0x60) + && runtime.get(i + 1) == Some(&0x40) + && runtime.get(i + 2) == Some(&0x52) + { + return Some(value); + } + None + } + + /// Compile `solidity` and return the deployed runtime bytecode. + /// + /// # Panics + /// Panics under the same conditions as [`compile_solidity`]. + pub fn compile_solidity_runtime(solidity: impl AsRef<[u8]>) -> Vec { + let solc = require_pinned_solc(); + let mut process = Command::new(&solc) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("--bin-runtime") + .arg("--optimize") + .arg("--optimize-runs") + .arg(DEFAULT_OPTIMIZE_RUNS.to_string()) + .arg("--via-ir") + .arg("--evm-version") + .arg("cancun") + .arg("--no-cbor-metadata") + .arg("-") + .spawn() + .unwrap_or_else(|err| panic!("Failed to spawn process with command '{solc}':\n{err}")); + process.stdin.take().unwrap().write_all(solidity.as_ref()).unwrap(); + let output = process.wait_with_output().unwrap(); + let stdout = str::from_utf8(&output.stdout).unwrap(); + let marker = "Binary of the runtime part:"; + let start = stdout.find(marker).unwrap_or_else(|| { + panic!( + "Runtime compilation fails:\n{}", + str::from_utf8(&output.stderr).unwrap() + ) + }) + marker.len(); + hex::decode(stdout[start..].trim()).expect("solc runtime output should be hex") + } + /// Extract creation bytecode from solc's text `--bin` output. fn find_binary(stdout: &str) -> Option> { let start = stdout.find("Binary:")? + 8; diff --git a/proofs/solidity-verifier/src/lib.rs b/proofs/solidity-verifier/src/lib.rs index 011af0a58..6cf2f30cf 100644 --- a/proofs/solidity-verifier/src/lib.rs +++ b/proofs/solidity-verifier/src/lib.rs @@ -58,8 +58,9 @@ pub const OUTER_SINGLE_H_COMMITMENT_ENABLED: bool = cfg!(feature = "outer-single #[cfg(feature = "evm")] pub use evm::test::{ - compile_solidity, compile_solidity_with_runs, pinned_solc_available, revm, solc_version, - CallOutcome, Evm, ALLOW_UNPINNED_SOLC_ENV, DEFAULT_OPTIMIZE_RUNS, PINNED_SOLC_VERSION, + compile_solidity, compile_solidity_runtime, compile_solidity_with_runs, pinned_solc_available, + revm, runtime_free_memory_pointer_init, solc_version, CallOutcome, Evm, + ALLOW_UNPINNED_SOLC_ENV, DEFAULT_OPTIMIZE_RUNS, PINNED_SOLC_VERSION, }; /// Test-only helper that exposes the internal BLS12-381 G1 to EIP-2537 diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index b91c70f1d..fd91314d3 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -1374,7 +1374,7 @@ mod tests { let layout = VerifierMemoryLayout::new( &meta, &vk, - Ptr::memory(0x1000), + Ptr::memory(0x2000), VerifierMemoryLayoutConfig::default(), ); let theta = layout.theta_mptr.value().as_usize(); @@ -1429,7 +1429,7 @@ mod tests { let layout = VerifierMemoryLayout::new( &meta, &vk, - Ptr::memory(0x1000), + Ptr::memory(0x2000), VerifierMemoryLayoutConfig::default(), ); @@ -1531,7 +1531,7 @@ mod tests { .expect("scalar inversion scratch registered"); assert_eq!( layout.scalar_inv_scratch_mptr, - 0x1000 - MODEXP_SCRATCH_BYTES + 0x2000 - MODEXP_SCRATCH_BYTES ); assert_eq!(scalar_inv.start, layout.scalar_inv_scratch_mptr); assert_eq!(scalar_inv.len, MODEXP_FRAME_BYTES); @@ -1545,17 +1545,17 @@ mod tests { let windows = ThetaWindowLayout::compatibility(); let mut config = VerifierMemoryLayoutConfig::default(); config.pcs.rot_points_words = windows.rot_points_cap_words + 1; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); assert!(layout.validate().unwrap_err().contains("ROT_POINTS_MPTR")); let mut config = VerifierMemoryLayoutConfig::default(); config.pcs.x1_powers_words = windows.x1_powers_cap_words + 1; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); assert!(layout.validate().unwrap_err().contains("X1_POWERS_MPTR")); let mut config = VerifierMemoryLayoutConfig::default(); config.pcs.q_eval_set_words = windows.q_eval_set_cap_words + 1; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); assert!(layout.validate().unwrap_err().contains("Q_EVAL_SET_MPTR")); } @@ -1567,7 +1567,7 @@ mod tests { acc_msm_terms: 4, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); let region = layout.map.region("accumulator_msm").expect("accumulator MSM region registered"); @@ -1584,7 +1584,7 @@ mod tests { let layout = VerifierMemoryLayout::new( &meta, &vk, - Ptr::memory(0x1000), + Ptr::memory(0x2000), VerifierMemoryLayoutConfig::default(), ); let selector = layout @@ -1621,7 +1621,7 @@ mod tests { }, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); let region = layout.map.region("trace_u256_log_word").expect("trace_u256 region registered"); @@ -1648,7 +1648,7 @@ mod tests { }, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); for (name, end) in [ ( @@ -1690,7 +1690,7 @@ mod tests { num_instances: 5, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); let region = layout .map .region("batch_invert_scratch") @@ -1727,7 +1727,7 @@ mod tests { num_instances: max_instances, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); assert_eq!(layout.batch_invert_input_words, cap_words); layout.validate().expect("run ending below Q_EVAL_CPTR_MPTR is valid"); @@ -1735,7 +1735,7 @@ mod tests { num_instances: max_instances + 1, ..VerifierMemoryLayoutConfig::default() }; - let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x1000), config); + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); let err = layout.validate().unwrap_err(); assert!( err.contains("Lagrange batch-inversion input run"), diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index a84bc8236..76a08f82f 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -26,7 +26,22 @@ pub(crate) const SOLIDITY_ALLOCATABLE_MEMORY_START: usize = 0x80; /// The full reserved prefix: scratch, free-memory pointer, and zero slot. pub(crate) const SOLIDITY_RESERVED_MEMORY_BYTES: usize = SOLIDITY_ALLOCATABLE_MEMORY_START; /// Generated verifier transcript and low-memory precompile scratch base. -pub(crate) const LOW_MEMORY_SCRATCH_START: usize = SOLIDITY_ALLOCATABLE_MEMORY_START; +/// +/// Deliberately *above* [`SOLIDITY_ALLOCATABLE_MEMORY_START`]. The verifier +/// body is wrapped in `assembly ("memory-safe")`, which is what lets solc's +/// via-IR stack-to-memory mover run at all -- without it the block does not +/// compile (stack too deep). That mover reserves spill slots from `0x80` +/// upward and records the top in the runtime's `mstore(0x40, ...)` prologue. +/// Observed reservations run from `0x80` (none) to `0x8e0`, varying with the +/// circuit, the solc release, and the optimizer schedule. +/// +/// Basing the generated layout at `0x80` therefore put solc's spill slots and +/// the verifier's own transcript buffer in the same bytes, kept apart only by +/// live ranges that nothing enforced. Starting above the largest observed +/// reservation makes them disjoint by construction; +/// `compiled_memoryguard_does_not_overlap_generated_layout` fails the build if +/// a future circuit or compiler pushes the reservation past this base. +pub(crate) const LOW_MEMORY_SCRATCH_START: usize = 0x1000; /// Start of the Keccak transcript buffer used by the assembly helpers. pub(crate) const TRANSCRIPT_BUFFER_START: usize = LOW_MEMORY_SCRATCH_START; /// Shared low-memory scratch for PCS pairing serialization. @@ -36,7 +51,12 @@ pub(crate) const VERIFIER_RETURN_BUFFER_START: usize = LOW_MEMORY_SCRATCH_START; /// Return buffer used by split quotient evaluator calls. pub(crate) const QUOTIENT_RETURN_BUFFER_START: usize = LOW_MEMORY_SCRATCH_START; /// Constructor-time memory base for the separate VK runtime payload. -pub(crate) const VK_CONSTRUCTOR_PAYLOAD_START: usize = LOW_MEMORY_SCRATCH_START; +/// +/// Deliberately *not* derived from [`LOW_MEMORY_SCRATCH_START`]. This buffer +/// belongs to `Halo2VerifyingKey`, a separate contract whose assembly is not +/// annotated `memory-safe`, so solc reserves no via-IR spill window there and +/// the payload can sit at Solidity's normal allocatable start. +pub(crate) const VK_CONSTRUCTOR_PAYLOAD_START: usize = SOLIDITY_ALLOCATABLE_MEMORY_START; /// Number of EVM words in one Fr scalar. pub(crate) const FR_WORDS: usize = 1; /// EIP-2537 padded G1 encoding: x_hi, x_lo, y_hi, y_lo. @@ -662,7 +682,13 @@ mod tests { assert_eq!(super::SOLIDITY_FREE_MEMORY_POINTER_SLOT, 0x40); assert_eq!(super::SOLIDITY_ZERO_SLOT, 0x60); assert_eq!(super::SOLIDITY_RESERVED_MEMORY_BYTES, 0x80); - assert_eq!(super::TRANSCRIPT_BUFFER_START, 0x80); + assert_eq!( + super::TRANSCRIPT_BUFFER_START, + super::LOW_MEMORY_SCRATCH_START + ); + // Above Solidity's allocatable start on purpose: solc reserves + // via-IR spill slots upward from 0x80 in this contract. + assert!(super::LOW_MEMORY_SCRATCH_START > super::SOLIDITY_ALLOCATABLE_MEMORY_START); assert_eq!(super::VK_CONSTRUCTOR_PAYLOAD_START, 0x80); } diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index 52e54c7c9..58974681b 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -1065,7 +1065,7 @@ mod tests { let memory = VerifierMemoryLayout::new( &ConstraintSystemMeta::default(), &synthetic_vk(0, 0), - Ptr::memory(0x1000), + Ptr::memory(0x2000), VerifierMemoryLayoutConfig::default(), ); let mut proof = ProofReadPlan::default(); @@ -1119,9 +1119,9 @@ mod tests { }, memory, vk_header: Default::default(), - vk_mptr: Ptr::memory(0x1000), - challenge_mptr: Ptr::memory(0x1200), - theta_mptr: Ptr::memory(0x1300), + vk_mptr: Ptr::memory(0x2000), + challenge_mptr: Ptr::memory(0x2200), + theta_mptr: Ptr::memory(0x2300), proof_cptr: Ptr::calldata(proof_cptr), abi_selector_bytes: crate::lowering::layout::abi::SELECTOR_BYTES, abi_proof_head_offset: crate::lowering::layout::abi::VERIFY_PROOF_PROOF_HEAD_OFFSET, diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index a47e14ab6..9ef3ee5ae 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -45,9 +45,10 @@ use ruint::aliases::U256; use sha3::Digest; use crate::{ - compile_solidity, encode_calldata, pinned_solc_available, AccumulatorEncoding, CallOutcome, - Evm, GeneratorConfig, RenderDiagnostics, RenderOptions, RenderQuotient, RenderVk, - SolidityGenerator, FN_SIG_VERIFY_PROOF, + compile_solidity, compile_solidity_runtime, encode_calldata, pinned_solc_available, + runtime_free_memory_pointer_init, AccumulatorEncoding, CallOutcome, Evm, GeneratorConfig, + RenderDiagnostics, RenderOptions, RenderQuotient, RenderVk, SolidityGenerator, + FN_SIG_VERIFY_PROOF, }; /// Scalar field used by the BLS12-381 Poseidon fixtures. @@ -1357,6 +1358,45 @@ fn pinned_quotient_verifier_rejects_wrong_vk_and_quotient_contracts() { ); } +/// The verifier body is wrapped in `assembly ("memory-safe")` while writing +/// absolute addresses, which is a false promise: it never allocates through the +/// free-memory pointer. That annotation is nonetheless load-bearing -- without +/// it the block does not compile (stack too deep) -- and it is what lets solc's +/// via-IR stack-to-memory mover reserve spill slots upward from `0x80`. +/// +/// The generated layout is therefore based above that reservation rather than +/// at `0x80`, so solc's spill slots and the verifier's own memory are disjoint +/// by construction instead of by a liveness coincidence. The reservation size +/// is not fixed -- observed values range from `0x80` to `0x8e0` depending on +/// the circuit, the solc release, and the optimizer schedule -- so assert the +/// property against real compiled bytecode rather than assuming it holds. +#[test] +fn compiled_memoryguard_does_not_overlap_generated_layout() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let fixture = create_property_poseidon_fixture(); + for (name, source) in [ + ("embedded", fixture.embedded_verifier_solidity.as_str()), + ("separate", fixture.separate_verifier_solidity.as_str()), + ("quotient", fixture.quotient_verifier_solidity.as_str()), + ] { + let runtime = compile_solidity_runtime(source); + let reserved_end = runtime_free_memory_pointer_init(&runtime).unwrap_or_else(|| { + panic!("{name}: could not read the free-memory-pointer prologue from runtime bytecode") + }); + assert!( + reserved_end <= crate::lowering::layout::LOW_MEMORY_SCRATCH_START, + "{name}: solc reserved [0x80, {reserved_end:#x}) for via-IR spill slots, which \ + overlaps the generated verifier layout based at {:#x}. A live spill slot can then \ + sit across a verifier write, silently corrupting a challenge or pairing input. \ + Raise LOW_MEMORY_SCRATCH_START above {reserved_end:#x}.", + crate::lowering::layout::LOW_MEMORY_SCRATCH_START + ); + } +} + #[test] fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { if !poseidon_inputs_available_for_evm() { From a30fef416406900ece595f320524feae6bd4e0bf Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 02:52:38 +0100 Subject: [PATCH 062/108] Enforce the EIP-170 runtime size limit on the verifier contracts `Halo2VerifyingKey` is size-checked at render time by `validate_payload_layout`, because a data contract's runtime length is known before compilation. The verifier's is not -- it only exists once solc has run -- so nothing bounded it. That gap was invisible rather than latent: the revm harness sets `cfg.limit_contract_code_size = Some(usize::MAX)` (evm.rs), deliberately, so that in-process tests can run oversized contracts. The consequence is that a verifier exceeding 24576 bytes would pass the entire suite, including every end-to-end proof verification, and then fail to deploy on mainnet or any other EIP-170 chain. The comment justifying the cap lift is also stale: it cites a ~25 kB verifier from before the inline `decompress_g1` calls were removed. Add `compiled_verifier_runtime_fits_the_eip170_limit`, which compiles the embedded, separate, quotient and VK renders and asserts each runtime is within the limit. Checking the compiled artifact is the only option here, since the size is a property of solc's output rather than of the plan. Current headroom is comfortable -- the embedded poseidon render is 16037 bytes and the largest known verifier, the deployed moonlight-wrap one, is 21161 -- but the layout rebase in the previous commit widens some address literals from PUSH1 to PUSH2, so the bound is now worth asserting rather than assuming. Verified the assertion measures real bytecode by temporarily inverting it and reading back the reported sizes. Co-Authored-By: Claude Opus 4.8 --- proofs/solidity-verifier/src/test.rs | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 9ef3ee5ae..5eab7d99b 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1397,6 +1397,37 @@ fn compiled_memoryguard_does_not_overlap_generated_layout() { } } +/// `Halo2VerifyingKey` is size-checked at render time by +/// `validate_payload_layout`, because a data contract's runtime length is known +/// before compilation. The verifier's is not -- it only exists once solc has +/// run -- so nothing bounded it, and the revm harness deliberately sets +/// `limit_contract_code_size = usize::MAX` (see `evm.rs`), meaning an oversized +/// verifier would pass the whole suite and then fail to deploy on any EIP-170 +/// chain. Check the compiled artifact directly. +#[test] +fn compiled_verifier_runtime_fits_the_eip170_limit() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let limit = crate::lowering::render::EIP_170_MAX_RUNTIME_BYTES; + let fixture = create_property_poseidon_fixture(); + for (name, source) in [ + ("embedded", fixture.embedded_verifier_solidity.as_str()), + ("separate", fixture.separate_verifier_solidity.as_str()), + ("quotient", fixture.quotient_verifier_solidity.as_str()), + ("vk", fixture.vk_solidity.as_str()), + ] { + let runtime_len = compile_solidity_runtime(source).len(); + assert!( + runtime_len <= limit, + "{name}: compiled runtime is {runtime_len} bytes, over the EIP-170 limit of \ + {limit}; this contract cannot be deployed on mainnet or any \ + EIP-170 chain. Note the revm harness lifts this cap, so no other test catches it." + ); + } +} + #[test] fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { if !poseidon_inputs_available_for_evm() { From 2938a400d9d187fbd24fd3bb07fc3812329c49e9 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 03:09:18 +0100 Subject: [PATCH 063/108] Propagate the TranscriptInputBytes bound to LightAggregator::verify `midnight-aggregation` did not compile. `LightAggregator::verify` delegates to `plonk::prepare`, which gained the bound ::Input: TranscriptInputBytes in db26827 ("test(solidity): add native differential trace hooks"). The bound was never propagated to this caller, so the crate has been broken at HEAD -- and because it is a workspace member, `cargo check --workspace` fails before reaching anything else. Add the bound to `verify`'s where clause, matching how the other `prepare` callers declare it in `proofs/tests/plonk_api.rs:477,523`. This is a propagation gap rather than a design problem: `TranscriptInputBytes` is implemented for both real transcript input types, `Vec` and `Vec`, so every concrete transcript already satisfies it and no call site needs to change. `cargo check --workspace --lib --tests` is clean and the crate's two lib tests pass. Co-Authored-By: Claude Opus 4.8 --- aggregation/src/light_aggregator/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aggregation/src/light_aggregator/mod.rs b/aggregation/src/light_aggregator/mod.rs index d78d35022..3ef582708 100644 --- a/aggregation/src/light_aggregator/mod.rs +++ b/aggregation/src/light_aggregator/mod.rs @@ -81,7 +81,9 @@ use midnight_proofs::{ }, EvaluationDomain, }, - transcript::{CircuitTranscript, Hashable, Sampleable, Transcript}, + transcript::{ + CircuitTranscript, Hashable, Sampleable, Transcript, TranscriptHash, TranscriptInputBytes, + }, }; use rand::{CryptoRng, RngCore}; @@ -414,6 +416,11 @@ impl LightAggregator { C: Hashable, F: Sampleable + Hashable, u32: Hashable, + // Required by `plonk::prepare`, which this method delegates to. The + // bound is satisfied by both real transcript input types (`Vec` + // and `Vec`); propagating it here mirrors the other `prepare` + // callers in `proofs/tests/plonk_api.rs`. + ::Input: TranscriptInputBytes, { // Read the LHS of the acc from the transcript. let acc_lhs: Msm = { From 70dd1a8a5c69f6bcfb35a050e1a986c69aab9d32 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 03:59:02 +0100 Subject: [PATCH 064/108] Add a CI replay that adversarially exercises the accumulator decoder The public-accumulator decode path in AccumulatorHelpers.yul had no executing test coverage at all. The tests that appeared to cover it -- `accumulator_decoder_rejects_noncanonical_infinity` and neighbours in src/lowering/tests.rs -- are `verifier_template.contains("...")` string greps over the raw template: they assert the guard *text* is present and never render, compile, or run it. That is exactly how the always-false `and` guard fixed in a951f04 survived. Those greps passed for as long as the identity branch was dead code, and a regression that re-deadened it would pass them again. The only executing accumulator tests are in tests/ivc_keccak_solidity.rs, which proves a k=20 decider from scratch. It needs ~300 MB of SRS and three minutes, so it is gated behind HALO2_SOLIDITY_RUN_IVC_BENCH=1 and never runs in CI. Replace the orphaned fixtures/ivc contents with pre-rendered artifacts and replay those instead. The previous fixtures (vk.bin, proof.bin, instance.bin, two trace dumps) were referenced by no test, script, or example, had no writer anywhere in the repo, and were not even loadable: `VerifyingKey` serialization starts with VERSION = 0x03 while vk.bin starts with 0x12. Reading one would also require the decider circuit type from midnight-aggregation, and rendering a verifier from a VK needs the full SRS because `SolidityGenerator` consumes `params.g_lagrange()` -- which is what makes a VK-based replay unusable in CI no matter how fresh the fixture is. Shipping the rendered contracts plus matching calldata sidesteps all of that: the replay needs only solc and revm. It runs in ~2 s. The test verifies the fixture proof is accepted first, then asserts three classes of accumulator mutation are rejected: non-canonical limb packing, a malformed coordinate with a zeroed scalar, and substitution of the canonical encoded point at infinity. The accept baseline is what makes the rejections meaningful -- without it they could pass because the verifier rejects everything. Two things guard against the test passing vacuously: - The offset arithmetic is checked structurally. Four 56-bit limbs occupy the low 224 bits of a packed word, so every accumulator coordinate word must have four zero high bytes; random proof bytes would not. A miscomputed offset would otherwise still revert, for the wrong reason. - Each mutation class was individually neutered and confirmed to make the verifier accept, so all three assertions are load-bearing. The fixture describes itself: accumulator offset, limb count and the has_accumulator flag are parsed back out of the rendered VK payload, and the infinity encoding out of the verifier's own constants, so this test carries no duplicate constants that could drift from the artifact. Fixtures were regenerated at this branch's codegen and confirmed to carry the rebased memory layout (TRANSCRIPT_MPTR = 0x1000); the underlying bench verified the proof on-chain in 1,285,274 gas. fixtures/ivc/README.md records provenance and the regeneration command. Known limitation: a rendered fixture is a codegen snapshot. It stays self-consistent and keeps passing after a codegen change, so it silently stops testing current output. Detecting that needs re-rendering, which needs the SRS again, so it is tracked by a commit stamp rather than an assertion. Co-Authored-By: Claude Opus 4.8 --- .../fixtures/ivc/Halo2QuotientEvaluator.sol | 1593 ++++++++++++ .../fixtures/ivc/Halo2Verifier.sol | 2282 +++++++++++++++++ .../fixtures/ivc/Halo2VerifyingKey.sol | 693 +++++ .../solidity-verifier/fixtures/ivc/README.md | 48 + .../fixtures/ivc/calldata.bin | Bin 0 -> 8356 bytes .../fixtures/ivc/instance.bin | Bin 3528 -> 0 bytes .../solidity-verifier/fixtures/ivc/proof.bin | Bin 9824 -> 0 bytes .../fixtures/ivc/rust_trace.json | 1068 -------- .../fixtures/ivc/solidity_trace.json | 1 - proofs/solidity-verifier/fixtures/ivc/vk.bin | Bin 66731 -> 0 bytes .../tests/ivc_accumulator_replay.rs | 315 +++ 11 files changed, 4931 insertions(+), 1069 deletions(-) create mode 100644 proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol create mode 100644 proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol create mode 100644 proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol create mode 100644 proofs/solidity-verifier/fixtures/ivc/README.md create mode 100644 proofs/solidity-verifier/fixtures/ivc/calldata.bin delete mode 100644 proofs/solidity-verifier/fixtures/ivc/instance.bin delete mode 100644 proofs/solidity-verifier/fixtures/ivc/proof.bin delete mode 100644 proofs/solidity-verifier/fixtures/ivc/rust_trace.json delete mode 100644 proofs/solidity-verifier/fixtures/ivc/solidity_trace.json delete mode 100644 proofs/solidity-verifier/fixtures/ivc/vk.bin create mode 100644 proofs/solidity-verifier/tests/ivc_accumulator_replay.rs diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol new file mode 100644 index 000000000..c2bc6699d --- /dev/null +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol @@ -0,0 +1,1593 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.24; + +/// @title Split Halo2 quotient numerator evaluator. +/// @notice Reconstructs the scalar side of the linearization query for a generated verifier. +/// @dev This is the split-out implementation of the expensive +/// `partially_evaluate_identities` / `compute_linearization_commitment` side +/// from the Midfall Rust verifier: +/// - `midfall/proofs/src/plonk/mod.rs::partially_evaluate_identities` +/// - `midfall/proofs/src/plonk/linearization/verifier.rs::compute_linearization_commitment` +/// - `midfall/proofs/src/plonk/{permutation,logup,trash}.rs` +/// @dev The main verifier has already parsed calldata, checked proof scalar +/// ranges, sampled Fiat-Shamir challenges, loaded the VK payload, and computed +/// local Lagrange/public-input values before making the staticcall. +/// +/// Instead of receiving structured Solidity arguments, the evaluator receives +/// the verifier's memory frame as raw calldata: +/// +/// calldata[0..QUOTIENT_FRAME_LEN) +/// == memory[QUOTIENT_FRAME_BASE..QUOTIENT_FRAME_BASE+QUOTIENT_FRAME_LEN) +/// +/// The fallback copies that frame back into the same generated memory +/// addresses. All constants below are therefore memory addresses inside that +/// copied frame, not ABI offsets. +/// +/// Output is a compact fixed frame consumed by Halo2Verifier: +/// +/// word 0: QUOTIENT_MAGIC, a generated version/magic guard +/// word 1: linearization_expected_eval +/// word 2..: simple-selector accumulator scalars +/// +/// This contract reconstructs the Rust verifier's y-batched identity numerator +/// nu_y(x) and returns the linearization expected scalar -nu_y(x). It does not +/// evaluate or trust a quotient scalar h(x). +/// +/// The quotient limb commitments are handled by Halo2Verifier on the commitment +/// side as (1 - x^n) * sum_i x_split^i * Q_i. That is why this scalar side is +/// -nu_y(x), not h(x) = nu_y(x) / (x^n - 1). +/// +/// See docs/QUOTIENT_NUMERATOR_EVALUATOR.md for the full Rust/Solidity mapping. +contract Halo2QuotientEvaluator { + // BLS12-381 scalar field modulus. All arithmetic in this contract is over + // Fr and uses addmod/mulmod with this modulus. + uint256 internal constant FR_MODULUS = + 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; + + // Start of the copied verifier-key payload in memory. The VK payload also + // carries the compact quotient VM constant/program tables used by the + // included numerator block. + uint256 internal constant VK_MPTR = 0x3680; + + // Fiat-Shamir challenge slots. Halo2Verifier sampled these in transcript + // order before the external call. The evaluator only reads them. + uint256 internal constant CHALLENGE_MPTR = 0x7900; + uint256 internal constant THETA_MPTR = 0x7900; + uint256 internal constant BETA_MPTR = 0x7920; + uint256 internal constant GAMMA_MPTR = 0x7940; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x7960; + uint256 internal constant Y_MPTR = 0x7980; + uint256 internal constant X_MPTR = 0x79a0; + uint256 internal constant X1_MPTR = 0x79c0; + uint256 internal constant X2_MPTR = 0x79e0; + uint256 internal constant X3_MPTR = 0x7a00; + uint256 internal constant X4_MPTR = 0x7a20; + + // Common polynomial values at x. Halo2Verifier computes these once after + // sampling x and places them in the frame so the numerator block can share + // the exact Rust verifier inputs. + uint256 internal constant X_N_MPTR = 0x7c40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x7c60; + uint256 internal constant L_LAST_MPTR = 0x7c80; + uint256 internal constant L_BLIND_MPTR = 0x7ca0; + uint256 internal constant L_0_MPTR = 0x7cc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x7ce0; + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x7d00; + + // Proof evaluation table. Values are already decoded as canonical Fr words + // by Halo2Verifier. The generated numerator code indexes this table by the + // same query order as the Rust verifier. + uint256 internal constant REVERSED_EVALS_MPTR = 0x9480; + + // Scratch/output region for simple-selector linearization accumulators. + // The numerator block writes one bucket per simple selector, then the + // fallback copies those buckets into the compact return frame. + uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; + // Callee-local scratch for trace hooks. Trace-enabled verifier builds call + // this evaluator with CALL so quotient identity logs can be compared with + // the native Rust trace. Production verifier builds keep using STATICCALL + // and render this evaluator without trace hooks. + uint256 internal constant TRACE_U256_MPTR = 0x1000; + uint256 internal constant QUOTIENT_OUTPUT_MPTR = 0x1000; + + // External-call frame metadata. The main verifier calls this contract with + // exactly QUOTIENT_FRAME_LEN bytes starting at + // QUOTIENT_FRAME_BASE, then checks the return length and QUOTIENT_MAGIC. + uint256 internal constant QUOTIENT_FRAME_BASE = 0x3680; + uint256 internal constant QUOTIENT_FRAME_LEN = 0x6ac0; + uint256 internal constant QUOTIENT_OUTPUT_LEN = 0x0180; + uint256 internal constant QUOTIENT_MAGIC = 0x00000000000000000000000000000000000000000000000051554556414c0001; + + /// @notice Evaluate the generated quotient numerator block for one verifier memory frame. + /// @dev Calldata is exactly the raw frame, not ABI-encoded arguments. Returns `QUOTIENT_MAGIC`, the linearization expected eval, and selector buckets. + /// @dev This fallback also uses generated absolute memory addresses and + /// returns directly from assembly. Its compact return frame starts at + /// `0x80`, preserving Solidity's reserved memory words. + fallback() external { + assembly ("memory-safe") { + // Reject malformed calls. This contract is not a general-purpose + // ABI endpoint; accepting partial or shifted frames would make the + // generated memory addresses point at the wrong data. + if iszero(eq(calldatasize(), QUOTIENT_FRAME_LEN)) { revert(0, 0) } + + // Rehydrate the verifier memory image. From this point onward the + // generated Yul can use the same MPTR constants as the monolithic + // verifier path. + calldatacopy(QUOTIENT_FRAME_BASE, 0, QUOTIENT_FRAME_LEN) + + let r := FR_MODULUS + + // This included block is the main body of the evaluator. It: + // 1. evaluates gate/permutation/lookup/trash identities in the + // same order as Rust `partially_evaluate_identities`; + // 2. y-batches fully evaluated identities into + // quotient_eval_numer; + // 3. y-batches simple-selector identities into + // SELECTOR_ACC_MPTR buckets; + // 4. writes -quotient_eval_numer to QUOTIENT_EVAL_MPTR. + // + // Depending on codegen settings, some identities are native Yul + // callbacks and the rest are executed by the compact q_program VM + // stored in the copied VK payload. + // + // The upstream Rust comments call out that simple multiplicative + // selectors do not appear as normal proof eval scalars. The Yul + // block mirrors that rule by accumulating those identities into + // SELECTOR_ACC_MPTR buckets for later multiplication by fixed + // selector commitments, while fully evaluated identities contribute + // to the negated expected scalar. // Optional quotient helper functions. Each one is rendered only + // when the Rust lowering pass recognized the corresponding + // expression shape in this generated verifier. They are pure Fr + // helpers and share the same FR_MODULUS as the surrounding + // numerator block. + // VK-specialized identity helper for Poseidon S-box terms. + // + // Rust source shape: + // circuits/src/hash/poseidon/poseidon_chip.rs::sbox + // full_round_gate / partial_round_gate + // circuits/src/hash/poseidon/round_skips.rs::RoundId + // + // The Rust verifier only sees this as an Expression tree from + // `vk.cs.gates`; the generator emits q_pow5 after recognizing five + // equal multiplicative factors. It is a codegen shortcut for x^5, + // not a separate verifier rule. + function q_pow5(x) -> z { + let q_r := FR_MODULUS + let x2 := mulmod(x, x, q_r) + z := mulmod(x, mulmod(x2, x2, q_r), q_r) + } // =============================================================== + // Batched identity numerator / linearization target. + // + // This block does not evaluate the quotient polynomial h(x), and + // the proof does not provide an h(x) scalar to trust. Instead it: + // + // 1. Reconstructs the y-batched constraint numerator nu_y(x) + // from the alleged polynomial evaluations read after the + // transcript sampled x. + // 2. Stores -nu_y(x) as the expected opening scalar for the + // linearized commitment. + // + // The commitment side is built in the next block from the quotient + // limb commitments as (1 - x^n) * Σ_i x_split^i * Q_i, plus any + // simple-selector commitments. The PCS check later binds that + // linearized commitment to this expected scalar at x. + // + // Rust source-of-truth: + // - verifier.rs reads quotient commitments, samples x, then + // reads/computes all evaluations used below. + // - mod.rs::partially_evaluate_identities returns identities in + // gate, permutation, lookup, trash order. + // - linearization/verifier.rs::compute_linearization_commitment + // reverse-folds those identities by powers of y, sends + // simple-selector identities to selector commitment scalars, + // and subtracts fully-evaluated identities into expected_eval. + // + // This template is shared by the monolithic and external quotient + // paths. In the external path, Halo2QuotientEvaluator first copies + // the verifier memory frame into the same generated addresses. + // + // Runtime inputs expected to exist before this block starts: + // - `r` is the BLS12-381 scalar-field modulus. + // - Y_MPTR holds the quotient batching challenge y. + // - X_MPTR, L_*_MPTR, INSTANCE_EVAL_MPTR, and + // REVERSED_EVALS_MPTR hold values parsed or derived by the + // main verifier after the transcript sampled x. + // - VK_MPTR holds the pinned VK payload; in compact mode that + // payload includes the quotient constant table and bytecode. + // + // Runtime outputs written by this block: + // - QUOTIENT_EVAL_MPTR receives the scalar expected opening for + // the linearized commitment, namely -nu_y(x). + // - SELECTOR_ACC_MPTR[0..num_simple_selectors) receives one + // linearization scalar per generated simple selector. + // + // Line-by-line reading conventions used below: + // + // * Every runtime value is one canonical Fr element stored in a + // 256-bit EVM memory word. The small integer operands decoded + // from q_program are never field values; they are pointers, + // constant-table slots, selector indexes, offsets, or counts. + // + // * `mload(ptr)` is the only way the VM turns a small pointer + // operand into a real 255-bit field element. The value loaded + // from memory is then combined with `addmod(..., r)` or + // `mulmod(..., r)`, so every arithmetic line is reduced modulo + // the BLS12-381 scalar-field order. + // + // * `q_top` is the cached top of the VM operand stack. When an + // opcode needs to push while `q_top` is already live, the old + // value is written to `q_sp` and `q_sp` is advanced by one + // word. Binary `ADD`/`MUL` move `q_sp` back by one word and + // combine that spilled value with `q_top`. + // + // * Identity boundaries are explicit. Expression opcodes leave + // one value in `q_top`; `FOLD_MAIN` or `FOLD_SELECTOR` consumes + // it and advances the global y-batch position. Native callback + // opcodes are only emitted at empty-stack boundaries and run + // generated Yul that performs the same fold side effects. + // + // * The generated Solidity source intentionally emits comments + // before opcode cases. Those comments are documentation only: + // they do not affect bytecode, but they make rendered verifier + // assembly readable without jumping back to Rust codegen. + // =============================================================== + { + // Compact quotient-program mode. + // + // The largest identity expressions are not all emitted as + // unrolled Yul. Instead, most arithmetic is encoded as a small + // q_program bytecode stored in the VK payload. This block + // interprets that program, while selected heavy identities may + // still be emitted as native callbacks for gas. + // + // Compact mode is a code-size trade: short bytecode operands + // name already-planned memory slots, and the interpreter turns + // those names into Fr arithmetic. The opcode stream is fully + // generated and pinned by the VK/runtime codehash; no proof + // calldata can alter control flow. + // Load the quotient batching challenge used by every fold. + let y := mload(Y_MPTR) + + // q_const_mptr points to Fr constants used by the VM. + // q_program_mptr points to the bytecode stream. + // Constants are stored as consecutive 32-byte Fr words. + let q_const_mptr := 0x3a60 + // Program bytes are also stored in the VK payload, packed into + // 32-byte words by PackedProgramCodec. + let q_program_mptr := 0x50a0 + // Running Horner accumulator for fully evaluated identities. + // After all identities, this is nu_y(x) for the `None` + // identity group. + // Initialize A = 0 before scanning the identity stream. + mstore(0xb280, 0) + // Simple selectors are grouped into separate linearization + // buckets. They start at zero for every proof. + // q_sel_zero_off walks selector bucket byte offsets. + for { let q_sel_zero_off := 0 } lt(q_sel_zero_off, 0x0140) { q_sel_zero_off := add(q_sel_zero_off, 0x20) } { + // B_s = 0 for each simple selector bucket. + mstore(add(SELECTOR_ACC_MPTR, q_sel_zero_off), 0) + } + // Codegen knows the selector identity positions. Precompute + // the y^k powers needed for selector gap and tail updates, + // avoiding a runtime y^-1 modexp and per-identity selector + // scale maintenance. + { + // q_y_power holds y^i at the current loop index. + let q_y_power := 1 + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0xb2c0, 1) + // Start at i=1 because y^0 = 1 is written above. + for { let q_y_power_i := 1 } lt(q_y_power_i, 49) { q_y_power_i := add(q_y_power_i, 1) } { + // Advance from y^(i-1) to y^i modulo Fr. + q_y_power := mulmod(q_y_power, y, r) + // Store y^i at selector_power_mptr + 32*i. + mstore(add(0xb2c0, shl(5, q_y_power_i)), q_y_power) + } + } + + // Direct inline prefix. These identities are generated as Yul + // before entering the VM. They use the same fold snippets as + // VM/native identities, so they occupy the same y-batch order. + { + let var0 := 0x1 + let f_3 := mload(0x9ac0) + let f_4 := mload(0x99c0) + let a_0 := mload(0x94a0) + let var1 := mulmod(f_4, a_0, r) + let var2 := addmod(f_3, var1, r) + let f_5 := mload(0x99e0) + let a_1 := mload(0x94c0) + let var3 := mulmod(f_5, a_1, r) + let var4 := addmod(var2, var3, r) + let f_6 := mload(0x9a00) + let a_2 := mload(0x94e0) + let var5 := mulmod(f_6, a_2, r) + let var6 := addmod(var4, var5, r) + let f_7 := mload(0x9a20) + let a_3 := mload(0x9500) + let var7 := mulmod(f_7, a_3, r) + let var8 := addmod(var6, var7, r) + let f_8 := mload(0x9a40) + let a_4 := mload(0x9520) + let var9 := mulmod(f_8, a_4, r) + let var10 := addmod(var8, var9, r) + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var11 := mulmod(f_0, a_0_next_1, r) + let var12 := addmod(var10, var11, r) + let f_1 := mload(0x9a80) + let var13 := mulmod(f_1, a_0, r) + let var14 := mulmod(var13, a_1, r) + let var15 := addmod(var12, var14, r) + let f_2 := mload(0x9aa0) + let var16 := mulmod(f_2, a_0, r) + let var17 := mulmod(var16, a_2, r) + let var18 := addmod(var15, var17, r) + let var19 := mulmod(var0, var18, r) + mstore(0xb8e0, var19) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_1 := mload(0x94c0) + let a_2 := mload(0x94e0) + let var1 := addmod(a_1, a_2, r) + let a_3 := mload(0x9500) + let var2 := addmod(0, sub(r, a_3), r) + let var3 := addmod(var1, var2, r) + let a_4 := mload(0x9520) + let var4 := addmod(0, sub(r, a_4), r) + let var5 := addmod(var3, var4, r) + let var6 := mulmod(var0, var5, r) + mstore(0xb8e0, var6) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let f_4 := mload(0x99c0) + let var1 := addmod(a_0, f_4, r) + let a_0_next_1 := mload(0x9540) + let var2 := addmod(0, sub(r, a_0_next_1), r) + let var3 := addmod(var1, var2, r) + let var4 := mulmod(var0, var3, r) + mstore(0xb8e0, var4) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_1 := mload(0x94c0) + let f_5 := mload(0x99e0) + let var1 := addmod(a_1, f_5, r) + let a_1_next_1 := mload(0x9560) + let var2 := addmod(0, sub(r, a_1_next_1), r) + let var3 := addmod(var1, var2, r) + let var4 := mulmod(var0, var3, r) + mstore(0xb8e0, var4) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + + // VM registers: + // q_pc current bytecode pointer + // q_end end of bytecode stream + // q_sp memory stack pointer for non-top stack values + // q_top cached top-of-stack value + // q_has_top whether q_top currently holds a stack value + // + // The cached top reduces memory traffic in the interpreter. + // q_sp's registered range must cover the interpreted operand + // stack plus any native callback scratch that reuses this base + // pointer. In particular, the native permutation callback + // writes a structured scratch table at program.stack_mptr. + // q_pc starts at the first encoded instruction. + let q_pc := q_program_mptr + // q_end is an exclusive byte pointer for the VM loop. + let q_end := add(q_program_mptr, 0x11cf) + // q_sp starts at the first free stack word. + let q_sp := 0xb8e0 + // q_top is meaningless until q_has_top is set. + let q_top := 0 + // q_has_top = 0 means the VM stack is empty. + let q_has_top := 0 + + // q_program opcode summary: + // 0x01/0x09 push const 0x02/0x05 push memory + // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg + // 0x0a fold main identity 0x0b fold selector identity + // 0x0c..0x11 add/mul const or memory into top + // 0x12..0x16 fused add-mul runs + // 0x17/0x18 reserved + // 0x19 native permutation 0x1b native heavy identity + // 0x1c LIN7 0x1d BILIN7_ROW + // 0x1e BILIN7_PAIRWISE 0x1f native lookup + // 0x20 POW5 0x21 MODARITH7 + // 0x22 AFFINE_SUM + // + // The default IVC verifier uses one physical encoding for the + // logical VM: compact byte-oriented opcodes with variable-width + // operands, dynamic runs, and limb-aware cases. + + // Byte-oriented encoding: opcodes are one byte followed by + // variable-width operand bytes. + for { } lt(q_pc, q_end) { } { + // The bytecode table is byte-addressed, but EVM memory + // loads whole words. `byte(0, mload(q_pc))` extracts the + // opcode at the current byte cursor; each case advances + // q_pc by exactly its operand width. + let q_op := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + + switch q_op + // VM 0x05 PUSH_MEM_U16 (bytes): next two bytes are a short memory pointer. + case 0x05 { + // Operand layout: u16 absolute memory pointer. The + // memory planner keeps the hot quotient frame below + // 64 KiB when this compact form is emitted. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + if q_has_top { + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } + q_top := mload(q_ptr) + q_has_top := 1 + } + // VM 0x06 ADD: pop one spilled stack word and add it to q_top. + case 0x06 { + // The safety validator guarantees a spilled operand + // exists before ADD. q_top is the right operand. + q_sp := sub(q_sp, 0x20) + q_top := addmod(mload(q_sp), q_top, r) + } + // VM 0x08 NEG: replace q_top with its Fr negation. + case 0x08 { + // addmod(0, r - x, r) maps zero back to zero and every + // nonzero scalar to its canonical additive inverse. + q_top := addmod(0, sub(r, q_top), r) + } + // VM 0x0d MUL_CONST_U8: multiply q_top by a small constant-table slot. + case 0x0d { + // One-byte constant-index multiply, used by short + // affine chains after an initial PUSH. + let qconst := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + q_top := mulmod(q_top, mload(add(q_const_mptr, shl(5, qconst))), r) + } + // VM 0x10 ADD_MEM_U16: add a short memory load into q_top. + case 0x10 { + // Operand layout: u16 pointer. The pointed word is an + // already range-checked Fr scalar in verifier memory. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + q_top := addmod(q_top, mload(q_ptr), r) + } + // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. + case 0x11 { + // In-place multiply by a planned memory word. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + q_top := mulmod(q_top, mload(q_ptr), r) + } + // Limb-aware opcodes are opt-in compact forms for + // structurally recognized non-SHA foreign-field shapes. + // Coefficients are indexes into q_const_mptr, which is + // generated from VK/program data, never from proof + // calldata. + // + // Rust source shape: + // proofs/src/plonk/mod.rs::partially_evaluate_identities + // circuits/src/field/foreign/util.rs::{sum_exprs,pair_wise_prod} + // circuits/src/field/foreign/params.rs::{base_powers,double_base_powers} + // + // "Foreign field" means the circuit represents elements + // modulo another modulus m as 7 limbs in base + // 2^LOG2_BASE. The verifier does not switch fields; it + // evaluates the lowered identity over BLS12-381 Fr, using + // Fr coefficients equal to base^i mod m or base^(i+j) mod m. + // VM 0x21 MODARITH7: byte-only fused affine 7-limb foreign-field/ECC identity. + case 0x21 { + // MODARITH7: + // maybe_cond * ( + // c + // + sum LIN7 blocks + // + sum BILIN7_ROW blocks + // + sum BILIN7_PAIRWISE blocks + // + sum coeff[k] * mload(ptr[k]) + // + sum coeff[k] * mload(lhs[k]) * mload(rhs[k]) + // ) + // It is a dispatch/operand-load optimization only; + // all coefficients still come from the generated + // quotient constant table. + // + // Flags: + // bit 0: multiply the final affine sum by a memory + // condition word. + // bit 1: seed q_acc from a constant-table word + // before reading the counted term blocks. + let q_flags := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + let q_cond_ptr := 0 + if and(q_flags, 0x01) { + // Optional condition pointer. When present, the + // whole identity is gated by mload(q_cond_ptr). + q_cond_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + } + + let q_acc := 0 + if and(q_flags, 0x02) { + // Optional constant seed for affine identities + // with a standalone constant term. + let qconst := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + q_acc := mload(add(q_const_mptr, shl(5, qconst))) + } + + // Five one-byte counters describe the blocks that + // follow. Each block has a fixed-width internal layout, + // so q_pc can advance without per-term tags. + let q_counts_word := mload(q_pc) + let q_lin_count := byte(0, q_counts_word) + let q_row_count := byte(1, q_counts_word) + let q_pairwise_count := byte(2, q_counts_word) + let q_mem_count := byte(3, q_counts_word) + let q_product_count := byte(4, q_counts_word) + q_pc := add(q_pc, 5) + + if q_has_top { + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } + + // LIN7 blocks: q_acc += sum_i c_i * limb_i. + for { let q_lin_block := 0 } lt(q_lin_block, q_lin_count) { q_lin_block := add(q_lin_block, 1) } { + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_ptr := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), + r + ) + } + } + + // BILIN7_ROW blocks: q_acc += lhs * sum_i c_i * rhs_i. + for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { + let q_lhs := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + let q_lhs_value := mload(q_lhs) + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_rhs := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod( + mulmod(q_lhs_value, mload(q_rhs), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + } + + // BILIN7_PAIRWISE blocks: q_acc += weighted 7-by-7 + // product convolution. + for { let q_pair_block := 0 } lt(q_pair_block, q_pairwise_count) { q_pair_block := add(q_pair_block, 1) } { + let q_pair_word := mload(q_pc) + let q_lhs_base := shr(240, q_pair_word) + let q_rhs_base := and(shr(224, q_pair_word), 0xffff) + q_pc := add(q_pc, 0x04) + let q_coeff_pc := q_pc + q_pc := add(q_pc, 13) + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_lhs_value := mload(add(q_lhs_base, shl(5, q_i))) + for { let q_j := 0 } lt(q_j, 7) { q_j := add(q_j, 1) } { + let qconst := byte(0, mload(add(q_coeff_pc, add(q_i, q_j)))) + q_acc := addmod( + q_acc, + mulmod( + mulmod(q_lhs_value, mload(add(q_rhs_base, shl(5, q_j))), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + } + } + + // Extra linear memory terms outside the 7-limb shapes. + for { let q_mem_block := 0 } lt(q_mem_block, q_mem_count) { q_mem_block := add(q_mem_block, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_ptr := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), + r + ) + } + + // Extra binary product terms outside the 7-limb shapes. + for { let q_product_block := 0 } lt(q_product_block, q_product_count) { q_product_block := add(q_product_block, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_lhs := and(shr(232, q_word), 0xffff) + let q_rhs := and(shr(216, q_word), 0xffff) + q_pc := add(q_pc, 5) + q_acc := addmod( + q_acc, + mulmod( + mulmod(mload(q_lhs), mload(q_rhs), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + + if and(q_flags, 0x01) { + // Apply the optional gate condition last so every + // subterm shares the same selector/condition. + q_acc := mulmod(mload(q_cond_ptr), q_acc, r) + } + // MODARITH7 pushes its fused identity value. + q_top := q_acc + q_has_top := 1 + } + // Native permutation callback. It evaluates the + // permutation identities from permutation.rs at this exact + // VM position, preserving the Rust identity order while + // avoiding a large interpreted product loop. + // VM 0x19 NATIVE_PERMUTATION: marker for the generated permutation callback. + case 0x19 { + // Native callbacks are identity-boundary opcodes. They + // must not inherit any partially evaluated VM stack + // state from the previous expression. + q_top := 0 + q_has_top := 0 + // The generated loop below uses program.stack_mptr as + // its scratch-table base, not as a conventional VM + // stack. The Rust memory planner must reserve enough + // words for structured_permutation_scratch_words(meta) + // whenever this opcode can appear. + q_sp := 0xb8e0 + // The generated lines below call the same fold snippets + // used by interpreted expressions, so trace IDs and + // y-batch positions remain contiguous. + { + let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 + let q_perm_vals := 0xb8e0 + let q_perm_sigmas := 0xbb20 + let q_perm_z_cur := 0xbd60 + let q_perm_z_next := 0xbe20 + let q_perm_z_last := 0xbee0 + let q_perm_delta_base_ptr := 0xbf80 + let q_perm_num_cols := 18 + let q_perm_num_sets := 6 + let q_perm_chunk_len := 3 + let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 + mstore(add(q_perm_vals, 0x0), mload(0x99a0)) + { + for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { + let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) + let q_perm_val_load_src_off := q_perm_val_load_dst_off + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x94a0, q_perm_val_load_src_off))) + } + } + mstore(add(q_perm_vals, 0xc0), mload(0x9480)) + mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) + { + for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 9) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { + let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) + let q_perm_val_load_src_off := q_perm_val_load_dst_off + mstore(add(add(q_perm_vals, 0x100), q_perm_val_load_dst_off), mload(add(0x95a0, q_perm_val_load_src_off))) + } + } + mstore(add(q_perm_vals, 0x220), mload(0x9980)) + { + for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 18) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { + let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) + let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x9bc0, q_perm_sigma_load_src_off))) + } + } + { + for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 6) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { + let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) + let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x9e00, q_perm_z_cur_load_src_off))) + } + } + { + for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 6) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { + let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) + let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x9e20, q_perm_z_next_load_src_off))) + } + } + { + for { let q_perm_z_last_load_i := 0 } lt(q_perm_z_last_load_i, 5) { q_perm_z_last_load_i := add(q_perm_z_last_load_i, 1) } { + let q_perm_z_last_load_dst_off := shl(5, q_perm_z_last_load_i) + let q_perm_z_last_load_src_off := mul(q_perm_z_last_load_i, 0x60) + mstore(add(add(q_perm_z_last, 0x0), q_perm_z_last_load_dst_off), mload(add(0x9e40, q_perm_z_last_load_src_off))) + } + } + let q_perm_eval := 0 + q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + let q_perm_zn := mload(add(q_perm_z_cur, 0xa0)) + q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + for { let q_perm_i := 1 } lt(q_perm_i, 6) { q_perm_i := add(q_perm_i, 1) } { + let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) + let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) + q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + } + mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) + for { let q_perm_set := 0 } lt(q_perm_set, 6) { q_perm_set := add(q_perm_set, 1) } { + let q_perm_start := mul(q_perm_set, q_perm_chunk_len) + let q_perm_end := add(q_perm_start, q_perm_chunk_len) + if gt(q_perm_end, q_perm_num_cols) { q_perm_end := q_perm_num_cols } + let q_perm_left := mload(add(q_perm_z_next, shl(5, q_perm_set))) + let q_perm_right := mload(add(q_perm_z_cur, shl(5, q_perm_set))) + let q_perm_delta_pow := mload(q_perm_delta_base_ptr) + for { let q_perm_j := q_perm_start } lt(q_perm_j, q_perm_end) { q_perm_j := add(q_perm_j, 1) } { + let q_perm_off := shl(5, q_perm_j) + let q_perm_v := mload(add(q_perm_vals, q_perm_off)) + let q_perm_s := mload(add(q_perm_sigmas, q_perm_off)) + q_perm_left := mulmod(q_perm_left, addmod(addmod(q_perm_v, mulmod(mload(BETA_MPTR), q_perm_s, r), r), mload(GAMMA_MPTR), r), r) + q_perm_right := mulmod(q_perm_right, addmod(addmod(q_perm_v, q_perm_delta_pow, r), mload(GAMMA_MPTR), r), r) + q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) + } + q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) + } + } + } + // Native lookup callback. This whole-family opcode + // evaluates the LogUp boundary, helper-chunk, and + // accumulator identities at this VM position, preserving + // the Rust y-batch order while avoiding many interpreted + // product-loop opcodes. + // VM 0x1f NATIVE_LOOKUP: marker for the generated LogUp lookup callback. + case 0x1f { + // Reset VM stack state before entering structured + // lookup Yul. Lookup callbacks own their scratch + // layout and perform all needed folds internally. + q_top := 0 + q_has_top := 0 + // The generated loop below uses program.stack_mptr as + // f+beta/prefix/suffix scratch rather than as a + // conventional VM stack. The Rust memory planner must + // reserve structured_lookup_scratch_words(meta). + q_sp := 0xb8e0 + // Generated LogUp code follows the same y-batch order + // as the Rust identity stream. + { + let q_lookup_f := 0xb8e0 + let q_lookup_prefix := 0xb960 + let q_lookup_suffix := 0xb9e0 + let q_lookup_l0 := mload(L_0_MPTR) + let q_lookup_llast := mload(L_LAST_MPTR) + let q_lookup_lblind := mload(L_BLIND_MPTR) + let q_lookup_lsum := addmod(q_lookup_l0, q_lookup_llast, r) + let q_lookup_active := addmod(1, sub(r, addmod(q_lookup_llast, q_lookup_lblind, r)), r) + let q_lookup_beta := mload(BETA_MPTR) + let q_lookup_theta := mload(THETA_MPTR) + { + { + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa060), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let f_10 := mload(0x9ae0) + let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) + let var1 := mulmod(var0, q_lookup_theta, r) + for { let q_lookup_shared_i := 0 } lt(q_lookup_shared_i, 4) { q_lookup_shared_i := add(q_lookup_shared_i, 1) } { + let q_lookup_shared_off := shl(5, q_lookup_shared_i) + let q_lookup_shared_tail := mload(add(0x94c0, q_lookup_shared_off)) + let q_lookup_shared_compressed := addmod(var1, q_lookup_shared_tail, r) + mstore(add(q_lookup_f, q_lookup_shared_off), addmod(q_lookup_shared_compressed, q_lookup_beta, r)) + } + let q_lookup_product := 1 + for { let q_lookup_prod_i := 0 } lt(q_lookup_prod_i, 4) { q_lookup_prod_i := add(q_lookup_prod_i, 1) } { + q_lookup_product := mulmod(q_lookup_product, mload(add(q_lookup_f, shl(5, q_lookup_prod_i))), r) + } + mstore(q_lookup_prefix, 1) + for { let q_lookup_pref_i := 1 } lt(q_lookup_pref_i, 4) { q_lookup_pref_i := add(q_lookup_pref_i, 1) } { + let q_lookup_pref_prev := sub(q_lookup_pref_i, 1) + mstore(add(q_lookup_prefix, shl(5, q_lookup_pref_i)), mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_pref_prev))), mload(add(q_lookup_f, shl(5, q_lookup_pref_prev))), r)) + } + mstore(add(q_lookup_suffix, 0x60), 1) + for { let q_lookup_suf_i := sub(4, 1) } gt(q_lookup_suf_i, 0) { q_lookup_suf_i := sub(q_lookup_suf_i, 1) } { + let q_lookup_suf_prev := sub(q_lookup_suf_i, 1) + mstore(add(q_lookup_suffix, shl(5, q_lookup_suf_prev)), mulmod(mload(add(q_lookup_suffix, shl(5, q_lookup_suf_i))), mload(add(q_lookup_f, shl(5, q_lookup_suf_i))), r)) + } + let q_lookup_sum := 0 + for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 4) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { + q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) + } + let q_lookup_eval := addmod(mulmod(mload(0xa040), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let q_lookup_sum_h := mload(0xa040) + let f_17 := mload(0x9b60) + let f_11 := mload(0x9b00) + let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) + let f_12 := mload(0x9b20) + let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) + let q_lookup_s_sum_h := mulmod(f_17, q_lookup_sum_h, r) + let q_lookup_diff := addmod(mload(0xa080), sub(r, addmod(mload(0xa060), q_lookup_s_sum_h, r)), r) + let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa020), r) + let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + } + { + { + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa0e0), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let a_14 := mload(0x9980) + let var0 := addmod(mulmod(0, q_lookup_theta, r), a_14, r) + let a_0 := mload(0x94a0) + let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_0, r) + let a_1 := mload(0x94c0) + let var2 := addmod(mulmod(var1, q_lookup_theta, r), a_1, r) + let a_2 := mload(0x94e0) + let var3 := addmod(mulmod(var2, q_lookup_theta, r), a_2, r) + let a_3 := mload(0x9500) + let var4 := addmod(mulmod(var3, q_lookup_theta, r), a_3, r) + let a_4 := mload(0x9520) + let var5 := addmod(mulmod(var4, q_lookup_theta, r), a_4, r) + let a_5 := mload(0x95a0) + let var6 := addmod(mulmod(var5, q_lookup_theta, r), a_5, r) + let a_6 := mload(0x95c0) + let var7 := addmod(mulmod(var6, q_lookup_theta, r), a_6, r) + let a_7 := mload(0x95e0) + let var8 := addmod(mulmod(var7, q_lookup_theta, r), a_7, r) + let a_8 := mload(0x9600) + let var9 := addmod(mulmod(var8, q_lookup_theta, r), a_8, r) + let a_9 := mload(0x9620) + let var10 := addmod(mulmod(var9, q_lookup_theta, r), a_9, r) + let a_10 := mload(0x9640) + let var11 := addmod(mulmod(var10, q_lookup_theta, r), a_10, r) + let a_11 := mload(0x9660) + let var12 := addmod(mulmod(var11, q_lookup_theta, r), a_11, r) + let a_12 := mload(0x9680) + let var13 := addmod(mulmod(var12, q_lookup_theta, r), a_12, r) + let a_13 := mload(0x96a0) + let var14 := addmod(mulmod(var13, q_lookup_theta, r), a_13, r) + let f_13 := mload(0x9b40) + let var15 := addmod(mulmod(var14, q_lookup_theta, r), f_13, r) + let q_lookup_eval := addmod(mulmod(mload(0xa0c0), addmod(var15, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let q_lookup_sum_h := mload(0xa0c0) + let var0 := 0x1 + let f_26 := mload(0x9ba0) + let var1 := addmod(0, sub(r, f_26), r) + let var2 := addmod(var0, var1, r) + let a_14 := mload(0x9980) + let var3 := mulmod(var2, a_14, r) + let var4 := addmod(mulmod(0, q_lookup_theta, r), var3, r) + let a_0 := mload(0x94a0) + let var5 := mulmod(var2, a_0, r) + let var6 := addmod(mulmod(var4, q_lookup_theta, r), var5, r) + let a_1 := mload(0x94c0) + let var7 := mulmod(var2, a_1, r) + let var8 := addmod(mulmod(var6, q_lookup_theta, r), var7, r) + let a_2 := mload(0x94e0) + let var9 := mulmod(var2, a_2, r) + let var10 := addmod(mulmod(var8, q_lookup_theta, r), var9, r) + let a_3 := mload(0x9500) + let var11 := mulmod(var2, a_3, r) + let var12 := addmod(mulmod(var10, q_lookup_theta, r), var11, r) + let a_4 := mload(0x9520) + let var13 := mulmod(var2, a_4, r) + let var14 := addmod(mulmod(var12, q_lookup_theta, r), var13, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var2, a_5, r) + let var16 := addmod(mulmod(var14, q_lookup_theta, r), var15, r) + let a_6 := mload(0x95c0) + let var17 := mulmod(var2, a_6, r) + let var18 := addmod(mulmod(var16, q_lookup_theta, r), var17, r) + let a_7 := mload(0x95e0) + let var19 := mulmod(var2, a_7, r) + let var20 := addmod(mulmod(var18, q_lookup_theta, r), var19, r) + let a_8 := mload(0x9600) + let var21 := mulmod(var2, a_8, r) + let var22 := addmod(mulmod(var20, q_lookup_theta, r), var21, r) + let a_9 := mload(0x9620) + let var23 := mulmod(var2, a_9, r) + let var24 := addmod(mulmod(var22, q_lookup_theta, r), var23, r) + let a_10 := mload(0x9640) + let var25 := mulmod(var2, a_10, r) + let var26 := addmod(mulmod(var24, q_lookup_theta, r), var25, r) + let a_11 := mload(0x9660) + let var27 := mulmod(var2, a_11, r) + let var28 := addmod(mulmod(var26, q_lookup_theta, r), var27, r) + let a_12 := mload(0x9680) + let var29 := mulmod(var2, a_12, r) + let var30 := addmod(mulmod(var28, q_lookup_theta, r), var29, r) + let a_13 := mload(0x96a0) + let var31 := mulmod(var2, a_13, r) + let var32 := addmod(mulmod(var30, q_lookup_theta, r), var31, r) + let f_13 := mload(0x9b40) + let var33 := mulmod(var2, f_13, r) + let var34 := addmod(mulmod(var32, q_lookup_theta, r), var33, r) + let q_lookup_s_sum_h := mulmod(var0, q_lookup_sum_h, r) + let q_lookup_diff := addmod(mload(0xa100), sub(r, addmod(mload(0xa0e0), q_lookup_s_sum_h, r)), r) + let q_lookup_t_beta := addmod(var34, q_lookup_beta, r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa0a0), r) + let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + } + } + } + // Native callbacks are generated only for the heaviest + // recognized Midfall gate identities. All other gate and + // non-native identity arithmetic remains in + // the compact q_program VM above, preserving the Rust + // `partially_evaluate_identities` order. + // VM 0x1b NATIVE_IDENTITY: marker for generated heavy-gate callbacks. + case 0x1b { + // Operand layout: u16 native callback index. The + // manifest validates that callback indexes appear in + // generated order and target existing switch cases. + let q_native_idx := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + // Heavy identities are whole expressions, so clear the + // interpreter stack before dispatching. + q_top := 0 + q_has_top := 0 + q_sp := 0xb8e0 + // Native identity sub-cases are generated from selected heavy gate identities. + switch q_native_idx + case 0 { + { + let var0 := 0x1 + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var1 := addmod(0, sub(r, a_0_next_1), r) + let var2 := addmod(f_0, var1, r) + let var3 := 0x1b8114c381b922fd5d6d241210e2d8a68ad5744053ba9e776118de4107b51ace + let a_0 := mload(0x94a0) + let var4 := mulmod(a_0, a_0, r) + let a_3 := mload(0x9500) + let var5 := mulmod(var4, a_3, r) + let var6 := mulmod(var3, var5, r) + let var7 := addmod(var2, var6, r) + let var8 := 0x3df32e4cc4cb2ed20e5d21899cf5331775990ccaec4c09b4e3717213fcc0d763 + let a_1 := mload(0x94c0) + let var9 := mulmod(a_1, a_1, r) + let a_4 := mload(0x9520) + let var10 := mulmod(var9, a_4, r) + let var11 := mulmod(var8, var10, r) + let var12 := addmod(var7, var11, r) + let var13 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 + let a_2 := mload(0x94e0) + let var14 := mulmod(a_2, a_2, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var14, a_5, r) + let var16 := mulmod(var13, var15, r) + let var17 := addmod(var12, var16, r) + let var18 := mulmod(var0, var17, r) + mstore(0xb8e0, var18) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 1 { + { + let var0 := 0x1 + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) + let var1 := addmod(0, sub(r, a_1_next_1), r) + let var2 := addmod(f_1, var1, r) + let var3 := 0x404d21073985d14e432a4ad76d3fae06ca74314b950fe7b1d7f501cd31a8b374 + let a_0 := mload(0x94a0) + let var4 := mulmod(a_0, a_0, r) + let a_3 := mload(0x9500) + let var5 := mulmod(var4, a_3, r) + let var6 := mulmod(var3, var5, r) + let var7 := addmod(var2, var6, r) + let var8 := 0xb2cc8704264c6bd81bc620e9e524d4b73e9b2317679422ff7fa1603955649f1 + let a_1 := mload(0x94c0) + let var9 := mulmod(a_1, a_1, r) + let a_4 := mload(0x9520) + let var10 := mulmod(var9, a_4, r) + let var11 := mulmod(var8, var10, r) + let var12 := addmod(var7, var11, r) + let var13 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f + let a_2 := mload(0x94e0) + let var14 := mulmod(a_2, a_2, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var14, a_5, r) + let var16 := mulmod(var13, var15, r) + let var17 := addmod(var12, var16, r) + let var18 := mulmod(var0, var17, r) + mstore(0xb8e0, var18) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 2 { + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let a_0_next_1 := mload(0x9540) + let var1 := mulmod(a_0, a_0_next_1, r) + let var2 := 0x100000000000000 + let a_1_next_1 := mload(0x9560) + let var3 := mulmod(a_0, a_1_next_1, r) + let var4 := mulmod(var2, var3, r) + let var5 := addmod(var1, var4, r) + let var6 := 0x10000000000000000000000000000 + let a_2_next_1 := mload(0x9580) + let var7 := mulmod(a_0, a_2_next_1, r) + let var8 := mulmod(var6, var7, r) + let var9 := addmod(var5, var8, r) + let a_1 := mload(0x94c0) + let var10 := mulmod(a_1, a_0_next_1, r) + let var11 := mulmod(var2, var10, r) + let var12 := addmod(var9, var11, r) + let var13 := mulmod(a_1, a_1_next_1, r) + let var14 := mulmod(var6, var13, r) + let var15 := addmod(var12, var14, r) + let var16 := 0x3212e00cde6d2002b119d800000347fcb8 + let a_6_next_1 := mload(0x9720) + let var17 := mulmod(a_1, a_6_next_1, r) + let var18 := mulmod(var16, var17, r) + let var19 := addmod(var15, var18, r) + let a_2 := mload(0x94e0) + let var20 := mulmod(a_2, a_0_next_1, r) + let var21 := mulmod(var6, var20, r) + let var22 := addmod(var19, var21, r) + let a_5_next_1 := mload(0x9700) + let var23 := mulmod(a_2, a_5_next_1, r) + let var24 := mulmod(var16, var23, r) + let var25 := addmod(var22, var24, r) + let var26 := 0x297784894e27525bc342b7fde37dba9366 + let var27 := mulmod(a_2, a_6_next_1, r) + let var28 := mulmod(var26, var27, r) + let var29 := addmod(var25, var28, r) + let a_3 := mload(0x9500) + let a_4_next_1 := mload(0x96e0) + let var30 := mulmod(a_3, a_4_next_1, r) + let var31 := mulmod(var16, var30, r) + let var32 := addmod(var29, var31, r) + let var33 := mulmod(a_3, a_5_next_1, r) + let var34 := mulmod(var26, var33, r) + let var35 := addmod(var32, var34, r) + let var36 := 0x340f2ebe380a0f5eff4360543988a61dc2 + let var37 := mulmod(a_3, a_6_next_1, r) + let var38 := mulmod(var36, var37, r) + let var39 := addmod(var35, var38, r) + let a_4 := mload(0x9520) + let a_3_next_1 := mload(0x96c0) + let var40 := mulmod(a_4, a_3_next_1, r) + let var41 := mulmod(var16, var40, r) + let var42 := addmod(var39, var41, r) + let var43 := mulmod(a_4, a_4_next_1, r) + let var44 := mulmod(var26, var43, r) + let var45 := addmod(var42, var44, r) + let var46 := mulmod(a_4, a_5_next_1, r) + let var47 := mulmod(var36, var46, r) + let var48 := addmod(var45, var47, r) + let var49 := 0x13af65741744bd7bb2c6872df2b800320 + let var50 := mulmod(a_4, a_6_next_1, r) + let var51 := mulmod(var49, var50, r) + let var52 := addmod(var48, var51, r) + let a_5 := mload(0x95a0) + let var53 := mulmod(a_5, a_2_next_1, r) + let var54 := mulmod(var16, var53, r) + let var55 := addmod(var52, var54, r) + let var56 := mulmod(a_5, a_3_next_1, r) + let var57 := mulmod(var26, var56, r) + let var58 := addmod(var55, var57, r) + let var59 := mulmod(a_5, a_4_next_1, r) + let var60 := mulmod(var36, var59, r) + let var61 := addmod(var58, var60, r) + let var62 := mulmod(a_5, a_5_next_1, r) + let var63 := mulmod(var49, var62, r) + let var64 := addmod(var61, var63, r) + let var65 := 0x2cb9b546d20373eaf85e8f53db883cb548 + let var66 := mulmod(a_5, a_6_next_1, r) + let var67 := mulmod(var65, var66, r) + let var68 := addmod(var64, var67, r) + let a_6 := mload(0x95c0) + let var69 := mulmod(a_6, a_1_next_1, r) + let var70 := mulmod(var16, var69, r) + let var71 := addmod(var68, var70, r) + let var72 := mulmod(a_6, a_2_next_1, r) + let var73 := mulmod(var26, var72, r) + let var74 := addmod(var71, var73, r) + let var75 := mulmod(a_6, a_3_next_1, r) + let var76 := mulmod(var36, var75, r) + let var77 := addmod(var74, var76, r) + let var78 := mulmod(a_6, a_4_next_1, r) + let var79 := mulmod(var49, var78, r) + let var80 := addmod(var77, var79, r) + let var81 := mulmod(a_6, a_5_next_1, r) + let var82 := mulmod(var65, var81, r) + let var83 := addmod(var80, var82, r) + let var84 := 0xc8557e86f90d0d89eed6eb5349a0f8820 + let var85 := mulmod(a_6, a_6_next_1, r) + let var86 := mulmod(var84, var85, r) + let var87 := addmod(var83, var86, r) + let var88 := mulmod(var2, a_1, r) + let var89 := addmod(a_0, var88, r) + let var90 := mulmod(var6, a_2, r) + let var91 := addmod(var89, var90, r) + let var92 := addmod(var87, var91, r) + let var93 := mulmod(var2, a_1_next_1, r) + let var94 := addmod(a_0_next_1, var93, r) + let var95 := mulmod(var6, a_2_next_1, r) + let var96 := addmod(var94, var95, r) + let var97 := addmod(var92, var96, r) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) + let var98 := mulmod(var2, a_8, r) + let var99 := addmod(a_7, var98, r) + let a_9 := mload(0x9620) + let var100 := mulmod(var6, a_9, r) + let var101 := addmod(var99, var100, r) + let var102 := addmod(0, sub(r, var101), r) + let var103 := addmod(var97, var102, r) + let a_7_next_1 := mload(0x9740) + let var104 := 0x241eabfffeb153ffffb9feffffffffaaab + let var105 := mulmod(a_7_next_1, var104, r) + let var106 := addmod(0, sub(r, var105), r) + let var107 := addmod(var103, var106, r) + let var108 := addmod(0, sub(r, var16), r) + let var109 := addmod(var107, var108, r) + let a_8_next_1 := mload(0x9760) + let var110 := 0x73eda753299d7d483339d80809a1d80553b9202d7ffe85d4800008bb20000001 + let var111 := addmod(a_8_next_1, var110, r) + let var112 := 0x4000000000000000000000000000000000 + let var113 := mulmod(var111, var112, r) + let var114 := addmod(0, sub(r, var113), r) + let var115 := addmod(var109, var114, r) + let var116 := mulmod(var0, var115, r) + mstore(0xb8e0, var116) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x80) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 3 { + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let var1 := 0x10000000000000000000000000000 + let var2 := addmod(a_0, var1, r) + let var3 := 0x100000000000000 + let a_1 := mload(0x94c0) + let var4 := addmod(a_1, var1, r) + let var5 := mulmod(var3, var4, r) + let var6 := addmod(var2, var5, r) + let a_2 := mload(0x94e0) + let var7 := addmod(a_2, var1, r) + let var8 := mulmod(var1, var7, r) + let var9 := addmod(var6, var8, r) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) + let var10 := mulmod(var3, a_8, r) + let var11 := addmod(a_7, var10, r) + let a_9 := mload(0x9620) + let var12 := mulmod(var1, a_9, r) + let var13 := addmod(var11, var12, r) + let var14 := addmod(0, sub(r, var13), r) + let var15 := addmod(var9, var14, r) + let var16 := addmod(0, sub(r, var1), r) + let var17 := addmod(var15, var16, r) + let a_7_next_1 := mload(0x9740) + let var18 := 0x241eabfffeb153ffffb9feffffffffaaab + let var19 := mulmod(a_7_next_1, var18, r) + let var20 := addmod(0, sub(r, var19), r) + let var21 := addmod(var17, var20, r) + let var22 := 0xd9d44a30b019261257667fde3844a8cd6 + let var23 := addmod(0, sub(r, var22), r) + let var24 := addmod(var21, var23, r) + let a_8_next_1 := mload(0x9760) + let var25 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5b6e855000003ab00002 + let var26 := addmod(a_8_next_1, var25, r) + let var27 := 0x4000000000000000000000000000000000 + let var28 := mulmod(var26, var27, r) + let var29 := addmod(0, sub(r, var28), r) + let var30 := addmod(var24, var29, r) + let var31 := mulmod(var0, var30, r) + mstore(0xb8e0, var31) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xa0) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + default { revert(0, 0) } + } + // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. + case 0x0b { + // Operand layout packed into three bytes: + // high byte: selector bucket index; + // low u16 : y-power gap since this selector's + // previous contribution. + let q_selector_payload := shr(232, mload(q_pc)) + q_pc := add(q_pc, 3) + let q_sel_idx := shr(16, q_selector_payload) + let q_sel_gap := and(q_selector_payload, 0xffff) + let q_eval := q_top + q_has_top := 0 + // Simple-selector identity: keep the same y-batch + // position as main identities, then advance only this + // selector bucket by its codegen-known gap. + // + // The global fully-evaluated accumulator is still + // multiplied by y so later main identities land at the + // same y powers as Rust's reverse fold. + mstore(0xb280, mulmod(mload(0xb280), y, r)) + let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) + let q_sel_acc := mload(q_target_ptr) + if q_sel_gap { + // Selector buckets are sparse in the global + // identity stream. Precomputed y^gap advances only + // this selector's local accumulator. + q_sel_acc := mulmod(q_sel_acc, mload(add(0xb2c0, shl(5, q_sel_gap))), r) + } + mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) + } + // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. + default { + revert(0, 0) + } + } + // The VK-pinned bytecode must end exactly at q_end and every + // identity must have been consumed by a fold/native callback. + // This catches malformed generator output whose final opcode + // over-reads operands or leaves a partial expression live. + if iszero(eq(q_pc, q_end)) { revert(0, 0) } + if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } + + // Structured post-VM suffix. The current default uses this for + // regular trash constraints: it is smaller than fully unrolled + // Yul and cheaper than interpreting every trash operation. + // + // These generated blocks run after q_pc reaches q_end, but + // they still participate in the same identity order and write + // into the same numerator / selector accumulators. + { + let q_trash_tau := mload(TRASH_CHALLENGE_MPTR) + { + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var0 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000 + let var1 := mulmod(a_0_next_1, var0, r) + let var2 := addmod(f_0, var1, r) + let var3 := 0x590ba402032e82eb1f660ef09796c5686345a5054ed96dae8e2d233633788771 + let a_0 := mload(0x94a0) + let var4 := mulmod(var3, a_0, r) + let var5 := addmod(var2, var4, r) + let var6 := 0x52f789e4afc3801f7411102ee2f47cc5954a744e71cac98e75ea962a55a0a76f + let a_1 := mload(0x94c0) + let var7 := mulmod(var6, a_1, r) + let var8 := addmod(var5, var7, r) + let var9 := 0x3509dd2fe3aac0080783557fec090fb1cb4b2b0901253c55282024331d1fe1a8 + let a_2 := mload(0x94e0) + let var10 := q_pow5(a_2) + let var11 := mulmod(var9, var10, r) + let var12 := addmod(var8, var11, r) + let var13 := 0x333f8046ece5579cbd6872449c57f2703dfc8864cfadc06d587ff104a0d0c1f2 + let a_3 := mload(0x9500) + let var14 := q_pow5(a_3) + let var15 := mulmod(var13, var14, r) + let var16 := addmod(var12, var15, r) + let var17 := 0x412c98232b6ab8a47aa76ee814ef7ec6261987c9802f2cfc490e007951a60ca5 + let a_4 := mload(0x9520) + let var18 := q_pow5(a_4) + let var19 := mulmod(var17, var18, r) + let var20 := addmod(var16, var19, r) + let var21 := 0x53fded36d490ba6b05a5d10fd99ffe5456baec6a6a8753199d5ebdc33c99790e + let a_5 := mload(0x95a0) + let var22 := q_pow5(a_5) + let var23 := mulmod(var21, var22, r) + let var24 := addmod(var20, var23, r) + let var25 := 0x6ccb1c7d87f3c12a2bde4e68ac7f1e8b03481ba15d7f88f9a7f9b8310dd6d34 + let a_6 := mload(0x95c0) + let var26 := q_pow5(a_6) + let var27 := mulmod(var25, var26, r) + let var28 := addmod(var24, var27, r) + let var29 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 + let a_7 := mload(0x95e0) + let var30 := q_pow5(a_7) + let var31 := mulmod(var29, var30, r) + let var32 := addmod(var28, var31, r) + let var33 := addmod(mulmod(0, q_trash_tau, r), var32, r) + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) + let var34 := mulmod(a_1_next_1, var0, r) + let var35 := addmod(f_1, var34, r) + let var36 := 0x5b1fc262a28cbb8bf75d9b1a6edaa74591ec24cd9a209512213cec3a3c0f1a5d + let var37 := mulmod(var36, a_0, r) + let var38 := addmod(var35, var37, r) + let var39 := 0x4d0ea7f9c3fda06d9535b0fdafd8338bd47c2200b284fa71a325ff41ac358028 + let var40 := mulmod(var39, a_1, r) + let var41 := addmod(var38, var40, r) + let var42 := 0x26cc223e16f47c20e17cc6069605fa5a8af05ea4f6eb36029a641d23b818eb10 + let var43 := mulmod(var42, var10, r) + let var44 := addmod(var41, var43, r) + let var45 := 0x31e823a45e567484c1544e310c0fa5cd66547a8f0dde659ac61698c30e838d25 + let var46 := mulmod(var45, var14, r) + let var47 := addmod(var44, var46, r) + let var48 := 0x275a20361ea91992193920270d3e2d1f6361880ac0a439c64bef815d4469ba85 + let var49 := mulmod(var48, var18, r) + let var50 := addmod(var47, var49, r) + let var51 := 0x5f3a15bab4ce4097b1edc3a25002694b92395ce355a8a12fe557459d9633f701 + let var52 := mulmod(var51, var22, r) + let var53 := addmod(var50, var52, r) + let var54 := 0x301cf56f9b4577112cc4241cddf6484aaadedbf1bbd0f2351adf2e41c2fb2ecd + let var55 := mulmod(var54, var26, r) + let var56 := addmod(var53, var55, r) + let var57 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f + let var58 := mulmod(var57, var30, r) + let var59 := addmod(var56, var58, r) + let var60 := addmod(mulmod(var33, q_trash_tau, r), var59, r) + let f_2 := mload(0x9aa0) + let var61 := mulmod(a_3, var0, r) + let var62 := addmod(f_2, var61, r) + let var63 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 + let var64 := mulmod(var63, a_0, r) + let var65 := addmod(var62, var64, r) + let var66 := 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a + let var67 := mulmod(var66, a_1, r) + let var68 := addmod(var65, var67, r) + let var69 := 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db + let var70 := mulmod(var69, var10, r) + let var71 := addmod(var68, var70, r) + let var72 := addmod(mulmod(var60, q_trash_tau, r), var71, r) + let f_3 := mload(0x9ac0) + let var73 := mulmod(a_4, var0, r) + let var74 := addmod(f_3, var73, r) + let var75 := 0x222e83e70453dfee19b402e9fa8dfe2c4987b034d0be3ceb478b3022e97934c1 + let var76 := mulmod(var75, a_0, r) + let var77 := addmod(var74, var76, r) + let var78 := 0x26c2cc87f95726b28f33ca03409a460ec987cfe12adae32769e3565865d07191 + let var79 := mulmod(var78, a_1, r) + let var80 := addmod(var77, var79, r) + let var81 := 0x4382d0938a760120dd6cef8f3b90a0c38abae475e3d21e39365472b76d780272 + let var82 := mulmod(var81, var10, r) + let var83 := addmod(var80, var82, r) + let var84 := mulmod(var69, var14, r) + let var85 := addmod(var83, var84, r) + let var86 := addmod(mulmod(var72, q_trash_tau, r), var85, r) + let f_4 := mload(0x99c0) + let var87 := mulmod(a_5, var0, r) + let var88 := addmod(f_4, var87, r) + let var89 := 0x726df1506749848155630b86ae25a82b281ecd050fe3a52d85a181fa87202e4b + let var90 := mulmod(var89, a_0, r) + let var91 := addmod(var88, var90, r) + let var92 := 0x24822e1af9aa2887c912c87eb0f20bd332330e7e55cd784de67cb407a9f05520 + let var93 := mulmod(var92, a_1, r) + let var94 := addmod(var91, var93, r) + let var95 := 0x4e5280109d8f96b8bfb543a6b1af25fb56a9db616af85a90eedc558e3eb1ea29 + let var96 := mulmod(var95, var10, r) + let var97 := addmod(var94, var96, r) + let var98 := mulmod(var81, var14, r) + let var99 := addmod(var97, var98, r) + let var100 := mulmod(var69, var18, r) + let var101 := addmod(var99, var100, r) + let var102 := addmod(mulmod(var86, q_trash_tau, r), var101, r) + let f_5 := mload(0x99e0) + let var103 := mulmod(a_6, var0, r) + let var104 := addmod(f_5, var103, r) + let var105 := 0x2f5908b169c6cf1bd26dcf0f9e5105481f5164f3ece0582bf3098312167751a7 + let var106 := mulmod(var105, a_0, r) + let var107 := addmod(var104, var106, r) + let var108 := 0x23a6684b942d726a22e4d5b8d8ff83aeaa773f62600184efe5d033d7c7c6e827 + let var109 := mulmod(var108, a_1, r) + let var110 := addmod(var107, var109, r) + let var111 := 0x1981b4b33d6a9dab957b351d981d3323e65da39493af5bc01f7e8ffe17f98d4e + let var112 := mulmod(var111, var10, r) + let var113 := addmod(var110, var112, r) + let var114 := mulmod(var95, var14, r) + let var115 := addmod(var113, var114, r) + let var116 := mulmod(var81, var18, r) + let var117 := addmod(var115, var116, r) + let var118 := mulmod(var69, var22, r) + let var119 := addmod(var117, var118, r) + let var120 := addmod(mulmod(var102, q_trash_tau, r), var119, r) + let f_6 := mload(0x9a00) + let var121 := mulmod(a_7, var0, r) + let var122 := addmod(f_6, var121, r) + let var123 := 0x6d05a41959f539a7fc9ec0972ea1e3dbb6fc67dd51daf3414f7fbbb091c7274a + let var124 := mulmod(var123, a_0, r) + let var125 := addmod(var122, var124, r) + let var126 := 0x27e7119226c42a6d19c1541904b99ae40685511ed2e078964b74594d38340849 + let var127 := mulmod(var126, a_1, r) + let var128 := addmod(var125, var127, r) + let var129 := 0xd94c46a8456352aa44d7a885ab59e3a36664e6fb25e826f8a4cd79822f0533 + let var130 := mulmod(var129, var10, r) + let var131 := addmod(var128, var130, r) + let var132 := mulmod(var111, var14, r) + let var133 := addmod(var131, var132, r) + let var134 := mulmod(var95, var18, r) + let var135 := addmod(var133, var134, r) + let var136 := mulmod(var81, var22, r) + let var137 := addmod(var135, var136, r) + let var138 := mulmod(var69, var26, r) + let var139 := addmod(var137, var138, r) + let var140 := addmod(mulmod(var120, q_trash_tau, r), var139, r) + let f_7 := mload(0x9a20) + let a_2_next_1 := mload(0x9580) + let var141 := mulmod(a_2_next_1, var0, r) + let var142 := addmod(f_7, var141, r) + let var143 := 0x70d8f2a733a64d650faccc9b1c2a766a9544bb3ff1a11ee73cb43947ef386633 + let var144 := mulmod(var143, a_0, r) + let var145 := addmod(var142, var144, r) + let var146 := 0x40fa389feb2522bb934881ac9ed749aee2296502af592418c6b5675c0f560261 + let var147 := mulmod(var146, a_1, r) + let var148 := addmod(var145, var147, r) + let var149 := 0x1f61345b652161410c5e29f51e301ae56342af824bc110649393d2b911c50d3e + let var150 := mulmod(var149, var10, r) + let var151 := addmod(var148, var150, r) + let var152 := mulmod(var129, var14, r) + let var153 := addmod(var151, var152, r) + let var154 := mulmod(var111, var18, r) + let var155 := addmod(var153, var154, r) + let var156 := mulmod(var95, var22, r) + let var157 := addmod(var155, var156, r) + let var158 := mulmod(var81, var26, r) + let var159 := addmod(var157, var158, r) + let var160 := mulmod(var69, var30, r) + let var161 := addmod(var159, var160, r) + let var162 := addmod(mulmod(var140, q_trash_tau, r), var161, r) + let f_19 := mload(0x9b80) + let q_trash_one_minus_selector := addmod(1, sub(r, f_19), r) + let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0xa120), r) + let q_trash_eval := addmod(var162, sub(r, q_trash_scaled), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_trash_eval, r)) + } + } + // Finish selector buckets by applying the codegen-known tail + // from each selector's last identity to the end of the global + // y-batch. + // + // After this step, every selector bucket is aligned with the + // final global y position and can be multiplied by its fixed + // selector commitment in the linearized MSM. + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0600)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x05e0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0580)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x04c0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x80) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0460)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xa0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0400)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xc0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x03a0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xe0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0340)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0100) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x02e0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0120) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0280)), r)) + } + + // Fully evaluated identities are the constant-polynomial side + // of the linearization query. Rust subtracts that grouped + // scalar into expected_eval, so Solidity stores -nu_y(x). + let linearization_expected_eval := addmod(0, sub(r, mload(0xb280)), r) + mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) + pop(y) + } + + // Return the compact output frame. Halo2Verifier checks the magic, + // stores word 1 as the linearization expected eval, then expands + // selector buckets into the fused final PCS MSM. + mstore(QUOTIENT_OUTPUT_MPTR, QUOTIENT_MAGIC) + mstore(add(QUOTIENT_OUTPUT_MPTR, 0x20), mload(QUOTIENT_EVAL_MPTR)) + // Copy selector buckets from the generated absolute memory region + // into the compact external-call return frame. + for { let q_i := 0 } lt(q_i, 10) { q_i := add(q_i, 1) } { + mstore(add(QUOTIENT_OUTPUT_MPTR, add(0x40, shl(5, q_i))), mload(add(SELECTOR_ACC_MPTR, shl(5, q_i)))) + } + return(QUOTIENT_OUTPUT_MPTR, QUOTIENT_OUTPUT_LEN) + } + } +} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol new file mode 100644 index 000000000..6f66ad7c7 --- /dev/null +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol @@ -0,0 +1,2282 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.24; + +/// @title Halo2 BLS12-381 KZG verifier. +/// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 +/// proofs rendered by this repository's Rust generator. +/// @dev This contract ports the verifier flow from +/// `midfall/proofs/src/plonk/verifier.rs`, the Keccak transcript comments from +/// `midfall/proofs/src/transcript/implementors.rs`, and the KZG multi-open +/// comments from `midfall/proofs/src/poly/kzg/mod.rs`. +/// @dev It is not a generic verifier. The proof layout, VK payload, quotient +/// identity program, memory layout, and optional quotient evaluator are all +/// generated for one `VerifyingKey>`. +/// +/// Halo2 KZG verifier for the BLS12-381 curve, midnight-proofs flavour. +/// +/// Differences vs the original BN254 / halo2 v0.4 template: +// +/// - BLS12-381 base field Fp is 381 bits and does not fit in a uint256. +/// Each Fp coord is encoded EIP-2537 padded (16 zero bytes + 48 bytes). +/// A G1 point is 128 bytes (4 words); a G2 point is 256 bytes (8). +/// - Calldata carries G1 commitments in uncompressed EIP-2537 padded +/// form (4 words = 128 bytes per point: x_hi, x_lo, y_hi, y_lo). The +/// proof bytes produced by midnight-proofs prover are repacked off +/// chain (compressed -> uncompressed) before being passed to +/// `verifyProof`. The verifier hashes the uncompressed 128-byte form into +/// the transcript verbatim, matching `Hashable for G1Projective::to_input`; +/// see `common_uncompressed_g1`. +/// - Transcript `common` absorbs raw inputs in order. `squeeze` computes one +/// Keccak digest, resets the transcript buffer to that digest, then samples +/// by interpreting the digest as a big-endian integer modulo r. +/// - Scalar inversion uses modexp(scalar, r-2, r). +/// - Constructors run deployment-time smoke tests for MCOPY and the EIP-2537 +/// precompiles using identity inputs. Compile with Solidity >=0.8.24 and +/// deploy only on chains/forks that support MCOPY and EIP-2537. +contract Halo2Verifier { + + /// @notice Verifying-key contract address authorized for this verifier. + /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. + address public immutable AUTHORIZED_VK; + // Expected VK runtime metadata. The deployed VK runtime is + // INVALID || payload, hence EXPECTED_VK_LENGTH is one byte longer than + // EXPECTED_VK_PAYLOAD_LENGTH. + uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 17024; + uint256 internal constant EXPECTED_VK_LENGTH = 17025; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x67bac137fa7e479c25b63324812752e4b6e13d9841d5bf83c322170bf91c0f88; + bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); + /// @notice Quotient evaluator contract authorized for split quotient reconstruction. + /// @dev The evaluator returns the linearization expected scalar and selector buckets; its runtime may be pinned by generated constants. + address public immutable AUTHORIZED_QUOTIENT; + // Expected split evaluator runtime metadata. It is checked at deployment + // and again immediately before each external quotient reconstruction. + uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9552; + uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c; + bytes32 internal constant EXPECTED_QUOTIENT_CODEHASH = bytes32(EXPECTED_QUOTIENT_CODEHASH_WORD); + + // Solidity ABI calldata cursors. The generated verifier accepts exactly + // verifyProof(bytes proof, uint256[] instances), then parses the `proof` + // bytes itself in the same order as the Rust verifier transcript. + uint256 internal constant PROOF_LEN_CPTR = 0x44; + uint256 internal constant PROOF_CPTR = 0x64; + uint256 internal constant NUM_INSTANCE_CPTR = 0x1ec4; + uint256 internal constant INSTANCE_CPTR = 0x1ee4; + // First general-purpose memory words reserved by the generated verifier. + // RETURN_MPTR is a single word set to 1 on success. + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; + + // ---------------------------------------------------------------------- + // Verifying-key memory map. The VK header lives at VK_MPTR, followed + // by the quotient VM payload and commitments. After the full VK + // runtime comes the challenge slots (challenge_mptr..) and the + // per-stage scratch (theta_mptr..). + // ---------------------------------------------------------------------- + uint256 internal constant VK_MPTR = 0x3680; + uint256 internal constant VK_DIGEST_MPTR = 0x3680; + uint256 internal constant NUM_INSTANCES_MPTR = 0x36a0; + uint256 internal constant K_MPTR = 0x36c0; + uint256 internal constant N_INV_MPTR = 0x36e0; + uint256 internal constant OMEGA_MPTR = 0x3700; + uint256 internal constant OMEGA_INV_MPTR = 0x3720; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x3740; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x3760; + uint256 internal constant ACC_OFFSET_MPTR = 0x3780; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x37a0; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x37c0; + uint256 internal constant G1_BASE_MPTR = 0x37e0; + uint256 internal constant G2_BASE_MPTR = 0x3860; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x3960; + + uint256 internal constant CHALLENGE_MPTR = 0x7900; + + // Challenge layout. Squeeze order in midnight-proofs: + // user_phase challenges (variable count) + // theta -> beta, gamma -> trash_challenge -> y -> x -> + // x1, x2 -> x3 -> x4 + uint256 internal constant THETA_MPTR = 0x7900; + uint256 internal constant BETA_MPTR = 0x7920; + uint256 internal constant GAMMA_MPTR = 0x7940; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x7960; + uint256 internal constant Y_MPTR = 0x7980; + uint256 internal constant X_MPTR = 0x79a0; + uint256 internal constant X1_MPTR = 0x79c0; + uint256 internal constant X2_MPTR = 0x79e0; + uint256 internal constant X3_MPTR = 0x7a00; + uint256 internal constant X4_MPTR = 0x7a20; + + // Batch-open commitments live in 4-word EIP-2537 padded slots. + uint256 internal constant F_COM_MPTR = 0x7a40; + uint256 internal constant PI_MPTR = 0x7ac0; + + // Accumulator (KZG IVC). + uint256 internal constant ACC_LHS_MPTR = 0x7b40; + uint256 internal constant ACC_RHS_MPTR = 0x7bc0; + + // Lagrange / linearization scratch. + uint256 internal constant X_N_MPTR = 0x7c40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x7c60; + uint256 internal constant L_LAST_MPTR = 0x7c80; + uint256 internal constant L_BLIND_MPTR = 0x7ca0; + uint256 internal constant L_0_MPTR = 0x7cc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x7ce0; + // Legacy name: this is not h(x). It stores the expected opening + // scalar for the linearized commitment, i.e. the negated y-batched + // identity numerator reconstructed from the alleged evals at x. + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x7d00; + uint256 internal constant QUOTIENT_MPTR = 0x7d20; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x7dc0; + uint256 internal constant V_MPTR = 0x7de0; + uint256 internal constant FINAL_COM_MPTR = 0x7e00; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x7e80; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x7f00; // 4 words + + // Multi-prepare scratch (sized at codegen time). + uint256 internal constant ROT_POINTS_MPTR = 0x7f80; + uint256 internal constant X1_POWERS_MPTR = 0x8300; + // Q_COM materialization is currently fused into the final MSM scratch, + // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero + // reserved capacity until a future emitter starts writing Q_COM_MPTR. + uint256 internal constant Q_COM_MPTR = 0x8b20; + uint256 internal constant Q_EVAL_SET_MPTR = 0x8b20; + + // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals + // block of the proof; we keep it as a memory slot for symmetry. + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; + + // Reserved 4-word slot for the G1 identity (point at infinity) in + // EIP-2537 padded form. EVM memory is zero-initialised, and we + // never write to this region, so the four `mload`s below produce + // 0,0,0,0 which is exactly the identity encoding the EIP-2537 + // ec_add / ec_mul precompiles accept. + uint256 internal constant G1_IDENTITY_MPTR = 0x9320; + + // Decoded polynomial-eval buffer (Optimisation H3). The off-chain + // Solidity proof shim rewrites proof scalars into canonical BE words, + // so `calldataload` gives the field element directly. The transcript- + // side `evaluations` loop range-checks and spills that value here so + // downstream eval references (gate evaluator + PCS q_eval Horner) + // become 3-gas `mload(...)` instead of calldata reads. + uint256 internal constant REVERSED_EVALS_MPTR = 0x9480; + uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + uint256 internal constant TRACE_U256_MPTR = 0xe340; + + // ---------------------------------------------------------------------- + // Per-category bases for EIP-2537 padded G1 commitments. The proof + // calldata carries 128-byte uncompressed/padded G1s after the off-chain + // proof shim repacks midnight-proofs' native compressed stream; this + // region stores the 4-word slots used by PCS / quotient-fold sections. + // + // Cumulative offsets (in words from `comms_mptr_base`): + // ADVICE_COMMS_MPTR_BASE + 0 + // LOOKUP_M_COMMS_MPTR_BASE + 4*total_advices + // PERM_Z_COMMS_MPTR_BASE + 4*total_advices + 4*num_lookups + // LOOKUP_HELPER_COMMS_MPTR_BASE + ... + 4*num_permutation_zs + // LOOKUP_Z_COMMS_MPTR_BASE + ... + 4*lookup_helper_chunks_total + // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups + // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans + // ---------------------------------------------------------------------- + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0xa140; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0xa8c0; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0xa9c0; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0xacc0; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0xadc0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; + + // BLS12-381 scalar-field modulus, used for transcript challenges and all + // Halo2 verifier arithmetic. + uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; + + // BLS12-381 Fp modulus minus one, split like an EIP-2537 coordinate: + // high word = 16 zero bytes || top 16 coordinate bytes, low word = + // bottom 32 coordinate bytes. + uint256 internal constant BLS_P_HI = 0x000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd7; + uint256 internal constant BLS_P_MINUS_ONE_LO = 0x64774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa; + // Packed public-accumulator sentinels for the shifted coordinate codec. + // The `_WITH_ID_FLAG` variant is used only for the first x-coordinate word. + uint256 internal constant BLS_P_MINUS_ONE_PACKED_0 = 0x00000000f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa; + uint256 internal constant BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG = 0x00000000f38512bf6730d2a0f6b0f6241eabfffeb153ffffbafeffffffffaaaa; + uint256 internal constant BLS_P_MINUS_ONE_PACKED_1 = 0x0000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84; + + /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. + /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + function require_eip2537_precompiles() private view { + assembly ("memory-safe") { + // Scratch is reused for every runtime-prerequisite probe. + let scratch := 0x1000 + + // MCOPY must be available because the verifier uses it for + // proof-time point/scratch staging. Execute the opcode here so a + // non-Cancun fork fails during deployment instead of later proofs. + mstore(scratch, 0x1234) + mcopy(add(scratch, 0x20), scratch, 0x20) + if iszero(eq(mload(add(scratch, 0x20)), 0x1234)) { revert(0, 0) } + + // Start the EIP-2537 probes with the identity encoding for G1/G2: + // all-zero padded words. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + + // G1ADD(identity, identity) -> identity, 128-byte return. + // This catches chains where the precompile is missing or returns a + // non-standard success shape. + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { + revert(0, 0) + } + + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + + // Worst-case generated G1MSM with all identity/zero terms -> + // identity, 128-byte return. This exercises the largest MSM input + // length rendered by this verifier instead of only a one-pair + // smoke call. + let msm_scratch := 0xb140 + for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { + mstore(add(msm_scratch, off), 0) + } + // The production verifier uses G1MSM both for commitments and as + // the subgroup validator for absorbed proof points. + if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { + revert(0, 0) + } + + // PAIRING_CHECK([(identity_g1, identity_g2), (identity_g1, identity_g2)]) + // -> true, 32-byte return. This matches the runtime two-pair KZG + // pairing input size and catches absent pairing precompiles, + // short return data, and obviously incompatible semantics. + if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(scratch), 1)) { revert(0, 0) } + } + } + + + /// @notice Create a verifier pinned to a verifying key and quotient evaluator. + /// @dev Checks MCOPY/EIP-2537 availability and verifies both dependency runtimes before storing their addresses. + /// @param authorizedVk Address of the generated `Halo2VerifyingKey` runtime. + /// @param authorizedQuotient Address of the generated `Halo2QuotientEvaluator` runtime. + constructor(address authorizedVk, address authorizedQuotient) { + // Verifier correctness depends on chain support for MCOPY and the + // BLS12-381 precompiles; fail deployment before pinning dependencies. + require_eip2537_precompiles(); + // Pin the generated VK runtime exactly. The verifier later repeats the + // codehash/length check before copying the VK payload for a proof. + require( + authorizedVk.code.length == EXPECTED_VK_LENGTH + && authorizedVk.codehash == EXPECTED_VK_CODEHASH, + "invalid vk" + ); + // The split evaluator contains generated verifier logic, not a generic + // library. Pin it with the same strictness as the verifying key. + require( + authorizedQuotient.code.length == EXPECTED_QUOTIENT_LENGTH + && authorizedQuotient.codehash == EXPECTED_QUOTIENT_CODEHASH, + "invalid quotient" + ); + // Store the already-validated dependency addresses for proof-time + // memory loading and quotient reconstruction. + AUTHORIZED_VK = authorizedVk; + AUTHORIZED_QUOTIENT = authorizedQuotient; + } + + /// @notice Verify a Halo2/Midfall proof for the generated verifying key. + /// @dev This checks only that `proof` verifies for the supplied public + /// `instances` under this pinned VK/protocol. Application contracts must + /// bind the meaning of those instances separately: state roots, program + /// identifiers, expected IVC outputs, chain/domain separation, and any + /// protocol-specific authorization are outside this raw verifier ABI. + /// @dev Production renders are success-or-revert: accepted proofs return + /// `true`, while malformed calldata, invalid proof material, failed + /// precompiles, or mismatched pinned dependency code revert. Trace and gas + /// renders keep the same failure policy. + /// @dev The generated verifier uses absolute Yul memory addresses instead + /// of Solidity's free-memory pointer, but generated scratch starts at + /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// assembly block remains terminal: accepted proofs return from assembly + /// and all rejected inputs revert. Do not inline this body into Solidity + /// code that continues executing after verification without reviewing the + /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. + /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. + /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. + function verifyProof( + bytes calldata proof, + uint256[] calldata instances + ) external view returns (bool) { + // Cheap ABI-shape guard before any generated memory work: + // - proof head must point at the bytes payload; + // - instances head must point at the generated instance array. + // + // The verifier below is a hand-rolled calldata parser. Failing here + // keeps malformed dynamic-argument layouts from being interpreted as a + // valid Midfall proof stream. + assembly ("memory-safe") { + if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { + revert(0, 0) + } + } + // Non-embedded renders pin the VK by address and codehash. The Yul + // loader rechecks the runtime before every proof and copies the + // INVALID-prefixed payload into VK_MPTR. + address vk = AUTHORIZED_VK; + // Split quotient renders delegate the scalar-side identity numerator + // reconstruction to a separately deployed generated evaluator. + address quotientEvaluator = AUTHORIZED_QUOTIENT; + assembly ("memory-safe") { + // This block owns the call-frame memory and remains terminal. + // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Solidity's reserved scratch, free-memory-pointer, and zero-slot + // words. See docs/MEMORY_LAYOUT.md. + // =============================================================== + // Helpers: modexp, transcript, EIP-2537 calls + // =============================================================== + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // calls this only after transcript absorption is complete, so it + // reuses the dead transcript buffer just below VK_MPTR instead of + // a fixed post-VK address that can collide with live PCS scratch + // when the VK payload becomes smaller. + function scalar_inv(x) -> inv { + // Zero has no multiplicative inverse in Fr; callers rely on a + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } + if iszero(x) { revert(0, 0) } + let p := 0x3580 + // EIP-198 modexp frame: + // [base_len, exp_len, mod_len, base, exponent, modulus] + mstore(add(p, 0x00), 0x20) // base len + mstore(add(p, 0x20), 0x20) // exp len + mstore(add(p, 0x40), 0x20) // mod len + mstore(add(p, 0x60), x) + mstore(add(p, 0x80), sub(FR_MODULUS, 2)) + mstore(add(p, 0xa0), FR_MODULUS) + if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + inv := mload(p) + } + + // ---------- Streaming Keccak256 transcript helpers ---------- + // + // The transcript buffer lives at + // memory[TRANSCRIPT_MPTR..buf_len). On verifier entry it starts + // empty. Each common(input) appends raw bytes. squeeze_*(buf_len) + // computes one Keccak digest, reseeds the buffer with that + // 32-byte digest, and samples a Fq element as + // uint256(digest_be) mod r. + + function transcript_init() -> buf_len { + // Empty transcript buffer starts exactly at TRANSCRIPT_MPTR. + buf_len := TRANSCRIPT_MPTR + } + + // Append one 32-byte big-endian field/transcript word at the + // current end of the transcript buffer. + function common_word(buf_len, word) -> ret { + mstore(buf_len, word) + ret := add(buf_len, 32) + } + + // Absorb a BLS12-381 G1 point in EIP-2537 padded + // uncompressed form (4 calldata words = 128 bytes: + // x_hi || x_lo || y_hi || y_lo, each coord = 16 zero + // pad bytes + 48 big-endian field bytes) into the + // transcript buffer at `buf_len`. + // + // Matches the patched `Hashable for + // midnight_curves::G1Projective::to_input` in + // midnight-proofs, which now emits the same 128-byte form + // (`midfall/proofs/src/transcript/implementors.rs`). The + // previous emitter hashed the 48-byte ZCash compressed + // encoding instead and ran a 384-bit `lex(y) > lex(p − y)` + // ladder + identity flag fixup to derive the sign bit on + // the fly; switching to the uncompressed form drops that + // ladder entirely. + // + // Canonicality: reject non-zero bytes in the top 16 bytes + // of each `_hi` calldata word and reject coordinates + // outside Fp. Normalizing those bytes before hashing would + // make multiple calldata encodings share one transcript. + // + // This helper does not run an independent curve/subgroup + // check. Instead, ProtocolPlan::validate rejects generated + // plans where an absorbed proof commitment would not later be + // consumed by an EIP-2537 G1MSM or pairing path, and those + // precompiles perform the curve/subgroup validation. + // + // The point's uncompressed form remains in calldata; the + // call site is responsible for `calldatacopy`-ing it into + // memory afterwards if it needs the on-curve coordinates. + function common_uncompressed_g1(buf_len, cptr) -> ret { + let x_hi_word := calldataload(cptr) + let x_lo := calldataload(add(cptr, 0x20)) + let y_hi_word := calldataload(add(cptr, 0x40)) + let y_lo := calldataload(add(cptr, 0x60)) + if shr(128, x_hi_word) { revert(0, 0) } + if shr(128, y_hi_word) { revert(0, 0) } + + let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) + let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) + if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { + revert(0, 0) + } + if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { + revert(0, 0) + } + + // Memcpy the 4 calldata words (128 bytes) verbatim + // into the keccak buffer. + calldatacopy(buf_len, cptr, 0x80) + ret := add(buf_len, 0x80) + } + + // One Keccak finalization + reseed. Returns the new buffer + // cursor (= TRANSCRIPT_MPTR + 32) and stores the squeezed Fq at + // `mptr`. + function squeeze_to(buf_len, mptr) -> ret { + let h0 := keccak256(TRANSCRIPT_MPTR, sub(buf_len, TRANSCRIPT_MPTR)) + // Reseed: write the 32-byte digest at start of buffer. + mstore(TRANSCRIPT_MPTR, h0) + let r := FR_MODULUS + // Sample Fq as uint256(keccak_digest_be) mod r. + mstore(mptr, mod(h0, r)) + ret := add(TRANSCRIPT_MPTR, 32) + } + + // ---------- EC primitives (EIP-2537 wrappers) ---------- + // + // These mirror the BN254 helpers but operate on 4-word G1 + // points. They use planned memory windows above Solidity's + // reserved prefix; the streaming transcript buffer is no longer + // needed once all challenges are squeezed. + + // Invert a contiguous run of Fr words in-place using Montgomery's + // batch inversion trick: + // 1. write prefix products to scratch; + // 2. invert the total product once with modexp; + // 3. walk backward to recover each individual inverse. + // + // The function returns a boolean instead of reverting so callers + // can combine it with other `success` plumbing until a section + // boundary decides whether to fail closed. + function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret { + ret := success + if iszero(ret) { leave } + // Memory ranges must be forward and word-aligned by + // construction; a reversed range is always a codegen error. + if lt(mptr_end, mptr_start) { + ret := 0 + leave + } + + let count_bytes := sub(mptr_end, mptr_start) + // Empty batch is valid and leaves memory untouched. + if iszero(count_bytes) { leave } + + // Fast path for a single denominator: avoid prefix scratch and + // just run one modexp inverse in place. + if eq(count_bytes, 0x20) { + let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } + if iszero(x) { + ret := 0 + leave + } + + let single_scratch := scratch_mptr + mstore(add(single_scratch, 0x00), 0x20) + mstore(add(single_scratch, 0x20), 0x20) + mstore(add(single_scratch, 0x40), 0x20) + mstore(add(single_scratch, 0x60), x) + mstore(add(single_scratch, 0x80), sub(r, 2)) + mstore(add(single_scratch, 0xa0), r) + ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + if ret { mstore(mptr_start, mload(single_scratch)) } + leave + } + + // Forward pass: scratch stores prefix products up to, but not + // including, the final element. `gp` becomes the total product. + let gp_mptr := scratch_mptr + let gp := mload(mptr_start) + let mptr := add(mptr_start, 0x20) + for {} lt(mptr, sub(mptr_end, 0x20)) {} { + gp := mulmod(gp, mload(mptr), r) + mstore(gp_mptr, gp) + mptr := add(mptr, 0x20) + gp_mptr := add(gp_mptr, 0x20) + } + gp := mulmod(gp, mload(mptr), r) + // A zero total product means at least one denominator was + // zero, so no batch inverse exists. + if iszero(gp) { + ret := 0 + leave + } + + // Invert the total product once. + mstore(add(gp_mptr, 0x00), 0x20) + mstore(add(gp_mptr, 0x20), 0x20) + mstore(add(gp_mptr, 0x40), 0x20) + mstore(add(gp_mptr, 0x60), gp) + mstore(add(gp_mptr, 0x80), sub(r, 2)) + mstore(add(gp_mptr, 0xa0), r) + ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } + let all_inv := mload(gp_mptr) + + // Backward pass: derive each inverse from the inverted total + // product and the saved prefix products. + let first_mptr := mptr_start + let second_mptr := add(first_mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + for {} lt(second_mptr, mptr) {} { + let inv := mulmod(all_inv, mload(gp_mptr), r) + all_inv := mulmod(all_inv, mload(mptr), r) + mstore(mptr, inv) + mptr := sub(mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + } + let inv_first := mulmod(all_inv, mload(second_mptr), r) + let inv_second := mulmod(all_inv, mload(first_mptr), r) + mstore(first_mptr, inv_first) + mstore(second_mptr, inv_second) + } + + // Final EIP-2537 pairing wrapper. `lhs_mptr` and `rhs_mptr` are + // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. + function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { + ret := success + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } + // Lay out two (G1, G2) pairs at scratch..scratch+0x300: + // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] + // Cancun MCOPY (3 + 3·words gas) replaces what used to + // be a 4-step mstore chain for each G1 (~60 gas) and an + // 8-iter mstore loop for each G2 (~240 gas). Net saving + // here is ~500 gas per ec_pairing call. + let scratch := 0x0320 + mcopy(scratch, lhs_mptr, 0x80) + mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) + mcopy(add(scratch, 0x180), rhs_mptr, 0x80) + mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) + ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) + if iszero(ret) { revert(0, 0) } + ret := 1 + } + + // ---------- IVC accumulator public-input decoding ---------- + // + // `AssignedForeignPoint` exposes each base-field coordinate + // through `AssignedField::as_public_input`: seven radix-2^56 limbs of + // (coord - 1) are packed four-at-a-time into native field elements. + // The x coordinate's first packed word carries the identity flag by + // adding one raw radix base. Rebuild EIP-2537 padded + // (x_hi, x_lo, y_hi, y_lo) words from that encoding. + // + // Public-input layout for one coordinate: + // word 0: limb_0 | limb_1 << bits | ... up to limbs_per_word + // word 1: next limbs, if any + // + // The limbs are little-endian in the represented integer even + // though calldata words are loaded as big 256-bit values. The loop + // below extracts each limb by shifting inside the packed word and + // reconstructs the full coordinate into the two-word EIP-2537 + // representation expected by the BLS12-381 precompiles. + function load_acc_coord_shifted(src, bits, n, base, limbs_per_word, first_adjust) -> hi, lo { + // Mask for one radix limb, e.g. 2^56 - 1 for the current + // BLS12-381 self-emulation parameters. + let mask := sub(base, 1) + for { let i := 0 } lt(i, n) { i := add(i, 1) } { + // Limb words are little-endian packed inside each Fr + // public input. `first_adjust` removes the identity flag + // base from the first x word when present. + let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { + packed := sub(packed, first_adjust) + } + // Select limb i from its packed field word. The mod/div + // pair maps a limb index to an intra-word limb slot and + // the calldata word containing it. + let limb := and(shr(mul(mod(i, limbs_per_word), bits), packed), mask) + + let shift := mul(i, bits) + // Split the reconstructed 384-bit coordinate into the + // EIP-2537 high/low words expected by the precompiles. + if lt(shift, 256) { + lo := add(lo, shl(shift, limb)) + if gt(add(shift, bits), 256) { + // A limb can straddle the 256-bit low/high split. + // Move the overflow bits into hi. + hi := add(hi, shr(sub(256, shift), limb)) + } + } + if iszero(lt(shift, 256)) { + // Once shift >= 256 the whole limb belongs to hi. + hi := add(hi, shl(sub(shift, 256), limb)) + } + } + } + + // The shifted coordinate codec represents zero as p-1 before the + // final +1 below, so keep this sentinel explicit. + function is_bls_p_minus_one(hi, lo) -> yes { + yes := and(eq(hi, BLS_P_HI), eq(lo, BLS_P_MINUS_ONE_LO)) + } + + // Canonical encoded accumulator identity: + // x = p-1 plus the identity flag in the first packed word, + // y = p-1 with no identity flag. + // It decodes to the EIP-2537 point-at-infinity slot (all zeros). + // + // This fast path is deliberately stricter than "decodes to zero": + // the point at infinity has exactly one accepted public-input + // encoding. Non-canonical zero-like encodings are rejected later. + function is_acc_encoded_identity(src) -> yes { + yes := and( + and( + eq(calldataload(src), BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG), + eq(calldataload(add(src, 0x20)), BLS_P_MINUS_ONE_PACKED_1) + ), + and( + eq(calldataload(add(src, 0x40)), BLS_P_MINUS_ONE_PACKED_0), + eq(calldataload(add(src, 0x60)), BLS_P_MINUS_ONE_PACKED_1) + ) + ) + } + + // Reject unused high bits in the packed public-input words. This + // makes each accumulator point encoding canonical before it reaches + // the precompile-based curve/subgroup validation. + function check_acc_coord_packing(src, bits, n, limbs_per_word) -> ok { + ok := 1 + // Number of packed native-field public-input words occupied by + // one coordinate. + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + for { let word_idx := 0 } lt(word_idx, coord_words) { word_idx := add(word_idx, 1) } { + // The final word may contain fewer than limbs_per_word + // limbs. Any unused high bits must be zero, otherwise the + // same coordinate would have multiple calldata encodings. + let remaining := sub(n, mul(word_idx, limbs_per_word)) + let limbs_in_word := limbs_per_word + if lt(remaining, limbs_per_word) { + limbs_in_word := remaining + } + let used_bits := mul(limbs_in_word, bits) + if lt(used_bits, 256) { + // shl(used_bits, 1) == 2^used_bits. The packed word + // must be strictly less than that bound. + ok := and(ok, lt(calldataload(add(src, mul(word_idx, 0x20))), shl(used_bits, 1))) + } + } + } + + // Decode one shifted coordinate. `allow_id` is true only for x, + // because the identity flag lives in x's first packed word. + function load_acc_coord(src, allow_id, bits, n, base, limbs_per_word) -> ok, hi, lo, is_id { + ok := check_acc_coord_packing(src, bits, n, limbs_per_word) + if and(allow_id, iszero(lt(calldataload(src), base))) { + // Probe the x identity flag by removing one radix base and + // checking whether the adjusted coordinate is p-1. + // + // `calldataload(src) >= base` is a cheap prefilter: only x + // can carry this flag, and adding one radix base must make + // the first packed word at least base. + let adj_hi, adj_lo := load_acc_coord_shifted(src, bits, n, base, limbs_per_word, base) + is_id := is_bls_p_minus_one(adj_hi, adj_lo) + } + + // Decode again with the identity adjustment applied only when + // the canonical identity flag was actually detected. + hi, lo := load_acc_coord_shifted(src, bits, n, base, limbs_per_word, mul(is_id, base)) + ok := and( + ok, + // Coordinate must be in the BLS12-381 base field, i.e. + // <= p - 1 in split hi/lo form. + or(lt(hi, BLS_P_HI), and(eq(hi, BLS_P_HI), iszero(gt(lo, BLS_P_MINUS_ONE_LO)))) + ) + + let was_p_minus_one := is_bls_p_minus_one(hi, lo) + if was_p_minus_one { + // Shifted encoding maps p-1 back to zero. + hi := 0 + lo := 0 + } + if iszero(was_p_minus_one) { + // All other coordinates are encoded as coord - 1, so add + // one back with carry into the high word. + let next_lo := add(lo, 1) + hi := add(hi, lt(next_lo, lo)) + lo := next_lo + } + + // EIP-2537 pads each 48-byte Fp coordinate to 64 bytes, + // so the high word must fit in its low 128 bits. + // This also catches impossible reconstructions above 384 bits. + ok := and(ok, lt(hi, shl(128, 1))) + } + + // Decode a public accumulator point into an EIP-2537 4-word G1 + // slot. Non-identity points are curve/subgroup checked later by + // routing them through G1MSM. + function load_acc_point(dst, src, bits, n, base) -> ok, is_id { + // Prefer the canonical all-coordinate identity encoding before + // attempting coordinate-level shifted decoding. This accepts + // the point at infinity only in the exact form generated by the + // circuit's public-input codec. + is_id := is_acc_encoded_identity(src) + if is_id { + ok := 1 + // EIP-2537 encodes G1 identity as four zero words: + // x_hi = x_lo = y_hi = y_lo = 0. + mstore(dst, 0) + mstore(add(dst, 0x20), 0) + mstore(add(dst, 0x40), 0) + mstore(add(dst, 0x60), 0) + } + if iszero(is_id) { + // x occupies coord_words packed public-input words; y + // starts immediately after x. + let limbs_per_word := 4 + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + // Only x may carry the identity flag. y must decode as a + // normal shifted coordinate. + let x_ok, x_hi, x_lo, x_is_id := load_acc_coord(src, 1, bits, n, base, limbs_per_word) + let y_ok, y_hi, y_lo, y_id := load_acc_coord( + add(src, mul(coord_words, 0x20)), + 0, + bits, + n, + base, + limbs_per_word + ) + // y_id is always zero because allow_id was false, but the + // tuple shape is shared with x decoding. + pop(y_id) + ok := and(x_ok, y_ok) + is_id := x_is_id + + if is_id { + // If x carried the identity flag, both decoded + // coordinates must be zero after shifting. Any other y + // value would be a malformed infinity encoding. + ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) + mstore(dst, 0) + mstore(add(dst, 0x20), 0) + mstore(add(dst, 0x40), 0) + mstore(add(dst, 0x60), 0) + } + if iszero(is_id) { + // The coordinate codec maps encoded p-1 to decoded + // zero. EIP-2537 reserves affine (0,0) for the point + // at infinity, so a decoded infinity is only valid + // when the canonical accumulator identity encoding + // was used above. + let decoded_zero := iszero(or(or(x_hi, x_lo), or(y_hi, y_lo))) + ok := and(ok, iszero(decoded_zero)) + // Store the affine point in the exact precompile input + // layout: x_hi, x_lo, y_hi, y_lo. + mstore(dst, x_hi) + mstore(add(dst, 0x20), x_lo) + mstore(add(dst, 0x40), y_hi) + mstore(add(dst, 0x60), y_lo) + } + } + } + // Validate and prepare the public accumulator equation before the + // main transcript starts. This fails malformed public inputs early + // and writes ACC_LHS_MPTR / ACC_RHS_MPTR for final pairing batching. + // + // The accumulator public input represents an equality of two G1 + // commitments used by the recursive KZG accumulator. This helper: + // 1. decodes carried public G1 points from shifted limbs; + // 2. forces every decoded point through EIP-2537 G1MSM so the + // precompile validates curve/subgroup membership; + // 3. folds the RHS carried point and fixed-base scalar tail into + // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for + // randomized batching in FinalPairing.yul. + function validate_public_accumulator(success, r) -> out { + out := success + let bits := 56 + let n := 7 + // The BLS12-381 self-emulation currently exposes Fp + // coordinates as 7 radix-2^56 limbs. + let limb_base := shl(bits, 1) + let limbs_per_word := 4 + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + // acc_offset is generated from the VK/protocol shape and + // points into the ABI `instances` array. + let acc_instance_ptr := add(INSTANCE_CPTR, 0x80) + + // LHS layout: point limbs (x,y), then either an explicit + // scalar word or an implicit unit scalar for already-collapsed + // point-pair public inputs. + // The scalar pointer is computed unconditionally; the rendered + // branch below decides whether to read it or use scalar 1. + let lhs_scalar_ptr := add(acc_instance_ptr, mul(mul(2, coord_words), 0x20)) + let lhs_ok, lhs_is_id := load_acc_point(ACC_LHS_MPTR, acc_instance_ptr, bits, n, limb_base) + out := and(out, lhs_ok) + // Shared scratch for one-pair LHS validation and the later + // variable-length RHS MSM. + let acc_scratch := 0xb140 + { + // Carried-scalar layout: the circuit exposes the scalar + // that multiplies the carried LHS point. + let lhs_scalar := calldataload(lhs_scalar_ptr) + // Canonicality is enforced here rather than relying on the + // later instance-absorption loop: G1MSM reduces scalars + // mod r implicitly, so s and s+r would be indistinguishable + // inside this helper. + out := and(out, lt(lhs_scalar, r)) + // Identity status is useful for decoding checks above, but + // validation still goes through G1MSM for all points. + pop(lhs_is_id) + // Always route the decoded carried point through G1MSM, + // even for identity points and zero/one scalars. The + // precompile is the on-curve/subgroup validator for this + // public-input point; skipping it would let a malformed + // non-identity point hide behind scalar 0. + mcopy(acc_scratch, ACC_LHS_MPTR, 0x80) + mstore(add(acc_scratch, 0x80), lhs_scalar) + if out { + // Single-pair MSM output overwrites ACC_LHS_MPTR with + // lhs_scalar * decoded_lhs. If lhs_scalar is one, this + // is also a curve/subgroup validation round-trip. + out := staticcall(gas(), 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) + out := and(out, eq(returndatasize(), 0x80)) + } + } + // RHS layout for this generated verifier is fully collapsed: + // point limbs (x,y), scalar. There is no fixed-base scalar + // tail; fixed-base contributions were already folded into + // ACC_RHS by the circuit/native accumulator construction. + let rhs_instance_ptr := add(lhs_scalar_ptr, 0x20) + // RHS scalar, when present, immediately follows the RHS point + // limbs. The fixed-base scalar tail starts after it. + let rhs_scalar_ptr := add(rhs_instance_ptr, mul(mul(2, coord_words), 0x20)) + let rhs_ok, rhs_is_id := load_acc_point(ACC_RHS_MPTR, rhs_instance_ptr, bits, n, limb_base) + out := and(out, rhs_ok) + // acc_pair_ptr appends (G1, scalar) pairs into acc_scratch for + // one final RHS MSM. + let acc_pair_ptr := acc_scratch + { + // Explicit carried RHS scalar. + let rhs_scalar := calldataload(rhs_scalar_ptr) + out := and(out, lt(rhs_scalar, r)) + pop(rhs_is_id) + // Keep the carried RHS point in the MSM input even when + // it is encoded as identity or has scalar 0/1, so EIP-2537 + // validates every decoded public accumulator point before + // it can affect, or be erased from, the pairing batch. + mcopy(acc_pair_ptr, ACC_RHS_MPTR, 0x80) + mstore(add(acc_pair_ptr, 0x80), rhs_scalar) + // Move to the next (G1, scalar) pair slot. + acc_pair_ptr := add(acc_pair_ptr, 0xa0) + } + // Total byte length of the appended RHS MSM input pairs. This + // is at least one pair because the carried RHS point is always + // appended; keep the guard for synthetic render configurations. + let acc_msm_len := sub(acc_pair_ptr, acc_scratch) + if acc_msm_len { + // Fold the carried RHS point and any generated fixed-base + // tail into ACC_RHS_MPTR. The later final pairing block + // randomizes this equation together with the KZG pairing. + if out { + // Output overwrites ACC_RHS_MPTR with: + // rhs_scalar * carried_rhs + // + sum_i fixed_scalar_i * fixed_base_i + // + // The precompile also validates every nonzero fixed + // base embedded by codegen and the carried RHS point. + out := staticcall( + gas(), + 0x0c, + acc_scratch, + acc_msm_len, + ACC_RHS_MPTR, + 0x80 + ) + out := and(out, eq(returndatasize(), 0x80)) + } + } + // The caller checks `out` and reverts before transcript work if + // any decode, canonicality, or precompile validation failed. + } + + + + let r := FR_MODULUS + let success := true + + + + // =============================================================== + // VK loading: either bake in the embedded VK bytes or fetch + // them from the linked AUTHORIZED_VK contract. + // + // This is the first verifier phase after helper definitions. Its + // job is to make the generated VK payload available at VK_MPTR in + // one canonical memory layout, regardless of whether this render + // embeds the VK directly or links a separate Halo2VerifyingKey + // contract. + // + // Later template partials treat VK_MPTR as already populated with: + // - header words: vk_digest, domain data, accumulator metadata; + // - BLS12-381 base points used by the final pairing; + // - compact quotient VM constants/program bytes, when enabled; + // - fixed and permutation commitments in 4-word G1 slots. + // =============================================================== + { + // Re-check the pinned VK dependency on every proof. The + // constructor check catches normal deployment mistakes, while + // this fresh check hardens forks or same-transaction edge + // cases where code at the authorized address could differ + // from the runtime originally pinned by this verifier. + // + // EXPECTED_VK_LENGTH includes the leading INVALID byte in the + // Halo2VerifyingKey runtime. EXPECTED_VK_CODEHASH_WORD is the + // full runtime hash, not only the payload hash. + if iszero(and( + eq(extcodesize(vk), EXPECTED_VK_LENGTH), + eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) + )) { revert(0, 0) } + // Runtime byte 0 is INVALID so direct calls cannot execute the + // payload. Copy from byte 1 into VK_MPTR to reconstruct the + // exact payload layout used by the embedded branch. + extcodecopy(vk, VK_MPTR, 0x01, EXPECTED_VK_PAYLOAD_LENGTH) + + // Cross-check loaded VK header words against the verifier + // constants used by later parser, domain, and accumulator + // paths. Codehash pinning protects the external VK address; + // these checks catch generator drift before calldata parsing + // chooses a stale schema. + success := and(success, eq(mload(NUM_INSTANCES_MPTR), 14)) + success := and(success, eq(mload(K_MPTR), 20)) + success := and(success, eq(mload(HAS_ACCUMULATOR_MPTR), 1)) + success := and(success, eq(mload(ACC_OFFSET_MPTR), 4)) + success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 7)) + success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 56)) + if iszero(success) { revert(0, 0) } + // + // The checks below validate the dynamic ABI envelope before the + // transcript parser starts walking raw calldata: + // - proof bytes length equals the generated proof layout; + // - instance array length equals the generated public input + // count; + // - total calldata length has no missing or trailing words. + // + // `success` is folded through `and` for consistency with later + // sections, then immediately enforced at the end of this block. + // A failure here means the verifier is not looking at the proof + // shape it was generated to parse. + success := and(success, eq(0x1e60, calldataload(PROOF_LEN_CPTR))) + success := and(success, eq(14, calldataload(NUM_INSTANCE_CPTR))) + // Calldata must contain exactly the ABI selector, proof bytes, + // instance-array length, and generated number of instance + // words. Any trailing bytes fail closed. + success := and( + success, + eq(calldatasize(), add(INSTANCE_CPTR, 0x01c0)) + ) + // Stop before any transcript absorption if the ABI/proof shape + // is not exactly the generated one. + if iszero(success) { revert(0, 0) } + } + // Fail malformed accumulator public inputs before transcript, + // quotient, PCS, and final pairing work. The late accumulator block + // only batches these already-validated G1 outputs into the final + // pairing equation. + // + // Accumulator validation decodes shifted public-input limbs into + // EIP-2537 G1 slots, checks canonical encodings, and routes points + // through G1MSM for curve/subgroup validation. Doing it here means + // invalid accumulator public inputs cannot influence transcript + // challenge derivation or waste gas in later quotient/PCS work. + // validate_public_accumulator returns a boolean to share the same + // success-plumbing style as other helper calls; this boundary is + // where the verifier converts failure to a revert. + success := validate_public_accumulator(success, r) + if iszero(success) { revert(0, 0) } + + // =============================================================== + // Transcript: VK digest + instances + proof. + // + // This block is the Solidity mirror of the native Midfall verifier + // transcript schedule. It does three jobs at once: + // + // 1. Absorb public data and proof bytes into the streaming + // Keccak transcript in exactly the native order. + // 2. Decode/range-check proof scalars and canonical G1 calldata. + // 3. Copy proof commitments/evaluations into planned memory + // slots consumed by Lagrange, quotient, PCS, and pairing + // blocks later in the verifier. + // + // `buf_len` is a write cursor into the transcript buffer. The + // helper functions append bytes and return the new cursor; squeeze + // helpers hash memory[TRANSCRIPT_MPTR..buf_len), reseed the buffer + // with the digest, and write the sampled Fr challenge to memory. + // =============================================================== + let buf_len := transcript_init() + // VK_DIGEST_MPTR holds the digest as a BE 32-byte word (the + // VK contract stores it via `mstore`, which matches the + // Keccak Fq transcript input). + // + // This digest commits to the verifier key / constraint system + // before any proof material is read. + buf_len := common_word(buf_len, mload(VK_DIGEST_MPTR)) + + // Absorb committed_pi = G1Affine::identity() when the + // `committed-instances` feature is on in midnight-proofs. + // Under the patched `Hashable::to_input` (see + // `midfall/proofs/src/transcript/implementors.rs`), the + // identity hashes as 128 zero bytes (EIP-2537 (0,0) + // convention), NOT the 48-byte ZCash compressed form + // 0xc0||47*0x00 that the previous emitter produced. + // Native verifier absorbs this BEFORE the instance count. + { + // 128 zero bytes: zero out 4 consecutive 32-byte words + // at buf_len. + // This is a raw transcript absorb, not a memory slot kept for + // later elliptic-curve operations. + mstore(buf_len, 0) + mstore(add(buf_len, 0x20), 0) + mstore(add(buf_len, 0x40), 0) + mstore(add(buf_len, 0x60), 0) + buf_len := add(buf_len, 0x80) + } + + { + // Native verifier absorbs a length scalar before instance + // values; Keccak Fq transcript input is canonical BE. + // The ABI length was already checked against this generated + // constant in VkLoading.yul. + buf_len := common_word(buf_len, 14) + + let instance_cptr := INSTANCE_CPTR + for { let instance_cptr_end := add(instance_cptr, 0x01c0) } + lt(instance_cptr, instance_cptr_end) + { instance_cptr := add(instance_cptr, 0x20) } { + let inst_be := calldataload(instance_cptr) + // Public inputs are BLS12-381 scalar-field elements. They + // must be canonical before transcript absorption; accepting + // non-canonical encodings would admit transcript aliases. + success := and(success, lt(inst_be, r)) + // Instances are passed BE in calldata, matching the + // Keccak Fq transcript input. + buf_len := common_word(buf_len, inst_be) + } + if iszero(success) { revert(0, 0) } + } + + // =============================================================== + // Per-user-phase reads + challenge squeezes. + // + // Each proof G1 is already EIP-2537 padded in calldata. The + // verifier validates and absorbs that 128-byte form, then copies + // it into the corresponding per-category MPTR. The PCS / + // quotient-fold blocks below dereference those MPTRs. + // + // All G1 reads follow the same pattern: + // - common_uncompressed_g1 canonicalizes/range-checks the two Fp + // coordinates and appends the exact 128 calldata bytes; + // - calldatacopy stores the same 4-word G1 slot in planned + // memory for later EIP-2537 precompile calls; + // - proof_cptr advances by one G1 byte length. + // =============================================================== + // proof_cptr walks the raw proof bytes inside the ABI `bytes` + // payload. Every successful read advances it exactly once, and the + // final equality check below proves the parser consumed the whole + // generated proof layout. + let proof_cptr := PROOF_CPTR + // advice_walk mirrors proof commitment order into the contiguous + // G1 commitment memory region used by PCS and quotient folding. + let advice_walk := ADVICE_COMMS_MPTR_BASE + // ---- User phase 1 ---- + // Advice commitments for this phase are absorbed before the phase's + // challenge squeezes. The number of commitments and challenges is + // generated from the protocol plan. + for { let end := add(proof_cptr, 0x0780) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + // Store the commitment at its phase-ordered advice slot. + calldatacopy(advice_walk, proof_cptr, 0x80) + advice_walk := add(advice_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- theta ---- + // From this point onward the transcript alternates between + // squeezed challenges and proof commitments exactly as + // midnight-proofs does in `plonk/verifier.rs`. + // theta batches lookup input expressions. + buf_len := squeeze_to(buf_len, THETA_MPTR) + // ---- multiplicities (one G1 per lookup) ---- + // Lookup multiplicity commitments are absorbed after theta and + // copied into their own contiguous G1 region. + let lookup_m_walk := LOOKUP_M_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0100) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_m_walk, proof_cptr, 0x80) + lookup_m_walk := add(lookup_m_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- beta, gamma ---- + // beta and gamma are the permutation/lookup randomizers. They are + // squeezed after lookup multiplicities and before permutation + // product commitments, matching the native verifier schedule. + buf_len := squeeze_to(buf_len, BETA_MPTR) + buf_len := squeeze_to(buf_len, GAMMA_MPTR) + // ---- permutation Z products ---- + // Permutation product commitments are used by the permutation + // identities in the quotient numerator and later by PCS openings. + let perm_z_walk := PERM_Z_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0300) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(perm_z_walk, proof_cptr, 0x80) + perm_z_walk := add(perm_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // ---- lookup helpers + accumulators (per-lookup) ---- + // Each lookup contributes zero or more helper commitments followed + // by its lookup accumulator Z commitment. The generated layout keeps + // helper commitments and accumulator commitments in separate memory + // regions because the quotient/PCS schedules address them + // differently. + let lookup_helper_walk := LOOKUP_HELPER_COMMS_MPTR_BASE + let lookup_z_walk := LOOKUP_Z_COMMS_MPTR_BASE + // lookup 0: 1 helper(s) + 1 acc + // Helper commitments for lookup 0. + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_helper_walk, proof_cptr, 0x80) + lookup_helper_walk := add(lookup_helper_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // Accumulator commitment for lookup 0. This is + // always one G1 when the lookup section is present. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_z_walk, proof_cptr, 0x80) + lookup_z_walk := add(lookup_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + // lookup 1: 1 helper(s) + 1 acc + // Helper commitments for lookup 1. + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_helper_walk, proof_cptr, 0x80) + lookup_helper_walk := add(lookup_helper_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // Accumulator commitment for lookup 1. This is + // always one G1 when the lookup section is present. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_z_walk, proof_cptr, 0x80) + lookup_z_walk := add(lookup_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // ---- trash_challenge ---- + // Midnight squeezes this challenge unconditionally, even when the + // circuit has no trash arguments. + // Keeping this squeeze unconditional preserves transcript + // compatibility across circuits with and without trash columns. + buf_len := squeeze_to(buf_len, TRASH_CHALLENGE_MPTR) + // ---- trashcans ---- + // Trashcan commitments are optional, but when present they are + // absorbed before y so the quotient batching challenge binds them. + let trashcan_walk := TRASHCAN_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(trashcan_walk, proof_cptr, 0x80) + trashcan_walk := add(trashcan_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- y ---- + // y batches all quotient identities. Quotient commitments are read + // only after y is sampled, matching the Rust verifier flow. + buf_len := squeeze_to(buf_len, Y_MPTR) + + // ---- quotient commitment(s) ---- + // Each uncompressed quotient commitment is calldatacopied directly to + // QUOTIENT_LIMB_COMMS_MPTR_BASE; the Horner fold below reads + // them back from memory. common_uncompressed_g1 absorbs the + // 128-byte calldata form into the transcript verbatim. + // + // Multi-limb quotient mode reads several Q_i commitments; single-H + // mode renders this loop with one limb. + let quotient_walk := QUOTIENT_LIMB_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0200) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(quotient_walk, proof_cptr, 0x80) + quotient_walk := add(quotient_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- x ---- + // x is the main evaluation point. Values read after this point are + // alleged polynomial evaluations at x or derived PCS openings. + buf_len := squeeze_to(buf_len, X_MPTR) + + // ---- evaluations ---- + // Optimisation H3: the off-chain Solidity proof shim rewrites + // proof scalars into BE calldata words. Spill each decoded eval + // into REVERSED_EVALS_MPTR in the same iteration we range-check + // it, so downstream references can use cheap mload. + // + // The Rust verifier conceptually reads evaluations in query order. + // The lowering plan arranges REVERSED_EVALS_MPTR in the order used + // by the quotient VM/direct evaluator, hence the generated name. + { + let eval_buf := REVERSED_EVALS_MPTR + for { let end := add(proof_cptr, 0x0cc0) } + lt(proof_cptr, end) + {} { + let eval := calldataload(proof_cptr) + // Proof evaluation scalars must be canonical Fr elements + // before they are absorbed or made available to quotient + // reconstruction. + if iszero(lt(eval, r)) { revert(0, 0) } + // Spill for quotient numerator and PCS codegen. + mstore(eval_buf, eval) + eval_buf := add(eval_buf, 0x20) + // Absorb the exact BE field word used by the native + // Keccak transcript. + buf_len := common_word(buf_len, eval) + proof_cptr := add(proof_cptr, 0x20) + } + } + + // ---- x1, x2 ---- + // x1 and x2 batch the KZG multi-opening reduction. They are + // squeezed after all polynomial evaluations are absorbed. + buf_len := squeeze_to(buf_len, X1_MPTR) + buf_len := squeeze_to(buf_len, X2_MPTR) + + // ---- f_com (1 uncompressed G1) ---- + // f_com is the commitment to the batched polynomial used by the PCS + // multi-open protocol. It is both transcript material and later + // pairing/MSM input. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(F_COM_MPTR, proof_cptr, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // ---- x3 ---- + // x3 is the PCS evaluation point for f_com. + buf_len := squeeze_to(buf_len, X3_MPTR) + // truncated-challenges mirrors midnight-proofs + // proofs/src/poly/kzg/mod.rs: + // - x3 is the f_com evaluation point and is truncated + // immediately after squeeze. + // - x1 and x4 remain full squeezed Fr words, but later PCS + // batching stores truncate(x1^i) and truncate(x4^i) while + // keeping the internal power accumulators full precision. + // This direct x3 mask is therefore one part of the PCS truncation + // rule, not the only truncated value used by the verifier. + mstore(X3_MPTR, and(mload(X3_MPTR), 0xffffffffffffffffffffffffffffffff)) + + // ---- q_evals (one Fq per point set) ---- + // q_evals are not spilled into REVERSED_EVALS_MPTR because the PCS + // emitter reads them as a contiguous calldata range from the saved + // Q_EVAL_CPTR_MPTR cursor. + // + // Each q_eval is the claimed evaluation for one prepared point set + // in the KZG multi-open reduction. They are still transcript + // material and must be range-checked as Fr scalars. + mstore(Q_EVAL_CPTR_MPTR, proof_cptr) + for { let end := add(proof_cptr, 0xa0) } + lt(proof_cptr, end) + {} { + let eval := calldataload(proof_cptr) + // Canonical Fr check before transcript absorption. + if iszero(lt(eval, r)) { revert(0, 0) } + buf_len := common_word(buf_len, eval) + proof_cptr := add(proof_cptr, 0x20) + } + + // ---- x4 ---- + // x4 is the final PCS batching challenge, sampled after q_evals + // and before the opening proof point pi. + buf_len := squeeze_to(buf_len, X4_MPTR) + + // ---- pi (1 uncompressed G1) ---- + // pi is the KZG opening proof commitment. It is the last proof + // object absorbed into the transcript and later becomes one side of + // the final pairing check. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(PI_MPTR, proof_cptr, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // The hand-rolled proof parser must consume exactly the ABI + // `proof` bytes before the `instances` length word. This is + // redundant with the generated proof length today, but makes + // future proof-layout drift fail closed. + // + // NUM_INSTANCE_CPTR is the calldata word immediately after the + // dynamic proof bytes payload. If proof_cptr lands anywhere else, + // some section was under-read or over-read. + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + + // `success` carries deferred canonicality failures from public + // instance reads. G1/proof scalar helpers revert immediately. + if iszero(success) { revert(0, 0) } + + // =============================================================== + // Lagrange & instance-evaluation block (pure Fr arithmetic). + // =============================================================== + { + let k := 20 + let x := mload(X_MPTR) + // Compute x^n by repeated squaring, with n = 2^k. + let x_n := x + for { let idx := 0 } lt(idx, k) { idx := add(idx, 1) } { + x_n := mulmod(x_n, x_n, r) + } + + let omega := mload(OMEGA_MPTR) + + // First pass writes denominators (x - omega_i) for every + // Lagrange value needed below, then appends x^n - 1. The + // batch inversion pass turns all of them into inverses in one + // modexp call. + let mptr := X_N_MPTR + let mptr_end := add(mptr, 0x0300) + for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } { + mstore(mptr, addmod(x, sub(r, pow_of_omega), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) + success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + + // Convert inverted denominators into Lagrange evaluations: + // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). + mptr := X_N_MPTR + let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) + for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } { + mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + + // l_blind is the sum of the negative-rotation Lagrange terms + // used by the midnight-proofs blinding identity. + let l_blind := mload(add(X_N_MPTR, 0x20)) + let l_i_cptr := add(X_N_MPTR, 0x40) + for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + lt(l_i_cptr, l_i_cptr_end) + { l_i_cptr := add(l_i_cptr, 0x20) } { + l_blind := addmod(l_blind, mload(l_i_cptr), r) + } + + // Public instance polynomial evaluation at x. Instance words + // have already been range-checked and absorbed in transcript + // order; this loop only forms the linear combination. + let instance_eval := 0 + for { + let instance_cptr := INSTANCE_CPTR + let instance_cptr_end := add(instance_cptr, 0x01c0) + } + lt(instance_cptr, instance_cptr_end) + { instance_cptr := add(instance_cptr, 0x20) + l_i_cptr := add(l_i_cptr, 0x20) } { + instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r) + } + + // Persist the derived values into named memory slots consumed + // by quotient reconstruction and PCS preparation. + let x_n_minus_1_inv := mload(mptr_end) + let l_last := mload(X_N_MPTR) + let l_0 := mload(add(X_N_MPTR, 0x0140)) + + mstore(X_N_MPTR, x_n) + mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) + mstore(L_LAST_MPTR, l_last) + mstore(L_BLIND_MPTR, l_blind) + mstore(L_0_MPTR, l_0) + mstore(INSTANCE_EVAL_MPTR, instance_eval) + } + + if iszero(success) { revert(0, 0) } + + + // =============================================================== + // External batched identity numerator reconstruction. + // + // The quotient evaluator receives the verifier memory image from + // QUOTIENT_FRAME_BASE..+QUOTIENT_FRAME_LEN, reconstructs the same + // y-batched numerator, and returns: + // word 0: magic/version + // word 1: linearization expected eval + // word 2..: simple-selector accumulators + // =============================================================== + { + let q_out := QUOTIENT_RETURN_MPTR + // The quotient evaluator is as correctness-critical as the VK: + // it reconstructs the y-batched identity numerator and + // selector buckets. Re-check the pinned runtime before every + // external call, mirroring the VK freshness guard above. + if iszero(and( + eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), + eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) + )) { revert(0, 0) } + if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x0180)) { revert(0, 0) } + if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { revert(0, 0) } + // Word 1 is the negated y-batched identity numerator, stored + // in the same memory slot used by the monolithic path. + mstore(QUOTIENT_EVAL_MPTR, mload(add(q_out, 0x20))) + // Remaining return words are selector linearization buckets. + // Copy them back into the canonical selector accumulator region + // so the PCS code path is identical for split and monolithic + // quotient renders. + for { let q_i := 0 } lt(q_i, 10) { q_i := add(q_i, 1) } { + mstore(add(SELECTOR_ACC_MPTR, shl(5, q_i)), mload(add(q_out, add(0x40, shl(5, q_i))))) + } + } + + // =============================================================== + // Prepare linearization scalars for the final PCS MSM. + // + // The linearized commitment is + // (1 - x^n) * Σ_i x_split^i * Q_i + // + Σ_j sel_acc_j * S_j_com, + // where x_split = x^(n-1). Instead of materializing that point + // with a standalone G1MSM here, PCS block 5 expands the + // linearized commitment into its quotient and selector + // pairs inside the already-fused final MSM. + // + // QUOTIENT_MPTR is no longer a G1 point in this path. Its first + // two words carry: + // word 0: x_split + // word 1: one_minus_x_n + // =============================================================== + { + let x := mload(X_MPTR) + let k := 20 + // Compute both x^n and x^(n-1) with the same squaring walk: + // x_pow_2i tracks x^(2^i), while x_pow_2i_minus1 tracks + // x^(2^i - 1). + let x_pow_2i := x + let x_pow_2i_minus1 := 1 + for { let idx := 0 } lt(idx, k) { idx := add(idx, 1) } { + x_pow_2i_minus1 := mulmod( + mulmod(x_pow_2i_minus1, x_pow_2i_minus1, r), + x, + r + ) + x_pow_2i := mulmod(x_pow_2i, x_pow_2i, r) + } + let x_split := x_pow_2i_minus1 + let one_minus_x_n := addmod(1, sub(r, x_pow_2i), r) + + // PCS block 5 interprets this 2-word payload as scalar + // metadata, not as a materialized G1 point. + mstore(QUOTIENT_MPTR, x_split) + mstore(add(QUOTIENT_MPTR, 0x20), one_minus_x_n) + } + + // =============================================================== + // PCS computation (multi-prepare emitter from Step 5). + // + // The Rust lowering stage has already expanded the KZG multi-open + // equation into a sequence of generated Yul sub-blocks. Those + // blocks populate: + // - F_EVAL_MPTR / V_MPTR scalar batching values; + // - FINAL_COM_MPTR for the fused commitment MSM; + // - PAIRING_LHS_MPTR and PAIRING_RHS_MPTR for the final pairing. + // =============================================================== + { + // Generated PCS sub-block 1. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // 4 distinct rotation(s) + let x := mload(X_MPTR) + let omega := mload(OMEGA_MPTR) + let omega_inv := mload(OMEGA_INV_MPTR) + let x_pow_of_omega := x + mstore(add(ROT_POINTS_MPTR, 0x40), x_pow_of_omega) + x_pow_of_omega := mulmod(x_pow_of_omega, omega, r) + mstore(add(ROT_POINTS_MPTR, 0x60), x_pow_of_omega) + x_pow_of_omega := x + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + mstore(add(ROT_POINTS_MPTR, 0x20), x_pow_of_omega) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + mstore(add(ROT_POINTS_MPTR, 0x0), x_pow_of_omega) + } + // Generated PCS sub-block 2. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // pre-compute 43 x1 power(s) + let x1 := mload(X1_MPTR) + mstore(X1_POWERS_MPTR, 1) + let acc := 1 + let p := X1_POWERS_MPTR + for { let i := 0 } lt(i, 0x2a) { i := add(i, 1) } { + p := add(p, 0x20) + acc := mulmod(acc, x1, r) + mstore(p, and(acc, 0xffffffffffffffffffffffffffffffff)) + } + } + // Generated PCS sub-block 3. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x9980) + mstore(0xb2a0, 0x9480) + mstore(0xb2c0, 0xa020) + mstore(0xb2e0, 0xa040) + mstore(0xb300, 0xa0a0) + mstore(0xb320, 0xa0c0) + mstore(0xb340, 0xa120) + mstore(0xb360, 0x99a0) + mstore(0xb380, 0x99c0) + mstore(0xb3a0, 0x99e0) + mstore(0xb3c0, 0x9a00) + mstore(0xb3e0, 0x9a20) + mstore(0xb400, 0x9a40) + mstore(0xb420, 0x9a60) + mstore(0xb440, 0x9a80) + mstore(0xb460, 0x9aa0) + mstore(0xb480, 0x9ac0) + mstore(0xb4a0, 0x9ae0) + mstore(0xb4c0, 0x9b00) + mstore(0xb4e0, 0x9b20) + mstore(0xb500, 0x9b40) + mstore(0xb520, 0x9b60) + mstore(0xb540, 0x9b80) + mstore(0xb560, 0x9ba0) + mstore(0xb580, 0x9bc0) + mstore(0xb5a0, 0x9be0) + mstore(0xb5c0, 0x9c00) + mstore(0xb5e0, 0x9c20) + mstore(0xb600, 0x9c40) + mstore(0xb620, 0x9c60) + mstore(0xb640, 0x9c80) + mstore(0xb660, 0x9ca0) + mstore(0xb680, 0x9cc0) + mstore(0xb6a0, 0x9ce0) + mstore(0xb6c0, 0x9d00) + mstore(0xb6e0, 0x9d20) + mstore(0xb700, 0x9d40) + mstore(0xb720, 0x9d60) + mstore(0xb740, 0x9d80) + mstore(0xb760, 0x9da0) + mstore(0xb780, 0x9dc0) + mstore(0xb7a0, 0x9de0) + mstore(0xb7c0, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x9980) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x20) + for { let i := 1 } lt(i, 0x2b) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x20) + } + mstore(add(Q_EVAL_SET_MPTR, 0x0), q_eval_set_0) + } + // Generated PCS sub-block 4. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[1]: 3 commitment(s) + let q_eval_set_0 := mload(0x9660) + let q_eval_set_1 := mload(0x9920) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9940), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x96a0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9960), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) + } + // Generated PCS sub-block 5. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[2]: 3 commitment(s) + let q_eval_set_0 := mload(0x9fe0) + let q_eval_set_1 := mload(0xa000) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa080), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa0e0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa100), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) + } + // Generated PCS sub-block 6. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x94a0) + mstore(0xb2a0, 0x9540) + mstore(0xb2c0, 0x97c0) + mstore(0xb2e0, 0x94c0) + mstore(0xb300, 0x9560) + mstore(0xb320, 0x97e0) + mstore(0xb340, 0x94e0) + mstore(0xb360, 0x9580) + mstore(0xb380, 0x9800) + mstore(0xb3a0, 0x9500) + mstore(0xb3c0, 0x96c0) + mstore(0xb3e0, 0x9820) + mstore(0xb400, 0x9520) + mstore(0xb420, 0x96e0) + mstore(0xb440, 0x9840) + mstore(0xb460, 0x95a0) + mstore(0xb480, 0x9700) + mstore(0xb4a0, 0x9860) + mstore(0xb4c0, 0x95c0) + mstore(0xb4e0, 0x9720) + mstore(0xb500, 0x9880) + mstore(0xb520, 0x95e0) + mstore(0xb540, 0x9740) + mstore(0xb560, 0x98a0) + mstore(0xb580, 0x9600) + mstore(0xb5a0, 0x9760) + mstore(0xb5c0, 0x98c0) + mstore(0xb5e0, 0x9620) + mstore(0xb600, 0x9780) + mstore(0xb620, 0x98e0) + mstore(0xb640, 0x9640) + mstore(0xb660, 0x97a0) + mstore(0xb680, 0x9900) + let q_eval_set_0 := mload(0x94a0) + let q_eval_set_1 := mload(0x9540) + let q_eval_set_2 := mload(0x97c0) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x60) + for { let i := 1 } lt(i, 0xb) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(mload(add(eval_p, 0x20))), pow, r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(mload(add(eval_p, 0x40))), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x60) + } + mstore(add(Q_EVAL_SET_MPTR, 0xa0), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_1) + mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_2) + } + // Generated PCS sub-block 7. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x9e00) + mstore(0xb2a0, 0x9e20) + mstore(0xb2c0, 0x9e40) + mstore(0xb2e0, 0x9e60) + mstore(0xb300, 0x9e80) + mstore(0xb320, 0x9ea0) + mstore(0xb340, 0x9ec0) + mstore(0xb360, 0x9ee0) + mstore(0xb380, 0x9f00) + mstore(0xb3a0, 0x9f20) + mstore(0xb3c0, 0x9f40) + mstore(0xb3e0, 0x9f60) + mstore(0xb400, 0x9f80) + mstore(0xb420, 0x9fa0) + mstore(0xb440, 0x9fc0) + let q_eval_set_0 := mload(0x9e00) + let q_eval_set_1 := mload(0x9e20) + let q_eval_set_2 := mload(0x9e40) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x60) + for { let i := 1 } lt(i, 0x5) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(mload(add(eval_p, 0x20))), pow, r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(mload(add(eval_p, 0x40))), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x60) + } + mstore(add(Q_EVAL_SET_MPTR, 0x100), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x120), q_eval_set_1) + mstore(add(Q_EVAL_SET_MPTR, 0x140), q_eval_set_2) + } + // Generated PCS sub-block 8. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // f_eval via Horner over 5 reversed set(s) + let x2 := mload(X2_MPTR) + let x3 := mload(X3_MPTR) + let f_eval := 0 + let Q_EVAL_CPTR := mload(Q_EVAL_CPTR_MPTR) + let rot_pt_0 := mload(add(ROT_POINTS_MPTR, 0x0)) + let rot_pt_1 := mload(add(ROT_POINTS_MPTR, 0x20)) + let rot_pt_2 := mload(add(ROT_POINTS_MPTR, 0x40)) + let rot_pt_3 := mload(add(ROT_POINTS_MPTR, 0x60)) + // --- set 4 (cardinality 3) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let dx_2 := addmod(x3, sub(r, rot_pt_0), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_0), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_0), r), r) + let lbasis_2 := 1 + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_0, sub(r, rot_pt_2), r), r) + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_0, sub(r, rot_pt_3), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, dx_2, r) + let bp_3 := mulmod(bp_2, lbasis_0, r) + let bp_4 := mulmod(bp_3, lbasis_1, r) + let bp_5 := mulmod(bp_4, lbasis_2, r) + let bq := scalar_inv(bp_5) + let lbasis_inv_2 := mulmod(bq, bp_4, r) + bq := mulmod(bq, lbasis_2, r) + let lbasis_inv_1 := mulmod(bq, bp_3, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_2 := mulmod(bq, bp_1, r) + bq := mulmod(bq, dx_2, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + den_inv := mulmod(den_inv, dx_inv_2, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x80)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x100)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x120)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + let term_2 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x140)), dx_inv_2, r), lbasis_inv_2, r) + eval := addmod(eval, sub(r, term_2), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 3 (cardinality 3) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let dx_2 := addmod(x3, sub(r, rot_pt_1), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_1), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_1), r), r) + let lbasis_2 := 1 + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_1, sub(r, rot_pt_2), r), r) + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_1, sub(r, rot_pt_3), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, dx_2, r) + let bp_3 := mulmod(bp_2, lbasis_0, r) + let bp_4 := mulmod(bp_3, lbasis_1, r) + let bp_5 := mulmod(bp_4, lbasis_2, r) + let bq := scalar_inv(bp_5) + let lbasis_inv_2 := mulmod(bq, bp_4, r) + bq := mulmod(bq, lbasis_2, r) + let lbasis_inv_1 := mulmod(bq, bp_3, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_2 := mulmod(bq, bp_1, r) + bq := mulmod(bq, dx_2, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + den_inv := mulmod(den_inv, dx_inv_2, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xa0)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xc0)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + let term_2 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xe0)), dx_inv_2, r), lbasis_inv_2, r) + eval := addmod(eval, sub(r, term_2), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 2 (cardinality 2) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, lbasis_0, r) + let bp_3 := mulmod(bp_2, lbasis_1, r) + let bq := scalar_inv(bp_3) + let lbasis_inv_1 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_1, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x60)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x80)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 1 (cardinality 2) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_1), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_1), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_1, sub(r, rot_pt_2), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, lbasis_0, r) + let bp_3 := mulmod(bp_2, lbasis_1, r) + let bq := scalar_inv(bp_3) + let lbasis_inv_1 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_1, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x20)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x40)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 0 (cardinality 1) --- + { + let dx0 := addmod(x3, sub(r, rot_pt_2), r) + let dx0_inv := scalar_inv(dx0) + let eval := mulmod(addmod(calldataload(add(Q_EVAL_CPTR, 0x0)), sub(r, mload(add(Q_EVAL_SET_MPTR, 0x0))), r), dx0_inv, r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + mstore(F_EVAL_MPTR, f_eval) + } + // Generated PCS sub-block 9. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // build final_com and v (KZG single-opening proof, fused MSM) + // final MSM input length from circuit/VK shape: 78 term(s) + let x4 := mload(X4_MPTR) + let lin_x_split := mload(QUOTIENT_MPTR) + let lin_one_minus_x_n := mload(add(QUOTIENT_MPTR, 0x20)) + let Q_EVAL_CPTR := mload(Q_EVAL_CPTR_MPTR) + let x4_pow_full := 1 + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_1 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_2 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_3 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_4 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_5 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + let v := calldataload(Q_EVAL_CPTR) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), x4_pow_1, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), x4_pow_3, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x80)), x4_pow_4, r), r) + v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_5, r), r) + mcopy(0xb280, 0xa840, 0x80) + mstore(0xb300, 1) + mcopy(0xb320, 0xa8c0, 0x80) + mstore(0xb3a0, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0xb3c0, 0xacc0, 0x80) + mstore(0xb440, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0xb460, 0xa940, 0x80) + mstore(0xb4e0, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0xb500, 0xad40, 0x80) + mstore(0xb580, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0xb5a0, 0xaec0, 0x80) + mstore(0xb620, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0xb640, 0x6700, 0x80) + mstore(0xb6c0, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0xb6e0, 0x6480, 0x80) + mstore(0xb760, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0xb780, 0x6500, 0x80) + mstore(0xb800, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0xb820, 0x6580, 0x80) + mstore(0xb8a0, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0xb8c0, 0x6600, 0x80) + mstore(0xb940, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0xb960, 0x6680, 0x80) + mstore(0xb9e0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0xba00, 0x6280, 0x80) + mstore(0xba80, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0xbaa0, 0x6300, 0x80) + mstore(0xbb20, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0xbb40, 0x6380, 0x80) + mstore(0xbbc0, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0xbbe0, 0x6400, 0x80) + mstore(0xbc60, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0xbc80, 0x6780, 0x80) + mstore(0xbd00, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0xbd20, 0x6800, 0x80) + mstore(0xbda0, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0xbdc0, 0x6880, 0x80) + mstore(0xbe40, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0xbe60, 0x6900, 0x80) + mstore(0xbee0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0xbf00, 0x6b00, 0x80) + mstore(0xbf80, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0xbfa0, 0x6c00, 0x80) + mstore(0xc020, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0xc040, 0x6f80, 0x80) + mstore(0xc0c0, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0xc0e0, 0x7000, 0x80) + mstore(0xc160, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0xc180, 0x7080, 0x80) + mstore(0xc200, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0xc220, 0x7100, 0x80) + mstore(0xc2a0, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0xc2c0, 0x7180, 0x80) + mstore(0xc340, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0xc360, 0x7200, 0x80) + mstore(0xc3e0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0xc400, 0x7280, 0x80) + mstore(0xc480, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0xc4a0, 0x7300, 0x80) + mstore(0xc520, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0xc540, 0x7380, 0x80) + mstore(0xc5c0, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0xc5e0, 0x7400, 0x80) + mstore(0xc660, mload(add(X1_POWERS_MPTR, 0x400))) + mcopy(0xc680, 0x7480, 0x80) + mstore(0xc700, mload(add(X1_POWERS_MPTR, 0x420))) + mcopy(0xc720, 0x7500, 0x80) + mstore(0xc7a0, mload(add(X1_POWERS_MPTR, 0x440))) + mcopy(0xc7c0, 0x7580, 0x80) + mstore(0xc840, mload(add(X1_POWERS_MPTR, 0x460))) + mcopy(0xc860, 0x7600, 0x80) + mstore(0xc8e0, mload(add(X1_POWERS_MPTR, 0x480))) + mcopy(0xc900, 0x7680, 0x80) + mstore(0xc980, mload(add(X1_POWERS_MPTR, 0x4a0))) + mcopy(0xc9a0, 0x7700, 0x80) + mstore(0xca20, mload(add(X1_POWERS_MPTR, 0x4c0))) + mcopy(0xca40, 0x7780, 0x80) + mstore(0xcac0, mload(add(X1_POWERS_MPTR, 0x4e0))) + mcopy(0xcae0, 0x7800, 0x80) + mstore(0xcb60, mload(add(X1_POWERS_MPTR, 0x500))) + mcopy(0xcb80, 0x7880, 0x80) + mstore(0xcc00, mload(add(X1_POWERS_MPTR, 0x520))) + let lin_query_scalar_41 := mload(add(X1_POWERS_MPTR, 0x540)) + let lin_cur_scalar_41 := mulmod(lin_query_scalar_41, lin_one_minus_x_n, r) + mcopy(0xcc20, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0xcca0, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xccc0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0xcd40, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xcd60, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0xcde0, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xce00, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0xce80, lin_cur_scalar_41) + mcopy(0xcea0, 0x6980, 0x80) + mstore(0xcf20, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0xcf40, 0x6a00, 0x80) + mstore(0xcfc0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0xcfe0, 0x6a80, 0x80) + mstore(0xd060, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0xd080, 0x6b80, 0x80) + mstore(0xd100, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0xd120, 0x6c80, 0x80) + mstore(0xd1a0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) + mcopy(0xd1c0, 0x6d00, 0x80) + mstore(0xd240, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) + mcopy(0xd260, 0x6d80, 0x80) + mstore(0xd2e0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) + mcopy(0xd300, 0x6e00, 0x80) + mstore(0xd380, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) + mcopy(0xd3a0, 0x6e80, 0x80) + mstore(0xd420, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) + mcopy(0xd440, 0x6f00, 0x80) + mstore(0xd4c0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) + mcopy(0xd4e0, 0xa6c0, 0x80) + mstore(0xd560, x4_pow_1) + mcopy(0xd580, 0xa740, 0x80) + mstore(0xd600, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0xd620, 0xa7c0, 0x80) + mstore(0xd6a0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0xd6c0, 0xac40, 0x80) + mstore(0xd740, x4_pow_2) + mcopy(0xd760, 0xadc0, 0x80) + mstore(0xd7e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0xd800, 0xae40, 0x80) + mstore(0xd880, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) + mcopy(0xd8a0, 0xa140, 0x80) + mstore(0xd920, x4_pow_3) + mcopy(0xd940, 0xa1c0, 0x80) + mstore(0xd9c0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) + mcopy(0xd9e0, 0xa240, 0x80) + mstore(0xda60, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_3, r)) + mcopy(0xda80, 0xa2c0, 0x80) + mstore(0xdb00, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_3, r)) + mcopy(0xdb20, 0xa340, 0x80) + mstore(0xdba0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_3, r)) + mcopy(0xdbc0, 0xa3c0, 0x80) + mstore(0xdc40, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_3, r)) + mcopy(0xdc60, 0xa440, 0x80) + mstore(0xdce0, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_3, r)) + mcopy(0xdd00, 0xa4c0, 0x80) + mstore(0xdd80, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_3, r)) + mcopy(0xdda0, 0xa540, 0x80) + mstore(0xde20, mulmod(mload(add(X1_POWERS_MPTR, 0x100)), x4_pow_3, r)) + mcopy(0xde40, 0xa5c0, 0x80) + mstore(0xdec0, mulmod(mload(add(X1_POWERS_MPTR, 0x120)), x4_pow_3, r)) + mcopy(0xdee0, 0xa640, 0x80) + mstore(0xdf60, mulmod(mload(add(X1_POWERS_MPTR, 0x140)), x4_pow_3, r)) + mcopy(0xdf80, 0xa9c0, 0x80) + mstore(0xe000, x4_pow_4) + mcopy(0xe020, 0xaa40, 0x80) + mstore(0xe0a0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_4, r)) + mcopy(0xe0c0, 0xaac0, 0x80) + mstore(0xe140, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_4, r)) + mcopy(0xe160, 0xab40, 0x80) + mstore(0xe1e0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_4, r)) + mcopy(0xe200, 0xabc0, 0x80) + mstore(0xe280, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_4, r)) + mcopy(0xe2a0, F_COM_MPTR, 0x80) + mstore(0xe320, x4_pow_5) + if success { + success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mstore(V_MPTR, v) + } + // Generated PCS sub-block 10. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // Scale z*pi - vG before the final pairing check + // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) + mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) + if success { + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(0x1080, FINAL_COM_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) + if success { + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + if success { + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) + } + } + + // Batch the prevalidated public IVC accumulator pairing equation + // into the final KZG pairing. + // + // We do not simply multiply the two pairing equations together: + // two bad equations could cancel. Instead, after all four G1 + // pairing inputs are fixed, derive a verifier-local randomizer + // alpha and check: + // + // e(kzg_rhs + alpha * acc_rhs, G2_BASE) + // * e(kzg_lhs + alpha * acc_lhs, NEG_S_G2_BASE) == 1 + // + // If either original equation is bad, this combined equation + // holds for at most one alpha in Fr. + { + let batch_ptr := 0x0100 + + // Domain || KZG rhs/lhs || accumulator rhs/lhs. + mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) + mcopy(add(batch_ptr, 0x20), PAIRING_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0xa0), PAIRING_LHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x0120), ACC_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x01a0), ACC_LHS_MPTR, 0x80) + // alpha is Fiat-Shamir over the fully materialized pairing + // inputs. Replace the negligible zero draw with one so the + // accumulator equation cannot be accidentally dropped. + let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0220), r) + if iszero(acc_pair_alpha) { acc_pair_alpha := 1 } + + // PAIRING_RHS_MPTR += alpha * ACC_RHS_MPTR. + // First compute alpha * ACC_RHS with a one-pair G1MSM, then + // add it into the KZG RHS point. + mcopy(batch_ptr, ACC_RHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x80), acc_pair_alpha) + if success { + success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(add(batch_ptr, 0x80), PAIRING_RHS_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + + // PAIRING_LHS_MPTR += alpha * ACC_LHS_MPTR. + // Mirror the same randomized batching on the KZG LHS point. + mcopy(batch_ptr, ACC_LHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x80), acc_pair_alpha) + if success { + success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(add(batch_ptr, 0x80), PAIRING_LHS_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + } + + // The Yul `ec_pairing` helper checks + // e(arg0, G2_BASE) * e(arg1, NEG_S_G2_BASE) == 1 + // i.e. e(arg0, [1]_2) = e(arg1, [s]_2). + // + // The KZG pairing identity is + // e(final_com - v*G + x3*pi, [1]_2) = e(pi, [s]_2), + // so arg0 must be (final_com - v*G + x3*pi) and arg1 must be + // pi. The PAIRING_*_MPTR slots store + // PAIRING_LHS_MPTR := pi + // PAIRING_RHS_MPTR := final_com - v*G + x3*pi + // -- the historical "LHS"/"RHS" naming follows the dual MSM + // accumulator (left = pi, right = combined) and *not* the + // pairing argument order. Pass them swapped to ec_pairing. + if iszero(success) { revert(0, 0) } + success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) + + + + // Success path is terminal. Invalid inputs have already reverted, + // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } + mstore(RETURN_MPTR, 1) + return(RETURN_MPTR, 0x20) + } + } +} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol new file mode 100644 index 000000000..f8c08652b --- /dev/null +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: CC0-1.0 + +pragma solidity ^0.8.24; + +/// @title Halo2 BLS12-381 verifying-key payload. +/// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. +/// @dev Byte 0 is an unconditional INVALID opcode so direct calls cannot execute payload bytes as code. The linked verifier pins the full runtime by length/codehash and copies the payload starting at byte 1. +/// @dev The layout follows the verifier inputs derived from +/// `midfall/proofs/src/plonk/mod.rs::VerifyingKey` and the transcript +/// `vk.hash_into` behavior used by `midfall/proofs/src/plonk/verifier.rs`. +/// +/// Layout (in 32-byte words, big-endian). The header slots are generated from +/// Rust's `VkHeaderLayout`; the byte offsets are absolute from the start of the +/// VK payload, not from byte 0 of the runtime. Runtime byte 0 is the INVALID +/// prefix; the verifier loads the payload via +/// `extcodecopy(vk, VK_MPTR, 0x01, vk_payload_len)` and then references each +/// slot by `VK_MPTR + i`. +/// +/// word 0 : vk_digest (Fq, transcript_repr of the CS) +/// word 1 : num_instances +/// word 2 : k (log2 of the domain size) +/// word 3 : n_inv (1/n in Fr) +/// word 4 : omega (n-th primitive root of unity) +/// word 5 : omega_inv +/// word 6 : omega_inv_to_l (omega_inv ^ |rotation_last|) +/// word 7 : has_accumulator (0 or 1) +/// word 8 : acc_offset (instance index of the accumulator) +/// word 9 : num_acc_limbs +/// word 10 : num_acc_limb_bits +/// word 11..14 : G1_BASE (4 words, EIP-2537 padded) +/// word 15..22 : G2_BASE (8 words, EIP-2537 padded) +/// word 23..30 : NEG_S_G2_BASE (8 words, EIP-2537 padded) +/// word 31..30 + Q_PAYLOAD : quotient VM constants + packed bytecode +/// word 31 + Q_PAYLOAD .. : fixed_comms (4 words each) +/// word 31 + Q_PAYLOAD + 4*N_FIXED .. +/// : permutation_comms (4 words each) +/// +/// Notes: +/// - `extcodehash` of this contract is pinned by the linked verifier via +/// `EXPECTED_VK_CODEHASH`, so any byte tweak is detected at deploy time. +/// - The quotient identity interpreter's static program is stored in this +/// pinned VK runtime. The verifier reads it from memory after `extcodecopy`, +/// avoiding verifier-side PUSH32/mstore immediates while keeping the program +/// covered by `EXPECTED_VK_CODEHASH`. +/// - The midnight-proofs migration bakes the per-lookup chunk counts, trashcan +/// structure, and `num_simple_selectors` into the generated verifier code. +contract Halo2VerifyingKey { + /// @notice Deploy the verifying-key payload as this contract's runtime bytecode. + /// @dev The constructor writes an INVALID byte followed by generated words into memory and returns that prefixed runtime. + /// @dev The transient construction buffer starts at `0x80`, preserving Solidity's reserved memory words. + constructor() { + assembly { + // Runtime layout: + // byte 0 : INVALID, so the payload cannot be executed + // byte 1..end : generated VK payload copied by Halo2Verifier + // + // `runtime` includes the INVALID prefix; `payload` points to word + // zero of the verifier-key data described in the contract NatSpec. + let runtime := 0x80 + let payload := add(runtime, 0x01) + mstore8(runtime, 0xfe) + // Header, base-point, and quotient-program words generated from + // VkPayloadLayout. The inline names on each mstore identify the + // exact slot in the rendered source. + mstore(add(payload, 0x0000), 0x04d431b03dc86a4ddf0aef1f258576d6df8e1b884a7aa7564fea2df1b04a0f86) // vk_digest + mstore(add(payload, 0x0020), 0x000000000000000000000000000000000000000000000000000000000000000e) // num_instances + mstore(add(payload, 0x0040), 0x0000000000000000000000000000000000000000000000000000000000000014) // k + mstore(add(payload, 0x0060), 0x73eda0144f284aae5b6554d46c21576b363d4ec725be2bff1a400fff00001001) // n_inv + mstore(add(payload, 0x0080), 0x03e1c54bcb947035a57a6e07cb98de4a2f69e02d265e09d9fece7e0e39898d4b) // omega + mstore(add(payload, 0x00a0), 0x6c39442eade0092768ac033fa6f608750624a1bb17dbc026ef97c3573a28fc8c) // omega_inv + mstore(add(payload, 0x00c0), 0x2a0ccbaa0613f093f2bb6e97859513f0b613d8587eaa92db9e5604b8d6b68d45) // omega_inv_to_l + mstore(add(payload, 0x00e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // has_accumulator + mstore(add(payload, 0x0100), 0x0000000000000000000000000000000000000000000000000000000000000004) // acc_offset + mstore(add(payload, 0x0120), 0x0000000000000000000000000000000000000000000000000000000000000007) // num_acc_limbs + mstore(add(payload, 0x0140), 0x0000000000000000000000000000000000000000000000000000000000000038) // num_acc_limb_bits + mstore(add(payload, 0x0160), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) // g1_x_hi + mstore(add(payload, 0x0180), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) // g1_x_lo + mstore(add(payload, 0x01a0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) // g1_y_hi + mstore(add(payload, 0x01c0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) // g1_y_lo + mstore(add(payload, 0x01e0), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) // g2_x_c0_hi + mstore(add(payload, 0x0200), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) // g2_x_c0_lo + mstore(add(payload, 0x0220), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) // g2_x_c1_hi + mstore(add(payload, 0x0240), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) // g2_x_c1_lo + mstore(add(payload, 0x0260), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) // g2_y_c0_hi + mstore(add(payload, 0x0280), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) // g2_y_c0_lo + mstore(add(payload, 0x02a0), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) // g2_y_c1_hi + mstore(add(payload, 0x02c0), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) // g2_y_c1_lo + mstore(add(payload, 0x02e0), 0x0000000000000000000000000000000007acb569b3187c0fd1993980aa52a6e9) // neg_s_g2_x_c0_hi + mstore(add(payload, 0x0300), 0xe2080b9697fab96abd5c5f1c3b988256f2d99366f1bbccf13cf0e20702fee18c) // neg_s_g2_x_c0_lo + mstore(add(payload, 0x0320), 0x0000000000000000000000000000000004bbe1a24fcc4f988c6ef268d0c1160e) // neg_s_g2_x_c1_hi + mstore(add(payload, 0x0340), 0xac0a0c4f53d80bd74f3d2e4667be27408625a83825354e27c70859883102eb43) // neg_s_g2_x_c1_lo + mstore(add(payload, 0x0360), 0x00000000000000000000000000000000091f5fc856da557cdb852412d3fd2cef) // neg_s_g2_y_c0_hi + mstore(add(payload, 0x0380), 0x9034c9a66ce38bf356c49f6a012109440035923a9cd6c71ca0c8efa5b6badf52) // neg_s_g2_y_c0_lo + mstore(add(payload, 0x03a0), 0x000000000000000000000000000000000af8fa5434d3fdd8c90fe8e532246c49) // neg_s_g2_y_c1_hi + mstore(add(payload, 0x03c0), 0x9926d8d728ccbb4ac40381158e8da573b4895782bfdb788c8ff40ba22032eab3) // neg_s_g2_y_c1_lo + mstore(add(payload, 0x03e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // quotient_const + mstore(add(payload, 0x0400), 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140) // quotient_const + mstore(add(payload, 0x0420), 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a) // quotient_const + mstore(add(payload, 0x0440), 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db) // quotient_const + mstore(add(payload, 0x0460), 0x00bbe1fbe9ef1e2d62490b03a82bf9ef10f5e9b2323033669cf6c50481f63e05) // quotient_const + mstore(add(payload, 0x0480), 0x0000000000000000000000000000000000000000000000000100000000000000) // quotient_const + mstore(add(payload, 0x04a0), 0x0000000000000000000000000000000000010000000000000000000000000000) // quotient_const + mstore(add(payload, 0x04c0), 0x0000000000000000000000000000000000000000000000000000000400000000) // quotient_const + mstore(add(payload, 0x04e0), 0x0000000000000000000000000000000000000000040000000000000000000000) // quotient_const + mstore(add(payload, 0x0500), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x0520), 0x0000000000000000000000000000000000000000000000100000000000000000) // quotient_const + mstore(add(payload, 0x0540), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000) // quotient_const + mstore(add(payload, 0x0560), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefeffffff00000001) // quotient_const + mstore(add(payload, 0x0580), 0x73eda753299d7d483339d80809a1d80553bca402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x05a0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffb00000001) // quotient_const + mstore(add(payload, 0x05c0), 0x73eda753299d7d483339d80809a1d80553bda402fbfe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x05e0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffefffff001) // quotient_const + mstore(add(payload, 0x0600), 0x73eda753299d7d483339d80809a1d80553bda402fffe5beeffffffff00000001) // quotient_const + mstore(add(payload, 0x0620), 0x00000000000000000000000000000010ff0726c5de281020ad8016cf6f691213) // quotient_const + mstore(add(payload, 0x0640), 0x0000000000000000000000000000002c64068790f917282347187665718b04c8) // quotient_const + mstore(add(payload, 0x0660), 0x00000000000000000000000000000027241bb5338dce8a77499428839473bf3a) // quotient_const + mstore(add(payload, 0x0680), 0x0000000000000000000000000000002b7c4a26a1c7ae6fc4b499d04e4a463c4b) // quotient_const + mstore(add(payload, 0x06a0), 0x000000000000000000000000000000274bc40fcf526be95333a8c22c79465298) // quotient_const + mstore(add(payload, 0x06c0), 0x0000000000000000000000000000002a5ee6db49930276e2939d1c43ac82f744) // quotient_const + mstore(add(payload, 0x06e0), 0x73eda753299d7d483339d80809a1d7edd77e26c51c38afb5debf8afa00c15cc3) // quotient_const + mstore(add(payload, 0x0700), 0x73eda753299d7d483339d80809a1d7c553bda402fffe5bfeffffffff00000002) // quotient_const + mstore(add(payload, 0x0720), 0x73eda753299d7d483339d80809a1d80553bda402fffe53ebc627fffef6280001) // quotient_const + mstore(add(payload, 0x0740), 0x0000000000000000000001000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0760), 0x0000000100000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0780), 0x6bc66e553973f396854f5626172ba135587d41e37a68209402355093fdcaaf6c) // quotient_const + mstore(add(payload, 0x07a0), 0x63f31e3f446953960c9d6964474300df43ab29179970f642a28e39d6c883c74b) // quotient_const + mstore(add(payload, 0x07c0), 0x73eda753299d7d483339d70809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x07e0), 0x73eda752299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x0800), 0x082738fdf02989b1adea81e1f27636cffb40621f85963b6afdcaaf6b02355095) // quotient_const + mstore(add(payload, 0x0820), 0x0ffa8913e53429b2269c6ea3c25ed72610127aeb668d65bc5d71c628377c38b6) // quotient_const + mstore(add(payload, 0x0840), 0x01ec1c0519185dfe86132d479c76d0786e1e037d0b05ca47648a1c5d29492c9b) // quotient_const + mstore(add(payload, 0x0860), 0x1e179025ca2470882b34e63940ccbd7ad9090bf414d43b696e093b5a8782528f) // quotient_const + mstore(add(payload, 0x0880), 0x4298bfee9a84c8ef8e83702075cb1abeb576f146636342e3db9ea6b0a4adf29d) // quotient_const + mstore(add(payload, 0x08a0), 0x3c83b078e9abed278d042acc8f3bd21e228716f04be96af8025da860e2d1bba9) // quotient_const + mstore(add(payload, 0x08c0), 0x427868260f487d1ef07edaadf37f5dbe705bd1318290f2577ae756b009c24f11) // quotient_const + mstore(add(payload, 0x08e0), 0x03020e6a35e595abd22838beeadc45cfcb0545d85ca0ab2c59d44c203fac84a7) // quotient_const + mstore(add(payload, 0x0900), 0x000000000000000000000000000000000000000000000000d201000000010000) // quotient_const + mstore(add(payload, 0x0920), 0x0000000100001b7c3f8d3fe3c5b448f1bdeb2ae34698b72d6ce966fc208c05ed) // quotient_const + mstore(add(payload, 0x0940), 0x73eda753299d7d483339d80809a1d7fd4057a4c12f26d1c1778e3360a6820001) // quotient_const + mstore(add(payload, 0x0960), 0x057797fa7060856f215654ff11006fe0acf6a437e9477bf6f782dfac86f2cf75) // quotient_const + mstore(add(payload, 0x0980), 0x0000000000000000000000000000000000000000000000000000000000000002) // quotient_const + mstore(add(payload, 0x09a0), 0x0000000000000000000000000000000000000000000000000200000000000000) // quotient_const + mstore(add(payload, 0x09c0), 0x0000000000000000000000000000000000020000000000000000000000000000) // quotient_const + mstore(add(payload, 0x09e0), 0x73eda753299d7d483339d80809a1d7e13511a4044eaa5bff4600ffff00005556) // quotient_const + mstore(add(payload, 0x0a00), 0x73eda753299d7d483339d80809a1d7c553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x0a20), 0x73eda753299d7d483339d80809a1d7d340dd972492de594de627fffefcb80349) // quotient_const + mstore(add(payload, 0x0a40), 0x73eda753299d7d483339d80809a1d7dbdc391ab4d8ac003bbd48021b82456c9b) // quotient_const + mstore(add(payload, 0x0a60), 0x73eda753299d7d483339d80809a1d7d1448ee5caf5eefcffbc9fabc57759e23f) // quotient_const + mstore(add(payload, 0x0a80), 0x73eda753299d7d483339d80809a1d80418c74cc18bb28443d3978d1fd47ffce1) // quotient_const + mstore(add(payload, 0x0aa0), 0x0000000000000000000000000000006425c019bcda40056233b00000068ff970) // quotient_const + mstore(add(payload, 0x0ac0), 0x00000000000000000000000000000052ef09129c4ea4b786856ffbc6fb7526cc) // quotient_const + mstore(add(payload, 0x0ae0), 0x73eda753299d7d483339d80809a1d7d89a085d30fc8a7106a170ac2377c34ab9) // quotient_const + mstore(add(payload, 0x0b00), 0x73eda753299d7d483339d80809a1d7f8ce65bb936f2d836012914aca65f077e1) // quotient_const + mstore(add(payload, 0x0b20), 0x000000000000000000000000000000681e5d7c70141ebdfe86c0a873114c3b84) // quotient_const + mstore(add(payload, 0x0b40), 0x000000000000000000000000000000297784894e27525bc342b7fde37dba9366) // quotient_const + mstore(add(payload, 0x0b60), 0x0000000000000000000000000000000275ecae82e897af7658d0e5be57000640) // quotient_const + mstore(add(payload, 0x0b80), 0x000000000000000000000000000000013af65741744bd7bb2c6872df2b800320) // quotient_const + mstore(add(payload, 0x0ba0), 0x00000000000000000000000000000059736a8da406e7d5f0bd1ea7b710796a90) // quotient_const + mstore(add(payload, 0x0bc0), 0x0000000000000000000000000000000c8557e86f90d0d89eed6eb5349a0f8820) // quotient_const + mstore(add(payload, 0x0be0), 0x0453ae02a5f228d8f956b5eab4fc92bbeea5eb26b6ae4b42b4fdfcfdf026aa22) // quotient_const + mstore(add(payload, 0x0c00), 0x0000000000000000000000000000000000000000000000000000000800000000) // quotient_const + mstore(add(payload, 0x0c20), 0x0000000000000000000000000000000000000000080000000000000000000000) // quotient_const + mstore(add(payload, 0x0c40), 0x0000000000000000000000000000000000000000000000000000000000002000) // quotient_const + mstore(add(payload, 0x0c60), 0x0000000000000000000000000000000000000000000000200000000000000000) // quotient_const + mstore(add(payload, 0x0c80), 0x73eda753299d7d483339d80809a1d7f454b67d3d21d64bde527fe92f9096edee) // quotient_const + mstore(add(payload, 0x0ca0), 0x73eda753299d7d483339d80809a1d7d8efb71c7206e733dbb8e789998e74fb39) // quotient_const + mstore(add(payload, 0x0cc0), 0x73eda753299d7d483339d80809a1d7de2fa1eecf722fd187b66bd77b6b8c40c7) // quotient_const + mstore(add(payload, 0x0ce0), 0x73eda753299d7d483339d80809a1d7d9d7737d61384fec3a4b662fb0b5b9c3b6) // quotient_const + mstore(add(payload, 0x0d00), 0x73eda753299d7d483339d80809a1d7de07f99433ad9272abcc573dd286b9ad69) // quotient_const + mstore(add(payload, 0x0d20), 0x73eda753299d7d483339d80809a1d7daf4d6c8b96cfbe51c6c62e3bb537d08bd) // quotient_const + mstore(add(payload, 0x0d40), 0x00000000000000000000000000000021fe0e4d8bbc5020415b002d9eded22426) // quotient_const + mstore(add(payload, 0x0d60), 0x00000000000000000000000000000058c80d0f21f22e50468e30eccae3160990) // quotient_const + mstore(add(payload, 0x0d80), 0x0000000000000000000000000000004e48376a671b9d14ee9328510728e77e74) // quotient_const + mstore(add(payload, 0x0da0), 0x00000000000000000000000000000056f8944d438f5cdf896933a09c948c7896) // quotient_const + mstore(add(payload, 0x0dc0), 0x0000000000000000000000000000004e97881f9ea4d7d2a667518458f28ca530) // quotient_const + mstore(add(payload, 0x0de0), 0x73eda753299d7d4833351088b4af7508df8b737010b26e15294bfcbb9194fffd) // quotient_const + mstore(add(payload, 0x0e00), 0x0000000000000000000002000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0e20), 0x0000000200000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0e40), 0x639f3557494a69e4d764d44424b56a655d3cdfc3f4d1e529046aa128fb955ed7) // quotient_const + mstore(add(payload, 0x0e60), 0x53f8952b5f3529e3e600fac084e429b93398ae2c32e39086451c73ae91078e95) // quotient_const + mstore(add(payload, 0x0e80), 0x72018b4e10851f49ad26aac06d2b078ce59fa085f4f891b79b75e3a1d6b6d366) // quotient_const + mstore(add(payload, 0x0ea0), 0x55d6172d5f790cc00804f1cec8d51a8a7ab4980eeb2a209591f6c4a4787dad72) // quotient_const + mstore(add(payload, 0x0ec0), 0x3154e7648f18b458a4b667e793d6bd469e46b2bc9c9b191b2461594e5b520d64) // quotient_const + mstore(add(payload, 0x0ee0), 0x3769f6da3ff19020a635ad3b7a6605e731368d12b414f106fda2579e1d2e4458) // quotient_const + mstore(add(payload, 0x0f00), 0x31753f2d1a55002942bafd5a16227a46e361d2d17d6d69a78518a94ef63db0f0) // quotient_const + mstore(add(payload, 0x0f20), 0x70eb98e8f3b7e79c61119f491ec5923588b85e2aa35db0d2a62bb3dec0537b5a) // quotient_const + mstore(add(payload, 0x0f40), 0x03d8380a3230bbfd0c265a8f38eda0f0dc3c06fa160b948ec91438ba52925936) // quotient_const + mstore(add(payload, 0x0f60), 0x3c2f204b9448e1105669cc7281997af5b21217e829a876d2dc1276b50f04a51e) // quotient_const + mstore(add(payload, 0x0f80), 0x1143d88a0b6c1496e9cd0838e1f45d7817303e89c6c829c8b73d4d62495be539) // quotient_const + mstore(add(payload, 0x0fa0), 0x0519b99ea9ba5d06e6ce7d9114d5cc36f15089dd97d479f104bb50c2c5a37751) // quotient_const + mstore(add(payload, 0x0fc0), 0x110328f8f4f37cf5adc3dd53dd5ce3778cf9fe60052388aff5cead6113849e21) // quotient_const + mstore(add(payload, 0x0fe0), 0x057797fa7060856f215655ff11006fee9a1697597c277945ddaadfac83aad2c0) // quotient_const + mstore(add(payload, 0x1000), 0x0000000000000000000000000000003212e00cde6d2002b119d800000347fcb8) // quotient_const + mstore(add(payload, 0x1020), 0x000000000000000000000000000000340f2ebe380a0f5eff4360543988a61dc2) // quotient_const + mstore(add(payload, 0x1040), 0x0000000000000000000000000000002cb9b546d20373eaf85e8f53db883cb548) // quotient_const + mstore(add(payload, 0x1060), 0x0453ae02a5f228d8f956b6eab50092aaff9ec460d8863b22077de62a80bd8812) // quotient_const + mstore(add(payload, 0x1080), 0x73eda753299d7d4833351088b4af7508df8b737010b26601ef73fcbb87bd0000) // quotient_const + mstore(add(payload, 0x10a0), 0x0aef2ff4e0c10ade42aca9fe2200e00159ed486fd28ef7edef05bf590de59ef3) // quotient_const + mstore(add(payload, 0x10c0), 0x0000000000000000000000000000000000000000000000000000000000000006) // quotient_const + mstore(add(payload, 0x10e0), 0x0000000000000000000000000000000000000000000000000600000000000000) // quotient_const + mstore(add(payload, 0x1100), 0x0000000000000000000000000000000000060000000000000000000000000000) // quotient_const + mstore(add(payload, 0x1120), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffffff) // quotient_const + mstore(add(payload, 0x1140), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefdffffff00000001) // quotient_const + mstore(add(payload, 0x1160), 0x73eda753299d7d483339d80809a1d80553bba402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1180), 0x0000000000000000000000000000000000000000000000000000000000000003) // quotient_const + mstore(add(payload, 0x11a0), 0x0000000000000000000000000000000000030000000000000000000000000000) // quotient_const + mstore(add(payload, 0x11c0), 0x0000000000000000000000000000012c71404d368ec010269b10000013afec50) // quotient_const + mstore(add(payload, 0x11e0), 0x000000000000000000000000000000f8cd1b37d4ebee2693904ff354f25f7464) // quotient_const + mstore(add(payload, 0x1200), 0x000000000000000000000000000001385b1875503c5c39fb9441f95933e4b28c) // quotient_const + mstore(add(payload, 0x1220), 0x0000000000000000000000000000007c668d9bea75f71349c827f9aa792fba32) // quotient_const + mstore(add(payload, 0x1240), 0x0000000000000000000000000000000761c60b88b9c70e630a72b13b050012c0) // quotient_const + mstore(add(payload, 0x1260), 0x73eda753299d7d483339d80809a1d7a12dfd8a4625be569ccc4ffffef9700691) // quotient_const + mstore(add(payload, 0x1280), 0x73eda753299d7d483339d80809a1d7b264b49166b159a4787a900438048ad935) // quotient_const + mstore(add(payload, 0x12a0), 0x00000000000000000000000000000003b0e305c45ce387318539589d82800960) // quotient_const + mstore(add(payload, 0x12c0), 0x0000000000000000000000000000010c5a3fa8ec14b781d2375bf725316c3fb0) // quotient_const + mstore(add(payload, 0x12e0), 0x000000000000000000000000000000259007b94eb27289dcc84c1f9dce2e9860) // quotient_const + mstore(add(payload, 0x1300), 0x73eda753299d7d483339d80809a1d79d35602792ebdf9e00793f578beeb3c47d) // quotient_const + mstore(add(payload, 0x1320), 0x73eda753299d7d483339d80809a1d802ddd0f5801766ac88a72f1a40a8fff9c1) // quotient_const + mstore(add(payload, 0x1340), 0x73eda753299d7d483339d80809a1d7abe053165ef916860e42e15847ef869571) // quotient_const + mstore(add(payload, 0x1360), 0x73eda753299d7d483339d80809a1d7ec490dd323de5caac125229595cbe0efc1) // quotient_const + mstore(add(payload, 0x1380), 0x08a75c054be451b1f2ad6bd569f92577dd4bd64d6d5c968569fbf9fbe04d544d) // quotient_const + mstore(add(payload, 0x13a0), 0x0000000000000000000000000000000000000000000000000000001800000000) // quotient_const + mstore(add(payload, 0x13c0), 0x0000000000000000000000000000000000000000180000000000000000000000) // quotient_const + mstore(add(payload, 0x13e0), 0x0000000000000000000000000000000000000000000000000000000000006000) // quotient_const + mstore(add(payload, 0x1400), 0x0000000000000000000000000000000000000000000000600000000000000000) // quotient_const + mstore(add(payload, 0x1420), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffff700000001) // quotient_const + mstore(add(payload, 0x1440), 0x73eda753299d7d483339d80809a1d80553bda402f7fe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1460), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffe001) // quotient_const + mstore(add(payload, 0x1480), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bdeffffffff00000001) // quotient_const + mstore(add(payload, 0x14a0), 0x73eda753299d7d483339d80809a1d7e355af567743ae3bbda4ffd260212ddbdb) // quotient_const + mstore(add(payload, 0x14c0), 0x73eda753299d7d483339d80809a1d7ac8bb094e10dd00bb871cf13341ce9f671) // quotient_const + mstore(add(payload, 0x14e0), 0x73eda753299d7d483339d80809a1d7b70b86399be46147106cd7aef7d718818d) // quotient_const + mstore(add(payload, 0x1500), 0x73eda753299d7d483339d80809a1d7ae5b2956bf70a17c7596cc5f626b73876b) // quotient_const + mstore(add(payload, 0x1520), 0x73eda753299d7d483339d80809a1d7b6bc3584645b26895898ae7ba60d735ad1) // quotient_const + mstore(add(payload, 0x1540), 0x73eda753299d7d483339d80809a1d7b095efed6fd9f96e39d8c5c777a6fa1179) // quotient_const + mstore(add(payload, 0x1560), 0x00000000000000000000000000000065fa2ae8a334f060c4110088dc9c766c72) // quotient_const + mstore(add(payload, 0x1580), 0x00000000000000000000000000000000000000000c0000000000000000000000) // quotient_const + mstore(add(payload, 0x15a0), 0x0000000000000000000000000000010a58272d65d68af0d3aa92c660a9421cb0) // quotient_const + mstore(add(payload, 0x15c0), 0x0000000000000000000000000000000000000000000000300000000000000000) // quotient_const + mstore(add(payload, 0x15e0), 0x000000000000000000000000000000ead8a63f3552d73ecbb978f3157ab67b5c) // quotient_const + mstore(add(payload, 0x1600), 0x000000000000000000000000000000852c1396b2eb457869d549633054a10e58) // quotient_const + mstore(add(payload, 0x1620), 0x00000000000000000000000000000104e9bce7caae169e9c3b9ae1d5bda569c2) // quotient_const + mstore(add(payload, 0x1640), 0x0000000000000000000000000000008274de73e5570b4f4e1dcd70eaded2b4e1) // quotient_const + mstore(add(payload, 0x1660), 0x000000000000000000000000000000ebc6985edbee8777f335f48d0ad7a5ef90) // quotient_const + mstore(add(payload, 0x1680), 0x0000000000000000000000000000007f1cb491dcb90764a7bad754cb0588e5cc) // quotient_const + mstore(add(payload, 0x16a0), 0x73eda753299d7d48333049095fbd120c6b5942dd2166802b5297f978232a0002) // quotient_const + mstore(add(payload, 0x16c0), 0x0000000000000000000006000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x16e0), 0x0000000600000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x1700), 0x4302515f88a4431e1fbaccbc5adc8f25703b5745de78f77d0d3fe37cf2c01c83) // quotient_const + mstore(add(payload, 0x1720), 0x140e70dbca64831b4b8f40317b68cd20f34ec27e98adf994cf555b0db316abbd) // quotient_const + mstore(add(payload, 0x1740), 0x73eda753299d7d483339d60809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1760), 0x73eda751299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1780), 0x104e71fbe05313635bd503c3e4ec6d9ff680c43f0b2c76d5fb955ed6046aa12a) // quotient_const + mstore(add(payload, 0x17a0), 0x1ff51227ca6853644d38dd4784bdae4c2024f5d6cd1acb78bae38c506ef8716c) // quotient_const + mstore(add(payload, 0x17c0), 0x70156f48f76cc14b27137d78d0b4371477819d08e9f2c77036ebc744ad6da6cb) // quotient_const + mstore(add(payload, 0x17e0), 0x37be870795549c37dcd00b9588085d0fa1ab8c1ad655e52c23ed8949f0fb5ae3) // quotient_const + mstore(add(payload, 0x1800), 0x62a9cec91e3168b1496ccfcf27ad7a8d3c8d65793936323648c2b29cb6a41ac8) // quotient_const + mstore(add(payload, 0x1820), 0x6ed3edb47fe320414c6b5a76f4cc0bce626d1a256829e20dfb44af3c3a5c88b0) // quotient_const + mstore(add(payload, 0x1840), 0x62ea7e5a34aa00528575fab42c44f48dc6c3a5a2fadad34f0a31529dec7b61e0) // quotient_const + mstore(add(payload, 0x1860), 0x6de98a7ebdd251f08ee9668a33e94c65bdb3185246bd05a64c5767be80a6f6b3) // quotient_const + mstore(add(payload, 0x1880), 0x0b88a81e969233f724730fadaac8e2d294b414ee4222bdac5b3caa2ef7b70ba2) // quotient_const + mstore(add(payload, 0x18a0), 0x0000000300000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x18c0), 0x409fb98f933d25e8d0038d4f7b2a98dbc278a3b57cfb0879943764202d0def59) // quotient_const + mstore(add(payload, 0x18e0), 0x43fe0c177a010031bf648c1cc285529323863340cc562ac9e7aaad86598b55df) // quotient_const + mstore(add(payload, 0x1900), 0x33cb899e22443dc4bd6718aaa5dd18684590bb9d54587d5a25b7e826dc13afab) // quotient_const + mstore(add(payload, 0x1920), 0x5a46b0715e6d5198819eb2abc26638708b1b23dc3e7cb23c4a1bb20f9686f7ad) // quotient_const + mstore(add(payload, 0x1940), 0x0f4d2cdbfd2f1714b46b78b33e8164a4d3f19d98c77d6dd30e31f24850ea65f3) // quotient_const + mstore(add(payload, 0x1960), 0x419d6a1793664a2e73d2a85da4119e5513d7a0cde3bde4e90718f923a87532fa) // quotient_const + mstore(add(payload, 0x1980), 0x33097aeadeda76e1094b97fb9816aa66a6edfb200f6a9a0fe16c08233a8dda63) // quotient_const + mstore(add(payload, 0x19a0), 0x09062b3ea1b0c1037678aa3cc094d16f610fd18915e201850d7ce460bf058df5) // quotient_const + mstore(add(payload, 0x19c0), 0x0456a29a706afacf2158850711006fe0acf6a437e9477bf6f782dfac86f2cf7b) // quotient_const + mstore(add(payload, 0x19e0), 0x0397cc06bc030aab970dabe70cd498bbeea8daaea65607bb6a872125fec74a10) // quotient_const + mstore(add(payload, 0x1a00), 0x73eda753299d7d4833351088b4af7508df8b737010b26e15294bfcbb91950003) // quotient_const + mstore(add(payload, 0x1a20), 0x0594e0109a0005958008060d000b0200010594a01194a01194a005950008060d) // quotient_program + mstore(add(payload, 0x1a40), 0x000b0300000594c01194c01194c005952008060d000b0300010594e01194e011) // quotient_program + mstore(add(payload, 0x1a60), 0x94e00595a008060d000b0300011b00001b000105958008109aa00594a01194a0) // quotient_program + mstore(add(payload, 0x1a80), 0x1195000d01060594c01194c01195200d02060594e01194e01195a00d03060d00) // quotient_program + mstore(add(payload, 0x1aa0), 0x0b0300011b000221020403070002000094a00594c00694e00795000895200095) // quotient_program + mstore(add(payload, 0x1ac0), 0x400595600695800995a00a95c00b95e00c96000d96200e96400f966010968011) // quotient_program + mstore(add(payload, 0x1ae0), 0x96a00796c00896e00997000a972094a00095400595600695800796c00896e009) // quotient_program + mstore(add(payload, 0x1b00), 0x97000a972094c00595400695600795800896c00996e00a970012972094e00695) // quotient_program + mstore(add(payload, 0x1b20), 0x400795600895800996c00a96e012970013972095000795400895600995800a96) // quotient_program + mstore(add(payload, 0x1b40), 0xc01296e013970014972095200895400995600a95801296c01396e01497001597) // quotient_program + mstore(add(payload, 0x1b60), 0x2095a00995400a95601295801396c01496e015970016972095c00a9540129560) // quotient_program + mstore(add(payload, 0x1b80), 0x1395801496c01596e01697001797201897401997800b04000121021a03070001) // quotient_program + mstore(add(payload, 0x1ba0), 0x000094a00594c00694e01b95001c95200095400595600695801d95a01e95c00b) // quotient_program + mstore(add(payload, 0x1bc0), 0x95e00c96000d96201f96402096602196802296a01b96c01c96e01d97001e9720) // quotient_program + mstore(add(payload, 0x1be0), 0x94a00095400595600695801b96c01c96e01d97001e972094c00595400695601b) // quotient_program + mstore(add(payload, 0x1c00), 0x95801c96c01d96e01e970023972094e00695401b95601c95801d96c01e96e023) // quotient_program + mstore(add(payload, 0x1c20), 0x970024972095001b95401c95601d95801e96c02396e024970025972095201c95) // quotient_program + mstore(add(payload, 0x1c40), 0x401d95601e95802396c02496e025970026972095a01d95401e95602395802496) // quotient_program + mstore(add(payload, 0x1c60), 0xc02596e026970027972095c01e95402395602495802596c02696e02797002897) // quotient_program + mstore(add(payload, 0x1c80), 0x202997400b0400011b000321022a01000009000995a00a95c00b95e00c96000d) // quotient_program + mstore(add(payload, 0x1ca0), 0x96200e96400f96600094a00594c00694e00795000895201096801196a0189740) // quotient_program + mstore(add(payload, 0x1cc0), 0x1997800b05000121022b01000008001d95a01e95c00b95e00c96000d96201f96) // quotient_program + mstore(add(payload, 0x1ce0), 0x402096600094a00594c00694e01b95001c95202196802296a02997400b050001) // quotient_program + mstore(add(payload, 0x1d00), 0x210397a02c0000000b2b0b94a00c94c00d94e02d95402e95602f95800b95e00c) // quotient_program + mstore(add(payload, 0x1d20), 0x96000d96203097403197600b94a095e00c94a096000d94a096200c94c095e00d) // quotient_program + mstore(add(payload, 0x1d40), 0x94c096003294c096a00d94e095e03294e096803394e096a03295009660339500) // quotient_program + mstore(add(payload, 0x1d60), 0x968034950096a032952096403395209660349520968035952096a00095409540) // quotient_program + mstore(add(payload, 0x1d80), 0x2e954095602f9540958006956095603695609720369580970037958097203295) // quotient_program + mstore(add(payload, 0x1da0), 0xa096203395a096403495a096603595a096803895a096a03295c096003395c096) // quotient_program + mstore(add(payload, 0x1dc0), 0x203495c096403595c096603895c096803995c096a03696c096e03796c097003a) // quotient_program + mstore(add(payload, 0x1de0), 0x96c097203b96e096e03a96e097003c96e097203d970097003e970097203f9720) // quotient_program + mstore(add(payload, 0x1e00), 0x97200d000b060000210397a04003080002150b94a00c94c00d94e00e95000f95) // quotient_program + mstore(add(payload, 0x1e20), 0x202d95402e95602f95801095a01195c00b95e00c96000d96200e96400f966010) // quotient_program + mstore(add(payload, 0x1e40), 0x96801196a04196c04296e043970044972094a00b95e00c96000d96200e96400f) // quotient_program + mstore(add(payload, 0x1e60), 0x96601096801196a094c00c95e00d96000e96200f96401096601196804596a094) // quotient_program + mstore(add(payload, 0x1e80), 0xe00d95e00e96000f96201096401196604596804696a095000e95e00f96001096) // quotient_program + mstore(add(payload, 0x1ea0), 0x201196404596604696804796a095200f95e01096001196204596404696604796) // quotient_program + mstore(add(payload, 0x1ec0), 0x804896a095400095402e95602f95804196c04296e043970044972095a01095e0) // quotient_program + mstore(add(payload, 0x1ee0), 0x1196004596204696404796604896804996a095c01195e0459600469620479640) // quotient_program + mstore(add(payload, 0x1f00), 0x4896604996804a96a01897401997800695609560419560958042956096c04395) // quotient_program + mstore(add(payload, 0x1f20), 0x6096e044956097004b95609720089580958043958096c044958096e04b958097) // quotient_program + mstore(add(payload, 0x1f40), 0x004c958097200a96c096c04b96c096e04c96c097004d96c097201396e096e04d) // quotient_program + mstore(add(payload, 0x1f60), 0x96e097004e96e0972015970097004f9700972017972097200d000b0600012103) // quotient_program + mstore(add(payload, 0x1f80), 0x97a05003080001150b94a00c94c00d94e01f95002095202d95402e95602f9580) // quotient_program + mstore(add(payload, 0x1fa0), 0x2195a02295c00b95e00c96000d96201f96402096602196802296a05196c05296) // quotient_program + mstore(add(payload, 0x1fc0), 0xe053970054972094a00b95e00c96000d96201f96402096602196802296a094c0) // quotient_program + mstore(add(payload, 0x1fe0), 0x0c95e00d96001f96202096402196602296805596a094e00d95e01f9600209620) // quotient_program + mstore(add(payload, 0x2000), 0x2196402296605596805696a095001f95e0209600219620229640559660569680) // quotient_program + mstore(add(payload, 0x2020), 0x5796a095202095e02196002296205596405696605796805896a095400095402e) // quotient_program + mstore(add(payload, 0x2040), 0x95602f95805196c05296e053970054972095a02195e022960055962056964057) // quotient_program + mstore(add(payload, 0x2060), 0x96605896805996a095c02295e05596005696205796405896605996805a96a029) // quotient_program + mstore(add(payload, 0x2080), 0x97400695609560519560958052956096c053956096e054956097005b95609720) // quotient_program + mstore(add(payload, 0x20a0), 0x1c9580958053958096c054958096e05b958097005c958097201e96c096c05b96) // quotient_program + mstore(add(payload, 0x20c0), 0xc096e05c96c097005d96c097202496e096e05d96e097005e96e0972026970097) // quotient_program + mstore(add(payload, 0x20e0), 0x005f9700972028972097200d000b060001210397a0600000000c390b94a00c94) // quotient_program + mstore(add(payload, 0x2100), 0xc00d94e03097403197600097a00097c00597e00698000b98a00c98c00d98e000) // quotient_program + mstore(add(payload, 0x2120), 0x954097c005954097e006954098000b954098a00c954098c00d954098e0059560) // quotient_program + mstore(add(payload, 0x2140), 0x97c006956097e061956098800c956098a00d956098c0329560996006958097c0) // quotient_program + mstore(add(payload, 0x2160), 0x61958098603b958098800d958098a0329580994033958099600095e097a00596) // quotient_program + mstore(add(payload, 0x2180), 0x0097a006962097a06196c098403b96c098606296c098803296c099203396c099) // quotient_program + mstore(add(payload, 0x21a0), 0x403496c099606196e098203b96e098406296e098603d96e098803296e0990033) // quotient_program + mstore(add(payload, 0x21c0), 0x96e099203496e099403596e0996061970098003b9700982062970098403d9700) // quotient_program + mstore(add(payload, 0x21e0), 0x9860639700988032970098e03397009900349700992035970099403897009960) // quotient_program + mstore(add(payload, 0x2200), 0x61972097e03b9720980062972098203d9720984063972098603f972098803297) // quotient_program + mstore(add(payload, 0x2220), 0x2098c033972098e034972099003597209920389720994039972099600d000b07) // quotient_program + mstore(add(payload, 0x2240), 0x0000210397a064020f000a001997800097a00097c00597e00698000798200898) // quotient_program + mstore(add(payload, 0x2260), 0x400998600a98800b98a00c98c00d98e00e99000f992097a00095e00596000696) // quotient_program + mstore(add(payload, 0x2280), 0x200796400896600996800a96a097c00095400595600695800796c00896e00997) // quotient_program + mstore(add(payload, 0x22a0), 0x000a972097e00595400695600795800896c00996e00a97001297209800069540) // quotient_program + mstore(add(payload, 0x22c0), 0x0795600895800996c00a96e012970013972098200795400895600995800a96c0) // quotient_program + mstore(add(payload, 0x22e0), 0x1296e013970014972098400895400995600a95801296c01396e0149700159720) // quotient_program + mstore(add(payload, 0x2300), 0x98600995400a95601295801396c01496e015970016972098800a954012956013) // quotient_program + mstore(add(payload, 0x2320), 0x95801496c01596e016970017972095400b98a00c98c00d98e00e99000f992010) // quotient_program + mstore(add(payload, 0x2340), 0x994011996095600c98a00d98c00e98e00f990010992011994045996095800d98) // quotient_program + mstore(add(payload, 0x2360), 0xa00e98c00f98e010990011992045994046996096c00e98a00f98c01098e01199) // quotient_program + mstore(add(payload, 0x2380), 0x0045992046994047996096e00f98a01098c01198e04599004699204799404899) // quotient_program + mstore(add(payload, 0x23a0), 0x6097001098a01198c04598e046990047992048994049996097201198a04598c0) // quotient_program + mstore(add(payload, 0x23c0), 0x4698e04799004899204999404a99600b94a00c94c00d94e00e95000f95201095) // quotient_program + mstore(add(payload, 0x23e0), 0xa01195c01897401099401199600d000b070001210397a065020f0009000097a0) // quotient_program + mstore(add(payload, 0x2400), 0x0097c00597e00698001b98201c98401d98601e98800b98a00c98c00d98e01f99) // quotient_program + mstore(add(payload, 0x2420), 0x0020992021994097a00095e00596000696201b96401c96601d96801e96a097c0) // quotient_program + mstore(add(payload, 0x2440), 0x0095400595600695801b96c01c96e01d97001e972097e00595400695601b9580) // quotient_program + mstore(add(payload, 0x2460), 0x1c96c01d96e01e970023972098000695401b95601c95801d96c01e96e0239700) // quotient_program + mstore(add(payload, 0x2480), 0x24972098201b95401c95601d95801e96c02396e024970025972098401c95401d) // quotient_program + mstore(add(payload, 0x24a0), 0x95601e95802396c02496e025970026972098601d95401e95602395802496c025) // quotient_program + mstore(add(payload, 0x24c0), 0x96e026970027972098801e95402395602495802596c02696e027970028972095) // quotient_program + mstore(add(payload, 0x24e0), 0x400b98a00c98c00d98e01f990020992021994022996095600c98a00d98c01f98) // quotient_program + mstore(add(payload, 0x2500), 0xe020990021992022994055996095800d98a01f98c02098e02199002299205599) // quotient_program + mstore(add(payload, 0x2520), 0x4056996096c01f98a02098c02198e022990055992056994057996096e02098a0) // quotient_program + mstore(add(payload, 0x2540), 0x2198c02298e055990056992057994058996097002198a02298c05598e0569900) // quotient_program + mstore(add(payload, 0x2560), 0x57992058994059996097202298a05598c05698e05799005899205999405a9960) // quotient_program + mstore(add(payload, 0x2580), 0x0b94a00c94c00d94e01f95002095202195a02295c02997402299600d000b0700) // quotient_program + mstore(add(payload, 0x25a0), 0x01210397a0660000000b2b6794a06894c06994e06a95406b95606c95806a95e0) // quotient_program + mstore(add(payload, 0x25c0), 0x6b96006c96203097403197606d94a094a06894a094c06994a094e06e94c094c0) // quotient_program + mstore(add(payload, 0x25e0), 0x6f94c095c06f94e095a07094e095c06f9500952070950095a071950095c07295) // quotient_program + mstore(add(payload, 0x2600), 0x20952071952095a073952095c06a954095e06b954096006c954096206b956095) // quotient_program + mstore(add(payload, 0x2620), 0xe06c9560960074956096a06c958095e0749580968075958096a07695a095a077) // quotient_program + mstore(add(payload, 0x2640), 0x95a095c07895c095c074960097207496209700759620972074964096e0759640) // quotient_program + mstore(add(payload, 0x2660), 0x9700799640972074966096c075966096e079966097007a9660972075968096c0) // quotient_program + mstore(add(payload, 0x2680), 0x79968096e07a968097007b968097207996a096c07a96a096e07b96a097007c96) // quotient_program + mstore(add(payload, 0x26a0), 0xa097200d000b080000210397a07d03080002156794a06894c06994e07e95007f) // quotient_program + mstore(add(payload, 0x26c0), 0x95206a95406b95606c95808095a08195c06a95e06b96006c9620829640839660) // quotient_program + mstore(add(payload, 0x26e0), 0x8496808596a08296c08396e084970085972094a06d94a06894c06994e07e9500) // quotient_program + mstore(add(payload, 0x2700), 0x7f95208095a08195c095406a95e06b96006c96208296408396608496808596a0) // quotient_program + mstore(add(payload, 0x2720), 0x95606b95e06c96008296208396408496608596808696a095806c95e082960083) // quotient_program + mstore(add(payload, 0x2740), 0x96208496408596608696808796a096c08295e083960084962085964086966087) // quotient_program + mstore(add(payload, 0x2760), 0x96808896a096e08395e08496008596208696408796608896808996a097008495) // quotient_program + mstore(add(payload, 0x2780), 0xe08596008696208796408896608996808a96a097208595e08696008796208896) // quotient_program + mstore(add(payload, 0x27a0), 0x408996608a96808b96a01897401997806e94c094c07e94c094e07f94c0950080) // quotient_program + mstore(add(payload, 0x27c0), 0x94c095208194c095a08c94c095c08d94e094e08094e095008194e095208c94e0) // quotient_program + mstore(add(payload, 0x27e0), 0x95a08e94e095c08f950095008c950095208e950095a090950095c09195209520) // quotient_program + mstore(add(payload, 0x2800), 0x90952095a092952095c09395a095a09495a095c09595c095c00d000b08000121) // quotient_program + mstore(add(payload, 0x2820), 0x0397a09603080001156794a06894c06994e09795009895206a95406b95606c95) // quotient_program + mstore(add(payload, 0x2840), 0x809995a09a95c06a95e06b96006c96209b96409c96609d96809e96a09b96c09c) // quotient_program + mstore(add(payload, 0x2860), 0x96e09d97009e972094a06d94a06894c06994e09795009895209995a09a95c095) // quotient_program + mstore(add(payload, 0x2880), 0x406a95e06b96006c96209b96409c96609d96809e96a095606b95e06c96009b96) // quotient_program + mstore(add(payload, 0x28a0), 0x209c96409d96609e96809f96a095806c95e09b96009c96209d96409e96609f96) // quotient_program + mstore(add(payload, 0x28c0), 0x80a096a096c09b95e09c96009d96209e96409f9660a09680a196a096e09c95e0) // quotient_program + mstore(add(payload, 0x28e0), 0x9d96009e96209f9640a09660a19680a296a097009d95e09e96009f9620a09640) // quotient_program + mstore(add(payload, 0x2900), 0xa19660a29680a396a097209e95e09f9600a09620a19640a29660a39680a496a0) // quotient_program + mstore(add(payload, 0x2920), 0x2997406e94c094c09794c094e09894c095009994c095209a94c095a0a594c095) // quotient_program + mstore(add(payload, 0x2940), 0xc0a694e094e09994e095009a94e09520a594e095a0a794e095c0a895009500a5) // quotient_program + mstore(add(payload, 0x2960), 0x95009520a7950095a0a9950095c0aa95209520a9952095a0ab952095c0ac95a0) // quotient_program + mstore(add(payload, 0x2980), 0x95a0ad95a095c0ae95c095c00d000b080001210397a0af0000000e100094a005) // quotient_program + mstore(add(payload, 0x29a0), 0x94c00694e06a95406b95606c95800095e00596000696203097403197600097c0) // quotient_program + mstore(add(payload, 0x29c0), 0x0597e00698000b954095406b954095606c954095800d95609560749560972074) // quotient_program + mstore(add(payload, 0x29e0), 0x9580970075958097207496c096e07596c097007996c097203396e096e07996e0) // quotient_program + mstore(add(payload, 0x2a00), 0x97007a96e0972035970097007b9700972039972097200d000b090000210397a0) // quotient_program + mstore(add(payload, 0x2a20), 0xb004010002150094a00594c00694e00795000895206a95406b95606c95800995) // quotient_program + mstore(add(payload, 0x2a40), 0xa00a95c00095e00596000696200796400896600996800a96a08296c08396e084) // quotient_program + mstore(add(payload, 0x2a60), 0x97008597200097c00597e00698000798200898400998600a988095400b95406b) // quotient_program + mstore(add(payload, 0x2a80), 0x95606c95808296c08396e08497008597201897401997800d9560956082956095) // quotient_program + mstore(add(payload, 0x2aa0), 0x8083956096c084956096e0859560970086956097200f9580958084958096c085) // quotient_program + mstore(add(payload, 0x2ac0), 0x958096e0869580970087958097201196c096c08696c096e08796c097008896c0) // quotient_program + mstore(add(payload, 0x2ae0), 0x97204696e096e08896e097008996e0972048970097008a970097204a97209720) // quotient_program + mstore(add(payload, 0x2b00), 0x0d000b090001210397a0b104010001150094a00594c00694e01b95001c95206a) // quotient_program + mstore(add(payload, 0x2b20), 0x95406b95606c95801d95a01e95c00095e00596000696201b96401c96601d9680) // quotient_program + mstore(add(payload, 0x2b40), 0x1e96a09b96c09c96e09d97009e97200097c00597e00698001b98201c98401d98) // quotient_program + mstore(add(payload, 0x2b60), 0x601e988095400b95406b95606c95809b96c09c96e09d97009e97202997400d95) // quotient_program + mstore(add(payload, 0x2b80), 0x6095609b956095809c956096c09d956096e09e956097009f9560972020958095) // quotient_program + mstore(add(payload, 0x2ba0), 0x809d958096c09e958096e09f95809700a0958097202296c096c09f96c096e0a0) // quotient_program + mstore(add(payload, 0x2bc0), 0x96c09700a196c097205696e096e0a196e09700a296e097205897009700a39700) // quotient_program + mstore(add(payload, 0x2be0), 0x97205a972097200d000b090001191f0000000000000000000000000000000000) // quotient_program + // Fixed-column commitment 0, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2c00), 0x00000000000000000000000000000000055f7961345dce7ce57401dd993cc81a) // fixed_comms[0].x_hi + mstore(add(payload, 0x2c20), 0xb4a8bb072416d10d143dbceefaa489acea245ef19b9b96fef5bf433eb3a11715) // fixed_comms[0].x_lo + mstore(add(payload, 0x2c40), 0x00000000000000000000000000000000123e8a257be057ec25558c37e4b17ce9) // fixed_comms[0].y_hi + mstore(add(payload, 0x2c60), 0x8e3b8e47d06f0961e4194860938f70e8f8f29e6c09dc697cb5c3486879220eaf) // fixed_comms[0].y_lo + // Fixed-column commitment 1, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2c80), 0x000000000000000000000000000000000dc17ef381e9c195813396905a4c7619) // fixed_comms[1].x_hi + mstore(add(payload, 0x2ca0), 0x326e62da20d14e245cf995ae353e85749ad599d8859cdf7ff0996b64ad724553) // fixed_comms[1].x_lo + mstore(add(payload, 0x2cc0), 0x0000000000000000000000000000000004af0ea1ccdc1cd0a2a638aa09f6e2ae) // fixed_comms[1].y_hi + mstore(add(payload, 0x2ce0), 0xe2fe34ad7bd96fb709c73d2d9705c120c1c78c8702fc136bcecb58a6efc4353d) // fixed_comms[1].y_lo + // Fixed-column commitment 2, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2d00), 0x0000000000000000000000000000000018da87ffd53a1cdfc243a1f594c7db5f) // fixed_comms[2].x_hi + mstore(add(payload, 0x2d20), 0x6a20adfd78c0e9d2dd4a3377189dcaf31f886eecc6bcfd19d7263ff57b36c01e) // fixed_comms[2].x_lo + mstore(add(payload, 0x2d40), 0x0000000000000000000000000000000001921c576e8a2684cc7521fbf6ec96c3) // fixed_comms[2].y_hi + mstore(add(payload, 0x2d60), 0xde86625c4429546e64909b0f415e9b7bcff50f6e96df84f795a6bf7c3fd0e085) // fixed_comms[2].y_lo + // Fixed-column commitment 3, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2d80), 0x000000000000000000000000000000001390c4b48f0af2e2a9332b1851fbb5d1) // fixed_comms[3].x_hi + mstore(add(payload, 0x2da0), 0xe13c168e64b12da23a13fb7b449e2f8d38dd385220d9a9cc7af8c1cb5d7e7364) // fixed_comms[3].x_lo + mstore(add(payload, 0x2dc0), 0x0000000000000000000000000000000019b9ac80c33724396a9da36abc8884bc) // fixed_comms[3].y_hi + mstore(add(payload, 0x2de0), 0x9adb1d0bf586080efd6ffd8520aab78d8d205c0a11726db029aecc899111d9a9) // fixed_comms[3].y_lo + // Fixed-column commitment 4, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2e00), 0x0000000000000000000000000000000015bc72a82a34331b999a01881b5c4b3b) // fixed_comms[4].x_hi + mstore(add(payload, 0x2e20), 0xb138f213ddd19ae669c32f961811a4164e6eec8fac46a36f5a4e04870f11a3d1) // fixed_comms[4].x_lo + mstore(add(payload, 0x2e40), 0x00000000000000000000000000000000197b5b9237d51d93dc155332b6330653) // fixed_comms[4].y_hi + mstore(add(payload, 0x2e60), 0xef5fa3e86ca7b8acaf6cb32697d8ececfbdac8b2ffe2f53e47bdc8ba9e3993b6) // fixed_comms[4].y_lo + // Fixed-column commitment 5, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2e80), 0x0000000000000000000000000000000013eb9d933b5284bfef6caf1f9e08ca59) // fixed_comms[5].x_hi + mstore(add(payload, 0x2ea0), 0x283ea2dbd92fc9a748e3761fff443680718b50347a55be560c0229972f7e0a24) // fixed_comms[5].x_lo + mstore(add(payload, 0x2ec0), 0x000000000000000000000000000000001100235c0764123ef1a72a76e2abc95c) // fixed_comms[5].y_hi + mstore(add(payload, 0x2ee0), 0x8af88c99dda9239bf71fca4d07b5fee527d576ad79c679035b5836347686d74b) // fixed_comms[5].y_lo + // Fixed-column commitment 6, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2f00), 0x000000000000000000000000000000000563bb1e4b8d6ac080403aa94fe32b7d) // fixed_comms[6].x_hi + mstore(add(payload, 0x2f20), 0xe1921a07b4a8ade8f03fbf6079d44191250a74ad822758d3f3c76ac1dcf34844) // fixed_comms[6].x_lo + mstore(add(payload, 0x2f40), 0x000000000000000000000000000000001660e1d7dc487ef2074c1cbcc53f96c4) // fixed_comms[6].y_hi + mstore(add(payload, 0x2f60), 0x90a10debafc892aa61fc1f5deccbe9e504f860b20ab154069fc7d9db6abd4b8c) // fixed_comms[6].y_lo + // Fixed-column commitment 7, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2f80), 0x0000000000000000000000000000000011d8086a3a74772d6977655ec27ea545) // fixed_comms[7].x_hi + mstore(add(payload, 0x2fa0), 0xb8f93c43434e29d5987c92a14aff1f1eaaf7301c5a7e3089af5e92d1f848d0ca) // fixed_comms[7].x_lo + mstore(add(payload, 0x2fc0), 0x0000000000000000000000000000000005dad0d11cdc8ea706cfc3def7d4b133) // fixed_comms[7].y_hi + mstore(add(payload, 0x2fe0), 0xc3589649c58c36b9396e7ba08d2dcce7e9ffc79c05293e88ffdcd779031bd430) // fixed_comms[7].y_lo + // Fixed-column commitment 8, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3000), 0x000000000000000000000000000000000c93bd7351261d64a616e0136a9d422b) // fixed_comms[8].x_hi + mstore(add(payload, 0x3020), 0xb749e19c58376c59582349ad89c4cd137403a5708d9c57caa9aa60a61ebac5eb) // fixed_comms[8].x_lo + mstore(add(payload, 0x3040), 0x000000000000000000000000000000000cbfb4f76cc2e2dd1cb5c3d5102d3b9a) // fixed_comms[8].y_hi + mstore(add(payload, 0x3060), 0xd4a9cd56cbcb6df99c181927f6448f16319d629b8e456d7c82888b8ebff6605c) // fixed_comms[8].y_lo + // Fixed-column commitment 9, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3080), 0x0000000000000000000000000000000008727a8cb32cb038513549fb17b3ba8d) // fixed_comms[9].x_hi + mstore(add(payload, 0x30a0), 0xd9695316ca607544e71a5430e6910b8fee65f6ad1a50f524c684c5e957c1c73e) // fixed_comms[9].x_lo + mstore(add(payload, 0x30c0), 0x000000000000000000000000000000000108a6377aea32a5e3bbce056526f625) // fixed_comms[9].y_hi + mstore(add(payload, 0x30e0), 0x33a146b087d572d2cdda900fca8baea1863367075e4b606110b6325be4397d52) // fixed_comms[9].y_lo + // Fixed-column commitment 10, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3100), 0x0000000000000000000000000000000004757ce24e0add6ba492d720099e2fbd) // fixed_comms[10].x_hi + mstore(add(payload, 0x3120), 0xc54defd9e931ec5af33e4a92ad1867c2f4d790e30268a97b42e74f65d1d26feb) // fixed_comms[10].x_lo + mstore(add(payload, 0x3140), 0x0000000000000000000000000000000010f63d4681250b4d2f91725c42a7993b) // fixed_comms[10].y_hi + mstore(add(payload, 0x3160), 0xaa140dc9f52cc57f62aa46386e696d66b92a24406de6a8dfb053ebf589cd908b) // fixed_comms[10].y_lo + // Fixed-column commitment 11, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3180), 0x00000000000000000000000000000000085b6410030ecdc020942851047cf237) // fixed_comms[11].x_hi + mstore(add(payload, 0x31a0), 0x9c9c9bb218540241434381109f505f21842aadb79e1290bf15d09779052c830e) // fixed_comms[11].x_lo + mstore(add(payload, 0x31c0), 0x0000000000000000000000000000000001662c17e52c0576a1daf532fd9b5d44) // fixed_comms[11].y_hi + mstore(add(payload, 0x31e0), 0xa3b693810486d8cc2b3231928889a5901b11f8de1ea0a8d7da54719bb1bacb39) // fixed_comms[11].y_lo + // Fixed-column commitment 12, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3200), 0x000000000000000000000000000000001842a8cec63398e3cd72495091717037) // fixed_comms[12].x_hi + mstore(add(payload, 0x3220), 0xed2687fe07e288a66dbddadb866eab042e668795097a24350329af3a2faa15e8) // fixed_comms[12].x_lo + mstore(add(payload, 0x3240), 0x000000000000000000000000000000000cee59973fde1d885353d9f171f17c99) // fixed_comms[12].y_hi + mstore(add(payload, 0x3260), 0xfd88d67302f6cec5cbcd7d8430f17485f2bbaa4a092e725824499b3fc0cf01bd) // fixed_comms[12].y_lo + // Fixed-column commitment 13, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3280), 0x0000000000000000000000000000000019d8a32c4ce7586146ff1ba0ac184d1e) // fixed_comms[13].x_hi + mstore(add(payload, 0x32a0), 0x8263acc4da9e972d5b111879f60990df5070a38e99c93a8e9f52e94ffc5e889e) // fixed_comms[13].x_lo + mstore(add(payload, 0x32c0), 0x00000000000000000000000000000000027e571331ef494a3859d52330b48271) // fixed_comms[13].y_hi + mstore(add(payload, 0x32e0), 0x9386739b55372fd11694634dc2fe32fc5ed8a01fbe87cdbbcfacb4aed4903fc3) // fixed_comms[13].y_lo + // Fixed-column commitment 14, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3300), 0x00000000000000000000000000000000017d226d304f23f7f52ffe5adadcaca9) // fixed_comms[14].x_hi + mstore(add(payload, 0x3320), 0x54a9d37b66adcd661144899193c80d6d365b30bd133f0bd5a60c12da38b4685e) // fixed_comms[14].x_lo + mstore(add(payload, 0x3340), 0x000000000000000000000000000000000f485636ff7bd4a83beb91de87df7ed4) // fixed_comms[14].y_hi + mstore(add(payload, 0x3360), 0x4757ccb9b4c2999112e89a82d9c72579b1d0020cdda10f3e0b41bf57aec34686) // fixed_comms[14].y_lo + // Fixed-column commitment 15, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3380), 0x0000000000000000000000000000000000000000000000000000000000000000) // fixed_comms[15].x_hi + mstore(add(payload, 0x33a0), 0x0000000000000000000000000000000000000000000000000000000000000000) // fixed_comms[15].x_lo + mstore(add(payload, 0x33c0), 0x0000000000000000000000000000000000000000000000000000000000000000) // fixed_comms[15].y_hi + mstore(add(payload, 0x33e0), 0x0000000000000000000000000000000000000000000000000000000000000000) // fixed_comms[15].y_lo + // Fixed-column commitment 16, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3400), 0x0000000000000000000000000000000008fd1060bd58dfc0e828393d62e3aee0) // fixed_comms[16].x_hi + mstore(add(payload, 0x3420), 0xfe8983d71d04414402f77df4de23f2a73b3c5c48ee85fa51fcd64a3027e0167b) // fixed_comms[16].x_lo + mstore(add(payload, 0x3440), 0x000000000000000000000000000000001024eab25af80d874e553df0f690d9e3) // fixed_comms[16].y_hi + mstore(add(payload, 0x3460), 0x634a41f5518caaaeee1dbc993ced1264ade8431a680d202247d83eb8ef1ed620) // fixed_comms[16].y_lo + // Fixed-column commitment 17, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3480), 0x000000000000000000000000000000000b877a879e46bc947071a221c60797d8) // fixed_comms[17].x_hi + mstore(add(payload, 0x34a0), 0x0d338c66213b76689a66c79be8734280510aa45f8c79ce0eaaba3d7f2c201c99) // fixed_comms[17].x_lo + mstore(add(payload, 0x34c0), 0x000000000000000000000000000000000ffcad707a79c0b29c100d2ab1b60935) // fixed_comms[17].y_hi + mstore(add(payload, 0x34e0), 0x2a2c605009875c39b73bb6d3e2216b305369028923566fc6ef2d22c8b74ce2bf) // fixed_comms[17].y_lo + // Fixed-column commitment 18, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3500), 0x000000000000000000000000000000000d0d0b7c841523297c824431ffca522d) // fixed_comms[18].x_hi + mstore(add(payload, 0x3520), 0xb24daa6cbd8c5f783501a4681bf7367e7aa5d71fca25234cd1a8f31ff24b9871) // fixed_comms[18].x_lo + mstore(add(payload, 0x3540), 0x000000000000000000000000000000001396209d456313b44ec6d4a2fe5f434f) // fixed_comms[18].y_hi + mstore(add(payload, 0x3560), 0xd5bd61218a04eaee084c376ade74d9bceba17fb9e12c2341581e5279596d7c97) // fixed_comms[18].y_lo + // Fixed-column commitment 19, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3580), 0x00000000000000000000000000000000136cd0a2afc84eaecd680d24627d704f) // fixed_comms[19].x_hi + mstore(add(payload, 0x35a0), 0x7e67e5d7fa3094f1aac03b8600277d394817f19fd0b0810dd2087b359429bf11) // fixed_comms[19].x_lo + mstore(add(payload, 0x35c0), 0x0000000000000000000000000000000015cedd2e0ff3e776d58981915174cb65) // fixed_comms[19].y_hi + mstore(add(payload, 0x35e0), 0x13bbf7d0f959d6be24d858ac4ae78c6b9ba0c80d69183a84cd73ec4e47693a14) // fixed_comms[19].y_lo + // Fixed-column commitment 20, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3600), 0x0000000000000000000000000000000010e71146f473749481916e34fff2ba4a) // fixed_comms[20].x_hi + mstore(add(payload, 0x3620), 0xd3e26bb933c011913f506f7892a36f43f7ba4f88b3f1c632e707bbffede7feb9) // fixed_comms[20].x_lo + mstore(add(payload, 0x3640), 0x000000000000000000000000000000000982bd3e7a5ba58d468d0835936ad925) // fixed_comms[20].y_hi + mstore(add(payload, 0x3660), 0xa3d7160336e586296b5e3742251d002e79d8d8d409bf94bafd09719f3ff0b382) // fixed_comms[20].y_lo + // Fixed-column commitment 21, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3680), 0x00000000000000000000000000000000141c94b0741a3d6471b0dd59b3420d9e) // fixed_comms[21].x_hi + mstore(add(payload, 0x36a0), 0xa03be602a9ebe7f1567966db7e3ace5a14ae393194015380293d1d995596651c) // fixed_comms[21].x_lo + mstore(add(payload, 0x36c0), 0x000000000000000000000000000000000185758fd177d9c06fad9502b24ca417) // fixed_comms[21].y_hi + mstore(add(payload, 0x36e0), 0x9cbb2dd41d7ede5248fb78316c557683f183c083b731a261a7381d45cf930742) // fixed_comms[21].y_lo + // Fixed-column commitment 22, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3700), 0x0000000000000000000000000000000001e93db65a35232bfd9581766d6c5c59) // fixed_comms[22].x_hi + mstore(add(payload, 0x3720), 0xa90a6d1906f94fc5643024253805f7a17b6fc2428bbe864add9dd8124518153c) // fixed_comms[22].x_lo + mstore(add(payload, 0x3740), 0x000000000000000000000000000000001897a8f562cb20282c670eecf5f77249) // fixed_comms[22].y_hi + mstore(add(payload, 0x3760), 0x4df0f2823207b6a3832a1b0d7987b20827e8416b563efbbfe212f510acf289df) // fixed_comms[22].y_lo + // Fixed-column commitment 23, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3780), 0x000000000000000000000000000000001141339a865a8fc5477605fae30566b9) // fixed_comms[23].x_hi + mstore(add(payload, 0x37a0), 0x7bd7c27d8d218efa4eb28c80916844e8ec5d47c7dc2f871545707f004b7bde50) // fixed_comms[23].x_lo + mstore(add(payload, 0x37c0), 0x000000000000000000000000000000000a728fcbfa5a7a5bfae84b4ab18b83e6) // fixed_comms[23].y_hi + mstore(add(payload, 0x37e0), 0xb10f17f88be257afb9d981d6516cfd2c4b3e89f5fa5ca13434fd95b24bc0f5c1) // fixed_comms[23].y_lo + // Fixed-column commitment 24, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3800), 0x0000000000000000000000000000000002a788024d9035e7e40f601bb8082ff8) // fixed_comms[24].x_hi + mstore(add(payload, 0x3820), 0x53ec39d899cd245ad2ee9ad32549a184d0c5cb4d4d99940a1cda52c4aa50f79d) // fixed_comms[24].x_lo + mstore(add(payload, 0x3840), 0x0000000000000000000000000000000019a91d8fc2a4d3db45f22db05108197e) // fixed_comms[24].y_hi + mstore(add(payload, 0x3860), 0x7eac8129c7add70a75761fd1e18fa2f40ea6e687a3f43b41995a2e74bf31ff24) // fixed_comms[24].y_lo + // Fixed-column commitment 25, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3880), 0x0000000000000000000000000000000001442c60b19c670229debddb76233f20) // fixed_comms[25].x_hi + mstore(add(payload, 0x38a0), 0x6a6627da0dc462833c112cdb1784e1f5f8a9aec196cf07b4442d408dbdc8de34) // fixed_comms[25].x_lo + mstore(add(payload, 0x38c0), 0x0000000000000000000000000000000013f3b855645d02a97df448668efd5d7f) // fixed_comms[25].y_hi + mstore(add(payload, 0x38e0), 0x8d52d302c0337d44e292fff6ae85d5a6dc5a59067e2a4f0925f48080dc521d40) // fixed_comms[25].y_lo + // Fixed-column commitment 26, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3900), 0x00000000000000000000000000000000190429c7a977675dbb8d96b442fe3eb0) // fixed_comms[26].x_hi + mstore(add(payload, 0x3920), 0xb466636ed724932185b8820e3f115e95ce19cde31f721358e32beda77fa44c98) // fixed_comms[26].x_lo + mstore(add(payload, 0x3940), 0x00000000000000000000000000000000058d18d63ff3a3abf337b6edc6a7709a) // fixed_comms[26].y_hi + mstore(add(payload, 0x3960), 0x36a019565bfbe01076597121c5484c2f3c63a301ed971058d75bb5d61b50bf05) // fixed_comms[26].y_lo + // Permutation commitment 0, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3980), 0x00000000000000000000000000000000120ea7ffaddae135109dc68a0169e39e) // permutation_comms[0].x_hi + mstore(add(payload, 0x39a0), 0x17f95865ea6411611a36d6ee8affde13b3120990c5feff3a2dc32b1b71606512) // permutation_comms[0].x_lo + mstore(add(payload, 0x39c0), 0x000000000000000000000000000000000d8604c2a5312ba81e5c56ad904e3fd3) // permutation_comms[0].y_hi + mstore(add(payload, 0x39e0), 0xc73a292e67febcd994e3d882c050e50940bcd0364b49eaf0ea8c838123757e51) // permutation_comms[0].y_lo + // Permutation commitment 1, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3a00), 0x0000000000000000000000000000000012baec9d926370da0174d2da9125909f) // permutation_comms[1].x_hi + mstore(add(payload, 0x3a20), 0x51c030289c7267c9173faacb20c43e027ba889a257fc9da7685fe92a1d8e1159) // permutation_comms[1].x_lo + mstore(add(payload, 0x3a40), 0x00000000000000000000000000000000151c6bdabf6387e09e4ab927a972d0a5) // permutation_comms[1].y_hi + mstore(add(payload, 0x3a60), 0x93e74bf9513d1d9be31b2d8828eb248d8b76fd529ee3d3343629b1327f47b74c) // permutation_comms[1].y_lo + // Permutation commitment 2, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3a80), 0x000000000000000000000000000000000502f4f83331ce4fe3b1e618b27af0d4) // permutation_comms[2].x_hi + mstore(add(payload, 0x3aa0), 0xed1c9014937f4e0c989f42c2a22d0d54e395b1e6d35830f1681e7f7633bd5e48) // permutation_comms[2].x_lo + mstore(add(payload, 0x3ac0), 0x00000000000000000000000000000000158fff4ecfaf728c449c4f9955fe87b1) // permutation_comms[2].y_hi + mstore(add(payload, 0x3ae0), 0x8938d2b58f9f4325ad6c56ef82526e5d6bedff11dd4ef4730c55430e7ecc12b7) // permutation_comms[2].y_lo + // Permutation commitment 3, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3b00), 0x00000000000000000000000000000000157dbf7d9e1605bb29df570e4e4165d2) // permutation_comms[3].x_hi + mstore(add(payload, 0x3b20), 0xe3af202d72afd27c2516ad10f0ef973f33dddb0fb0e34df741b4385b713cd1a8) // permutation_comms[3].x_lo + mstore(add(payload, 0x3b40), 0x000000000000000000000000000000001227de928658870ba5ecaeae8dc6272e) // permutation_comms[3].y_hi + mstore(add(payload, 0x3b60), 0x3c0f65f9d0e0daf9bcae0c8d2f61f4dfe5603cd4f9c2efe24c8bb68df6091f8b) // permutation_comms[3].y_lo + // Permutation commitment 4, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3b80), 0x00000000000000000000000000000000095679f4757e1699305ce877a6cede75) // permutation_comms[4].x_hi + mstore(add(payload, 0x3ba0), 0xa7e634400e785e5c802142e6df51aa4b9d707d525cf7a80209699c36020b7971) // permutation_comms[4].x_lo + mstore(add(payload, 0x3bc0), 0x00000000000000000000000000000000044f9e79c7622ffb279d558f84e0e7ec) // permutation_comms[4].y_hi + mstore(add(payload, 0x3be0), 0x8355f52668f5832af0d5f80a018da5d9cf622b4ad414ef10eaad16f94ddc8def) // permutation_comms[4].y_lo + // Permutation commitment 5, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3c00), 0x000000000000000000000000000000000dc0d3a9a27cacb14bf99d6c879fc0f2) // permutation_comms[5].x_hi + mstore(add(payload, 0x3c20), 0x92f80d3f8becaa901863aa7ca5b046bbe0f61b5da880eb4b1bb5b40ecf735d54) // permutation_comms[5].x_lo + mstore(add(payload, 0x3c40), 0x00000000000000000000000000000000077a8a36b30f3ba3d444bc0427088640) // permutation_comms[5].y_hi + mstore(add(payload, 0x3c60), 0x8840d2e5d575557d7495f63d40abf4b7daa04fc2bd662f6e299fc27aca5de4c5) // permutation_comms[5].y_lo + // Permutation commitment 6, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3c80), 0x0000000000000000000000000000000000986f7215a9b5e4bc69608acaeb755c) // permutation_comms[6].x_hi + mstore(add(payload, 0x3ca0), 0xc0ed4dd7bd88976da07e9c47756f1c9b90ef494c5cc3031ac6c9b5570fe5c45d) // permutation_comms[6].x_lo + mstore(add(payload, 0x3cc0), 0x0000000000000000000000000000000003658180fe0ac3ab217301cc34d2f9aa) // permutation_comms[6].y_hi + mstore(add(payload, 0x3ce0), 0x04b19a3be7154ad43d1737fd1668783a7069648dfb24de83a6b13d7261001032) // permutation_comms[6].y_lo + // Permutation commitment 7, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3d00), 0x0000000000000000000000000000000001a53f321f3bf6d20af84c660efc018e) // permutation_comms[7].x_hi + mstore(add(payload, 0x3d20), 0xa56fe987917489d477e3f2ac4da73c5a1e032748de091337870f0d5405473cd7) // permutation_comms[7].x_lo + mstore(add(payload, 0x3d40), 0x000000000000000000000000000000000cc1da20073f989dd769a6d1003df07d) // permutation_comms[7].y_hi + mstore(add(payload, 0x3d60), 0x5f354c49e670c02fcd04d732bf1dcf1ea91bf6fda6ccaf7b3884498827925ad7) // permutation_comms[7].y_lo + // Permutation commitment 8, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3d80), 0x0000000000000000000000000000000006416291ebc77017412205eb4523f2c4) // permutation_comms[8].x_hi + mstore(add(payload, 0x3da0), 0xfd559ac96201738085b756438d69e28d22d12d42527f26d4d076768379361baf) // permutation_comms[8].x_lo + mstore(add(payload, 0x3dc0), 0x000000000000000000000000000000000d7c5e9e2123f1a9259e09115e8bcbde) // permutation_comms[8].y_hi + mstore(add(payload, 0x3de0), 0x993cb20b6226d0b408d9ba2ea78f60939c10a918d0b706c0069e74ba1eeb7587) // permutation_comms[8].y_lo + // Permutation commitment 9, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3e00), 0x00000000000000000000000000000000155b9dd46792d67982688c923afe6f78) // permutation_comms[9].x_hi + mstore(add(payload, 0x3e20), 0xf0a9671faf2fbd90216a37854e9cc8f38a4e4e2edfbec79eabb17473cb14233a) // permutation_comms[9].x_lo + mstore(add(payload, 0x3e40), 0x000000000000000000000000000000001136f0b77aaf0d619c1ab6b1f0dcee68) // permutation_comms[9].y_hi + mstore(add(payload, 0x3e60), 0x5a362fa96be37353acf9f0ad8061c2da4ea54d0a983b25c140fff64eb5814a43) // permutation_comms[9].y_lo + // Permutation commitment 10, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3e80), 0x00000000000000000000000000000000190c34b5f99861f6dfcdde40fbfd95d0) // permutation_comms[10].x_hi + mstore(add(payload, 0x3ea0), 0x95a6bd47b58b054fe90452e3b358cd4dba6dd76fa6d5877d1ad1a6dc5f2c2ad7) // permutation_comms[10].x_lo + mstore(add(payload, 0x3ec0), 0x00000000000000000000000000000000025a2fa63f92a2b0012325d053fb4dd7) // permutation_comms[10].y_hi + mstore(add(payload, 0x3ee0), 0xeea7e8f98e3d57f1d404d8c6266072c77e1bf610f1b2d7e66a24c4eb5c7fa858) // permutation_comms[10].y_lo + // Permutation commitment 11, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3f00), 0x0000000000000000000000000000000006dba7402f78627c2b84e3f197be1ff9) // permutation_comms[11].x_hi + mstore(add(payload, 0x3f20), 0xe3b778c0de9938ede71f40c70a82c4b21e7f7e17f5ae37d8f431d8c56cb0cb7d) // permutation_comms[11].x_lo + mstore(add(payload, 0x3f40), 0x0000000000000000000000000000000002f707f86413969433104530051e0e7f) // permutation_comms[11].y_hi + mstore(add(payload, 0x3f60), 0xef774edc804973bdd3807446ef32363e657593d67b0460a33e76fc23d9feb998) // permutation_comms[11].y_lo + // Permutation commitment 12, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3f80), 0x00000000000000000000000000000000116f8891da6e5ddfca44225df76baa02) // permutation_comms[12].x_hi + mstore(add(payload, 0x3fa0), 0x795f3f817116f937e2102b4196eb86112a0d3290a6811fa1e7ada37bdcd91129) // permutation_comms[12].x_lo + mstore(add(payload, 0x3fc0), 0x0000000000000000000000000000000012b7e92df964086ecd115e6b47daad77) // permutation_comms[12].y_hi + mstore(add(payload, 0x3fe0), 0xcf396451a41cf55fa02fe68aaea4416953ad112a6608797bcc1f4a06ec6a786f) // permutation_comms[12].y_lo + // Permutation commitment 13, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4000), 0x000000000000000000000000000000000c92a9011db64f5f7857340d5ecc0e76) // permutation_comms[13].x_hi + mstore(add(payload, 0x4020), 0x6d6a2f4362053c3253503813a1a4167c6848cdbae2c90b104fc2a05290a24f78) // permutation_comms[13].x_lo + mstore(add(payload, 0x4040), 0x00000000000000000000000000000000143212478a1a01c12e08520644d09291) // permutation_comms[13].y_hi + mstore(add(payload, 0x4060), 0x4b417957d5c80179f30c06b68b329aa111de3f613cc66c70fd4841ec26139999) // permutation_comms[13].y_lo + // Permutation commitment 14, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4080), 0x000000000000000000000000000000000a03f34520ffafc5b6a3f90f70e4e373) // permutation_comms[14].x_hi + mstore(add(payload, 0x40a0), 0x673b3105b9864666ae11b398378b0648279065fc693c5edc4d42da133102545c) // permutation_comms[14].x_lo + mstore(add(payload, 0x40c0), 0x00000000000000000000000000000000073205a58fda6d5adfd59e82867a548c) // permutation_comms[14].y_hi + mstore(add(payload, 0x40e0), 0x80b028b16770d9a79d949f623d043d9aeff1cac440bd1482d1c898d7fc7bbbce) // permutation_comms[14].y_lo + // Permutation commitment 15, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4100), 0x0000000000000000000000000000000008f70210c58006a3cb8b927287fa0bfb) // permutation_comms[15].x_hi + mstore(add(payload, 0x4120), 0x55da954a29534ecb479d764e8ca977440dee39b3d09ebbe6b3fbb9c5b92cfe8b) // permutation_comms[15].x_lo + mstore(add(payload, 0x4140), 0x0000000000000000000000000000000007285c63d0eadb56452c598285dfaa89) // permutation_comms[15].y_hi + mstore(add(payload, 0x4160), 0x7d569c04ddbe85aa5deb978df472a328eb6db26586db41278f2cddeee55568cf) // permutation_comms[15].y_lo + // Permutation commitment 16, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4180), 0x0000000000000000000000000000000019e4494289915c32cc82722cdf9cd7f2) // permutation_comms[16].x_hi + mstore(add(payload, 0x41a0), 0xdc0187db7a50b887b1b5b2003c62effcf00f99c2a920ec56cfee0462655ac108) // permutation_comms[16].x_lo + mstore(add(payload, 0x41c0), 0x000000000000000000000000000000001933cb285d7f70cc217fdf83c792d776) // permutation_comms[16].y_hi + mstore(add(payload, 0x41e0), 0x527c8109795e8922038ac6a98e67c92d0fcb6e3a700e7ec2c0fa98cc1df52702) // permutation_comms[16].y_lo + // Permutation commitment 17, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4200), 0x000000000000000000000000000000000485fd87bac44c42dc3c80fd042cc7d0) // permutation_comms[17].x_hi + mstore(add(payload, 0x4220), 0xbb99316753b744e151e09c7f07e670300181f2f8e79a8b37c9828ac6be7a9573) // permutation_comms[17].x_lo + mstore(add(payload, 0x4240), 0x000000000000000000000000000000000fd370bb45717fa6282230adcff6e4b6) // permutation_comms[17].y_hi + mstore(add(payload, 0x4260), 0xab0ead4db625a61209a55551a96a3b5618f2996e645f09bbfda12ca3881536ac) // permutation_comms[17].y_lo + + // Return exactly the INVALID prefix plus the generated payload. The + // linked verifier pins this byte length and the resulting codehash. + return(runtime, 0x4281) + } + } +} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md new file mode 100644 index 000000000..350fbe00f --- /dev/null +++ b/proofs/solidity-verifier/fixtures/ivc/README.md @@ -0,0 +1,48 @@ +# IVC Public-Accumulator Replay Fixture + +Pre-rendered artifacts for `tests/ivc_accumulator_replay.rs`, which replays a +real IVC final proof and then mutates the accumulator public inputs to check the +decoder in `templates/partials/verifier/AccumulatorHelpers.yul` rejects them. + +These are *rendered* contracts plus matching calldata rather than a verifying +key and proof, so the replay needs only solc and revm -- no SRS, no proving run, +and no `midnight-aggregation`. A verifier cannot be rendered from a VK without +the full SRS, because `SolidityGenerator` consumes `params.g_lagrange()`; that +is what makes a vk.bin-based replay unusable in CI. + +## Provenance + +| Field | Value | +| --- | --- | +| Source commit | `f5b7466` | +| Rendered by | `tests/ivc_keccak_solidity.rs` (`ivc_final_keccak_solidity_e2e`) | +| Circuit | IVC k=19 leaves, k=20 decider | +| Accumulator | `AccumulatorEncoding::new(offset=4, num_limbs=7, num_limb_bits=56)` | +| Verified on-chain | yes, 1,285,274 gas under revm Prague | + +## Regenerating + +Requires `midnight-srs-2p19` and `midnight-srs-2p20` in `SRS_DIR` +(~300 MB, from ): + +```bash +HALO2_SOLIDITY_RUN_IVC_BENCH=1 \ + SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ + cargo test --release \ + --features evm,truncated-challenges,in-circuit-fewer-point-sets \ + --test ivc_keccak_solidity -- --nocapture + +cp target/ivc-keccak-solidity-dump/{Halo2Verifier.sol,Halo2VerifyingKey.sol,\ +Halo2QuotientEvaluator.sol,calldata.bin} fixtures/ivc/ +``` + +Then update the source commit above. + +## Staleness + +This is a snapshot of the codegen that produced it. The artifacts are +self-consistent, so the replay keeps passing after a codegen change -- it just +stops exercising current output. Detecting that automatically would mean +re-rendering, which needs the SRS again, so it is tracked by the commit stamp +above rather than by an assertion. Regenerate after changes to the accumulator +templates or the memory layout. diff --git a/proofs/solidity-verifier/fixtures/ivc/calldata.bin b/proofs/solidity-verifier/fixtures/ivc/calldata.bin new file mode 100644 index 0000000000000000000000000000000000000000..9aed1ca8961ee78ba7fde25b9914805108918db6 GIT binary patch literal 8356 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 S-r{X~M&0oI&-}kB!~Z|Q2_ESH literal 0 HcmV?d00001 diff --git a/proofs/solidity-verifier/fixtures/ivc/instance.bin b/proofs/solidity-verifier/fixtures/ivc/instance.bin deleted file mode 100644 index 9247d55a50fd0ab415307885a5f1bc9985cc2e75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3528 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 Qv#xewZ=xlnO_ciXKNgEPzyJUM diff --git a/proofs/solidity-verifier/fixtures/ivc/proof.bin b/proofs/solidity-verifier/fixtures/ivc/proof.bin deleted file mode 100644 index 910bd9d65092fc823312c99eca1732f391ffb29a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9824 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 G&vsxZbJ7z4 diff --git a/proofs/solidity-verifier/fixtures/ivc/rust_trace.json b/proofs/solidity-verifier/fixtures/ivc/rust_trace.json deleted file mode 100644 index 3f5fe0189..000000000 --- a/proofs/solidity-verifier/fixtures/ivc/rust_trace.json +++ /dev/null @@ -1,1068 +0,0 @@ -{ - "entries": [ - { - "kind": "Intermediate", - "data": { - "tag": "vk_repr", - "fe_be_hex": "51a3ad301c5292dcc208abbe14bae00feebc636408a4b2c54d5edd07ffc492a2" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[0]", - "eip2537_hex": "9324a75f7803c2fb7be84f8f8f92397fc38f438472414438972d85137fa1e884f7fde28c1f4b1d3555b721915e60a4d7" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[1]", - "eip2537_hex": "afabdc807327c5de8fc13495028900d83ac62f2a9533b780582fdd18bd68e5e20287c861c82923e6576330099dec584b" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[2]", - "eip2537_hex": "ab042a4727ee1f333d73706db25bd1f229cb608765128af1b9377b3e2b4795e85503deb7f086fdb781a3c4d190205a40" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[3]", - "eip2537_hex": "986d652bf616055fcb845f79e496bb94a6dcdc7e332a53d2c1d2370a637b0d2a4f2636551e681cf1eb70c561defa62c7" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[4]", - "eip2537_hex": "a24481617df262dbd06b5fddf658f9c32e49c6403bff43252ea10fb35c37d987af93346ecee6db2b794f8ea6b2b60286" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[5]", - "eip2537_hex": "955ddbc47fea8bf6280024d6b455ebb60462d79a19f49187443bcdcec9b16a84f41f41367805521eb89f876c13cc2880" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[6]", - "eip2537_hex": "872ba4345eb8cc6bc2fca678eae0455ed17ceca164901368a453b3826fde369e8cf63db2a87b14fc54073a369ccabfe2" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[7]", - "eip2537_hex": "8e14088f20db449b8f49695c3c84d8d873faedfdde1ebbe87c39c81765d149380c313b4242278b752177fd7b661d0554" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[8]", - "eip2537_hex": "b5e8f709e287c8a92bcfae306d20a15034f8f04e0cd8dee49059feaec3e99e002d4268f36f613598b68b55cc3b6ffaf6" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[9]", - "eip2537_hex": "93c8f3366eb85800f928116e3a177bb36a5baa5b698e70afc838e2e9eac2b35a5a0895da21f21f86b4dd5833447118ac" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[10]", - "eip2537_hex": "a23d93bcefea6c36837e348911ea299e8f478c5097f803c74c9aa0752a09c812749102e3a3321193452d710a95ed97fa" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[11]", - "eip2537_hex": "8c509b6d23069f785cdcac3319040d8b5dd155bac5e4a3b815891e6a571dedf99a2d46b4670dfdaa7c89cf43fc4f7df9" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[12]", - "eip2537_hex": "b642bfcd07db3fb367d968a923c87f6c0db808f812cd9014a01f36d8b1a33b20de6409ebd7db009104cdf07ce9ddd872" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[13]", - "eip2537_hex": "8980d60b9cfe2b6d5327ced4400e8ac611d292991c0abd3a2c7e692ff63b866ebf4c1a54f15c38603e60ec9247578c24" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "advice[14]", - "eip2537_hex": "b946984d70cd450a0f9def10b8f8694e58f74b5cfc521963170307df92baa7e8237fe25d9fe81c0421d909ad0f5a6b76" - } - }, - { - "kind": "Challenge", - "data": { - "name": "theta", - "fe_be_hex": "3ff9db99be64b81421248a42da80d4cd7ba4aa6bb94e8ca2dc7c04b5feaabccf" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_mult", - "eip2537_hex": "883447beb33d2cd632274e5745542ba9f827e3de62e2218a3139751cb8997abcbd90a1ca2dd9be5f6c861b06c2c9ebbc" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_mult", - "eip2537_hex": "a06266251c32ea2ac0f43fb5dcee056bb7e8002fd9ea8480c384085f1e788e542965d48ab07e31d0140987c4b566eca4" - } - }, - { - "kind": "Challenge", - "data": { - "name": "beta", - "fe_be_hex": "5e1004307780e019454167777748c63f1ceb0bfd8137c218f46a29d9fcd8997b" - } - }, - { - "kind": "Challenge", - "data": { - "name": "gamma", - "fe_be_hex": "0058d4bedb482ef6ec68cc4102d79d26a3e68c67a660554306766a08d0b4bae4" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "b992ef1d42c2f3db9b82a33465d87623c31772480224aceaa7bf46ab89cca003b1973ef7cb161a373cb00d968286aafd" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "b124921f1914ac76be4886f24155f31c4ec67e4bfd34b400eb9d1a282310d7c4e7577f80297f48c5e46e17247c9cc03c" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "9215d3b97960403604292c0e49b5560bda50f7de776039dd4792ddf1afcf4485e4036d4c6f3d84c6a730805f433432c8" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "89d2652251e8c6df970de2fc4b5090d192110de217fb3da3b11db3886c472d7b9d4f9b4eac8f599e90071394dc7efe0e" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "86302bed0abdb7528321e4170aaef2962c67c8926908dc990923971736f90f2173ea372b7110afe8d9e393cb73da0677" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "perm_product", - "eip2537_hex": "b36a8b2ee086077c3673c953aa45c68f947735789e2c386fe2c7bc768251bff3eea2ac6681d1ba9dbf24a774ffb41662" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_helper", - "eip2537_hex": "88451ae997148f4b0b042066e35fd50c3a39a24507945b0ea61d3a5557d39e45f01740cc16d469f688730cda358e55fa" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_acc", - "eip2537_hex": "b14d249dd6b8c44b4007503b116d26e684be9ff9d1e76c66b9a0182f4d4a5998bb0bbea3c807f2294543b0651afaaede" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_helper", - "eip2537_hex": "a2d3ee8eea5e7e755b69bb79d8fc18ca688ff7487afb894c3077ab6c68cb8d7151e96009cc5bea912ad2fcca23c63f26" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "lookup_acc", - "eip2537_hex": "84189193c82ea16ce40c6c3a7670c782d9ef22343531180d8f15aef0e3ac7714c6b4d2c3eb58485630260e95a094e50d" - } - }, - { - "kind": "Challenge", - "data": { - "name": "trash_challenge", - "fe_be_hex": "0de9348372df1d1e7432fcb24ef5ecbf1358ae5dbe88097c7df40bfcb8d7889d" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "trashcan", - "eip2537_hex": "a846009a66f994210618221e9d4c3b7dd2830290c5a316a1befb1cb3fa2fc5ef84b679e5e5766914673284cbf6a1f3f8" - } - }, - { - "kind": "Challenge", - "data": { - "name": "y", - "fe_be_hex": "717b58f00b4d3d2793757513329c2c1d50deb5b93956dfd2048548a4d7837d9f" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "quotient_limb", - "eip2537_hex": "b4a018c05d3d9fa4b36bf3f2ae2feca08a658412829a26fe41aec4134158fba7739358e125cea1a5914f72cf9b525e72" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "quotient_limb", - "eip2537_hex": "815a896114a233d654689dafd891428d126e7e620e30dee5a5f1c0d9ceabc0581fa23b37dbd0b7775aeabd9fccb1d3b1" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "quotient_limb", - "eip2537_hex": "b6b9678337e622f2d663b2293748d82b7102ac83213590b5813c5099481fa123f81cf582d5f7b4e81dd3ce024d79097d" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "quotient_limb", - "eip2537_hex": "a2c5f0060ffd5c4f8741b884ee6834a04366739fecb2bbef7f27b8e2d08065b4e979ede81b398a1ac6cad46664035ead" - } - }, - { - "kind": "Challenge", - "data": { - "name": "x", - "fe_be_hex": "25a95a70b527cd00441e66fc7716f297fce60d998bcc0158e816488a393e408c" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "committed_instance_eval", - "fe_be_hex": "0000000000000000000000000000000000000000000000000000000000000000" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[0]", - "fe_be_hex": "2aff2f04fce943e11f15b05b610d1006f7276184a3eb52764a9b162ef19b774b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[1]", - "fe_be_hex": "613ce970681657d1997019c85dd9e468b607ebeb81c81bf5b3e373afcf25e417" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[2]", - "fe_be_hex": "5ad602afd794d4ba4fa04d59b442983c446b7a1924f36a1c869b6fc2718f1b33" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[3]", - "fe_be_hex": "1b19d3101f528b398c5636f9af64ceb203941f5a69906344f6018dcdd93ec9f8" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[4]", - "fe_be_hex": "63f62d35bef1451fe363e8ae48f478aa78d3775c1df49470ed9b08acc8a582f1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[5]", - "fe_be_hex": "6120b59c0ef4b1422d808ba3bf08c4319da59fe04f3ed69e30cca0e30438fc02" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[6]", - "fe_be_hex": "04924d8799758ac570dbce5be1bccde9de9b44f64ba93506721bc8fd9b0bbaed" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[7]", - "fe_be_hex": "2cb4f7a76de56ef73523af97075a0498d7789853d23aad7fc12c7b7f7092a018" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[8]", - "fe_be_hex": "62b0bdacb806ca168215731c666c8d1b3d35241023674f4e8866119719dbfc3f" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[9]", - "fe_be_hex": "5d9ea3fb49590e6dbc8a42f662741fec9a7322411f948f8d3f54bd70191a6f3b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[10]", - "fe_be_hex": "28c0c553847c9c7c586fa0c979a308b2d4c0c87e3c7061d200f7aef29776f159" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[11]", - "fe_be_hex": "48a364fdc95646a925fe21aaf84ed1fc70e97483af6ce14452c251c4fd20ab8c" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[12]", - "fe_be_hex": "4e4e184924e843a78524088430f840c2734476144dd5adf53bb35071bb7b2d0e" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[13]", - "fe_be_hex": "1061413a5fd1787a3f0d54dad842be30a6097a89c52db89360ecd2bbdc98dca9" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[14]", - "fe_be_hex": "64da1115a5c5107dc2aa9304d6dc5b3d83195eb097c28fc05cd57a218fbef7c9" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[15]", - "fe_be_hex": "33ffd290974cedb43eb4e5e4cf9ae0a8c6b1c45b45654b5e960ab34df74efb2a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[16]", - "fe_be_hex": "5cfeb68e3f0b568eadbc559b3466c6d236161a3c8a040c0b4514b8145ce79238" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[17]", - "fe_be_hex": "18e676097fd27a394eecbfc4fc9e77b93bcec22fa31c8cb5df47148a24d61f5a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[18]", - "fe_be_hex": "188899add7daab3c574a1ea69dc2462b98f4784965414b67fe968533a5046841" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[19]", - "fe_be_hex": "678d9102966f8980e4ab679b0e8d89062a8a4b4287350de27b073897526af3d3" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[20]", - "fe_be_hex": "2c69fff1c50460ad0cb18d96216a250fdca786373030ea394cf3e08493085c3b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[21]", - "fe_be_hex": "69e0c4daf6c37e6c659ee977e0f911703782d74a535f30c757b45b83fc865da6" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[22]", - "fe_be_hex": "728344ed27b3ebaa17612c3ffb57a14efb120656258b47fa20c25ee225ef2171" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[23]", - "fe_be_hex": "4806c4286bf892869328dc209bc46314b2759765bdcbcb99744fa0f348545a75" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[24]", - "fe_be_hex": "0af784a7a802b57c08ffaea2b29653005cac85e3332f5cee2b754ab02b5e0bb3" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[25]", - "fe_be_hex": "15d0be507d1046854082c0ae8b1d4ff812a5b0f2899cccfb3d7877f355d5b83b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[26]", - "fe_be_hex": "27f5830c86931649356219918d1fe8ed97eb4600aa3e46b4b173778d7671d50c" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[27]", - "fe_be_hex": "6e3f6903d3dc1e0e195f673938a9edfdd6dd456dcdcd560ad4d9dbfaf85f39cc" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[28]", - "fe_be_hex": "22ca4cfa850bf7487c8d7eb1cf2ec2c86a633768d9b9e2f16919b0830d3fb844" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[29]", - "fe_be_hex": "5a9e3590a4f9be93687d68104c9b6cb2cc9ed410fc07d6162dbc9f64decd7ce1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[30]", - "fe_be_hex": "4b7d002e918dddcd4be4f0623d8f9c0a9533b24af17e5dc634df24e500729dba" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[31]", - "fe_be_hex": "5d3073c3a96253693c8df7ce25e52b38b8c78afd7950a60e21cda35c3e48b78b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[32]", - "fe_be_hex": "2f1400afb1e213b69d45580bf9a0054f90e54c4dfaf340510358368d7eb037fc" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[33]", - "fe_be_hex": "54f6ff91933cf536ecfe439e01b2103b02aff564ad64cc03322803101fba3812" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[34]", - "fe_be_hex": "6bc15393109fc72220322b2e100a293d9b4d7f43828783f18f226701900cb91c" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[35]", - "fe_be_hex": "1071a9bbef3816d70ebf4b92b9755e176e2a8558a3bbb3d16ebe2570ffb34f1b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[36]", - "fe_be_hex": "700c1d9c6e073b01b5c81986fb4df82a1ec87043972046372890ca3c7b5b0928" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[37]", - "fe_be_hex": "64a7cee5b982c3b7eecc70e2a7a96e53be8effb11d1040c9a73a9ebf334b1194" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[38]", - "fe_be_hex": "0175ebff5c51ed1bc0b0ac14b7193dafdf64b1c2cec0c23de2e781fa8394362e" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "advice_eval[39]", - "fe_be_hex": "6955a4c86380c065bd0c80036c3ab85fbdb52dcced432ecd68c48d9a1b274509" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[0]", - "fe_be_hex": "094662684cbadaf67132f94dfe2511cc8aee0f2519f2540b17314664295d2d49" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[1]", - "fe_be_hex": "6249297a890a17fbc31920e6f5b33e284b17b738d945b93af9ac63581f39e926" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[2]", - "fe_be_hex": "533aa4f8f4c2d59ee7d3ef836d846c08608c2c2a0f9322f6f6b269284401b569" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[3]", - "fe_be_hex": "0a7069537b5283f647e1a5fb4510e338d37915aadcab9cee9ac42474f027159e" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[4]", - "fe_be_hex": "036721bd95b1adffb069c6f37846d0949a2541fddded7dbef574c926ea067125" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[5]", - "fe_be_hex": "151dd83de8726f4907cad27fe7c01b6a38b780c9e36a92f2b14b334c6d43d323" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[6]", - "fe_be_hex": "0d8f561572fb44d01ce808d9b57f3dea1151b1c70af6170efd615597953aab90" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[7]", - "fe_be_hex": "388498775fc06d0cede26ab654db23b72fd6d2c693ee2fcebb0c3c8943544618" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[8]", - "fe_be_hex": "3f4cd7d8912aa56d301ccaabfff5b239f7d0b375dc7e59e70ac83d1df74cea7f" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[9]", - "fe_be_hex": "0d28bbe4bb3217c71d9f55cf4e629b6fcbb9cbaf3db566064f6c14d650c3518b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[10]", - "fe_be_hex": "6ee5a51f25ab89cecb00e84084a45fc4f644603406662d4ee5e8f8c93ab72c8e" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[11]", - "fe_be_hex": "6aabae683a739b717d4284d4ce090ca897bf16439d18a537381223febcacf0d1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[12]", - "fe_be_hex": "734189390c0049b73dd5622affb5e10138229f67c4fa0f70f3acc7ac5492da03" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[13]", - "fe_be_hex": "1be1180e1778d1802e467100378415b572888ae535042e01cb3539dd1059352f" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[14]", - "fe_be_hex": "5a8998c3bdc57c8c6bb4b209ce16f2e401655f094e065e08a1b42d14091d6c1b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[15]", - "fe_be_hex": "497165498e6280b15e3e3b2b3bb1be8fafb4880013a2860237039c2872fb5a1d" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "fixed_eval[16]", - "fe_be_hex": "3969731b9c485b627553a8d5c91fee63f06759560d441480d36ab2144c382294" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[0]", - "fe_be_hex": "17e99dd0f4b34d2795f0c82eed3b8081bb499b675d2ef634a8b2b399adf374c3" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[1]", - "fe_be_hex": "434e96f8f1801a73f63d1faf599d28f3c7c9eaa3112979564c2a59a955dd3cd2" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[2]", - "fe_be_hex": "6b5e6841b8101eaa53ccb8eefb7fa79e95275028679301c335ff66f216f41b93" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[3]", - "fe_be_hex": "43752a03cf17d3d0d64777af9a39d283e7859eaac4a2da400baf3af7359a127c" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[4]", - "fe_be_hex": "4ee605378c3ccaf4e48e82fa9f5c6ef2c9bd3a44f482ef00cb170f7901cc2b8b" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[5]", - "fe_be_hex": "0fc1c5e02cfbf5d9115b7137074f6f0f6f294d7777c54d75f5b7c6cca84c03f1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[6]", - "fe_be_hex": "5492e7d49f48fdb68ab634eaf30059712aa662ac23bc8d7bb269afee222f3d93" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[7]", - "fe_be_hex": "09ede7d5f304404ce3602f10ac6c48423349268c98a5e7512c42a85e54a4a8b5" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[8]", - "fe_be_hex": "25bae27aa445934670e7660234eb483b0855de75f8e0e5c25a8859d5b5f1697a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[9]", - "fe_be_hex": "10a09e888fe4fa67cc79bcce1fb2965b6e166238799d9772d47a07b947236493" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[10]", - "fe_be_hex": "22b7aea68284a218fc8a1c85c16f2674c1f9b76494e29be3d5d1d25879b2bfe4" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[11]", - "fe_be_hex": "421d73a8c0aaf6b421264b6ac308d0ba2dd267d3f3134b006b8e440d08e2a0cd" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[12]", - "fe_be_hex": "2fcb6e506ea4f6d5a73ff93256c62ef6c08ce5cb4dfa0834f80fcebabbcd98c0" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[13]", - "fe_be_hex": "2a8865c0d658cdc019c2bad26c10b388ab8138c474013d2618a4a7a9fd78a151" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[14]", - "fe_be_hex": "256e955fd4aca98fc22078c6b2ddfa4535dde657f14193bc91a10e81c6ac8637" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[15]", - "fe_be_hex": "3b36739c2dab05e8731283b6a33ae8a8f899a4dce36067d38876c5603e6d4dfa" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[16]", - "fe_be_hex": "71de8b575f2b8d2f97d31a3877fcaec1603135e3648dc8fa91ed9a159dc72026" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_common[17]", - "fe_be_hex": "2693d914e4ec4b414043dd7cd62baad35ef74a798d63641cbb89b9adaa44b2e5" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "6f5d99221a6baa6fdd4a86dccdaecda185b900e389abb4aebe6a78dae9986dd6" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "09e25e6e94f2d464bc6dfbdb00dec371465c9e63b351f030faa16f2fc9089729" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_last", - "fe_be_hex": "6d7e57bcc8a142e541bd48302d7d5f09ced322a30f7f46f5ebd3f068934ff3c5" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "09e6e9d001c1722bef8caaa1defa9016313d4ad09c6ab2a025c873fdf217a88a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "3c4fadc803f4d688529db1ab405f4b7c87d62b8312d06b82580e09f83509eaf8" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_last", - "fe_be_hex": "35a66b9743844178d52f221e577f21da84afa99357bd796ab5ea58a44000abaa" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "0a1d4b022e51379ad4fb5e3dd2ef2d85782787f64cdc57b69e4eefdea908c5be" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "04411e7377b1c6c426bfc47ff792dc95b65276cb44d3e3742944dadd2356ecd7" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_last", - "fe_be_hex": "3a8947962b0f02550c0eb3ca374c7dad62e6a93f6beac0b717f0ecd53ddc08db" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "530b29213aa759519d799bcfced039200fdc999b52b0a3a805fe5f17a87ec4f1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "610e49e355e2d7b519059f2a05cee82ba7af81ccc8521c00c05a299b43afad72" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_last", - "fe_be_hex": "4c4ae9b7ff00533557189e0d7e3d92968a22b735511793c9b1cfd24ddb481426" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "360e366879475eaf65c181ee1ec4f7cb7505e72c2cbbf909ba9501657943c7e6" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "6793d5eb4cab328ec774e8790d4fa5f7e2eb2fcb326aaad5da8d7902bfbb0cbb" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_last", - "fe_be_hex": "61bef43e11955c61a073955b26c7a5100c70f40cbc557d72efd31d37de08eb99" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_cur", - "fe_be_hex": "4f8352e3683141c181c8b3f2c36fb3c87d307f2ce83460476b2abc3e00e367ba" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "perm_next", - "fe_be_hex": "6a3393d0a58d7eff8d70efe2ca1651abea2810066637f38d47d3fe505e6a66b1" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_m_eval", - "fe_be_hex": "5db5037d269fe3b3163aee34efa1700b945b64eea07a169e05c1beec055879b3" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_helper_eval", - "fe_be_hex": "739afd93c5d8099da5c1a1a38c3b931c0b9d78ad5ac1b0cc8a5a02fd0b9b8290" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_acc_eval", - "fe_be_hex": "3c654f49671abd7b7d5e4a2dc444a8b59ba8be9a5422bfc776344bcda00f2575" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_acc_next_eval", - "fe_be_hex": "5c73faba39c84ccb0f0a9be5f7afad39553d992f22d65e43370137f7f1748ea8" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_m_eval", - "fe_be_hex": "37b288ce777b7ad710ca063faeca1c7e830994011132bee36592dab105910e30" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_helper_eval", - "fe_be_hex": "0b10469cb107cf10a1323b9a3488bcb5070d70e57cec1012a0d832cea8f50d5a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_acc_eval", - "fe_be_hex": "1f5f07b0f2b3157e0b593ffe0cd4c03602ebba3bce94a97d1416c12c0c04cb13" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "lookup_acc_next_eval", - "fe_be_hex": "19aea3331455c4d6a7d7e0396441b078d62d74d9b13021572a4bd8f9ac98353d" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "trash_eval", - "fe_be_hex": "2c5b5194dadc6558b5486ac297257d2f731ab83bf4a6de7f1adb44611ad985be" - } - }, - { - "kind": "Challenge", - "data": { - "name": "x1", - "fe_be_hex": "13f8c24186a7be1a397c7b2859ff227b2d0920d32d545885da542bbed0ae254f" - } - }, - { - "kind": "Challenge", - "data": { - "name": "x2", - "fe_be_hex": "29175d62cd5f3b273588fab38705600a7614b67768c291d31130891f1199a011" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "f_com", - "eip2537_hex": "a6812bc568c0e0aa3aafc20385685e504c2f36778180e78ca44ab76a64b6be3b77c87f80da055bbd519aba9d5122e459" - } - }, - { - "kind": "Challenge", - "data": { - "name": "x3", - "fe_be_hex": "58a0feaa98295060f65934374141b1b8720018a665345b485d2fc89de8704cde" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "q_eval", - "fe_be_hex": "15874d911e497a01d83006b38e4b7fd697d1cbc335f9119f085739db694a5a85" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "q_eval", - "fe_be_hex": "34d56361507e3fe5e2faf8f8289d4fb0b5a83072b4fe6b898b1fab754381561d" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "q_eval", - "fe_be_hex": "4928e1876a849e1c27ee7536482186bf9359d26c1d347cde0fcf83aa529f147a" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "q_eval", - "fe_be_hex": "48ac5842c24471f2d12739e9db0f841e972ee94549e5a16531e6b0972273c8a2" - } - }, - { - "kind": "ReadScalar", - "data": { - "tag": "q_eval", - "fe_be_hex": "4ec3466b72d2b0ea1ab18978b23d2da7d01b8b040443598bbe13c6b04d404983" - } - }, - { - "kind": "Challenge", - "data": { - "name": "x4", - "fe_be_hex": "0406be097ef26b66a1727792c8300aca3e81715664c38d1284b4d40ea47edc67" - } - }, - { - "kind": "ReadPoint", - "data": { - "tag": "pi", - "eip2537_hex": "a9f4920b7a8364d6c85cfc71346be70f46dd9ecd7fd527f2593c83cb55359ae395f091c8c26289f663cbcc7bc945b923" - } - } - ] -} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/ivc/solidity_trace.json b/proofs/solidity-verifier/fixtures/ivc/solidity_trace.json deleted file mode 100644 index 287b943bc..000000000 --- a/proofs/solidity-verifier/fixtures/ivc/solidity_trace.json +++ /dev/null @@ -1 +0,0 @@ -[{"kind":"ReadPoint","tag":"advice","eip2537_hex":"b5a3ed19b468966d517a4246fc2d3dffeff693cfae260ebca3c20570b03d90bb67818f1f29fc5eed276dd931d0a8f744"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"81725d4f826bd4e1b2d44973a7cafaa3ef68635e81b756986e1e7e9c5aa88dee5b132e5675c53cabc1a6650d4f7724b5"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"8405678eca7b3899fe8a5151c2f120af233db43316370079b635b0a1b586a11f88640a51e8fbc3b828a9c5761aa247e8"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"a94e856a5ce18ebd3ac321a8e927365411113a2c94c5e318351aea31e2927b998ed7aa69f7ab94eacfec259a90944f4a"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"9927ed8349c0e9a120abd70a94b2be16d801db78a48ebf1b8e832c12bad6b1439d2449a232fb7834c9ee802a9c17b99a"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"87f25afb4c569da357338c5a8d6f6f8f9a70d3ee4c4c76112ce557120a6c6675e7a050cf6e31a3bf9810ceb691fb5939"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"a901dbf17bda36068a654324f80bbb5cb662cb3b6b6c8de00c092be6d339f7089b92885504c313ce6942de14bb465b5c"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"895a3b7f738bb1df304e5dbe3d3f053598e3eb2e421980ad161aabc942edefac85393611ec42fd40d0374bbf924f405e"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"9662fc7620753324b71ae06218c1b5e8089bb31839463665723d8fbe7a2ad245e5133c774bdf716041751bd486235a32"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"8024ab67e2e9b10695f9d9de724f8150fbe2ae651c15270b46ea58edab90cd9458f2384ba9d3b5fab6645dcda696a95b"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"940bca31980207633c105e4723789eb5f4127c41f6325b855daf2cf3180eeab52b72f734549b72b57f0a27f787a5ca07"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"8cfa3c33b295c80d24437052ff753e93461752b8ab0170a48208d445658e53f6fb76bba84de7344233644bb68650a7d8"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"a7390d9b294df6d8c18c35c3ea28883c1c4cd48fbc12e8d82928d1e2dc340cd64defac67dca106a37967fab7fa8d3cb0"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"acc0d4d4feab2c840d1eecde2bc9f96bc6d2cda78ff298ec6716da118151cf598938b6c9346d8037a02b2e241dd1a3f6"},{"kind":"ReadPoint","tag":"advice","eip2537_hex":"8af8bc94ee0178b5f139926856976d0253940d5cb5391b39b9b4cf2c06f3ba7289bd798230be9a834976ae152441886b"},{"kind":"Challenge","tag":"theta","fe_be_hex":"27e8037bbfbfd47ffd3c2ce862e3acf6b81a0a6619471248726ed6576227807f"},{"kind":"ReadPoint","tag":"lookup_mult","eip2537_hex":"8309bd912ca8cf399279d7dbc8f453e873317ebcbc5e510acb13e62904711a628ff30b61dbbf04f66ef56f464056c3f4"},{"kind":"ReadPoint","tag":"lookup_mult","eip2537_hex":"873b6c597af9d183834ecbb4ba28a741e5a76ca027e14dccb5018f7cb527c07bceae9bfbab353f064720b0df70515ff5"},{"kind":"Challenge","tag":"beta","fe_be_hex":"12bc4f0d2f0d0c27bdaf7b29adc5b364ef4eb3550618960d1e6e7699f4b71760"},{"kind":"Challenge","tag":"gamma","fe_be_hex":"32539d02a7dc77ccee137a40521fe9a0adca56d16214e383a1458d03ea2ddd15"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"868f44698ed2b1174d655ade22a1bcabde75534c1af29d4c646df25add46d276e58066d8ffc6d7a7221c93669959d1fe"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"a734a580452233277b40065adb5f3145c701f870e3f8a07cf401ac04ca5787e44b551f11f521813b76db5ab41ce56b83"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"84da1d462aee0e1f8e2b08ceea88ac0b7f60842a6ecd97428bafa652e50b722f646dcc6d5a3b41ad5a5ead0178a9775e"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"88677162fef7cc540a46813c82a43da84b476a8726e6e376faaabe15d30e379aa0a902b5c962cfcad26f0b6b7046df38"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"94ade48a9857fdd229d84e556f6e483c512cdd54dd550503686b8317d6d99fee43f79390e91b5ebd303cf0c6bf32f06a"},{"kind":"ReadPoint","tag":"perm_product","eip2537_hex":"adda51a9ad06282aeaf8d1f2d5e7e7ffdbc3e89f0748db870157cf2ba3de8053d731c204001c8063a3b4e18e0981adb0"},{"kind":"ReadPoint","tag":"lookup","eip2537_hex":"906be3c46e0499a65febbc526c0af1d4c7f0d630af1f76ff05f3da874adfa98f83d8a9d048a94b06bccd71f1d8370e22"},{"kind":"ReadPoint","tag":"lookup","eip2537_hex":"a963d0a8790cec1acad417d575f03d18963b97d0b8699fde81074471ab5ff84b6b2435e4de358646f2f8cbedd20781b9"},{"kind":"ReadPoint","tag":"lookup","eip2537_hex":"8d562aa58c17eb6a5bead6f10b62ca93dde62817d7b1c8d37d60ebc7699f07bdd4c1df103a6308381b6ce1ef62758956"},{"kind":"ReadPoint","tag":"lookup","eip2537_hex":"82aee8ae26dfa6e8cd888e145c7a221fc4b4179bfc7aadccfd173129b1ae29c28f8f8cfd0b68e00142592aaae2697662"},{"kind":"Challenge","tag":"trash_challenge","fe_be_hex":"1f4aa81eea4602bcd9a4d8c413c83d27a205f49d074b3e58d25d8202feae2b60"},{"kind":"ReadPoint","tag":"trashcan","eip2537_hex":"ac938f8075047aec1fa27b4a958db254a15380ba93ec93b19f5cf8a8be1d4078e74b1b1a0a70d907f5ce640816ff1d15"},{"kind":"Challenge","tag":"y","fe_be_hex":"4b77a617a03318cfb24402ba260a8d4b6bb38e03827db22b36d6196840061025"},{"kind":"ReadPoint","tag":"quotient_limb","eip2537_hex":"ad70a4fd9070cbb6a2dd9a302486e2158fcb67de21eb59cee8603396e869f34c7dc3eb5bdfe3cb6a99629ee6524662d0"},{"kind":"ReadPoint","tag":"quotient_limb","eip2537_hex":"a71a43c4506df681ca8112d94d5f57cdeee6c1be7c875f0cfac40e8291bb52dbb147c0655b7c15aef823e5778f764ae7"},{"kind":"ReadPoint","tag":"quotient_limb","eip2537_hex":"b1fe3bf128c226686b753e4bae0a9f7633e3ff0d3905e0dd90e926578fd1d9bfc270e4faec8ea370827f85283fb5231f"},{"kind":"ReadPoint","tag":"quotient_limb","eip2537_hex":"af288e6aba3df8ac49d2320b0d2d8e1bbf9665922e962bf2047178ba018bd55b6c6494c59f6e55db80cef009dd2ecae3"},{"kind":"Challenge","tag":"x","fe_be_hex":"480c85d8d1c587dac3891e48a29ade9ecf1674679a0b808e8d2cb5bb3491f2ea"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"09ef5b8920d5d73deec7f3a353ac34262031dbd8f12384123a56b0444384a71b"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"5492a2956c450bac44d8590d6d8802e03f4951161e6b8b638a70f02fa6f8679e"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"201b58816342ae2f3b644148e9df8dba8e4df21d31e77e57d14c192830856d0a"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"3e8973b8bec854146133131923f26a622f86d10f3729e5a033972672d2ba18aa"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"08476b87f42a92ea6faee7430cf19849167bee80d0903e2b94ff68d20d067e16"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"4a5f88276bae0a6dc5737b3acc98ef978311a886979287c51213f09e50700dbc"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"4ddbb2b1a19d17740886685096269f5cfeedecbb4f842b69e18da0667676652c"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"64b29d580131ef7df38067302827572041f0284568335e3a06a9a73b736e2acc"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"2cff007180182c6e10eb772a9093d7b2f42a77e82888711d3e74bd370b605d03"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"0eb888285a964a03a607bcfdd1ba5ad71072b5e96901bace474d434cbeb1c35a"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"1d1f55b5e070b508ff54a51106ad265408ba62256d10f0aeaed5dc756e33bf51"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"0843b40b6701ff67871c911b0bb6768586ba9c034200dea8eff3dc70bc130b66"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"3f9f6a7efb75d7c4571bc4154df2fa8c95e1df48ac1a1e3b32f0f3920d14bb16"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"19242199f60bd966b08275c90466ac422e5945d0ec08b26fb6178369d6b32abb"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"5be8a576c4e42c8e6698aa6424296843af9218bc4d67105d6c77e792fb936cf7"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"54c32b308570688ccb4a3d9877f1667393f9c775a190d15bd789be77a7872637"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"65dc496a78bb27bea7e832fb2fcc519ca0a1a0e9f1a3da01fb7842400f84596e"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"2fd8a069b0528005bad464a072e383372b46dba2bb12557d1c0620f48520d260"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"2c925fce6a934219fbbab1c5a2423edaa05d161143fc7731319d38ebab1076c0"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"4232af1b388ff9803753312c54e93a055085b754c3f051507f855cef7ab8415a"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"49b4754ff126553764ae10edbd8caa67b7ff08b4acbb4cf9403588bc12e7b9c4"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"62a4bdee4055ebda8b75c8c458c6d8ceedabc9c82abb574ca64d0d0d54265b49"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"53d0c5cdfd35487168e993afcc0857ac972e732b06d3d21e33d60b8153c73d9a"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"2c3fba7975d6454c64a7806254b583692fb94c78221cd2d50256d03e47a71146"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"596f33fe28d30a2cd4c578e366568a4fd773643713d11c317a74d1c324e7fd23"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"049d1ebe2161d109d340ae7152df2f4831ad22fec7548578283d91d7607e6474"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"6627866c47eba59bd8337e7ef01a0067277a257293e77d9cdb1f317de54c7074"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"34f29783304a2e64bdced10de519a3550478203d00d69574dad8df6020cdcd30"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"48362875e1a6d36ba286b3a5a8a538d437762d7364b33c3c3b742b2aa58913e3"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"61935b799327cf51fc7b3e9d3662669d75026e5bd83f8bb50da9c277a5903dfc"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"44c545a9fb7660541a696d877c75b4dc275948679124d98196f050c72b3bb4db"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"27a1235745ef505fe3cc0e473f494379096496a9f239282f5380ea91e9d4c0f2"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"3197b3329a543c53400fa92f0ef912fe3f12265a7a9ebfd1fad1c96c5b4b7573"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"0c6b7da40f51cefedc5e562d996225571e96da7ee9afce17a551f343f6893a21"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"1d219cb7e0e9fe1c009f965566fbfa71aa4567bcd937963627640f6eaa6cc77c"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"1d871e9691901bfd6d4089a6cf77afc86504b1521e3ecca9172bce5984df3c07"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"5ac394b97b804f3b8557fc3b67d2ea12919e27a9f1c33aa3470db54e493f30c1"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"46d90b6372812f62be94add1c0914df911e1c520e0d7776556696a3be3f2a2ee"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"461997adfb8e95e75c697a3975ea365a6667e975e90fc5520d86a2e19a8d5e79"},{"kind":"ReadScalar","tag":"advice_eval","fe_be_hex":"019b99c3d5c202bbabc76aa2a2a86c9e445988e698197b96cfb09dfd7311511b"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"14ad4103f2e8bc5ddca276f21b54e3ee4054a6e21b9d567e71a819478626cf80"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"5b6dfb1926f4165466b1c34793247660c1ecd8244a2eab3340aee10747bdf466"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"2414f225327ed2c7ddf7b77b5d10f05d6aa9634913a35c2e5138611de4a6cfc9"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"6ab6d2f1fc1ced14f72c7a8cdcf48abba1e048161d8a720c7a290853956f1e2d"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"6dbc0726ddbd4e1cbaf60f38999498eb2e8eb9d5010f2300594d3703be266658"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"37726ba651383f231e61b5cf282561273a93f0344d01d68d4dc209e724395d1c"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"3e68bc805df454fca334e1720f57a3363811f1c17808da70f205bca79f0d599c"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"3b40f386c432f27daf4e49a626e983cc4a8bb5501f0fef370a463cfed9d63aff"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"5e34b61c1b3db7f63cfd45d3e261d300e858536fd81612be8f50451447b519a2"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"2f16371f1d896cd93e2201b39fc4ba25d2f6d09d8b82ac12e46e930ed3ac21fa"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"0ea3f215bfe32c3166b8abbf36962f3ece721ff0bd303c5c59bf566521bf1791"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"004f497fb64bacf49f0e7273047e805a2c1af696595c259f8a73a49bdb41799c"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"3e06211806b4e7b4674d4a2dd409484190ecb8158387b9d9be9940e35fdf9b1e"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"1db7203289fa5f6db1e2b150057157b1da3fc8b87a54b62f42f3521edaeade54"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"01bbc3918a1edda73c72ef9c0ccc91b584fd1915e469bb9355897c37515e0075"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"1134aa786c389ecc8afb97cc1f80c6d17fe4b0a282371404e99daf7e22748a0a"},{"kind":"ReadScalar","tag":"fixed_eval","fe_be_hex":"44154629726a79952b69531e24d1c476a100c387864071ce9873ca0bd4fb8259"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"6c9e183607a90e4d710b847ed3082cb90e11430e161e180fb4cf6dff5e60f6fe"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"712d02268b3d16ffd37948ddbf54e8e0476873c1a561ed9a50983d8c3af196a6"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"5839aa24628fdcc4ee441615e0f60859084e903ca95b43bd89aee00ff1accc76"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"37f5ac771c0edd9ef214a34b33a469bbac297bc17e16ba72be1c046fe41fbaae"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"655ecb16378f8d990cf6c442d21bc690ab2ce050f6af93c8d94357f3979e72e0"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"3241d62aa2ee77caa09d00c1048f1b383f5f632cc741a71a382d6912a5f0350e"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"373f161bec38765b8579fae5f9057301be67013bb38928b5776909ea08337edb"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"0dc1d24a4f7bd8331c394efe98e5f452ff3955e737ddae522f9e2552ca79280b"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"516c5fae7051b044cc4798c9f75bbcf06c4b5910f882f1ffe15e82f329165c6c"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"3de4833d15a75e94c5fc30c03ec19c7e238058d2fa242e7caf17d6b7b57ee2a1"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"201cd483ad4dc7d466cb4e9e2ea6785b921cc491bfb23d121a8a4bd1c314af48"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"18f0620cfe7ecbea2b26b6419cf1afa321bef2146fd0e26398d201b2b68cefe7"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"0a2b19de67150f439452406bb4d962da831d80241e625cd714e9bd0a413ffc1a"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"19a2b386a5a2414caf2d9a688b4bb38364810775cc9fde2ed1804d34a1e4905e"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"4729b5d831af837bbb9f838f11dce195a82d1694320c7e9e98808e77b5fe556c"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"6307e640d82663d46481590a917b746fb0627a5f80dec829c691d0a442dead1f"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"64ff573b09c5d6897d782bb730572d1f05f73ae3c9ab8b7dcef6a8312df95c23"},{"kind":"ReadScalar","tag":"perm_common_eval","fe_be_hex":"6b8bd275e850818bc69ff00f3b8be5d689eb8cf7be45af436d2317ad048d8a73"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"69f0d9446331009d2881069dc939974374d361c058e4419736d747d753d8e4d5"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"5f14c13215ffc96f43762265ec6be1523aa467caaa8dbbed4fb5250f6f5fd26b"},{"kind":"ReadScalar","tag":"perm_last","fe_be_hex":"08c5f4d6099af4b9b425951caeec5b2034cc116c781005a1855c1b0809acca87"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"09da2149c10bf24f5398bb9ffce65639c62f5e65eb46c9088527dfb3058f0281"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"324f6ef7243ba96253f8669000cdacc095449ab947719ea8de02b57ef087da6b"},{"kind":"ReadScalar","tag":"perm_last","fe_be_hex":"503c69e9a786ddd9cc47b1a7b33c24d9125ee2d3a8a73812ddfeb2e2820c5b81"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"3b45aab1197f9e693e77ffbbf656671c103e7cc7fabd7676cfba7c0dbe1e6910"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"68038ff1509fd4631d2d8ca7a62939990052c92827ae6692656bd3c2e18ae3a5"},{"kind":"ReadScalar","tag":"perm_last","fe_be_hex":"52f75632c182416b0ec8eae43b99ba8f4cb07f305d4a23e7328433ea7cdcccaf"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"5c3379b067d47d07f0baee88a7f96a71809523bc2122e94ce803a77bd790b7d1"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"142f5d5ffedf93ab9733f1d1c1322d7a2a787636328b35c11e0e9336c9776233"},{"kind":"ReadScalar","tag":"perm_last","fe_be_hex":"1dd4d02fab4470903c87e221cbef954679ffd8190fa9df7d19ccfa9730c1d32d"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"0311fe738e056e8db829dbb795c41570a66b8de508afba7753313a8e0f64b1f2"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"5296e8474e56d657c049421b19587912eedfe9a88ac5f3167eb63ddd4bcec4fb"},{"kind":"ReadScalar","tag":"perm_last","fe_be_hex":"04263ab0bcb0df4e05cab8ad7e3033bf7a14d5b0bc2bce18deacff2e36cd1741"},{"kind":"ReadScalar","tag":"perm_cur","fe_be_hex":"24cdd547d581885a9499b9dcfeb3daf3f6b2573249433b68ae4b06e5c6e17145"},{"kind":"ReadScalar","tag":"perm_next","fe_be_hex":"066b9b55e4b6942a9bd6a7d37d970a88f38772d00e3955947d7288267dacbdc3"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"68ee03441d1c0f093ed8fabea2015e3444c1d9ae728a6fe6da42fb84a98a8e73"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"18425279cb0d2ea5a3fe6a9008003baf88d8609655e501bb056d6fac2b3a8154"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"08f9d736bb32f4fc2fd22f40ce8d737e27c02aef5ecadd2117e182ccfec4907d"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"52cf1481bbb3ab0dcb051cff44bc54d8719152970ff508290418e0c36d59ac9c"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"160dae4607f1df78f3391e992a9fe6f757227067b7ec1d0d02ec14c1d9bee8db"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"44cb92fc492e5dc73f69d9cd84c668734a36de040e2b9fd5f158fca36f9c3f10"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"1ca147219543e05d489c2a27ea73f94cff979d018a579df61bfe1fc962913b33"},{"kind":"ReadScalar","tag":"lookup_eval","fe_be_hex":"0a163b1652cc1a06d13c3d35fa936ddf34bbc1ca841c6c39204a133da267c0ac"},{"kind":"ReadScalar","tag":"trash_eval","fe_be_hex":"2236f4d3167396b4d87b1d7defd0e879ae415244035f3d7eaff75943bb4ad383"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4d84f602435f12f8f5b1345a446e1d5af680c023f2e1bec4cd2971d49c4ca92a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"38e4c99b63fb2f92a207528b53ec6384413939f13d1d5eeb6e40d401095cccf9"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6a115d18c53d7506b6e98cccbce5760ac0103a70bde718afc76d989e92a49d61"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"11e74c9d92f5333b73311b9d81ddea08e8048e9693c54c3f7f522886cd4fe73f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4b6767e53ed2bfe61aec89506ebb5d11422fa20f171424c75f1a578e5f14499b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"39df664536219ae8c6d13cd65b0542a4f37585fc551cc32da9e8bf19b619a325"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0493e84246159d9a0c5ee0b0d451fbafce46f9bb9a5c2845327628d26f1e7bbb"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1cd2ab993c64e766697fe1b0129938a0944298703452af46be29d5522aa88970"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5619c9c33806fb0e1f45ca1279b1c6303b9aa577ffceb8fd1ce85debe63e8b23"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4cc558c2bd77616304b3fb7b7d77a5e9b15abe455dde10e63182f80335a95e5f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"689634165a2730277593e57798b7c066dc5186379d0b15d4f4d7856982daffcc"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"355b92c70ec6af51ebf804e565c7d1a1228564101c77f73abe0c3c88aeaba470"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"461f03079bbefd53cecb5f46fb80476a0195d44d635ee14f9b29097c0a631efc"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2ad47773f05f81e86ad287bea69ff972ac8ff4af5fb9b08d585309ad53f6daa7"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"57261f6222454259b1b70bf4b5ddb3e090b3900b7efa6a8b536d45a4518d9724"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"057ac9a6d8cdf2c93f6014f0f10b9a2002bfd4efd1a98dda624e3b5f17e94834"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"26602d5b7d46eae0be328ee647587ffc128d4bdf58d5347e22aeb4f828c4d248"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"381b2bcb3e25616c0707c9d717197f9fd63a65037515d07211b05f3d6c9f58ae"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6ca1d68e1a6b7792a57bfb3b936070ec9e2b62dfd80edf6bb011736de7a474bf"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"42ef248d0a8c8391546451c282110ab5048f334383c82ec31b444d4ceb3096ce"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"55e21e3da2832df2f41d6a6f43a020f3f4bd2ab7bece259d999bc908f0abec2c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1c53991259ba6373b5823de5dfd510952bac4a31af688a42635a506aa3d1799f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0f79a34578494b0e29f69a1df1939463ec999607412f22275623c241bd3c3fee"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"04aa7cd595d0166bddec5fe573ed2c525ad1227e5476c7def868f5b264954750"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"18676fbe593dcd108833fc5da5423a9f916fa9a30bd080fbdd93315cd4d47dbc"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"131071e42b01b53cc5a69662719d931d7d7b9990e703a53ae84096d048f9ae3c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"01675aadf0c0d8681f8d27bc981bd2d2111820e15c7fdf04009c6e0af1f455c5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5e27b5e1f5a3260b0700251b06342a148fff1c9ac5ad4432f0d95c3c658c56fa"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2c97d440a8c86cc5ac8ae887b62f78ba1adeec390673cee6fdd679465c0794d1"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1824e3e45ab7c6b5353d2d250fdad905e8465daa05c2a47572b791f92cd14ff5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0f80a9f7bc25fe7c2b512bfd60b4823141eef42adf188c14242f8bf78f6c9fbd"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6940b7e93ea186db8c9089f0730eabea3b14a6f2bcc4d5f640e79a3df0e9629f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"17fd958f28b995d154f198bc0da303f14ca5f808705a77dfd144ed6a94d9249e"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5f0ae1389418a52788093ba4a333c9fe08f8ad8625d3d0f126ff9593deee4a98"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"48ffcedfc3681408df77ecf6e1b6b1010e76eedecb534506435060091ecd2625"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"44046630593df43fc89df0f40ef2825e44d3060718c5236f3766852e595e1d65"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"22201493963df06b078882d59ef1baf520c7f8a38e683270f208fe3f11b5da1c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"01bad9a7a03e41cd6bd172f3fc4e62fa729a77cf2e722733d242526d2f5a7ecd"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"12cc9895e0990ea45556a45312c508ae9fe8f8573484156ef20db108976a284b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"216b01ea2caf761404161e279de3dc4f62da3a8dd4f469706ce0a1bb3b61448b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1b67dd2a644fc0d81bf61ca12d534a66a0220548880d3daa2dd459dae236b0de"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"565997706ebffb9d7754038a6c62645854f0df8090e0708df29c899e99022b56"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2b6581101163f525d224824c36435408e6fc905e3f317353314613def0a07518"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"68e20f87934b626a2d5f7c209d869401839a4a118b5bb8b178ce3090d20e8487"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"21d1f9e69bd479903c92a4303b730a30323e07b9bd09962714fc3e7287beb409"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"45ba1a715ae585a0893569cf924a6b7489ae3f09e258430d2b339b8ccde77007"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"280ad47f4e418e50f544e959e498e91b26f1c0d6f52338b60acda2c062ebdf30"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6ff36b9a1df788dcb81f4f9a55e7b03fa49fc3b7e6d7c25316cdbd2014f48e81"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"04dbf5bc21710d87e2f53f794c449b940c3dbf98d0c3715039be44948efee6e3"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4cce456370593b4b2c12338ba432d7d2dc8d2b954fc27ad7839953b388c7fa40"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"245136107ff6c9127cd806b4c4d551c870e803b2d6bcac2a4b8488326f5dde50"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"037537ee588437badb0e3f22d0d7bfc2cc529bd03dd760e06bfaa4814caa14ed"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"06bdcd39f7b0136caabbea18e942888444142bde27356b103aeed6b9b10613a7"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4938b50ea746606c644b6de8e69de0a1e1864b137526b661ea92e5f23e862012"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2d42164ca6c6c3fba64ca662762968296b76eaefdbcc2f72ce6c659730f06303"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2cf5ed389a2b092dde54c11fc598b5296f3f9ea6083366b8e08af58d2424797a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5e2e4955bb1026354983477b6391a75eef3ec35abc89ca0ad9b2836bbe052efd"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"23b0a43901f778461e3e19850f0a644639f5b098404462b28f9eb11dcf5c943d"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"42c426784977ee16629b7b136ffd514988b085edb2b2b5732ff6ddef06212b65"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"510c8c528c8aaefc6e7ee6636a68fe5c0d6676244c76e739f6db4350657ee7db"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1f5fa161bd17eb5cd7f51486008198a2288cfc068de4c1d52f7ce9165dbd1a32"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"723089e8c78223ff6bcf157f5d7795048d0e5f342272e157c99fca5221b91c9f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3819ad665aa0f4079328407614b2763c879aa0688462dd1d2a054a692fd625db"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"65714decc38fc058c4c9647ba3bda9deaa1a66c396f0a2ff9882db4e4bb6eed5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"11a51b2754bd7e318250260b9e937f8097aa6f5c456ac5ba7b108dec1f4e94b6"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2b94f00cf585aac715f80005811db45996cb13a743397362fcf9c66575e11c79"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0a685a3e3bca3ff7b2c6a384a0bf9f35d9a2dcdc359de738765268cb3168cb67"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"44ea929ce6e2d770840cd5e995b12643282cae1749c019df2a74fa328152b2d1"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"45c2845b5844106df6f399279ac4df7145f86caaabafdc21285923a6a74179b3"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4d41d079b8ccb0700381f9cd3445420ce2f7216919d2476d167e16ce020ba1d3"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4050fc9352e2344291a6150266d4ee85b3f348bf9e048d5b959cb418244e9d1c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"241730773066d495dc9d78b9ae20bb88625f7db54fe8922d10cf63d3f1faeafe"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"10c4dee4dd83ea316988a170a4b5f98b098131f919bba00b0b7bd458fcd8da12"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"34fe8bc397563d8317fbe40dde895fdbffb7c69d9c11cc24330d41b9b4db242b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1186fce670c53ea565b4cc9bedd44983fa02f3ed77004f78630248955dd8fcbf"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2c9d92613f842529943da94911cd4d53d89144aad4f196d65f9282d774ebe3ef"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"43c252a5adfbab1141b203505fe28a11d67c3578e268e74ec5cea27ff466fa8a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0aec0d131103b9c6e998dbc5e145158df9b668512ea007b84c8d2a69589e57c6"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"16fdd35187250871cabce08b82f94ad2a6b5e64038cebc13c3a193b2aed03525"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"52eb863553792fd28628cbe7c673c265f0200c836e8bbb3a3ad10e9dd2788f4d"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"044b950152a054968cadfa9f38f136dafcde35c8b00c1ef07231244c04ba0a44"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"461715185e0141c19d67c47351d7ad78683e1ef1b5b1d2fb337f3e0ec3f3b249"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3a6860e88b5723601efcdd3c47c13c7cd78f0f1b718369b068c8c8dff92ef071"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6f180c1c3141f5d42fa4cdb774114b9a7032ef944c6a0199443f966f63c2a1e2"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"63c9fc3b50a25e5a8ae95997e46f3c582543251ad166556ac863ac987e6bc10f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"30d882588ee8f6959b437bccc3d6ed9d2deeca82d24a1f26e2d7f22f6914082c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"04922982ba64fdfb4fd3d8a4fa3c312ae96ed18a2070d900179d47cf710cba27"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5d7d715c6f859bff0b379c04001acc2755621cf4c9b7d83d0aea9ca516340585"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"193e3bd8a15fd20590d839dcded732f17f97d47434bffc3831de95caedd7bf8f"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"152104cd9b83bc618b92993d360b4d04e7478fff837cd4af8da3e64aa9c19f3c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"447f5f3b822ad2157c6cd978078607526759f0f312beb0cf8753ae893f7bc736"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"35a49b4552bc2897670723e74f0e687ee1cab24d67a67711f030e305d8852c51"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1c23439d4cf76c447fb8afd031d562c07f75d0e5e5c91950c0e4528ed7b3110c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5aa38b685836bb01905355f1faaa3eb0bf44091f957fedb8866431b50ca21ddb"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2fb774f3e1d4ca762d402be85203ceff34ddeab9e654270864c40042cf693ae6"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4220c142b4b52f30d04f8c217fcc3f59eebbea5780acbcb6189586b586e9f4ae"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1f72922c6c67a07ac1a4ab00aeba2a2d206a979104f8332a97a42a1ba43f1914"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"378647b10cb904a603e7d8f71c01f8ae0bb3b3625d9fa395c4bb52e839cd6efd"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"67487522f6a74fa7cef58cbb07683df5491680ef85085fa407036639950ae5d1"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"19937dfeefd2158ca0bc9e683b1d325bb5c90053db94f517c6ceb9af4eb40c86"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"58745b577b25297b5690da2a6f756362e2886372b5728c9179f4009b92597fb5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"245ab486accc627b29a57d4bb9cdc50562eb3e8f2e013c55dde35f1a4c4afc85"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"01d265e5bc50c71b71644720d66cae2fcadfcfb9cd57bad131cfd436f16b3ad4"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3cae55f63a45e8ff3ecc07611f0de9d5091af977e5a9e37b00912cc8f65450d7"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4562d249ab3ab25956c3de8943594e55aecd3e5c3415883a06ee8194a04ecd77"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3178d11e65909267934d86293bb734ac15e64585f69abfc3e8a96ac96efd5443"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6626afb1b7f2e317e5ee2112695b983b77158e0047d819aaf887ff0c6fd64422"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"353fd5b33bdaa47a4edf336f9ae45d83385458c9e6d038b44090bc38a29b05de"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"48996b81338a8b87f989f69eeacecba348d0bcd96e5b9dfc78ec615ff3f572e4"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0896da0029fc2c69b7558bb1b17603cf24b45717eb7bb1af86712ba784679e18"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"130fb75572e05392617c3f551305841d859e7e066fc9dfdad0ef4df6ebb8cb5a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"49c9e00faaa7ed77efe0a387f3c5071503e0e530e83fe1356b42aa564f62e9f4"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"60cef6247d3feb13cdd27653bf4fafa8401af878a97e0a8e5dff84f26b147588"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"07e3202eb6b6e74418ee84c8323af991b2667a27b9a3da4b3913b67a3acc3ef3"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3935077739ab4d47a0618aef4f8e5d30b10b37f9339175d9eb1b636be268b2fd"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5862cf4d8acb32ed43215038ef1c7e21aef91bb8a36a55f8109900bfb155375b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"73988db21c1f117f899f4c54bdf532c9b9cb10265f18300aec5a91a6fb107812"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1947314d727a59bfd9e04162b2e12cd90e4cd82dfd8de26e9dc97b7e78ece0be"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0ac408ecdb6ad3b5cf54c15edbfaac8e6e201db89f94a4746d3b13175cf8960d"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"48f98be7724694687e4fc7e16870109ba6aacfc31aecca40ef927bdae0c339db"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"16bbe36a02d0e3e8e9f01fb110230fbdacdb0707e98ee0a54a8eacd0d907051a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"37ab84231048f467c2b936aa5d14e2104c0d35e1ddc0abcb9e39891eaa640372"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2d354479ac28e801fc69ddbd171916a382bb4d9fe19b7d7e5e47b3993d775c29"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5289eb6c95e57d1ad45e356ff215b710b00977e6b878bac2f3666c337eff957c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3c2940471aea3e0ce4cb460fa12b31443bb9d2bcf6761b7e0d13334357c973b5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"04ec541aaf70d69c8653191b4536b5d179005c975df40ffcefa000785269d1b0"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4c0c5a5528bebc895414052346322a486f3c13ea28ab92d8f3e6895440212bee"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"457d318a5dfcd57055dfe70341eb983de6d319e2865f580cd83838c1a35d0273"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"72f512e290a77f23ffb69963813bfc2889a0708c02478b163cf1ee0589c2c059"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"289bd7dd96c36c5a2cd05941aad06beda7473df7a2e09ecc0292ca3f4191ea7a"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2124419ef77feab36d68c55819258cd114a1ee496fdb8e247bb9002e403cb392"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5682cd00f9040a55c6f616db6ee35678fe44561fad92131a134ef9f6445c9e9b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4c279fbc9241e8ffc73217187428cbf39cb29dbc86a25a8bab3153146bc562bf"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"606022c0776c73bdba99263ba976580e3fa453dbc6ed3ce321495518cfac5c97"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1b3c85c78620750db6865c0ab7c02962e13bbafd26a8f62e680a06bf099e96a3"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4e88df3cf58488335c62ab4b60010b0ad3e7ec5c6fa8e1fbc819440076f39fb2"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2128334d48bb8c736754aec52e94822a683250edbca9c64bc71763b41cb5f0db"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"2efa47645723e1b1d2aba11a901c5ae5c6a3954f2da8143eda496296461638cb"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0dedea303cf72dd88c5dd088f6b64a11ff0ad7e03808cc329077cbce08ccdcb0"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"70178e70b89186bff3ef1f778729fcf11e9909d1a341fc391cca61ae7503bea9"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5506ba47f40b9142d10acfb4678db90e687060b17d1a11c3f07fa37eb759b2f9"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"433bfa74fa0fe35dc664aa104f8618ab10eb6bb09d9e200e87a5aa78560d72fb"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5c141c77fd15a20905f40a4f46a47c782cd4b9b0246cddc79e1b5133721ec369"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"50425855791ad3327346bb7dd650c040a41e909d0e9e826d00850dcab138439b"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"0ab7145a5f012039efbd8abc425d1adc640625fe6ad438845382d418af87d0cc"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"52e36072d5fc448de5583f545c97443b9722b6fd380a0abf76bd27d629252b35"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"4513c98e9becd4d01b9d9734382c0116b59583474a487c2087da3c3498c1ffd9"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"37d2f2356a2f0eee375547232c36c6756249547d8c867acc93ec1963aa3c6d31"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"3c3fabeb32f89129ad9027840b32aa28686e0627135772c7b6b9510848947a00"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"48aa721a6af9f92c658a39617590780619dbefec5e31794a1358907354d5ff2c"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"5cc0ab5e75c80c54d6001fb4e90f302e3269c87afe4166f62fde2965e7fdf7c1"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"6abc22d42dfa2da89411aa00d98aac6a68d325dc34455a6c3cc98ceab56c5836"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"55f48be93ffd19a77df336ecf30080e84669468f92216bf063ed907addb560f5"},{"kind":"ReadScalar","tag":"dummy_eval","fe_be_hex":"1123b770b00b6e62a0f3c01c42d570127854425c70a66e004b6b7ebdeea69817"},{"kind":"Challenge","tag":"x1","fe_be_hex":"1c098ae6b043e3086251d5a69213433f867bce3584401f06632376bf4cc0d51f"},{"kind":"Challenge","tag":"x2","fe_be_hex":"450e371d88aee670e1855a0118a6ef70867a135a675e6283dc8a18cc1384add8"},{"kind":"ReadPoint","tag":"f_com","eip2537_hex":"909974aed62735634516ad3d04fb1c75814b1f04420e7ba5153e3f8ea730a425fd8cc7f4b9c06bc994f9b9fb18153ccd"},{"kind":"Challenge","tag":"x3","fe_be_hex":"2f336b860308ad449b601a9a51554f543475b39cd5647fee3fe190cf524b9693"},{"kind":"ReadScalar","tag":"q_eval","fe_be_hex":"3c84ab264411455250488b3d02d4498a82654a620a29d7f86a53d62c3b7cdd10"},{"kind":"Challenge","tag":"x4","fe_be_hex":"52e5456496a5abf0c1067996c62310f623e7d6b4972e9ae2746606965965c719"},{"kind":"ReadPoint","tag":"pi","eip2537_hex":"8b260bc8f81180fc5b6bce2401c2d81895ef4e29d8ac2300fad888e667cdbd286708865ad384a4aa27bd090951cf7660"}] \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/ivc/vk.bin b/proofs/solidity-verifier/fixtures/ivc/vk.bin deleted file mode 100644 index 670ff28e0213779ab0a81c3866bb6041da154306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66731 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 a%1iSU_Fk)}6(r}v(@_BN5cLSJ^8W+(ed+W7 diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs new file mode 100644 index 000000000..0fba70215 --- /dev/null +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: CC0-1.0 +//! CI-runnable adversarial replay of the public-accumulator decode path. +//! +//! The accumulator decoder in `templates/partials/verifier/AccumulatorHelpers.yul` +//! had no executing test coverage. The tests that looked like they covered it +//! -- `accumulator_decoder_rejects_noncanonical_infinity` and friends in +//! `src/lowering/tests.rs` -- are `verifier_template.contains("...")` string +//! greps over the raw template. They assert the guard *text* exists and never +//! render, compile, or run it. That is why the always-false `and` guard in +//! `load_acc_coord_shifted` survived: those greps passed for as long as the +//! identity branch was dead code. +//! +//! The only executing accumulator tests live in `tests/ivc_keccak_solidity.rs`, +//! which proves a k=20 decider from scratch and needs ~300 MB of SRS, so it is +//! gated behind `HALO2_SOLIDITY_RUN_IVC_BENCH=1` and never runs in CI. +//! +//! This test closes that gap by replaying *pre-rendered* artifacts. Because it +//! ships the generated Solidity and the matching calldata rather than a +//! verifying key, it needs neither SRS nor a proving run nor +//! `midnight-aggregation` -- only solc and revm. A verifier cannot be rendered +//! from a VK without the full SRS (`SolidityGenerator` consumes +//! `params.g_lagrange()`), which is what rules out a vk.bin-based replay. +//! +//! Regenerate the fixtures with: +//! +//! ```text +//! HALO2_SOLIDITY_RUN_IVC_BENCH=1 \ +//! SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ +//! cargo test --release \ +//! --features evm,truncated-challenges,in-circuit-fewer-point-sets \ +//! --test ivc_keccak_solidity -- --nocapture +//! ``` +//! +//! then copy `target/ivc-keccak-solidity-dump/{Halo2Verifier.sol, +//! Halo2VerifyingKey.sol,Halo2QuotientEvaluator.sol,calldata.bin}` into +//! `fixtures/ivc/` and update the commit stamp in `fixtures/ivc/README.md`. +//! +//! The fixture describes its own accumulator placement: the offset, limb count +//! and `has_accumulator` flag are parsed back out of the rendered verifying-key +//! payload, and the infinity encoding out of the verifier's own constants, so +//! this file carries no second copy that could drift. +//! +//! Staleness caveat: these are a snapshot of the codegen that produced them. +//! The fixture is self-consistent, so it keeps passing after a codegen change +//! -- it just stops testing current output. `fixtures/ivc/README.md` records +//! the source commit so drift is auditable; detecting it automatically would +//! require re-rendering, which needs the SRS again. + +#![cfg(feature = "evm")] + +use std::path::PathBuf; + +use halo2_solidity_verifier::{compile_solidity_with_runs, CallOutcome, Evm}; + +/// The IVC verifier is large, so it is rendered and benched at `runs = 1`. +const SOLC_OPTIMIZE_RUNS: u32 = 1; +/// Generous cap so an unexpected loop reports OutOfGas rather than masquerading +/// as a revert. +const GAS_CAP: u64 = 5_000_000_000; +/// ABI prologue: selector, proof head, instances head, then the proof length +/// word. The proof payload starts immediately after. +const PROOF_PAYLOAD_START: usize = 4 + 0x40 + 0x20; + +fn fixture_dir() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures/ivc") +} + +fn read_fixture(name: &str) -> Vec { + let path = fixture_dir().join(name); + std::fs::read(&path) + .unwrap_or_else(|err| panic!("missing IVC fixture {}: {err}", path.display())) +} + +fn read_fixture_string(name: &str) -> String { + String::from_utf8(read_fixture(name)).expect("fixture should be UTF-8") +} + +/// Read a labelled VK payload word out of the rendered verifying-key source. +/// +/// The generator emits each header word as +/// `mstore(add(payload, 0x...), 0x...) // name`, so the fixture describes its +/// own accumulator placement and this test does not have to carry a second +/// copy that could drift out of sync with the artifact. +fn vk_payload_word(vk_solidity: &str, name: &str) -> u64 { + let suffix = format!("// {name}"); + let line = vk_solidity + .lines() + .map(str::trim) + .find(|line| line.starts_with("mstore(") && line.ends_with(&suffix)) + .unwrap_or_else(|| panic!("verifying-key source has no `{name}` payload word")); + let value = line + .rsplit_once("0x") + .expect("payload word should be hex") + .1 + .split_whitespace() + .next() + .expect("payload word should have a value") + .trim_end_matches(')'); + u64::from_str_radix(value.trim_start_matches('0'), 16).unwrap_or(0) +} + +fn read_u256_word(calldata: &[u8], offset: usize) -> u64 { + let word = &calldata[offset..offset + 0x20]; + assert!( + word[..24].iter().all(|b| *b == 0), + "word at {offset:#x} does not fit in u64" + ); + u64::from_be_bytes(word[24..].try_into().unwrap()) +} + +fn assert_reverts(outcome: CallOutcome, case: &str) { + match outcome { + CallOutcome::Revert { .. } => {} + CallOutcome::Success { output, .. } => panic!( + "{case}: verifier accepted a proof it must reject (output = 0x{})", + hex::encode(output) + ), + CallOutcome::Halt { reason, .. } => { + panic!("{case}: expected a revert but the call halted ({reason})") + } + } +} + +/// Replay the shipped IVC accumulator fixture, then mutate the accumulator +/// public inputs and assert every mutation is rejected. +/// +/// The accept baseline is what gives the rejections meaning: without it a +/// "rejects" assertion could pass because the verifier rejects everything. +#[test] +fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { + let verifier_solidity = read_fixture_string("Halo2Verifier.sol"); + let vk_solidity = read_fixture_string("Halo2VerifyingKey.sol"); + let quotient_solidity = read_fixture_string("Halo2QuotientEvaluator.sol"); + let calldata = read_fixture("calldata.bin"); + + assert_eq!( + vk_payload_word(&vk_solidity, "has_accumulator"), + 1, + "fixture must be a public-accumulator render, otherwise this test \ + exercises none of AccumulatorHelpers.yul" + ); + let final_acc_offset = vk_payload_word(&vk_solidity, "acc_offset") as usize; + let num_acc_limbs = vk_payload_word(&vk_solidity, "num_acc_limbs"); + + // Derive the accumulator's calldata position from the ABI layout; the + // fixture describes its own instance-space offset via the VK payload. + let proof_len = read_u256_word(&calldata, PROOF_PAYLOAD_START - 0x20) as usize; + let instances_len_word = PROOF_PAYLOAD_START + proof_len; + let first_acc_word = instances_len_word + 0x20 + final_acc_offset * 0x20; + // 7 limbs of 56 bits pack 4 to a field element, so each coordinate takes 2 + // words and each point 4, with one scalar word following. + assert_eq!( + num_acc_limbs, 7, + "limb count changed; the word arithmetic below no longer holds" + ); + let lhs_scalar_word = first_acc_word + 4 * 0x20; + let rhs_first_word = lhs_scalar_word + 0x20; + let rhs_scalar_word = rhs_first_word + 4 * 0x20; + assert!( + rhs_scalar_word + 0x20 <= calldata.len(), + "accumulator words run past the fixture calldata; the fixture is inconsistent" + ); + + // Guard the offset arithmetic above. Without this, a miscomputed + // `first_acc_word` would still make every mutation below revert -- for the + // wrong reason -- and the test would pass while exercising nothing. + // + // Four 56-bit limbs occupy the low 224 bits of a packed word, so the top + // four bytes of every accumulator coordinate word must be zero. Random + // proof or instance bytes would not satisfy this. + for (index, word_start) in [first_acc_word, rhs_first_word] + .into_iter() + .flat_map(|point| (0..4).map(move |w| point + w * 0x20)) + .enumerate() + { + assert_eq!( + &calldata[word_start..word_start + 4], + &[0u8; 4], + "accumulator coordinate word {index} at {word_start:#x} has non-zero high bytes; \ + the computed accumulator offset does not point at packed limbs" + ); + } + + let mut evm = Evm::default(); + let vk_address = evm.create(compile_solidity_with_runs(&vk_solidity, SOLC_OPTIMIZE_RUNS)); + let quotient_address = evm.create(compile_solidity_with_runs( + "ient_solidity, + SOLC_OPTIMIZE_RUNS, + )); + let verifier_address = evm.create_with_two_address_args( + compile_solidity_with_runs(&verifier_solidity, SOLC_OPTIMIZE_RUNS), + vk_address, + quotient_address, + ); + + match evm.try_call_with_gas(verifier_address, calldata.clone(), GAS_CAP) { + CallOutcome::Success { output, .. } => { + let expected: Vec = [vec![0u8; 31], vec![1]].concat(); + assert_eq!( + output, expected, + "fixture proof should verify; the fixture and calldata may be out of sync" + ); + } + CallOutcome::Revert { gas_used, output } => panic!( + "fixture proof was rejected (gas_used = {gas_used}, output = 0x{}); \ + regenerate fixtures/ivc -- see this file's header", + hex::encode(output) + ), + CallOutcome::Halt { gas_used, reason } => { + panic!("fixture proof halted (gas_used = {gas_used}, reason = {reason})") + } + } + + // Limbs are 56 bits packed 4 to a word, so the first word carries 224 + // significant bits. Byte 3 is the lowest unused high byte in the + // big-endian word: setting it keeps the value below the Fr modulus, so + // only `check_acc_coord_packing` can catch it. + let mut bad_packing = calldata.clone(); + bad_packing[first_acc_word + 3] ^= 0x01; + assert_reverts( + evm.try_call_with_gas(verifier_address, bad_packing, GAS_CAP), + "non-canonical accumulator limb packing", + ); + + // Perturb a coordinate and zero its scalar, so the term cannot be + // dismissed as a no-op multiply and has to fail the point decode. + for (case, point_word, scalar_word) in [ + ( + "malformed LHS accumulator point", + first_acc_word, + lhs_scalar_word, + ), + ( + "malformed RHS accumulator point", + rhs_first_word, + rhs_scalar_word, + ), + ] { + let mut malformed = calldata.clone(); + malformed[point_word + 31] ^= 0x01; + malformed[scalar_word..scalar_word + 0x20].fill(0); + assert_reverts( + evm.try_call_with_gas(verifier_address, malformed, GAS_CAP), + case, + ); + } + + // Substituting the canonical point at infinity for a real accumulator term + // must not verify. This is the encoding `is_acc_encoded_identity` accepts, + // so it exercises the identity path rather than the range check. + for (case, point_word) in [ + ( + "LHS accumulator replaced with encoded infinity", + first_acc_word, + ), + ( + "RHS accumulator replaced with encoded infinity", + rhs_first_word, + ), + ] { + let mut identity = calldata.clone(); + write_encoded_identity(&mut identity, point_word, &verifier_solidity); + assert_reverts( + evm.try_call_with_gas(verifier_address, identity, GAS_CAP), + case, + ); + } +} + +/// Read a rendered `uint256 internal constant NAME = 0x...;` out of the +/// fixture's verifier source. +/// +/// Parsing the constants back out of the artifact under test keeps this file +/// from carrying a second copy of them: if codegen ever changes the encoding, +/// the vector below follows automatically instead of silently testing a stale +/// literal. +fn solidity_constant(source: &str, name: &str) -> [u8; 0x20] { + let needle = format!("constant {name} "); + let line = source + .lines() + .map(str::trim) + .find(|line| line.starts_with("uint256") && line.contains(&needle)) + .unwrap_or_else(|| panic!("verifier source has no constant `{name}`")); + let hex_value = line + .split_once("0x") + .expect("constant should be hex") + .1 + .trim_end_matches(';') + .trim(); + let bytes = hex::decode(format!("{hex_value:0>64}")) + .unwrap_or_else(|err| panic!("constant `{name}` is not hex: {err}")); + bytes.try_into().expect("constant should be one EVM word") +} + +/// Overwrite the four accumulator coordinate words at `point_word` with the +/// canonical encoded point at infinity. +/// +/// This is the exact quadruple `is_acc_encoded_identity` accepts: `p - 1` in +/// every packed word, with the identity flag (one radix base) folded into the +/// first word of `x`. +fn write_encoded_identity(calldata: &mut [u8], point_word: usize, verifier_solidity: &str) { + for (index, name) in [ + "BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG", + "BLS_P_MINUS_ONE_PACKED_1", + "BLS_P_MINUS_ONE_PACKED_0", + "BLS_P_MINUS_ONE_PACKED_1", + ] + .into_iter() + .enumerate() + { + let word = solidity_constant(verifier_solidity, name); + let at = point_word + index * 0x20; + calldata[at..at + 0x20].copy_from_slice(&word); + } +} From 6f786863b1642cb465348c41592d682bb0f23786 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 04:43:55 +0100 Subject: [PATCH 065/108] Cover point_pair accumulators and port calldata attacks to the replays Two gaps remained after the IVC replay landed. The `point_pair` accumulator encoding had no executing coverage of any kind. `accumulator_verifier_variants_compile_with_pinned_solc` renders it against the poseidon VK and checks it compiles, but the template's `expected_acc_has_carried_scalars = false` arms were never run against a proof -- and that is the encoding the deployed Moonlight wrap verifier uses. It cannot be synthesized from the IVC fixture either: point_pair occupies 8 public-input words against point-and-scalar's 10, so dropping the scalars changes the instance count, hence the Lagrange evaluation and the transcript. Public inputs are bound into the proof. So generate a real one. `fixtures/moonlight-wrap` holds the rendered wrap decider and its calldata, produced by Moonlight's wrap bench on `origin/codex/wrap-bench-cherry-picks` against this branch's codegen. That run also confirms the layout rebase against a second accumulator shape: proof accepted on-chain in 1,277,823 gas with 244 native/Solidity trace points matched. The replay is now parameterized over both fixtures and recovers the encoding kind from the payload width rather than being told, so a fixture still describes itself. Split renders deploy a quotient evaluator; single-contract renders like the wrap one deploy against the verifying key alone. Second gap: the ivc replay only attacked the accumulator words. Port the calldata-level dimensions that poseidon covers and a static fixture can carry -- framing (trailing bytes, truncation, selector, ABI heads, proof length, instance count), every proof commitment against off-curve, base-modulus and non-canonical-padding G1 vectors, and every evaluation scalar and non-accumulator public input set to the Fr modulus. That is 32 commitments x 3 vectors, 115 eval words and 14 instances for the IVC fixture, ~230 EVM calls in about 2 s. The poseidon suite is left intact. Much of it cannot move to a static fixture -- wrong-VK and VK-mutation cases need a second verifying key, cross-wiring needs four circuits on one SRS, the forced-domain-root case needs prover-side control, and the pbt_* family draws fresh proptest seeds per run. Deleting those would have removed dimensions no fixture replay can reproduce, so this is additive: the accumulator configs gain the portable attacks, poseidon keeps the rest. The commitment run length is discovered from the EIP-2537 padding signature rather than hardcoded, so a regenerated fixture with a different commitment count stays covered. Every mutation class was individually neutered and confirmed to make the verifier accept, including on the point_pair fixture -- so its accumulator is genuinely consumed rather than ignored, and no assertion passes vacuously. Co-Authored-By: Claude Opus 4.8 --- .../fixtures/moonlight-wrap/Halo2Verifier.sol | 3659 +++++++++++++++++ .../moonlight-wrap/Halo2VerifyingKey.sol | 693 ++++ .../fixtures/moonlight-wrap/README.md | 69 + .../fixtures/moonlight-wrap/calldata.bin | Bin 0 -> 8516 bytes .../tests/ivc_accumulator_replay.rs | 302 +- 5 files changed, 4674 insertions(+), 49 deletions(-) create mode 100644 proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol create mode 100644 proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol create mode 100644 proofs/solidity-verifier/fixtures/moonlight-wrap/README.md create mode 100644 proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol new file mode 100644 index 000000000..026c4e8a6 --- /dev/null +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol @@ -0,0 +1,3659 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.24; + +/// @title Halo2 BLS12-381 KZG verifier. +/// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 +/// proofs rendered by this repository's Rust generator. +/// @dev This contract ports the verifier flow from +/// `midfall/proofs/src/plonk/verifier.rs`, the Keccak transcript comments from +/// `midfall/proofs/src/transcript/implementors.rs`, and the KZG multi-open +/// comments from `midfall/proofs/src/poly/kzg/mod.rs`. +/// @dev It is not a generic verifier. The proof layout, VK payload, quotient +/// identity program, memory layout, and optional quotient evaluator are all +/// generated for one `VerifyingKey>`. +/// +/// Halo2 KZG verifier for the BLS12-381 curve, midnight-proofs flavour. +/// +/// Differences vs the original BN254 / halo2 v0.4 template: +// +/// - BLS12-381 base field Fp is 381 bits and does not fit in a uint256. +/// Each Fp coord is encoded EIP-2537 padded (16 zero bytes + 48 bytes). +/// A G1 point is 128 bytes (4 words); a G2 point is 256 bytes (8). +/// - Calldata carries G1 commitments in uncompressed EIP-2537 padded +/// form (4 words = 128 bytes per point: x_hi, x_lo, y_hi, y_lo). The +/// proof bytes produced by midnight-proofs prover are repacked off +/// chain (compressed -> uncompressed) before being passed to +/// `verifyProof`. The verifier hashes the uncompressed 128-byte form into +/// the transcript verbatim, matching `Hashable for G1Projective::to_input`; +/// see `common_uncompressed_g1`. +/// - Transcript `common` absorbs raw inputs in order. `squeeze` computes one +/// Keccak digest, resets the transcript buffer to that digest, then samples +/// by interpreting the digest as a big-endian integer modulo r. +/// - Scalar inversion uses modexp(scalar, r-2, r). +/// - Constructors run deployment-time smoke tests for MCOPY and the EIP-2537 +/// precompiles using identity inputs. Compile with Solidity >=0.8.24 and +/// deploy only on chains/forks that support MCOPY and EIP-2537. +contract Halo2Verifier { + + /// @notice Verifying-key contract address authorized for this verifier. + /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. + address public immutable AUTHORIZED_VK; + // Expected VK runtime metadata. The deployed VK runtime is + // INVALID || payload, hence EXPECTED_VK_LENGTH is one byte longer than + // EXPECTED_VK_PAYLOAD_LENGTH. + uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 17024; + uint256 internal constant EXPECTED_VK_LENGTH = 17025; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0xe68d89362065c8b7107055774f1e045b69bc3bffde4704541c5bc5c91c94cf52; + bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); + + // Solidity ABI calldata cursors. The generated verifier accepts exactly + // verifyProof(bytes proof, uint256[] instances), then parses the `proof` + // bytes itself in the same order as the Rust verifier transcript. + uint256 internal constant PROOF_LEN_CPTR = 0x44; + uint256 internal constant PROOF_CPTR = 0x64; + uint256 internal constant NUM_INSTANCE_CPTR = 0x1ec4; + uint256 internal constant INSTANCE_CPTR = 0x1ee4; + // First general-purpose memory words reserved by the generated verifier. + // RETURN_MPTR is a single word set to 1 on success. + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; + + // ---------------------------------------------------------------------- + // Verifying-key memory map. The VK header lives at VK_MPTR, followed + // by the quotient VM payload and commitments. After the full VK + // runtime comes the challenge slots (challenge_mptr..) and the + // per-stage scratch (theta_mptr..). + // ---------------------------------------------------------------------- + uint256 internal constant VK_MPTR = 0x3680; + uint256 internal constant VK_DIGEST_MPTR = 0x3680; + uint256 internal constant NUM_INSTANCES_MPTR = 0x36a0; + uint256 internal constant K_MPTR = 0x36c0; + uint256 internal constant N_INV_MPTR = 0x36e0; + uint256 internal constant OMEGA_MPTR = 0x3700; + uint256 internal constant OMEGA_INV_MPTR = 0x3720; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x3740; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x3760; + uint256 internal constant ACC_OFFSET_MPTR = 0x3780; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x37a0; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x37c0; + uint256 internal constant G1_BASE_MPTR = 0x37e0; + uint256 internal constant G2_BASE_MPTR = 0x3860; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x3960; + + uint256 internal constant CHALLENGE_MPTR = 0x7900; + + // Challenge layout. Squeeze order in midnight-proofs: + // user_phase challenges (variable count) + // theta -> beta, gamma -> trash_challenge -> y -> x -> + // x1, x2 -> x3 -> x4 + uint256 internal constant THETA_MPTR = 0x7900; + uint256 internal constant BETA_MPTR = 0x7920; + uint256 internal constant GAMMA_MPTR = 0x7940; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x7960; + uint256 internal constant Y_MPTR = 0x7980; + uint256 internal constant X_MPTR = 0x79a0; + uint256 internal constant X1_MPTR = 0x79c0; + uint256 internal constant X2_MPTR = 0x79e0; + uint256 internal constant X3_MPTR = 0x7a00; + uint256 internal constant X4_MPTR = 0x7a20; + + // Batch-open commitments live in 4-word EIP-2537 padded slots. + uint256 internal constant F_COM_MPTR = 0x7a40; + uint256 internal constant PI_MPTR = 0x7ac0; + + // Accumulator (KZG IVC). + uint256 internal constant ACC_LHS_MPTR = 0x7b40; + uint256 internal constant ACC_RHS_MPTR = 0x7bc0; + + // Lagrange / linearization scratch. + uint256 internal constant X_N_MPTR = 0x7c40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x7c60; + uint256 internal constant L_LAST_MPTR = 0x7c80; + uint256 internal constant L_BLIND_MPTR = 0x7ca0; + uint256 internal constant L_0_MPTR = 0x7cc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x7ce0; + // Legacy name: this is not h(x). It stores the expected opening + // scalar for the linearized commitment, i.e. the negated y-batched + // identity numerator reconstructed from the alleged evals at x. + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x7d00; + uint256 internal constant QUOTIENT_MPTR = 0x7d20; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x7dc0; + uint256 internal constant V_MPTR = 0x7de0; + uint256 internal constant FINAL_COM_MPTR = 0x7e00; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x7e80; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x7f00; // 4 words + + // Multi-prepare scratch (sized at codegen time). + uint256 internal constant ROT_POINTS_MPTR = 0x7f80; + uint256 internal constant X1_POWERS_MPTR = 0x8300; + // Q_COM materialization is currently fused into the final MSM scratch, + // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero + // reserved capacity until a future emitter starts writing Q_COM_MPTR. + uint256 internal constant Q_COM_MPTR = 0x8b20; + uint256 internal constant Q_EVAL_SET_MPTR = 0x8b20; + + // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals + // block of the proof; we keep it as a memory slot for symmetry. + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; + + // Reserved 4-word slot for the G1 identity (point at infinity) in + // EIP-2537 padded form. EVM memory is zero-initialised, and we + // never write to this region, so the four `mload`s below produce + // 0,0,0,0 which is exactly the identity encoding the EIP-2537 + // ec_add / ec_mul precompiles accept. + uint256 internal constant G1_IDENTITY_MPTR = 0x9320; + + // Decoded polynomial-eval buffer (Optimisation H3). The off-chain + // Solidity proof shim rewrites proof scalars into canonical BE words, + // so `calldataload` gives the field element directly. The transcript- + // side `evaluations` loop range-checks and spills that value here so + // downstream eval references (gate evaluator + PCS q_eval Horner) + // become 3-gas `mload(...)` instead of calldata reads. + uint256 internal constant REVERSED_EVALS_MPTR = 0x9480; + uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + uint256 internal constant TRACE_U256_MPTR = 0xe340; + + // ---------------------------------------------------------------------- + // Per-category bases for EIP-2537 padded G1 commitments. The proof + // calldata carries 128-byte uncompressed/padded G1s after the off-chain + // proof shim repacks midnight-proofs' native compressed stream; this + // region stores the 4-word slots used by PCS / quotient-fold sections. + // + // Cumulative offsets (in words from `comms_mptr_base`): + // ADVICE_COMMS_MPTR_BASE + 0 + // LOOKUP_M_COMMS_MPTR_BASE + 4*total_advices + // PERM_Z_COMMS_MPTR_BASE + 4*total_advices + 4*num_lookups + // LOOKUP_HELPER_COMMS_MPTR_BASE + ... + 4*num_permutation_zs + // LOOKUP_Z_COMMS_MPTR_BASE + ... + 4*lookup_helper_chunks_total + // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups + // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans + // ---------------------------------------------------------------------- + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0xa140; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0xa8c0; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0xa9c0; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0xacc0; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0xadc0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; + + // BLS12-381 scalar-field modulus, used for transcript challenges and all + // Halo2 verifier arithmetic. + uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; + + // BLS12-381 Fp modulus minus one, split like an EIP-2537 coordinate: + // high word = 16 zero bytes || top 16 coordinate bytes, low word = + // bottom 32 coordinate bytes. + uint256 internal constant BLS_P_HI = 0x000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd7; + uint256 internal constant BLS_P_MINUS_ONE_LO = 0x64774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa; + // Packed public-accumulator sentinels for the shifted coordinate codec. + // The `_WITH_ID_FLAG` variant is used only for the first x-coordinate word. + uint256 internal constant BLS_P_MINUS_ONE_PACKED_0 = 0x00000000f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa; + uint256 internal constant BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG = 0x00000000f38512bf6730d2a0f6b0f6241eabfffeb153ffffbafeffffffffaaaa; + uint256 internal constant BLS_P_MINUS_ONE_PACKED_1 = 0x0000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84; + + /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. + /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + function require_eip2537_precompiles() private view { + assembly ("memory-safe") { + // Scratch is reused for every runtime-prerequisite probe. + let scratch := 0x1000 + + // MCOPY must be available because the verifier uses it for + // proof-time point/scratch staging. Execute the opcode here so a + // non-Cancun fork fails during deployment instead of later proofs. + mstore(scratch, 0x1234) + mcopy(add(scratch, 0x20), scratch, 0x20) + if iszero(eq(mload(add(scratch, 0x20)), 0x1234)) { revert(0, 0) } + + // Start the EIP-2537 probes with the identity encoding for G1/G2: + // all-zero padded words. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + + // G1ADD(identity, identity) -> identity, 128-byte return. + // This catches chains where the precompile is missing or returns a + // non-standard success shape. + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { + revert(0, 0) + } + + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + + // Worst-case generated G1MSM with all identity/zero terms -> + // identity, 128-byte return. This exercises the largest MSM input + // length rendered by this verifier instead of only a one-pair + // smoke call. + let msm_scratch := 0xb140 + for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { + mstore(add(msm_scratch, off), 0) + } + // The production verifier uses G1MSM both for commitments and as + // the subgroup validator for absorbed proof points. + if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { + revert(0, 0) + } + + // PAIRING_CHECK([(identity_g1, identity_g2), (identity_g1, identity_g2)]) + // -> true, 32-byte return. This matches the runtime two-pair KZG + // pairing input size and catches absent pairing precompiles, + // short return data, and obviously incompatible semantics. + if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(scratch), 1)) { revert(0, 0) } + } + } + + + /// @notice Create a verifier pinned to a generated verifying key. + /// @dev Checks MCOPY/EIP-2537 availability and verifies the VK runtime before storing its address. + /// @param authorizedVk Address of the generated `Halo2VerifyingKey` runtime. + constructor(address authorizedVk) { + // Embedded quotient path: only the external VK runtime needs to be + // pinned, but the runtime opcode/precompile prerequisites are still + // mandatory. + require_eip2537_precompiles(); + require( + authorizedVk.code.length == EXPECTED_VK_LENGTH + && authorizedVk.codehash == EXPECTED_VK_CODEHASH, + "invalid vk" + ); + AUTHORIZED_VK = authorizedVk; + } + + /// @notice Verify a Halo2/Midfall proof for the generated verifying key. + /// @dev This checks only that `proof` verifies for the supplied public + /// `instances` under this pinned VK/protocol. Application contracts must + /// bind the meaning of those instances separately: state roots, program + /// identifiers, expected IVC outputs, chain/domain separation, and any + /// protocol-specific authorization are outside this raw verifier ABI. + /// @dev Production renders are success-or-revert: accepted proofs return + /// `true`, while malformed calldata, invalid proof material, failed + /// precompiles, or mismatched pinned dependency code revert. Trace and gas + /// renders keep the same failure policy. + /// @dev The generated verifier uses absolute Yul memory addresses instead + /// of Solidity's free-memory pointer, but generated scratch starts at + /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// assembly block remains terminal: accepted proofs return from assembly + /// and all rejected inputs revert. Do not inline this body into Solidity + /// code that continues executing after verification without reviewing the + /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. + /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. + /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. + function verifyProof( + bytes calldata proof, + uint256[] calldata instances + ) external view returns (bool) { + // Cheap ABI-shape guard before any generated memory work: + // - proof head must point at the bytes payload; + // - instances head must point at the generated instance array. + // + // The verifier below is a hand-rolled calldata parser. Failing here + // keeps malformed dynamic-argument layouts from being interpreted as a + // valid Midfall proof stream. + assembly ("memory-safe") { + if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { + revert(0, 0) + } + } + // Non-embedded renders pin the VK by address and codehash. The Yul + // loader rechecks the runtime before every proof and copies the + // INVALID-prefixed payload into VK_MPTR. + address vk = AUTHORIZED_VK; + assembly ("memory-safe") { + // This block owns the call-frame memory and remains terminal. + // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Solidity's reserved scratch, free-memory-pointer, and zero-slot + // words. See docs/MEMORY_LAYOUT.md. + // =============================================================== + // Helpers: modexp, transcript, EIP-2537 calls + // =============================================================== + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // calls this only after transcript absorption is complete, so it + // reuses the dead transcript buffer just below VK_MPTR instead of + // a fixed post-VK address that can collide with live PCS scratch + // when the VK payload becomes smaller. + function scalar_inv(x) -> inv { + // Zero has no multiplicative inverse in Fr; callers rely on a + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } + if iszero(x) { revert(0, 0) } + let p := 0x3580 + // EIP-198 modexp frame: + // [base_len, exp_len, mod_len, base, exponent, modulus] + mstore(add(p, 0x00), 0x20) // base len + mstore(add(p, 0x20), 0x20) // exp len + mstore(add(p, 0x40), 0x20) // mod len + mstore(add(p, 0x60), x) + mstore(add(p, 0x80), sub(FR_MODULUS, 2)) + mstore(add(p, 0xa0), FR_MODULUS) + if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + inv := mload(p) + } + + // ---------- Streaming Keccak256 transcript helpers ---------- + // + // The transcript buffer lives at + // memory[TRANSCRIPT_MPTR..buf_len). On verifier entry it starts + // empty. Each common(input) appends raw bytes. squeeze_*(buf_len) + // computes one Keccak digest, reseeds the buffer with that + // 32-byte digest, and samples a Fq element as + // uint256(digest_be) mod r. + + function transcript_init() -> buf_len { + // Empty transcript buffer starts exactly at TRANSCRIPT_MPTR. + buf_len := TRANSCRIPT_MPTR + } + + // Append one 32-byte big-endian field/transcript word at the + // current end of the transcript buffer. + function common_word(buf_len, word) -> ret { + mstore(buf_len, word) + ret := add(buf_len, 32) + } + + // Absorb a BLS12-381 G1 point in EIP-2537 padded + // uncompressed form (4 calldata words = 128 bytes: + // x_hi || x_lo || y_hi || y_lo, each coord = 16 zero + // pad bytes + 48 big-endian field bytes) into the + // transcript buffer at `buf_len`. + // + // Matches the patched `Hashable for + // midnight_curves::G1Projective::to_input` in + // midnight-proofs, which now emits the same 128-byte form + // (`midfall/proofs/src/transcript/implementors.rs`). The + // previous emitter hashed the 48-byte ZCash compressed + // encoding instead and ran a 384-bit `lex(y) > lex(p − y)` + // ladder + identity flag fixup to derive the sign bit on + // the fly; switching to the uncompressed form drops that + // ladder entirely. + // + // Canonicality: reject non-zero bytes in the top 16 bytes + // of each `_hi` calldata word and reject coordinates + // outside Fp. Normalizing those bytes before hashing would + // make multiple calldata encodings share one transcript. + // + // This helper does not run an independent curve/subgroup + // check. Instead, ProtocolPlan::validate rejects generated + // plans where an absorbed proof commitment would not later be + // consumed by an EIP-2537 G1MSM or pairing path, and those + // precompiles perform the curve/subgroup validation. + // + // The point's uncompressed form remains in calldata; the + // call site is responsible for `calldatacopy`-ing it into + // memory afterwards if it needs the on-curve coordinates. + function common_uncompressed_g1(buf_len, cptr) -> ret { + let x_hi_word := calldataload(cptr) + let x_lo := calldataload(add(cptr, 0x20)) + let y_hi_word := calldataload(add(cptr, 0x40)) + let y_lo := calldataload(add(cptr, 0x60)) + if shr(128, x_hi_word) { revert(0, 0) } + if shr(128, y_hi_word) { revert(0, 0) } + + let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) + let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) + if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { + revert(0, 0) + } + if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { + revert(0, 0) + } + + // Memcpy the 4 calldata words (128 bytes) verbatim + // into the keccak buffer. + calldatacopy(buf_len, cptr, 0x80) + ret := add(buf_len, 0x80) + } + + // One Keccak finalization + reseed. Returns the new buffer + // cursor (= TRANSCRIPT_MPTR + 32) and stores the squeezed Fq at + // `mptr`. + function squeeze_to(buf_len, mptr) -> ret { + let h0 := keccak256(TRANSCRIPT_MPTR, sub(buf_len, TRANSCRIPT_MPTR)) + // Reseed: write the 32-byte digest at start of buffer. + mstore(TRANSCRIPT_MPTR, h0) + let r := FR_MODULUS + // Sample Fq as uint256(keccak_digest_be) mod r. + mstore(mptr, mod(h0, r)) + ret := add(TRANSCRIPT_MPTR, 32) + } + + // ---------- EC primitives (EIP-2537 wrappers) ---------- + // + // These mirror the BN254 helpers but operate on 4-word G1 + // points. They use planned memory windows above Solidity's + // reserved prefix; the streaming transcript buffer is no longer + // needed once all challenges are squeezed. + + // Invert a contiguous run of Fr words in-place using Montgomery's + // batch inversion trick: + // 1. write prefix products to scratch; + // 2. invert the total product once with modexp; + // 3. walk backward to recover each individual inverse. + // + // The function returns a boolean instead of reverting so callers + // can combine it with other `success` plumbing until a section + // boundary decides whether to fail closed. + function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret { + ret := success + if iszero(ret) { leave } + // Memory ranges must be forward and word-aligned by + // construction; a reversed range is always a codegen error. + if lt(mptr_end, mptr_start) { + ret := 0 + leave + } + + let count_bytes := sub(mptr_end, mptr_start) + // Empty batch is valid and leaves memory untouched. + if iszero(count_bytes) { leave } + + // Fast path for a single denominator: avoid prefix scratch and + // just run one modexp inverse in place. + if eq(count_bytes, 0x20) { + let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } + if iszero(x) { + ret := 0 + leave + } + + let single_scratch := scratch_mptr + mstore(add(single_scratch, 0x00), 0x20) + mstore(add(single_scratch, 0x20), 0x20) + mstore(add(single_scratch, 0x40), 0x20) + mstore(add(single_scratch, 0x60), x) + mstore(add(single_scratch, 0x80), sub(r, 2)) + mstore(add(single_scratch, 0xa0), r) + ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + if ret { mstore(mptr_start, mload(single_scratch)) } + leave + } + + // Forward pass: scratch stores prefix products up to, but not + // including, the final element. `gp` becomes the total product. + let gp_mptr := scratch_mptr + let gp := mload(mptr_start) + let mptr := add(mptr_start, 0x20) + for {} lt(mptr, sub(mptr_end, 0x20)) {} { + gp := mulmod(gp, mload(mptr), r) + mstore(gp_mptr, gp) + mptr := add(mptr, 0x20) + gp_mptr := add(gp_mptr, 0x20) + } + gp := mulmod(gp, mload(mptr), r) + // A zero total product means at least one denominator was + // zero, so no batch inverse exists. + if iszero(gp) { + ret := 0 + leave + } + + // Invert the total product once. + mstore(add(gp_mptr, 0x00), 0x20) + mstore(add(gp_mptr, 0x20), 0x20) + mstore(add(gp_mptr, 0x40), 0x20) + mstore(add(gp_mptr, 0x60), gp) + mstore(add(gp_mptr, 0x80), sub(r, 2)) + mstore(add(gp_mptr, 0xa0), r) + ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } + let all_inv := mload(gp_mptr) + + // Backward pass: derive each inverse from the inverted total + // product and the saved prefix products. + let first_mptr := mptr_start + let second_mptr := add(first_mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + for {} lt(second_mptr, mptr) {} { + let inv := mulmod(all_inv, mload(gp_mptr), r) + all_inv := mulmod(all_inv, mload(mptr), r) + mstore(mptr, inv) + mptr := sub(mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + } + let inv_first := mulmod(all_inv, mload(second_mptr), r) + let inv_second := mulmod(all_inv, mload(first_mptr), r) + mstore(first_mptr, inv_first) + mstore(second_mptr, inv_second) + } + + // Final EIP-2537 pairing wrapper. `lhs_mptr` and `rhs_mptr` are + // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. + function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { + ret := success + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } + // Lay out two (G1, G2) pairs at scratch..scratch+0x300: + // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] + // Cancun MCOPY (3 + 3·words gas) replaces what used to + // be a 4-step mstore chain for each G1 (~60 gas) and an + // 8-iter mstore loop for each G2 (~240 gas). Net saving + // here is ~500 gas per ec_pairing call. + let scratch := 0x0320 + mcopy(scratch, lhs_mptr, 0x80) + mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) + mcopy(add(scratch, 0x180), rhs_mptr, 0x80) + mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) + ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := and(ret, eq(returndatasize(), 0x20)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) + if iszero(ret) { revert(0, 0) } + ret := 1 + } + + // ---------- IVC accumulator public-input decoding ---------- + // + // `AssignedForeignPoint` exposes each base-field coordinate + // through `AssignedField::as_public_input`: seven radix-2^56 limbs of + // (coord - 1) are packed four-at-a-time into native field elements. + // The x coordinate's first packed word carries the identity flag by + // adding one raw radix base. Rebuild EIP-2537 padded + // (x_hi, x_lo, y_hi, y_lo) words from that encoding. + // + // Public-input layout for one coordinate: + // word 0: limb_0 | limb_1 << bits | ... up to limbs_per_word + // word 1: next limbs, if any + // + // The limbs are little-endian in the represented integer even + // though calldata words are loaded as big 256-bit values. The loop + // below extracts each limb by shifting inside the packed word and + // reconstructs the full coordinate into the two-word EIP-2537 + // representation expected by the BLS12-381 precompiles. + function load_acc_coord_shifted(src, bits, n, base, limbs_per_word, first_adjust) -> hi, lo { + // Mask for one radix limb, e.g. 2^56 - 1 for the current + // BLS12-381 self-emulation parameters. + let mask := sub(base, 1) + for { let i := 0 } lt(i, n) { i := add(i, 1) } { + // Limb words are little-endian packed inside each Fr + // public input. `first_adjust` removes the identity flag + // base from the first x word when present. + let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { + packed := sub(packed, first_adjust) + } + // Select limb i from its packed field word. The mod/div + // pair maps a limb index to an intra-word limb slot and + // the calldata word containing it. + let limb := and(shr(mul(mod(i, limbs_per_word), bits), packed), mask) + + let shift := mul(i, bits) + // Split the reconstructed 384-bit coordinate into the + // EIP-2537 high/low words expected by the precompiles. + if lt(shift, 256) { + lo := add(lo, shl(shift, limb)) + if gt(add(shift, bits), 256) { + // A limb can straddle the 256-bit low/high split. + // Move the overflow bits into hi. + hi := add(hi, shr(sub(256, shift), limb)) + } + } + if iszero(lt(shift, 256)) { + // Once shift >= 256 the whole limb belongs to hi. + hi := add(hi, shl(sub(shift, 256), limb)) + } + } + } + + // The shifted coordinate codec represents zero as p-1 before the + // final +1 below, so keep this sentinel explicit. + function is_bls_p_minus_one(hi, lo) -> yes { + yes := and(eq(hi, BLS_P_HI), eq(lo, BLS_P_MINUS_ONE_LO)) + } + + // Canonical encoded accumulator identity: + // x = p-1 plus the identity flag in the first packed word, + // y = p-1 with no identity flag. + // It decodes to the EIP-2537 point-at-infinity slot (all zeros). + // + // This fast path is deliberately stricter than "decodes to zero": + // the point at infinity has exactly one accepted public-input + // encoding. Non-canonical zero-like encodings are rejected later. + function is_acc_encoded_identity(src) -> yes { + yes := and( + and( + eq(calldataload(src), BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG), + eq(calldataload(add(src, 0x20)), BLS_P_MINUS_ONE_PACKED_1) + ), + and( + eq(calldataload(add(src, 0x40)), BLS_P_MINUS_ONE_PACKED_0), + eq(calldataload(add(src, 0x60)), BLS_P_MINUS_ONE_PACKED_1) + ) + ) + } + + // Reject unused high bits in the packed public-input words. This + // makes each accumulator point encoding canonical before it reaches + // the precompile-based curve/subgroup validation. + function check_acc_coord_packing(src, bits, n, limbs_per_word) -> ok { + ok := 1 + // Number of packed native-field public-input words occupied by + // one coordinate. + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + for { let word_idx := 0 } lt(word_idx, coord_words) { word_idx := add(word_idx, 1) } { + // The final word may contain fewer than limbs_per_word + // limbs. Any unused high bits must be zero, otherwise the + // same coordinate would have multiple calldata encodings. + let remaining := sub(n, mul(word_idx, limbs_per_word)) + let limbs_in_word := limbs_per_word + if lt(remaining, limbs_per_word) { + limbs_in_word := remaining + } + let used_bits := mul(limbs_in_word, bits) + if lt(used_bits, 256) { + // shl(used_bits, 1) == 2^used_bits. The packed word + // must be strictly less than that bound. + ok := and(ok, lt(calldataload(add(src, mul(word_idx, 0x20))), shl(used_bits, 1))) + } + } + } + + // Decode one shifted coordinate. `allow_id` is true only for x, + // because the identity flag lives in x's first packed word. + function load_acc_coord(src, allow_id, bits, n, base, limbs_per_word) -> ok, hi, lo, is_id { + ok := check_acc_coord_packing(src, bits, n, limbs_per_word) + if and(allow_id, iszero(lt(calldataload(src), base))) { + // Probe the x identity flag by removing one radix base and + // checking whether the adjusted coordinate is p-1. + // + // `calldataload(src) >= base` is a cheap prefilter: only x + // can carry this flag, and adding one radix base must make + // the first packed word at least base. + let adj_hi, adj_lo := load_acc_coord_shifted(src, bits, n, base, limbs_per_word, base) + is_id := is_bls_p_minus_one(adj_hi, adj_lo) + } + + // Decode again with the identity adjustment applied only when + // the canonical identity flag was actually detected. + hi, lo := load_acc_coord_shifted(src, bits, n, base, limbs_per_word, mul(is_id, base)) + ok := and( + ok, + // Coordinate must be in the BLS12-381 base field, i.e. + // <= p - 1 in split hi/lo form. + or(lt(hi, BLS_P_HI), and(eq(hi, BLS_P_HI), iszero(gt(lo, BLS_P_MINUS_ONE_LO)))) + ) + + let was_p_minus_one := is_bls_p_minus_one(hi, lo) + if was_p_minus_one { + // Shifted encoding maps p-1 back to zero. + hi := 0 + lo := 0 + } + if iszero(was_p_minus_one) { + // All other coordinates are encoded as coord - 1, so add + // one back with carry into the high word. + let next_lo := add(lo, 1) + hi := add(hi, lt(next_lo, lo)) + lo := next_lo + } + + // EIP-2537 pads each 48-byte Fp coordinate to 64 bytes, + // so the high word must fit in its low 128 bits. + // This also catches impossible reconstructions above 384 bits. + ok := and(ok, lt(hi, shl(128, 1))) + } + + // Decode a public accumulator point into an EIP-2537 4-word G1 + // slot. Non-identity points are curve/subgroup checked later by + // routing them through G1MSM. + function load_acc_point(dst, src, bits, n, base) -> ok, is_id { + // Prefer the canonical all-coordinate identity encoding before + // attempting coordinate-level shifted decoding. This accepts + // the point at infinity only in the exact form generated by the + // circuit's public-input codec. + is_id := is_acc_encoded_identity(src) + if is_id { + ok := 1 + // EIP-2537 encodes G1 identity as four zero words: + // x_hi = x_lo = y_hi = y_lo = 0. + mstore(dst, 0) + mstore(add(dst, 0x20), 0) + mstore(add(dst, 0x40), 0) + mstore(add(dst, 0x60), 0) + } + if iszero(is_id) { + // x occupies coord_words packed public-input words; y + // starts immediately after x. + let limbs_per_word := 4 + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + // Only x may carry the identity flag. y must decode as a + // normal shifted coordinate. + let x_ok, x_hi, x_lo, x_is_id := load_acc_coord(src, 1, bits, n, base, limbs_per_word) + let y_ok, y_hi, y_lo, y_id := load_acc_coord( + add(src, mul(coord_words, 0x20)), + 0, + bits, + n, + base, + limbs_per_word + ) + // y_id is always zero because allow_id was false, but the + // tuple shape is shared with x decoding. + pop(y_id) + ok := and(x_ok, y_ok) + is_id := x_is_id + + if is_id { + // If x carried the identity flag, both decoded + // coordinates must be zero after shifting. Any other y + // value would be a malformed infinity encoding. + ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) + mstore(dst, 0) + mstore(add(dst, 0x20), 0) + mstore(add(dst, 0x40), 0) + mstore(add(dst, 0x60), 0) + } + if iszero(is_id) { + // The coordinate codec maps encoded p-1 to decoded + // zero. EIP-2537 reserves affine (0,0) for the point + // at infinity, so a decoded infinity is only valid + // when the canonical accumulator identity encoding + // was used above. + let decoded_zero := iszero(or(or(x_hi, x_lo), or(y_hi, y_lo))) + ok := and(ok, iszero(decoded_zero)) + // Store the affine point in the exact precompile input + // layout: x_hi, x_lo, y_hi, y_lo. + mstore(dst, x_hi) + mstore(add(dst, 0x20), x_lo) + mstore(add(dst, 0x40), y_hi) + mstore(add(dst, 0x60), y_lo) + } + } + } + // Validate and prepare the public accumulator equation before the + // main transcript starts. This fails malformed public inputs early + // and writes ACC_LHS_MPTR / ACC_RHS_MPTR for final pairing batching. + // + // The accumulator public input represents an equality of two G1 + // commitments used by the recursive KZG accumulator. This helper: + // 1. decodes carried public G1 points from shifted limbs; + // 2. forces every decoded point through EIP-2537 G1MSM so the + // precompile validates curve/subgroup membership; + // 3. folds the RHS carried point and fixed-base scalar tail into + // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for + // randomized batching in FinalPairing.yul. + function validate_public_accumulator(success, r) -> out { + out := success + let bits := 56 + let n := 7 + // The BLS12-381 self-emulation currently exposes Fp + // coordinates as 7 radix-2^56 limbs. + let limb_base := shl(bits, 1) + let limbs_per_word := 4 + let coord_words := div(add(n, sub(limbs_per_word, 1)), limbs_per_word) + // acc_offset is generated from the VK/protocol shape and + // points into the ABI `instances` array. + let acc_instance_ptr := add(INSTANCE_CPTR, 0x0160) + + // LHS layout: point limbs (x,y), then either an explicit + // scalar word or an implicit unit scalar for already-collapsed + // point-pair public inputs. + // The scalar pointer is computed unconditionally; the rendered + // branch below decides whether to read it or use scalar 1. + let lhs_scalar_ptr := add(acc_instance_ptr, mul(mul(2, coord_words), 0x20)) + let lhs_ok, lhs_is_id := load_acc_point(ACC_LHS_MPTR, acc_instance_ptr, bits, n, limb_base) + out := and(out, lhs_ok) + // Shared scratch for one-pair LHS validation and the later + // variable-length RHS MSM. + let acc_scratch := 0xb140 + { + // Already-collapsed point-pair layout: carried scalars are + // implicit one. + let lhs_scalar := 1 + // Identity status is useful for decoding checks above, but + // validation still goes through G1MSM for all points. + pop(lhs_is_id) + // Always route the decoded carried point through G1MSM, + // even for identity points and zero/one scalars. The + // precompile is the on-curve/subgroup validator for this + // public-input point; skipping it would let a malformed + // non-identity point hide behind scalar 0. + mcopy(acc_scratch, ACC_LHS_MPTR, 0x80) + mstore(add(acc_scratch, 0x80), lhs_scalar) + if out { + // Single-pair MSM output overwrites ACC_LHS_MPTR with + // lhs_scalar * decoded_lhs. If lhs_scalar is one, this + // is also a curve/subgroup validation round-trip. + out := staticcall(gas(), 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) + out := and(out, eq(returndatasize(), 0x80)) + } + } + // RHS layout for this generated verifier is an already + // collapsed point pair: lhs point, rhs point. Both carried + // scalars are implicit one, and there is no fixed-base scalar + // tail. + let rhs_instance_ptr := lhs_scalar_ptr + // RHS scalar, when present, immediately follows the RHS point + // limbs. The fixed-base scalar tail starts after it. + let rhs_scalar_ptr := add(rhs_instance_ptr, mul(mul(2, coord_words), 0x20)) + let rhs_ok, rhs_is_id := load_acc_point(ACC_RHS_MPTR, rhs_instance_ptr, bits, n, limb_base) + out := and(out, rhs_ok) + // acc_pair_ptr appends (G1, scalar) pairs into acc_scratch for + // one final RHS MSM. + let acc_pair_ptr := acc_scratch + { + // Implicit unit scalar for already-collapsed point pairs. + let rhs_scalar := 1 + pop(rhs_is_id) + // Keep the carried RHS point in the MSM input even when + // it is encoded as identity or has scalar 0/1, so EIP-2537 + // validates every decoded public accumulator point before + // it can affect, or be erased from, the pairing batch. + mcopy(acc_pair_ptr, ACC_RHS_MPTR, 0x80) + mstore(add(acc_pair_ptr, 0x80), rhs_scalar) + // Move to the next (G1, scalar) pair slot. + acc_pair_ptr := add(acc_pair_ptr, 0xa0) + } + // Total byte length of the appended RHS MSM input pairs. This + // is at least one pair because the carried RHS point is always + // appended; keep the guard for synthetic render configurations. + let acc_msm_len := sub(acc_pair_ptr, acc_scratch) + if acc_msm_len { + // Fold the carried RHS point and any generated fixed-base + // tail into ACC_RHS_MPTR. The later final pairing block + // randomizes this equation together with the KZG pairing. + if out { + // Output overwrites ACC_RHS_MPTR with: + // rhs_scalar * carried_rhs + // + sum_i fixed_scalar_i * fixed_base_i + // + // The precompile also validates every nonzero fixed + // base embedded by codegen and the carried RHS point. + out := staticcall( + gas(), + 0x0c, + acc_scratch, + acc_msm_len, + ACC_RHS_MPTR, + 0x80 + ) + out := and(out, eq(returndatasize(), 0x80)) + } + } + // The caller checks `out` and reverts before transcript work if + // any decode, canonicality, or precompile validation failed. + } + + + + let r := FR_MODULUS + let success := true + + + + // =============================================================== + // VK loading: either bake in the embedded VK bytes or fetch + // them from the linked AUTHORIZED_VK contract. + // + // This is the first verifier phase after helper definitions. Its + // job is to make the generated VK payload available at VK_MPTR in + // one canonical memory layout, regardless of whether this render + // embeds the VK directly or links a separate Halo2VerifyingKey + // contract. + // + // Later template partials treat VK_MPTR as already populated with: + // - header words: vk_digest, domain data, accumulator metadata; + // - BLS12-381 base points used by the final pairing; + // - compact quotient VM constants/program bytes, when enabled; + // - fixed and permutation commitments in 4-word G1 slots. + // =============================================================== + { + // Re-check the pinned VK dependency on every proof. The + // constructor check catches normal deployment mistakes, while + // this fresh check hardens forks or same-transaction edge + // cases where code at the authorized address could differ + // from the runtime originally pinned by this verifier. + // + // EXPECTED_VK_LENGTH includes the leading INVALID byte in the + // Halo2VerifyingKey runtime. EXPECTED_VK_CODEHASH_WORD is the + // full runtime hash, not only the payload hash. + if iszero(and( + eq(extcodesize(vk), EXPECTED_VK_LENGTH), + eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) + )) { revert(0, 0) } + // Runtime byte 0 is INVALID so direct calls cannot execute the + // payload. Copy from byte 1 into VK_MPTR to reconstruct the + // exact payload layout used by the embedded branch. + extcodecopy(vk, VK_MPTR, 0x01, EXPECTED_VK_PAYLOAD_LENGTH) + + // Cross-check loaded VK header words against the verifier + // constants used by later parser, domain, and accumulator + // paths. Codehash pinning protects the external VK address; + // these checks catch generator drift before calldata parsing + // chooses a stale schema. + success := and(success, eq(mload(NUM_INSTANCES_MPTR), 19)) + success := and(success, eq(mload(K_MPTR), 20)) + success := and(success, eq(mload(HAS_ACCUMULATOR_MPTR), 1)) + success := and(success, eq(mload(ACC_OFFSET_MPTR), 11)) + success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 7)) + success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 56)) + if iszero(success) { revert(0, 0) } + // + // The checks below validate the dynamic ABI envelope before the + // transcript parser starts walking raw calldata: + // - proof bytes length equals the generated proof layout; + // - instance array length equals the generated public input + // count; + // - total calldata length has no missing or trailing words. + // + // `success` is folded through `and` for consistency with later + // sections, then immediately enforced at the end of this block. + // A failure here means the verifier is not looking at the proof + // shape it was generated to parse. + success := and(success, eq(0x1e60, calldataload(PROOF_LEN_CPTR))) + success := and(success, eq(19, calldataload(NUM_INSTANCE_CPTR))) + // Calldata must contain exactly the ABI selector, proof bytes, + // instance-array length, and generated number of instance + // words. Any trailing bytes fail closed. + success := and( + success, + eq(calldatasize(), add(INSTANCE_CPTR, 0x0260)) + ) + // Stop before any transcript absorption if the ABI/proof shape + // is not exactly the generated one. + if iszero(success) { revert(0, 0) } + } + // Fail malformed accumulator public inputs before transcript, + // quotient, PCS, and final pairing work. The late accumulator block + // only batches these already-validated G1 outputs into the final + // pairing equation. + // + // Accumulator validation decodes shifted public-input limbs into + // EIP-2537 G1 slots, checks canonical encodings, and routes points + // through G1MSM for curve/subgroup validation. Doing it here means + // invalid accumulator public inputs cannot influence transcript + // challenge derivation or waste gas in later quotient/PCS work. + // validate_public_accumulator returns a boolean to share the same + // success-plumbing style as other helper calls; this boundary is + // where the verifier converts failure to a revert. + success := validate_public_accumulator(success, r) + if iszero(success) { revert(0, 0) } + + // =============================================================== + // Transcript: VK digest + instances + proof. + // + // This block is the Solidity mirror of the native Midfall verifier + // transcript schedule. It does three jobs at once: + // + // 1. Absorb public data and proof bytes into the streaming + // Keccak transcript in exactly the native order. + // 2. Decode/range-check proof scalars and canonical G1 calldata. + // 3. Copy proof commitments/evaluations into planned memory + // slots consumed by Lagrange, quotient, PCS, and pairing + // blocks later in the verifier. + // + // `buf_len` is a write cursor into the transcript buffer. The + // helper functions append bytes and return the new cursor; squeeze + // helpers hash memory[TRANSCRIPT_MPTR..buf_len), reseed the buffer + // with the digest, and write the sampled Fr challenge to memory. + // =============================================================== + let buf_len := transcript_init() + // VK_DIGEST_MPTR holds the digest as a BE 32-byte word (the + // VK contract stores it via `mstore`, which matches the + // Keccak Fq transcript input). + // + // This digest commits to the verifier key / constraint system + // before any proof material is read. + buf_len := common_word(buf_len, mload(VK_DIGEST_MPTR)) + + // Absorb committed_pi = G1Affine::identity() when the + // `committed-instances` feature is on in midnight-proofs. + // Under the patched `Hashable::to_input` (see + // `midfall/proofs/src/transcript/implementors.rs`), the + // identity hashes as 128 zero bytes (EIP-2537 (0,0) + // convention), NOT the 48-byte ZCash compressed form + // 0xc0||47*0x00 that the previous emitter produced. + // Native verifier absorbs this BEFORE the instance count. + { + // 128 zero bytes: zero out 4 consecutive 32-byte words + // at buf_len. + // This is a raw transcript absorb, not a memory slot kept for + // later elliptic-curve operations. + mstore(buf_len, 0) + mstore(add(buf_len, 0x20), 0) + mstore(add(buf_len, 0x40), 0) + mstore(add(buf_len, 0x60), 0) + buf_len := add(buf_len, 0x80) + } + + { + // Native verifier absorbs a length scalar before instance + // values; Keccak Fq transcript input is canonical BE. + // The ABI length was already checked against this generated + // constant in VkLoading.yul. + buf_len := common_word(buf_len, 19) + + let instance_cptr := INSTANCE_CPTR + for { let instance_cptr_end := add(instance_cptr, 0x0260) } + lt(instance_cptr, instance_cptr_end) + { instance_cptr := add(instance_cptr, 0x20) } { + let inst_be := calldataload(instance_cptr) + // Public inputs are BLS12-381 scalar-field elements. They + // must be canonical before transcript absorption; accepting + // non-canonical encodings would admit transcript aliases. + success := and(success, lt(inst_be, r)) + // Instances are passed BE in calldata, matching the + // Keccak Fq transcript input. + buf_len := common_word(buf_len, inst_be) + } + if iszero(success) { revert(0, 0) } + } + + // =============================================================== + // Per-user-phase reads + challenge squeezes. + // + // Each proof G1 is already EIP-2537 padded in calldata. The + // verifier validates and absorbs that 128-byte form, then copies + // it into the corresponding per-category MPTR. The PCS / + // quotient-fold blocks below dereference those MPTRs. + // + // All G1 reads follow the same pattern: + // - common_uncompressed_g1 canonicalizes/range-checks the two Fp + // coordinates and appends the exact 128 calldata bytes; + // - calldatacopy stores the same 4-word G1 slot in planned + // memory for later EIP-2537 precompile calls; + // - proof_cptr advances by one G1 byte length. + // =============================================================== + // proof_cptr walks the raw proof bytes inside the ABI `bytes` + // payload. Every successful read advances it exactly once, and the + // final equality check below proves the parser consumed the whole + // generated proof layout. + let proof_cptr := PROOF_CPTR + // advice_walk mirrors proof commitment order into the contiguous + // G1 commitment memory region used by PCS and quotient folding. + let advice_walk := ADVICE_COMMS_MPTR_BASE + // ---- User phase 1 ---- + // Advice commitments for this phase are absorbed before the phase's + // challenge squeezes. The number of commitments and challenges is + // generated from the protocol plan. + for { let end := add(proof_cptr, 0x0780) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + // Store the commitment at its phase-ordered advice slot. + calldatacopy(advice_walk, proof_cptr, 0x80) + advice_walk := add(advice_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- theta ---- + // From this point onward the transcript alternates between + // squeezed challenges and proof commitments exactly as + // midnight-proofs does in `plonk/verifier.rs`. + // theta batches lookup input expressions. + buf_len := squeeze_to(buf_len, THETA_MPTR) + // ---- multiplicities (one G1 per lookup) ---- + // Lookup multiplicity commitments are absorbed after theta and + // copied into their own contiguous G1 region. + let lookup_m_walk := LOOKUP_M_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0100) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_m_walk, proof_cptr, 0x80) + lookup_m_walk := add(lookup_m_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- beta, gamma ---- + // beta and gamma are the permutation/lookup randomizers. They are + // squeezed after lookup multiplicities and before permutation + // product commitments, matching the native verifier schedule. + buf_len := squeeze_to(buf_len, BETA_MPTR) + buf_len := squeeze_to(buf_len, GAMMA_MPTR) + // ---- permutation Z products ---- + // Permutation product commitments are used by the permutation + // identities in the quotient numerator and later by PCS openings. + let perm_z_walk := PERM_Z_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0300) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(perm_z_walk, proof_cptr, 0x80) + perm_z_walk := add(perm_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // ---- lookup helpers + accumulators (per-lookup) ---- + // Each lookup contributes zero or more helper commitments followed + // by its lookup accumulator Z commitment. The generated layout keeps + // helper commitments and accumulator commitments in separate memory + // regions because the quotient/PCS schedules address them + // differently. + let lookup_helper_walk := LOOKUP_HELPER_COMMS_MPTR_BASE + let lookup_z_walk := LOOKUP_Z_COMMS_MPTR_BASE + // lookup 0: 1 helper(s) + 1 acc + // Helper commitments for lookup 0. + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_helper_walk, proof_cptr, 0x80) + lookup_helper_walk := add(lookup_helper_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // Accumulator commitment for lookup 0. This is + // always one G1 when the lookup section is present. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_z_walk, proof_cptr, 0x80) + lookup_z_walk := add(lookup_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + // lookup 1: 1 helper(s) + 1 acc + // Helper commitments for lookup 1. + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_helper_walk, proof_cptr, 0x80) + lookup_helper_walk := add(lookup_helper_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + // Accumulator commitment for lookup 1. This is + // always one G1 when the lookup section is present. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(lookup_z_walk, proof_cptr, 0x80) + lookup_z_walk := add(lookup_z_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // ---- trash_challenge ---- + // Midnight squeezes this challenge unconditionally, even when the + // circuit has no trash arguments. + // Keeping this squeeze unconditional preserves transcript + // compatibility across circuits with and without trash columns. + buf_len := squeeze_to(buf_len, TRASH_CHALLENGE_MPTR) + // ---- trashcans ---- + // Trashcan commitments are optional, but when present they are + // absorbed before y so the quotient batching challenge binds them. + let trashcan_walk := TRASHCAN_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x80) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(trashcan_walk, proof_cptr, 0x80) + trashcan_walk := add(trashcan_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- y ---- + // y batches all quotient identities. Quotient commitments are read + // only after y is sampled, matching the Rust verifier flow. + buf_len := squeeze_to(buf_len, Y_MPTR) + + // ---- quotient commitment(s) ---- + // Each uncompressed quotient commitment is calldatacopied directly to + // QUOTIENT_LIMB_COMMS_MPTR_BASE; the Horner fold below reads + // them back from memory. common_uncompressed_g1 absorbs the + // 128-byte calldata form into the transcript verbatim. + // + // Multi-limb quotient mode reads several Q_i commitments; single-H + // mode renders this loop with one limb. + let quotient_walk := QUOTIENT_LIMB_COMMS_MPTR_BASE + for { let end := add(proof_cptr, 0x0200) } + lt(proof_cptr, end) + {} { + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(quotient_walk, proof_cptr, 0x80) + quotient_walk := add(quotient_walk, 0x80) + proof_cptr := add(proof_cptr, 0x80) + } + + // ---- x ---- + // x is the main evaluation point. Values read after this point are + // alleged polynomial evaluations at x or derived PCS openings. + buf_len := squeeze_to(buf_len, X_MPTR) + + // ---- evaluations ---- + // Optimisation H3: the off-chain Solidity proof shim rewrites + // proof scalars into BE calldata words. Spill each decoded eval + // into REVERSED_EVALS_MPTR in the same iteration we range-check + // it, so downstream references can use cheap mload. + // + // The Rust verifier conceptually reads evaluations in query order. + // The lowering plan arranges REVERSED_EVALS_MPTR in the order used + // by the quotient VM/direct evaluator, hence the generated name. + { + let eval_buf := REVERSED_EVALS_MPTR + for { let end := add(proof_cptr, 0x0cc0) } + lt(proof_cptr, end) + {} { + let eval := calldataload(proof_cptr) + // Proof evaluation scalars must be canonical Fr elements + // before they are absorbed or made available to quotient + // reconstruction. + if iszero(lt(eval, r)) { revert(0, 0) } + // Spill for quotient numerator and PCS codegen. + mstore(eval_buf, eval) + eval_buf := add(eval_buf, 0x20) + // Absorb the exact BE field word used by the native + // Keccak transcript. + buf_len := common_word(buf_len, eval) + proof_cptr := add(proof_cptr, 0x20) + } + } + + // ---- x1, x2 ---- + // x1 and x2 batch the KZG multi-opening reduction. They are + // squeezed after all polynomial evaluations are absorbed. + buf_len := squeeze_to(buf_len, X1_MPTR) + buf_len := squeeze_to(buf_len, X2_MPTR) + + // ---- f_com (1 uncompressed G1) ---- + // f_com is the commitment to the batched polynomial used by the PCS + // multi-open protocol. It is both transcript material and later + // pairing/MSM input. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(F_COM_MPTR, proof_cptr, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // ---- x3 ---- + // x3 is the PCS evaluation point for f_com. + buf_len := squeeze_to(buf_len, X3_MPTR) + // truncated-challenges mirrors midnight-proofs + // proofs/src/poly/kzg/mod.rs: + // - x3 is the f_com evaluation point and is truncated + // immediately after squeeze. + // - x1 and x4 remain full squeezed Fr words, but later PCS + // batching stores truncate(x1^i) and truncate(x4^i) while + // keeping the internal power accumulators full precision. + // This direct x3 mask is therefore one part of the PCS truncation + // rule, not the only truncated value used by the verifier. + mstore(X3_MPTR, and(mload(X3_MPTR), 0xffffffffffffffffffffffffffffffff)) + + // ---- q_evals (one Fq per point set) ---- + // q_evals are not spilled into REVERSED_EVALS_MPTR because the PCS + // emitter reads them as a contiguous calldata range from the saved + // Q_EVAL_CPTR_MPTR cursor. + // + // Each q_eval is the claimed evaluation for one prepared point set + // in the KZG multi-open reduction. They are still transcript + // material and must be range-checked as Fr scalars. + mstore(Q_EVAL_CPTR_MPTR, proof_cptr) + for { let end := add(proof_cptr, 0xa0) } + lt(proof_cptr, end) + {} { + let eval := calldataload(proof_cptr) + // Canonical Fr check before transcript absorption. + if iszero(lt(eval, r)) { revert(0, 0) } + buf_len := common_word(buf_len, eval) + proof_cptr := add(proof_cptr, 0x20) + } + + // ---- x4 ---- + // x4 is the final PCS batching challenge, sampled after q_evals + // and before the opening proof point pi. + buf_len := squeeze_to(buf_len, X4_MPTR) + + // ---- pi (1 uncompressed G1) ---- + // pi is the KZG opening proof commitment. It is the last proof + // object absorbed into the transcript and later becomes one side of + // the final pairing check. + buf_len := common_uncompressed_g1(buf_len, proof_cptr) + calldatacopy(PI_MPTR, proof_cptr, 0x80) + proof_cptr := add(proof_cptr, 0x80) + + // The hand-rolled proof parser must consume exactly the ABI + // `proof` bytes before the `instances` length word. This is + // redundant with the generated proof length today, but makes + // future proof-layout drift fail closed. + // + // NUM_INSTANCE_CPTR is the calldata word immediately after the + // dynamic proof bytes payload. If proof_cptr lands anywhere else, + // some section was under-read or over-read. + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + + // `success` carries deferred canonicality failures from public + // instance reads. G1/proof scalar helpers revert immediately. + if iszero(success) { revert(0, 0) } + + // =============================================================== + // Lagrange & instance-evaluation block (pure Fr arithmetic). + // =============================================================== + { + let k := 20 + let x := mload(X_MPTR) + // Compute x^n by repeated squaring, with n = 2^k. + let x_n := x + for { let idx := 0 } lt(idx, k) { idx := add(idx, 1) } { + x_n := mulmod(x_n, x_n, r) + } + + let omega := mload(OMEGA_MPTR) + + // First pass writes denominators (x - omega_i) for every + // Lagrange value needed below, then appends x^n - 1. The + // batch inversion pass turns all of them into inverses in one + // modexp call. + let mptr := X_N_MPTR + let mptr_end := add(mptr, 0x03a0) + for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } { + mstore(mptr, addmod(x, sub(r, pow_of_omega), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) + success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + + // Convert inverted denominators into Lagrange evaluations: + // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). + mptr := X_N_MPTR + let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) + for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } { + mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + + // l_blind is the sum of the negative-rotation Lagrange terms + // used by the midnight-proofs blinding identity. + let l_blind := mload(add(X_N_MPTR, 0x20)) + let l_i_cptr := add(X_N_MPTR, 0x40) + for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + lt(l_i_cptr, l_i_cptr_end) + { l_i_cptr := add(l_i_cptr, 0x20) } { + l_blind := addmod(l_blind, mload(l_i_cptr), r) + } + + // Public instance polynomial evaluation at x. Instance words + // have already been range-checked and absorbed in transcript + // order; this loop only forms the linear combination. + let instance_eval := 0 + for { + let instance_cptr := INSTANCE_CPTR + let instance_cptr_end := add(instance_cptr, 0x0260) + } + lt(instance_cptr, instance_cptr_end) + { instance_cptr := add(instance_cptr, 0x20) + l_i_cptr := add(l_i_cptr, 0x20) } { + instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r) + } + + // Persist the derived values into named memory slots consumed + // by quotient reconstruction and PCS preparation. + let x_n_minus_1_inv := mload(mptr_end) + let l_last := mload(X_N_MPTR) + let l_0 := mload(add(X_N_MPTR, 0x0140)) + + mstore(X_N_MPTR, x_n) + mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) + mstore(L_LAST_MPTR, l_last) + mstore(L_BLIND_MPTR, l_blind) + mstore(L_0_MPTR, l_0) + mstore(INSTANCE_EVAL_MPTR, instance_eval) + } + + if iszero(success) { revert(0, 0) } + + // Optional quotient helper functions. Each one is rendered only + // when the Rust lowering pass recognized the corresponding + // expression shape in this generated verifier. They are pure Fr + // helpers and share the same FR_MODULUS as the surrounding + // numerator block. + // VK-specialized identity helper for Poseidon S-box terms. + // + // Rust source shape: + // circuits/src/hash/poseidon/poseidon_chip.rs::sbox + // full_round_gate / partial_round_gate + // circuits/src/hash/poseidon/round_skips.rs::RoundId + // + // The Rust verifier only sees this as an Expression tree from + // `vk.cs.gates`; the generator emits q_pow5 after recognizing five + // equal multiplicative factors. It is a codegen shortcut for x^5, + // not a separate verifier rule. + function q_pow5(x) -> z { + let q_r := FR_MODULUS + let x2 := mulmod(x, x, q_r) + z := mulmod(x, mulmod(x2, x2, q_r), q_r) + } // =============================================================== + // Batched identity numerator / linearization target. + // + // This block does not evaluate the quotient polynomial h(x), and + // the proof does not provide an h(x) scalar to trust. Instead it: + // + // 1. Reconstructs the y-batched constraint numerator nu_y(x) + // from the alleged polynomial evaluations read after the + // transcript sampled x. + // 2. Stores -nu_y(x) as the expected opening scalar for the + // linearized commitment. + // + // The commitment side is built in the next block from the quotient + // limb commitments as (1 - x^n) * Σ_i x_split^i * Q_i, plus any + // simple-selector commitments. The PCS check later binds that + // linearized commitment to this expected scalar at x. + // + // Rust source-of-truth: + // - verifier.rs reads quotient commitments, samples x, then + // reads/computes all evaluations used below. + // - mod.rs::partially_evaluate_identities returns identities in + // gate, permutation, lookup, trash order. + // - linearization/verifier.rs::compute_linearization_commitment + // reverse-folds those identities by powers of y, sends + // simple-selector identities to selector commitment scalars, + // and subtracts fully-evaluated identities into expected_eval. + // + // This template is shared by the monolithic and external quotient + // paths. In the external path, Halo2QuotientEvaluator first copies + // the verifier memory frame into the same generated addresses. + // + // Runtime inputs expected to exist before this block starts: + // - `r` is the BLS12-381 scalar-field modulus. + // - Y_MPTR holds the quotient batching challenge y. + // - X_MPTR, L_*_MPTR, INSTANCE_EVAL_MPTR, and + // REVERSED_EVALS_MPTR hold values parsed or derived by the + // main verifier after the transcript sampled x. + // - VK_MPTR holds the pinned VK payload; in compact mode that + // payload includes the quotient constant table and bytecode. + // + // Runtime outputs written by this block: + // - QUOTIENT_EVAL_MPTR receives the scalar expected opening for + // the linearized commitment, namely -nu_y(x). + // - SELECTOR_ACC_MPTR[0..num_simple_selectors) receives one + // linearization scalar per generated simple selector. + // + // Line-by-line reading conventions used below: + // + // * Every runtime value is one canonical Fr element stored in a + // 256-bit EVM memory word. The small integer operands decoded + // from q_program are never field values; they are pointers, + // constant-table slots, selector indexes, offsets, or counts. + // + // * `mload(ptr)` is the only way the VM turns a small pointer + // operand into a real 255-bit field element. The value loaded + // from memory is then combined with `addmod(..., r)` or + // `mulmod(..., r)`, so every arithmetic line is reduced modulo + // the BLS12-381 scalar-field order. + // + // * `q_top` is the cached top of the VM operand stack. When an + // opcode needs to push while `q_top` is already live, the old + // value is written to `q_sp` and `q_sp` is advanced by one + // word. Binary `ADD`/`MUL` move `q_sp` back by one word and + // combine that spilled value with `q_top`. + // + // * Identity boundaries are explicit. Expression opcodes leave + // one value in `q_top`; `FOLD_MAIN` or `FOLD_SELECTOR` consumes + // it and advances the global y-batch position. Native callback + // opcodes are only emitted at empty-stack boundaries and run + // generated Yul that performs the same fold side effects. + // + // * The generated Solidity source intentionally emits comments + // before opcode cases. Those comments are documentation only: + // they do not affect bytecode, but they make rendered verifier + // assembly readable without jumping back to Rust codegen. + // =============================================================== + { + // Compact quotient-program mode. + // + // The largest identity expressions are not all emitted as + // unrolled Yul. Instead, most arithmetic is encoded as a small + // q_program bytecode stored in the VK payload. This block + // interprets that program, while selected heavy identities may + // still be emitted as native callbacks for gas. + // + // Compact mode is a code-size trade: short bytecode operands + // name already-planned memory slots, and the interpreter turns + // those names into Fr arithmetic. The opcode stream is fully + // generated and pinned by the VK/runtime codehash; no proof + // calldata can alter control flow. + // Load the quotient batching challenge used by every fold. + let y := mload(Y_MPTR) + + // q_const_mptr points to Fr constants used by the VM. + // q_program_mptr points to the bytecode stream. + // Constants are stored as consecutive 32-byte Fr words. + let q_const_mptr := 0x3a60 + // Program bytes are also stored in the VK payload, packed into + // 32-byte words by PackedProgramCodec. + let q_program_mptr := 0x50a0 + // Running Horner accumulator for fully evaluated identities. + // After all identities, this is nu_y(x) for the `None` + // identity group. + // Initialize A = 0 before scanning the identity stream. + mstore(0xb280, 0) + // Simple selectors are grouped into separate linearization + // buckets. They start at zero for every proof. + // q_sel_zero_off walks selector bucket byte offsets. + for { let q_sel_zero_off := 0 } lt(q_sel_zero_off, 0x0140) { q_sel_zero_off := add(q_sel_zero_off, 0x20) } { + // B_s = 0 for each simple selector bucket. + mstore(add(SELECTOR_ACC_MPTR, q_sel_zero_off), 0) + } + // Codegen knows the selector identity positions. Precompute + // the y^k powers needed for selector gap and tail updates, + // avoiding a runtime y^-1 modexp and per-identity selector + // scale maintenance. + { + // q_y_power holds y^i at the current loop index. + let q_y_power := 1 + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0xb2c0, 1) + // Start at i=1 because y^0 = 1 is written above. + for { let q_y_power_i := 1 } lt(q_y_power_i, 49) { q_y_power_i := add(q_y_power_i, 1) } { + // Advance from y^(i-1) to y^i modulo Fr. + q_y_power := mulmod(q_y_power, y, r) + // Store y^i at selector_power_mptr + 32*i. + mstore(add(0xb2c0, shl(5, q_y_power_i)), q_y_power) + } + } + + // Direct inline prefix. These identities are generated as Yul + // before entering the VM. They use the same fold snippets as + // VM/native identities, so they occupy the same y-batch order. + { + let var0 := 0x1 + let f_3 := mload(0x9ac0) + let f_4 := mload(0x99c0) + let a_0 := mload(0x94a0) + let var1 := mulmod(f_4, a_0, r) + let var2 := addmod(f_3, var1, r) + let f_5 := mload(0x99e0) + let a_1 := mload(0x94c0) + let var3 := mulmod(f_5, a_1, r) + let var4 := addmod(var2, var3, r) + let f_6 := mload(0x9a00) + let a_2 := mload(0x94e0) + let var5 := mulmod(f_6, a_2, r) + let var6 := addmod(var4, var5, r) + let f_7 := mload(0x9a20) + let a_3 := mload(0x9500) + let var7 := mulmod(f_7, a_3, r) + let var8 := addmod(var6, var7, r) + let f_8 := mload(0x9a40) + let a_4 := mload(0x9520) + let var9 := mulmod(f_8, a_4, r) + let var10 := addmod(var8, var9, r) + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var11 := mulmod(f_0, a_0_next_1, r) + let var12 := addmod(var10, var11, r) + let f_1 := mload(0x9a80) + let var13 := mulmod(f_1, a_0, r) + let var14 := mulmod(var13, a_1, r) + let var15 := addmod(var12, var14, r) + let f_2 := mload(0x9aa0) + let var16 := mulmod(f_2, a_0, r) + let var17 := mulmod(var16, a_2, r) + let var18 := addmod(var15, var17, r) + let var19 := mulmod(var0, var18, r) + mstore(0xb8e0, var19) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_1 := mload(0x94c0) + let a_2 := mload(0x94e0) + let var1 := addmod(a_1, a_2, r) + let a_3 := mload(0x9500) + let var2 := addmod(0, sub(r, a_3), r) + let var3 := addmod(var1, var2, r) + let a_4 := mload(0x9520) + let var4 := addmod(0, sub(r, a_4), r) + let var5 := addmod(var3, var4, r) + let var6 := mulmod(var0, var5, r) + mstore(0xb8e0, var6) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let f_4 := mload(0x99c0) + let var1 := addmod(a_0, f_4, r) + let a_0_next_1 := mload(0x9540) + let var2 := addmod(0, sub(r, a_0_next_1), r) + let var3 := addmod(var1, var2, r) + let var4 := mulmod(var0, var3, r) + mstore(0xb8e0, var4) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + { + let var0 := 0x1 + let a_1 := mload(0x94c0) + let f_5 := mload(0x99e0) + let var1 := addmod(a_1, f_5, r) + let a_1_next_1 := mload(0x9560) + let var2 := addmod(0, sub(r, a_1_next_1), r) + let var3 := addmod(var1, var2, r) + let var4 := mulmod(var0, var3, r) + mstore(0xb8e0, var4) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + + // VM registers: + // q_pc current bytecode pointer + // q_end end of bytecode stream + // q_sp memory stack pointer for non-top stack values + // q_top cached top-of-stack value + // q_has_top whether q_top currently holds a stack value + // + // The cached top reduces memory traffic in the interpreter. + // q_sp's registered range must cover the interpreted operand + // stack plus any native callback scratch that reuses this base + // pointer. In particular, the native permutation callback + // writes a structured scratch table at program.stack_mptr. + // q_pc starts at the first encoded instruction. + let q_pc := q_program_mptr + // q_end is an exclusive byte pointer for the VM loop. + let q_end := add(q_program_mptr, 0x11cf) + // q_sp starts at the first free stack word. + let q_sp := 0xb8e0 + // q_top is meaningless until q_has_top is set. + let q_top := 0 + // q_has_top = 0 means the VM stack is empty. + let q_has_top := 0 + + // q_program opcode summary: + // 0x01/0x09 push const 0x02/0x05 push memory + // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg + // 0x0a fold main identity 0x0b fold selector identity + // 0x0c..0x11 add/mul const or memory into top + // 0x12..0x16 fused add-mul runs + // 0x17/0x18 reserved + // 0x19 native permutation 0x1b native heavy identity + // 0x1c LIN7 0x1d BILIN7_ROW + // 0x1e BILIN7_PAIRWISE 0x1f native lookup + // 0x20 POW5 0x21 MODARITH7 + // 0x22 AFFINE_SUM + // + // The default IVC verifier uses one physical encoding for the + // logical VM: compact byte-oriented opcodes with variable-width + // operands, dynamic runs, and limb-aware cases. + + // Byte-oriented encoding: opcodes are one byte followed by + // variable-width operand bytes. + for { } lt(q_pc, q_end) { } { + // The bytecode table is byte-addressed, but EVM memory + // loads whole words. `byte(0, mload(q_pc))` extracts the + // opcode at the current byte cursor; each case advances + // q_pc by exactly its operand width. + let q_op := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + + switch q_op + // VM 0x05 PUSH_MEM_U16 (bytes): next two bytes are a short memory pointer. + case 0x05 { + // Operand layout: u16 absolute memory pointer. The + // memory planner keeps the hot quotient frame below + // 64 KiB when this compact form is emitted. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + if q_has_top { + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } + q_top := mload(q_ptr) + q_has_top := 1 + } + // VM 0x06 ADD: pop one spilled stack word and add it to q_top. + case 0x06 { + // The safety validator guarantees a spilled operand + // exists before ADD. q_top is the right operand. + q_sp := sub(q_sp, 0x20) + q_top := addmod(mload(q_sp), q_top, r) + } + // VM 0x08 NEG: replace q_top with its Fr negation. + case 0x08 { + // addmod(0, r - x, r) maps zero back to zero and every + // nonzero scalar to its canonical additive inverse. + q_top := addmod(0, sub(r, q_top), r) + } + // VM 0x0d MUL_CONST_U8: multiply q_top by a small constant-table slot. + case 0x0d { + // One-byte constant-index multiply, used by short + // affine chains after an initial PUSH. + let qconst := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + q_top := mulmod(q_top, mload(add(q_const_mptr, shl(5, qconst))), r) + } + // VM 0x10 ADD_MEM_U16: add a short memory load into q_top. + case 0x10 { + // Operand layout: u16 pointer. The pointed word is an + // already range-checked Fr scalar in verifier memory. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + q_top := addmod(q_top, mload(q_ptr), r) + } + // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. + case 0x11 { + // In-place multiply by a planned memory word. + let q_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + q_top := mulmod(q_top, mload(q_ptr), r) + } + // Limb-aware opcodes are opt-in compact forms for + // structurally recognized non-SHA foreign-field shapes. + // Coefficients are indexes into q_const_mptr, which is + // generated from VK/program data, never from proof + // calldata. + // + // Rust source shape: + // proofs/src/plonk/mod.rs::partially_evaluate_identities + // circuits/src/field/foreign/util.rs::{sum_exprs,pair_wise_prod} + // circuits/src/field/foreign/params.rs::{base_powers,double_base_powers} + // + // "Foreign field" means the circuit represents elements + // modulo another modulus m as 7 limbs in base + // 2^LOG2_BASE. The verifier does not switch fields; it + // evaluates the lowered identity over BLS12-381 Fr, using + // Fr coefficients equal to base^i mod m or base^(i+j) mod m. + // VM 0x21 MODARITH7: byte-only fused affine 7-limb foreign-field/ECC identity. + case 0x21 { + // MODARITH7: + // maybe_cond * ( + // c + // + sum LIN7 blocks + // + sum BILIN7_ROW blocks + // + sum BILIN7_PAIRWISE blocks + // + sum coeff[k] * mload(ptr[k]) + // + sum coeff[k] * mload(lhs[k]) * mload(rhs[k]) + // ) + // It is a dispatch/operand-load optimization only; + // all coefficients still come from the generated + // quotient constant table. + // + // Flags: + // bit 0: multiply the final affine sum by a memory + // condition word. + // bit 1: seed q_acc from a constant-table word + // before reading the counted term blocks. + let q_flags := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + let q_cond_ptr := 0 + if and(q_flags, 0x01) { + // Optional condition pointer. When present, the + // whole identity is gated by mload(q_cond_ptr). + q_cond_ptr := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + } + + let q_acc := 0 + if and(q_flags, 0x02) { + // Optional constant seed for affine identities + // with a standalone constant term. + let qconst := byte(0, mload(q_pc)) + q_pc := add(q_pc, 1) + q_acc := mload(add(q_const_mptr, shl(5, qconst))) + } + + // Five one-byte counters describe the blocks that + // follow. Each block has a fixed-width internal layout, + // so q_pc can advance without per-term tags. + let q_counts_word := mload(q_pc) + let q_lin_count := byte(0, q_counts_word) + let q_row_count := byte(1, q_counts_word) + let q_pairwise_count := byte(2, q_counts_word) + let q_mem_count := byte(3, q_counts_word) + let q_product_count := byte(4, q_counts_word) + q_pc := add(q_pc, 5) + + if q_has_top { + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } + + // LIN7 blocks: q_acc += sum_i c_i * limb_i. + for { let q_lin_block := 0 } lt(q_lin_block, q_lin_count) { q_lin_block := add(q_lin_block, 1) } { + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_ptr := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), + r + ) + } + } + + // BILIN7_ROW blocks: q_acc += lhs * sum_i c_i * rhs_i. + for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { + let q_lhs := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + let q_lhs_value := mload(q_lhs) + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_rhs := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod( + mulmod(q_lhs_value, mload(q_rhs), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + } + + // BILIN7_PAIRWISE blocks: q_acc += weighted 7-by-7 + // product convolution. + for { let q_pair_block := 0 } lt(q_pair_block, q_pairwise_count) { q_pair_block := add(q_pair_block, 1) } { + let q_pair_word := mload(q_pc) + let q_lhs_base := shr(240, q_pair_word) + let q_rhs_base := and(shr(224, q_pair_word), 0xffff) + q_pc := add(q_pc, 0x04) + let q_coeff_pc := q_pc + q_pc := add(q_pc, 13) + for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { + let q_lhs_value := mload(add(q_lhs_base, shl(5, q_i))) + for { let q_j := 0 } lt(q_j, 7) { q_j := add(q_j, 1) } { + let qconst := byte(0, mload(add(q_coeff_pc, add(q_i, q_j)))) + q_acc := addmod( + q_acc, + mulmod( + mulmod(q_lhs_value, mload(add(q_rhs_base, shl(5, q_j))), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + } + } + + // Extra linear memory terms outside the 7-limb shapes. + for { let q_mem_block := 0 } lt(q_mem_block, q_mem_count) { q_mem_block := add(q_mem_block, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_ptr := and(shr(232, q_word), 0xffff) + q_pc := add(q_pc, 3) + q_acc := addmod( + q_acc, + mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), + r + ) + } + + // Extra binary product terms outside the 7-limb shapes. + for { let q_product_block := 0 } lt(q_product_block, q_product_count) { q_product_block := add(q_product_block, 1) } { + let q_word := mload(q_pc) + let qconst := byte(0, q_word) + let q_lhs := and(shr(232, q_word), 0xffff) + let q_rhs := and(shr(216, q_word), 0xffff) + q_pc := add(q_pc, 5) + q_acc := addmod( + q_acc, + mulmod( + mulmod(mload(q_lhs), mload(q_rhs), r), + mload(add(q_const_mptr, shl(5, qconst))), + r + ), + r + ) + } + + if and(q_flags, 0x01) { + // Apply the optional gate condition last so every + // subterm shares the same selector/condition. + q_acc := mulmod(mload(q_cond_ptr), q_acc, r) + } + // MODARITH7 pushes its fused identity value. + q_top := q_acc + q_has_top := 1 + } + // Native permutation callback. It evaluates the + // permutation identities from permutation.rs at this exact + // VM position, preserving the Rust identity order while + // avoiding a large interpreted product loop. + // VM 0x19 NATIVE_PERMUTATION: marker for the generated permutation callback. + case 0x19 { + // Native callbacks are identity-boundary opcodes. They + // must not inherit any partially evaluated VM stack + // state from the previous expression. + q_top := 0 + q_has_top := 0 + // The generated loop below uses program.stack_mptr as + // its scratch-table base, not as a conventional VM + // stack. The Rust memory planner must reserve enough + // words for structured_permutation_scratch_words(meta) + // whenever this opcode can appear. + q_sp := 0xb8e0 + // The generated lines below call the same fold snippets + // used by interpreted expressions, so trace IDs and + // y-batch positions remain contiguous. + { + let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 + let q_perm_vals := 0xb8e0 + let q_perm_sigmas := 0xbb20 + let q_perm_z_cur := 0xbd60 + let q_perm_z_next := 0xbe20 + let q_perm_z_last := 0xbee0 + let q_perm_delta_base_ptr := 0xbf80 + let q_perm_num_cols := 18 + let q_perm_num_sets := 6 + let q_perm_chunk_len := 3 + let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 + mstore(add(q_perm_vals, 0x0), mload(0x99a0)) + { + for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { + let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) + let q_perm_val_load_src_off := q_perm_val_load_dst_off + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x94a0, q_perm_val_load_src_off))) + } + } + mstore(add(q_perm_vals, 0xc0), mload(0x9480)) + mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) + { + for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 9) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { + let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) + let q_perm_val_load_src_off := q_perm_val_load_dst_off + mstore(add(add(q_perm_vals, 0x100), q_perm_val_load_dst_off), mload(add(0x95a0, q_perm_val_load_src_off))) + } + } + mstore(add(q_perm_vals, 0x220), mload(0x9980)) + { + for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 18) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { + let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) + let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x9bc0, q_perm_sigma_load_src_off))) + } + } + { + for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 6) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { + let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) + let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x9e00, q_perm_z_cur_load_src_off))) + } + } + { + for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 6) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { + let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) + let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x9e20, q_perm_z_next_load_src_off))) + } + } + { + for { let q_perm_z_last_load_i := 0 } lt(q_perm_z_last_load_i, 5) { q_perm_z_last_load_i := add(q_perm_z_last_load_i, 1) } { + let q_perm_z_last_load_dst_off := shl(5, q_perm_z_last_load_i) + let q_perm_z_last_load_src_off := mul(q_perm_z_last_load_i, 0x60) + mstore(add(add(q_perm_z_last, 0x0), q_perm_z_last_load_dst_off), mload(add(0x9e40, q_perm_z_last_load_src_off))) + } + } + let q_perm_eval := 0 + q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + let q_perm_zn := mload(add(q_perm_z_cur, 0xa0)) + q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + for { let q_perm_i := 1 } lt(q_perm_i, 6) { q_perm_i := add(q_perm_i, 1) } { + let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) + let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) + q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + } + mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) + for { let q_perm_set := 0 } lt(q_perm_set, 6) { q_perm_set := add(q_perm_set, 1) } { + let q_perm_start := mul(q_perm_set, q_perm_chunk_len) + let q_perm_end := add(q_perm_start, q_perm_chunk_len) + if gt(q_perm_end, q_perm_num_cols) { q_perm_end := q_perm_num_cols } + let q_perm_left := mload(add(q_perm_z_next, shl(5, q_perm_set))) + let q_perm_right := mload(add(q_perm_z_cur, shl(5, q_perm_set))) + let q_perm_delta_pow := mload(q_perm_delta_base_ptr) + for { let q_perm_j := q_perm_start } lt(q_perm_j, q_perm_end) { q_perm_j := add(q_perm_j, 1) } { + let q_perm_off := shl(5, q_perm_j) + let q_perm_v := mload(add(q_perm_vals, q_perm_off)) + let q_perm_s := mload(add(q_perm_sigmas, q_perm_off)) + q_perm_left := mulmod(q_perm_left, addmod(addmod(q_perm_v, mulmod(mload(BETA_MPTR), q_perm_s, r), r), mload(GAMMA_MPTR), r), r) + q_perm_right := mulmod(q_perm_right, addmod(addmod(q_perm_v, q_perm_delta_pow, r), mload(GAMMA_MPTR), r), r) + q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) + } + q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) + mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) + } + } + } + // Native lookup callback. This whole-family opcode + // evaluates the LogUp boundary, helper-chunk, and + // accumulator identities at this VM position, preserving + // the Rust y-batch order while avoiding many interpreted + // product-loop opcodes. + // VM 0x1f NATIVE_LOOKUP: marker for the generated LogUp lookup callback. + case 0x1f { + // Reset VM stack state before entering structured + // lookup Yul. Lookup callbacks own their scratch + // layout and perform all needed folds internally. + q_top := 0 + q_has_top := 0 + // The generated loop below uses program.stack_mptr as + // f+beta/prefix/suffix scratch rather than as a + // conventional VM stack. The Rust memory planner must + // reserve structured_lookup_scratch_words(meta). + q_sp := 0xb8e0 + // Generated LogUp code follows the same y-batch order + // as the Rust identity stream. + { + let q_lookup_f := 0xb8e0 + let q_lookup_prefix := 0xb960 + let q_lookup_suffix := 0xb9e0 + let q_lookup_l0 := mload(L_0_MPTR) + let q_lookup_llast := mload(L_LAST_MPTR) + let q_lookup_lblind := mload(L_BLIND_MPTR) + let q_lookup_lsum := addmod(q_lookup_l0, q_lookup_llast, r) + let q_lookup_active := addmod(1, sub(r, addmod(q_lookup_llast, q_lookup_lblind, r)), r) + let q_lookup_beta := mload(BETA_MPTR) + let q_lookup_theta := mload(THETA_MPTR) + { + { + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa060), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let f_10 := mload(0x9ae0) + let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) + let var1 := mulmod(var0, q_lookup_theta, r) + for { let q_lookup_shared_i := 0 } lt(q_lookup_shared_i, 4) { q_lookup_shared_i := add(q_lookup_shared_i, 1) } { + let q_lookup_shared_off := shl(5, q_lookup_shared_i) + let q_lookup_shared_tail := mload(add(0x94c0, q_lookup_shared_off)) + let q_lookup_shared_compressed := addmod(var1, q_lookup_shared_tail, r) + mstore(add(q_lookup_f, q_lookup_shared_off), addmod(q_lookup_shared_compressed, q_lookup_beta, r)) + } + let q_lookup_product := 1 + for { let q_lookup_prod_i := 0 } lt(q_lookup_prod_i, 4) { q_lookup_prod_i := add(q_lookup_prod_i, 1) } { + q_lookup_product := mulmod(q_lookup_product, mload(add(q_lookup_f, shl(5, q_lookup_prod_i))), r) + } + mstore(q_lookup_prefix, 1) + for { let q_lookup_pref_i := 1 } lt(q_lookup_pref_i, 4) { q_lookup_pref_i := add(q_lookup_pref_i, 1) } { + let q_lookup_pref_prev := sub(q_lookup_pref_i, 1) + mstore(add(q_lookup_prefix, shl(5, q_lookup_pref_i)), mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_pref_prev))), mload(add(q_lookup_f, shl(5, q_lookup_pref_prev))), r)) + } + mstore(add(q_lookup_suffix, 0x60), 1) + for { let q_lookup_suf_i := sub(4, 1) } gt(q_lookup_suf_i, 0) { q_lookup_suf_i := sub(q_lookup_suf_i, 1) } { + let q_lookup_suf_prev := sub(q_lookup_suf_i, 1) + mstore(add(q_lookup_suffix, shl(5, q_lookup_suf_prev)), mulmod(mload(add(q_lookup_suffix, shl(5, q_lookup_suf_i))), mload(add(q_lookup_f, shl(5, q_lookup_suf_i))), r)) + } + let q_lookup_sum := 0 + for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 4) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { + q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) + } + let q_lookup_eval := addmod(mulmod(mload(0xa040), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let q_lookup_sum_h := mload(0xa040) + let f_17 := mload(0x9b60) + let f_11 := mload(0x9b00) + let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) + let f_12 := mload(0x9b20) + let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) + let q_lookup_s_sum_h := mulmod(f_17, q_lookup_sum_h, r) + let q_lookup_diff := addmod(mload(0xa080), sub(r, addmod(mload(0xa060), q_lookup_s_sum_h, r)), r) + let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa020), r) + let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + } + { + { + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa0e0), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let a_14 := mload(0x9980) + let var0 := addmod(mulmod(0, q_lookup_theta, r), a_14, r) + let a_0 := mload(0x94a0) + let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_0, r) + let a_1 := mload(0x94c0) + let var2 := addmod(mulmod(var1, q_lookup_theta, r), a_1, r) + let a_2 := mload(0x94e0) + let var3 := addmod(mulmod(var2, q_lookup_theta, r), a_2, r) + let a_3 := mload(0x9500) + let var4 := addmod(mulmod(var3, q_lookup_theta, r), a_3, r) + let a_4 := mload(0x9520) + let var5 := addmod(mulmod(var4, q_lookup_theta, r), a_4, r) + let a_5 := mload(0x95a0) + let var6 := addmod(mulmod(var5, q_lookup_theta, r), a_5, r) + let a_6 := mload(0x95c0) + let var7 := addmod(mulmod(var6, q_lookup_theta, r), a_6, r) + let a_7 := mload(0x95e0) + let var8 := addmod(mulmod(var7, q_lookup_theta, r), a_7, r) + let a_8 := mload(0x9600) + let var9 := addmod(mulmod(var8, q_lookup_theta, r), a_8, r) + let a_9 := mload(0x9620) + let var10 := addmod(mulmod(var9, q_lookup_theta, r), a_9, r) + let a_10 := mload(0x9640) + let var11 := addmod(mulmod(var10, q_lookup_theta, r), a_10, r) + let a_11 := mload(0x9660) + let var12 := addmod(mulmod(var11, q_lookup_theta, r), a_11, r) + let a_12 := mload(0x9680) + let var13 := addmod(mulmod(var12, q_lookup_theta, r), a_12, r) + let a_13 := mload(0x96a0) + let var14 := addmod(mulmod(var13, q_lookup_theta, r), a_13, r) + let f_13 := mload(0x9b40) + let var15 := addmod(mulmod(var14, q_lookup_theta, r), f_13, r) + let q_lookup_eval := addmod(mulmod(mload(0xa0c0), addmod(var15, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + { + let q_lookup_sum_h := mload(0xa0c0) + let var0 := 0x1 + let f_24 := mload(0x9b80) + let var1 := addmod(0, sub(r, f_24), r) + let var2 := addmod(var0, var1, r) + let a_14 := mload(0x9980) + let var3 := mulmod(var2, a_14, r) + let var4 := addmod(mulmod(0, q_lookup_theta, r), var3, r) + let a_0 := mload(0x94a0) + let var5 := mulmod(var2, a_0, r) + let var6 := addmod(mulmod(var4, q_lookup_theta, r), var5, r) + let a_1 := mload(0x94c0) + let var7 := mulmod(var2, a_1, r) + let var8 := addmod(mulmod(var6, q_lookup_theta, r), var7, r) + let a_2 := mload(0x94e0) + let var9 := mulmod(var2, a_2, r) + let var10 := addmod(mulmod(var8, q_lookup_theta, r), var9, r) + let a_3 := mload(0x9500) + let var11 := mulmod(var2, a_3, r) + let var12 := addmod(mulmod(var10, q_lookup_theta, r), var11, r) + let a_4 := mload(0x9520) + let var13 := mulmod(var2, a_4, r) + let var14 := addmod(mulmod(var12, q_lookup_theta, r), var13, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var2, a_5, r) + let var16 := addmod(mulmod(var14, q_lookup_theta, r), var15, r) + let a_6 := mload(0x95c0) + let var17 := mulmod(var2, a_6, r) + let var18 := addmod(mulmod(var16, q_lookup_theta, r), var17, r) + let a_7 := mload(0x95e0) + let var19 := mulmod(var2, a_7, r) + let var20 := addmod(mulmod(var18, q_lookup_theta, r), var19, r) + let a_8 := mload(0x9600) + let var21 := mulmod(var2, a_8, r) + let var22 := addmod(mulmod(var20, q_lookup_theta, r), var21, r) + let a_9 := mload(0x9620) + let var23 := mulmod(var2, a_9, r) + let var24 := addmod(mulmod(var22, q_lookup_theta, r), var23, r) + let a_10 := mload(0x9640) + let var25 := mulmod(var2, a_10, r) + let var26 := addmod(mulmod(var24, q_lookup_theta, r), var25, r) + let a_11 := mload(0x9660) + let var27 := mulmod(var2, a_11, r) + let var28 := addmod(mulmod(var26, q_lookup_theta, r), var27, r) + let a_12 := mload(0x9680) + let var29 := mulmod(var2, a_12, r) + let var30 := addmod(mulmod(var28, q_lookup_theta, r), var29, r) + let a_13 := mload(0x96a0) + let var31 := mulmod(var2, a_13, r) + let var32 := addmod(mulmod(var30, q_lookup_theta, r), var31, r) + let f_13 := mload(0x9b40) + let var33 := mulmod(var2, f_13, r) + let var34 := addmod(mulmod(var32, q_lookup_theta, r), var33, r) + let q_lookup_s_sum_h := mulmod(var0, q_lookup_sum_h, r) + let q_lookup_diff := addmod(mload(0xa100), sub(r, addmod(mload(0xa0e0), q_lookup_s_sum_h, r)), r) + let q_lookup_t_beta := addmod(var34, q_lookup_beta, r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa0a0), r) + let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) + } + } + } + } + // Native callbacks are generated only for the heaviest + // recognized Midfall gate identities. All other gate and + // non-native identity arithmetic remains in + // the compact q_program VM above, preserving the Rust + // `partially_evaluate_identities` order. + // VM 0x1b NATIVE_IDENTITY: marker for generated heavy-gate callbacks. + case 0x1b { + // Operand layout: u16 native callback index. The + // manifest validates that callback indexes appear in + // generated order and target existing switch cases. + let q_native_idx := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) + // Heavy identities are whole expressions, so clear the + // interpreter stack before dispatching. + q_top := 0 + q_has_top := 0 + q_sp := 0xb8e0 + // Native identity sub-cases are generated from selected heavy gate identities. + switch q_native_idx + case 0 { + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let a_0_next_1 := mload(0x9540) + let var1 := mulmod(a_0, a_0_next_1, r) + let var2 := 0x100000000000000 + let a_1_next_1 := mload(0x9560) + let var3 := mulmod(a_0, a_1_next_1, r) + let var4 := mulmod(var2, var3, r) + let var5 := addmod(var1, var4, r) + let var6 := 0x10000000000000000000000000000 + let a_2_next_1 := mload(0x9580) + let var7 := mulmod(a_0, a_2_next_1, r) + let var8 := mulmod(var6, var7, r) + let var9 := addmod(var5, var8, r) + let a_1 := mload(0x94c0) + let var10 := mulmod(a_1, a_0_next_1, r) + let var11 := mulmod(var2, var10, r) + let var12 := addmod(var9, var11, r) + let var13 := mulmod(a_1, a_1_next_1, r) + let var14 := mulmod(var6, var13, r) + let var15 := addmod(var12, var14, r) + let var16 := 0x3212e00cde6d2002b119d800000347fcb8 + let a_6_next_1 := mload(0x9720) + let var17 := mulmod(a_1, a_6_next_1, r) + let var18 := mulmod(var16, var17, r) + let var19 := addmod(var15, var18, r) + let a_2 := mload(0x94e0) + let var20 := mulmod(a_2, a_0_next_1, r) + let var21 := mulmod(var6, var20, r) + let var22 := addmod(var19, var21, r) + let a_5_next_1 := mload(0x9700) + let var23 := mulmod(a_2, a_5_next_1, r) + let var24 := mulmod(var16, var23, r) + let var25 := addmod(var22, var24, r) + let var26 := 0x297784894e27525bc342b7fde37dba9366 + let var27 := mulmod(a_2, a_6_next_1, r) + let var28 := mulmod(var26, var27, r) + let var29 := addmod(var25, var28, r) + let a_3 := mload(0x9500) + let a_4_next_1 := mload(0x96e0) + let var30 := mulmod(a_3, a_4_next_1, r) + let var31 := mulmod(var16, var30, r) + let var32 := addmod(var29, var31, r) + let var33 := mulmod(a_3, a_5_next_1, r) + let var34 := mulmod(var26, var33, r) + let var35 := addmod(var32, var34, r) + let var36 := 0x340f2ebe380a0f5eff4360543988a61dc2 + let var37 := mulmod(a_3, a_6_next_1, r) + let var38 := mulmod(var36, var37, r) + let var39 := addmod(var35, var38, r) + let a_4 := mload(0x9520) + let a_3_next_1 := mload(0x96c0) + let var40 := mulmod(a_4, a_3_next_1, r) + let var41 := mulmod(var16, var40, r) + let var42 := addmod(var39, var41, r) + let var43 := mulmod(a_4, a_4_next_1, r) + let var44 := mulmod(var26, var43, r) + let var45 := addmod(var42, var44, r) + let var46 := mulmod(a_4, a_5_next_1, r) + let var47 := mulmod(var36, var46, r) + let var48 := addmod(var45, var47, r) + let var49 := 0x13af65741744bd7bb2c6872df2b800320 + let var50 := mulmod(a_4, a_6_next_1, r) + let var51 := mulmod(var49, var50, r) + let var52 := addmod(var48, var51, r) + let a_5 := mload(0x95a0) + let var53 := mulmod(a_5, a_2_next_1, r) + let var54 := mulmod(var16, var53, r) + let var55 := addmod(var52, var54, r) + let var56 := mulmod(a_5, a_3_next_1, r) + let var57 := mulmod(var26, var56, r) + let var58 := addmod(var55, var57, r) + let var59 := mulmod(a_5, a_4_next_1, r) + let var60 := mulmod(var36, var59, r) + let var61 := addmod(var58, var60, r) + let var62 := mulmod(a_5, a_5_next_1, r) + let var63 := mulmod(var49, var62, r) + let var64 := addmod(var61, var63, r) + let var65 := 0x2cb9b546d20373eaf85e8f53db883cb548 + let var66 := mulmod(a_5, a_6_next_1, r) + let var67 := mulmod(var65, var66, r) + let var68 := addmod(var64, var67, r) + let a_6 := mload(0x95c0) + let var69 := mulmod(a_6, a_1_next_1, r) + let var70 := mulmod(var16, var69, r) + let var71 := addmod(var68, var70, r) + let var72 := mulmod(a_6, a_2_next_1, r) + let var73 := mulmod(var26, var72, r) + let var74 := addmod(var71, var73, r) + let var75 := mulmod(a_6, a_3_next_1, r) + let var76 := mulmod(var36, var75, r) + let var77 := addmod(var74, var76, r) + let var78 := mulmod(a_6, a_4_next_1, r) + let var79 := mulmod(var49, var78, r) + let var80 := addmod(var77, var79, r) + let var81 := mulmod(a_6, a_5_next_1, r) + let var82 := mulmod(var65, var81, r) + let var83 := addmod(var80, var82, r) + let var84 := 0xc8557e86f90d0d89eed6eb5349a0f8820 + let var85 := mulmod(a_6, a_6_next_1, r) + let var86 := mulmod(var84, var85, r) + let var87 := addmod(var83, var86, r) + let var88 := mulmod(var2, a_1, r) + let var89 := addmod(a_0, var88, r) + let var90 := mulmod(var6, a_2, r) + let var91 := addmod(var89, var90, r) + let var92 := addmod(var87, var91, r) + let var93 := mulmod(var2, a_1_next_1, r) + let var94 := addmod(a_0_next_1, var93, r) + let var95 := mulmod(var6, a_2_next_1, r) + let var96 := addmod(var94, var95, r) + let var97 := addmod(var92, var96, r) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) + let var98 := mulmod(var2, a_8, r) + let var99 := addmod(a_7, var98, r) + let a_9 := mload(0x9620) + let var100 := mulmod(var6, a_9, r) + let var101 := addmod(var99, var100, r) + let var102 := addmod(0, sub(r, var101), r) + let var103 := addmod(var97, var102, r) + let a_7_next_1 := mload(0x9740) + let var104 := 0x241eabfffeb153ffffb9feffffffffaaab + let var105 := mulmod(a_7_next_1, var104, r) + let var106 := addmod(0, sub(r, var105), r) + let var107 := addmod(var103, var106, r) + let var108 := addmod(0, sub(r, var16), r) + let var109 := addmod(var107, var108, r) + let a_8_next_1 := mload(0x9760) + let var110 := 0x73eda753299d7d483339d80809a1d80553b9202d7ffe85d4800008bb20000001 + let var111 := addmod(a_8_next_1, var110, r) + let var112 := 0x4000000000000000000000000000000000 + let var113 := mulmod(var111, var112, r) + let var114 := addmod(0, sub(r, var113), r) + let var115 := addmod(var109, var114, r) + let var116 := mulmod(var0, var115, r) + mstore(0xb8e0, var116) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 1 { + { + let var0 := 0x1 + let a_0 := mload(0x94a0) + let var1 := 0x10000000000000000000000000000 + let var2 := addmod(a_0, var1, r) + let var3 := 0x100000000000000 + let a_1 := mload(0x94c0) + let var4 := addmod(a_1, var1, r) + let var5 := mulmod(var3, var4, r) + let var6 := addmod(var2, var5, r) + let a_2 := mload(0x94e0) + let var7 := addmod(a_2, var1, r) + let var8 := mulmod(var1, var7, r) + let var9 := addmod(var6, var8, r) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) + let var10 := mulmod(var3, a_8, r) + let var11 := addmod(a_7, var10, r) + let a_9 := mload(0x9620) + let var12 := mulmod(var1, a_9, r) + let var13 := addmod(var11, var12, r) + let var14 := addmod(0, sub(r, var13), r) + let var15 := addmod(var9, var14, r) + let var16 := addmod(0, sub(r, var1), r) + let var17 := addmod(var15, var16, r) + let a_7_next_1 := mload(0x9740) + let var18 := 0x241eabfffeb153ffffb9feffffffffaaab + let var19 := mulmod(a_7_next_1, var18, r) + let var20 := addmod(0, sub(r, var19), r) + let var21 := addmod(var17, var20, r) + let var22 := 0xd9d44a30b019261257667fde3844a8cd6 + let var23 := addmod(0, sub(r, var22), r) + let var24 := addmod(var21, var23, r) + let a_8_next_1 := mload(0x9760) + let var25 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5b6e855000003ab00002 + let var26 := addmod(a_8_next_1, var25, r) + let var27 := 0x4000000000000000000000000000000000 + let var28 := mulmod(var26, var27, r) + let var29 := addmod(0, sub(r, var28), r) + let var30 := addmod(var24, var29, r) + let var31 := mulmod(var0, var30, r) + mstore(0xb8e0, var31) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x80) + let q_selector_acc := mload(q_selector_ptr) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 2 { + { + let var0 := 0x1 + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var1 := addmod(0, sub(r, a_0_next_1), r) + let var2 := addmod(f_0, var1, r) + let var3 := 0x1b8114c381b922fd5d6d241210e2d8a68ad5744053ba9e776118de4107b51ace + let a_0 := mload(0x94a0) + let var4 := mulmod(a_0, a_0, r) + let a_3 := mload(0x9500) + let var5 := mulmod(var4, a_3, r) + let var6 := mulmod(var3, var5, r) + let var7 := addmod(var2, var6, r) + let var8 := 0x3df32e4cc4cb2ed20e5d21899cf5331775990ccaec4c09b4e3717213fcc0d763 + let a_1 := mload(0x94c0) + let var9 := mulmod(a_1, a_1, r) + let a_4 := mload(0x9520) + let var10 := mulmod(var9, a_4, r) + let var11 := mulmod(var8, var10, r) + let var12 := addmod(var7, var11, r) + let var13 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 + let a_2 := mload(0x94e0) + let var14 := mulmod(a_2, a_2, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var14, a_5, r) + let var16 := mulmod(var13, var15, r) + let var17 := addmod(var12, var16, r) + let var18 := mulmod(var0, var17, r) + mstore(0xb8e0, var18) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x120) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + case 3 { + { + let var0 := 0x1 + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) + let var1 := addmod(0, sub(r, a_1_next_1), r) + let var2 := addmod(f_1, var1, r) + let var3 := 0x404d21073985d14e432a4ad76d3fae06ca74314b950fe7b1d7f501cd31a8b374 + let a_0 := mload(0x94a0) + let var4 := mulmod(a_0, a_0, r) + let a_3 := mload(0x9500) + let var5 := mulmod(var4, a_3, r) + let var6 := mulmod(var3, var5, r) + let var7 := addmod(var2, var6, r) + let var8 := 0xb2cc8704264c6bd81bc620e9e524d4b73e9b2317679422ff7fa1603955649f1 + let a_1 := mload(0x94c0) + let var9 := mulmod(a_1, a_1, r) + let a_4 := mload(0x9520) + let var10 := mulmod(var9, a_4, r) + let var11 := mulmod(var8, var10, r) + let var12 := addmod(var7, var11, r) + let var13 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f + let a_2 := mload(0x94e0) + let var14 := mulmod(a_2, a_2, r) + let a_5 := mload(0x95a0) + let var15 := mulmod(var14, a_5, r) + let var16 := mulmod(var13, var15, r) + let var17 := addmod(var12, var16, r) + let var18 := mulmod(var0, var17, r) + mstore(0xb8e0, var18) + } + mstore(0xb280, mulmod(mload(0xb280), y, r)) + { + let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x120) + let q_selector_acc := mload(q_selector_ptr) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) + } + } + default { revert(0, 0) } + } + // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. + case 0x0b { + // Operand layout packed into three bytes: + // high byte: selector bucket index; + // low u16 : y-power gap since this selector's + // previous contribution. + let q_selector_payload := shr(232, mload(q_pc)) + q_pc := add(q_pc, 3) + let q_sel_idx := shr(16, q_selector_payload) + let q_sel_gap := and(q_selector_payload, 0xffff) + let q_eval := q_top + q_has_top := 0 + // Simple-selector identity: keep the same y-batch + // position as main identities, then advance only this + // selector bucket by its codegen-known gap. + // + // The global fully-evaluated accumulator is still + // multiplied by y so later main identities land at the + // same y powers as Rust's reverse fold. + mstore(0xb280, mulmod(mload(0xb280), y, r)) + let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) + let q_sel_acc := mload(q_target_ptr) + if q_sel_gap { + // Selector buckets are sparse in the global + // identity stream. Precomputed y^gap advances only + // this selector's local accumulator. + q_sel_acc := mulmod(q_sel_acc, mload(add(0xb2c0, shl(5, q_sel_gap))), r) + } + mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) + } + // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. + default { + revert(0, 0) + } + } + // The VK-pinned bytecode must end exactly at q_end and every + // identity must have been consumed by a fold/native callback. + // This catches malformed generator output whose final opcode + // over-reads operands or leaves a partial expression live. + if iszero(eq(q_pc, q_end)) { revert(0, 0) } + if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } + + // Structured post-VM suffix. The current default uses this for + // regular trash constraints: it is smaller than fully unrolled + // Yul and cheaper than interpreting every trash operation. + // + // These generated blocks run after q_pc reaches q_end, but + // they still participate in the same identity order and write + // into the same numerator / selector accumulators. + { + let q_trash_tau := mload(TRASH_CHALLENGE_MPTR) + { + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) + let var0 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000 + let var1 := mulmod(a_0_next_1, var0, r) + let var2 := addmod(f_0, var1, r) + let var3 := 0x590ba402032e82eb1f660ef09796c5686345a5054ed96dae8e2d233633788771 + let a_0 := mload(0x94a0) + let var4 := mulmod(var3, a_0, r) + let var5 := addmod(var2, var4, r) + let var6 := 0x52f789e4afc3801f7411102ee2f47cc5954a744e71cac98e75ea962a55a0a76f + let a_1 := mload(0x94c0) + let var7 := mulmod(var6, a_1, r) + let var8 := addmod(var5, var7, r) + let var9 := 0x3509dd2fe3aac0080783557fec090fb1cb4b2b0901253c55282024331d1fe1a8 + let a_2 := mload(0x94e0) + let var10 := q_pow5(a_2) + let var11 := mulmod(var9, var10, r) + let var12 := addmod(var8, var11, r) + let var13 := 0x333f8046ece5579cbd6872449c57f2703dfc8864cfadc06d587ff104a0d0c1f2 + let a_3 := mload(0x9500) + let var14 := q_pow5(a_3) + let var15 := mulmod(var13, var14, r) + let var16 := addmod(var12, var15, r) + let var17 := 0x412c98232b6ab8a47aa76ee814ef7ec6261987c9802f2cfc490e007951a60ca5 + let a_4 := mload(0x9520) + let var18 := q_pow5(a_4) + let var19 := mulmod(var17, var18, r) + let var20 := addmod(var16, var19, r) + let var21 := 0x53fded36d490ba6b05a5d10fd99ffe5456baec6a6a8753199d5ebdc33c99790e + let a_5 := mload(0x95a0) + let var22 := q_pow5(a_5) + let var23 := mulmod(var21, var22, r) + let var24 := addmod(var20, var23, r) + let var25 := 0x6ccb1c7d87f3c12a2bde4e68ac7f1e8b03481ba15d7f88f9a7f9b8310dd6d34 + let a_6 := mload(0x95c0) + let var26 := q_pow5(a_6) + let var27 := mulmod(var25, var26, r) + let var28 := addmod(var24, var27, r) + let var29 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 + let a_7 := mload(0x95e0) + let var30 := q_pow5(a_7) + let var31 := mulmod(var29, var30, r) + let var32 := addmod(var28, var31, r) + let var33 := addmod(mulmod(0, q_trash_tau, r), var32, r) + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) + let var34 := mulmod(a_1_next_1, var0, r) + let var35 := addmod(f_1, var34, r) + let var36 := 0x5b1fc262a28cbb8bf75d9b1a6edaa74591ec24cd9a209512213cec3a3c0f1a5d + let var37 := mulmod(var36, a_0, r) + let var38 := addmod(var35, var37, r) + let var39 := 0x4d0ea7f9c3fda06d9535b0fdafd8338bd47c2200b284fa71a325ff41ac358028 + let var40 := mulmod(var39, a_1, r) + let var41 := addmod(var38, var40, r) + let var42 := 0x26cc223e16f47c20e17cc6069605fa5a8af05ea4f6eb36029a641d23b818eb10 + let var43 := mulmod(var42, var10, r) + let var44 := addmod(var41, var43, r) + let var45 := 0x31e823a45e567484c1544e310c0fa5cd66547a8f0dde659ac61698c30e838d25 + let var46 := mulmod(var45, var14, r) + let var47 := addmod(var44, var46, r) + let var48 := 0x275a20361ea91992193920270d3e2d1f6361880ac0a439c64bef815d4469ba85 + let var49 := mulmod(var48, var18, r) + let var50 := addmod(var47, var49, r) + let var51 := 0x5f3a15bab4ce4097b1edc3a25002694b92395ce355a8a12fe557459d9633f701 + let var52 := mulmod(var51, var22, r) + let var53 := addmod(var50, var52, r) + let var54 := 0x301cf56f9b4577112cc4241cddf6484aaadedbf1bbd0f2351adf2e41c2fb2ecd + let var55 := mulmod(var54, var26, r) + let var56 := addmod(var53, var55, r) + let var57 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f + let var58 := mulmod(var57, var30, r) + let var59 := addmod(var56, var58, r) + let var60 := addmod(mulmod(var33, q_trash_tau, r), var59, r) + let f_2 := mload(0x9aa0) + let var61 := mulmod(a_3, var0, r) + let var62 := addmod(f_2, var61, r) + let var63 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 + let var64 := mulmod(var63, a_0, r) + let var65 := addmod(var62, var64, r) + let var66 := 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a + let var67 := mulmod(var66, a_1, r) + let var68 := addmod(var65, var67, r) + let var69 := 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db + let var70 := mulmod(var69, var10, r) + let var71 := addmod(var68, var70, r) + let var72 := addmod(mulmod(var60, q_trash_tau, r), var71, r) + let f_3 := mload(0x9ac0) + let var73 := mulmod(a_4, var0, r) + let var74 := addmod(f_3, var73, r) + let var75 := 0x222e83e70453dfee19b402e9fa8dfe2c4987b034d0be3ceb478b3022e97934c1 + let var76 := mulmod(var75, a_0, r) + let var77 := addmod(var74, var76, r) + let var78 := 0x26c2cc87f95726b28f33ca03409a460ec987cfe12adae32769e3565865d07191 + let var79 := mulmod(var78, a_1, r) + let var80 := addmod(var77, var79, r) + let var81 := 0x4382d0938a760120dd6cef8f3b90a0c38abae475e3d21e39365472b76d780272 + let var82 := mulmod(var81, var10, r) + let var83 := addmod(var80, var82, r) + let var84 := mulmod(var69, var14, r) + let var85 := addmod(var83, var84, r) + let var86 := addmod(mulmod(var72, q_trash_tau, r), var85, r) + let f_4 := mload(0x99c0) + let var87 := mulmod(a_5, var0, r) + let var88 := addmod(f_4, var87, r) + let var89 := 0x726df1506749848155630b86ae25a82b281ecd050fe3a52d85a181fa87202e4b + let var90 := mulmod(var89, a_0, r) + let var91 := addmod(var88, var90, r) + let var92 := 0x24822e1af9aa2887c912c87eb0f20bd332330e7e55cd784de67cb407a9f05520 + let var93 := mulmod(var92, a_1, r) + let var94 := addmod(var91, var93, r) + let var95 := 0x4e5280109d8f96b8bfb543a6b1af25fb56a9db616af85a90eedc558e3eb1ea29 + let var96 := mulmod(var95, var10, r) + let var97 := addmod(var94, var96, r) + let var98 := mulmod(var81, var14, r) + let var99 := addmod(var97, var98, r) + let var100 := mulmod(var69, var18, r) + let var101 := addmod(var99, var100, r) + let var102 := addmod(mulmod(var86, q_trash_tau, r), var101, r) + let f_5 := mload(0x99e0) + let var103 := mulmod(a_6, var0, r) + let var104 := addmod(f_5, var103, r) + let var105 := 0x2f5908b169c6cf1bd26dcf0f9e5105481f5164f3ece0582bf3098312167751a7 + let var106 := mulmod(var105, a_0, r) + let var107 := addmod(var104, var106, r) + let var108 := 0x23a6684b942d726a22e4d5b8d8ff83aeaa773f62600184efe5d033d7c7c6e827 + let var109 := mulmod(var108, a_1, r) + let var110 := addmod(var107, var109, r) + let var111 := 0x1981b4b33d6a9dab957b351d981d3323e65da39493af5bc01f7e8ffe17f98d4e + let var112 := mulmod(var111, var10, r) + let var113 := addmod(var110, var112, r) + let var114 := mulmod(var95, var14, r) + let var115 := addmod(var113, var114, r) + let var116 := mulmod(var81, var18, r) + let var117 := addmod(var115, var116, r) + let var118 := mulmod(var69, var22, r) + let var119 := addmod(var117, var118, r) + let var120 := addmod(mulmod(var102, q_trash_tau, r), var119, r) + let f_6 := mload(0x9a00) + let var121 := mulmod(a_7, var0, r) + let var122 := addmod(f_6, var121, r) + let var123 := 0x6d05a41959f539a7fc9ec0972ea1e3dbb6fc67dd51daf3414f7fbbb091c7274a + let var124 := mulmod(var123, a_0, r) + let var125 := addmod(var122, var124, r) + let var126 := 0x27e7119226c42a6d19c1541904b99ae40685511ed2e078964b74594d38340849 + let var127 := mulmod(var126, a_1, r) + let var128 := addmod(var125, var127, r) + let var129 := 0xd94c46a8456352aa44d7a885ab59e3a36664e6fb25e826f8a4cd79822f0533 + let var130 := mulmod(var129, var10, r) + let var131 := addmod(var128, var130, r) + let var132 := mulmod(var111, var14, r) + let var133 := addmod(var131, var132, r) + let var134 := mulmod(var95, var18, r) + let var135 := addmod(var133, var134, r) + let var136 := mulmod(var81, var22, r) + let var137 := addmod(var135, var136, r) + let var138 := mulmod(var69, var26, r) + let var139 := addmod(var137, var138, r) + let var140 := addmod(mulmod(var120, q_trash_tau, r), var139, r) + let f_7 := mload(0x9a20) + let a_2_next_1 := mload(0x9580) + let var141 := mulmod(a_2_next_1, var0, r) + let var142 := addmod(f_7, var141, r) + let var143 := 0x70d8f2a733a64d650faccc9b1c2a766a9544bb3ff1a11ee73cb43947ef386633 + let var144 := mulmod(var143, a_0, r) + let var145 := addmod(var142, var144, r) + let var146 := 0x40fa389feb2522bb934881ac9ed749aee2296502af592418c6b5675c0f560261 + let var147 := mulmod(var146, a_1, r) + let var148 := addmod(var145, var147, r) + let var149 := 0x1f61345b652161410c5e29f51e301ae56342af824bc110649393d2b911c50d3e + let var150 := mulmod(var149, var10, r) + let var151 := addmod(var148, var150, r) + let var152 := mulmod(var129, var14, r) + let var153 := addmod(var151, var152, r) + let var154 := mulmod(var111, var18, r) + let var155 := addmod(var153, var154, r) + let var156 := mulmod(var95, var22, r) + let var157 := addmod(var155, var156, r) + let var158 := mulmod(var81, var26, r) + let var159 := addmod(var157, var158, r) + let var160 := mulmod(var69, var30, r) + let var161 := addmod(var159, var160, r) + let var162 := addmod(mulmod(var140, q_trash_tau, r), var161, r) + let f_26 := mload(0x9ba0) + let q_trash_one_minus_selector := addmod(1, sub(r, f_26), r) + let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0xa120), r) + let q_trash_eval := addmod(var162, sub(r, q_trash_scaled), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_trash_eval, r)) + } + } + // Finish selector buckets by applying the codegen-known tail + // from each selector's last identity to the end of the global + // y-batch. + // + // After this step, every selector bucket is aligned with the + // final global y position and can be multiplied by its fixed + // selector commitment in the linearized MSM. + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0600)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x05e0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0580)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0520)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x80) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x04c0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xa0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0460)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xc0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0400)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xe0) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x03a0)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0100) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0340)), r)) + } + { + let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0120) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0280)), r)) + } + + // Fully evaluated identities are the constant-polynomial side + // of the linearization query. Rust subtracts that grouped + // scalar into expected_eval, so Solidity stores -nu_y(x). + let linearization_expected_eval := addmod(0, sub(r, mload(0xb280)), r) + mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) + pop(y) + } + + // =============================================================== + // Prepare linearization scalars for the final PCS MSM. + // + // The linearized commitment is + // (1 - x^n) * Σ_i x_split^i * Q_i + // + Σ_j sel_acc_j * S_j_com, + // where x_split = x^(n-1). Instead of materializing that point + // with a standalone G1MSM here, PCS block 5 expands the + // linearized commitment into its quotient and selector + // pairs inside the already-fused final MSM. + // + // QUOTIENT_MPTR is no longer a G1 point in this path. Its first + // two words carry: + // word 0: x_split + // word 1: one_minus_x_n + // =============================================================== + { + let x := mload(X_MPTR) + let k := 20 + // Compute both x^n and x^(n-1) with the same squaring walk: + // x_pow_2i tracks x^(2^i), while x_pow_2i_minus1 tracks + // x^(2^i - 1). + let x_pow_2i := x + let x_pow_2i_minus1 := 1 + for { let idx := 0 } lt(idx, k) { idx := add(idx, 1) } { + x_pow_2i_minus1 := mulmod( + mulmod(x_pow_2i_minus1, x_pow_2i_minus1, r), + x, + r + ) + x_pow_2i := mulmod(x_pow_2i, x_pow_2i, r) + } + let x_split := x_pow_2i_minus1 + let one_minus_x_n := addmod(1, sub(r, x_pow_2i), r) + + // PCS block 5 interprets this 2-word payload as scalar + // metadata, not as a materialized G1 point. + mstore(QUOTIENT_MPTR, x_split) + mstore(add(QUOTIENT_MPTR, 0x20), one_minus_x_n) + } + + // =============================================================== + // PCS computation (multi-prepare emitter from Step 5). + // + // The Rust lowering stage has already expanded the KZG multi-open + // equation into a sequence of generated Yul sub-blocks. Those + // blocks populate: + // - F_EVAL_MPTR / V_MPTR scalar batching values; + // - FINAL_COM_MPTR for the fused commitment MSM; + // - PAIRING_LHS_MPTR and PAIRING_RHS_MPTR for the final pairing. + // =============================================================== + { + // Generated PCS sub-block 1. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // 4 distinct rotation(s) + let x := mload(X_MPTR) + let omega := mload(OMEGA_MPTR) + let omega_inv := mload(OMEGA_INV_MPTR) + let x_pow_of_omega := x + mstore(add(ROT_POINTS_MPTR, 0x40), x_pow_of_omega) + x_pow_of_omega := mulmod(x_pow_of_omega, omega, r) + mstore(add(ROT_POINTS_MPTR, 0x60), x_pow_of_omega) + x_pow_of_omega := x + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + mstore(add(ROT_POINTS_MPTR, 0x20), x_pow_of_omega) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + mstore(add(ROT_POINTS_MPTR, 0x0), x_pow_of_omega) + } + // Generated PCS sub-block 2. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // pre-compute 43 x1 power(s) + let x1 := mload(X1_MPTR) + mstore(X1_POWERS_MPTR, 1) + let acc := 1 + let p := X1_POWERS_MPTR + for { let i := 0 } lt(i, 0x2a) { i := add(i, 1) } { + p := add(p, 0x20) + acc := mulmod(acc, x1, r) + mstore(p, and(acc, 0xffffffffffffffffffffffffffffffff)) + } + } + // Generated PCS sub-block 3. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x9980) + mstore(0xb2a0, 0x9480) + mstore(0xb2c0, 0xa020) + mstore(0xb2e0, 0xa040) + mstore(0xb300, 0xa0a0) + mstore(0xb320, 0xa0c0) + mstore(0xb340, 0xa120) + mstore(0xb360, 0x99a0) + mstore(0xb380, 0x99c0) + mstore(0xb3a0, 0x99e0) + mstore(0xb3c0, 0x9a00) + mstore(0xb3e0, 0x9a20) + mstore(0xb400, 0x9a40) + mstore(0xb420, 0x9a60) + mstore(0xb440, 0x9a80) + mstore(0xb460, 0x9aa0) + mstore(0xb480, 0x9ac0) + mstore(0xb4a0, 0x9ae0) + mstore(0xb4c0, 0x9b00) + mstore(0xb4e0, 0x9b20) + mstore(0xb500, 0x9b40) + mstore(0xb520, 0x9b60) + mstore(0xb540, 0x9b80) + mstore(0xb560, 0x9ba0) + mstore(0xb580, 0x9bc0) + mstore(0xb5a0, 0x9be0) + mstore(0xb5c0, 0x9c00) + mstore(0xb5e0, 0x9c20) + mstore(0xb600, 0x9c40) + mstore(0xb620, 0x9c60) + mstore(0xb640, 0x9c80) + mstore(0xb660, 0x9ca0) + mstore(0xb680, 0x9cc0) + mstore(0xb6a0, 0x9ce0) + mstore(0xb6c0, 0x9d00) + mstore(0xb6e0, 0x9d20) + mstore(0xb700, 0x9d40) + mstore(0xb720, 0x9d60) + mstore(0xb740, 0x9d80) + mstore(0xb760, 0x9da0) + mstore(0xb780, 0x9dc0) + mstore(0xb7a0, 0x9de0) + mstore(0xb7c0, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x9980) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x20) + for { let i := 1 } lt(i, 0x2b) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x20) + } + mstore(add(Q_EVAL_SET_MPTR, 0x0), q_eval_set_0) + } + // Generated PCS sub-block 4. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[1]: 3 commitment(s) + let q_eval_set_0 := mload(0x9660) + let q_eval_set_1 := mload(0x9920) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9940), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x96a0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9960), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) + } + // Generated PCS sub-block 5. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[2]: 3 commitment(s) + let q_eval_set_0 := mload(0x9fe0) + let q_eval_set_1 := mload(0xa000) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa080), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa0e0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa100), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) + } + // Generated PCS sub-block 6. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x94a0) + mstore(0xb2a0, 0x9540) + mstore(0xb2c0, 0x97c0) + mstore(0xb2e0, 0x94c0) + mstore(0xb300, 0x9560) + mstore(0xb320, 0x97e0) + mstore(0xb340, 0x94e0) + mstore(0xb360, 0x9580) + mstore(0xb380, 0x9800) + mstore(0xb3a0, 0x9500) + mstore(0xb3c0, 0x96c0) + mstore(0xb3e0, 0x9820) + mstore(0xb400, 0x9520) + mstore(0xb420, 0x96e0) + mstore(0xb440, 0x9840) + mstore(0xb460, 0x95a0) + mstore(0xb480, 0x9700) + mstore(0xb4a0, 0x9860) + mstore(0xb4c0, 0x95c0) + mstore(0xb4e0, 0x9720) + mstore(0xb500, 0x9880) + mstore(0xb520, 0x95e0) + mstore(0xb540, 0x9740) + mstore(0xb560, 0x98a0) + mstore(0xb580, 0x9600) + mstore(0xb5a0, 0x9760) + mstore(0xb5c0, 0x98c0) + mstore(0xb5e0, 0x9620) + mstore(0xb600, 0x9780) + mstore(0xb620, 0x98e0) + mstore(0xb640, 0x9640) + mstore(0xb660, 0x97a0) + mstore(0xb680, 0x9900) + let q_eval_set_0 := mload(0x94a0) + let q_eval_set_1 := mload(0x9540) + let q_eval_set_2 := mload(0x97c0) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x60) + for { let i := 1 } lt(i, 0xb) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(mload(add(eval_p, 0x20))), pow, r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(mload(add(eval_p, 0x40))), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x60) + } + mstore(add(Q_EVAL_SET_MPTR, 0xa0), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_1) + mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_2) + } + // Generated PCS sub-block 7. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) + // stage per-(commit, rotation) eval source addresses + mstore(0xb280, 0x9e00) + mstore(0xb2a0, 0x9e20) + mstore(0xb2c0, 0x9e40) + mstore(0xb2e0, 0x9e60) + mstore(0xb300, 0x9e80) + mstore(0xb320, 0x9ea0) + mstore(0xb340, 0x9ec0) + mstore(0xb360, 0x9ee0) + mstore(0xb380, 0x9f00) + mstore(0xb3a0, 0x9f20) + mstore(0xb3c0, 0x9f40) + mstore(0xb3e0, 0x9f60) + mstore(0xb400, 0x9f80) + mstore(0xb420, 0x9fa0) + mstore(0xb440, 0x9fc0) + let q_eval_set_0 := mload(0x9e00) + let q_eval_set_1 := mload(0x9e20) + let q_eval_set_2 := mload(0x9e40) + let pow_p := add(X1_POWERS_MPTR, 0x20) + let eval_p := add(0xb280, 0x60) + for { let i := 1 } lt(i, 0x5) { i := add(i, 1) } { + let pow := mload(pow_p) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(mload(add(eval_p, 0x20))), pow, r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(mload(add(eval_p, 0x40))), pow, r), r) + pow_p := add(pow_p, 0x20) + eval_p := add(eval_p, 0x60) + } + mstore(add(Q_EVAL_SET_MPTR, 0x100), q_eval_set_0) + mstore(add(Q_EVAL_SET_MPTR, 0x120), q_eval_set_1) + mstore(add(Q_EVAL_SET_MPTR, 0x140), q_eval_set_2) + } + // Generated PCS sub-block 8. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // f_eval via Horner over 5 reversed set(s) + let x2 := mload(X2_MPTR) + let x3 := mload(X3_MPTR) + let f_eval := 0 + let Q_EVAL_CPTR := mload(Q_EVAL_CPTR_MPTR) + let rot_pt_0 := mload(add(ROT_POINTS_MPTR, 0x0)) + let rot_pt_1 := mload(add(ROT_POINTS_MPTR, 0x20)) + let rot_pt_2 := mload(add(ROT_POINTS_MPTR, 0x40)) + let rot_pt_3 := mload(add(ROT_POINTS_MPTR, 0x60)) + // --- set 4 (cardinality 3) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let dx_2 := addmod(x3, sub(r, rot_pt_0), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_0), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_0), r), r) + let lbasis_2 := 1 + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_0, sub(r, rot_pt_2), r), r) + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_0, sub(r, rot_pt_3), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, dx_2, r) + let bp_3 := mulmod(bp_2, lbasis_0, r) + let bp_4 := mulmod(bp_3, lbasis_1, r) + let bp_5 := mulmod(bp_4, lbasis_2, r) + let bq := scalar_inv(bp_5) + let lbasis_inv_2 := mulmod(bq, bp_4, r) + bq := mulmod(bq, lbasis_2, r) + let lbasis_inv_1 := mulmod(bq, bp_3, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_2 := mulmod(bq, bp_1, r) + bq := mulmod(bq, dx_2, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + den_inv := mulmod(den_inv, dx_inv_2, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x80)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x100)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x120)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + let term_2 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x140)), dx_inv_2, r), lbasis_inv_2, r) + eval := addmod(eval, sub(r, term_2), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 3 (cardinality 3) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let dx_2 := addmod(x3, sub(r, rot_pt_1), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_1), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_1), r), r) + let lbasis_2 := 1 + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_1, sub(r, rot_pt_2), r), r) + lbasis_2 := mulmod(lbasis_2, addmod(rot_pt_1, sub(r, rot_pt_3), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, dx_2, r) + let bp_3 := mulmod(bp_2, lbasis_0, r) + let bp_4 := mulmod(bp_3, lbasis_1, r) + let bp_5 := mulmod(bp_4, lbasis_2, r) + let bq := scalar_inv(bp_5) + let lbasis_inv_2 := mulmod(bq, bp_4, r) + bq := mulmod(bq, lbasis_2, r) + let lbasis_inv_1 := mulmod(bq, bp_3, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_2 := mulmod(bq, bp_1, r) + bq := mulmod(bq, dx_2, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + den_inv := mulmod(den_inv, dx_inv_2, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xa0)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xc0)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + let term_2 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0xe0)), dx_inv_2, r), lbasis_inv_2, r) + eval := addmod(eval, sub(r, term_2), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 2 (cardinality 2) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_3), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_3), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_3, sub(r, rot_pt_2), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, lbasis_0, r) + let bp_3 := mulmod(bp_2, lbasis_1, r) + let bq := scalar_inv(bp_3) + let lbasis_inv_1 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_1, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x60)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x80)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 1 (cardinality 2) --- + { + let dx_0 := addmod(x3, sub(r, rot_pt_2), r) + let dx_1 := addmod(x3, sub(r, rot_pt_1), r) + let lbasis_0 := 1 + lbasis_0 := mulmod(lbasis_0, addmod(rot_pt_2, sub(r, rot_pt_1), r), r) + let lbasis_1 := 1 + lbasis_1 := mulmod(lbasis_1, addmod(rot_pt_1, sub(r, rot_pt_2), r), r) + let bp_0 := dx_0 + let bp_1 := mulmod(bp_0, dx_1, r) + let bp_2 := mulmod(bp_1, lbasis_0, r) + let bp_3 := mulmod(bp_2, lbasis_1, r) + let bq := scalar_inv(bp_3) + let lbasis_inv_1 := mulmod(bq, bp_2, r) + bq := mulmod(bq, lbasis_1, r) + let lbasis_inv_0 := mulmod(bq, bp_1, r) + bq := mulmod(bq, lbasis_0, r) + let dx_inv_1 := mulmod(bq, bp_0, r) + bq := mulmod(bq, dx_1, r) + let dx_inv_0 := bq + let den_inv := dx_inv_0 + den_inv := mulmod(den_inv, dx_inv_1, r) + let eval := mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), den_inv, r) + let term_0 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x20)), dx_inv_0, r), lbasis_inv_0, r) + eval := addmod(eval, sub(r, term_0), r) + let term_1 := mulmod(mulmod(mload(add(Q_EVAL_SET_MPTR, 0x40)), dx_inv_1, r), lbasis_inv_1, r) + eval := addmod(eval, sub(r, term_1), r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + // --- set 0 (cardinality 1) --- + { + let dx0 := addmod(x3, sub(r, rot_pt_2), r) + let dx0_inv := scalar_inv(dx0) + let eval := mulmod(addmod(calldataload(add(Q_EVAL_CPTR, 0x0)), sub(r, mload(add(Q_EVAL_SET_MPTR, 0x0))), r), dx0_inv, r) + f_eval := addmod(mulmod(f_eval, x2, r), eval, r) + } + mstore(F_EVAL_MPTR, f_eval) + } + // Generated PCS sub-block 9. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // build final_com and v (KZG single-opening proof, fused MSM) + // final MSM input length from circuit/VK shape: 78 term(s) + let x4 := mload(X4_MPTR) + let lin_x_split := mload(QUOTIENT_MPTR) + let lin_one_minus_x_n := mload(add(QUOTIENT_MPTR, 0x20)) + let Q_EVAL_CPTR := mload(Q_EVAL_CPTR_MPTR) + let x4_pow_full := 1 + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_1 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_2 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_3 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_4 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_5 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + let v := calldataload(Q_EVAL_CPTR) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), x4_pow_1, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), x4_pow_3, r), r) + v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x80)), x4_pow_4, r), r) + v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_5, r), r) + mcopy(0xb280, 0xa840, 0x80) + mstore(0xb300, 1) + mcopy(0xb320, 0xa8c0, 0x80) + mstore(0xb3a0, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0xb3c0, 0xacc0, 0x80) + mstore(0xb440, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0xb460, 0xa940, 0x80) + mstore(0xb4e0, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0xb500, 0xad40, 0x80) + mstore(0xb580, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0xb5a0, 0xaec0, 0x80) + mstore(0xb620, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0xb640, 0x6700, 0x80) + mstore(0xb6c0, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0xb6e0, 0x6480, 0x80) + mstore(0xb760, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0xb780, 0x6500, 0x80) + mstore(0xb800, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0xb820, 0x6580, 0x80) + mstore(0xb8a0, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0xb8c0, 0x6600, 0x80) + mstore(0xb940, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0xb960, 0x6680, 0x80) + mstore(0xb9e0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0xba00, 0x6280, 0x80) + mstore(0xba80, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0xbaa0, 0x6300, 0x80) + mstore(0xbb20, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0xbb40, 0x6380, 0x80) + mstore(0xbbc0, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0xbbe0, 0x6400, 0x80) + mstore(0xbc60, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0xbc80, 0x6780, 0x80) + mstore(0xbd00, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0xbd20, 0x6800, 0x80) + mstore(0xbda0, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0xbdc0, 0x6880, 0x80) + mstore(0xbe40, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0xbe60, 0x6900, 0x80) + mstore(0xbee0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0xbf00, 0x6b00, 0x80) + mstore(0xbf80, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0xbfa0, 0x6e80, 0x80) + mstore(0xc020, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0xc040, 0x6f80, 0x80) + mstore(0xc0c0, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0xc0e0, 0x7000, 0x80) + mstore(0xc160, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0xc180, 0x7080, 0x80) + mstore(0xc200, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0xc220, 0x7100, 0x80) + mstore(0xc2a0, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0xc2c0, 0x7180, 0x80) + mstore(0xc340, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0xc360, 0x7200, 0x80) + mstore(0xc3e0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0xc400, 0x7280, 0x80) + mstore(0xc480, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0xc4a0, 0x7300, 0x80) + mstore(0xc520, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0xc540, 0x7380, 0x80) + mstore(0xc5c0, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0xc5e0, 0x7400, 0x80) + mstore(0xc660, mload(add(X1_POWERS_MPTR, 0x400))) + mcopy(0xc680, 0x7480, 0x80) + mstore(0xc700, mload(add(X1_POWERS_MPTR, 0x420))) + mcopy(0xc720, 0x7500, 0x80) + mstore(0xc7a0, mload(add(X1_POWERS_MPTR, 0x440))) + mcopy(0xc7c0, 0x7580, 0x80) + mstore(0xc840, mload(add(X1_POWERS_MPTR, 0x460))) + mcopy(0xc860, 0x7600, 0x80) + mstore(0xc8e0, mload(add(X1_POWERS_MPTR, 0x480))) + mcopy(0xc900, 0x7680, 0x80) + mstore(0xc980, mload(add(X1_POWERS_MPTR, 0x4a0))) + mcopy(0xc9a0, 0x7700, 0x80) + mstore(0xca20, mload(add(X1_POWERS_MPTR, 0x4c0))) + mcopy(0xca40, 0x7780, 0x80) + mstore(0xcac0, mload(add(X1_POWERS_MPTR, 0x4e0))) + mcopy(0xcae0, 0x7800, 0x80) + mstore(0xcb60, mload(add(X1_POWERS_MPTR, 0x500))) + mcopy(0xcb80, 0x7880, 0x80) + mstore(0xcc00, mload(add(X1_POWERS_MPTR, 0x520))) + let lin_query_scalar_41 := mload(add(X1_POWERS_MPTR, 0x540)) + let lin_cur_scalar_41 := mulmod(lin_query_scalar_41, lin_one_minus_x_n, r) + mcopy(0xcc20, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0xcca0, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xccc0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0xcd40, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xcd60, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0xcde0, lin_cur_scalar_41) + lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) + mcopy(0xce00, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0xce80, lin_cur_scalar_41) + mcopy(0xcea0, 0x6980, 0x80) + mstore(0xcf20, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0xcf40, 0x6a00, 0x80) + mstore(0xcfc0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0xcfe0, 0x6a80, 0x80) + mstore(0xd060, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0xd080, 0x6b80, 0x80) + mstore(0xd100, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0xd120, 0x6c00, 0x80) + mstore(0xd1a0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) + mcopy(0xd1c0, 0x6c80, 0x80) + mstore(0xd240, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) + mcopy(0xd260, 0x6d00, 0x80) + mstore(0xd2e0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) + mcopy(0xd300, 0x6d80, 0x80) + mstore(0xd380, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) + mcopy(0xd3a0, 0x6e00, 0x80) + mstore(0xd420, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) + mcopy(0xd440, 0x6f00, 0x80) + mstore(0xd4c0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) + mcopy(0xd4e0, 0xa6c0, 0x80) + mstore(0xd560, x4_pow_1) + mcopy(0xd580, 0xa740, 0x80) + mstore(0xd600, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0xd620, 0xa7c0, 0x80) + mstore(0xd6a0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0xd6c0, 0xac40, 0x80) + mstore(0xd740, x4_pow_2) + mcopy(0xd760, 0xadc0, 0x80) + mstore(0xd7e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0xd800, 0xae40, 0x80) + mstore(0xd880, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) + mcopy(0xd8a0, 0xa140, 0x80) + mstore(0xd920, x4_pow_3) + mcopy(0xd940, 0xa1c0, 0x80) + mstore(0xd9c0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) + mcopy(0xd9e0, 0xa240, 0x80) + mstore(0xda60, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_3, r)) + mcopy(0xda80, 0xa2c0, 0x80) + mstore(0xdb00, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_3, r)) + mcopy(0xdb20, 0xa340, 0x80) + mstore(0xdba0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_3, r)) + mcopy(0xdbc0, 0xa3c0, 0x80) + mstore(0xdc40, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_3, r)) + mcopy(0xdc60, 0xa440, 0x80) + mstore(0xdce0, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_3, r)) + mcopy(0xdd00, 0xa4c0, 0x80) + mstore(0xdd80, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_3, r)) + mcopy(0xdda0, 0xa540, 0x80) + mstore(0xde20, mulmod(mload(add(X1_POWERS_MPTR, 0x100)), x4_pow_3, r)) + mcopy(0xde40, 0xa5c0, 0x80) + mstore(0xdec0, mulmod(mload(add(X1_POWERS_MPTR, 0x120)), x4_pow_3, r)) + mcopy(0xdee0, 0xa640, 0x80) + mstore(0xdf60, mulmod(mload(add(X1_POWERS_MPTR, 0x140)), x4_pow_3, r)) + mcopy(0xdf80, 0xa9c0, 0x80) + mstore(0xe000, x4_pow_4) + mcopy(0xe020, 0xaa40, 0x80) + mstore(0xe0a0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_4, r)) + mcopy(0xe0c0, 0xaac0, 0x80) + mstore(0xe140, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_4, r)) + mcopy(0xe160, 0xab40, 0x80) + mstore(0xe1e0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_4, r)) + mcopy(0xe200, 0xabc0, 0x80) + mstore(0xe280, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_4, r)) + mcopy(0xe2a0, F_COM_MPTR, 0x80) + mstore(0xe320, x4_pow_5) + if success { + success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mstore(V_MPTR, v) + } + // Generated PCS sub-block 10. These lines are + // emitted by the multi-prepare lowering pass and are kept + // grouped so gas checkpoints can attribute their cost. + { + // Scale z*pi - vG before the final pairing check + // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) + mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) + if success { + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(0x1080, FINAL_COM_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) + if success { + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + if success { + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) + } + } + + // Batch the prevalidated public IVC accumulator pairing equation + // into the final KZG pairing. + // + // We do not simply multiply the two pairing equations together: + // two bad equations could cancel. Instead, after all four G1 + // pairing inputs are fixed, derive a verifier-local randomizer + // alpha and check: + // + // e(kzg_rhs + alpha * acc_rhs, G2_BASE) + // * e(kzg_lhs + alpha * acc_lhs, NEG_S_G2_BASE) == 1 + // + // If either original equation is bad, this combined equation + // holds for at most one alpha in Fr. + { + let batch_ptr := 0x0100 + + // Domain || KZG rhs/lhs || accumulator rhs/lhs. + mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) + mcopy(add(batch_ptr, 0x20), PAIRING_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0xa0), PAIRING_LHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x0120), ACC_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x01a0), ACC_LHS_MPTR, 0x80) + // alpha is Fiat-Shamir over the fully materialized pairing + // inputs. Replace the negligible zero draw with one so the + // accumulator equation cannot be accidentally dropped. + let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0220), r) + if iszero(acc_pair_alpha) { acc_pair_alpha := 1 } + + // PAIRING_RHS_MPTR += alpha * ACC_RHS_MPTR. + // First compute alpha * ACC_RHS with a one-pair G1MSM, then + // add it into the KZG RHS point. + mcopy(batch_ptr, ACC_RHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x80), acc_pair_alpha) + if success { + success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(add(batch_ptr, 0x80), PAIRING_RHS_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + + // PAIRING_LHS_MPTR += alpha * ACC_LHS_MPTR. + // Mirror the same randomized batching on the KZG LHS point. + mcopy(batch_ptr, ACC_LHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x80), acc_pair_alpha) + if success { + success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + mcopy(add(batch_ptr, 0x80), PAIRING_LHS_MPTR, 0x80) + if success { + success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) + success := and(success, eq(returndatasize(), 0x80)) + } + } + + // The Yul `ec_pairing` helper checks + // e(arg0, G2_BASE) * e(arg1, NEG_S_G2_BASE) == 1 + // i.e. e(arg0, [1]_2) = e(arg1, [s]_2). + // + // The KZG pairing identity is + // e(final_com - v*G + x3*pi, [1]_2) = e(pi, [s]_2), + // so arg0 must be (final_com - v*G + x3*pi) and arg1 must be + // pi. The PAIRING_*_MPTR slots store + // PAIRING_LHS_MPTR := pi + // PAIRING_RHS_MPTR := final_com - v*G + x3*pi + // -- the historical "LHS"/"RHS" naming follows the dual MSM + // accumulator (left = pi, right = combined) and *not* the + // pairing argument order. Pass them swapped to ec_pairing. + if iszero(success) { revert(0, 0) } + success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) + + + + // Success path is terminal. Invalid inputs have already reverted, + // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } + mstore(RETURN_MPTR, 1) + return(RETURN_MPTR, 0x20) + } + } +} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol new file mode 100644 index 000000000..8f0b378f8 --- /dev/null +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: CC0-1.0 + +pragma solidity ^0.8.24; + +/// @title Halo2 BLS12-381 verifying-key payload. +/// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. +/// @dev Byte 0 is an unconditional INVALID opcode so direct calls cannot execute payload bytes as code. The linked verifier pins the full runtime by length/codehash and copies the payload starting at byte 1. +/// @dev The layout follows the verifier inputs derived from +/// `midfall/proofs/src/plonk/mod.rs::VerifyingKey` and the transcript +/// `vk.hash_into` behavior used by `midfall/proofs/src/plonk/verifier.rs`. +/// +/// Layout (in 32-byte words, big-endian). The header slots are generated from +/// Rust's `VkHeaderLayout`; the byte offsets are absolute from the start of the +/// VK payload, not from byte 0 of the runtime. Runtime byte 0 is the INVALID +/// prefix; the verifier loads the payload via +/// `extcodecopy(vk, VK_MPTR, 0x01, vk_payload_len)` and then references each +/// slot by `VK_MPTR + i`. +/// +/// word 0 : vk_digest (Fq, transcript_repr of the CS) +/// word 1 : num_instances +/// word 2 : k (log2 of the domain size) +/// word 3 : n_inv (1/n in Fr) +/// word 4 : omega (n-th primitive root of unity) +/// word 5 : omega_inv +/// word 6 : omega_inv_to_l (omega_inv ^ |rotation_last|) +/// word 7 : has_accumulator (0 or 1) +/// word 8 : acc_offset (instance index of the accumulator) +/// word 9 : num_acc_limbs +/// word 10 : num_acc_limb_bits +/// word 11..14 : G1_BASE (4 words, EIP-2537 padded) +/// word 15..22 : G2_BASE (8 words, EIP-2537 padded) +/// word 23..30 : NEG_S_G2_BASE (8 words, EIP-2537 padded) +/// word 31..30 + Q_PAYLOAD : quotient VM constants + packed bytecode +/// word 31 + Q_PAYLOAD .. : fixed_comms (4 words each) +/// word 31 + Q_PAYLOAD + 4*N_FIXED .. +/// : permutation_comms (4 words each) +/// +/// Notes: +/// - `extcodehash` of this contract is pinned by the linked verifier via +/// `EXPECTED_VK_CODEHASH`, so any byte tweak is detected at deploy time. +/// - The quotient identity interpreter's static program is stored in this +/// pinned VK runtime. The verifier reads it from memory after `extcodecopy`, +/// avoiding verifier-side PUSH32/mstore immediates while keeping the program +/// covered by `EXPECTED_VK_CODEHASH`. +/// - The midnight-proofs migration bakes the per-lookup chunk counts, trashcan +/// structure, and `num_simple_selectors` into the generated verifier code. +contract Halo2VerifyingKey { + /// @notice Deploy the verifying-key payload as this contract's runtime bytecode. + /// @dev The constructor writes an INVALID byte followed by generated words into memory and returns that prefixed runtime. + /// @dev The transient construction buffer starts at `0x80`, preserving Solidity's reserved memory words. + constructor() { + assembly { + // Runtime layout: + // byte 0 : INVALID, so the payload cannot be executed + // byte 1..end : generated VK payload copied by Halo2Verifier + // + // `runtime` includes the INVALID prefix; `payload` points to word + // zero of the verifier-key data described in the contract NatSpec. + let runtime := 0x80 + let payload := add(runtime, 0x01) + mstore8(runtime, 0xfe) + // Header, base-point, and quotient-program words generated from + // VkPayloadLayout. The inline names on each mstore identify the + // exact slot in the rendered source. + mstore(add(payload, 0x0000), 0x56c0824fcff237dd8dc7b15f527346d9e1647d191815acb142500b0293e84f66) // vk_digest + mstore(add(payload, 0x0020), 0x0000000000000000000000000000000000000000000000000000000000000013) // num_instances + mstore(add(payload, 0x0040), 0x0000000000000000000000000000000000000000000000000000000000000014) // k + mstore(add(payload, 0x0060), 0x73eda0144f284aae5b6554d46c21576b363d4ec725be2bff1a400fff00001001) // n_inv + mstore(add(payload, 0x0080), 0x03e1c54bcb947035a57a6e07cb98de4a2f69e02d265e09d9fece7e0e39898d4b) // omega + mstore(add(payload, 0x00a0), 0x6c39442eade0092768ac033fa6f608750624a1bb17dbc026ef97c3573a28fc8c) // omega_inv + mstore(add(payload, 0x00c0), 0x2a0ccbaa0613f093f2bb6e97859513f0b613d8587eaa92db9e5604b8d6b68d45) // omega_inv_to_l + mstore(add(payload, 0x00e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // has_accumulator + mstore(add(payload, 0x0100), 0x000000000000000000000000000000000000000000000000000000000000000b) // acc_offset + mstore(add(payload, 0x0120), 0x0000000000000000000000000000000000000000000000000000000000000007) // num_acc_limbs + mstore(add(payload, 0x0140), 0x0000000000000000000000000000000000000000000000000000000000000038) // num_acc_limb_bits + mstore(add(payload, 0x0160), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) // g1_x_hi + mstore(add(payload, 0x0180), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) // g1_x_lo + mstore(add(payload, 0x01a0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) // g1_y_hi + mstore(add(payload, 0x01c0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) // g1_y_lo + mstore(add(payload, 0x01e0), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) // g2_x_c0_hi + mstore(add(payload, 0x0200), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) // g2_x_c0_lo + mstore(add(payload, 0x0220), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) // g2_x_c1_hi + mstore(add(payload, 0x0240), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) // g2_x_c1_lo + mstore(add(payload, 0x0260), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) // g2_y_c0_hi + mstore(add(payload, 0x0280), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) // g2_y_c0_lo + mstore(add(payload, 0x02a0), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) // g2_y_c1_hi + mstore(add(payload, 0x02c0), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) // g2_y_c1_lo + mstore(add(payload, 0x02e0), 0x000000000000000000000000000000000632aaf712568f19c297802268a7ad9d) // neg_s_g2_x_c0_hi + mstore(add(payload, 0x0300), 0xceea6ef7ab6f75a7d26781c8e90c7432bc5e99dcc219ba64010f3052123983ab) // neg_s_g2_x_c0_lo + mstore(add(payload, 0x0320), 0x00000000000000000000000000000000191ff4920e077a2f8cb3969ba8f05bc2) // neg_s_g2_x_c1_hi + mstore(add(payload, 0x0340), 0xaa9da8c95d640b1e051be7cf344ee7f01996df2568bf0e7ccd9eb70978820045) // neg_s_g2_x_c1_lo + mstore(add(payload, 0x0360), 0x0000000000000000000000000000000005f434ebf45460a864ad5b17497c7903) // neg_s_g2_y_c0_hi + mstore(add(payload, 0x0380), 0x71820c70c83aa186029536d22dff54373251152c28bc43269f95281eba1b012e) // neg_s_g2_y_c0_lo + mstore(add(payload, 0x03a0), 0x0000000000000000000000000000000004d1c747141bcac15e77e3e1d3853254) // neg_s_g2_y_c1_hi + mstore(add(payload, 0x03c0), 0xc8687afdad35345a04f79d9c2759007f6640676eb44aee7011ce5ad80744bb23) // neg_s_g2_y_c1_lo + mstore(add(payload, 0x03e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // quotient_const + mstore(add(payload, 0x0400), 0x00bbe1fbe9ef1e2d62490b03a82bf9ef10f5e9b2323033669cf6c50481f63e05) // quotient_const + mstore(add(payload, 0x0420), 0x0000000000000000000000000000000000000000000000000100000000000000) // quotient_const + mstore(add(payload, 0x0440), 0x0000000000000000000000000000000000010000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0460), 0x0000000000000000000000000000000000000000000000000000000400000000) // quotient_const + mstore(add(payload, 0x0480), 0x0000000000000000000000000000000000000000040000000000000000000000) // quotient_const + mstore(add(payload, 0x04a0), 0x0000000000000000000000000000000000000000000000000000000000001000) // quotient_const + mstore(add(payload, 0x04c0), 0x0000000000000000000000000000000000000000000000100000000000000000) // quotient_const + mstore(add(payload, 0x04e0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000) // quotient_const + mstore(add(payload, 0x0500), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefeffffff00000001) // quotient_const + mstore(add(payload, 0x0520), 0x73eda753299d7d483339d80809a1d80553bca402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x0540), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffb00000001) // quotient_const + mstore(add(payload, 0x0560), 0x73eda753299d7d483339d80809a1d80553bda402fbfe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x0580), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffefffff001) // quotient_const + mstore(add(payload, 0x05a0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5beeffffffff00000001) // quotient_const + mstore(add(payload, 0x05c0), 0x00000000000000000000000000000010ff0726c5de281020ad8016cf6f691213) // quotient_const + mstore(add(payload, 0x05e0), 0x0000000000000000000000000000002c64068790f917282347187665718b04c8) // quotient_const + mstore(add(payload, 0x0600), 0x00000000000000000000000000000027241bb5338dce8a77499428839473bf3a) // quotient_const + mstore(add(payload, 0x0620), 0x0000000000000000000000000000002b7c4a26a1c7ae6fc4b499d04e4a463c4b) // quotient_const + mstore(add(payload, 0x0640), 0x000000000000000000000000000000274bc40fcf526be95333a8c22c79465298) // quotient_const + mstore(add(payload, 0x0660), 0x0000000000000000000000000000002a5ee6db49930276e2939d1c43ac82f744) // quotient_const + mstore(add(payload, 0x0680), 0x73eda753299d7d483339d80809a1d7edd77e26c51c38afb5debf8afa00c15cc3) // quotient_const + mstore(add(payload, 0x06a0), 0x73eda753299d7d483339d80809a1d7c553bda402fffe5bfeffffffff00000002) // quotient_const + mstore(add(payload, 0x06c0), 0x73eda753299d7d483339d80809a1d80553bda402fffe53ebc627fffef6280001) // quotient_const + mstore(add(payload, 0x06e0), 0x0000000000000000000001000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0700), 0x0000000100000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0720), 0x6bc66e553973f396854f5626172ba135587d41e37a68209402355093fdcaaf6c) // quotient_const + mstore(add(payload, 0x0740), 0x63f31e3f446953960c9d6964474300df43ab29179970f642a28e39d6c883c74b) // quotient_const + mstore(add(payload, 0x0760), 0x73eda753299d7d483339d70809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x0780), 0x73eda752299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x07a0), 0x082738fdf02989b1adea81e1f27636cffb40621f85963b6afdcaaf6b02355095) // quotient_const + mstore(add(payload, 0x07c0), 0x0ffa8913e53429b2269c6ea3c25ed72610127aeb668d65bc5d71c628377c38b6) // quotient_const + mstore(add(payload, 0x07e0), 0x01ec1c0519185dfe86132d479c76d0786e1e037d0b05ca47648a1c5d29492c9b) // quotient_const + mstore(add(payload, 0x0800), 0x1e179025ca2470882b34e63940ccbd7ad9090bf414d43b696e093b5a8782528f) // quotient_const + mstore(add(payload, 0x0820), 0x4298bfee9a84c8ef8e83702075cb1abeb576f146636342e3db9ea6b0a4adf29d) // quotient_const + mstore(add(payload, 0x0840), 0x3c83b078e9abed278d042acc8f3bd21e228716f04be96af8025da860e2d1bba9) // quotient_const + mstore(add(payload, 0x0860), 0x427868260f487d1ef07edaadf37f5dbe705bd1318290f2577ae756b009c24f11) // quotient_const + mstore(add(payload, 0x0880), 0x03020e6a35e595abd22838beeadc45cfcb0545d85ca0ab2c59d44c203fac84a7) // quotient_const + mstore(add(payload, 0x08a0), 0x000000000000000000000000000000000000000000000000d201000000010000) // quotient_const + mstore(add(payload, 0x08c0), 0x0000000100001b7c3f8d3fe3c5b448f1bdeb2ae34698b72d6ce966fc208c05ed) // quotient_const + mstore(add(payload, 0x08e0), 0x73eda753299d7d483339d80809a1d7fd4057a4c12f26d1c1778e3360a6820001) // quotient_const + mstore(add(payload, 0x0900), 0x057797fa7060856f215654ff11006fe0acf6a437e9477bf6f782dfac86f2cf75) // quotient_const + mstore(add(payload, 0x0920), 0x0000000000000000000000000000000000000000000000000000000000000002) // quotient_const + mstore(add(payload, 0x0940), 0x0000000000000000000000000000000000000000000000000200000000000000) // quotient_const + mstore(add(payload, 0x0960), 0x0000000000000000000000000000000000020000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0980), 0x73eda753299d7d483339d80809a1d7e13511a4044eaa5bff4600ffff00005556) // quotient_const + mstore(add(payload, 0x09a0), 0x73eda753299d7d483339d80809a1d7c553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x09c0), 0x73eda753299d7d483339d80809a1d7d340dd972492de594de627fffefcb80349) // quotient_const + mstore(add(payload, 0x09e0), 0x73eda753299d7d483339d80809a1d7dbdc391ab4d8ac003bbd48021b82456c9b) // quotient_const + mstore(add(payload, 0x0a00), 0x73eda753299d7d483339d80809a1d7d1448ee5caf5eefcffbc9fabc57759e23f) // quotient_const + mstore(add(payload, 0x0a20), 0x73eda753299d7d483339d80809a1d80418c74cc18bb28443d3978d1fd47ffce1) // quotient_const + mstore(add(payload, 0x0a40), 0x0000000000000000000000000000006425c019bcda40056233b00000068ff970) // quotient_const + mstore(add(payload, 0x0a60), 0x00000000000000000000000000000052ef09129c4ea4b786856ffbc6fb7526cc) // quotient_const + mstore(add(payload, 0x0a80), 0x73eda753299d7d483339d80809a1d7d89a085d30fc8a7106a170ac2377c34ab9) // quotient_const + mstore(add(payload, 0x0aa0), 0x73eda753299d7d483339d80809a1d7f8ce65bb936f2d836012914aca65f077e1) // quotient_const + mstore(add(payload, 0x0ac0), 0x000000000000000000000000000000681e5d7c70141ebdfe86c0a873114c3b84) // quotient_const + mstore(add(payload, 0x0ae0), 0x000000000000000000000000000000297784894e27525bc342b7fde37dba9366) // quotient_const + mstore(add(payload, 0x0b00), 0x0000000000000000000000000000000275ecae82e897af7658d0e5be57000640) // quotient_const + mstore(add(payload, 0x0b20), 0x000000000000000000000000000000013af65741744bd7bb2c6872df2b800320) // quotient_const + mstore(add(payload, 0x0b40), 0x00000000000000000000000000000059736a8da406e7d5f0bd1ea7b710796a90) // quotient_const + mstore(add(payload, 0x0b60), 0x0000000000000000000000000000000c8557e86f90d0d89eed6eb5349a0f8820) // quotient_const + mstore(add(payload, 0x0b80), 0x0453ae02a5f228d8f956b5eab4fc92bbeea5eb26b6ae4b42b4fdfcfdf026aa22) // quotient_const + mstore(add(payload, 0x0ba0), 0x0000000000000000000000000000000000000000000000000000000800000000) // quotient_const + mstore(add(payload, 0x0bc0), 0x0000000000000000000000000000000000000000080000000000000000000000) // quotient_const + mstore(add(payload, 0x0be0), 0x0000000000000000000000000000000000000000000000000000000000002000) // quotient_const + mstore(add(payload, 0x0c00), 0x0000000000000000000000000000000000000000000000200000000000000000) // quotient_const + mstore(add(payload, 0x0c20), 0x73eda753299d7d483339d80809a1d7f454b67d3d21d64bde527fe92f9096edee) // quotient_const + mstore(add(payload, 0x0c40), 0x73eda753299d7d483339d80809a1d7d8efb71c7206e733dbb8e789998e74fb39) // quotient_const + mstore(add(payload, 0x0c60), 0x73eda753299d7d483339d80809a1d7de2fa1eecf722fd187b66bd77b6b8c40c7) // quotient_const + mstore(add(payload, 0x0c80), 0x73eda753299d7d483339d80809a1d7d9d7737d61384fec3a4b662fb0b5b9c3b6) // quotient_const + mstore(add(payload, 0x0ca0), 0x73eda753299d7d483339d80809a1d7de07f99433ad9272abcc573dd286b9ad69) // quotient_const + mstore(add(payload, 0x0cc0), 0x73eda753299d7d483339d80809a1d7daf4d6c8b96cfbe51c6c62e3bb537d08bd) // quotient_const + mstore(add(payload, 0x0ce0), 0x00000000000000000000000000000021fe0e4d8bbc5020415b002d9eded22426) // quotient_const + mstore(add(payload, 0x0d00), 0x00000000000000000000000000000058c80d0f21f22e50468e30eccae3160990) // quotient_const + mstore(add(payload, 0x0d20), 0x0000000000000000000000000000004e48376a671b9d14ee9328510728e77e74) // quotient_const + mstore(add(payload, 0x0d40), 0x00000000000000000000000000000056f8944d438f5cdf896933a09c948c7896) // quotient_const + mstore(add(payload, 0x0d60), 0x0000000000000000000000000000004e97881f9ea4d7d2a667518458f28ca530) // quotient_const + mstore(add(payload, 0x0d80), 0x73eda753299d7d4833351088b4af7508df8b737010b26e15294bfcbb9194fffd) // quotient_const + mstore(add(payload, 0x0da0), 0x0000000000000000000002000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0dc0), 0x0000000200000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x0de0), 0x639f3557494a69e4d764d44424b56a655d3cdfc3f4d1e529046aa128fb955ed7) // quotient_const + mstore(add(payload, 0x0e00), 0x53f8952b5f3529e3e600fac084e429b93398ae2c32e39086451c73ae91078e95) // quotient_const + mstore(add(payload, 0x0e20), 0x72018b4e10851f49ad26aac06d2b078ce59fa085f4f891b79b75e3a1d6b6d366) // quotient_const + mstore(add(payload, 0x0e40), 0x55d6172d5f790cc00804f1cec8d51a8a7ab4980eeb2a209591f6c4a4787dad72) // quotient_const + mstore(add(payload, 0x0e60), 0x3154e7648f18b458a4b667e793d6bd469e46b2bc9c9b191b2461594e5b520d64) // quotient_const + mstore(add(payload, 0x0e80), 0x3769f6da3ff19020a635ad3b7a6605e731368d12b414f106fda2579e1d2e4458) // quotient_const + mstore(add(payload, 0x0ea0), 0x31753f2d1a55002942bafd5a16227a46e361d2d17d6d69a78518a94ef63db0f0) // quotient_const + mstore(add(payload, 0x0ec0), 0x70eb98e8f3b7e79c61119f491ec5923588b85e2aa35db0d2a62bb3dec0537b5a) // quotient_const + mstore(add(payload, 0x0ee0), 0x03d8380a3230bbfd0c265a8f38eda0f0dc3c06fa160b948ec91438ba52925936) // quotient_const + mstore(add(payload, 0x0f00), 0x3c2f204b9448e1105669cc7281997af5b21217e829a876d2dc1276b50f04a51e) // quotient_const + mstore(add(payload, 0x0f20), 0x1143d88a0b6c1496e9cd0838e1f45d7817303e89c6c829c8b73d4d62495be539) // quotient_const + mstore(add(payload, 0x0f40), 0x0519b99ea9ba5d06e6ce7d9114d5cc36f15089dd97d479f104bb50c2c5a37751) // quotient_const + mstore(add(payload, 0x0f60), 0x110328f8f4f37cf5adc3dd53dd5ce3778cf9fe60052388aff5cead6113849e21) // quotient_const + mstore(add(payload, 0x0f80), 0x057797fa7060856f215655ff11006fee9a1697597c277945ddaadfac83aad2c0) // quotient_const + mstore(add(payload, 0x0fa0), 0x0000000000000000000000000000003212e00cde6d2002b119d800000347fcb8) // quotient_const + mstore(add(payload, 0x0fc0), 0x000000000000000000000000000000340f2ebe380a0f5eff4360543988a61dc2) // quotient_const + mstore(add(payload, 0x0fe0), 0x0000000000000000000000000000002cb9b546d20373eaf85e8f53db883cb548) // quotient_const + mstore(add(payload, 0x1000), 0x0453ae02a5f228d8f956b6eab50092aaff9ec460d8863b22077de62a80bd8812) // quotient_const + mstore(add(payload, 0x1020), 0x73eda753299d7d4833351088b4af7508df8b737010b26601ef73fcbb87bd0000) // quotient_const + mstore(add(payload, 0x1040), 0x0aef2ff4e0c10ade42aca9fe2200e00159ed486fd28ef7edef05bf590de59ef3) // quotient_const + mstore(add(payload, 0x1060), 0x0000000000000000000000000000000000000000000000000000000000000006) // quotient_const + mstore(add(payload, 0x1080), 0x0000000000000000000000000000000000000000000000000600000000000000) // quotient_const + mstore(add(payload, 0x10a0), 0x0000000000000000000000000000000000060000000000000000000000000000) // quotient_const + mstore(add(payload, 0x10c0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffffff) // quotient_const + mstore(add(payload, 0x10e0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefdffffff00000001) // quotient_const + mstore(add(payload, 0x1100), 0x73eda753299d7d483339d80809a1d80553bba402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1120), 0x0000000000000000000000000000000000000000000000000000000000000003) // quotient_const + mstore(add(payload, 0x1140), 0x0000000000000000000000000000000000030000000000000000000000000000) // quotient_const + mstore(add(payload, 0x1160), 0x0000000000000000000000000000012c71404d368ec010269b10000013afec50) // quotient_const + mstore(add(payload, 0x1180), 0x000000000000000000000000000000f8cd1b37d4ebee2693904ff354f25f7464) // quotient_const + mstore(add(payload, 0x11a0), 0x000000000000000000000000000001385b1875503c5c39fb9441f95933e4b28c) // quotient_const + mstore(add(payload, 0x11c0), 0x0000000000000000000000000000007c668d9bea75f71349c827f9aa792fba32) // quotient_const + mstore(add(payload, 0x11e0), 0x0000000000000000000000000000000761c60b88b9c70e630a72b13b050012c0) // quotient_const + mstore(add(payload, 0x1200), 0x73eda753299d7d483339d80809a1d7a12dfd8a4625be569ccc4ffffef9700691) // quotient_const + mstore(add(payload, 0x1220), 0x73eda753299d7d483339d80809a1d7b264b49166b159a4787a900438048ad935) // quotient_const + mstore(add(payload, 0x1240), 0x00000000000000000000000000000003b0e305c45ce387318539589d82800960) // quotient_const + mstore(add(payload, 0x1260), 0x0000000000000000000000000000010c5a3fa8ec14b781d2375bf725316c3fb0) // quotient_const + mstore(add(payload, 0x1280), 0x000000000000000000000000000000259007b94eb27289dcc84c1f9dce2e9860) // quotient_const + mstore(add(payload, 0x12a0), 0x73eda753299d7d483339d80809a1d79d35602792ebdf9e00793f578beeb3c47d) // quotient_const + mstore(add(payload, 0x12c0), 0x73eda753299d7d483339d80809a1d802ddd0f5801766ac88a72f1a40a8fff9c1) // quotient_const + mstore(add(payload, 0x12e0), 0x73eda753299d7d483339d80809a1d7abe053165ef916860e42e15847ef869571) // quotient_const + mstore(add(payload, 0x1300), 0x73eda753299d7d483339d80809a1d7ec490dd323de5caac125229595cbe0efc1) // quotient_const + mstore(add(payload, 0x1320), 0x08a75c054be451b1f2ad6bd569f92577dd4bd64d6d5c968569fbf9fbe04d544d) // quotient_const + mstore(add(payload, 0x1340), 0x0000000000000000000000000000000000000000000000000000001800000000) // quotient_const + mstore(add(payload, 0x1360), 0x0000000000000000000000000000000000000000180000000000000000000000) // quotient_const + mstore(add(payload, 0x1380), 0x0000000000000000000000000000000000000000000000000000000000006000) // quotient_const + mstore(add(payload, 0x13a0), 0x0000000000000000000000000000000000000000000000600000000000000000) // quotient_const + mstore(add(payload, 0x13c0), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffff700000001) // quotient_const + mstore(add(payload, 0x13e0), 0x73eda753299d7d483339d80809a1d80553bda402f7fe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1400), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffe001) // quotient_const + mstore(add(payload, 0x1420), 0x73eda753299d7d483339d80809a1d80553bda402fffe5bdeffffffff00000001) // quotient_const + mstore(add(payload, 0x1440), 0x73eda753299d7d483339d80809a1d7e355af567743ae3bbda4ffd260212ddbdb) // quotient_const + mstore(add(payload, 0x1460), 0x73eda753299d7d483339d80809a1d7ac8bb094e10dd00bb871cf13341ce9f671) // quotient_const + mstore(add(payload, 0x1480), 0x73eda753299d7d483339d80809a1d7b70b86399be46147106cd7aef7d718818d) // quotient_const + mstore(add(payload, 0x14a0), 0x73eda753299d7d483339d80809a1d7ae5b2956bf70a17c7596cc5f626b73876b) // quotient_const + mstore(add(payload, 0x14c0), 0x73eda753299d7d483339d80809a1d7b6bc3584645b26895898ae7ba60d735ad1) // quotient_const + mstore(add(payload, 0x14e0), 0x73eda753299d7d483339d80809a1d7b095efed6fd9f96e39d8c5c777a6fa1179) // quotient_const + mstore(add(payload, 0x1500), 0x00000000000000000000000000000065fa2ae8a334f060c4110088dc9c766c72) // quotient_const + mstore(add(payload, 0x1520), 0x00000000000000000000000000000000000000000c0000000000000000000000) // quotient_const + mstore(add(payload, 0x1540), 0x0000000000000000000000000000010a58272d65d68af0d3aa92c660a9421cb0) // quotient_const + mstore(add(payload, 0x1560), 0x0000000000000000000000000000000000000000000000300000000000000000) // quotient_const + mstore(add(payload, 0x1580), 0x000000000000000000000000000000ead8a63f3552d73ecbb978f3157ab67b5c) // quotient_const + mstore(add(payload, 0x15a0), 0x000000000000000000000000000000852c1396b2eb457869d549633054a10e58) // quotient_const + mstore(add(payload, 0x15c0), 0x00000000000000000000000000000104e9bce7caae169e9c3b9ae1d5bda569c2) // quotient_const + mstore(add(payload, 0x15e0), 0x0000000000000000000000000000008274de73e5570b4f4e1dcd70eaded2b4e1) // quotient_const + mstore(add(payload, 0x1600), 0x000000000000000000000000000000ebc6985edbee8777f335f48d0ad7a5ef90) // quotient_const + mstore(add(payload, 0x1620), 0x0000000000000000000000000000007f1cb491dcb90764a7bad754cb0588e5cc) // quotient_const + mstore(add(payload, 0x1640), 0x73eda753299d7d48333049095fbd120c6b5942dd2166802b5297f978232a0002) // quotient_const + mstore(add(payload, 0x1660), 0x0000000000000000000006000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x1680), 0x0000000600000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x16a0), 0x4302515f88a4431e1fbaccbc5adc8f25703b5745de78f77d0d3fe37cf2c01c83) // quotient_const + mstore(add(payload, 0x16c0), 0x140e70dbca64831b4b8f40317b68cd20f34ec27e98adf994cf555b0db316abbd) // quotient_const + mstore(add(payload, 0x16e0), 0x73eda753299d7d483339d60809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1700), 0x73eda751299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001) // quotient_const + mstore(add(payload, 0x1720), 0x104e71fbe05313635bd503c3e4ec6d9ff680c43f0b2c76d5fb955ed6046aa12a) // quotient_const + mstore(add(payload, 0x1740), 0x1ff51227ca6853644d38dd4784bdae4c2024f5d6cd1acb78bae38c506ef8716c) // quotient_const + mstore(add(payload, 0x1760), 0x70156f48f76cc14b27137d78d0b4371477819d08e9f2c77036ebc744ad6da6cb) // quotient_const + mstore(add(payload, 0x1780), 0x37be870795549c37dcd00b9588085d0fa1ab8c1ad655e52c23ed8949f0fb5ae3) // quotient_const + mstore(add(payload, 0x17a0), 0x62a9cec91e3168b1496ccfcf27ad7a8d3c8d65793936323648c2b29cb6a41ac8) // quotient_const + mstore(add(payload, 0x17c0), 0x6ed3edb47fe320414c6b5a76f4cc0bce626d1a256829e20dfb44af3c3a5c88b0) // quotient_const + mstore(add(payload, 0x17e0), 0x62ea7e5a34aa00528575fab42c44f48dc6c3a5a2fadad34f0a31529dec7b61e0) // quotient_const + mstore(add(payload, 0x1800), 0x6de98a7ebdd251f08ee9668a33e94c65bdb3185246bd05a64c5767be80a6f6b3) // quotient_const + mstore(add(payload, 0x1820), 0x0b88a81e969233f724730fadaac8e2d294b414ee4222bdac5b3caa2ef7b70ba2) // quotient_const + mstore(add(payload, 0x1840), 0x0000000300000000000000000000000000000000000000000000000000000000) // quotient_const + mstore(add(payload, 0x1860), 0x409fb98f933d25e8d0038d4f7b2a98dbc278a3b57cfb0879943764202d0def59) // quotient_const + mstore(add(payload, 0x1880), 0x43fe0c177a010031bf648c1cc285529323863340cc562ac9e7aaad86598b55df) // quotient_const + mstore(add(payload, 0x18a0), 0x33cb899e22443dc4bd6718aaa5dd18684590bb9d54587d5a25b7e826dc13afab) // quotient_const + mstore(add(payload, 0x18c0), 0x5a46b0715e6d5198819eb2abc26638708b1b23dc3e7cb23c4a1bb20f9686f7ad) // quotient_const + mstore(add(payload, 0x18e0), 0x0f4d2cdbfd2f1714b46b78b33e8164a4d3f19d98c77d6dd30e31f24850ea65f3) // quotient_const + mstore(add(payload, 0x1900), 0x419d6a1793664a2e73d2a85da4119e5513d7a0cde3bde4e90718f923a87532fa) // quotient_const + mstore(add(payload, 0x1920), 0x33097aeadeda76e1094b97fb9816aa66a6edfb200f6a9a0fe16c08233a8dda63) // quotient_const + mstore(add(payload, 0x1940), 0x09062b3ea1b0c1037678aa3cc094d16f610fd18915e201850d7ce460bf058df5) // quotient_const + mstore(add(payload, 0x1960), 0x0456a29a706afacf2158850711006fe0acf6a437e9477bf6f782dfac86f2cf7b) // quotient_const + mstore(add(payload, 0x1980), 0x0397cc06bc030aab970dabe70cd498bbeea8daaea65607bb6a872125fec74a10) // quotient_const + mstore(add(payload, 0x19a0), 0x73eda753299d7d4833351088b4af7508df8b737010b26e15294bfcbb91950003) // quotient_const + mstore(add(payload, 0x19c0), 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140) // quotient_const + mstore(add(payload, 0x19e0), 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a) // quotient_const + mstore(add(payload, 0x1a00), 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db) // quotient_const + mstore(add(payload, 0x1a20), 0x0594e0109a0005958008060d000b0200011b000021020103070002000094a002) // quotient_program + mstore(add(payload, 0x1a40), 0x94c00394e00495000595200095400295600395800695a00795c00895e0099600) // quotient_program + mstore(add(payload, 0x1a60), 0x0a96200b96400c96600d96800e96a00496c00596e006970007972094a0009540) // quotient_program + mstore(add(payload, 0x1a80), 0x0295600395800496c00596e006970007972094c00295400395600495800596c0) // quotient_program + mstore(add(payload, 0x1aa0), 0x0696e00797000f972094e00395400495600595800696c00796e00f9700109720) // quotient_program + mstore(add(payload, 0x1ac0), 0x95000495400595600695800796c00f96e0109700119720952005954006956007) // quotient_program + mstore(add(payload, 0x1ae0), 0x95800f96c01096e011970012972095a00695400795600f95801096c01196e012) // quotient_program + mstore(add(payload, 0x1b00), 0x970013972095c00795400f95601095801196c01296e013970014972015974016) // quotient_program + mstore(add(payload, 0x1b20), 0x97800b03000121021703070001000094a00294c00394e0189500199520009540) // quotient_program + mstore(add(payload, 0x1b40), 0x0295600395801a95a01b95c00895e00996000a96201c96401d96601e96801f96) // quotient_program + mstore(add(payload, 0x1b60), 0xa01896c01996e01a97001b972094a00095400295600395801896c01996e01a97) // quotient_program + mstore(add(payload, 0x1b80), 0x001b972094c00295400395601895801996c01a96e01b970020972094e0039540) // quotient_program + mstore(add(payload, 0x1ba0), 0x1895601995801a96c01b96e020970021972095001895401995601a95801b96c0) // quotient_program + mstore(add(payload, 0x1bc0), 0x2096e021970022972095201995401a95601b95802096c02196e0229700239720) // quotient_program + mstore(add(payload, 0x1be0), 0x95a01a95401b95602095802196c02296e023970024972095c01b954020956021) // quotient_program + mstore(add(payload, 0x1c00), 0x95802296c02396e02497002597202697400b0300011b00012102270100000900) // quotient_program + mstore(add(payload, 0x1c20), 0x0695a00795c00895e00996000a96200b96400c96600094a00294c00394e00495) // quotient_program + mstore(add(payload, 0x1c40), 0x000595200d96800e96a01597401697800b04000121022801000008001a95a01b) // quotient_program + mstore(add(payload, 0x1c60), 0x95c00895e00996000a96201c96401d96600094a00294c00394e0189500199520) // quotient_program + mstore(add(payload, 0x1c80), 0x1e96801f96a02697400b040001210397a0290000000b2b0894a00994c00a94e0) // quotient_program + mstore(add(payload, 0x1ca0), 0x2a95402b95602c95800895e00996000a96202d97402e97600894a095e00994a0) // quotient_program + mstore(add(payload, 0x1cc0), 0x96000a94a096200994c095e00a94c096002f94c096a00a94e095e02f94e09680) // quotient_program + mstore(add(payload, 0x1ce0), 0x3094e096a02f95009660309500968031950096a02f9520964030952096603195) // quotient_program + mstore(add(payload, 0x1d00), 0x20968032952096a000954095402b954095602c95409580039560956033956097) // quotient_program + mstore(add(payload, 0x1d20), 0x20339580970034958097202f95a096203095a096403195a096603295a0968035) // quotient_program + mstore(add(payload, 0x1d40), 0x95a096a02f95c096003095c096203195c096403295c096603595c096803695c0) // quotient_program + mstore(add(payload, 0x1d60), 0x96a03396c096e03496c097003796c097203896e096e03796e097003996e09720) // quotient_program + mstore(add(payload, 0x1d80), 0x3a970097003b970097203c972097200d000b050000210397a03d030800021508) // quotient_program + mstore(add(payload, 0x1da0), 0x94a00994c00a94e00b95000c95202a95402b95602c95800d95a00e95c00895e0) // quotient_program + mstore(add(payload, 0x1dc0), 0x0996000a96200b96400c96600d96800e96a03e96c03f96e040970041972094a0) // quotient_program + mstore(add(payload, 0x1de0), 0x0895e00996000a96200b96400c96600d96800e96a094c00995e00a96000b9620) // quotient_program + mstore(add(payload, 0x1e00), 0x0c96400d96600e96804296a094e00a95e00b96000c96200d96400e9660429680) // quotient_program + mstore(add(payload, 0x1e20), 0x4396a095000b95e00c96000d96200e96404296604396804496a095200c95e00d) // quotient_program + mstore(add(payload, 0x1e40), 0x96000e96204296404396604496804596a095400095402b95602c95803e96c03f) // quotient_program + mstore(add(payload, 0x1e60), 0x96e040970041972095a00d95e00e96004296204396404496604596804696a095) // quotient_program + mstore(add(payload, 0x1e80), 0xc00e95e04296004396204496404596604696804796a015974016978003956095) // quotient_program + mstore(add(payload, 0x1ea0), 0x603e956095803f956096c040956096e041956097004895609720059580958040) // quotient_program + mstore(add(payload, 0x1ec0), 0x958096c041958096e0489580970049958097200796c096c04896c096e04996c0) // quotient_program + mstore(add(payload, 0x1ee0), 0x97004a96c097201096e096e04a96e097004b96e0972012970097004c97009720) // quotient_program + mstore(add(payload, 0x1f00), 0x14972097200d000b050001210397a04d03080001150894a00994c00a94e01c95) // quotient_program + mstore(add(payload, 0x1f20), 0x001d95202a95402b95602c95801e95a01f95c00895e00996000a96201c96401d) // quotient_program + mstore(add(payload, 0x1f40), 0x96601e96801f96a04e96c04f96e050970051972094a00895e00996000a96201c) // quotient_program + mstore(add(payload, 0x1f60), 0x96401d96601e96801f96a094c00995e00a96001c96201d96401e96601f968052) // quotient_program + mstore(add(payload, 0x1f80), 0x96a094e00a95e01c96001d96201e96401f96605296805396a095001c95e01d96) // quotient_program + mstore(add(payload, 0x1fa0), 0x001e96201f96405296605396805496a095201d95e01e96001f96205296405396) // quotient_program + mstore(add(payload, 0x1fc0), 0x605496805596a095400095402b95602c95804e96c04f96e050970051972095a0) // quotient_program + mstore(add(payload, 0x1fe0), 0x1e95e01f96005296205396405496605596805696a095c01f95e0529600539620) // quotient_program + mstore(add(payload, 0x2000), 0x5496405596605696805796a026974003956095604e956095804f956096c05095) // quotient_program + mstore(add(payload, 0x2020), 0x6096e051956097005895609720199580958050958096c051958096e058958097) // quotient_program + mstore(add(payload, 0x2040), 0x0059958097201b96c096c05896c096e05996c097005a96c097202196e096e05a) // quotient_program + mstore(add(payload, 0x2060), 0x96e097005b96e0972023970097005c9700972025972097200d000b0500012103) // quotient_program + mstore(add(payload, 0x2080), 0x97a05d0000000c390894a00994c00a94e02d97402e97600097a00097c00297e0) // quotient_program + mstore(add(payload, 0x20a0), 0x0398000898a00998c00a98e000954097c002954097e0039540980008954098a0) // quotient_program + mstore(add(payload, 0x20c0), 0x09954098c00a954098e002956097c003956097e05e9560988009956098a00a95) // quotient_program + mstore(add(payload, 0x20e0), 0x6098c02f9560996003958097c05e9580986038958098800a958098a02f958099) // quotient_program + mstore(add(payload, 0x2100), 0x4030958099600095e097a002960097a003962097a05e96c098403896c098605f) // quotient_program + mstore(add(payload, 0x2120), 0x96c098802f96c099203096c099403196c099605e96e098203896e098405f96e0) // quotient_program + mstore(add(payload, 0x2140), 0x98603a96e098802f96e099003096e099203196e099403296e099605e97009800) // quotient_program + mstore(add(payload, 0x2160), 0x38970098205f970098403a9700986060970098802f970098e030970099003197) // quotient_program + mstore(add(payload, 0x2180), 0x009920329700994035970099605e972097e038972098005f972098203a972098) // quotient_program + mstore(add(payload, 0x21a0), 0x4060972098603c972098802f972098c030972098e03197209900329720992035) // quotient_program + mstore(add(payload, 0x21c0), 0x9720994036972099600d000b060000210397a061020f000a001697800097a000) // quotient_program + mstore(add(payload, 0x21e0), 0x97c00297e00398000498200598400698600798800898a00998c00a98e00b9900) // quotient_program + mstore(add(payload, 0x2200), 0x0c992097a00095e00296000396200496400596600696800796a097c000954002) // quotient_program + mstore(add(payload, 0x2220), 0x95600395800496c00596e006970007972097e00295400395600495800596c006) // quotient_program + mstore(add(payload, 0x2240), 0x96e00797000f972098000395400495600595800696c00796e00f970010972098) // quotient_program + mstore(add(payload, 0x2260), 0x200495400595600695800796c00f96e010970011972098400595400695600795) // quotient_program + mstore(add(payload, 0x2280), 0x800f96c01096e011970012972098600695400795600f95801096c01196e01297) // quotient_program + mstore(add(payload, 0x22a0), 0x0013972098800795400f95601095801196c01296e013970014972095400898a0) // quotient_program + mstore(add(payload, 0x22c0), 0x0998c00a98e00b99000c99200d99400e996095600998a00a98c00b98e00c9900) // quotient_program + mstore(add(payload, 0x22e0), 0x0d99200e994042996095800a98a00b98c00c98e00d99000e9920429940439960) // quotient_program + mstore(add(payload, 0x2300), 0x96c00b98a00c98c00d98e00e990042992043994044996096e00c98a00d98c00e) // quotient_program + mstore(add(payload, 0x2320), 0x98e042990043992044994045996097000d98a00e98c04298e043990044992045) // quotient_program + mstore(add(payload, 0x2340), 0x994046996097200e98a04298c04398e04499004599204699404799600894a009) // quotient_program + mstore(add(payload, 0x2360), 0x94c00a94e00b95000c95200d95a00e95c01597400d99400e99600d000b060001) // quotient_program + mstore(add(payload, 0x2380), 0x210397a062020f0009000097a00097c00297e00398001898201998401a98601b) // quotient_program + mstore(add(payload, 0x23a0), 0x98800898a00998c00a98e01c99001d99201e994097a00095e002960003962018) // quotient_program + mstore(add(payload, 0x23c0), 0x96401996601a96801b96a097c00095400295600395801896c01996e01a97001b) // quotient_program + mstore(add(payload, 0x23e0), 0x972097e00295400395601895801996c01a96e01b970020972098000395401895) // quotient_program + mstore(add(payload, 0x2400), 0x601995801a96c01b96e020970021972098201895401995601a95801b96c02096) // quotient_program + mstore(add(payload, 0x2420), 0xe021970022972098401995401a95601b95802096c02196e02297002397209860) // quotient_program + mstore(add(payload, 0x2440), 0x1a95401b95602095802196c02296e023970024972098801b9540209560219580) // quotient_program + mstore(add(payload, 0x2460), 0x2296c02396e024970025972095400898a00998c00a98e01c99001d99201e9940) // quotient_program + mstore(add(payload, 0x2480), 0x1f996095600998a00a98c01c98e01d99001e99201f994052996095800a98a01c) // quotient_program + mstore(add(payload, 0x24a0), 0x98c01d98e01e99001f992052994053996096c01c98a01d98c01e98e01f990052) // quotient_program + mstore(add(payload, 0x24c0), 0x992053994054996096e01d98a01e98c01f98e052990053992054994055996097) // quotient_program + mstore(add(payload, 0x24e0), 0x001e98a01f98c05298e053990054992055994056996097201f98a05298c05398) // quotient_program + mstore(add(payload, 0x2500), 0xe05499005599205699405799600894a00994c00a94e01c95001d95201e95a01f) // quotient_program + mstore(add(payload, 0x2520), 0x95c02697401f99600d000b060001210397a0630000000b2b6494a06594c06694) // quotient_program + mstore(add(payload, 0x2540), 0xe06795406895606995806795e06896006996202d97402e97606a94a094a06594) // quotient_program + mstore(add(payload, 0x2560), 0xa094c06694a094e06b94c094c06c94c095c06c94e095a06d94e095c06c950095) // quotient_program + mstore(add(payload, 0x2580), 0x206d950095a06e950095c06f952095206e952095a070952095c067954095e068) // quotient_program + mstore(add(payload, 0x25a0), 0x95409600699540962068956095e0699560960071956096a069958095e0719580) // quotient_program + mstore(add(payload, 0x25c0), 0x968072958096a07395a095a07495a095c07595c095c071960097207196209700) // quotient_program + mstore(add(payload, 0x25e0), 0x729620972071964096e07296409700769640972071966096c072966096e07696) // quotient_program + mstore(add(payload, 0x2600), 0x609700779660972072968096c076968096e0779680970078968097207696a096) // quotient_program + mstore(add(payload, 0x2620), 0xc07796a096e07896a097007996a097200d000b070000210397a07a0308000215) // quotient_program + mstore(add(payload, 0x2640), 0x6494a06594c06694e07b95007c95206795406895606995807d95a07e95c06795) // quotient_program + mstore(add(payload, 0x2660), 0xe06896006996207f96408096608196808296a07f96c08096e081970082972094) // quotient_program + mstore(add(payload, 0x2680), 0xa06a94a06594c06694e07b95007c95207d95a07e95c095406795e06896006996) // quotient_program + mstore(add(payload, 0x26a0), 0x207f96408096608196808296a095606895e06996007f96208096408196608296) // quotient_program + mstore(add(payload, 0x26c0), 0x808396a095806995e07f96008096208196408296608396808496a096c07f95e0) // quotient_program + mstore(add(payload, 0x26e0), 0x8096008196208296408396608496808596a096e08095e0819600829620839640) // quotient_program + mstore(add(payload, 0x2700), 0x8496608596808696a097008195e08296008396208496408596608696808796a0) // quotient_program + mstore(add(payload, 0x2720), 0x97208295e08396008496208596408696608796808896a01597401697806b94c0) // quotient_program + mstore(add(payload, 0x2740), 0x94c07b94c094e07c94c095007d94c095207e94c095a08994c095c08a94e094e0) // quotient_program + mstore(add(payload, 0x2760), 0x7d94e095007e94e095208994e095a08b94e095c08c9500950089950095208b95) // quotient_program + mstore(add(payload, 0x2780), 0x0095a08d950095c08e952095208d952095a08f952095c09095a095a09195a095) // quotient_program + mstore(add(payload, 0x27a0), 0xc09295c095c00d000b070001210397a09303080001156494a06594c06694e094) // quotient_program + mstore(add(payload, 0x27c0), 0x95009595206795406895606995809695a09795c06795e0689600699620989640) // quotient_program + mstore(add(payload, 0x27e0), 0x9996609a96809b96a09896c09996e09a97009b972094a06a94a06594c06694e0) // quotient_program + mstore(add(payload, 0x2800), 0x9495009595209695a09795c095406795e06896006996209896409996609a9680) // quotient_program + mstore(add(payload, 0x2820), 0x9b96a095606895e06996009896209996409a96609b96809c96a095806995e098) // quotient_program + mstore(add(payload, 0x2840), 0x96009996209a96409b96609c96809d96a096c09895e09996009a96209b96409c) // quotient_program + mstore(add(payload, 0x2860), 0x96609d96809e96a096e09995e09a96009b96209c96409d96609e96809f96a097) // quotient_program + mstore(add(payload, 0x2880), 0x009a95e09b96009c96209d96409e96609f9680a096a097209b95e09c96009d96) // quotient_program + mstore(add(payload, 0x28a0), 0x209e96409f9660a09680a196a02697406b94c094c09494c094e09594c0950096) // quotient_program + mstore(add(payload, 0x28c0), 0x94c095209794c095a0a294c095c0a394e094e09694e095009794e09520a294e0) // quotient_program + mstore(add(payload, 0x28e0), 0x95a0a494e095c0a595009500a295009520a4950095a0a6950095c0a795209520) // quotient_program + mstore(add(payload, 0x2900), 0xa6952095a0a8952095c0a995a095a0aa95a095c0ab95c095c00d000b07000121) // quotient_program + mstore(add(payload, 0x2920), 0x0397a0ac0000000e100094a00294c00394e06795406895606995800095e00296) // quotient_program + mstore(add(payload, 0x2940), 0x000396202d97402e97600097c00297e003980008954095406895409560699540) // quotient_program + mstore(add(payload, 0x2960), 0x95800a956095607195609720719580970072958097207196c096e07296c09700) // quotient_program + mstore(add(payload, 0x2980), 0x7696c097203096e096e07696e097007796e09720329700970078970097203697) // quotient_program + mstore(add(payload, 0x29a0), 0x2097200d000b080000210397a0ad04010002150094a00294c00394e004950005) // quotient_program + mstore(add(payload, 0x29c0), 0x95206795406895606995800695a00795c00095e0029600039620049640059660) // quotient_program + mstore(add(payload, 0x29e0), 0x0696800796a07f96c08096e08197008297200097c00297e00398000498200598) // quotient_program + mstore(add(payload, 0x2a00), 0x4006986007988095400895406895606995807f96c08096e08197008297201597) // quotient_program + mstore(add(payload, 0x2a20), 0x401697800a956095607f9560958080956096c081956096e08295609700839560) // quotient_program + mstore(add(payload, 0x2a40), 0x97200c9580958081958096c082958096e0839580970084958097200e96c096c0) // quotient_program + mstore(add(payload, 0x2a60), 0x8396c096e08496c097008596c097204396e096e08596e097008696e097204597) // quotient_program + mstore(add(payload, 0x2a80), 0x009700879700972047972097200d000b080001210397a0ae04010001150094a0) // quotient_program + mstore(add(payload, 0x2aa0), 0x0294c00394e01895001995206795406895606995801a95a01b95c00095e00296) // quotient_program + mstore(add(payload, 0x2ac0), 0x000396201896401996601a96801b96a09896c09996e09a97009b97200097c002) // quotient_program + mstore(add(payload, 0x2ae0), 0x97e00398001898201998401a98601b988095400895406895606995809896c099) // quotient_program + mstore(add(payload, 0x2b00), 0x96e09a97009b97202697400a95609560989560958099956096c09a956096e09b) // quotient_program + mstore(add(payload, 0x2b20), 0x956097009c956097201d958095809a958096c09b958096e09c958097009d9580) // quotient_program + mstore(add(payload, 0x2b40), 0x97201f96c096c09c96c096e09d96c097009e96c097205396e096e09e96e09700) // quotient_program + mstore(add(payload, 0x2b60), 0x9f96e097205597009700a09700972057972097200d000b0800010594a01194a0) // quotient_program + mstore(add(payload, 0x2b80), 0x1194a005950008060d000b0900000594c01194c01194c005952008060d000b09) // quotient_program + mstore(add(payload, 0x2ba0), 0x00010594e01194e01194e00595a008060d000b0900011b00021b000305958008) // quotient_program + mstore(add(payload, 0x2bc0), 0x109aa00594a01194a01195000daf060594c01194c01195200db0060594e01194) // quotient_program + mstore(add(payload, 0x2be0), 0xe01195a00db1060d000b090001191f0000000000000000000000000000000000) // quotient_program + // Fixed-column commitment 0, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2c00), 0x0000000000000000000000000000000016e98a681dca730dcbe651aec5493976) // fixed_comms[0].x_hi + mstore(add(payload, 0x2c20), 0x11944be61932e7d19a63786871335939b0eefa7e32507b68b4ad6fd89a5c1028) // fixed_comms[0].x_lo + mstore(add(payload, 0x2c40), 0x0000000000000000000000000000000010e6ae8d3becb251e60db7d788be7029) // fixed_comms[0].y_hi + mstore(add(payload, 0x2c60), 0x8dbcdfdbb394da2ca9725e07485d6b630569a66ec867aa0d605573ae82d550df) // fixed_comms[0].y_lo + // Fixed-column commitment 1, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2c80), 0x000000000000000000000000000000000fb2ef3076aa1a8068bec7ef35167c1c) // fixed_comms[1].x_hi + mstore(add(payload, 0x2ca0), 0xf1f26a24abaa3b4dc8c6d218021c08429e4c175654b5996eb4de74d17a5c188d) // fixed_comms[1].x_lo + mstore(add(payload, 0x2cc0), 0x00000000000000000000000000000000000f94fa3dcc144ffe6a4ace1de5f956) // fixed_comms[1].y_hi + mstore(add(payload, 0x2ce0), 0x76ad02ffc32c0345767b466f064aec3f1101ecd9eaf91ba5d4c145f792d1285a) // fixed_comms[1].y_lo + // Fixed-column commitment 2, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2d00), 0x0000000000000000000000000000000016909a26057dec4152b5bd207c37f9a8) // fixed_comms[2].x_hi + mstore(add(payload, 0x2d20), 0xc3af2c8cfa63dfd83e34704255392445fae3c47d749e435e0291232659a8caeb) // fixed_comms[2].x_lo + mstore(add(payload, 0x2d40), 0x0000000000000000000000000000000000b9edb176686ec391a3684928dc0842) // fixed_comms[2].y_hi + mstore(add(payload, 0x2d60), 0x80c60eca091b8a3925e31ef1032793f2ef4e31225ab560bf721f17525dd476c8) // fixed_comms[2].y_lo + // Fixed-column commitment 3, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2d80), 0x0000000000000000000000000000000014861e20b064f637d60cc250ff3b8804) // fixed_comms[3].x_hi + mstore(add(payload, 0x2da0), 0x9b9697b5245d031c784398bdf950e99d7968c86e92c4ec1cb3821a69686dfb09) // fixed_comms[3].x_lo + mstore(add(payload, 0x2dc0), 0x000000000000000000000000000000000c117b524f84a06b024a40003e1c3aab) // fixed_comms[3].y_hi + mstore(add(payload, 0x2de0), 0x25253a3cf5b53d2f77d1f9328a9c0b32bea4f591eb470dbb599b5fbdfa7df46b) // fixed_comms[3].y_lo + // Fixed-column commitment 4, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2e00), 0x000000000000000000000000000000001420bb2d8c182dda6c982eb820e035f6) // fixed_comms[4].x_hi + mstore(add(payload, 0x2e20), 0xa4a5c6c69376dfda17ac5588d34a0b313800b8d18ecd818f3e4e2671589ec691) // fixed_comms[4].x_lo + mstore(add(payload, 0x2e40), 0x0000000000000000000000000000000000855eb6333071d5bb90a0351dbf958c) // fixed_comms[4].y_hi + mstore(add(payload, 0x2e60), 0x13e5648bcafb55776c78e46031e4620cfda02728e26bb97f067a9a0cdf72aa9f) // fixed_comms[4].y_lo + // Fixed-column commitment 5, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2e80), 0x000000000000000000000000000000000707698990b767903c9aaf028c98b46a) // fixed_comms[5].x_hi + mstore(add(payload, 0x2ea0), 0xc4925e4e30db42105aade1a5cd7dd9b3d2222bd7085071b5c2212709cfcc2d46) // fixed_comms[5].x_lo + mstore(add(payload, 0x2ec0), 0x000000000000000000000000000000000a88a7d4f1148bd3efffaedb5be62777) // fixed_comms[5].y_hi + mstore(add(payload, 0x2ee0), 0x27fad92f1005d28d12ef861b5dcf8b580a1322048d469da5f84b26fa7f8d2e4d) // fixed_comms[5].y_lo + // Fixed-column commitment 6, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2f00), 0x000000000000000000000000000000001495975f8f8c0cb6c54e1163fe045732) // fixed_comms[6].x_hi + mstore(add(payload, 0x2f20), 0x2be3eb4af919cb0eb6126028ebeab81d075dff85aa522989166bf6e01880c1be) // fixed_comms[6].x_lo + mstore(add(payload, 0x2f40), 0x0000000000000000000000000000000018bdd4eef361f4a6d23a6511b48e20fb) // fixed_comms[6].y_hi + mstore(add(payload, 0x2f60), 0x4080898637660f3f3371adfb48585dd2ad89c29cc260d604ce9cd68a31ff427d) // fixed_comms[6].y_lo + // Fixed-column commitment 7, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x2f80), 0x00000000000000000000000000000000166c1cd47b07ac0aee553f0b4277cf37) // fixed_comms[7].x_hi + mstore(add(payload, 0x2fa0), 0xb4822422a23ea90486c60a5b3b9052dff113041d51718304e781a5a7bd93bdc2) // fixed_comms[7].x_lo + mstore(add(payload, 0x2fc0), 0x00000000000000000000000000000000016c91bfb3ce38ba23df779d69abeaa4) // fixed_comms[7].y_hi + mstore(add(payload, 0x2fe0), 0x8aaa142a59667ce4eabfaf36c5453af4aaec6e596ad923693a2a7d1483c2fd20) // fixed_comms[7].y_lo + // Fixed-column commitment 8, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3000), 0x000000000000000000000000000000001262dde7fc4aeca256572897f5d601ef) // fixed_comms[8].x_hi + mstore(add(payload, 0x3020), 0x5b8b5586b8593d43cbcd11d2fd80fe2a2214269e5479b5d976cf507d5262c273) // fixed_comms[8].x_lo + mstore(add(payload, 0x3040), 0x0000000000000000000000000000000012bd810c9b8eaaf899f161e2d8c26762) // fixed_comms[8].y_hi + mstore(add(payload, 0x3060), 0xc3f299919bfa2b2809a027cc9bcac1799ef2d48b11403ce47a5341f7307d2cd4) // fixed_comms[8].y_lo + // Fixed-column commitment 9, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3080), 0x00000000000000000000000000000000096d06362268ed80162468c5e664e2bb) // fixed_comms[9].x_hi + mstore(add(payload, 0x30a0), 0x1a1a3b60a6c419cb6edb470b646e9ed4e021686e93f82d0c3ee2448368fe81be) // fixed_comms[9].x_lo + mstore(add(payload, 0x30c0), 0x0000000000000000000000000000000015ceb98a36a3576ad6db1163a0a98d2a) // fixed_comms[9].y_hi + mstore(add(payload, 0x30e0), 0x0535a28ca330834bb07c6682d32b20cd8171f4c0d9f063d768b6e3185b6ae44e) // fixed_comms[9].y_lo + // Fixed-column commitment 10, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3100), 0x0000000000000000000000000000000019731a2f803950b978082f57fdfffb38) // fixed_comms[10].x_hi + mstore(add(payload, 0x3120), 0x0de3c6bef55492c30e409d77ac9acb523958dea2856b12cb4e87608584ab499a) // fixed_comms[10].x_lo + mstore(add(payload, 0x3140), 0x0000000000000000000000000000000005f057d8c91984630d36a0df6c2ebb07) // fixed_comms[10].y_hi + mstore(add(payload, 0x3160), 0x3881713eb294d8cdf7bb0374cb722b7bb5080101a54638216ab4886f0276a475) // fixed_comms[10].y_lo + // Fixed-column commitment 11, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3180), 0x0000000000000000000000000000000004d63c6ffcf22c5a45cbc67e299c2b3d) // fixed_comms[11].x_hi + mstore(add(payload, 0x31a0), 0xcfd98199c525785d127006aca0f82774876a94e120b9bde61b9227ee96dc6841) // fixed_comms[11].x_lo + mstore(add(payload, 0x31c0), 0x0000000000000000000000000000000002385e4a7b9ab571a73f07d9574152e5) // fixed_comms[11].y_hi + mstore(add(payload, 0x31e0), 0xa45de038325c587523413d98b5feb6d2071c293abbeab53bf941d76b264f3369) // fixed_comms[11].y_lo + // Fixed-column commitment 12, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3200), 0x000000000000000000000000000000000eea9ee53f693242e50678f2ac4a5053) // fixed_comms[12].x_hi + mstore(add(payload, 0x3220), 0x6bc4aa60deae574c46e3cf56a8d14af17d603f8c222728fb09300eee5c5b326b) // fixed_comms[12].x_lo + mstore(add(payload, 0x3240), 0x0000000000000000000000000000000014aa3a043bb1340472428a1756ad82bb) // fixed_comms[12].y_hi + mstore(add(payload, 0x3260), 0x49fa2fee5ff945799006e851969947efb6351c7642b2683deb31537ea6209643) // fixed_comms[12].y_lo + // Fixed-column commitment 13, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3280), 0x000000000000000000000000000000000b7028c202ee5b6a74d6ccfe5990dc98) // fixed_comms[13].x_hi + mstore(add(payload, 0x32a0), 0x4381d45aa22ccb019d848829dd72d16143e5af158899fcc009d5ca17c97c3414) // fixed_comms[13].x_lo + mstore(add(payload, 0x32c0), 0x0000000000000000000000000000000006c6ca7119058dbb54d5302f125f9cef) // fixed_comms[13].y_hi + mstore(add(payload, 0x32e0), 0xdc6b68957c7b970427a4b5a3bd0aa7ff5fa033687afdc2a4e150a408b0a5f4d2) // fixed_comms[13].y_lo + // Fixed-column commitment 14, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3300), 0x0000000000000000000000000000000008a540ee790774da565637ec30ced988) // fixed_comms[14].x_hi + mstore(add(payload, 0x3320), 0x563c90d314d01996465fa3f893d5fb010b617a4edcabc5c8f8141584792a0067) // fixed_comms[14].x_lo + mstore(add(payload, 0x3340), 0x00000000000000000000000000000000071e81991f7c8f62be7df37cd485cb5e) // fixed_comms[14].y_hi + mstore(add(payload, 0x3360), 0x1f941d942cc15f814350867bcdf1521ef6e7e76b6928827688b0d3d14a6cf1a3) // fixed_comms[14].y_lo + // Fixed-column commitment 15, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3380), 0x0000000000000000000000000000000005a4ed142d6c05e535a91ff8244ca5cb) // fixed_comms[15].x_hi + mstore(add(payload, 0x33a0), 0xdda66355e156c19ea759a1f5aecd1225e16cb3f18397a66b055a2918a2a74d54) // fixed_comms[15].x_lo + mstore(add(payload, 0x33c0), 0x000000000000000000000000000000000ce5eb9724134cce6feb1c0ff1b66ab3) // fixed_comms[15].y_hi + mstore(add(payload, 0x33e0), 0x5e79b2b4087200f1d9a76ee4a2b3b5424266da9d518653e9391e9a94196f1d7f) // fixed_comms[15].y_lo + // Fixed-column commitment 16, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3400), 0x0000000000000000000000000000000009b07c1df13d348c1ed7cb560fcdd682) // fixed_comms[16].x_hi + mstore(add(payload, 0x3420), 0x55221aadb75410fa4526857c95cea6bf3a0efa98e31898de56ea7ff30f7c514a) // fixed_comms[16].x_lo + mstore(add(payload, 0x3440), 0x0000000000000000000000000000000011b2d20f8b12527aba78064c809753e2) // fixed_comms[16].y_hi + mstore(add(payload, 0x3460), 0x21cebde9bb41aa67abae156e3a179655388e51211ba5614fb696a7f0cc212560) // fixed_comms[16].y_lo + // Fixed-column commitment 17, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3480), 0x0000000000000000000000000000000010ce280498c90ca7501427caf6bcd6d9) // fixed_comms[17].x_hi + mstore(add(payload, 0x34a0), 0xb4987380f8d9e8ef710b81034a460c8da32362568e1e9fd6b2cb5297805c98ad) // fixed_comms[17].x_lo + mstore(add(payload, 0x34c0), 0x000000000000000000000000000000000292967ae2e91be4d3555cddb84538dd) // fixed_comms[17].y_hi + mstore(add(payload, 0x34e0), 0x0edcb077ce0626f751bee2673ff6b24c182fd2ae99a0cd83881a81a3facfcb6e) // fixed_comms[17].y_lo + // Fixed-column commitment 18, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3500), 0x0000000000000000000000000000000017cf661d855e771f61cab52918bc03e5) // fixed_comms[18].x_hi + mstore(add(payload, 0x3520), 0x329761bebc6704041c0430c64bc2d589210a4250f57e9dec51a807d4d6926f31) // fixed_comms[18].x_lo + mstore(add(payload, 0x3540), 0x000000000000000000000000000000000f50cacb58bf9101f3d7926b2e26675d) // fixed_comms[18].y_hi + mstore(add(payload, 0x3560), 0x036c7cf34f335946dfc1d1a6e148de3da13cabfe8e7507f10baca11e07231413) // fixed_comms[18].y_lo + // Fixed-column commitment 19, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3580), 0x0000000000000000000000000000000016caf868eda0aeb753fd8ec3bee96cbe) // fixed_comms[19].x_hi + mstore(add(payload, 0x35a0), 0x3217eade0bae8e908b6cfe1f144518cbaec5bbbbc6e6641d82702b3dd5997985) // fixed_comms[19].x_lo + mstore(add(payload, 0x35c0), 0x000000000000000000000000000000000a35da0b540c40574d639e726b9c7e6d) // fixed_comms[19].y_hi + mstore(add(payload, 0x35e0), 0xb45e6cbefb614f14a1721bdbca2dfcb20aaeb64926032522ba3de23420dc1d87) // fixed_comms[19].y_lo + // Fixed-column commitment 20, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3600), 0x000000000000000000000000000000000b7f1691be78a38c579c2ac6bef18d54) // fixed_comms[20].x_hi + mstore(add(payload, 0x3620), 0xf2d63e634590931fda91cce7af80f7c589cc37a98870e127c93e059ff020df07) // fixed_comms[20].x_lo + mstore(add(payload, 0x3640), 0x0000000000000000000000000000000012582699af0164d4335252425d0251c4) // fixed_comms[20].y_hi + mstore(add(payload, 0x3660), 0xa1af4e259a3f65f0065b2b05127538a8434de1326c4920ee45da346bbbc7d293) // fixed_comms[20].y_lo + // Fixed-column commitment 21, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3680), 0x000000000000000000000000000000000e004abc0ac243147c480dca32186a34) // fixed_comms[21].x_hi + mstore(add(payload, 0x36a0), 0x78642aaafe922adde54e02ae93479fa0ae45b75ed0229c2f358a0473d17c09a5) // fixed_comms[21].x_lo + mstore(add(payload, 0x36c0), 0x0000000000000000000000000000000013e0dac8358fff676678a7b7d854aee3) // fixed_comms[21].y_hi + mstore(add(payload, 0x36e0), 0x3fda118cfb39d426f3418966ed06283adbd804fbe8cf51fd89c2f5c410919f48) // fixed_comms[21].y_lo + // Fixed-column commitment 22, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3700), 0x00000000000000000000000000000000168c0d6883d0d5b67d3a5944ee0616a3) // fixed_comms[22].x_hi + mstore(add(payload, 0x3720), 0xce7ac537685a26b678bab6b1b50115c32a5f90b6ca56cb8560a40964840893ce) // fixed_comms[22].x_lo + mstore(add(payload, 0x3740), 0x00000000000000000000000000000000197d467f656fc49a1c5119d7cd826cc2) // fixed_comms[22].y_hi + mstore(add(payload, 0x3760), 0xbe6345c67f108e7e44f8ebfcebea5366fdee85d69947c8f74f623165dc1029b5) // fixed_comms[22].y_lo + // Fixed-column commitment 23, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3780), 0x00000000000000000000000000000000133f78d1d5ad537d358f421d115bdb2f) // fixed_comms[23].x_hi + mstore(add(payload, 0x37a0), 0x44eff93e623017fb4a06006877bd8504b8b614c6c877d73de7cdc2c2e69a8998) // fixed_comms[23].x_lo + mstore(add(payload, 0x37c0), 0x00000000000000000000000000000000067b406b38e3895daddca2f64de3ee21) // fixed_comms[23].y_hi + mstore(add(payload, 0x37e0), 0x5c7961f1d2f1904f7e2aa60bc20559610c868810183505527e28eea6089d6bf8) // fixed_comms[23].y_lo + // Fixed-column commitment 24, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3800), 0x000000000000000000000000000000000bd679e559d6bf9f498928a3074a0709) // fixed_comms[24].x_hi + mstore(add(payload, 0x3820), 0x23c4cf1d5823b59316852fd6653fe003a4a2da9ba443e4640993524c79a6f56d) // fixed_comms[24].x_lo + mstore(add(payload, 0x3840), 0x000000000000000000000000000000000821077b092335b9f70fb79a424cca13) // fixed_comms[24].y_hi + mstore(add(payload, 0x3860), 0x4e823d96a4fdeaf4154ab7c5ef023844695a10e9bfdf314847ccaa40205f980a) // fixed_comms[24].y_lo + // Fixed-column commitment 25, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3880), 0x00000000000000000000000000000000041f7c88095a1bbf5759d88a7d109853) // fixed_comms[25].x_hi + mstore(add(payload, 0x38a0), 0x4b1661f3b1b9012866e17c7550a5b52861ac915beba38767c7aeb04c1df330ac) // fixed_comms[25].x_lo + mstore(add(payload, 0x38c0), 0x000000000000000000000000000000000f2e8cc95c27bf0235efa88fa70bb3eb) // fixed_comms[25].y_hi + mstore(add(payload, 0x38e0), 0x59a5ef2602a9b70c5af7b0db755f10a8e0ffc380b61a580c3300fda8d6077854) // fixed_comms[25].y_lo + // Fixed-column commitment 26, stored as one + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3900), 0x000000000000000000000000000000001983933b9a69c960c9eda1f5942af11a) // fixed_comms[26].x_hi + mstore(add(payload, 0x3920), 0x22de694e7c8b2a5f8d920b50d6c90aca30d149ace5ff9feebf84a136abdfa9f4) // fixed_comms[26].x_lo + mstore(add(payload, 0x3940), 0x00000000000000000000000000000000162f68d07437f5dd432392f6a244044d) // fixed_comms[26].y_hi + mstore(add(payload, 0x3960), 0x4605b4457384fb65577df046c667a744f851fbdb0e8751aaeeb334bf32fbd3e0) // fixed_comms[26].y_lo + // Permutation commitment 0, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3980), 0x0000000000000000000000000000000014669fe860d72f984d085b33bfffa399) // permutation_comms[0].x_hi + mstore(add(payload, 0x39a0), 0x12a9b0d0acb1ff8fd119eee9d0870eab9324293b88df67b9e1ebd180db262c72) // permutation_comms[0].x_lo + mstore(add(payload, 0x39c0), 0x000000000000000000000000000000000f3292f0f7b5707fe0874c56fdae2e88) // permutation_comms[0].y_hi + mstore(add(payload, 0x39e0), 0x2a2ba44cc1a14f736d255905838f8438fb8dbfd65ad84bcbca748a749c58955e) // permutation_comms[0].y_lo + // Permutation commitment 1, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3a00), 0x000000000000000000000000000000000ee7e9d684b203f28dd5424f3a511695) // permutation_comms[1].x_hi + mstore(add(payload, 0x3a20), 0xff88a9d696976adca8c54262e0f553756ec45b8e103453f8c18a07c3abcef5fd) // permutation_comms[1].x_lo + mstore(add(payload, 0x3a40), 0x00000000000000000000000000000000177029152e262c258c987bfbeeee14c8) // permutation_comms[1].y_hi + mstore(add(payload, 0x3a60), 0xe945c114efada4abdeff8610bea0cf199ef3f375cf15f6b437de67f3379c5801) // permutation_comms[1].y_lo + // Permutation commitment 2, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3a80), 0x000000000000000000000000000000000e2ead1ec1acc411940e7bea5d0f2114) // permutation_comms[2].x_hi + mstore(add(payload, 0x3aa0), 0x6b39327e36ebab84013dd8f5c2b3f8b576a125db88ff28db45a79a28df414b66) // permutation_comms[2].x_lo + mstore(add(payload, 0x3ac0), 0x00000000000000000000000000000000199b4ea033c01e1d83627c054ba6f2dc) // permutation_comms[2].y_hi + mstore(add(payload, 0x3ae0), 0x2a61b1277d07469ad65c413a1970c9cf179bedfc4cf2f61c1ee8ca5e4a01ab90) // permutation_comms[2].y_lo + // Permutation commitment 3, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3b00), 0x0000000000000000000000000000000011af8f4e99c419588e05414f664ae8f6) // permutation_comms[3].x_hi + mstore(add(payload, 0x3b20), 0xdded731799d69d8f5a72c124a5c6df33153e15767000ef54648a8dd23687140a) // permutation_comms[3].x_lo + mstore(add(payload, 0x3b40), 0x0000000000000000000000000000000017ba99d9323e45fe54ec6ac4daaad8d3) // permutation_comms[3].y_hi + mstore(add(payload, 0x3b60), 0x0c0dbc53d3f5f54c05667eb0e4f28da8973657bf62915fcdfc551698f56aa574) // permutation_comms[3].y_lo + // Permutation commitment 4, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3b80), 0x000000000000000000000000000000000ed68fa806cd3171cb061afebf65799d) // permutation_comms[4].x_hi + mstore(add(payload, 0x3ba0), 0xf9014492a08de2420f1234158d2f1d214b5354b7ad8cfc753d2712e6bb9b20a5) // permutation_comms[4].x_lo + mstore(add(payload, 0x3bc0), 0x0000000000000000000000000000000013f05c6e0393baeec023451082007353) // permutation_comms[4].y_hi + mstore(add(payload, 0x3be0), 0x55211ac5dd3c2267dcf706d18263fa7b7916e44ab1d5309430542f75717187c4) // permutation_comms[4].y_lo + // Permutation commitment 5, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3c00), 0x000000000000000000000000000000000a925e4ad4c2d71f096de0e53baea720) // permutation_comms[5].x_hi + mstore(add(payload, 0x3c20), 0x7a90226e678437d20f2ec9ae630075a12ae88a186bcfba1bc0444e5bc40245e7) // permutation_comms[5].x_lo + mstore(add(payload, 0x3c40), 0x0000000000000000000000000000000006ff1ce2b5e6c2c3cedd7a8465c5ed3a) // permutation_comms[5].y_hi + mstore(add(payload, 0x3c60), 0x72e4496eead09ba2cd0ef56fdd94942ed738b42b71caea3d1bd78b0ae3ec3f96) // permutation_comms[5].y_lo + // Permutation commitment 6, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3c80), 0x000000000000000000000000000000000190af4fe845524352a9f624463ae7ca) // permutation_comms[6].x_hi + mstore(add(payload, 0x3ca0), 0x406fa14f4319031fe5a7630ab2bd66c107d6cb05fa65b98ee0c5f0234c29d189) // permutation_comms[6].x_lo + mstore(add(payload, 0x3cc0), 0x0000000000000000000000000000000013036a5f7dca90b530955bf735da2920) // permutation_comms[6].y_hi + mstore(add(payload, 0x3ce0), 0x29b8759dc69e53d6c830a3bee081165d4d59442dacb50c2a06aded3193e88387) // permutation_comms[6].y_lo + // Permutation commitment 7, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3d00), 0x0000000000000000000000000000000012b6e22b800c1a2dfde554f3312f4b50) // permutation_comms[7].x_hi + mstore(add(payload, 0x3d20), 0x1b75400de7c8c476dcc9fd72dcef80d9384da4e4af8f928a07e4a9fa485da8bc) // permutation_comms[7].x_lo + mstore(add(payload, 0x3d40), 0x00000000000000000000000000000000053da19ebda674bbc95d3d10ad04cb96) // permutation_comms[7].y_hi + mstore(add(payload, 0x3d60), 0xa410aecead2c7059df1e12a1a56117a830f0008a91551cec88f1ad548a379dfe) // permutation_comms[7].y_lo + // Permutation commitment 8, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3d80), 0x0000000000000000000000000000000016038223f354e7d7c75614116c58b1c9) // permutation_comms[8].x_hi + mstore(add(payload, 0x3da0), 0x866a8a39d6b30ea560b263c68da7e78210b2f2a7f9b19564388f2f2370d7cd6a) // permutation_comms[8].x_lo + mstore(add(payload, 0x3dc0), 0x000000000000000000000000000000000bdb1d40f473070bfa087ff87bc9c86d) // permutation_comms[8].y_hi + mstore(add(payload, 0x3de0), 0x0d57398e71f45845ebcd0aa24a9ea829718dfce700af80fab46b51ad73fb58f6) // permutation_comms[8].y_lo + // Permutation commitment 9, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3e00), 0x00000000000000000000000000000000085c579504429306bbf0ec28b07f91a6) // permutation_comms[9].x_hi + mstore(add(payload, 0x3e20), 0x7326fabf9ec866a45ef4d294f390a7c497c7b990a62b602f5999fcaee0e7e9bc) // permutation_comms[9].x_lo + mstore(add(payload, 0x3e40), 0x000000000000000000000000000000000b042dab28398e8c0670ee6f04cca93a) // permutation_comms[9].y_hi + mstore(add(payload, 0x3e60), 0xa41ecc7205c8216513d027b4c1213d0e452c16898d7b2c811027598cf2715dc3) // permutation_comms[9].y_lo + // Permutation commitment 10, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3e80), 0x00000000000000000000000000000000093b6ec41dd5c2455b9d2dca635c472d) // permutation_comms[10].x_hi + mstore(add(payload, 0x3ea0), 0x386496c219c45db9f1a5d96c179d1028694626c4a1845aef384efaaa8053284b) // permutation_comms[10].x_lo + mstore(add(payload, 0x3ec0), 0x000000000000000000000000000000000386d1128886a4a879e8a93aa84b6525) // permutation_comms[10].y_hi + mstore(add(payload, 0x3ee0), 0x1061026f4dae08952816961f9d6fc0b8153784a5961f831b68f1e2ddc567efb7) // permutation_comms[10].y_lo + // Permutation commitment 11, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3f00), 0x0000000000000000000000000000000000b6ed6814a099c4e435e42fc8ee4250) // permutation_comms[11].x_hi + mstore(add(payload, 0x3f20), 0x0e16b88c78069cebe20e4d647c8bb44acd6b9c6712d53a3ebd014e54a1a75e89) // permutation_comms[11].x_lo + mstore(add(payload, 0x3f40), 0x0000000000000000000000000000000001ae3805b59b2f2d53a59e2c19001e97) // permutation_comms[11].y_hi + mstore(add(payload, 0x3f60), 0xaace57ac2ba8b58550a740e897ba6278e409291e5c87466a01edd7cbe3b99f88) // permutation_comms[11].y_lo + // Permutation commitment 12, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x3f80), 0x000000000000000000000000000000000ca3af5a65ec51141f694db29736dd57) // permutation_comms[12].x_hi + mstore(add(payload, 0x3fa0), 0xa1cdbfa79f45aa80a6cdda8de3d51c4b16c95361b412c6f47e132eae7b69f7f7) // permutation_comms[12].x_lo + mstore(add(payload, 0x3fc0), 0x0000000000000000000000000000000018dc16284e57fccd755058b259b913c7) // permutation_comms[12].y_hi + mstore(add(payload, 0x3fe0), 0x7a54da0d0e206b7906878fd3e994ad04c66f48e19cd982d5651f99b48b992064) // permutation_comms[12].y_lo + // Permutation commitment 13, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4000), 0x00000000000000000000000000000000197560c82bf47486bee750469d626ce4) // permutation_comms[13].x_hi + mstore(add(payload, 0x4020), 0x2d40ce7489ff61a64a0eb55e6672926a40f06348ab575f926fbe4d87b672fcd7) // permutation_comms[13].x_lo + mstore(add(payload, 0x4040), 0x0000000000000000000000000000000007b4f39a579a01d4f01f4ab9bc841a7d) // permutation_comms[13].y_hi + mstore(add(payload, 0x4060), 0xe70541d6b79945e9569fd59388739f5b4ce57794044d287d7b0b58e35198caab) // permutation_comms[13].y_lo + // Permutation commitment 14, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4080), 0x0000000000000000000000000000000004e1b539a3a123291eaa8c85be3395e7) // permutation_comms[14].x_hi + mstore(add(payload, 0x40a0), 0x9c6845178d995313daf42680692210e1ec79278ec8b6e2da1d6f289609100404) // permutation_comms[14].x_lo + mstore(add(payload, 0x40c0), 0x0000000000000000000000000000000010d56b62afe35890b4f98b946daa8936) // permutation_comms[14].y_hi + mstore(add(payload, 0x40e0), 0xd83e014595585e2892e21bfc5e86f84d404b435dc1a689539d74773aba55dad4) // permutation_comms[14].y_lo + // Permutation commitment 15, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4100), 0x000000000000000000000000000000000f227bcaef796cabf0a93289fb8321e9) // permutation_comms[15].x_hi + mstore(add(payload, 0x4120), 0x1d43880fa5fcebab73c77c6bb406cc5e9386a81774635b5a6144b75ef10cd994) // permutation_comms[15].x_lo + mstore(add(payload, 0x4140), 0x000000000000000000000000000000000a849d95d37e501cc6272f325f88d677) // permutation_comms[15].y_hi + mstore(add(payload, 0x4160), 0xb25be83ce57eb9c32d382613930bbc0ef7ec349d44ac74a9383c111efcb73783) // permutation_comms[15].y_lo + // Permutation commitment 16, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4180), 0x000000000000000000000000000000000b77ada25b279742ec75d2014583ad79) // permutation_comms[16].x_hi + mstore(add(payload, 0x41a0), 0x427bfa99ab8a941648e1a11084fec2a6fdb8192f498cf3e272a5e786597273a1) // permutation_comms[16].x_lo + mstore(add(payload, 0x41c0), 0x00000000000000000000000000000000056788c108fd40583888b8771a70d3f6) // permutation_comms[16].y_hi + mstore(add(payload, 0x41e0), 0x364290f978d1fc201c0a76561a4c1cdde7643f7d76448dad2586c3eac2e34104) // permutation_comms[16].y_lo + // Permutation commitment 17, also a 4-word + // EIP-2537 padded uncompressed G1 slot. + mstore(add(payload, 0x4200), 0x0000000000000000000000000000000002ecf71916494d46153fdd513ead1917) // permutation_comms[17].x_hi + mstore(add(payload, 0x4220), 0x06401b48839713727c920f4591fe09ac3e8f4140ef1cd9e39b0d0bbe0b5b87d4) // permutation_comms[17].x_lo + mstore(add(payload, 0x4240), 0x000000000000000000000000000000000e7bab8cc3c714f06826c8f3695dc63c) // permutation_comms[17].y_hi + mstore(add(payload, 0x4260), 0xe7e931ff0dbe009cbb84fef0b99124905d90cdd6f5356a7ee7673548f6f0692c) // permutation_comms[17].y_lo + + // Return exactly the INVALID prefix plus the generated payload. The + // linked verifier pins this byte length and the resulting codehash. + return(runtime, 0x4281) + } + } +} \ No newline at end of file diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md new file mode 100644 index 000000000..07efdfa66 --- /dev/null +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -0,0 +1,69 @@ +# Moonlight Wrap point_pair Replay Fixture + +Pre-rendered artifacts for the `point_pair` accumulator arm of +`tests/ivc_accumulator_replay.rs`. The IVC fixture next door covers +`AccumulatorEncoding::new` (explicit lhs/rhs scalars); this one covers +`AccumulatorEncoding::point_pair`, whose +`expected_acc_has_carried_scalars = false` template arms were otherwise only +ever compiled, never executed against a real proof. + +This is a single-contract render, so there is no `Halo2QuotientEvaluator.sol`; +the replay deploys the verifier with the verifying key alone. + +## Provenance + +| Field | Value | +| --- | --- | +| Source commit | `5209a9c` | +| Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | +| Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | +| Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | +| Public inputs | 19 (accumulator occupies the trailing 8 words) | +| Verified on-chain | yes, 1,277,823 gas under revm Prague | +| Native/Solidity trace | 244 trace points matched | + +## Regenerating + +Needs a Moonlight checkout on `origin/codex/wrap-bench-cherry-picks` placed as +a **sibling of this repository** -- its `aggregation/Cargo.toml` refers to +`../../midfall/proofs/solidity-verifier` by relative path, so the bench renders +with local codegen. + +That branch pins the Midfall crates to a fixed git revision, which would link a +second copy of `midnight-proofs` alongside the path-dependency one. Add a patch +to the Moonlight workspace `Cargo.toml` to unify them (do not commit it): + +```toml +[patch."https://github.com/EYBlockchain/midfall.git"] +midnight-circuits = { path = "/path/to/midfall/circuits" } +midnight-curves = { path = "/path/to/midfall/curves" } +midnight-proofs = { path = "/path/to/midfall/proofs" } +midnight-zk-stdlib = { path = "/path/to/midfall/zk_stdlib" } +blake2b_halo2 = { path = "/path/to/midfall/third_party/blake2b_halo2" } +``` + +Then, from the Moonlight checkout (needs `midnight-srs-2p19`/`2p20` in +`SRS_DIR`; takes several minutes): + +```bash +MOONLIGHT_RUN_WRAP_SOLIDITY_BENCH=1 \ +MOONLIGHT_RUN_WRAP_SOLIDITY_TRACE=1 \ +MOONLIGHT_WRAP_SOLIDITY_DUMP_DIR=/path/to/midfall/proofs/solidity-verifier/target/moonlight-wrap-solidity-dump \ +SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ + cargo test --release --lib \ + wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs \ + -- --ignored --nocapture + +cp target/moonlight-wrap-solidity-dump/{Halo2Verifier.sol,Halo2VerifyingKey.sol,\ +calldata.bin} fixtures/moonlight-wrap/ +``` + +Then update the source commit above. + +## Staleness + +A snapshot of the codegen that produced it. The artifacts are self-consistent, +so the replay keeps passing after a codegen change -- it just stops exercising +current output. Tracked by the commit stamp rather than an assertion, because +detecting drift means re-rendering, which needs the SRS and the Moonlight +checkout again. diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin b/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin new file mode 100644 index 0000000000000000000000000000000000000000..f19116b45b7a7b4a91f8cfd6990d9cb2af063bbd GIT binary patch literal 8516 zcmajkWl$VZmoQ)kXK)>y;O+!>x50x24+M7!?(S|05}e==+=IIl+}+(}zujNoJE_|3 zf45FQeY(5q-rIc+X)Gx=)c<~n{_kPZuKy!$1R00J`#pp73q?=<;R6#(>GU@~kOt8) z2NFOxxuM_ea-dk52u>~dt2DQ6I;&boOXfAC2PK3y(uybI-Wyi>OZKvJBxSYvEkCL{ zG=s+XRZz#+3uEB;x5(BVFO*FyU2<>eAU*u3!XCFAugD46J>v<2wCL^WxnP3Mv8tZ0 z*>a&quv*UCb=c|M{)qLD7lzBxN*qW}AO-j1D95oV?OL-z=O;#O2tY;?6q{#eaIH}o zuS^6$c3Jd~HZ;;ZB;4kjvs4R#^vEBZN?8q^I!TR~!21=b!a1$F@PCuP6-smfCL~ zny;5HVcbVcnzYNElueyEimZg2&UtOSV`Qe4(e}}6hkAL#7)mp)(X27nN-Ql= z8WtRE&91-mkN*szW z;*U7p0_oxC8W`M7*F>nb*{kCtOA^#h^wC%XH2eVm0wMIH>H3Oy;BXuYl#n7?h3`>> z4ZDyY_oY7|BY(#lX&VS1J~bQyOKbEAAT|E5vmmbi;(_vRL+9TnL3|_Jq*j*H6l=){ z>7fHsUjgM9Y$m>q+r1>%nywjT!_WG0#+S43?h)#iK#Rs#vGDXM;|dgRV)o+_0Z0#% zEwqsq3!{>4WX^!hmiTl$Q667I0sBRrs zExx~c{5N-aCvrX*QLv~llNy=ucXE;>e1que>VOjV@LL6iMFy3L=Fw9xq{oT(c#D~^ z2iv6zpN|_gzTc?zFRm=wx-wilv1K7#*i11)U*58bfpK4+o9i-0|9SsV-rkrUnRBmN z+9*R-8{f50j6TX33u{7uKhNs#*?k`Ea*(`4<9yAzub)%TjrmLfnI9_WGa^D88rQZ5 z(jd`y3Vm&?+XIAmqVI9J^Pft%C~?=nToq;eej=8~$79~^*1d)F2yVYc5nxKN(@>JX zjr$VQ@JhOhCrP_25co48!i&I>WYg$=r=9F4jC&{~Z4ZL`CqKd)`c1ZZiUAcaje+vf ziBKK_z+%N@saKHjZ|b*_MtGPTcn>ejgO~jJU8Tb`RYJ)8xcRD*2kZQ_+2q_+Rr0ck zYz|%|NOIn@T+QV;+GM#_ub01N7L67{kzCgF{6&X0Aw7oUGvbizvS=trVD$U;UARsMEoY!OtG@I-djvj373hWS<2_ zs|af7l*lVEbB!n`85&VSdJJZi(xXT}5^s7WPV1~HxnA)V%Iu(}J-0ekK46?>;K_MP zau_{%a~%JM&wNhU4@i&HT68h;k|$DudGt)kVN~*W2~W;Twf2R~_D3R&>m%}&=#^ONoxRs`RHL-#_Pb~C5)fcf1(lM((5%5cRBDQh{B_d zDCKti9Wx#OnLi-zp;LlN0&lyzMTH_Aw~dmA-+#I~h>veDG0X47D7WU0x=>5!gwOt_ zNaMhd{Z)X>4|2Kv>W8*FRq)aETl&hF%9*|j^1Gn}oY%n7?xh_WriQDqn2i4YCSW^> z{>Uep8`5JHZPq?VB8gRP3niKiDy7+_n=lGm$(=WJqyg1r8zvZ%LSvs$VH45toSKcG z%*Frl7qRGj!ftZJEV3tBVR0=^#3A>DgBCu^u#w)e6bjR(ZG1mcz8h21M8VPixG-af z^vG9K>9DOr)9f5H8yOK=H-(R#TXWv^Hfw8ztO8PhG@Fzwo!~wFBWl3aLR)7S^N=1k z7+9q(+N$=V0DX$#tHle2yjih#6fFhk*<>P>-7}Dfz^~dudnumAV_!qs&vy zu9;_sZjPptI(mEr2HuRE;us)Aqw^9$ZKzU8Tj-5DUDUbGInP9QO5_)DLVEb}S>w}I z(-X5|k75h@nNz58$x(cf<#$&l!`dYU{k|ya^gkr!O#(fLyNgG>$%>F3Q`5%bRZGl% zDB6QQ_O}H41DkLF-HKcBlQk~O4s+$cLuk*DhGgVI7$LB6M5YP=>EV6v7E0eo%#_IA z=!hQPeou9PY&?H{v-5%}Q0gA0!cPexLnMfhIYIhB8xcwEB?{?L1bOTuR!y__c3=W_ z#IUZiY`PcvOwf%WU@ffxX}I?HcHTw7UWGX5Im%uMHTTm9`7Cy*W#QM|EhkEHPJ+0_3V1GbBv zKrPg)r)sSJ5TSExi?b0hpi3dYL!uja9j%ATKi>}N0hfwL)W&t0T9M1DU|D0?kE)3} zwVttwg>rh5XcsH%^y{? zdA6RvKD=6WmRHkNOrhCbKPh)_Lg6!m^k`1Kdh4(!1d2nbeyoLMvE7?OL>F^@&KULJ z147_?CYf#vG#_%O<#-?B%p!Vl7NmzFO-OxYGt-Nr{w2>?vxcK4{ekNTR@(x$5Bwf_ zy;H*tg7+qs+UDL0Nx6I|kRAonBgRiylXInF3yl^sCb?OQZgyoT{NcN8eLK!Kr=P}~ zeciGJS21}FIu7?N?IO+3L3;cY9Yt-ASnOs8;zp0cha&DDaDuaRD6DiA&!lS}eH13v~3$eLnC<+Jh#X_Q6*XQ}_ zpZyd6s(Hde@hRZ_Z62>jI2Hc-Nj3NM!o%bqf0|8!y;i}jyzg(t-0*S|02R|4j^#UK zexQtW>J7eN`!xQ@oYvbmU$j_?30xx&-}N(|zU*p^Jql(DJ8rL`E4Oc{LG=3=2c!p4 z+qk5-Hm>933iUZt(-W69S}jq>EgPCX@I5sQTCx6-^$vbL$ji8$5h3KdeH4N8_(KHN z0B)P2JwS?3zfdoBwM4{l&-s;!56-8ZSaN2x)E}`?tHYYmBua_COf4P%?4Q`eG=)QH z=KiH4Yx+d{pH|mm)GlTt`Jc#wngv_R;mzH0S8^Uk`fl5F2-Hea3uqzp!_$3-1#YDf z7bG^0tpnj4YI111m`I|;AL&h(o=ULGy;-eAKL>gTjTTD^LHd8jPKyo$4vk`x zH-!l<;yzLUu1f(+knNO5Le288i0lU*hNq{EZPP){L(JcP$>42sdH6d?el79iwO`6x z>6tj#4C2lRECqb;TpP$$`Z76jbeH&B7=JnIk3(5Bd8Yx+`W-AXD^%{?J;7uA))`sE)8!&h_&2@3d7ZWt7)GmULz`K6h!wg3rO852?VqB{71GU&&hPZPjPQQye_=lVu$QY^{BQvm8Hwc zhfOLC?#Ui&8}N%jYT`j=AVUBTDgW&DvTi%V>RYt55j3sHHFrS-CT72ao3s ztm>V*izvPLIA50xAj@W9E0P$^sA->6g!9`P){c8f{my#DJ-=eY4IRC_KD-Er!j$OR zcU&#v6p1U6J}v*C)}nWM>R0St9UD;)R{i}wHLur*b6`NW!sRU zWM7H{za;P-W$klaqmM;{-YO-=QT$t!6@zs(s+AH@2S++k@5O$ovRS9TtfbEui=k;p zPh0I(q?5fa7JDNKtJz251Q`>&@sJw19z#fns{bjXB}Cwd1#i}vF{_NPTF8Bc=<;bbqu~ppj~P?UsH`9$#CMIS2q^@X6G`R zC|rQa0@r}HY_d<^G>*htz`1x3D%cWs&SlU7F}(7$ILM)hpM|w z36{p1vQ)+p^`49+4=}SF_DDo|fdj2q2x|0{CQQKxqV=mbb1}2fxPesCgXAi1E2De8 zqD@6AQzahu3?`^4L+=`I9Kg^5l+Z2rhPNL}a&5+wXh>TK$yYGeSNuMBjON!RsF3AF z2J~fkwkx(xMT7_PH}&c*2mY<(oQC;8IKkfm)BPuhSADI1=))}fL`60{LN(7S2IyMA zpOdp%%yaI!=+LJ3VAUi1-QGzYG4_2sbllO(p(Ud*!*_coJFtr#wh60!FH+Dj2=Gfb zTc%fJ!OW{KEV8l#<8AAM+4(xEwP!Jm)-M09wF13Xc%$7!eCJe2R@vD{&b&f3#YvMw z5+%xwfo3i;o8$b$HS9kpS!4W0!qV|^2J8A%^5F%GBsjInRx8+%w-#)IgKgDrg+CgD z57Dn=i_BE~>|7*zs5v+(Xcs>@n$5N(_VDxhRK7ReD_-=c#xC3veQx@u6xjaj?+`py zr~>bqR;RuHXk+~zD=bdR;ko@-Kh06^MY=%Uv*Cjg_n>0-5Yk$w%zzLMZ*6T*6p2Y_ zm<4p%d%84?8+!~0f$>xr|3EMAJTneKaZS;Xy3N@)RKH30BQT9Rt5bu)qVVN#5fnHq zWs)&Fi*6__?bBL!A=y*U!!1K8W5&G>z+@)$P429&sX1B5qKKoHLfdB|r*-Qt*Ub*b zLuyjG72>60{xDgJlmQCTdwx78Klk$X#rG?jZHV*<5N1sm6~QaeSPJ+VN=V!tih}$B zQ(HD^6HXW#=rjUDPQZt*XCiWf0l6q$8`?lslxHa!*}pP@KHCf8Q; zP7|P**Uj-RG}n^F61r1mI6O9%WX`O~GvcU;9&l2xgYuF>L_)=OAve%fed|y6{7Mbe z&E^!J3uT-=*Qz;InHS7)$ z0|ndcHW484m;j7l@$c2gA0J4l2c`W>kIl&aur|B~dU(djV)qVWF-)cE(HLy+R4*3<5lGvjwk2Y??}0_aQzc=2!Zd?fb~8 zNQyTqq%!O`r_8)-f9To#;IzQpESHMxq1v2iqc3cth)ZX0LP1&J{_Ju?TzS|AJDRO} z`QazL+}6RJI*-ydB0L=yUm$txxB9&5-nNyvZBCMpwG$;ac`c_P3%@B)BR@*<8@;M- z4t3)ZkJRK>(^uaEs+Nz(u2b++L4v2xzYIG0KKp#&qZUP!i*FU2QpPe9b{?6g7a?RzBXPV-C78?g$J4Pup=l7 zcVePY>}mTrbOxnC;QB*PLl^#*ONCJNrBR8B~3k^z~ zfIJOL41~@+i&`Fk$Dm9UidjgReK~Y`I3;jAI@$WGw9yHwqB$!Fi>nVZ(mJxKws>BT zqL>g$Kwj0DJA*aUvBa}qLFE-m$xPg!MZUD$8BC&8bx*LviL`ej+yNR3wChkQBmpbW zXq-qhgjQR8LS$?YP2T#7w8~Tc#ZWQ9rwqKY_QN! zvU>>a9vakKO}2JL=8b_1!;J!K%)*N%%PcT9@q$M?g<9akbVgHEkE9z!!6RgBKt8#n zjFN+(h|T1`nQ`n))o&NC4DP}@$zeH9xap;atPJ)%y>{+PAO5^k0YW|Q83D7f&s#<-~MvyB#V#%@< z^HHc@RxY<^(MlvAC-pf*WfWKt7-0}A4iPuy(n#?R`e`og7iG6E7;|JD4MmS6nY5df zRALY44?X4#RG2Ts1MhLtxTr2W)0ArF8k(cN$Gpz5hr_9OMC~-vfh3#_B?mkD!#-QC zbCJ&xbtpc`-O*Zx9WwzeSZ9*BgQe9du>DB4WH9k}^0K-A782-H-Ld-A{*nFc@5qGc z{@2yP#?vzDoBln$Ynr$Afp6Yf^`-8DKTnBcp=>91sE995%TsfDEe7qTje zv`fL#%ojtA5adVQuQ$+!WA>Zkc$Nv6Ekk{>ww$uzpF{{m?kev2?w^Yg%|5q4KL*D! zww2P9mbZ;v1PC_^kK2>D&Lde`Q+G~84C8!pgb&Ee3NvG#2y5Cn-$RM=uo0P_HKE^@ z8t)pA0d3DbTlu7&rol)C|IP-N#CC{}2XHcc_M+n;Ab@WRHO!cf*IJ(xJiV!KhCXI3 zB11{&%jKn-P?lxTb_ySRh6$$+js9`Fx%+AF;}5;MdV@Ms93LICRHT3a5S-a@;tvTN z#l+k+LRT@e0(pzv0gKgMV3^$oTVrbu5G~-mRHUbdV18X)y~o(C8_0`EE9bX9A~#j7gW;H>IkMSAMYLGgC3a8#biz0X15OPVhfY!bG0_SFF81U+V^ ztJWdgvE*VvekSpubJ5!t#mYS-Z{w>>7|GwEC&IRtxm@Olt`ST$ep!Y`QjniSDBY0r zqpi6Yxyn2V4aqJ~QKD|r!A+grAc?UzRtC4DiobOjyovArH$;MycLY;~Uy^Ikms{bt zYj~HFJ33O13&n#}z`{GM98QVaSeXa0`uOCuz-qu74k~4~x}-^fHhrl{F4=>Z8!kO> zBze^Jo&!B{{c}9VuH;o`mmp~~`jR_J?meC!PU7g3ngvb^9fjW zt5IsXel!;-H<d){_7|@z`C^^Xk;JK9DzA5% z^ELm}f9j{`T==z9$M59e5di~ODEL(Bw@nq^)aM-c4@i4i#)eN4Dcx~T9AP75EP2se zKG`Xd|2x(;3G_VG1MrHh7@93;K{yQ*{9S+xB{*jNK| z*q^uWB-?@w(T0rYh{;KwW}>5HGX5mR^Q04=;J3r6Do+vwq{e_{Z#N{+Ta(PxI>rD~ zy?e_GzXzP?tff#dDJYJ1bkKwKV@zj#6(Zcw+tJU^gN`I$>*>`k6K z9#Mky5aa)=zx_{t2Eqd&#*o8*>T?h${L?>%h~wKFR0PIjCQDAXL&NiPX-T3Qv$zrJ z=$pXkpycY+)aMHu4oysBQu`R68*ux1Qsoq_OiebUFnuvEFQLxrvj3;P0&#r~@!k?e zPIzxrzji5J^yLo17MD^vw2`7>@x6NNjSPlGtaBV#0e<4hcvs*5r#@8(y;QeuRvUD5 zuSqK4Nl5IPMXD6PSX(ZU_^0UqzaQ*+o#Kj%mA%U4IfJLM#EtFY)IJC0{OU zH^U~TXRaTNql;1XP|VkKMlsO(kNPucKg{b5>a1g-Ue|Iw&gxnD1N!oRd+-2&tcudx zWOp-pb*qu-`K}4vI^al$S$3rQAN^~TjJXg%eD+iLuAo%n_`v#!knjJ@Zx3RN#5;HW wCe1R>k@#_Y^R%=CCf#+C`hGo?|L9*}d3-BmdhHJtYer6rsNY>C1K8aC7isx+d;kCd literal 0 HcmV?d00001 diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs index 0fba70215..a8f000c4f 100644 --- a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -21,30 +21,27 @@ //! from a VK without the full SRS (`SolidityGenerator` consumes //! `params.g_lagrange()`), which is what rules out a vk.bin-based replay. //! -//! Regenerate the fixtures with: +//! Two fixtures are replayed, covering both accumulator encodings: //! -//! ```text -//! HALO2_SOLIDITY_RUN_IVC_BENCH=1 \ -//! SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ -//! cargo test --release \ -//! --features evm,truncated-challenges,in-circuit-fewer-point-sets \ -//! --test ivc_keccak_solidity -- --nocapture -//! ``` +//! - `fixtures/ivc` -- the IVC Keccak decider, `AccumulatorEncoding::new`, +//! which carries explicit lhs/rhs scalars. +//! - `fixtures/moonlight-wrap` -- the Moonlight wrap decider, `point_pair`, +//! which does not. Its `expected_acc_has_carried_scalars = false` arms were +//! previously only ever compiled, never executed against a proof. //! -//! then copy `target/ivc-keccak-solidity-dump/{Halo2Verifier.sol, -//! Halo2VerifyingKey.sol,Halo2QuotientEvaluator.sol,calldata.bin}` into -//! `fixtures/ivc/` and update the commit stamp in `fixtures/ivc/README.md`. +//! Each fixture's README records its provenance and regeneration command. //! -//! The fixture describes its own accumulator placement: the offset, limb count -//! and `has_accumulator` flag are parsed back out of the rendered verifying-key -//! payload, and the infinity encoding out of the verifier's own constants, so -//! this file carries no second copy that could drift. +//! A fixture describes itself: the accumulator offset, limb count and +//! `has_accumulator` flag are parsed back out of the rendered verifying-key +//! payload, the encoding kind is recovered from the payload width, and the +//! infinity encoding comes from the verifier's own constants. So this file +//! carries no per-fixture constants that could drift from the artifacts. //! -//! Staleness caveat: these are a snapshot of the codegen that produced them. -//! The fixture is self-consistent, so it keeps passing after a codegen change -//! -- it just stops testing current output. `fixtures/ivc/README.md` records -//! the source commit so drift is auditable; detecting it automatically would -//! require re-rendering, which needs the SRS again. +//! Staleness caveat: these are snapshots of the codegen that produced them. +//! A fixture is self-consistent, so the replay keeps passing after a codegen +//! change -- it just stops testing current output. The commit stamp in each +//! README makes drift auditable; detecting it automatically would require +//! re-rendering, which needs the SRS again. #![cfg(feature = "evm")] @@ -61,18 +58,24 @@ const GAS_CAP: u64 = 5_000_000_000; /// word. The proof payload starts immediately after. const PROOF_PAYLOAD_START: usize = 4 + 0x40 + 0x20; -fn fixture_dir() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures/ivc") +fn fixture_dir(fixture: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures").join(fixture) } -fn read_fixture(name: &str) -> Vec { - let path = fixture_dir().join(name); - std::fs::read(&path) - .unwrap_or_else(|err| panic!("missing IVC fixture {}: {err}", path.display())) +fn read_fixture(fixture: &str, name: &str) -> Vec { + let path = fixture_dir(fixture).join(name); + std::fs::read(&path).unwrap_or_else(|err| panic!("missing fixture {}: {err}", path.display())) } -fn read_fixture_string(name: &str) -> String { - String::from_utf8(read_fixture(name)).expect("fixture should be UTF-8") +fn read_fixture_string(fixture: &str, name: &str) -> String { + String::from_utf8(read_fixture(fixture, name)).expect("fixture should be UTF-8") +} + +/// Read an optional fixture file. Split renders ship a quotient evaluator; +/// single-contract renders do not. +fn read_optional_fixture_string(fixture: &str, name: &str) -> Option { + let path = fixture_dir(fixture).join(name); + std::fs::read_to_string(path).ok() } /// Read a labelled VK payload word out of the rendered verifying-key source. @@ -121,17 +124,30 @@ fn assert_reverts(outcome: CallOutcome, case: &str) { } } -/// Replay the shipped IVC accumulator fixture, then mutate the accumulator -/// public inputs and assert every mutation is rejected. +/// The IVC decider carries explicit lhs/rhs scalars +/// (`AccumulatorEncoding::new`). +#[test] +fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { + replay_accumulator_fixture("ivc"); +} + +/// The Moonlight wrap decider uses the scalar-free `point_pair` encoding, whose +/// `expected_acc_has_carried_scalars = false` arms were previously only ever +/// compiled, never executed against a proof. +#[test] +fn wrap_point_pair_decoder_rejects_malformed_public_accumulator() { + replay_accumulator_fixture("moonlight-wrap"); +} + +/// Replay a rendered accumulator fixture, then mutate the proof and public +/// inputs and assert every mutation is rejected. /// /// The accept baseline is what gives the rejections meaning: without it a /// "rejects" assertion could pass because the verifier rejects everything. -#[test] -fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { - let verifier_solidity = read_fixture_string("Halo2Verifier.sol"); - let vk_solidity = read_fixture_string("Halo2VerifyingKey.sol"); - let quotient_solidity = read_fixture_string("Halo2QuotientEvaluator.sol"); - let calldata = read_fixture("calldata.bin"); +fn replay_accumulator_fixture(fixture: &str) { + let verifier_solidity = read_fixture_string(fixture, "Halo2Verifier.sol"); + let vk_solidity = read_fixture_string(fixture, "Halo2VerifyingKey.sol"); + let calldata = read_fixture(fixture, "calldata.bin"); assert_eq!( vk_payload_word(&vk_solidity, "has_accumulator"), @@ -146,18 +162,34 @@ fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { // fixture describes its own instance-space offset via the VK payload. let proof_len = read_u256_word(&calldata, PROOF_PAYLOAD_START - 0x20) as usize; let instances_len_word = PROOF_PAYLOAD_START + proof_len; + let instance_count = read_u256_word(&calldata, instances_len_word); let first_acc_word = instances_len_word + 0x20 + final_acc_offset * 0x20; // 7 limbs of 56 bits pack 4 to a field element, so each coordinate takes 2 - // words and each point 4, with one scalar word following. + // words and each point 4. assert_eq!( num_acc_limbs, 7, "limb count changed; the word arithmetic below no longer holds" ); + + // Recover the encoding kind from the payload width rather than hardcoding + // it per fixture: the accumulator occupies the instance tail, so eight + // words is `point_pair` and ten is the scalar-carrying encoding. + let acc_words = instance_count as usize - final_acc_offset; + let has_carried_scalars = match acc_words { + 8 => false, + 10 => true, + other => panic!( + "unexpected accumulator payload of {other} words; expected 8 (point_pair) \ + or 10 (point-and-scalar)" + ), + }; + let scalar_stride = if has_carried_scalars { 0x20 } else { 0 }; let lhs_scalar_word = first_acc_word + 4 * 0x20; - let rhs_first_word = lhs_scalar_word + 0x20; + let rhs_first_word = lhs_scalar_word + scalar_stride; let rhs_scalar_word = rhs_first_word + 4 * 0x20; + let acc_end_word = rhs_scalar_word + scalar_stride; assert!( - rhs_scalar_word + 0x20 <= calldata.len(), + acc_end_word <= calldata.len(), "accumulator words run past the fixture calldata; the fixture is inconsistent" ); @@ -183,15 +215,20 @@ fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { let mut evm = Evm::default(); let vk_address = evm.create(compile_solidity_with_runs(&vk_solidity, SOLC_OPTIMIZE_RUNS)); - let quotient_address = evm.create(compile_solidity_with_runs( - "ient_solidity, - SOLC_OPTIMIZE_RUNS, - )); - let verifier_address = evm.create_with_two_address_args( - compile_solidity_with_runs(&verifier_solidity, SOLC_OPTIMIZE_RUNS), - vk_address, - quotient_address, - ); + let verifier_code = compile_solidity_with_runs(&verifier_solidity, SOLC_OPTIMIZE_RUNS); + // Split renders pin a separately deployed quotient evaluator; single + // contract renders take the verifying key alone. + let verifier_address = match read_optional_fixture_string(fixture, "Halo2QuotientEvaluator.sol") + { + Some(quotient_solidity) => { + let quotient_address = evm.create(compile_solidity_with_runs( + "ient_solidity, + SOLC_OPTIMIZE_RUNS, + )); + evm.create_with_two_address_args(verifier_code, vk_address, quotient_address) + } + None => evm.create_with_address_arg(verifier_code, vk_address), + }; match evm.try_call_with_gas(verifier_address, calldata.clone(), GAS_CAP) { CallOutcome::Success { output, .. } => { @@ -238,7 +275,9 @@ fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { ] { let mut malformed = calldata.clone(); malformed[point_word + 31] ^= 0x01; - malformed[scalar_word..scalar_word + 0x20].fill(0); + if has_carried_scalars { + malformed[scalar_word..scalar_word + 0x20].fill(0); + } assert_reverts( evm.try_call_with_gas(verifier_address, malformed, GAS_CAP), case, @@ -265,6 +304,171 @@ fn ivc_accumulator_decoder_rejects_malformed_public_accumulator() { case, ); } + + // --------------------------------------------------------------------- + // Calldata framing. These attacks need no layout knowledge at all. + // --------------------------------------------------------------------- + let instance_count = read_u256_word(&calldata, instances_len_word); + let mut framing_cases: Vec<(String, Vec)> = Vec::new(); + + let mut trailing = calldata.clone(); + trailing.extend_from_slice(&[0xde, 0xad, 0xbe, 0xef]); + framing_cases.push(("extra trailing calldata".into(), trailing)); + + let mut truncated = calldata.clone(); + truncated.pop(); + framing_cases.push(("truncated calldata".into(), truncated)); + + let mut wrong_selector = calldata.clone(); + wrong_selector[3] ^= 0x01; + framing_cases.push(("wrong function selector".into(), wrong_selector)); + + for (case, offset, value) in [ + ("wrong proof ABI head", 0x04, 0x60), + ("wrong instances ABI head", 0x24, 0x20), + ( + "short proof length", + PROOF_PAYLOAD_START - 0x20, + proof_len as u64 - 0x20, + ), + ( + "long proof length", + PROOF_PAYLOAD_START - 0x20, + proof_len as u64 + 0x20, + ), + ( + "wrong instance array length", + instances_len_word, + instance_count + 1, + ), + ] { + let mut mutated = calldata.clone(); + write_u256_word(&mut mutated, offset, value); + framing_cases.push((case.into(), mutated)); + } + + for (case, mutated) in framing_cases { + assert_reverts( + evm.try_call_with_gas(verifier_address, mutated, GAS_CAP), + &case, + ); + } + + // --------------------------------------------------------------------- + // Curve-level attacks on every proof commitment. + // + // The repacked proof opens with a run of EIP-2537 padded G1 points, so the + // run length is discovered from the padding signature rather than + // hardcoded: a regenerated fixture with a different commitment count stays + // covered. + // --------------------------------------------------------------------- + let g1_count = padded_g1_block_count(&calldata, PROOF_PAYLOAD_START, proof_len); + assert!( + g1_count >= 8, + "expected a run of padded G1 commitments at the proof head, found {g1_count}; \ + the fixture proof layout changed" + ); + + let p_hi = solidity_constant(&verifier_solidity, "BLS_P_HI"); + let mut p_lo = solidity_constant(&verifier_solidity, "BLS_P_MINUS_ONE_LO"); + // p - 1 ends in ...aaaa, so incrementing cannot carry out of the low byte. + p_lo[31] += 1; + + for index in 0..g1_count { + let at = PROOF_PAYLOAD_START + index * G1_PADDED_BYTES; + + // (0, 1) is field-canonical but off the curve: y^2 = x^3 + 4 gives + // 1 != 4, so the G1 precompiles must reject it. + let mut off_curve = calldata.clone(); + off_curve[at..at + G1_PADDED_BYTES].fill(0); + off_curve[at + G1_PADDED_BYTES - 1] = 1; + + // x = p exactly: one past the largest canonical coordinate. + let mut base_modulus = calldata.clone(); + base_modulus[at..at + 0x20].copy_from_slice(&p_hi); + base_modulus[at + 0x20..at + 0x40].copy_from_slice(&p_lo); + + // EIP-2537 pads each 48-byte coordinate with 16 leading zero bytes. + // Setting one is a non-canonical encoding of an otherwise valid point. + let mut bad_padding = calldata.clone(); + bad_padding[at] ^= 0x01; + + for (label, mutated) in [ + ("off-curve", off_curve), + ("base-modulus", base_modulus), + ("non-canonical padding", bad_padding), + ] { + assert_reverts( + evm.try_call_with_gas(verifier_address, mutated, GAS_CAP), + &format!("{label} G1 at proof commitment {index}"), + ); + } + } + + // --------------------------------------------------------------------- + // Scalar canonicality across the evaluation block that follows the + // commitments, plus the non-accumulator public inputs. + // --------------------------------------------------------------------- + let fr_modulus = solidity_constant(&verifier_solidity, "FR_MODULUS"); + let evals_start = PROOF_PAYLOAD_START + g1_count * G1_PADDED_BYTES; + let evals_end = PROOF_PAYLOAD_START + proof_len; + assert!( + evals_start < evals_end && (evals_end - evals_start) % 0x20 == 0, + "evaluation block is not a whole number of words" + ); + + for (index, at) in (evals_start..evals_end).step_by(0x20).enumerate() { + let mut noncanonical = calldata.clone(); + noncanonical[at..at + 0x20].copy_from_slice(&fr_modulus); + assert_reverts( + evm.try_call_with_gas(verifier_address, noncanonical, GAS_CAP), + &format!("proof scalar {index} set to the Fr modulus"), + ); + } + + // The accumulator words are covered above; sweep the remaining public + // inputs for scalar canonicality. + let first_instance_word = instances_len_word + 0x20; + for index in 0..instance_count as usize { + let at = first_instance_word + index * 0x20; + if (first_acc_word..rhs_scalar_word + 0x20).contains(&at) { + continue; + } + let mut noncanonical = calldata.clone(); + noncanonical[at..at + 0x20].copy_from_slice(&fr_modulus); + assert_reverts( + evm.try_call_with_gas(verifier_address, noncanonical, GAS_CAP), + &format!("public input {index} set to the Fr modulus"), + ); + } +} + +/// EIP-2537 padded G1: `x_hi, x_lo, y_hi, y_lo`. +const G1_PADDED_BYTES: usize = 4 * 0x20; + +/// Count the leading run of EIP-2537 padded G1 points in the repacked proof. +/// +/// Each coordinate is a 48-byte field element left-padded to 64 bytes, so the +/// high word of `x` and of `y` both start with sixteen zero bytes. Evaluation +/// scalars do not share that signature, which is what ends the run. +fn padded_g1_block_count(calldata: &[u8], proof_start: usize, proof_len: usize) -> usize { + let mut count = 0; + while (count + 1) * G1_PADDED_BYTES <= proof_len { + let at = proof_start + count * G1_PADDED_BYTES; + let x_pad_zero = calldata[at..at + 16].iter().all(|b| *b == 0); + let y_pad_zero = calldata[at + 0x40..at + 0x50].iter().all(|b| *b == 0); + if !(x_pad_zero && y_pad_zero) { + break; + } + count += 1; + } + count +} + +/// Write `value` as a big-endian EVM word at `offset`. +fn write_u256_word(calldata: &mut [u8], offset: usize, value: u64) { + calldata[offset..offset + 0x20].fill(0); + calldata[offset + 0x18..offset + 0x20].copy_from_slice(&value.to_be_bytes()); } /// Read a rendered `uint256 internal constant NAME = 0x...;` out of the From 29b4eb91da47ddb87d33c5fdcd6545cce1850046 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 05:12:24 +0100 Subject: [PATCH 066/108] Record deployment status and bytecode verification for moonlight-wrap The Sepolia deployment record documented what was deployed but not how to check it, nor that the generator has since diverged from it. Add both. Deliberately does not regenerate the artifacts. This directory is a record of a live deployment -- addresses, transaction hashes and the runtime codehashes of contracts that exist on Sepolia. Re-rendering Halo2Verifier.sol at current codegen while leaving those fields would assert that 0x5CfEd44D16F994fc17f681A83FEdFEB9c3348c17 has source it does not have. The sources and bytecode stay exactly as deployed. Verification. The tracked source does reproduce the on-chain runtime: compiled with the documented flags at optimizer-runs 200 it yields 21,161 bytes, matching the recorded runtimeBytes. Its codehash (0x79432a36...) is *not* the recorded runtimeCodeHash, and should not be: a byte-level comparison against the fetched on-chain code shows exactly 40 differing bytes, in two 20-byte runs at offsets 0x51 and 0x125. Those are the placeholder slots for `address public immutable AUTHORIZED_VK`, which the constructor fills at deployment. Every other byte matches. Both the command and the figures were re-run from inside the deployment directory before being written down. Divergence. Re-rendering the same circuit at e5300d4 gives a 212,419-byte source and a 21,203-byte runtime against the deployed 206,619 / 21,161, with TRANSCRIPT_MPTR moving from 0x80 to 0x1000. The verifying key differs too, in its quotient_program section. The circuit is unchanged (acc_offset = 11, 19 public inputs, point_pair). The record now names the fixes the deployed code does not carry: the memory layout rebase (its layout still sits inside solc's via-IR spill window -- AUDIT.md TA-5), the always-false accumulator identity guard, the pairing check accepting any odd result word, and the identity-only EIP-2537 smoke vectors. None is a demonstrated forgery path, but a reader of this directory should not have to reconstruct that list from the git log. Redeployment needs a funded keystore and an RPC endpoint and is left to a deliberate operator action. Co-Authored-By: Claude Opus 4.8 --- .../sepolia/moonlight-wrap/README.md | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/proofs/solidity-verifier/deployments/sepolia/moonlight-wrap/README.md b/proofs/solidity-verifier/deployments/sepolia/moonlight-wrap/README.md index 0a2c41b79..130a695cf 100644 --- a/proofs/solidity-verifier/deployments/sepolia/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/deployments/sepolia/moonlight-wrap/README.md @@ -4,6 +4,64 @@ This directory contains the generated Moonlight wrap verifier contracts that were deployed to Sepolia, plus the exact runtime bytecode fetched back from the chain. +## Status: deployed code predates current codegen + +**The contracts at the addresses below are still the ones described here, but +the generator has since moved on. They are not reproducible from current +`main`.** Nothing in this directory has been regenerated -- the sources and +bytecode remain exactly what was deployed, because they are the record of what +is on chain. + +Re-rendering the same circuit at `e5300d4` produces a different verifier: + +| | Deployed | Current codegen | +| --- | ---: | ---: | +| `Halo2Verifier.sol` | 206,619 bytes | 212,419 bytes | +| Verifier runtime | 21,161 bytes | 21,203 bytes | +| `TRANSCRIPT_MPTR` | `0x80` | `0x1000` | + +The verifying key also differs, in its `quotient_program` section; the circuit +itself is unchanged (`acc_offset = 11`, 19 public inputs, `point_pair`). + +Fixes made after this deployment that it therefore does **not** carry: + +- **Memory layout rebase.** The deployed verifier bases its layout at `0x80`, + inside the `[0x80, 0x8e0)` window solc reserves for via-IR stack-to-memory + spill slots -- see AUDIT.md TA-5. It has not misbehaved, but the separation + rests on spill placement rather than on anything enforced. +- **Accumulator identity guard.** `load_acc_coord_shifted` used a bitwise `and` + against a radix base, making the guard false on every call; the identity + branch was dead and the canonicality barrier ineffective. Fail-closed, not a + forgery path. +- **Pairing result check.** `ec_pairing` folded the precompile result with a + bitwise `and`, accepting any odd return word rather than exactly `1`. +- **Constructor smoke test.** Probes used identity-only EIP-2537 vectors, which + a non-conformant precompile can satisfy without doing curve arithmetic. + +Redeploying is a deliberate on-chain action requiring a funded keystore and an +RPC endpoint; see "Recreate The Deployment" below. Until then this record stays +as-is and accurate. + +## Verifying the deployed bytecode + +The tracked source reproduces the on-chain runtime exactly, apart from the +immutable address slots that are substituted at deployment: + +```bash +solc --bin-runtime --optimize --optimize-runs 200 --via-ir \ + --evm-version cancun --no-cbor-metadata Halo2Verifier.sol +``` + +That yields 21,161 bytes -- matching `runtimeBytes` -- with codehash +`0x79432a36a98570db8c04b9c5cc23994477089eabd2501cfe0b0a78ae5f3c38f8`. + +It does **not** equal the recorded `runtimeCodeHash`, and should not: comparing +compiled output byte-for-byte against on-chain code shows exactly 40 differing +bytes, in two 20-byte runs at offsets `0x51` and `0x125`. Those are the two +placeholder slots for `address public immutable AUTHORIZED_VK`, filled in by the +constructor. Every other byte is identical. Verified at `e5300d4` with +`solc 0.8.30+commit.73712a01`. + ## Addresses | Contract | Address | From 9bf8c51e1d1cc29afeac5d64f9d676aa8d470369 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 05:14:22 +0100 Subject: [PATCH 067/108] Regenerate tracked verifier fixture artifacts The rendered artifacts under proofs/solidity-verifier/target are committed and gated in CI, which fails the build when they drift from the generator. Refresh them for the codegen changes on this branch. Every difference is accounted for: - TRANSCRIPT_MPTR / RETURN_MPTR move from 0x80 to 0x1000, the layout rebase above solc's via-IR spill reservation. - ec_pairing compares the precompile result against 1 rather than folding it with a bitwise and. - The accumulator limb decoder's identity guard is gated on the word index alone, replacing the always-false bitwise and. - The constructor smoke test gains the G1ADD(G, G) == 2G known-answer vector. - Halo2VerifyingKey's quotient_program changes because the VM encodes absolute memory pointers: each shifts by exactly 0xf80, which is 0x1000 - 0x80, matching the layout move (0x4740 -> 0x56c0, 0x48c0 -> 0x5840, 0x47e0 -> 0x5760). Co-Authored-By: Claude Opus 4.8 --- .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 1029 +++++++++-------- .../Halo2VerifyingKey.sol | 38 +- .../Halo2QuotientEvaluator.sol | 513 ++++---- .../Halo2Verifier.sol | 822 +++++++------ .../Halo2VerifyingKey.sol | 286 ++--- .../poseidon-fixture-dump/Halo2Verifier.sol | 811 +++++++------ .../Halo2VerifyingKey.sol | 6 +- .../Halo2Verifier.sol | 665 ++++++----- .../Halo2Verifier.sol | 963 +++++++-------- .../Halo2VerifyingKey.sol | 26 +- 10 files changed, 2719 insertions(+), 2440 deletions(-) diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index 3168b1c84..6c05c2567 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -43,7 +43,7 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 8640; uint256 internal constant EXPECTED_VK_LENGTH = 8641; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0xd85df9a6825e0edb1a2ed376a8a317078c3f98f663d45355679082083fbbd1ad; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x055be1a34918fad6a0d2545bab0bac0a28bbc5c616f3a9d284639391b7b99b3e; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -55,8 +55,8 @@ contract Halo2Verifier { uint256 internal constant INSTANCE_CPTR = 0x15c4; // First general-purpose memory words reserved by the generated verifier. // RETURN_MPTR is a single word set to 1 on success. - uint256 internal constant TRANSCRIPT_MPTR = 0x80; - uint256 internal constant RETURN_MPTR = 0x80; + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; // ---------------------------------------------------------------------- // Verifying-key memory map. The VK header lives at VK_MPTR, followed @@ -64,84 +64,84 @@ contract Halo2Verifier { // runtime comes the challenge slots (challenge_mptr..) and the // per-stage scratch (theta_mptr..). // ---------------------------------------------------------------------- - uint256 internal constant VK_MPTR = 0x1de0; - uint256 internal constant VK_DIGEST_MPTR = 0x1de0; - uint256 internal constant NUM_INSTANCES_MPTR = 0x1e00; - uint256 internal constant K_MPTR = 0x1e20; - uint256 internal constant N_INV_MPTR = 0x1e40; - uint256 internal constant OMEGA_MPTR = 0x1e60; - uint256 internal constant OMEGA_INV_MPTR = 0x1e80; - uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x1ea0; - uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x1ec0; - uint256 internal constant ACC_OFFSET_MPTR = 0x1ee0; - uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x1f00; - uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x1f20; - uint256 internal constant G1_BASE_MPTR = 0x1f40; - uint256 internal constant G2_BASE_MPTR = 0x1fc0; - uint256 internal constant NEG_S_G2_BASE_MPTR = 0x20c0; - - uint256 internal constant CHALLENGE_MPTR = 0x3fa0; + uint256 internal constant VK_MPTR = 0x2d60; + uint256 internal constant VK_DIGEST_MPTR = 0x2d60; + uint256 internal constant NUM_INSTANCES_MPTR = 0x2d80; + uint256 internal constant K_MPTR = 0x2da0; + uint256 internal constant N_INV_MPTR = 0x2dc0; + uint256 internal constant OMEGA_MPTR = 0x2de0; + uint256 internal constant OMEGA_INV_MPTR = 0x2e00; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x2e20; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x2e40; + uint256 internal constant ACC_OFFSET_MPTR = 0x2e60; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x2e80; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x2ea0; + uint256 internal constant G1_BASE_MPTR = 0x2ec0; + uint256 internal constant G2_BASE_MPTR = 0x2f40; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x3040; + + uint256 internal constant CHALLENGE_MPTR = 0x4f20; // Challenge layout. Squeeze order in midnight-proofs: // user_phase challenges (variable count) // theta -> beta, gamma -> trash_challenge -> y -> x -> // x1, x2 -> x3 -> x4 - uint256 internal constant THETA_MPTR = 0x3fa0; - uint256 internal constant BETA_MPTR = 0x3fc0; - uint256 internal constant GAMMA_MPTR = 0x3fe0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x4000; - uint256 internal constant Y_MPTR = 0x4020; - uint256 internal constant X_MPTR = 0x4040; - uint256 internal constant X1_MPTR = 0x4060; - uint256 internal constant X2_MPTR = 0x4080; - uint256 internal constant X3_MPTR = 0x40a0; - uint256 internal constant X4_MPTR = 0x40c0; + uint256 internal constant THETA_MPTR = 0x4f20; + uint256 internal constant BETA_MPTR = 0x4f40; + uint256 internal constant GAMMA_MPTR = 0x4f60; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x4f80; + uint256 internal constant Y_MPTR = 0x4fa0; + uint256 internal constant X_MPTR = 0x4fc0; + uint256 internal constant X1_MPTR = 0x4fe0; + uint256 internal constant X2_MPTR = 0x5000; + uint256 internal constant X3_MPTR = 0x5020; + uint256 internal constant X4_MPTR = 0x5040; // Batch-open commitments live in 4-word EIP-2537 padded slots. - uint256 internal constant F_COM_MPTR = 0x40e0; - uint256 internal constant PI_MPTR = 0x4160; + uint256 internal constant F_COM_MPTR = 0x5060; + uint256 internal constant PI_MPTR = 0x50e0; // Accumulator (KZG IVC). - uint256 internal constant ACC_LHS_MPTR = 0x41e0; - uint256 internal constant ACC_RHS_MPTR = 0x4260; + uint256 internal constant ACC_LHS_MPTR = 0x5160; + uint256 internal constant ACC_RHS_MPTR = 0x51e0; // Lagrange / linearization scratch. - uint256 internal constant X_N_MPTR = 0x42e0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x4300; - uint256 internal constant L_LAST_MPTR = 0x4320; - uint256 internal constant L_BLIND_MPTR = 0x4340; - uint256 internal constant L_0_MPTR = 0x4360; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x4380; + uint256 internal constant X_N_MPTR = 0x5260; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x5280; + uint256 internal constant L_LAST_MPTR = 0x52a0; + uint256 internal constant L_BLIND_MPTR = 0x52c0; + uint256 internal constant L_0_MPTR = 0x52e0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x5300; // Legacy name: this is not h(x). It stores the expected opening // scalar for the linearized commitment, i.e. the negated y-batched // identity numerator reconstructed from the alleged evals at x. - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x43a0; - uint256 internal constant QUOTIENT_MPTR = 0x43c0; // 4 words - uint256 internal constant F_EVAL_MPTR = 0x4460; - uint256 internal constant V_MPTR = 0x4480; - uint256 internal constant FINAL_COM_MPTR = 0x44a0; // 4 words - uint256 internal constant PAIRING_LHS_MPTR = 0x4520; // 4 words - uint256 internal constant PAIRING_RHS_MPTR = 0x45a0; // 4 words + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x5320; + uint256 internal constant QUOTIENT_MPTR = 0x5340; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x53e0; + uint256 internal constant V_MPTR = 0x5400; + uint256 internal constant FINAL_COM_MPTR = 0x5420; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x54a0; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x5520; // 4 words // Multi-prepare scratch (sized at codegen time). - uint256 internal constant ROT_POINTS_MPTR = 0x4620; - uint256 internal constant X1_POWERS_MPTR = 0x49a0; + uint256 internal constant ROT_POINTS_MPTR = 0x55a0; + uint256 internal constant X1_POWERS_MPTR = 0x5920; // Q_COM materialization is currently fused into the final MSM scratch, // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero // reserved capacity until a future emitter starts writing Q_COM_MPTR. - uint256 internal constant Q_COM_MPTR = 0x51c0; - uint256 internal constant Q_EVAL_SET_MPTR = 0x51c0; + uint256 internal constant Q_COM_MPTR = 0x6140; + uint256 internal constant Q_EVAL_SET_MPTR = 0x6140; // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals // block of the proof; we keep it as a memory slot for symmetry. - uint256 internal constant Q_EVAL_CPTR_MPTR = 0x58c0; + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x6840; // Reserved 4-word slot for the G1 identity (point at infinity) in // EIP-2537 padded form. EVM memory is zero-initialised, and we // never write to this region, so the four `mload`s below produce // 0,0,0,0 which is exactly the identity encoding the EIP-2537 // ec_add / ec_mul precompiles accept. - uint256 internal constant G1_IDENTITY_MPTR = 0x59c0; + uint256 internal constant G1_IDENTITY_MPTR = 0x6940; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain // Solidity proof shim rewrites proof scalars into canonical BE words, @@ -149,11 +149,11 @@ contract Halo2Verifier { // side `evaluations` loop range-checks and spills that value here so // downstream eval references (gate evaluator + PCS q_eval Horner) // become 3-gas `mload(...)` instead of calldata reads. - uint256 internal constant REVERSED_EVALS_MPTR = 0x5b20; - uint256 internal constant SELECTOR_ACC_MPTR = 0x6ee0; - uint256 internal constant QUOTIENT_RETURN_MPTR = 0x80; - uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x6ee0; - uint256 internal constant TRACE_U256_MPTR = 0x9a00; + uint256 internal constant REVERSED_EVALS_MPTR = 0x6aa0; + uint256 internal constant SELECTOR_ACC_MPTR = 0x7e60; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x7e60; + uint256 internal constant TRACE_U256_MPTR = 0xa980; // ---------------------------------------------------------------------- // Per-category bases for EIP-2537 padded G1 commitments. The proof @@ -170,13 +170,13 @@ contract Halo2Verifier { // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans // ---------------------------------------------------------------------- - uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x63e0; - uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x67e0; - uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x68e0; - uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x6a60; - uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x6b60; - uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x6c60; - uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x6ce0; + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x7360; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x7760; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x7860; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x79e0; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x7ae0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x7be0; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x7c60; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. @@ -198,7 +198,7 @@ contract Halo2Verifier { function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Scratch is reused for every runtime-prerequisite probe. - let scratch := 0x80 + let scratch := 0x1000 // MCOPY must be available because the verifier uses it for // proof-time point/scratch staging. Execute the opcode here so a @@ -222,11 +222,44 @@ contract Halo2Verifier { revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair // smoke call. - let msm_scratch := 0x6ee0 + let msm_scratch := 0x7e60 for { let off := 0 } lt(off, 0x2940) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } @@ -329,7 +362,7 @@ contract Halo2Verifier { // guards against a future emitter passing a raw scalar. if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } - let p := 0x1ce0 + let p := 0x2c60 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] mstore(add(p, 0x00), 0x20) // base len @@ -566,7 +599,11 @@ contract Halo2Verifier { mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } @@ -598,7 +635,13 @@ contract Halo2Verifier { // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div @@ -1402,15 +1445,15 @@ contract Halo2Verifier { // q_const_mptr points to Fr constants used by the VM. // q_program_mptr points to the bytecode stream. // Constants are stored as consecutive 32-byte Fr words. - let q_const_mptr := 0x21c0 + let q_const_mptr := 0x3140 // Program bytes are also stored in the VK payload, packed into // 32-byte words by PackedProgramCodec. - let q_program_mptr := 0x27c0 + let q_program_mptr := 0x3740 // Running Horner accumulator for fully evaluated identities. // After all identities, this is nu_y(x) for the `None` // identity group. // Initialize A = 0 before scanning the identity stream. - mstore(0x70c0, 0) + mstore(0x8040, 0) // Simple selectors are grouped into separate linearization // buckets. They start at zero for every proof. // q_sel_zero_off walks selector bucket byte offsets. @@ -1431,13 +1474,13 @@ contract Halo2Verifier { // block multiplies by mload(selector_power_mptr + offset) // unconditionally -- so initialize the slot rather than // leaving correctness to two filters in another file. - mstore(0x7100, 1) + mstore(0x8080, 1) // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 42) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) // Store y^i at selector_power_mptr + 32*i. - mstore(add(0x7100, shl(5, q_y_power_i)), q_y_power) + mstore(add(0x8080, shl(5, q_y_power_i)), q_y_power) } } @@ -1446,102 +1489,102 @@ contract Halo2Verifier { // VM/native identities, so they occupy the same y-batch order. { let var0 := 0x1 - let f_3 := mload(0x5f60) - let f_4 := mload(0x5e60) - let a_0 := mload(0x5b40) + let f_3 := mload(0x6ee0) + let f_4 := mload(0x6de0) + let a_0 := mload(0x6ac0) let var1 := mulmod(f_4, a_0, r) let var2 := addmod(f_3, var1, r) - let f_5 := mload(0x5e80) - let a_1 := mload(0x5b60) + let f_5 := mload(0x6e00) + let a_1 := mload(0x6ae0) let var3 := mulmod(f_5, a_1, r) let var4 := addmod(var2, var3, r) - let f_6 := mload(0x5ea0) - let a_2 := mload(0x5b80) + let f_6 := mload(0x6e20) + let a_2 := mload(0x6b00) let var5 := mulmod(f_6, a_2, r) let var6 := addmod(var4, var5, r) - let f_7 := mload(0x5ec0) - let a_3 := mload(0x5ba0) + let f_7 := mload(0x6e40) + let a_3 := mload(0x6b20) let var7 := mulmod(f_7, a_3, r) let var8 := addmod(var6, var7, r) - let f_8 := mload(0x5ee0) - let a_4 := mload(0x5bc0) + let f_8 := mload(0x6e60) + let a_4 := mload(0x6b40) let var9 := mulmod(f_8, a_4, r) let var10 := addmod(var8, var9, r) - let f_0 := mload(0x5f00) - let a_0_next_1 := mload(0x5be0) + let f_0 := mload(0x6e80) + let a_0_next_1 := mload(0x6b60) let var11 := mulmod(f_0, a_0_next_1, r) let var12 := addmod(var10, var11, r) - let f_1 := mload(0x5f20) + let f_1 := mload(0x6ea0) let var13 := mulmod(f_1, a_0, r) let var14 := mulmod(var13, a_1, r) let var15 := addmod(var12, var14, r) - let f_2 := mload(0x5f40) + let f_2 := mload(0x6ec0) let var16 := mulmod(f_2, a_0, r) let var17 := mulmod(var16, a_2, r) let var18 := addmod(var15, var17, r) let var19 := mulmod(var0, var18, r) - mstore(0x7640, var19) + mstore(0x85c0, var19) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } { let var0 := 0x1 - let a_1 := mload(0x5b60) - let a_2 := mload(0x5b80) + let a_1 := mload(0x6ae0) + let a_2 := mload(0x6b00) let var1 := addmod(a_1, a_2, r) - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var2 := addmod(0, sub(r, a_3), r) let var3 := addmod(var1, var2, r) - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var4 := addmod(0, sub(r, a_4), r) let var5 := addmod(var3, var4, r) let var6 := mulmod(var0, var5, r) - mstore(0x7640, var6) + mstore(0x85c0, var6) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } { let var0 := 0x1 - let a_0 := mload(0x5b40) - let f_4 := mload(0x5e60) + let a_0 := mload(0x6ac0) + let f_4 := mload(0x6de0) let var1 := addmod(a_0, f_4, r) - let a_0_next_1 := mload(0x5be0) + let a_0_next_1 := mload(0x6b60) let var2 := addmod(0, sub(r, a_0_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x7640, var4) + mstore(0x85c0, var4) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } { let var0 := 0x1 - let a_1 := mload(0x5b60) - let f_5 := mload(0x5e80) + let a_1 := mload(0x6ae0) + let f_5 := mload(0x6e00) let var1 := addmod(a_1, f_5, r) - let a_1_next_1 := mload(0x5c00) + let a_1_next_1 := mload(0x6b80) let var2 := addmod(0, sub(r, a_1_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x7640, var4) + mstore(0x85c0, var4) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x7100, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x8080, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } // VM registers: @@ -1561,7 +1604,7 @@ contract Halo2Verifier { // q_end is an exclusive byte pointer for the VM loop. let q_end := add(q_program_mptr, 0x025d) // q_sp starts at the first free stack word. - let q_sp := 0x7640 + let q_sp := 0x85c0 // q_top is meaningless until q_has_top is set. let q_top := 0 // q_has_top = 0 means the VM stack is empty. @@ -1892,70 +1935,70 @@ contract Halo2Verifier { // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := 0x7640 + q_sp := 0x85c0 // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. { let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 - let q_perm_vals := 0x7640 - let q_perm_sigmas := 0x7760 - let q_perm_z_cur := 0x7880 - let q_perm_z_next := 0x78e0 - let q_perm_z_last := 0x7940 - let q_perm_delta_base_ptr := 0x7980 + let q_perm_vals := 0x85c0 + let q_perm_sigmas := 0x86e0 + let q_perm_z_cur := 0x8800 + let q_perm_z_next := 0x8860 + let q_perm_z_last := 0x88c0 + let q_perm_delta_base_ptr := 0x8900 let q_perm_num_cols := 9 let q_perm_num_sets := 3 let q_perm_chunk_len := 3 let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 - mstore(add(q_perm_vals, 0x0), mload(0x5e40)) + mstore(add(q_perm_vals, 0x0), mload(0x6dc0)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x5b40, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x6ac0, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0xc0), mload(0x5b20)) + mstore(add(q_perm_vals, 0xc0), mload(0x6aa0)) mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) - mstore(add(q_perm_vals, 0x100), mload(0x5c40)) + mstore(add(q_perm_vals, 0x100), mload(0x6bc0)) { for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 9) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off - mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x60a0, q_perm_sigma_load_src_off))) + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x7020, q_perm_sigma_load_src_off))) } } { for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 3) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) - mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x61c0, q_perm_z_cur_load_src_off))) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x7140, q_perm_z_cur_load_src_off))) } } { for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 3) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) - mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x61e0, q_perm_z_next_load_src_off))) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x7160, q_perm_z_next_load_src_off))) } } - mstore(add(q_perm_z_last, 0x0), mload(0x6200)) - mstore(add(q_perm_z_last, 0x20), mload(0x6260)) + mstore(add(q_perm_z_last, 0x0), mload(0x7180)) + mstore(add(q_perm_z_last, 0x20), mload(0x71e0)) let q_perm_eval := 0 q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_perm_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_perm_eval, r)) let q_perm_zn := mload(add(q_perm_z_cur, 0x40)) q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_perm_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_perm_eval, r)) for { let q_perm_i := 1 } lt(q_perm_i, 3) { q_perm_i := add(q_perm_i, 1) } { let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_perm_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_perm_eval, r)) } mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) for { let q_perm_set := 0 } lt(q_perm_set, 3) { q_perm_set := add(q_perm_set, 1) } { @@ -1974,8 +2017,8 @@ contract Halo2Verifier { q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) } q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_perm_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_perm_eval, r)) mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) } } @@ -1996,13 +2039,13 @@ contract Halo2Verifier { // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := 0x7640 + q_sp := 0x85c0 // Generated LogUp code follows the same y-batch order // as the Rust identity stream. { - let q_lookup_f := 0x7640 - let q_lookup_prefix := 0x7680 - let q_lookup_suffix := 0x76c0 + let q_lookup_f := 0x85c0 + let q_lookup_prefix := 0x8600 + let q_lookup_suffix := 0x8640 let q_lookup_l0 := mload(L_0_MPTR) let q_lookup_llast := mload(L_LAST_MPTR) let q_lookup_lblind := mload(L_BLIND_MPTR) @@ -2012,54 +2055,54 @@ contract Halo2Verifier { let q_lookup_theta := mload(THETA_MPTR) { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x6300), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x7280), r) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } { - let f_10 := mload(0x5f80) + let f_10 := mload(0x6f00) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_1, r) - let q_lookup_eval := addmod(mulmod(mload(0x62e0), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x7260), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x62e0) - let f_19 := mload(0x6040) - let f_11 := mload(0x5fa0) + let q_lookup_sum_h := mload(0x7260) + let f_19 := mload(0x6fc0) + let f_11 := mload(0x6f20) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) - let f_12 := mload(0x5fc0) + let f_12 := mload(0x6f40) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) let q_lookup_s_sum_h := mulmod(f_19, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x6320), sub(r, addmod(mload(0x6300), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x72a0), sub(r, addmod(mload(0x7280), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x62c0), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x7240), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } } { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x6380), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x7300), r) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } { - let f_0 := mload(0x5f00) + let f_0 := mload(0x6e80) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_0, r) - let a_6 := mload(0x5c60) + let a_6 := mload(0x6be0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_6, r) - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var2 := addmod(mulmod(var1, q_lookup_theta, r), a_0, r) mstore(add(q_lookup_f, 0x0), addmod(var2, q_lookup_beta, r)) - let f_1 := mload(0x5f20) + let f_1 := mload(0x6ea0) let var3 := addmod(mulmod(0, q_lookup_theta, r), f_1, r) - let a_7 := mload(0x5c80) + let a_7 := mload(0x6c00) let var4 := addmod(mulmod(var3, q_lookup_theta, r), a_7, r) - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var5 := addmod(mulmod(var4, q_lookup_theta, r), a_1, r) mstore(add(q_lookup_f, 0x20), addmod(var5, q_lookup_beta, r)) let q_lookup_product := 1 @@ -2080,26 +2123,26 @@ contract Halo2Verifier { for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 2) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) } - let q_lookup_eval := addmod(mulmod(mload(0x6360), q_lookup_product, r), sub(r, q_lookup_sum), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x72e0), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x6360) - let f_20 := mload(0x6060) - let f_13 := mload(0x5fe0) + let q_lookup_sum_h := mload(0x72e0) + let f_20 := mload(0x6fe0) + let f_13 := mload(0x6f60) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_13, r) - let f_14 := mload(0x6000) + let f_14 := mload(0x6f80) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_14, r) - let f_15 := mload(0x6020) + let f_15 := mload(0x6fa0) let var2 := addmod(mulmod(var1, q_lookup_theta, r), f_15, r) let q_lookup_s_sum_h := mulmod(f_20, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x63a0), sub(r, addmod(mload(0x6380), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x7320), sub(r, addmod(mload(0x7300), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var2, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x6340), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x72c0), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_lookup_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_lookup_eval, r)) } } } @@ -2120,24 +2163,24 @@ contract Halo2Verifier { // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := 0x7640 + q_sp := 0x85c0 // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx case 0 { { let var0 := 0x1 let var1 := 0x1000000000000000 - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var2 := mulmod(var1, a_4, r) let var3 := 0x10000000000 - let a_3_prev_1 := mload(0x5ca0) + let a_3_prev_1 := mload(0x6c20) let var4 := mulmod(var3, a_3_prev_1, r) let var5 := addmod(var2, var4, r) let var6 := 0x400000 - let a_4_prev_1 := mload(0x5cc0) + let a_4_prev_1 := mload(0x6c40) let var7 := mulmod(var6, a_4_prev_1, r) let var8 := addmod(var5, var7, r) - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var9 := addmod(var8, a_3, r) let var10 := 0x40000000000 let var11 := mulmod(var10, a_3, r) @@ -2159,54 +2202,54 @@ contract Halo2Verifier { let var27 := addmod(var24, var26, r) let var28 := addmod(var27, a_3_prev_1, r) let var29 := addmod(var19, var28, r) - let a_0_prev_1 := mload(0x5ce0) + let a_0_prev_1 := mload(0x6c60) let var30 := mulmod(var10, a_0_prev_1, r) - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var31 := mulmod(var25, a_0, r) let var32 := addmod(var30, var31, r) - let a_0_next_1 := mload(0x5be0) + let a_0_next_1 := mload(0x6b60) let var33 := addmod(var32, a_0_next_1, r) let var34 := 0x2 - let a_1_prev_1 := mload(0x5d00) + let a_1_prev_1 := mload(0x6c80) let var35 := mulmod(var10, a_1_prev_1, r) - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var36 := mulmod(var25, a_1, r) let var37 := addmod(var35, var36, r) - let a_1_next_1 := mload(0x5c00) + let a_1_next_1 := mload(0x6b80) let var38 := addmod(var37, a_1_next_1, r) let var39 := mulmod(var34, var38, r) let var40 := addmod(var33, var39, r) let var41 := addmod(0, sub(r, var40), r) let var42 := addmod(var29, var41, r) let var43 := mulmod(var0, var42, r) - mstore(0x7640, var43) + mstore(0x85c0, var43) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xa0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } } case 1 { { let var0 := 0x1 let var1 := 0x10000000000000 - let a_3_next_1 := mload(0x5d20) + let a_3_next_1 := mload(0x6ca0) let var2 := mulmod(var1, a_3_next_1, r) let var3 := 0x4000000000 - let a_3_prev_1 := mload(0x5ca0) + let a_3_prev_1 := mload(0x6c20) let var4 := mulmod(var3, a_3_prev_1, r) let var5 := addmod(var2, var4, r) let var6 := 0x4000 - let a_4_prev_1 := mload(0x5cc0) + let a_4_prev_1 := mload(0x6c40) let var7 := mulmod(var6, a_4_prev_1, r) let var8 := addmod(var5, var7, r) let var9 := 0x400 - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var10 := mulmod(var9, a_3, r) let var11 := addmod(var8, var10, r) - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var12 := addmod(var11, a_4, r) let var13 := 0x40000000000000 let var14 := mulmod(var13, a_4, r) @@ -2233,112 +2276,112 @@ contract Halo2Verifier { let var35 := addmod(var33, var34, r) let var36 := addmod(var35, a_3_prev_1, r) let var37 := addmod(var25, var36, r) - let a_0_prev_1 := mload(0x5ce0) + let a_0_prev_1 := mload(0x6c60) let var38 := mulmod(var15, a_0_prev_1, r) let var39 := 0x100000 - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var40 := mulmod(var39, a_0, r) let var41 := addmod(var38, var40, r) - let a_0_next_1 := mload(0x5be0) + let a_0_next_1 := mload(0x6b60) let var42 := addmod(var41, a_0_next_1, r) let var43 := 0x2 - let a_1_prev_1 := mload(0x5d00) + let a_1_prev_1 := mload(0x6c80) let var44 := mulmod(var15, a_1_prev_1, r) - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var45 := mulmod(var39, a_1, r) let var46 := addmod(var44, var45, r) - let a_1_next_1 := mload(0x5c00) + let a_1_next_1 := mload(0x6b80) let var47 := addmod(var46, a_1_next_1, r) let var48 := mulmod(var43, var47, r) let var49 := addmod(var42, var48, r) let var50 := addmod(0, sub(r, var49), r) let var51 := addmod(var37, var50, r) let var52 := mulmod(var0, var51, r) - mstore(0x7640, var52) + mstore(0x85c0, var52) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xc0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } } case 2 { { let var0 := 0x1 - let f_0 := mload(0x5f00) - let a_0_next_1 := mload(0x5be0) + let f_0 := mload(0x6e80) + let a_0_next_1 := mload(0x6b60) let var1 := addmod(0, sub(r, a_0_next_1), r) let var2 := addmod(f_0, var1, r) let var3 := 0x1b8114c381b922fd5d6d241210e2d8a68ad5744053ba9e776118de4107b51ace - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0x3df32e4cc4cb2ed20e5d21899cf5331775990ccaec4c09b4e3717213fcc0d763 - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_2 := mload(0x5b80) + let a_2 := mload(0x6b00) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x5c40) + let a_5 := mload(0x6bc0) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x7640, var18) + mstore(0x85c0, var18) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x1c0) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x7100, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x8080, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } } case 3 { { let var0 := 0x1 - let f_1 := mload(0x5f20) - let a_1_next_1 := mload(0x5c00) + let f_1 := mload(0x6ea0) + let a_1_next_1 := mload(0x6b80) let var1 := addmod(0, sub(r, a_1_next_1), r) let var2 := addmod(f_1, var1, r) let var3 := 0x404d21073985d14e432a4ad76d3fae06ca74314b950fe7b1d7f501cd31a8b374 - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0xb2cc8704264c6bd81bc620e9e524d4b73e9b2317679422ff7fa1603955649f1 - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f - let a_2 := mload(0x5b80) + let a_2 := mload(0x6b00) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x5c40) + let a_5 := mload(0x6bc0) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x7640, var18) + mstore(0x85c0, var18) } - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x1c0) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x7100, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7640), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x8080, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } } default { revert(0, 0) } @@ -2362,14 +2405,14 @@ contract Halo2Verifier { // The global fully-evaluated accumulator is still // multiplied by y so later main identities land at the // same y powers as Rust's reverse fold. - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) let q_sel_acc := mload(q_target_ptr) if q_sel_gap { // Selector buckets are sparse in the global // identity stream. Precomputed y^gap advances only // this selector's local accumulator. - q_sel_acc := mulmod(q_sel_acc, mload(add(0x7100, shl(5, q_sel_gap))), r) + q_sel_acc := mulmod(q_sel_acc, mload(add(0x8080, shl(5, q_sel_gap))), r) } mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) } @@ -2389,7 +2432,7 @@ contract Halo2Verifier { // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x7640)) { revert(0, 0) } + if iszero(eq(q_sp, 0x85c0)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2401,52 +2444,52 @@ contract Halo2Verifier { { let q_trash_tau := mload(TRASH_CHALLENGE_MPTR) { - let f_0 := mload(0x5f00) - let a_0_next_1 := mload(0x5be0) + let f_0 := mload(0x6e80) + let a_0_next_1 := mload(0x6b60) let var0 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000 let var1 := mulmod(a_0_next_1, var0, r) let var2 := addmod(f_0, var1, r) let var3 := 0x590ba402032e82eb1f660ef09796c5686345a5054ed96dae8e2d233633788771 - let a_0 := mload(0x5b40) + let a_0 := mload(0x6ac0) let var4 := mulmod(var3, a_0, r) let var5 := addmod(var2, var4, r) let var6 := 0x52f789e4afc3801f7411102ee2f47cc5954a744e71cac98e75ea962a55a0a76f - let a_1 := mload(0x5b60) + let a_1 := mload(0x6ae0) let var7 := mulmod(var6, a_1, r) let var8 := addmod(var5, var7, r) let var9 := 0x3509dd2fe3aac0080783557fec090fb1cb4b2b0901253c55282024331d1fe1a8 - let a_2 := mload(0x5b80) + let a_2 := mload(0x6b00) let var10 := q_pow5(a_2) let var11 := mulmod(var9, var10, r) let var12 := addmod(var8, var11, r) let var13 := 0x333f8046ece5579cbd6872449c57f2703dfc8864cfadc06d587ff104a0d0c1f2 - let a_3 := mload(0x5ba0) + let a_3 := mload(0x6b20) let var14 := q_pow5(a_3) let var15 := mulmod(var13, var14, r) let var16 := addmod(var12, var15, r) let var17 := 0x412c98232b6ab8a47aa76ee814ef7ec6261987c9802f2cfc490e007951a60ca5 - let a_4 := mload(0x5bc0) + let a_4 := mload(0x6b40) let var18 := q_pow5(a_4) let var19 := mulmod(var17, var18, r) let var20 := addmod(var16, var19, r) let var21 := 0x53fded36d490ba6b05a5d10fd99ffe5456baec6a6a8753199d5ebdc33c99790e - let a_5 := mload(0x5c40) + let a_5 := mload(0x6bc0) let var22 := q_pow5(a_5) let var23 := mulmod(var21, var22, r) let var24 := addmod(var20, var23, r) let var25 := 0x6ccb1c7d87f3c12a2bde4e68ac7f1e8b03481ba15d7f88f9a7f9b8310dd6d34 - let a_6 := mload(0x5c60) + let a_6 := mload(0x6be0) let var26 := q_pow5(a_6) let var27 := mulmod(var25, var26, r) let var28 := addmod(var24, var27, r) let var29 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_7 := mload(0x5c80) + let a_7 := mload(0x6c00) let var30 := q_pow5(a_7) let var31 := mulmod(var29, var30, r) let var32 := addmod(var28, var31, r) let var33 := addmod(mulmod(0, q_trash_tau, r), var32, r) - let f_1 := mload(0x5f20) - let a_1_next_1 := mload(0x5c00) + let f_1 := mload(0x6ea0) + let a_1_next_1 := mload(0x6b80) let var34 := mulmod(a_1_next_1, var0, r) let var35 := addmod(f_1, var34, r) let var36 := 0x5b1fc262a28cbb8bf75d9b1a6edaa74591ec24cd9a209512213cec3a3c0f1a5d @@ -2474,7 +2517,7 @@ contract Halo2Verifier { let var58 := mulmod(var57, var30, r) let var59 := addmod(var56, var58, r) let var60 := addmod(mulmod(var33, q_trash_tau, r), var59, r) - let f_2 := mload(0x5f40) + let f_2 := mload(0x6ec0) let var61 := mulmod(a_3, var0, r) let var62 := addmod(f_2, var61, r) let var63 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 @@ -2487,7 +2530,7 @@ contract Halo2Verifier { let var70 := mulmod(var69, var10, r) let var71 := addmod(var68, var70, r) let var72 := addmod(mulmod(var60, q_trash_tau, r), var71, r) - let f_3 := mload(0x5f60) + let f_3 := mload(0x6ee0) let var73 := mulmod(a_4, var0, r) let var74 := addmod(f_3, var73, r) let var75 := 0x222e83e70453dfee19b402e9fa8dfe2c4987b034d0be3ceb478b3022e97934c1 @@ -2502,7 +2545,7 @@ contract Halo2Verifier { let var84 := mulmod(var69, var14, r) let var85 := addmod(var83, var84, r) let var86 := addmod(mulmod(var72, q_trash_tau, r), var85, r) - let f_4 := mload(0x5e60) + let f_4 := mload(0x6de0) let var87 := mulmod(a_5, var0, r) let var88 := addmod(f_4, var87, r) let var89 := 0x726df1506749848155630b86ae25a82b281ecd050fe3a52d85a181fa87202e4b @@ -2519,7 +2562,7 @@ contract Halo2Verifier { let var100 := mulmod(var69, var18, r) let var101 := addmod(var99, var100, r) let var102 := addmod(mulmod(var86, q_trash_tau, r), var101, r) - let f_5 := mload(0x5e80) + let f_5 := mload(0x6e00) let var103 := mulmod(a_6, var0, r) let var104 := addmod(f_5, var103, r) let var105 := 0x2f5908b169c6cf1bd26dcf0f9e5105481f5164f3ece0582bf3098312167751a7 @@ -2538,7 +2581,7 @@ contract Halo2Verifier { let var118 := mulmod(var69, var22, r) let var119 := addmod(var117, var118, r) let var120 := addmod(mulmod(var102, q_trash_tau, r), var119, r) - let f_6 := mload(0x5ea0) + let f_6 := mload(0x6e20) let var121 := mulmod(a_7, var0, r) let var122 := addmod(f_6, var121, r) let var123 := 0x6d05a41959f539a7fc9ec0972ea1e3dbb6fc67dd51daf3414f7fbbb091c7274a @@ -2559,8 +2602,8 @@ contract Halo2Verifier { let var138 := mulmod(var69, var26, r) let var139 := addmod(var137, var138, r) let var140 := addmod(mulmod(var120, q_trash_tau, r), var139, r) - let f_7 := mload(0x5ec0) - let a_2_next_1 := mload(0x5c20) + let f_7 := mload(0x6e40) + let a_2_next_1 := mload(0x6ba0) let var141 := mulmod(a_2_next_1, var0, r) let var142 := addmod(f_7, var141, r) let var143 := 0x70d8f2a733a64d650faccc9b1c2a766a9544bb3ff1a11ee73cb43947ef386633 @@ -2583,12 +2626,12 @@ contract Halo2Verifier { let var160 := mulmod(var69, var30, r) let var161 := addmod(var159, var160, r) let var162 := addmod(mulmod(var140, q_trash_tau, r), var161, r) - let f_33 := mload(0x6080) + let f_33 := mload(0x7000) let q_trash_one_minus_selector := addmod(1, sub(r, f_33), r) - let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0x63c0), r) + let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0x7340), r) let q_trash_eval := addmod(var162, sub(r, q_trash_scaled), r) - mstore(0x70c0, mulmod(mload(0x70c0), y, r)) - mstore(0x70c0, addmod(mload(0x70c0), q_trash_eval, r)) + mstore(0x8040, mulmod(mload(0x8040), y, r)) + mstore(0x8040, addmod(mload(0x8040), q_trash_eval, r)) } } // Finish selector buckets by applying the codegen-known tail @@ -2600,69 +2643,69 @@ contract Halo2Verifier { // selector commitment in the linearized MSM. { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0520)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0520)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0500)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0500)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x04a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x04a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0480)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0480)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x80) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0440)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0440)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xa0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0420)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0420)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xc0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0400)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0400)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xe0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x03e0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x03e0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0100) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x03c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x03c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0120) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x03a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x03a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0140) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0360)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0360)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0160) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0320)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0320)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0180) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x02a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x02a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x01a0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x0280)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x0280)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x01c0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7100, 0x01c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x8080, 0x01c0)), r)) } // Fully evaluated identities are the constant-polynomial side // of the linearization query. Rust subtracts that grouped // scalar into expected_eval, so Solidity stores -nu_y(x). - let linearization_expected_eval := addmod(0, sub(r, mload(0x70c0)), r) + let linearization_expected_eval := addmod(0, sub(r, mload(0x8040)), r) mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) pop(y) } @@ -2766,44 +2809,44 @@ contract Halo2Verifier { { // q_eval_set[0]: 35 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x70c0, 0x5b20) - mstore(0x70e0, 0x62c0) - mstore(0x7100, 0x62e0) - mstore(0x7120, 0x6340) - mstore(0x7140, 0x6360) - mstore(0x7160, 0x63c0) - mstore(0x7180, 0x5e40) - mstore(0x71a0, 0x5e60) - mstore(0x71c0, 0x5e80) - mstore(0x71e0, 0x5ea0) - mstore(0x7200, 0x5ec0) - mstore(0x7220, 0x5ee0) - mstore(0x7240, 0x5f00) - mstore(0x7260, 0x5f20) - mstore(0x7280, 0x5f40) - mstore(0x72a0, 0x5f60) - mstore(0x72c0, 0x5f80) - mstore(0x72e0, 0x5fa0) - mstore(0x7300, 0x5fc0) - mstore(0x7320, 0x5fe0) - mstore(0x7340, 0x6000) - mstore(0x7360, 0x6020) - mstore(0x7380, 0x6040) - mstore(0x73a0, 0x6060) - mstore(0x73c0, 0x6080) - mstore(0x73e0, 0x60a0) - mstore(0x7400, 0x60c0) - mstore(0x7420, 0x60e0) - mstore(0x7440, 0x6100) - mstore(0x7460, 0x6120) - mstore(0x7480, 0x6140) - mstore(0x74a0, 0x6160) - mstore(0x74c0, 0x6180) - mstore(0x74e0, 0x61a0) - mstore(0x7500, QUOTIENT_EVAL_MPTR) - let q_eval_set_0 := mload(0x5b20) + mstore(0x8040, 0x6aa0) + mstore(0x8060, 0x7240) + mstore(0x8080, 0x7260) + mstore(0x80a0, 0x72c0) + mstore(0x80c0, 0x72e0) + mstore(0x80e0, 0x7340) + mstore(0x8100, 0x6dc0) + mstore(0x8120, 0x6de0) + mstore(0x8140, 0x6e00) + mstore(0x8160, 0x6e20) + mstore(0x8180, 0x6e40) + mstore(0x81a0, 0x6e60) + mstore(0x81c0, 0x6e80) + mstore(0x81e0, 0x6ea0) + mstore(0x8200, 0x6ec0) + mstore(0x8220, 0x6ee0) + mstore(0x8240, 0x6f00) + mstore(0x8260, 0x6f20) + mstore(0x8280, 0x6f40) + mstore(0x82a0, 0x6f60) + mstore(0x82c0, 0x6f80) + mstore(0x82e0, 0x6fa0) + mstore(0x8300, 0x6fc0) + mstore(0x8320, 0x6fe0) + mstore(0x8340, 0x7000) + mstore(0x8360, 0x7020) + mstore(0x8380, 0x7040) + mstore(0x83a0, 0x7060) + mstore(0x83c0, 0x7080) + mstore(0x83e0, 0x70a0) + mstore(0x8400, 0x70c0) + mstore(0x8420, 0x70e0) + mstore(0x8440, 0x7100) + mstore(0x8460, 0x7120) + mstore(0x8480, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x6aa0) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x70c0, 0x20) + let eval_p := add(0x8040, 0x20) for { let i := 1 } lt(i, 0x23) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2817,12 +2860,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[1]: 3 commitment(s) - let q_eval_set_0 := mload(0x6280) - let q_eval_set_1 := mload(0x62a0) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6300), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6320), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6380), mload(add(X1_POWERS_MPTR, 0x40)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x63a0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + let q_eval_set_0 := mload(0x7200) + let q_eval_set_1 := mload(0x7220) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x7280), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x72a0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x7300), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x7320), mload(add(X1_POWERS_MPTR, 0x40)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) } @@ -2832,35 +2875,35 @@ contract Halo2Verifier { { // q_eval_set[2]: 8 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x70c0, 0x5b40) - mstore(0x70e0, 0x5be0) - mstore(0x7100, 0x5ce0) - mstore(0x7120, 0x5b60) - mstore(0x7140, 0x5c00) - mstore(0x7160, 0x5d00) - mstore(0x7180, 0x5b80) - mstore(0x71a0, 0x5c20) - mstore(0x71c0, 0x5da0) - mstore(0x71e0, 0x5ba0) - mstore(0x7200, 0x5d20) - mstore(0x7220, 0x5ca0) - mstore(0x7240, 0x5bc0) - mstore(0x7260, 0x5d40) - mstore(0x7280, 0x5cc0) - mstore(0x72a0, 0x5c40) - mstore(0x72c0, 0x5e00) - mstore(0x72e0, 0x5de0) - mstore(0x7300, 0x5c60) - mstore(0x7320, 0x5d80) - mstore(0x7340, 0x5d60) - mstore(0x7360, 0x5c80) - mstore(0x7380, 0x5e20) - mstore(0x73a0, 0x5dc0) - let q_eval_set_0 := mload(0x5b40) - let q_eval_set_1 := mload(0x5be0) - let q_eval_set_2 := mload(0x5ce0) + mstore(0x8040, 0x6ac0) + mstore(0x8060, 0x6b60) + mstore(0x8080, 0x6c60) + mstore(0x80a0, 0x6ae0) + mstore(0x80c0, 0x6b80) + mstore(0x80e0, 0x6c80) + mstore(0x8100, 0x6b00) + mstore(0x8120, 0x6ba0) + mstore(0x8140, 0x6d20) + mstore(0x8160, 0x6b20) + mstore(0x8180, 0x6ca0) + mstore(0x81a0, 0x6c20) + mstore(0x81c0, 0x6b40) + mstore(0x81e0, 0x6cc0) + mstore(0x8200, 0x6c40) + mstore(0x8220, 0x6bc0) + mstore(0x8240, 0x6d80) + mstore(0x8260, 0x6d60) + mstore(0x8280, 0x6be0) + mstore(0x82a0, 0x6d00) + mstore(0x82c0, 0x6ce0) + mstore(0x82e0, 0x6c00) + mstore(0x8300, 0x6da0) + mstore(0x8320, 0x6d40) + let q_eval_set_0 := mload(0x6ac0) + let q_eval_set_1 := mload(0x6b60) + let q_eval_set_2 := mload(0x6c60) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x70c0, 0x60) + let eval_p := add(0x8040, 0x60) for { let i := 1 } lt(i, 0x8) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2878,12 +2921,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[3]: 2 commitment(s) - let q_eval_set_0 := mload(0x61c0) - let q_eval_set_1 := mload(0x61e0) - let q_eval_set_2 := mload(0x6200) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6220), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6240), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x6260), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + let q_eval_set_0 := mload(0x7140) + let q_eval_set_1 := mload(0x7160) + let q_eval_set_2 := mload(0x7180) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x71a0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x71c0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x71e0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0x100), q_eval_set_2) @@ -3051,145 +3094,145 @@ contract Halo2Verifier { v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), x4_pow_3, r), r) v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_4, r), r) - mcopy(0x70c0, 0x67e0, 0x80) - mstore(0x7140, mload(add(X1_POWERS_MPTR, 0x20))) - mcopy(0x7160, 0x6a60, 0x80) - mstore(0x71e0, mload(add(X1_POWERS_MPTR, 0x40))) - mcopy(0x7200, 0x6860, 0x80) - mstore(0x7280, mload(add(X1_POWERS_MPTR, 0x60))) - mcopy(0x72a0, 0x6ae0, 0x80) - mstore(0x7320, mload(add(X1_POWERS_MPTR, 0x80))) - mcopy(0x7340, 0x6c60, 0x80) - mstore(0x73c0, mload(add(X1_POWERS_MPTR, 0xa0))) - mcopy(0x73e0, 0x2ea0, 0x80) - mstore(0x7460, mload(add(X1_POWERS_MPTR, 0xc0))) - mcopy(0x7480, 0x2c20, 0x80) - mstore(0x7500, mload(add(X1_POWERS_MPTR, 0xe0))) - mcopy(0x7520, 0x2ca0, 0x80) - mstore(0x75a0, mload(add(X1_POWERS_MPTR, 0x100))) - mcopy(0x75c0, 0x2d20, 0x80) - mstore(0x7640, mload(add(X1_POWERS_MPTR, 0x120))) - mcopy(0x7660, 0x2da0, 0x80) - mstore(0x76e0, mload(add(X1_POWERS_MPTR, 0x140))) - mcopy(0x7700, 0x2e20, 0x80) - mstore(0x7780, mload(add(X1_POWERS_MPTR, 0x160))) - mcopy(0x77a0, 0x2a20, 0x80) - mstore(0x7820, mload(add(X1_POWERS_MPTR, 0x180))) - mcopy(0x7840, 0x2aa0, 0x80) - mstore(0x78c0, mload(add(X1_POWERS_MPTR, 0x1a0))) - mcopy(0x78e0, 0x2b20, 0x80) - mstore(0x7960, mload(add(X1_POWERS_MPTR, 0x1c0))) - mcopy(0x7980, 0x2ba0, 0x80) - mstore(0x7a00, mload(add(X1_POWERS_MPTR, 0x1e0))) - mcopy(0x7a20, 0x2f20, 0x80) - mstore(0x7aa0, mload(add(X1_POWERS_MPTR, 0x200))) - mcopy(0x7ac0, 0x2fa0, 0x80) - mstore(0x7b40, mload(add(X1_POWERS_MPTR, 0x220))) - mcopy(0x7b60, 0x3020, 0x80) - mstore(0x7be0, mload(add(X1_POWERS_MPTR, 0x240))) - mcopy(0x7c00, 0x30a0, 0x80) - mstore(0x7c80, mload(add(X1_POWERS_MPTR, 0x260))) - mcopy(0x7ca0, 0x3120, 0x80) - mstore(0x7d20, mload(add(X1_POWERS_MPTR, 0x280))) - mcopy(0x7d40, 0x31a0, 0x80) - mstore(0x7dc0, mload(add(X1_POWERS_MPTR, 0x2a0))) - mcopy(0x7de0, 0x33a0, 0x80) - mstore(0x7e60, mload(add(X1_POWERS_MPTR, 0x2c0))) - mcopy(0x7e80, 0x3420, 0x80) - mstore(0x7f00, mload(add(X1_POWERS_MPTR, 0x2e0))) - mcopy(0x7f20, 0x3aa0, 0x80) - mstore(0x7fa0, mload(add(X1_POWERS_MPTR, 0x300))) - mcopy(0x7fc0, 0x3b20, 0x80) - mstore(0x8040, mload(add(X1_POWERS_MPTR, 0x320))) - mcopy(0x8060, 0x3ba0, 0x80) - mstore(0x80e0, mload(add(X1_POWERS_MPTR, 0x340))) - mcopy(0x8100, 0x3c20, 0x80) - mstore(0x8180, mload(add(X1_POWERS_MPTR, 0x360))) - mcopy(0x81a0, 0x3ca0, 0x80) - mstore(0x8220, mload(add(X1_POWERS_MPTR, 0x380))) - mcopy(0x8240, 0x3d20, 0x80) - mstore(0x82c0, mload(add(X1_POWERS_MPTR, 0x3a0))) - mcopy(0x82e0, 0x3da0, 0x80) - mstore(0x8360, mload(add(X1_POWERS_MPTR, 0x3c0))) - mcopy(0x8380, 0x3e20, 0x80) - mstore(0x8400, mload(add(X1_POWERS_MPTR, 0x3e0))) - mcopy(0x8420, 0x3ea0, 0x80) - mstore(0x84a0, mload(add(X1_POWERS_MPTR, 0x400))) - mcopy(0x84c0, 0x3f20, 0x80) - mstore(0x8540, mload(add(X1_POWERS_MPTR, 0x420))) + mcopy(0x8040, 0x7760, 0x80) + mstore(0x80c0, mload(add(X1_POWERS_MPTR, 0x20))) + mcopy(0x80e0, 0x79e0, 0x80) + mstore(0x8160, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0x8180, 0x77e0, 0x80) + mstore(0x8200, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0x8220, 0x7a60, 0x80) + mstore(0x82a0, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0x82c0, 0x7be0, 0x80) + mstore(0x8340, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0x8360, 0x3e20, 0x80) + mstore(0x83e0, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0x8400, 0x3ba0, 0x80) + mstore(0x8480, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0x84a0, 0x3c20, 0x80) + mstore(0x8520, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0x8540, 0x3ca0, 0x80) + mstore(0x85c0, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0x85e0, 0x3d20, 0x80) + mstore(0x8660, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0x8680, 0x3da0, 0x80) + mstore(0x8700, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0x8720, 0x39a0, 0x80) + mstore(0x87a0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0x87c0, 0x3a20, 0x80) + mstore(0x8840, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0x8860, 0x3aa0, 0x80) + mstore(0x88e0, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0x8900, 0x3b20, 0x80) + mstore(0x8980, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0x89a0, 0x3ea0, 0x80) + mstore(0x8a20, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0x8a40, 0x3f20, 0x80) + mstore(0x8ac0, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0x8ae0, 0x3fa0, 0x80) + mstore(0x8b60, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0x8b80, 0x4020, 0x80) + mstore(0x8c00, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0x8c20, 0x40a0, 0x80) + mstore(0x8ca0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0x8cc0, 0x4120, 0x80) + mstore(0x8d40, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0x8d60, 0x4320, 0x80) + mstore(0x8de0, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0x8e00, 0x43a0, 0x80) + mstore(0x8e80, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0x8ea0, 0x4a20, 0x80) + mstore(0x8f20, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0x8f40, 0x4aa0, 0x80) + mstore(0x8fc0, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0x8fe0, 0x4b20, 0x80) + mstore(0x9060, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0x9080, 0x4ba0, 0x80) + mstore(0x9100, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0x9120, 0x4c20, 0x80) + mstore(0x91a0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0x91c0, 0x4ca0, 0x80) + mstore(0x9240, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0x9260, 0x4d20, 0x80) + mstore(0x92e0, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0x9300, 0x4da0, 0x80) + mstore(0x9380, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0x93a0, 0x4e20, 0x80) + mstore(0x9420, mload(add(X1_POWERS_MPTR, 0x400))) + mcopy(0x9440, 0x4ea0, 0x80) + mstore(0x94c0, mload(add(X1_POWERS_MPTR, 0x420))) let lin_query_scalar_33 := mload(add(X1_POWERS_MPTR, 0x440)) let lin_cur_scalar_33 := mulmod(lin_query_scalar_33, lin_one_minus_x_n, r) - mcopy(0x8560, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) - mstore(0x85e0, lin_cur_scalar_33) + mcopy(0x94e0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0x9560, lin_cur_scalar_33) lin_cur_scalar_33 := mulmod(lin_cur_scalar_33, lin_x_split, r) - mcopy(0x8600, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) - mstore(0x8680, lin_cur_scalar_33) + mcopy(0x9580, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0x9600, lin_cur_scalar_33) lin_cur_scalar_33 := mulmod(lin_cur_scalar_33, lin_x_split, r) - mcopy(0x86a0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) - mstore(0x8720, lin_cur_scalar_33) + mcopy(0x9620, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0x96a0, lin_cur_scalar_33) lin_cur_scalar_33 := mulmod(lin_cur_scalar_33, lin_x_split, r) - mcopy(0x8740, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) - mstore(0x87c0, lin_cur_scalar_33) - mcopy(0x87e0, 0x3220, 0x80) - mstore(0x8860, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) - mcopy(0x8880, 0x32a0, 0x80) - mstore(0x8900, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) - mcopy(0x8920, 0x3320, 0x80) - mstore(0x89a0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) - mcopy(0x89c0, 0x34a0, 0x80) - mstore(0x8a40, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) - mcopy(0x8a60, 0x3520, 0x80) - mstore(0x8ae0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) - mcopy(0x8b00, 0x35a0, 0x80) - mstore(0x8b80, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) - mcopy(0x8ba0, 0x3620, 0x80) - mstore(0x8c20, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) - mcopy(0x8c40, 0x36a0, 0x80) - mstore(0x8cc0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) - mcopy(0x8ce0, 0x3720, 0x80) - mstore(0x8d60, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) - mcopy(0x8d80, 0x37a0, 0x80) - mstore(0x8e00, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) - mcopy(0x8e20, 0x3820, 0x80) - mstore(0x8ea0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x140)), r)) - mcopy(0x8ec0, 0x38a0, 0x80) - mstore(0x8f40, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x160)), r)) - mcopy(0x8f60, 0x3920, 0x80) - mstore(0x8fe0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x180)), r)) - mcopy(0x9000, 0x39a0, 0x80) - mstore(0x9080, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x1a0)), r)) - mcopy(0x90a0, 0x3a20, 0x80) - mstore(0x9120, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x1c0)), r)) - mcopy(0x9140, 0x69e0, 0x80) - mstore(0x91c0, x4_pow_1) - mcopy(0x91e0, 0x6b60, 0x80) - mstore(0x9260, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) - mcopy(0x9280, 0x6be0, 0x80) - mstore(0x9300, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) - mcopy(0x9320, 0x63e0, 0x80) - mstore(0x93a0, x4_pow_2) - mcopy(0x93c0, 0x6460, 0x80) - mstore(0x9440, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) - mcopy(0x9460, 0x64e0, 0x80) - mstore(0x94e0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) - mcopy(0x9500, 0x6560, 0x80) - mstore(0x9580, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_2, r)) - mcopy(0x95a0, 0x65e0, 0x80) - mstore(0x9620, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_2, r)) - mcopy(0x9640, 0x6660, 0x80) - mstore(0x96c0, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_2, r)) - mcopy(0x96e0, 0x66e0, 0x80) - mstore(0x9760, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_2, r)) - mcopy(0x9780, 0x6760, 0x80) - mstore(0x9800, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_2, r)) - mcopy(0x9820, 0x68e0, 0x80) - mstore(0x98a0, x4_pow_3) - mcopy(0x98c0, 0x6960, 0x80) - mstore(0x9940, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) - mcopy(0x9960, F_COM_MPTR, 0x80) - mstore(0x99e0, x4_pow_4) + mcopy(0x96c0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0x9740, lin_cur_scalar_33) + mcopy(0x9760, 0x41a0, 0x80) + mstore(0x97e0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0x9800, 0x4220, 0x80) + mstore(0x9880, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0x98a0, 0x42a0, 0x80) + mstore(0x9920, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0x9940, 0x4420, 0x80) + mstore(0x99c0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0x99e0, 0x44a0, 0x80) + mstore(0x9a60, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) + mcopy(0x9a80, 0x4520, 0x80) + mstore(0x9b00, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) + mcopy(0x9b20, 0x45a0, 0x80) + mstore(0x9ba0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) + mcopy(0x9bc0, 0x4620, 0x80) + mstore(0x9c40, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) + mcopy(0x9c60, 0x46a0, 0x80) + mstore(0x9ce0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) + mcopy(0x9d00, 0x4720, 0x80) + mstore(0x9d80, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) + mcopy(0x9da0, 0x47a0, 0x80) + mstore(0x9e20, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x140)), r)) + mcopy(0x9e40, 0x4820, 0x80) + mstore(0x9ec0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x160)), r)) + mcopy(0x9ee0, 0x48a0, 0x80) + mstore(0x9f60, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x180)), r)) + mcopy(0x9f80, 0x4920, 0x80) + mstore(0xa000, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x1a0)), r)) + mcopy(0xa020, 0x49a0, 0x80) + mstore(0xa0a0, mulmod(lin_query_scalar_33, mload(add(SELECTOR_ACC_MPTR, 0x1c0)), r)) + mcopy(0xa0c0, 0x7960, 0x80) + mstore(0xa140, x4_pow_1) + mcopy(0xa160, 0x7ae0, 0x80) + mstore(0xa1e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0xa200, 0x7b60, 0x80) + mstore(0xa280, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0xa2a0, 0x7360, 0x80) + mstore(0xa320, x4_pow_2) + mcopy(0xa340, 0x73e0, 0x80) + mstore(0xa3c0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0xa3e0, 0x7460, 0x80) + mstore(0xa460, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) + mcopy(0xa480, 0x74e0, 0x80) + mstore(0xa500, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_2, r)) + mcopy(0xa520, 0x7560, 0x80) + mstore(0xa5a0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_2, r)) + mcopy(0xa5c0, 0x75e0, 0x80) + mstore(0xa640, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_2, r)) + mcopy(0xa660, 0x7660, 0x80) + mstore(0xa6e0, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_2, r)) + mcopy(0xa700, 0x76e0, 0x80) + mstore(0xa780, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_2, r)) + mcopy(0xa7a0, 0x7860, 0x80) + mstore(0xa820, x4_pow_3) + mcopy(0xa840, 0x78e0, 0x80) + mstore(0xa8c0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) + mcopy(0xa8e0, F_COM_MPTR, 0x80) + mstore(0xa960, x4_pow_4) if success { - success := staticcall(gas(), 0x0c, 0x70c0, 0x2940, FINAL_COM_MPTR, 0x80) + success := staticcall(gas(), 0x0c, 0x8040, 0x2940, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -3201,28 +3244,28 @@ contract Halo2Verifier { // Scale z*pi - vG before the final pairing check // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) - mcopy(0x80, G1_BASE_MPTR, 0x80) - mstore(0x100, addmod(0, sub(r, mload(V_MPTR)), r)) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x80, 0xa0, 0x80, 0x80) + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, FINAL_COM_MPTR, 0x80) + mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, PI_MPTR, 0x80) - mstore(0x180, mload(X3_MPTR)) + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x100, 0xa0, 0x100, 0x80) + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(PAIRING_RHS_MPTR, 0x80, 0x80) + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol index 986773183..fcfb39dad 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol @@ -141,25 +141,25 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x0980), 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140) // quotient_const mstore(add(payload, 0x09a0), 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a) // quotient_const mstore(add(payload, 0x09c0), 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db) // quotient_const - mstore(add(payload, 0x09e0), 0x055b80105ea0055c2008060d000b020001055ca0105cc0105ba00902115d0013) // quotient_program - mstore(add(payload, 0x0a00), 0x5b6001105c000902115ce0135b4001105be00d030608060d000b030000055ca0) // quotient_program - mstore(add(payload, 0x0a20), 0x105cc00902115d00135b6001105c000902115ce0135b4001105be00d03060806) // quotient_program - mstore(add(payload, 0x0a40), 0x0d000b040000055b80105ba0055bc008060d000b0400011b00001b0001210001) // quotient_program - mstore(add(payload, 0x0a60), 0x00000700045b40055b60065b80075ba0085bc0095be00a5c000b5c200c5ca00d) // quotient_program - mstore(add(payload, 0x0a80), 0x5cc00e5ce00f5d00105d20115d400b07000021000100000700045b40055b6012) // quotient_program - mstore(add(payload, 0x0aa0), 0x5b80135ba0145bc0095be00a5c00155c20165ca0175cc00e5ce00f5d00185d20) // quotient_program - mstore(add(payload, 0x0ac0), 0x195d400b080000091b115d60135c601a105d80055da008060d000b090000091e) // quotient_program - mstore(add(payload, 0x0ae0), 0x115d60135dc01d135c601c105c80055da008060d000b0a00000921115ce0135d) // quotient_program - mstore(add(payload, 0x0b00), 0x0020135b401f105b60055b8008060d000b0a00010924115d60135dc01d135c60) // quotient_program - mstore(add(payload, 0x0b20), 0x23135c8022105d80055da008060d000b0b00000926115ce0135d0020135b401e) // quotient_program - mstore(add(payload, 0x0b40), 0x135b6025105be0055b8008060d000b0b00011c275c40285c60295c80015d601a) // quotient_program - mstore(add(payload, 0x0b60), 0x5dc02a5de02b5e00105d80055da008060d000b0c0000090008105de0115de00d) // quotient_program - mstore(add(payload, 0x0b80), 0x000b0c0001090008105c40115c400d000b0c0001090008105e00115e000d000b) // quotient_program - mstore(add(payload, 0x0ba0), 0x0c00011c005ba0005bc0005c20005ca0005cc0005d20005d40055da0135e202c) // quotient_program - mstore(add(payload, 0x0bc0), 0x08060d000b0d0000055b40115b40115b40055ba008060d000b0e0000055b6011) // quotient_program - mstore(add(payload, 0x0be0), 0x5b60115b60055bc008060d000b0e0001055b80115b80115b80055c4008060d00) // quotient_program - mstore(add(payload, 0x0c00), 0x0b0e00011b00021b0003055c2008105f40055b40115b40115ba00d2d06055b60) // quotient_program - mstore(add(payload, 0x0c20), 0x115b60115bc00d2e06055b80115b80115c400d2f060d000b0e0001191f000000) // quotient_program + mstore(add(payload, 0x09e0), 0x056b00106e20056ba008060d000b020001056c20106c40106b200902116c8013) // quotient_program + mstore(add(payload, 0x0a00), 0x6ae001106b800902116c60136ac001106b600d030608060d000b030000056c20) // quotient_program + mstore(add(payload, 0x0a20), 0x106c400902116c80136ae001106b800902116c60136ac001106b600d03060806) // quotient_program + mstore(add(payload, 0x0a40), 0x0d000b040000056b00106b20056b4008060d000b0400011b00001b0001210001) // quotient_program + mstore(add(payload, 0x0a60), 0x00000700046ac0056ae0066b00076b20086b40096b600a6b800b6ba00c6c200d) // quotient_program + mstore(add(payload, 0x0a80), 0x6c400e6c600f6c80106ca0116cc00b07000021000100000700046ac0056ae012) // quotient_program + mstore(add(payload, 0x0aa0), 0x6b00136b20146b40096b600a6b80156ba0166c20176c400e6c600f6c80186ca0) // quotient_program + mstore(add(payload, 0x0ac0), 0x196cc00b080000091b116ce0136be01a106d00056d2008060d000b090000091e) // quotient_program + mstore(add(payload, 0x0ae0), 0x116ce0136d401d136be01c106c00056d2008060d000b0a00000921116c60136c) // quotient_program + mstore(add(payload, 0x0b00), 0x8020136ac01f106ae0056b0008060d000b0a00010924116ce0136d401d136be0) // quotient_program + mstore(add(payload, 0x0b20), 0x23136c0022106d00056d2008060d000b0b00000926116c60136c8020136ac01e) // quotient_program + mstore(add(payload, 0x0b40), 0x136ae025106b60056b0008060d000b0b00011c276bc0286be0296c00016ce01a) // quotient_program + mstore(add(payload, 0x0b60), 0x6d402a6d602b6d80106d00056d2008060d000b0c0000090008106d60116d600d) // quotient_program + mstore(add(payload, 0x0b80), 0x000b0c0001090008106bc0116bc00d000b0c0001090008106d80116d800d000b) // quotient_program + mstore(add(payload, 0x0ba0), 0x0c00011c006b20006b40006ba0006c20006c40006ca0006cc0056d20136da02c) // quotient_program + mstore(add(payload, 0x0bc0), 0x08060d000b0d0000056ac0116ac0116ac0056b2008060d000b0e0000056ae011) // quotient_program + mstore(add(payload, 0x0be0), 0x6ae0116ae0056b4008060d000b0e0001056b00116b00116b00056bc008060d00) // quotient_program + mstore(add(payload, 0x0c00), 0x0b0e00011b00021b0003056ba008106ec0056ac0116ac0116b200d2d06056ae0) // quotient_program + mstore(add(payload, 0x0c20), 0x116ae0116b400d2e06056b00116b00116bc00d2f060d000b0e0001191f000000) // quotient_program // Fixed-column commitment 0, stored as one // EIP-2537 padded uncompressed G1 slot. mstore(add(payload, 0x0c40), 0x0000000000000000000000000000000002586b66bd923976cc5f5c9ff774e3c2) // fixed_comms[0].x_hi diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol index 6e74608d2..c2bc6699d 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol @@ -47,53 +47,53 @@ contract Halo2QuotientEvaluator { // Start of the copied verifier-key payload in memory. The VK payload also // carries the compact quotient VM constant/program tables used by the // included numerator block. - uint256 internal constant VK_MPTR = 0x2700; + uint256 internal constant VK_MPTR = 0x3680; // Fiat-Shamir challenge slots. Halo2Verifier sampled these in transcript // order before the external call. The evaluator only reads them. - uint256 internal constant CHALLENGE_MPTR = 0x6980; - uint256 internal constant THETA_MPTR = 0x6980; - uint256 internal constant BETA_MPTR = 0x69a0; - uint256 internal constant GAMMA_MPTR = 0x69c0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x69e0; - uint256 internal constant Y_MPTR = 0x6a00; - uint256 internal constant X_MPTR = 0x6a20; - uint256 internal constant X1_MPTR = 0x6a40; - uint256 internal constant X2_MPTR = 0x6a60; - uint256 internal constant X3_MPTR = 0x6a80; - uint256 internal constant X4_MPTR = 0x6aa0; + uint256 internal constant CHALLENGE_MPTR = 0x7900; + uint256 internal constant THETA_MPTR = 0x7900; + uint256 internal constant BETA_MPTR = 0x7920; + uint256 internal constant GAMMA_MPTR = 0x7940; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x7960; + uint256 internal constant Y_MPTR = 0x7980; + uint256 internal constant X_MPTR = 0x79a0; + uint256 internal constant X1_MPTR = 0x79c0; + uint256 internal constant X2_MPTR = 0x79e0; + uint256 internal constant X3_MPTR = 0x7a00; + uint256 internal constant X4_MPTR = 0x7a20; // Common polynomial values at x. Halo2Verifier computes these once after // sampling x and places them in the frame so the numerator block can share // the exact Rust verifier inputs. - uint256 internal constant X_N_MPTR = 0x6cc0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x6ce0; - uint256 internal constant L_LAST_MPTR = 0x6d00; - uint256 internal constant L_BLIND_MPTR = 0x6d20; - uint256 internal constant L_0_MPTR = 0x6d40; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x6d60; - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x6d80; + uint256 internal constant X_N_MPTR = 0x7c40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x7c60; + uint256 internal constant L_LAST_MPTR = 0x7c80; + uint256 internal constant L_BLIND_MPTR = 0x7ca0; + uint256 internal constant L_0_MPTR = 0x7cc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x7ce0; + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x7d00; // Proof evaluation table. Values are already decoded as canonical Fr words // by Halo2Verifier. The generated numerator code indexes this table by the // same query order as the Rust verifier. - uint256 internal constant REVERSED_EVALS_MPTR = 0x8500; + uint256 internal constant REVERSED_EVALS_MPTR = 0x9480; // Scratch/output region for simple-selector linearization accumulators. // The numerator block writes one bucket per simple selector, then the // fallback copies those buckets into the compact return frame. - uint256 internal constant SELECTOR_ACC_MPTR = 0xa1c0; + uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; // Callee-local scratch for trace hooks. Trace-enabled verifier builds call // this evaluator with CALL so quotient identity logs can be compared with // the native Rust trace. Production verifier builds keep using STATICCALL // and render this evaluator without trace hooks. - uint256 internal constant TRACE_U256_MPTR = 0x80; - uint256 internal constant QUOTIENT_OUTPUT_MPTR = 0x80; + uint256 internal constant TRACE_U256_MPTR = 0x1000; + uint256 internal constant QUOTIENT_OUTPUT_MPTR = 0x1000; // External-call frame metadata. The main verifier calls this contract with // exactly QUOTIENT_FRAME_LEN bytes starting at // QUOTIENT_FRAME_BASE, then checks the return length and QUOTIENT_MAGIC. - uint256 internal constant QUOTIENT_FRAME_BASE = 0x2700; + uint256 internal constant QUOTIENT_FRAME_BASE = 0x3680; uint256 internal constant QUOTIENT_FRAME_LEN = 0x6ac0; uint256 internal constant QUOTIENT_OUTPUT_LEN = 0x0180; uint256 internal constant QUOTIENT_MAGIC = 0x00000000000000000000000000000000000000000000000051554556414c0001; @@ -251,15 +251,15 @@ contract Halo2QuotientEvaluator { // q_const_mptr points to Fr constants used by the VM. // q_program_mptr points to the bytecode stream. // Constants are stored as consecutive 32-byte Fr words. - let q_const_mptr := 0x2ae0 + let q_const_mptr := 0x3a60 // Program bytes are also stored in the VK payload, packed into // 32-byte words by PackedProgramCodec. - let q_program_mptr := 0x4120 + let q_program_mptr := 0x50a0 // Running Horner accumulator for fully evaluated identities. // After all identities, this is nu_y(x) for the `None` // identity group. // Initialize A = 0 before scanning the identity stream. - mstore(0xa300, 0) + mstore(0xb280, 0) // Simple selectors are grouped into separate linearization // buckets. They start at zero for every proof. // q_sel_zero_off walks selector bucket byte offsets. @@ -274,12 +274,19 @@ contract Halo2QuotientEvaluator { { // q_y_power holds y^i at the current loop index. let q_y_power := 1 - // Start at i=1 because y^0 = 1 is implicit and never read. + // Slot 0 holds y^0 = 1. Codegen never emits a read of it + // (FOLD_SELECTOR guards on a nonzero gap, and + // selector_tail_updates drops zero tails), but the tail + // block multiplies by mload(selector_power_mptr + offset) + // unconditionally -- so initialize the slot rather than + // leaving correctness to two filters in another file. + mstore(0xb2c0, 1) + // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 49) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) // Store y^i at selector_power_mptr + 32*i. - mstore(add(0xa340, shl(5, q_y_power_i)), q_y_power) + mstore(add(0xb2c0, shl(5, q_y_power_i)), q_y_power) } } @@ -288,102 +295,102 @@ contract Halo2QuotientEvaluator { // VM/native identities, so they occupy the same y-batch order. { let var0 := 0x1 - let f_3 := mload(0x8b40) - let f_4 := mload(0x8a40) - let a_0 := mload(0x8520) + let f_3 := mload(0x9ac0) + let f_4 := mload(0x99c0) + let a_0 := mload(0x94a0) let var1 := mulmod(f_4, a_0, r) let var2 := addmod(f_3, var1, r) - let f_5 := mload(0x8a60) - let a_1 := mload(0x8540) + let f_5 := mload(0x99e0) + let a_1 := mload(0x94c0) let var3 := mulmod(f_5, a_1, r) let var4 := addmod(var2, var3, r) - let f_6 := mload(0x8a80) - let a_2 := mload(0x8560) + let f_6 := mload(0x9a00) + let a_2 := mload(0x94e0) let var5 := mulmod(f_6, a_2, r) let var6 := addmod(var4, var5, r) - let f_7 := mload(0x8aa0) - let a_3 := mload(0x8580) + let f_7 := mload(0x9a20) + let a_3 := mload(0x9500) let var7 := mulmod(f_7, a_3, r) let var8 := addmod(var6, var7, r) - let f_8 := mload(0x8ac0) - let a_4 := mload(0x85a0) + let f_8 := mload(0x9a40) + let a_4 := mload(0x9520) let var9 := mulmod(f_8, a_4, r) let var10 := addmod(var8, var9, r) - let f_0 := mload(0x8ae0) - let a_0_next_1 := mload(0x85c0) + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) let var11 := mulmod(f_0, a_0_next_1, r) let var12 := addmod(var10, var11, r) - let f_1 := mload(0x8b00) + let f_1 := mload(0x9a80) let var13 := mulmod(f_1, a_0, r) let var14 := mulmod(var13, a_1, r) let var15 := addmod(var12, var14, r) - let f_2 := mload(0x8b20) + let f_2 := mload(0x9aa0) let var16 := mulmod(f_2, a_0, r) let var17 := mulmod(var16, a_2, r) let var18 := addmod(var15, var17, r) let var19 := mulmod(var0, var18, r) - mstore(0xa960, var19) + mstore(0xb8e0, var19) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } { let var0 := 0x1 - let a_1 := mload(0x8540) - let a_2 := mload(0x8560) + let a_1 := mload(0x94c0) + let a_2 := mload(0x94e0) let var1 := addmod(a_1, a_2, r) - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var2 := addmod(0, sub(r, a_3), r) let var3 := addmod(var1, var2, r) - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var4 := addmod(0, sub(r, a_4), r) let var5 := addmod(var3, var4, r) let var6 := mulmod(var0, var5, r) - mstore(0xa960, var6) + mstore(0xb8e0, var6) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } { let var0 := 0x1 - let a_0 := mload(0x8520) - let f_4 := mload(0x8a40) + let a_0 := mload(0x94a0) + let f_4 := mload(0x99c0) let var1 := addmod(a_0, f_4, r) - let a_0_next_1 := mload(0x85c0) + let a_0_next_1 := mload(0x9540) let var2 := addmod(0, sub(r, a_0_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0xa960, var4) + mstore(0xb8e0, var4) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } { let var0 := 0x1 - let a_1 := mload(0x8540) - let f_5 := mload(0x8a60) + let a_1 := mload(0x94c0) + let f_5 := mload(0x99e0) let var1 := addmod(a_1, f_5, r) - let a_1_next_1 := mload(0x85e0) + let a_1_next_1 := mload(0x9560) let var2 := addmod(0, sub(r, a_1_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0xa960, var4) + mstore(0xb8e0, var4) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0xa340, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } // VM registers: @@ -403,7 +410,7 @@ contract Halo2QuotientEvaluator { // q_end is an exclusive byte pointer for the VM loop. let q_end := add(q_program_mptr, 0x11cf) // q_sp starts at the first free stack word. - let q_sp := 0xa960 + let q_sp := 0xb8e0 // q_top is meaningless until q_has_top is set. let q_top := 0 // q_has_top = 0 means the VM stack is empty. @@ -677,82 +684,82 @@ contract Halo2QuotientEvaluator { // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := 0xa960 + q_sp := 0xb8e0 // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. { let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 - let q_perm_vals := 0xa960 - let q_perm_sigmas := 0xaba0 - let q_perm_z_cur := 0xade0 - let q_perm_z_next := 0xaea0 - let q_perm_z_last := 0xaf60 - let q_perm_delta_base_ptr := 0xb000 + let q_perm_vals := 0xb8e0 + let q_perm_sigmas := 0xbb20 + let q_perm_z_cur := 0xbd60 + let q_perm_z_next := 0xbe20 + let q_perm_z_last := 0xbee0 + let q_perm_delta_base_ptr := 0xbf80 let q_perm_num_cols := 18 let q_perm_num_sets := 6 let q_perm_chunk_len := 3 let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 - mstore(add(q_perm_vals, 0x0), mload(0x8a20)) + mstore(add(q_perm_vals, 0x0), mload(0x99a0)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x8520, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x94a0, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0xc0), mload(0x8500)) + mstore(add(q_perm_vals, 0xc0), mload(0x9480)) mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 9) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x100), q_perm_val_load_dst_off), mload(add(0x8620, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x100), q_perm_val_load_dst_off), mload(add(0x95a0, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0x220), mload(0x8a00)) + mstore(add(q_perm_vals, 0x220), mload(0x9980)) { for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 18) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off - mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x8c40, q_perm_sigma_load_src_off))) + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x9bc0, q_perm_sigma_load_src_off))) } } { for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 6) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) - mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x8e80, q_perm_z_cur_load_src_off))) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x9e00, q_perm_z_cur_load_src_off))) } } { for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 6) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) - mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x8ea0, q_perm_z_next_load_src_off))) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x9e20, q_perm_z_next_load_src_off))) } } { for { let q_perm_z_last_load_i := 0 } lt(q_perm_z_last_load_i, 5) { q_perm_z_last_load_i := add(q_perm_z_last_load_i, 1) } { let q_perm_z_last_load_dst_off := shl(5, q_perm_z_last_load_i) let q_perm_z_last_load_src_off := mul(q_perm_z_last_load_i, 0x60) - mstore(add(add(q_perm_z_last, 0x0), q_perm_z_last_load_dst_off), mload(add(0x8ec0, q_perm_z_last_load_src_off))) + mstore(add(add(q_perm_z_last, 0x0), q_perm_z_last_load_dst_off), mload(add(0x9e40, q_perm_z_last_load_src_off))) } } let q_perm_eval := 0 q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_perm_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) let q_perm_zn := mload(add(q_perm_z_cur, 0xa0)) q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_perm_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) for { let q_perm_i := 1 } lt(q_perm_i, 6) { q_perm_i := add(q_perm_i, 1) } { let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_perm_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) } mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) for { let q_perm_set := 0 } lt(q_perm_set, 6) { q_perm_set := add(q_perm_set, 1) } { @@ -771,8 +778,8 @@ contract Halo2QuotientEvaluator { q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) } q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_perm_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_perm_eval, r)) mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) } } @@ -793,13 +800,13 @@ contract Halo2QuotientEvaluator { // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := 0xa960 + q_sp := 0xb8e0 // Generated LogUp code follows the same y-batch order // as the Rust identity stream. { - let q_lookup_f := 0xa960 - let q_lookup_prefix := 0xa9e0 - let q_lookup_suffix := 0xaa60 + let q_lookup_f := 0xb8e0 + let q_lookup_prefix := 0xb960 + let q_lookup_suffix := 0xb9e0 let q_lookup_l0 := mload(L_0_MPTR) let q_lookup_llast := mload(L_LAST_MPTR) let q_lookup_lblind := mload(L_BLIND_MPTR) @@ -809,17 +816,17 @@ contract Halo2QuotientEvaluator { let q_lookup_theta := mload(THETA_MPTR) { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x90e0), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa060), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } { - let f_10 := mload(0x8b60) + let f_10 := mload(0x9ae0) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) let var1 := mulmod(var0, q_lookup_theta, r) for { let q_lookup_shared_i := 0 } lt(q_lookup_shared_i, 4) { q_lookup_shared_i := add(q_lookup_shared_i, 1) } { let q_lookup_shared_off := shl(5, q_lookup_shared_i) - let q_lookup_shared_tail := mload(add(0x8540, q_lookup_shared_off)) + let q_lookup_shared_tail := mload(add(0x94c0, q_lookup_shared_off)) let q_lookup_shared_compressed := addmod(var1, q_lookup_shared_tail, r) mstore(add(q_lookup_f, q_lookup_shared_off), addmod(q_lookup_shared_compressed, q_lookup_beta, r)) } @@ -841,130 +848,130 @@ contract Halo2QuotientEvaluator { for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 4) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) } - let q_lookup_eval := addmod(mulmod(mload(0x90c0), q_lookup_product, r), sub(r, q_lookup_sum), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0xa040), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x90c0) - let f_17 := mload(0x8be0) - let f_11 := mload(0x8b80) + let q_lookup_sum_h := mload(0xa040) + let f_17 := mload(0x9b60) + let f_11 := mload(0x9b00) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) - let f_12 := mload(0x8ba0) + let f_12 := mload(0x9b20) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) let q_lookup_s_sum_h := mulmod(f_17, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x9100), sub(r, addmod(mload(0x90e0), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0xa080), sub(r, addmod(mload(0xa060), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x90a0), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa020), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } } { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x9160), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0xa0e0), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } { - let a_14 := mload(0x8a00) + let a_14 := mload(0x9980) let var0 := addmod(mulmod(0, q_lookup_theta, r), a_14, r) - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_0, r) - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var2 := addmod(mulmod(var1, q_lookup_theta, r), a_1, r) - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var3 := addmod(mulmod(var2, q_lookup_theta, r), a_2, r) - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var4 := addmod(mulmod(var3, q_lookup_theta, r), a_3, r) - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var5 := addmod(mulmod(var4, q_lookup_theta, r), a_4, r) - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var6 := addmod(mulmod(var5, q_lookup_theta, r), a_5, r) - let a_6 := mload(0x8640) + let a_6 := mload(0x95c0) let var7 := addmod(mulmod(var6, q_lookup_theta, r), a_6, r) - let a_7 := mload(0x8660) + let a_7 := mload(0x95e0) let var8 := addmod(mulmod(var7, q_lookup_theta, r), a_7, r) - let a_8 := mload(0x8680) + let a_8 := mload(0x9600) let var9 := addmod(mulmod(var8, q_lookup_theta, r), a_8, r) - let a_9 := mload(0x86a0) + let a_9 := mload(0x9620) let var10 := addmod(mulmod(var9, q_lookup_theta, r), a_9, r) - let a_10 := mload(0x86c0) + let a_10 := mload(0x9640) let var11 := addmod(mulmod(var10, q_lookup_theta, r), a_10, r) - let a_11 := mload(0x86e0) + let a_11 := mload(0x9660) let var12 := addmod(mulmod(var11, q_lookup_theta, r), a_11, r) - let a_12 := mload(0x8700) + let a_12 := mload(0x9680) let var13 := addmod(mulmod(var12, q_lookup_theta, r), a_12, r) - let a_13 := mload(0x8720) + let a_13 := mload(0x96a0) let var14 := addmod(mulmod(var13, q_lookup_theta, r), a_13, r) - let f_13 := mload(0x8bc0) + let f_13 := mload(0x9b40) let var15 := addmod(mulmod(var14, q_lookup_theta, r), f_13, r) - let q_lookup_eval := addmod(mulmod(mload(0x9140), addmod(var15, q_lookup_beta, r), r), sub(r, 1), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0xa0c0), addmod(var15, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x9140) + let q_lookup_sum_h := mload(0xa0c0) let var0 := 0x1 - let f_26 := mload(0x8c20) + let f_26 := mload(0x9ba0) let var1 := addmod(0, sub(r, f_26), r) let var2 := addmod(var0, var1, r) - let a_14 := mload(0x8a00) + let a_14 := mload(0x9980) let var3 := mulmod(var2, a_14, r) let var4 := addmod(mulmod(0, q_lookup_theta, r), var3, r) - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var5 := mulmod(var2, a_0, r) let var6 := addmod(mulmod(var4, q_lookup_theta, r), var5, r) - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var7 := mulmod(var2, a_1, r) let var8 := addmod(mulmod(var6, q_lookup_theta, r), var7, r) - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var9 := mulmod(var2, a_2, r) let var10 := addmod(mulmod(var8, q_lookup_theta, r), var9, r) - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var11 := mulmod(var2, a_3, r) let var12 := addmod(mulmod(var10, q_lookup_theta, r), var11, r) - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var13 := mulmod(var2, a_4, r) let var14 := addmod(mulmod(var12, q_lookup_theta, r), var13, r) - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var15 := mulmod(var2, a_5, r) let var16 := addmod(mulmod(var14, q_lookup_theta, r), var15, r) - let a_6 := mload(0x8640) + let a_6 := mload(0x95c0) let var17 := mulmod(var2, a_6, r) let var18 := addmod(mulmod(var16, q_lookup_theta, r), var17, r) - let a_7 := mload(0x8660) + let a_7 := mload(0x95e0) let var19 := mulmod(var2, a_7, r) let var20 := addmod(mulmod(var18, q_lookup_theta, r), var19, r) - let a_8 := mload(0x8680) + let a_8 := mload(0x9600) let var21 := mulmod(var2, a_8, r) let var22 := addmod(mulmod(var20, q_lookup_theta, r), var21, r) - let a_9 := mload(0x86a0) + let a_9 := mload(0x9620) let var23 := mulmod(var2, a_9, r) let var24 := addmod(mulmod(var22, q_lookup_theta, r), var23, r) - let a_10 := mload(0x86c0) + let a_10 := mload(0x9640) let var25 := mulmod(var2, a_10, r) let var26 := addmod(mulmod(var24, q_lookup_theta, r), var25, r) - let a_11 := mload(0x86e0) + let a_11 := mload(0x9660) let var27 := mulmod(var2, a_11, r) let var28 := addmod(mulmod(var26, q_lookup_theta, r), var27, r) - let a_12 := mload(0x8700) + let a_12 := mload(0x9680) let var29 := mulmod(var2, a_12, r) let var30 := addmod(mulmod(var28, q_lookup_theta, r), var29, r) - let a_13 := mload(0x8720) + let a_13 := mload(0x96a0) let var31 := mulmod(var2, a_13, r) let var32 := addmod(mulmod(var30, q_lookup_theta, r), var31, r) - let f_13 := mload(0x8bc0) + let f_13 := mload(0x9b40) let var33 := mulmod(var2, f_13, r) let var34 := addmod(mulmod(var32, q_lookup_theta, r), var33, r) let q_lookup_s_sum_h := mulmod(var0, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x9180), sub(r, addmod(mload(0x9160), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0xa100), sub(r, addmod(mload(0xa0e0), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var34, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x9120), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0xa0a0), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_lookup_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_lookup_eval, r)) } } } @@ -985,104 +992,104 @@ contract Halo2QuotientEvaluator { // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := 0xa960 + q_sp := 0xb8e0 // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx case 0 { { let var0 := 0x1 - let f_0 := mload(0x8ae0) - let a_0_next_1 := mload(0x85c0) + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) let var1 := addmod(0, sub(r, a_0_next_1), r) let var2 := addmod(f_0, var1, r) let var3 := 0x1b8114c381b922fd5d6d241210e2d8a68ad5744053ba9e776118de4107b51ace - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0x3df32e4cc4cb2ed20e5d21899cf5331775990ccaec4c09b4e3717213fcc0d763 - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0xa960, var18) + mstore(0xb8e0, var18) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0xa340, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } case 1 { { let var0 := 0x1 - let f_1 := mload(0x8b00) - let a_1_next_1 := mload(0x85e0) + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) let var1 := addmod(0, sub(r, a_1_next_1), r) let var2 := addmod(f_1, var1, r) let var3 := 0x404d21073985d14e432a4ad76d3fae06ca74314b950fe7b1d7f501cd31a8b374 - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0xb2cc8704264c6bd81bc620e9e524d4b73e9b2317679422ff7fa1603955649f1 - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0xa960, var18) + mstore(0xb8e0, var18) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0xa340, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0xb2c0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } case 2 { { let var0 := 0x1 - let a_0 := mload(0x8520) - let a_0_next_1 := mload(0x85c0) + let a_0 := mload(0x94a0) + let a_0_next_1 := mload(0x9540) let var1 := mulmod(a_0, a_0_next_1, r) let var2 := 0x100000000000000 - let a_1_next_1 := mload(0x85e0) + let a_1_next_1 := mload(0x9560) let var3 := mulmod(a_0, a_1_next_1, r) let var4 := mulmod(var2, var3, r) let var5 := addmod(var1, var4, r) let var6 := 0x10000000000000000000000000000 - let a_2_next_1 := mload(0x8600) + let a_2_next_1 := mload(0x9580) let var7 := mulmod(a_0, a_2_next_1, r) let var8 := mulmod(var6, var7, r) let var9 := addmod(var5, var8, r) - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var10 := mulmod(a_1, a_0_next_1, r) let var11 := mulmod(var2, var10, r) let var12 := addmod(var9, var11, r) @@ -1090,15 +1097,15 @@ contract Halo2QuotientEvaluator { let var14 := mulmod(var6, var13, r) let var15 := addmod(var12, var14, r) let var16 := 0x3212e00cde6d2002b119d800000347fcb8 - let a_6_next_1 := mload(0x87a0) + let a_6_next_1 := mload(0x9720) let var17 := mulmod(a_1, a_6_next_1, r) let var18 := mulmod(var16, var17, r) let var19 := addmod(var15, var18, r) - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var20 := mulmod(a_2, a_0_next_1, r) let var21 := mulmod(var6, var20, r) let var22 := addmod(var19, var21, r) - let a_5_next_1 := mload(0x8780) + let a_5_next_1 := mload(0x9700) let var23 := mulmod(a_2, a_5_next_1, r) let var24 := mulmod(var16, var23, r) let var25 := addmod(var22, var24, r) @@ -1106,8 +1113,8 @@ contract Halo2QuotientEvaluator { let var27 := mulmod(a_2, a_6_next_1, r) let var28 := mulmod(var26, var27, r) let var29 := addmod(var25, var28, r) - let a_3 := mload(0x8580) - let a_4_next_1 := mload(0x8760) + let a_3 := mload(0x9500) + let a_4_next_1 := mload(0x96e0) let var30 := mulmod(a_3, a_4_next_1, r) let var31 := mulmod(var16, var30, r) let var32 := addmod(var29, var31, r) @@ -1118,8 +1125,8 @@ contract Halo2QuotientEvaluator { let var37 := mulmod(a_3, a_6_next_1, r) let var38 := mulmod(var36, var37, r) let var39 := addmod(var35, var38, r) - let a_4 := mload(0x85a0) - let a_3_next_1 := mload(0x8740) + let a_4 := mload(0x9520) + let a_3_next_1 := mload(0x96c0) let var40 := mulmod(a_4, a_3_next_1, r) let var41 := mulmod(var16, var40, r) let var42 := addmod(var39, var41, r) @@ -1133,7 +1140,7 @@ contract Halo2QuotientEvaluator { let var50 := mulmod(a_4, a_6_next_1, r) let var51 := mulmod(var49, var50, r) let var52 := addmod(var48, var51, r) - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var53 := mulmod(a_5, a_2_next_1, r) let var54 := mulmod(var16, var53, r) let var55 := addmod(var52, var54, r) @@ -1150,7 +1157,7 @@ contract Halo2QuotientEvaluator { let var66 := mulmod(a_5, a_6_next_1, r) let var67 := mulmod(var65, var66, r) let var68 := addmod(var64, var67, r) - let a_6 := mload(0x8640) + let a_6 := mload(0x95c0) let var69 := mulmod(a_6, a_1_next_1, r) let var70 := mulmod(var16, var69, r) let var71 := addmod(var68, var70, r) @@ -1180,23 +1187,23 @@ contract Halo2QuotientEvaluator { let var95 := mulmod(var6, a_2_next_1, r) let var96 := addmod(var94, var95, r) let var97 := addmod(var92, var96, r) - let a_7 := mload(0x8660) - let a_8 := mload(0x8680) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) let var98 := mulmod(var2, a_8, r) let var99 := addmod(a_7, var98, r) - let a_9 := mload(0x86a0) + let a_9 := mload(0x9620) let var100 := mulmod(var6, a_9, r) let var101 := addmod(var99, var100, r) let var102 := addmod(0, sub(r, var101), r) let var103 := addmod(var97, var102, r) - let a_7_next_1 := mload(0x87c0) + let a_7_next_1 := mload(0x9740) let var104 := 0x241eabfffeb153ffffb9feffffffffaaab let var105 := mulmod(a_7_next_1, var104, r) let var106 := addmod(0, sub(r, var105), r) let var107 := addmod(var103, var106, r) let var108 := addmod(0, sub(r, var16), r) let var109 := addmod(var107, var108, r) - let a_8_next_1 := mload(0x87e0) + let a_8_next_1 := mload(0x9760) let var110 := 0x73eda753299d7d483339d80809a1d80553b9202d7ffe85d4800008bb20000001 let var111 := addmod(a_8_next_1, var110, r) let var112 := 0x4000000000000000000000000000000000 @@ -1204,42 +1211,42 @@ contract Halo2QuotientEvaluator { let var114 := addmod(0, sub(r, var113), r) let var115 := addmod(var109, var114, r) let var116 := mulmod(var0, var115, r) - mstore(0xa960, var116) + mstore(0xb8e0, var116) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x80) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } case 3 { { let var0 := 0x1 - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var1 := 0x10000000000000000000000000000 let var2 := addmod(a_0, var1, r) let var3 := 0x100000000000000 - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var4 := addmod(a_1, var1, r) let var5 := mulmod(var3, var4, r) let var6 := addmod(var2, var5, r) - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var7 := addmod(a_2, var1, r) let var8 := mulmod(var1, var7, r) let var9 := addmod(var6, var8, r) - let a_7 := mload(0x8660) - let a_8 := mload(0x8680) + let a_7 := mload(0x95e0) + let a_8 := mload(0x9600) let var10 := mulmod(var3, a_8, r) let var11 := addmod(a_7, var10, r) - let a_9 := mload(0x86a0) + let a_9 := mload(0x9620) let var12 := mulmod(var1, a_9, r) let var13 := addmod(var11, var12, r) let var14 := addmod(0, sub(r, var13), r) let var15 := addmod(var9, var14, r) let var16 := addmod(0, sub(r, var1), r) let var17 := addmod(var15, var16, r) - let a_7_next_1 := mload(0x87c0) + let a_7_next_1 := mload(0x9740) let var18 := 0x241eabfffeb153ffffb9feffffffffaaab let var19 := mulmod(a_7_next_1, var18, r) let var20 := addmod(0, sub(r, var19), r) @@ -1247,7 +1254,7 @@ contract Halo2QuotientEvaluator { let var22 := 0xd9d44a30b019261257667fde3844a8cd6 let var23 := addmod(0, sub(r, var22), r) let var24 := addmod(var21, var23, r) - let a_8_next_1 := mload(0x87e0) + let a_8_next_1 := mload(0x9760) let var25 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5b6e855000003ab00002 let var26 := addmod(a_8_next_1, var25, r) let var27 := 0x4000000000000000000000000000000000 @@ -1255,13 +1262,13 @@ contract Halo2QuotientEvaluator { let var29 := addmod(0, sub(r, var28), r) let var30 := addmod(var24, var29, r) let var31 := mulmod(var0, var30, r) - mstore(0xa960, var31) + mstore(0xb8e0, var31) } - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xa0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xa960), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } default { revert(0, 0) } @@ -1285,14 +1292,14 @@ contract Halo2QuotientEvaluator { // The global fully-evaluated accumulator is still // multiplied by y so later main identities land at the // same y powers as Rust's reverse fold. - mstore(0xa300, mulmod(mload(0xa300), y, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) let q_sel_acc := mload(q_target_ptr) if q_sel_gap { // Selector buckets are sparse in the global // identity stream. Precomputed y^gap advances only // this selector's local accumulator. - q_sel_acc := mulmod(q_sel_acc, mload(add(0xa340, shl(5, q_sel_gap))), r) + q_sel_acc := mulmod(q_sel_acc, mload(add(0xb2c0, shl(5, q_sel_gap))), r) } mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) } @@ -1307,6 +1314,12 @@ contract Halo2QuotientEvaluator { // over-reads operands or leaves a partial expression live. if iszero(eq(q_pc, q_end)) { revert(0, 0) } if q_has_top { revert(0, 0) } + // The spilled stack must also be balanced. A FOLD executed + // with more than one operand live consumes only the cached + // top, leaving abandoned words below q_sp with q_has_top + // clear -- so both checks above pass while an operand of the + // identity has been silently dropped from nu_y(x). + if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -1318,52 +1331,52 @@ contract Halo2QuotientEvaluator { { let q_trash_tau := mload(TRASH_CHALLENGE_MPTR) { - let f_0 := mload(0x8ae0) - let a_0_next_1 := mload(0x85c0) + let f_0 := mload(0x9a60) + let a_0_next_1 := mload(0x9540) let var0 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000 let var1 := mulmod(a_0_next_1, var0, r) let var2 := addmod(f_0, var1, r) let var3 := 0x590ba402032e82eb1f660ef09796c5686345a5054ed96dae8e2d233633788771 - let a_0 := mload(0x8520) + let a_0 := mload(0x94a0) let var4 := mulmod(var3, a_0, r) let var5 := addmod(var2, var4, r) let var6 := 0x52f789e4afc3801f7411102ee2f47cc5954a744e71cac98e75ea962a55a0a76f - let a_1 := mload(0x8540) + let a_1 := mload(0x94c0) let var7 := mulmod(var6, a_1, r) let var8 := addmod(var5, var7, r) let var9 := 0x3509dd2fe3aac0080783557fec090fb1cb4b2b0901253c55282024331d1fe1a8 - let a_2 := mload(0x8560) + let a_2 := mload(0x94e0) let var10 := q_pow5(a_2) let var11 := mulmod(var9, var10, r) let var12 := addmod(var8, var11, r) let var13 := 0x333f8046ece5579cbd6872449c57f2703dfc8864cfadc06d587ff104a0d0c1f2 - let a_3 := mload(0x8580) + let a_3 := mload(0x9500) let var14 := q_pow5(a_3) let var15 := mulmod(var13, var14, r) let var16 := addmod(var12, var15, r) let var17 := 0x412c98232b6ab8a47aa76ee814ef7ec6261987c9802f2cfc490e007951a60ca5 - let a_4 := mload(0x85a0) + let a_4 := mload(0x9520) let var18 := q_pow5(a_4) let var19 := mulmod(var17, var18, r) let var20 := addmod(var16, var19, r) let var21 := 0x53fded36d490ba6b05a5d10fd99ffe5456baec6a6a8753199d5ebdc33c99790e - let a_5 := mload(0x8620) + let a_5 := mload(0x95a0) let var22 := q_pow5(a_5) let var23 := mulmod(var21, var22, r) let var24 := addmod(var20, var23, r) let var25 := 0x6ccb1c7d87f3c12a2bde4e68ac7f1e8b03481ba15d7f88f9a7f9b8310dd6d34 - let a_6 := mload(0x8640) + let a_6 := mload(0x95c0) let var26 := q_pow5(a_6) let var27 := mulmod(var25, var26, r) let var28 := addmod(var24, var27, r) let var29 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_7 := mload(0x8660) + let a_7 := mload(0x95e0) let var30 := q_pow5(a_7) let var31 := mulmod(var29, var30, r) let var32 := addmod(var28, var31, r) let var33 := addmod(mulmod(0, q_trash_tau, r), var32, r) - let f_1 := mload(0x8b00) - let a_1_next_1 := mload(0x85e0) + let f_1 := mload(0x9a80) + let a_1_next_1 := mload(0x9560) let var34 := mulmod(a_1_next_1, var0, r) let var35 := addmod(f_1, var34, r) let var36 := 0x5b1fc262a28cbb8bf75d9b1a6edaa74591ec24cd9a209512213cec3a3c0f1a5d @@ -1391,7 +1404,7 @@ contract Halo2QuotientEvaluator { let var58 := mulmod(var57, var30, r) let var59 := addmod(var56, var58, r) let var60 := addmod(mulmod(var33, q_trash_tau, r), var59, r) - let f_2 := mload(0x8b20) + let f_2 := mload(0x9aa0) let var61 := mulmod(a_3, var0, r) let var62 := addmod(f_2, var61, r) let var63 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 @@ -1404,7 +1417,7 @@ contract Halo2QuotientEvaluator { let var70 := mulmod(var69, var10, r) let var71 := addmod(var68, var70, r) let var72 := addmod(mulmod(var60, q_trash_tau, r), var71, r) - let f_3 := mload(0x8b40) + let f_3 := mload(0x9ac0) let var73 := mulmod(a_4, var0, r) let var74 := addmod(f_3, var73, r) let var75 := 0x222e83e70453dfee19b402e9fa8dfe2c4987b034d0be3ceb478b3022e97934c1 @@ -1419,7 +1432,7 @@ contract Halo2QuotientEvaluator { let var84 := mulmod(var69, var14, r) let var85 := addmod(var83, var84, r) let var86 := addmod(mulmod(var72, q_trash_tau, r), var85, r) - let f_4 := mload(0x8a40) + let f_4 := mload(0x99c0) let var87 := mulmod(a_5, var0, r) let var88 := addmod(f_4, var87, r) let var89 := 0x726df1506749848155630b86ae25a82b281ecd050fe3a52d85a181fa87202e4b @@ -1436,7 +1449,7 @@ contract Halo2QuotientEvaluator { let var100 := mulmod(var69, var18, r) let var101 := addmod(var99, var100, r) let var102 := addmod(mulmod(var86, q_trash_tau, r), var101, r) - let f_5 := mload(0x8a60) + let f_5 := mload(0x99e0) let var103 := mulmod(a_6, var0, r) let var104 := addmod(f_5, var103, r) let var105 := 0x2f5908b169c6cf1bd26dcf0f9e5105481f5164f3ece0582bf3098312167751a7 @@ -1455,7 +1468,7 @@ contract Halo2QuotientEvaluator { let var118 := mulmod(var69, var22, r) let var119 := addmod(var117, var118, r) let var120 := addmod(mulmod(var102, q_trash_tau, r), var119, r) - let f_6 := mload(0x8a80) + let f_6 := mload(0x9a00) let var121 := mulmod(a_7, var0, r) let var122 := addmod(f_6, var121, r) let var123 := 0x6d05a41959f539a7fc9ec0972ea1e3dbb6fc67dd51daf3414f7fbbb091c7274a @@ -1476,8 +1489,8 @@ contract Halo2QuotientEvaluator { let var138 := mulmod(var69, var26, r) let var139 := addmod(var137, var138, r) let var140 := addmod(mulmod(var120, q_trash_tau, r), var139, r) - let f_7 := mload(0x8aa0) - let a_2_next_1 := mload(0x8600) + let f_7 := mload(0x9a20) + let a_2_next_1 := mload(0x9580) let var141 := mulmod(a_2_next_1, var0, r) let var142 := addmod(f_7, var141, r) let var143 := 0x70d8f2a733a64d650faccc9b1c2a766a9544bb3ff1a11ee73cb43947ef386633 @@ -1500,12 +1513,12 @@ contract Halo2QuotientEvaluator { let var160 := mulmod(var69, var30, r) let var161 := addmod(var159, var160, r) let var162 := addmod(mulmod(var140, q_trash_tau, r), var161, r) - let f_19 := mload(0x8c00) + let f_19 := mload(0x9b80) let q_trash_one_minus_selector := addmod(1, sub(r, f_19), r) - let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0x91a0), r) + let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0xa120), r) let q_trash_eval := addmod(var162, sub(r, q_trash_scaled), r) - mstore(0xa300, mulmod(mload(0xa300), y, r)) - mstore(0xa300, addmod(mload(0xa300), q_trash_eval, r)) + mstore(0xb280, mulmod(mload(0xb280), y, r)) + mstore(0xb280, addmod(mload(0xb280), q_trash_eval, r)) } } // Finish selector buckets by applying the codegen-known tail @@ -1517,49 +1530,49 @@ contract Halo2QuotientEvaluator { // selector commitment in the linearized MSM. { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0600)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0600)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x05e0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x05e0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0580)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0580)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x04c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x04c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x80) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0460)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0460)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xa0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0400)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0400)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xc0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x03a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x03a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xe0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0340)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0340)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0100) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x02e0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x02e0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0120) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xa340, 0x0280)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0xb2c0, 0x0280)), r)) } // Fully evaluated identities are the constant-polynomial side // of the linearization query. Rust subtracts that grouped // scalar into expected_eval, so Solidity stores -nu_y(x). - let linearization_expected_eval := addmod(0, sub(r, mload(0xa300)), r) + let linearization_expected_eval := addmod(0, sub(r, mload(0xb280)), r) mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) pop(y) } diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol index 8dd0fcf29..6f66ad7c7 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol @@ -43,15 +43,15 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 17024; uint256 internal constant EXPECTED_VK_LENGTH = 17025; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x0a489a96da94a3dde90d99d69bd4464d5d5731a89f202154559e68a17fac1c21; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x67bac137fa7e479c25b63324812752e4b6e13d9841d5bf83c322170bf91c0f88; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); /// @notice Quotient evaluator contract authorized for split quotient reconstruction. /// @dev The evaluator returns the linearization expected scalar and selector buckets; its runtime may be pinned by generated constants. address public immutable AUTHORIZED_QUOTIENT; // Expected split evaluator runtime metadata. It is checked at deployment // and again immediately before each external quotient reconstruction. - uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9531; - uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x02f1ea00260a78e72dc51376f5e3053ae6c83deae7219acb89c6a0bca5dc8f1c; + uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9552; + uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c; bytes32 internal constant EXPECTED_QUOTIENT_CODEHASH = bytes32(EXPECTED_QUOTIENT_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -63,8 +63,8 @@ contract Halo2Verifier { uint256 internal constant INSTANCE_CPTR = 0x1ee4; // First general-purpose memory words reserved by the generated verifier. // RETURN_MPTR is a single word set to 1 on success. - uint256 internal constant TRANSCRIPT_MPTR = 0x80; - uint256 internal constant RETURN_MPTR = 0x80; + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; // ---------------------------------------------------------------------- // Verifying-key memory map. The VK header lives at VK_MPTR, followed @@ -72,84 +72,84 @@ contract Halo2Verifier { // runtime comes the challenge slots (challenge_mptr..) and the // per-stage scratch (theta_mptr..). // ---------------------------------------------------------------------- - uint256 internal constant VK_MPTR = 0x2700; - uint256 internal constant VK_DIGEST_MPTR = 0x2700; - uint256 internal constant NUM_INSTANCES_MPTR = 0x2720; - uint256 internal constant K_MPTR = 0x2740; - uint256 internal constant N_INV_MPTR = 0x2760; - uint256 internal constant OMEGA_MPTR = 0x2780; - uint256 internal constant OMEGA_INV_MPTR = 0x27a0; - uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x27c0; - uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x27e0; - uint256 internal constant ACC_OFFSET_MPTR = 0x2800; - uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x2820; - uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x2840; - uint256 internal constant G1_BASE_MPTR = 0x2860; - uint256 internal constant G2_BASE_MPTR = 0x28e0; - uint256 internal constant NEG_S_G2_BASE_MPTR = 0x29e0; - - uint256 internal constant CHALLENGE_MPTR = 0x6980; + uint256 internal constant VK_MPTR = 0x3680; + uint256 internal constant VK_DIGEST_MPTR = 0x3680; + uint256 internal constant NUM_INSTANCES_MPTR = 0x36a0; + uint256 internal constant K_MPTR = 0x36c0; + uint256 internal constant N_INV_MPTR = 0x36e0; + uint256 internal constant OMEGA_MPTR = 0x3700; + uint256 internal constant OMEGA_INV_MPTR = 0x3720; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x3740; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x3760; + uint256 internal constant ACC_OFFSET_MPTR = 0x3780; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x37a0; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x37c0; + uint256 internal constant G1_BASE_MPTR = 0x37e0; + uint256 internal constant G2_BASE_MPTR = 0x3860; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x3960; + + uint256 internal constant CHALLENGE_MPTR = 0x7900; // Challenge layout. Squeeze order in midnight-proofs: // user_phase challenges (variable count) // theta -> beta, gamma -> trash_challenge -> y -> x -> // x1, x2 -> x3 -> x4 - uint256 internal constant THETA_MPTR = 0x6980; - uint256 internal constant BETA_MPTR = 0x69a0; - uint256 internal constant GAMMA_MPTR = 0x69c0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x69e0; - uint256 internal constant Y_MPTR = 0x6a00; - uint256 internal constant X_MPTR = 0x6a20; - uint256 internal constant X1_MPTR = 0x6a40; - uint256 internal constant X2_MPTR = 0x6a60; - uint256 internal constant X3_MPTR = 0x6a80; - uint256 internal constant X4_MPTR = 0x6aa0; + uint256 internal constant THETA_MPTR = 0x7900; + uint256 internal constant BETA_MPTR = 0x7920; + uint256 internal constant GAMMA_MPTR = 0x7940; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x7960; + uint256 internal constant Y_MPTR = 0x7980; + uint256 internal constant X_MPTR = 0x79a0; + uint256 internal constant X1_MPTR = 0x79c0; + uint256 internal constant X2_MPTR = 0x79e0; + uint256 internal constant X3_MPTR = 0x7a00; + uint256 internal constant X4_MPTR = 0x7a20; // Batch-open commitments live in 4-word EIP-2537 padded slots. - uint256 internal constant F_COM_MPTR = 0x6ac0; - uint256 internal constant PI_MPTR = 0x6b40; + uint256 internal constant F_COM_MPTR = 0x7a40; + uint256 internal constant PI_MPTR = 0x7ac0; // Accumulator (KZG IVC). - uint256 internal constant ACC_LHS_MPTR = 0x6bc0; - uint256 internal constant ACC_RHS_MPTR = 0x6c40; + uint256 internal constant ACC_LHS_MPTR = 0x7b40; + uint256 internal constant ACC_RHS_MPTR = 0x7bc0; // Lagrange / linearization scratch. - uint256 internal constant X_N_MPTR = 0x6cc0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x6ce0; - uint256 internal constant L_LAST_MPTR = 0x6d00; - uint256 internal constant L_BLIND_MPTR = 0x6d20; - uint256 internal constant L_0_MPTR = 0x6d40; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x6d60; + uint256 internal constant X_N_MPTR = 0x7c40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x7c60; + uint256 internal constant L_LAST_MPTR = 0x7c80; + uint256 internal constant L_BLIND_MPTR = 0x7ca0; + uint256 internal constant L_0_MPTR = 0x7cc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x7ce0; // Legacy name: this is not h(x). It stores the expected opening // scalar for the linearized commitment, i.e. the negated y-batched // identity numerator reconstructed from the alleged evals at x. - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x6d80; - uint256 internal constant QUOTIENT_MPTR = 0x6da0; // 4 words - uint256 internal constant F_EVAL_MPTR = 0x6e40; - uint256 internal constant V_MPTR = 0x6e60; - uint256 internal constant FINAL_COM_MPTR = 0x6e80; // 4 words - uint256 internal constant PAIRING_LHS_MPTR = 0x6f00; // 4 words - uint256 internal constant PAIRING_RHS_MPTR = 0x6f80; // 4 words + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x7d00; + uint256 internal constant QUOTIENT_MPTR = 0x7d20; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x7dc0; + uint256 internal constant V_MPTR = 0x7de0; + uint256 internal constant FINAL_COM_MPTR = 0x7e00; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x7e80; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x7f00; // 4 words // Multi-prepare scratch (sized at codegen time). - uint256 internal constant ROT_POINTS_MPTR = 0x7000; - uint256 internal constant X1_POWERS_MPTR = 0x7380; + uint256 internal constant ROT_POINTS_MPTR = 0x7f80; + uint256 internal constant X1_POWERS_MPTR = 0x8300; // Q_COM materialization is currently fused into the final MSM scratch, // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero // reserved capacity until a future emitter starts writing Q_COM_MPTR. - uint256 internal constant Q_COM_MPTR = 0x7ba0; - uint256 internal constant Q_EVAL_SET_MPTR = 0x7ba0; + uint256 internal constant Q_COM_MPTR = 0x8b20; + uint256 internal constant Q_EVAL_SET_MPTR = 0x8b20; // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals // block of the proof; we keep it as a memory slot for symmetry. - uint256 internal constant Q_EVAL_CPTR_MPTR = 0x82a0; + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; // Reserved 4-word slot for the G1 identity (point at infinity) in // EIP-2537 padded form. EVM memory is zero-initialised, and we // never write to this region, so the four `mload`s below produce // 0,0,0,0 which is exactly the identity encoding the EIP-2537 // ec_add / ec_mul precompiles accept. - uint256 internal constant G1_IDENTITY_MPTR = 0x83a0; + uint256 internal constant G1_IDENTITY_MPTR = 0x9320; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain // Solidity proof shim rewrites proof scalars into canonical BE words, @@ -157,11 +157,11 @@ contract Halo2Verifier { // side `evaluations` loop range-checks and spills that value here so // downstream eval references (gate evaluator + PCS q_eval Horner) // become 3-gas `mload(...)` instead of calldata reads. - uint256 internal constant REVERSED_EVALS_MPTR = 0x8500; - uint256 internal constant SELECTOR_ACC_MPTR = 0xa1c0; - uint256 internal constant QUOTIENT_RETURN_MPTR = 0x80; - uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xa1c0; - uint256 internal constant TRACE_U256_MPTR = 0xd3c0; + uint256 internal constant REVERSED_EVALS_MPTR = 0x9480; + uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + uint256 internal constant TRACE_U256_MPTR = 0xe340; // ---------------------------------------------------------------------- // Per-category bases for EIP-2537 padded G1 commitments. The proof @@ -178,13 +178,13 @@ contract Halo2Verifier { // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans // ---------------------------------------------------------------------- - uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x91c0; - uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x9940; - uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x9a40; - uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x9d40; - uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x9e40; - uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x9f40; - uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x9fc0; + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0xa140; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0xa8c0; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0xa9c0; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0xacc0; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0xadc0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. @@ -206,7 +206,7 @@ contract Halo2Verifier { function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Scratch is reused for every runtime-prerequisite probe. - let scratch := 0x80 + let scratch := 0x1000 // MCOPY must be available because the verifier uses it for // proof-time point/scratch staging. Execute the opcode here so a @@ -230,11 +230,44 @@ contract Halo2Verifier { revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair // smoke call. - let msm_scratch := 0xa1c0 + let msm_scratch := 0xb140 for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } @@ -344,9 +377,15 @@ contract Halo2Verifier { // when the VK payload becomes smaller. function scalar_inv(x) -> inv { // Zero has no multiplicative inverse in Fr; callers rely on a - // revert here rather than a bogus modexp result. + // revert here rather than a bogus modexp result. Check the + // full canonical range, not just the literal word 0: for any + // x congruent to 0 mod r (x = r, say) modexp returns 0, which + // downstream mulmod chains would silently absorb. Every + // current call site feeds addmod/mulmod output, so this only + // guards against a future emitter passing a raw scalar. + if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } - let p := 0x2600 + let p := 0x3580 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] mstore(add(p, 0x00), 0x20) // base len @@ -481,6 +520,13 @@ contract Halo2Verifier { // just run one modexp inverse in place. if eq(count_bytes, 0x20) { let x := mload(mptr_start) + // Reject anything congruent to zero mod r, not just the + // literal word 0: modexp would return 0 for those too, and + // the caller would take it for a valid inverse. + if iszero(lt(x, r)) { + ret := 0 + leave + } if iszero(x) { ret := 0 leave @@ -527,6 +573,12 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0xa0), r) ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would + // overwrite every denominator in [mptr_start, mptr_end) with + // garbage products before returning ret = 0. + if iszero(ret) { leave } let all_inv := mload(gp_mptr) // Backward pass: derive each inverse from the inverted total @@ -551,21 +603,30 @@ contract Halo2Verifier { // 4-word G1 slots; G2 bases are loaded from the pinned VK payload. function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret { ret := success - if iszero(ret) { leave } + // Every other exit from this function reverts, and the + // terminal `return(RETURN_MPTR, 0x20)` in TraceReturn.yul + // returns true without consulting `success`. Revert here too, + // so this helper has no path that hands control back to a + // caller that would report success for an unverified proof. + if iszero(ret) { revert(0, 0) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0300 + let scratch := 0x0320 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } @@ -597,7 +658,13 @@ contract Halo2Verifier { // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div @@ -823,11 +890,16 @@ contract Halo2Verifier { out := and(out, lhs_ok) // Shared scratch for one-pair LHS validation and the later // variable-length RHS MSM. - let acc_scratch := 0xa1c0 + let acc_scratch := 0xb140 { // Carried-scalar layout: the circuit exposes the scalar // that multiplies the carried LHS point. let lhs_scalar := calldataload(lhs_scalar_ptr) + // Canonicality is enforced here rather than relying on the + // later instance-absorption loop: G1MSM reduces scalars + // mod r implicitly, so s and s+r would be indistinguishable + // inside this helper. + out := and(out, lt(lhs_scalar, r)) // Identity status is useful for decoding checks above, but // validation still goes through G1MSM for all points. pop(lhs_is_id) @@ -862,6 +934,7 @@ contract Halo2Verifier { { // Explicit carried RHS scalar. let rhs_scalar := calldataload(rhs_scalar_ptr) + out := and(out, lt(rhs_scalar, r)) pop(rhs_is_id) // Keep the carried RHS point in the MSM input even when // it is encoded as identity or has scalar 0/1, so EIP-2537 @@ -1275,6 +1348,16 @@ contract Halo2Verifier { // ---- x3 ---- // x3 is the PCS evaluation point for f_com. buf_len := squeeze_to(buf_len, X3_MPTR) + // truncated-challenges mirrors midnight-proofs + // proofs/src/poly/kzg/mod.rs: + // - x3 is the f_com evaluation point and is truncated + // immediately after squeeze. + // - x1 and x4 remain full squeezed Fr words, but later PCS + // batching stores truncate(x1^i) and truncate(x4^i) while + // keeping the internal power accumulators full precision. + // This direct x3 mask is therefore one part of the PCS truncation + // rule, not the only truncated value used by the verifier. + mstore(X3_MPTR, and(mload(X3_MPTR), 0xffffffffffffffffffffffffffffffff)) // ---- q_evals (one Fq per point set) ---- // q_evals are not spilled into REVERSED_EVALS_MPTR because the PCS @@ -1424,7 +1507,7 @@ contract Halo2Verifier { eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) )) { revert(0, 0) } - if iszero(staticcall(gas(), quotientEvaluator, 0x2700, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } + if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x0180)) { revert(0, 0) } if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { revert(0, 0) } // Word 1 is the negated y-batched identity numerator, stored @@ -1529,7 +1612,7 @@ contract Halo2Verifier { for { let i := 0 } lt(i, 0x2a) { i := add(i, 1) } { p := add(p, 0x20) acc := mulmod(acc, x1, r) - mstore(p, acc) + mstore(p, and(acc, 0xffffffffffffffffffffffffffffffff)) } } // Generated PCS sub-block 3. These lines are @@ -1538,52 +1621,52 @@ contract Halo2Verifier { { // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0xa300, 0x8a00) - mstore(0xa320, 0x8500) - mstore(0xa340, 0x90a0) - mstore(0xa360, 0x90c0) - mstore(0xa380, 0x9120) - mstore(0xa3a0, 0x9140) - mstore(0xa3c0, 0x91a0) - mstore(0xa3e0, 0x8a20) - mstore(0xa400, 0x8a40) - mstore(0xa420, 0x8a60) - mstore(0xa440, 0x8a80) - mstore(0xa460, 0x8aa0) - mstore(0xa480, 0x8ac0) - mstore(0xa4a0, 0x8ae0) - mstore(0xa4c0, 0x8b00) - mstore(0xa4e0, 0x8b20) - mstore(0xa500, 0x8b40) - mstore(0xa520, 0x8b60) - mstore(0xa540, 0x8b80) - mstore(0xa560, 0x8ba0) - mstore(0xa580, 0x8bc0) - mstore(0xa5a0, 0x8be0) - mstore(0xa5c0, 0x8c00) - mstore(0xa5e0, 0x8c20) - mstore(0xa600, 0x8c40) - mstore(0xa620, 0x8c60) - mstore(0xa640, 0x8c80) - mstore(0xa660, 0x8ca0) - mstore(0xa680, 0x8cc0) - mstore(0xa6a0, 0x8ce0) - mstore(0xa6c0, 0x8d00) - mstore(0xa6e0, 0x8d20) - mstore(0xa700, 0x8d40) - mstore(0xa720, 0x8d60) - mstore(0xa740, 0x8d80) - mstore(0xa760, 0x8da0) - mstore(0xa780, 0x8dc0) - mstore(0xa7a0, 0x8de0) - mstore(0xa7c0, 0x8e00) - mstore(0xa7e0, 0x8e20) - mstore(0xa800, 0x8e40) - mstore(0xa820, 0x8e60) - mstore(0xa840, QUOTIENT_EVAL_MPTR) - let q_eval_set_0 := mload(0x8a00) + mstore(0xb280, 0x9980) + mstore(0xb2a0, 0x9480) + mstore(0xb2c0, 0xa020) + mstore(0xb2e0, 0xa040) + mstore(0xb300, 0xa0a0) + mstore(0xb320, 0xa0c0) + mstore(0xb340, 0xa120) + mstore(0xb360, 0x99a0) + mstore(0xb380, 0x99c0) + mstore(0xb3a0, 0x99e0) + mstore(0xb3c0, 0x9a00) + mstore(0xb3e0, 0x9a20) + mstore(0xb400, 0x9a40) + mstore(0xb420, 0x9a60) + mstore(0xb440, 0x9a80) + mstore(0xb460, 0x9aa0) + mstore(0xb480, 0x9ac0) + mstore(0xb4a0, 0x9ae0) + mstore(0xb4c0, 0x9b00) + mstore(0xb4e0, 0x9b20) + mstore(0xb500, 0x9b40) + mstore(0xb520, 0x9b60) + mstore(0xb540, 0x9b80) + mstore(0xb560, 0x9ba0) + mstore(0xb580, 0x9bc0) + mstore(0xb5a0, 0x9be0) + mstore(0xb5c0, 0x9c00) + mstore(0xb5e0, 0x9c20) + mstore(0xb600, 0x9c40) + mstore(0xb620, 0x9c60) + mstore(0xb640, 0x9c80) + mstore(0xb660, 0x9ca0) + mstore(0xb680, 0x9cc0) + mstore(0xb6a0, 0x9ce0) + mstore(0xb6c0, 0x9d00) + mstore(0xb6e0, 0x9d20) + mstore(0xb700, 0x9d40) + mstore(0xb720, 0x9d60) + mstore(0xb740, 0x9d80) + mstore(0xb760, 0x9da0) + mstore(0xb780, 0x9dc0) + mstore(0xb7a0, 0x9de0) + mstore(0xb7c0, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x9980) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0xa300, 0x20) + let eval_p := add(0xb280, 0x20) for { let i := 1 } lt(i, 0x2b) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -1597,12 +1680,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[1]: 3 commitment(s) - let q_eval_set_0 := mload(0x86e0) - let q_eval_set_1 := mload(0x89a0) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x8700), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x89c0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x8720), mload(add(X1_POWERS_MPTR, 0x40)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x89e0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + let q_eval_set_0 := mload(0x9660) + let q_eval_set_1 := mload(0x9920) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9940), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x96a0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9960), mload(add(X1_POWERS_MPTR, 0x40)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) } @@ -1611,12 +1694,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[2]: 3 commitment(s) - let q_eval_set_0 := mload(0x9060) - let q_eval_set_1 := mload(0x9080) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x90e0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9100), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9160), mload(add(X1_POWERS_MPTR, 0x40)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x9180), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + let q_eval_set_0 := mload(0x9fe0) + let q_eval_set_1 := mload(0xa000) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa080), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa0e0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0xa100), mload(add(X1_POWERS_MPTR, 0x40)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) } @@ -1626,44 +1709,44 @@ contract Halo2Verifier { { // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0xa300, 0x8520) - mstore(0xa320, 0x85c0) - mstore(0xa340, 0x8840) - mstore(0xa360, 0x8540) - mstore(0xa380, 0x85e0) - mstore(0xa3a0, 0x8860) - mstore(0xa3c0, 0x8560) - mstore(0xa3e0, 0x8600) - mstore(0xa400, 0x8880) - mstore(0xa420, 0x8580) - mstore(0xa440, 0x8740) - mstore(0xa460, 0x88a0) - mstore(0xa480, 0x85a0) - mstore(0xa4a0, 0x8760) - mstore(0xa4c0, 0x88c0) - mstore(0xa4e0, 0x8620) - mstore(0xa500, 0x8780) - mstore(0xa520, 0x88e0) - mstore(0xa540, 0x8640) - mstore(0xa560, 0x87a0) - mstore(0xa580, 0x8900) - mstore(0xa5a0, 0x8660) - mstore(0xa5c0, 0x87c0) - mstore(0xa5e0, 0x8920) - mstore(0xa600, 0x8680) - mstore(0xa620, 0x87e0) - mstore(0xa640, 0x8940) - mstore(0xa660, 0x86a0) - mstore(0xa680, 0x8800) - mstore(0xa6a0, 0x8960) - mstore(0xa6c0, 0x86c0) - mstore(0xa6e0, 0x8820) - mstore(0xa700, 0x8980) - let q_eval_set_0 := mload(0x8520) - let q_eval_set_1 := mload(0x85c0) - let q_eval_set_2 := mload(0x8840) + mstore(0xb280, 0x94a0) + mstore(0xb2a0, 0x9540) + mstore(0xb2c0, 0x97c0) + mstore(0xb2e0, 0x94c0) + mstore(0xb300, 0x9560) + mstore(0xb320, 0x97e0) + mstore(0xb340, 0x94e0) + mstore(0xb360, 0x9580) + mstore(0xb380, 0x9800) + mstore(0xb3a0, 0x9500) + mstore(0xb3c0, 0x96c0) + mstore(0xb3e0, 0x9820) + mstore(0xb400, 0x9520) + mstore(0xb420, 0x96e0) + mstore(0xb440, 0x9840) + mstore(0xb460, 0x95a0) + mstore(0xb480, 0x9700) + mstore(0xb4a0, 0x9860) + mstore(0xb4c0, 0x95c0) + mstore(0xb4e0, 0x9720) + mstore(0xb500, 0x9880) + mstore(0xb520, 0x95e0) + mstore(0xb540, 0x9740) + mstore(0xb560, 0x98a0) + mstore(0xb580, 0x9600) + mstore(0xb5a0, 0x9760) + mstore(0xb5c0, 0x98c0) + mstore(0xb5e0, 0x9620) + mstore(0xb600, 0x9780) + mstore(0xb620, 0x98e0) + mstore(0xb640, 0x9640) + mstore(0xb660, 0x97a0) + mstore(0xb680, 0x9900) + let q_eval_set_0 := mload(0x94a0) + let q_eval_set_1 := mload(0x9540) + let q_eval_set_2 := mload(0x97c0) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0xa300, 0x60) + let eval_p := add(0xb280, 0x60) for { let i := 1 } lt(i, 0xb) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -1682,26 +1765,26 @@ contract Halo2Verifier { { // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0xa300, 0x8e80) - mstore(0xa320, 0x8ea0) - mstore(0xa340, 0x8ec0) - mstore(0xa360, 0x8ee0) - mstore(0xa380, 0x8f00) - mstore(0xa3a0, 0x8f20) - mstore(0xa3c0, 0x8f40) - mstore(0xa3e0, 0x8f60) - mstore(0xa400, 0x8f80) - mstore(0xa420, 0x8fa0) - mstore(0xa440, 0x8fc0) - mstore(0xa460, 0x8fe0) - mstore(0xa480, 0x9000) - mstore(0xa4a0, 0x9020) - mstore(0xa4c0, 0x9040) - let q_eval_set_0 := mload(0x8e80) - let q_eval_set_1 := mload(0x8ea0) - let q_eval_set_2 := mload(0x8ec0) + mstore(0xb280, 0x9e00) + mstore(0xb2a0, 0x9e20) + mstore(0xb2c0, 0x9e40) + mstore(0xb2e0, 0x9e60) + mstore(0xb300, 0x9e80) + mstore(0xb320, 0x9ea0) + mstore(0xb340, 0x9ec0) + mstore(0xb360, 0x9ee0) + mstore(0xb380, 0x9f00) + mstore(0xb3a0, 0x9f20) + mstore(0xb3c0, 0x9f40) + mstore(0xb3e0, 0x9f60) + mstore(0xb400, 0x9f80) + mstore(0xb420, 0x9fa0) + mstore(0xb440, 0x9fc0) + let q_eval_set_0 := mload(0x9e00) + let q_eval_set_1 := mload(0x9e20) + let q_eval_set_2 := mload(0x9e40) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0xa300, 0x60) + let eval_p := add(0xb280, 0x60) for { let i := 1 } lt(i, 0x5) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -1892,181 +1975,186 @@ contract Halo2Verifier { let lin_x_split := mload(QUOTIENT_MPTR) let lin_one_minus_x_n := mload(add(QUOTIENT_MPTR, 0x20)) let Q_EVAL_CPTR := mload(Q_EVAL_CPTR_MPTR) - let x4_pow_0 := 1 - let x4_pow_1 := mulmod(x4_pow_0, x4, r) - let x4_pow_2 := mulmod(x4_pow_1, x4, r) - let x4_pow_3 := mulmod(x4_pow_2, x4, r) - let x4_pow_4 := mulmod(x4_pow_3, x4, r) - let x4_pow_5 := mulmod(x4_pow_4, x4, r) + let x4_pow_full := 1 + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_1 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_2 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_3 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_4 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) + x4_pow_full := mulmod(x4_pow_full, x4, r) + let x4_pow_5 := and(x4_pow_full, 0xffffffffffffffffffffffffffffffff) let v := calldataload(Q_EVAL_CPTR) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), x4_pow_1, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), x4_pow_3, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x80)), x4_pow_4, r), r) v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_5, r), r) - mcopy(0xa300, 0x98c0, 0x80) - mstore(0xa380, 1) - mcopy(0xa3a0, 0x9940, 0x80) - mstore(0xa420, mload(add(X1_POWERS_MPTR, 0x40))) - mcopy(0xa440, 0x9d40, 0x80) - mstore(0xa4c0, mload(add(X1_POWERS_MPTR, 0x60))) - mcopy(0xa4e0, 0x99c0, 0x80) - mstore(0xa560, mload(add(X1_POWERS_MPTR, 0x80))) - mcopy(0xa580, 0x9dc0, 0x80) - mstore(0xa600, mload(add(X1_POWERS_MPTR, 0xa0))) - mcopy(0xa620, 0x9f40, 0x80) - mstore(0xa6a0, mload(add(X1_POWERS_MPTR, 0xc0))) - mcopy(0xa6c0, 0x5780, 0x80) - mstore(0xa740, mload(add(X1_POWERS_MPTR, 0xe0))) - mcopy(0xa760, 0x5500, 0x80) - mstore(0xa7e0, mload(add(X1_POWERS_MPTR, 0x100))) - mcopy(0xa800, 0x5580, 0x80) - mstore(0xa880, mload(add(X1_POWERS_MPTR, 0x120))) - mcopy(0xa8a0, 0x5600, 0x80) - mstore(0xa920, mload(add(X1_POWERS_MPTR, 0x140))) - mcopy(0xa940, 0x5680, 0x80) - mstore(0xa9c0, mload(add(X1_POWERS_MPTR, 0x160))) - mcopy(0xa9e0, 0x5700, 0x80) - mstore(0xaa60, mload(add(X1_POWERS_MPTR, 0x180))) - mcopy(0xaa80, 0x5300, 0x80) - mstore(0xab00, mload(add(X1_POWERS_MPTR, 0x1a0))) - mcopy(0xab20, 0x5380, 0x80) - mstore(0xaba0, mload(add(X1_POWERS_MPTR, 0x1c0))) - mcopy(0xabc0, 0x5400, 0x80) - mstore(0xac40, mload(add(X1_POWERS_MPTR, 0x1e0))) - mcopy(0xac60, 0x5480, 0x80) - mstore(0xace0, mload(add(X1_POWERS_MPTR, 0x200))) - mcopy(0xad00, 0x5800, 0x80) - mstore(0xad80, mload(add(X1_POWERS_MPTR, 0x220))) - mcopy(0xada0, 0x5880, 0x80) - mstore(0xae20, mload(add(X1_POWERS_MPTR, 0x240))) - mcopy(0xae40, 0x5900, 0x80) - mstore(0xaec0, mload(add(X1_POWERS_MPTR, 0x260))) - mcopy(0xaee0, 0x5980, 0x80) - mstore(0xaf60, mload(add(X1_POWERS_MPTR, 0x280))) - mcopy(0xaf80, 0x5b80, 0x80) - mstore(0xb000, mload(add(X1_POWERS_MPTR, 0x2a0))) - mcopy(0xb020, 0x5c80, 0x80) - mstore(0xb0a0, mload(add(X1_POWERS_MPTR, 0x2c0))) - mcopy(0xb0c0, 0x6000, 0x80) - mstore(0xb140, mload(add(X1_POWERS_MPTR, 0x2e0))) - mcopy(0xb160, 0x6080, 0x80) - mstore(0xb1e0, mload(add(X1_POWERS_MPTR, 0x300))) - mcopy(0xb200, 0x6100, 0x80) - mstore(0xb280, mload(add(X1_POWERS_MPTR, 0x320))) - mcopy(0xb2a0, 0x6180, 0x80) - mstore(0xb320, mload(add(X1_POWERS_MPTR, 0x340))) - mcopy(0xb340, 0x6200, 0x80) - mstore(0xb3c0, mload(add(X1_POWERS_MPTR, 0x360))) - mcopy(0xb3e0, 0x6280, 0x80) - mstore(0xb460, mload(add(X1_POWERS_MPTR, 0x380))) - mcopy(0xb480, 0x6300, 0x80) - mstore(0xb500, mload(add(X1_POWERS_MPTR, 0x3a0))) - mcopy(0xb520, 0x6380, 0x80) - mstore(0xb5a0, mload(add(X1_POWERS_MPTR, 0x3c0))) - mcopy(0xb5c0, 0x6400, 0x80) - mstore(0xb640, mload(add(X1_POWERS_MPTR, 0x3e0))) - mcopy(0xb660, 0x6480, 0x80) - mstore(0xb6e0, mload(add(X1_POWERS_MPTR, 0x400))) - mcopy(0xb700, 0x6500, 0x80) - mstore(0xb780, mload(add(X1_POWERS_MPTR, 0x420))) - mcopy(0xb7a0, 0x6580, 0x80) - mstore(0xb820, mload(add(X1_POWERS_MPTR, 0x440))) - mcopy(0xb840, 0x6600, 0x80) - mstore(0xb8c0, mload(add(X1_POWERS_MPTR, 0x460))) - mcopy(0xb8e0, 0x6680, 0x80) - mstore(0xb960, mload(add(X1_POWERS_MPTR, 0x480))) - mcopy(0xb980, 0x6700, 0x80) - mstore(0xba00, mload(add(X1_POWERS_MPTR, 0x4a0))) - mcopy(0xba20, 0x6780, 0x80) - mstore(0xbaa0, mload(add(X1_POWERS_MPTR, 0x4c0))) - mcopy(0xbac0, 0x6800, 0x80) - mstore(0xbb40, mload(add(X1_POWERS_MPTR, 0x4e0))) - mcopy(0xbb60, 0x6880, 0x80) - mstore(0xbbe0, mload(add(X1_POWERS_MPTR, 0x500))) - mcopy(0xbc00, 0x6900, 0x80) - mstore(0xbc80, mload(add(X1_POWERS_MPTR, 0x520))) + mcopy(0xb280, 0xa840, 0x80) + mstore(0xb300, 1) + mcopy(0xb320, 0xa8c0, 0x80) + mstore(0xb3a0, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0xb3c0, 0xacc0, 0x80) + mstore(0xb440, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0xb460, 0xa940, 0x80) + mstore(0xb4e0, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0xb500, 0xad40, 0x80) + mstore(0xb580, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0xb5a0, 0xaec0, 0x80) + mstore(0xb620, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0xb640, 0x6700, 0x80) + mstore(0xb6c0, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0xb6e0, 0x6480, 0x80) + mstore(0xb760, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0xb780, 0x6500, 0x80) + mstore(0xb800, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0xb820, 0x6580, 0x80) + mstore(0xb8a0, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0xb8c0, 0x6600, 0x80) + mstore(0xb940, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0xb960, 0x6680, 0x80) + mstore(0xb9e0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0xba00, 0x6280, 0x80) + mstore(0xba80, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0xbaa0, 0x6300, 0x80) + mstore(0xbb20, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0xbb40, 0x6380, 0x80) + mstore(0xbbc0, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0xbbe0, 0x6400, 0x80) + mstore(0xbc60, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0xbc80, 0x6780, 0x80) + mstore(0xbd00, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0xbd20, 0x6800, 0x80) + mstore(0xbda0, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0xbdc0, 0x6880, 0x80) + mstore(0xbe40, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0xbe60, 0x6900, 0x80) + mstore(0xbee0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0xbf00, 0x6b00, 0x80) + mstore(0xbf80, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0xbfa0, 0x6c00, 0x80) + mstore(0xc020, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0xc040, 0x6f80, 0x80) + mstore(0xc0c0, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0xc0e0, 0x7000, 0x80) + mstore(0xc160, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0xc180, 0x7080, 0x80) + mstore(0xc200, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0xc220, 0x7100, 0x80) + mstore(0xc2a0, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0xc2c0, 0x7180, 0x80) + mstore(0xc340, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0xc360, 0x7200, 0x80) + mstore(0xc3e0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0xc400, 0x7280, 0x80) + mstore(0xc480, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0xc4a0, 0x7300, 0x80) + mstore(0xc520, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0xc540, 0x7380, 0x80) + mstore(0xc5c0, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0xc5e0, 0x7400, 0x80) + mstore(0xc660, mload(add(X1_POWERS_MPTR, 0x400))) + mcopy(0xc680, 0x7480, 0x80) + mstore(0xc700, mload(add(X1_POWERS_MPTR, 0x420))) + mcopy(0xc720, 0x7500, 0x80) + mstore(0xc7a0, mload(add(X1_POWERS_MPTR, 0x440))) + mcopy(0xc7c0, 0x7580, 0x80) + mstore(0xc840, mload(add(X1_POWERS_MPTR, 0x460))) + mcopy(0xc860, 0x7600, 0x80) + mstore(0xc8e0, mload(add(X1_POWERS_MPTR, 0x480))) + mcopy(0xc900, 0x7680, 0x80) + mstore(0xc980, mload(add(X1_POWERS_MPTR, 0x4a0))) + mcopy(0xc9a0, 0x7700, 0x80) + mstore(0xca20, mload(add(X1_POWERS_MPTR, 0x4c0))) + mcopy(0xca40, 0x7780, 0x80) + mstore(0xcac0, mload(add(X1_POWERS_MPTR, 0x4e0))) + mcopy(0xcae0, 0x7800, 0x80) + mstore(0xcb60, mload(add(X1_POWERS_MPTR, 0x500))) + mcopy(0xcb80, 0x7880, 0x80) + mstore(0xcc00, mload(add(X1_POWERS_MPTR, 0x520))) let lin_query_scalar_41 := mload(add(X1_POWERS_MPTR, 0x540)) let lin_cur_scalar_41 := mulmod(lin_query_scalar_41, lin_one_minus_x_n, r) - mcopy(0xbca0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) - mstore(0xbd20, lin_cur_scalar_41) + mcopy(0xcc20, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0xcca0, lin_cur_scalar_41) lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) - mcopy(0xbd40, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) - mstore(0xbdc0, lin_cur_scalar_41) + mcopy(0xccc0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0xcd40, lin_cur_scalar_41) lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) - mcopy(0xbde0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) - mstore(0xbe60, lin_cur_scalar_41) + mcopy(0xcd60, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0xcde0, lin_cur_scalar_41) lin_cur_scalar_41 := mulmod(lin_cur_scalar_41, lin_x_split, r) - mcopy(0xbe80, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) - mstore(0xbf00, lin_cur_scalar_41) - mcopy(0xbf20, 0x5a00, 0x80) - mstore(0xbfa0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) - mcopy(0xbfc0, 0x5a80, 0x80) - mstore(0xc040, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) - mcopy(0xc060, 0x5b00, 0x80) - mstore(0xc0e0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) - mcopy(0xc100, 0x5c00, 0x80) - mstore(0xc180, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) - mcopy(0xc1a0, 0x5d00, 0x80) - mstore(0xc220, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) - mcopy(0xc240, 0x5d80, 0x80) - mstore(0xc2c0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) - mcopy(0xc2e0, 0x5e00, 0x80) - mstore(0xc360, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) - mcopy(0xc380, 0x5e80, 0x80) - mstore(0xc400, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) - mcopy(0xc420, 0x5f00, 0x80) - mstore(0xc4a0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) - mcopy(0xc4c0, 0x5f80, 0x80) - mstore(0xc540, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) - mcopy(0xc560, 0x9740, 0x80) - mstore(0xc5e0, x4_pow_1) - mcopy(0xc600, 0x97c0, 0x80) - mstore(0xc680, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) - mcopy(0xc6a0, 0x9840, 0x80) - mstore(0xc720, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) - mcopy(0xc740, 0x9cc0, 0x80) - mstore(0xc7c0, x4_pow_2) - mcopy(0xc7e0, 0x9e40, 0x80) - mstore(0xc860, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) - mcopy(0xc880, 0x9ec0, 0x80) - mstore(0xc900, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) - mcopy(0xc920, 0x91c0, 0x80) - mstore(0xc9a0, x4_pow_3) - mcopy(0xc9c0, 0x9240, 0x80) - mstore(0xca40, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) - mcopy(0xca60, 0x92c0, 0x80) - mstore(0xcae0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_3, r)) - mcopy(0xcb00, 0x9340, 0x80) - mstore(0xcb80, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_3, r)) - mcopy(0xcba0, 0x93c0, 0x80) - mstore(0xcc20, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_3, r)) - mcopy(0xcc40, 0x9440, 0x80) - mstore(0xccc0, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_3, r)) - mcopy(0xcce0, 0x94c0, 0x80) - mstore(0xcd60, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_3, r)) - mcopy(0xcd80, 0x9540, 0x80) - mstore(0xce00, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_3, r)) - mcopy(0xce20, 0x95c0, 0x80) - mstore(0xcea0, mulmod(mload(add(X1_POWERS_MPTR, 0x100)), x4_pow_3, r)) - mcopy(0xcec0, 0x9640, 0x80) - mstore(0xcf40, mulmod(mload(add(X1_POWERS_MPTR, 0x120)), x4_pow_3, r)) - mcopy(0xcf60, 0x96c0, 0x80) - mstore(0xcfe0, mulmod(mload(add(X1_POWERS_MPTR, 0x140)), x4_pow_3, r)) - mcopy(0xd000, 0x9a40, 0x80) - mstore(0xd080, x4_pow_4) - mcopy(0xd0a0, 0x9ac0, 0x80) - mstore(0xd120, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_4, r)) - mcopy(0xd140, 0x9b40, 0x80) - mstore(0xd1c0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_4, r)) - mcopy(0xd1e0, 0x9bc0, 0x80) - mstore(0xd260, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_4, r)) - mcopy(0xd280, 0x9c40, 0x80) - mstore(0xd300, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_4, r)) - mcopy(0xd320, F_COM_MPTR, 0x80) - mstore(0xd3a0, x4_pow_5) + mcopy(0xce00, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0xce80, lin_cur_scalar_41) + mcopy(0xcea0, 0x6980, 0x80) + mstore(0xcf20, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0xcf40, 0x6a00, 0x80) + mstore(0xcfc0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0xcfe0, 0x6a80, 0x80) + mstore(0xd060, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0xd080, 0x6b80, 0x80) + mstore(0xd100, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0xd120, 0x6c80, 0x80) + mstore(0xd1a0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) + mcopy(0xd1c0, 0x6d00, 0x80) + mstore(0xd240, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) + mcopy(0xd260, 0x6d80, 0x80) + mstore(0xd2e0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) + mcopy(0xd300, 0x6e00, 0x80) + mstore(0xd380, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) + mcopy(0xd3a0, 0x6e80, 0x80) + mstore(0xd420, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) + mcopy(0xd440, 0x6f00, 0x80) + mstore(0xd4c0, mulmod(lin_query_scalar_41, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) + mcopy(0xd4e0, 0xa6c0, 0x80) + mstore(0xd560, x4_pow_1) + mcopy(0xd580, 0xa740, 0x80) + mstore(0xd600, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0xd620, 0xa7c0, 0x80) + mstore(0xd6a0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0xd6c0, 0xac40, 0x80) + mstore(0xd740, x4_pow_2) + mcopy(0xd760, 0xadc0, 0x80) + mstore(0xd7e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0xd800, 0xae40, 0x80) + mstore(0xd880, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) + mcopy(0xd8a0, 0xa140, 0x80) + mstore(0xd920, x4_pow_3) + mcopy(0xd940, 0xa1c0, 0x80) + mstore(0xd9c0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) + mcopy(0xd9e0, 0xa240, 0x80) + mstore(0xda60, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_3, r)) + mcopy(0xda80, 0xa2c0, 0x80) + mstore(0xdb00, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_3, r)) + mcopy(0xdb20, 0xa340, 0x80) + mstore(0xdba0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_3, r)) + mcopy(0xdbc0, 0xa3c0, 0x80) + mstore(0xdc40, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_3, r)) + mcopy(0xdc60, 0xa440, 0x80) + mstore(0xdce0, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_3, r)) + mcopy(0xdd00, 0xa4c0, 0x80) + mstore(0xdd80, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_3, r)) + mcopy(0xdda0, 0xa540, 0x80) + mstore(0xde20, mulmod(mload(add(X1_POWERS_MPTR, 0x100)), x4_pow_3, r)) + mcopy(0xde40, 0xa5c0, 0x80) + mstore(0xdec0, mulmod(mload(add(X1_POWERS_MPTR, 0x120)), x4_pow_3, r)) + mcopy(0xdee0, 0xa640, 0x80) + mstore(0xdf60, mulmod(mload(add(X1_POWERS_MPTR, 0x140)), x4_pow_3, r)) + mcopy(0xdf80, 0xa9c0, 0x80) + mstore(0xe000, x4_pow_4) + mcopy(0xe020, 0xaa40, 0x80) + mstore(0xe0a0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_4, r)) + mcopy(0xe0c0, 0xaac0, 0x80) + mstore(0xe140, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_4, r)) + mcopy(0xe160, 0xab40, 0x80) + mstore(0xe1e0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_4, r)) + mcopy(0xe200, 0xabc0, 0x80) + mstore(0xe280, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_4, r)) + mcopy(0xe2a0, F_COM_MPTR, 0x80) + mstore(0xe320, x4_pow_5) if success { - success := staticcall(gas(), 0x0c, 0xa300, 0x30c0, FINAL_COM_MPTR, 0x80) + success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2078,28 +2166,28 @@ contract Halo2Verifier { // Scale z*pi - vG before the final pairing check // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) - mcopy(0x80, G1_BASE_MPTR, 0x80) - mstore(0x100, addmod(0, sub(r, mload(V_MPTR)), r)) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x80, 0xa0, 0x80, 0x80) + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, FINAL_COM_MPTR, 0x80) + mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, PI_MPTR, 0x80) - mstore(0x180, mload(X3_MPTR)) + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x100, 0xa0, 0x100, 0x80) + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(PAIRING_RHS_MPTR, 0x80, 0x80) + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } @@ -2181,6 +2269,12 @@ contract Halo2Verifier { // Success path is terminal. Invalid inputs have already reverted, // so the Solidity ABI observes `true`. + // + // The guard is redundant today -- every failure path above reverts + // rather than clearing `success` -- but it keeps acceptance a local + // property of this file instead of an invariant split across + // FinalPairing.yul and ec_pairing. + if iszero(success) { revert(0, 0) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol index 7aac985fc..f8c08652b 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol @@ -271,149 +271,149 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x19c0), 0x0456a29a706afacf2158850711006fe0acf6a437e9477bf6f782dfac86f2cf7b) // quotient_const mstore(add(payload, 0x19e0), 0x0397cc06bc030aab970dabe70cd498bbeea8daaea65607bb6a872125fec74a10) // quotient_const mstore(add(payload, 0x1a00), 0x73eda753299d7d4833351088b4af7508df8b737010b26e15294bfcbb91950003) // quotient_const - mstore(add(payload, 0x1a20), 0x058560108a8005860008060d000b02000105852011852011852005858008060d) // quotient_program - mstore(add(payload, 0x1a40), 0x000b0300000585401185401185400585a008060d000b03000105856011856011) // quotient_program - mstore(add(payload, 0x1a60), 0x856005862008060d000b0300011b00001b000105860008108b20058520118520) // quotient_program - mstore(add(payload, 0x1a80), 0x1185800d01060585401185401185a00d02060585601185601186200d03060d00) // quotient_program - mstore(add(payload, 0x1aa0), 0x0b0300011b000221020403070002000085200585400685600785800885a00085) // quotient_program - mstore(add(payload, 0x1ac0), 0xc00585e00686000986200a86400b86600c86800d86a00e86c00f86e010870011) // quotient_program - mstore(add(payload, 0x1ae0), 0x87200787400887600987800a87a085200085c00585e006860007874008876009) // quotient_program - mstore(add(payload, 0x1b00), 0x87800a87a085400585c00685e00786000887400987600a87801287a085600685) // quotient_program - mstore(add(payload, 0x1b20), 0xc00785e00886000987400a87601287801387a085800785c00885e00986000a87) // quotient_program - mstore(add(payload, 0x1b40), 0x401287601387801487a085a00885c00985e00a86001287401387601487801587) // quotient_program - mstore(add(payload, 0x1b60), 0xa086200985c00a85e01286001387401487601587801687a086400a85c01285e0) // quotient_program - mstore(add(payload, 0x1b80), 0x1386001487401587601687801787a01887c01988000b04000121021a03070001) // quotient_program - mstore(add(payload, 0x1ba0), 0x000085200585400685601b85801c85a00085c00585e00686001d86201e86400b) // quotient_program - mstore(add(payload, 0x1bc0), 0x86600c86800d86a01f86c02086e02187002287201b87401c87601d87801e87a0) // quotient_program - mstore(add(payload, 0x1be0), 0x85200085c00585e00686001b87401c87601d87801e87a085400585c00685e01b) // quotient_program - mstore(add(payload, 0x1c00), 0x86001c87401d87601e87802387a085600685c01b85e01c86001d87401e876023) // quotient_program - mstore(add(payload, 0x1c20), 0x87802487a085801b85c01c85e01d86001e87402387602487802587a085a01c85) // quotient_program - mstore(add(payload, 0x1c40), 0xc01d85e01e86002387402487602587802687a086201d85c01e85e02386002487) // quotient_program - mstore(add(payload, 0x1c60), 0x402587602687802787a086401e85c02385e02486002587402687602787802887) // quotient_program - mstore(add(payload, 0x1c80), 0xa02987c00b0400011b000321022a01000009000986200a86400b86600c86800d) // quotient_program - mstore(add(payload, 0x1ca0), 0x86a00e86c00f86e00085200585400685600785800885a01087001187201887c0) // quotient_program - mstore(add(payload, 0x1cc0), 0x1988000b05000121022b01000008001d86201e86400b86600c86800d86a01f86) // quotient_program - mstore(add(payload, 0x1ce0), 0xc02086e00085200585400685601b85801c85a02187002287202987c00b050001) // quotient_program - mstore(add(payload, 0x1d00), 0x210388202c0000000b2b0b85200c85400d85602d85c02e85e02f86000b86600c) // quotient_program - mstore(add(payload, 0x1d20), 0x86800d86a03087c03187e00b852086600c852086800d852086a00c854086600d) // quotient_program - mstore(add(payload, 0x1d40), 0x8540868032854087200d856086603285608700338560872032858086e0338580) // quotient_program - mstore(add(payload, 0x1d60), 0x870034858087203285a086c03385a086e03485a087003585a087200085c085c0) // quotient_program - mstore(add(payload, 0x1d80), 0x2e85c085e02f85c086000685e085e03685e087a0368600878037860087a03286) // quotient_program - mstore(add(payload, 0x1da0), 0x2086a033862086c034862086e035862087003886208720328640868033864086) // quotient_program - mstore(add(payload, 0x1dc0), 0xa034864086c035864086e038864087003986408720368740876037874087803a) // quotient_program - mstore(add(payload, 0x1de0), 0x874087a03b876087603a876087803c876087a03d878087803e878087a03f87a0) // quotient_program - mstore(add(payload, 0x1e00), 0x87a00d000b060000210388204003080002150b85200c85400d85600e85800f85) // quotient_program - mstore(add(payload, 0x1e20), 0xa02d85c02e85e02f86001086201186400b86600c86800d86a00e86c00f86e010) // quotient_program - mstore(add(payload, 0x1e40), 0x87001187204187404287604387804487a085200b86600c86800d86a00e86c00f) // quotient_program - mstore(add(payload, 0x1e60), 0x86e010870011872085400c86600d86800e86a00f86c01086e011870045872085) // quotient_program - mstore(add(payload, 0x1e80), 0x600d86600e86800f86a01086c01186e045870046872085800e86600f86801086) // quotient_program - mstore(add(payload, 0x1ea0), 0xa01186c04586e046870047872085a00f86601086801186a04586c04686e04787) // quotient_program - mstore(add(payload, 0x1ec0), 0x0048872085c00085c02e85e02f86004187404287604387804487a08620108660) // quotient_program - mstore(add(payload, 0x1ee0), 0x1186804586a04686c04786e048870049872086401186604586804686a04786c0) // quotient_program - mstore(add(payload, 0x1f00), 0x4886e04987004a87201887c01988000685e085e04185e086004285e087404385) // quotient_program - mstore(add(payload, 0x1f20), 0xe087604485e087804b85e087a00886008600438600874044860087604b860087) // quotient_program - mstore(add(payload, 0x1f40), 0x804c860087a00a874087404b874087604c874087804d874087a013876087604d) // quotient_program - mstore(add(payload, 0x1f60), 0x876087804e876087a015878087804f878087a01787a087a00d000b0600012103) // quotient_program - mstore(add(payload, 0x1f80), 0x88205003080001150b85200c85400d85601f85802085a02d85c02e85e02f8600) // quotient_program - mstore(add(payload, 0x1fa0), 0x2186202286400b86600c86800d86a01f86c02086e02187002287205187405287) // quotient_program - mstore(add(payload, 0x1fc0), 0x605387805487a085200b86600c86800d86a01f86c02086e02187002287208540) // quotient_program - mstore(add(payload, 0x1fe0), 0x0c86600d86801f86a02086c02186e022870055872085600d86601f86802086a0) // quotient_program - mstore(add(payload, 0x2000), 0x2186c02286e055870056872085801f86602086802186a02286c05586e0568700) // quotient_program - mstore(add(payload, 0x2020), 0x57872085a02086602186802286a05586c05686e057870058872085c00085c02e) // quotient_program - mstore(add(payload, 0x2040), 0x85e02f86005187405287605387805487a086202186602286805586a05686c057) // quotient_program - mstore(add(payload, 0x2060), 0x86e058870059872086402286605586805686a05786c05886e05987005a872029) // quotient_program - mstore(add(payload, 0x2080), 0x87c00685e085e05185e086005285e087405385e087605485e087805b85e087a0) // quotient_program - mstore(add(payload, 0x20a0), 0x1c86008600538600874054860087605b860087805c860087a01e874087405b87) // quotient_program - mstore(add(payload, 0x20c0), 0x4087605c874087805d874087a024876087605d876087805e876087a026878087) // quotient_program - mstore(add(payload, 0x20e0), 0x805f878087a02887a087a00d000b06000121038820600000000c390b85200c85) // quotient_program - mstore(add(payload, 0x2100), 0x400d85603087c03187e00088200088400588600688800b89200c89400d896000) // quotient_program - mstore(add(payload, 0x2120), 0x85c088400585c088600685c088800b85c089200c85c089400d85c089600585e0) // quotient_program - mstore(add(payload, 0x2140), 0x88400685e088606185e089000c85e089200d85e089403285e089e00686008840) // quotient_program - mstore(add(payload, 0x2160), 0x61860088e03b860089000d8600892032860089c033860089e000866088200586) // quotient_program - mstore(add(payload, 0x2180), 0x8088200686a0882061874088c03b874088e0628740890032874089a033874089) // quotient_program - mstore(add(payload, 0x21a0), 0xc034874089e061876088a03b876088c062876088e03d87608900328760898033) // quotient_program - mstore(add(payload, 0x21c0), 0x876089a034876089c035876089e061878088803b878088a062878088c03d8780) // quotient_program - mstore(add(payload, 0x21e0), 0x88e063878089003287808960338780898034878089a035878089c038878089e0) // quotient_program - mstore(add(payload, 0x2200), 0x6187a088603b87a088806287a088a03d87a088c06387a088e03f87a089003287) // quotient_program - mstore(add(payload, 0x2220), 0xa089403387a089603487a089803587a089a03887a089c03987a089e00d000b07) // quotient_program - mstore(add(payload, 0x2240), 0x00002103882064020f000a001988000088200088400588600688800788a00888) // quotient_program - mstore(add(payload, 0x2260), 0xc00988e00a89000b89200c89400d89600e89800f89a088200086600586800686) // quotient_program - mstore(add(payload, 0x2280), 0xa00786c00886e00987000a872088400085c00585e00686000787400887600987) // quotient_program - mstore(add(payload, 0x22a0), 0x800a87a088600585c00685e00786000887400987600a87801287a088800685c0) // quotient_program - mstore(add(payload, 0x22c0), 0x0785e00886000987400a87601287801387a088a00785c00885e00986000a8740) // quotient_program - mstore(add(payload, 0x22e0), 0x1287601387801487a088c00885c00985e00a86001287401387601487801587a0) // quotient_program - mstore(add(payload, 0x2300), 0x88e00985c00a85e01286001387401487601587801687a089000a85c01285e013) // quotient_program - mstore(add(payload, 0x2320), 0x86001487401587601687801787a085c00b89200c89400d89600e89800f89a010) // quotient_program - mstore(add(payload, 0x2340), 0x89c01189e085e00c89200d89400e89600f89801089a01189c04589e086000d89) // quotient_program - mstore(add(payload, 0x2360), 0x200e89400f89601089801189a04589c04689e087400e89200f89401089601189) // quotient_program - mstore(add(payload, 0x2380), 0x804589a04689c04789e087600f89201089401189604589804689a04789c04889) // quotient_program - mstore(add(payload, 0x23a0), 0xe087801089201189404589604689804789a04889c04989e087a0118920458940) // quotient_program - mstore(add(payload, 0x23c0), 0x4689604789804889a04989c04a89e00b85200c85400d85600e85800f85a01086) // quotient_program - mstore(add(payload, 0x23e0), 0x201186401887c01089c01189e00d000b0700012103882065020f000900008820) // quotient_program - mstore(add(payload, 0x2400), 0x0088400588600688801b88a01c88c01d88e01e89000b89200c89400d89601f89) // quotient_program - mstore(add(payload, 0x2420), 0x802089a02189c088200086600586800686a01b86c01c86e01d87001e87208840) // quotient_program - mstore(add(payload, 0x2440), 0x0085c00585e00686001b87401c87601d87801e87a088600585c00685e01b8600) // quotient_program - mstore(add(payload, 0x2460), 0x1c87401d87601e87802387a088800685c01b85e01c86001d87401e8760238780) // quotient_program - mstore(add(payload, 0x2480), 0x2487a088a01b85c01c85e01d86001e87402387602487802587a088c01c85c01d) // quotient_program - mstore(add(payload, 0x24a0), 0x85e01e86002387402487602587802687a088e01d85c01e85e023860024874025) // quotient_program - mstore(add(payload, 0x24c0), 0x87602687802787a089001e85c02385e02486002587402687602787802887a085) // quotient_program - mstore(add(payload, 0x24e0), 0xc00b89200c89400d89601f89802089a02189c02289e085e00c89200d89401f89) // quotient_program - mstore(add(payload, 0x2500), 0x602089802189a02289c05589e086000d89201f89402089602189802289a05589) // quotient_program - mstore(add(payload, 0x2520), 0xc05689e087401f89202089402189602289805589a05689c05789e08760208920) // quotient_program - mstore(add(payload, 0x2540), 0x2189402289605589805689a05789c05889e08780218920228940558960568980) // quotient_program - mstore(add(payload, 0x2560), 0x5789a05889c05989e087a02289205589405689605789805889a05989c05a89e0) // quotient_program - mstore(add(payload, 0x2580), 0x0b85200c85400d85601f85802085a02186202286402987c02289e00d000b0700) // quotient_program - mstore(add(payload, 0x25a0), 0x0121038820660000000b2b6785206885406985606a85c06b85e06c86006a8660) // quotient_program - mstore(add(payload, 0x25c0), 0x6b86806c86a03087c03187e06d85208520688520854069852085606e85408540) // quotient_program - mstore(add(payload, 0x25e0), 0x6f854086406f8560862070856086406f858085a0708580862071858086407285) // quotient_program - mstore(add(payload, 0x2600), 0xa085a07185a086207385a086406a85c086606b85c086806c85c086a06b85e086) // quotient_program - mstore(add(payload, 0x2620), 0x606c85e086807485e087206c8600866074860087007586008720768620862077) // quotient_program - mstore(add(payload, 0x2640), 0x86208640788640864074868087a07486a087807586a087a07486c087607586c0) // quotient_program - mstore(add(payload, 0x2660), 0x87807986c087a07486e087407586e087607986e087807a86e087a07587008740) // quotient_program - mstore(add(payload, 0x2680), 0x79870087607a870087807b870087a079872087407a872087607b872087807c87) // quotient_program - mstore(add(payload, 0x26a0), 0x2087a00d000b080000210388207d03080002156785206885406985607e85807f) // quotient_program - mstore(add(payload, 0x26c0), 0x85a06a85c06b85e06c86008086208186406a86606b86806c86a08286c08386e0) // quotient_program - mstore(add(payload, 0x26e0), 0x8487008587208287408387608487808587a085206d85206885406985607e8580) // quotient_program - mstore(add(payload, 0x2700), 0x7f85a080862081864085c06a86606b86806c86a08286c08386e0848700858720) // quotient_program - mstore(add(payload, 0x2720), 0x85e06b86606c86808286a08386c08486e085870086872086006c866082868083) // quotient_program - mstore(add(payload, 0x2740), 0x86a08486c08586e086870087872087408286608386808486a08586c08686e087) // quotient_program - mstore(add(payload, 0x2760), 0x870088872087608386608486808586a08686c08786e088870089872087808486) // quotient_program - mstore(add(payload, 0x2780), 0x608586808686a08786c08886e08987008a872087a08586608686808786a08886) // quotient_program - mstore(add(payload, 0x27a0), 0xc08986e08a87008b87201887c01988006e854085407e854085607f8540858080) // quotient_program - mstore(add(payload, 0x27c0), 0x854085a081854086208c854086408d85608560808560858081856085a08c8560) // quotient_program - mstore(add(payload, 0x27e0), 0x86208e856086408f858085808c858085a08e8580862090858086409185a085a0) // quotient_program - mstore(add(payload, 0x2800), 0x9085a086209285a086409386208620948620864095864086400d000b08000121) // quotient_program - mstore(add(payload, 0x2820), 0x0388209603080001156785206885406985609785809885a06a85c06b85e06c86) // quotient_program - mstore(add(payload, 0x2840), 0x009986209a86406a86606b86806c86a09b86c09c86e09d87009e87209b87409c) // quotient_program - mstore(add(payload, 0x2860), 0x87609d87809e87a085206d85206885406985609785809885a09986209a864085) // quotient_program - mstore(add(payload, 0x2880), 0xc06a86606b86806c86a09b86c09c86e09d87009e872085e06b86606c86809b86) // quotient_program - mstore(add(payload, 0x28a0), 0xa09c86c09d86e09e87009f872086006c86609b86809c86a09d86c09e86e09f87) // quotient_program - mstore(add(payload, 0x28c0), 0x00a0872087409b86609c86809d86a09e86c09f86e0a08700a1872087609c8660) // quotient_program - mstore(add(payload, 0x28e0), 0x9d86809e86a09f86c0a086e0a18700a2872087809d86609e86809f86a0a086c0) // quotient_program - mstore(add(payload, 0x2900), 0xa186e0a28700a3872087a09e86609f8680a086a0a186c0a286e0a38700a48720) // quotient_program - mstore(add(payload, 0x2920), 0x2987c06e854085409785408560988540858099854085a09a85408620a5854086) // quotient_program - mstore(add(payload, 0x2940), 0x40a68560856099856085809a856085a0a585608620a785608640a885808580a5) // quotient_program - mstore(add(payload, 0x2960), 0x858085a0a785808620a985808640aa85a085a0a985a08620ab85a08640ac8620) // quotient_program - mstore(add(payload, 0x2980), 0x8620ad86208640ae864086400d000b08000121038820af0000000e1000852005) // quotient_program - mstore(add(payload, 0x29a0), 0x85400685606a85c06b85e06c86000086600586800686a03087c03187e0008840) // quotient_program - mstore(add(payload, 0x29c0), 0x0588600688800b85c085c06b85c085e06c85c086000d85e085e07485e087a074) // quotient_program - mstore(add(payload, 0x29e0), 0x8600878075860087a07487408760758740878079874087a03387608760798760) // quotient_program - mstore(add(payload, 0x2a00), 0x87807a876087a035878087807b878087a03987a087a00d000b09000021038820) // quotient_program - mstore(add(payload, 0x2a20), 0xb004010002150085200585400685600785800885a06a85c06b85e06c86000986) // quotient_program - mstore(add(payload, 0x2a40), 0x200a86400086600586800686a00786c00886e00987000a872082874083876084) // quotient_program - mstore(add(payload, 0x2a60), 0x87808587a00088400588600688800788a00888c00988e00a890085c00b85c06b) // quotient_program - mstore(add(payload, 0x2a80), 0x85e06c86008287408387608487808587a01887c01988000d85e085e08285e086) // quotient_program - mstore(add(payload, 0x2aa0), 0x008385e087408485e087608585e087808685e087a00f86008600848600874085) // quotient_program - mstore(add(payload, 0x2ac0), 0x86008760868600878087860087a0118740874086874087608787408780888740) // quotient_program - mstore(add(payload, 0x2ae0), 0x87a04687608760888760878089876087a048878087808a878087a04a87a087a0) // quotient_program - mstore(add(payload, 0x2b00), 0x0d000b09000121038820b104010001150085200585400685601b85801c85a06a) // quotient_program - mstore(add(payload, 0x2b20), 0x85c06b85e06c86001d86201e86400086600586800686a01b86c01c86e01d8700) // quotient_program - mstore(add(payload, 0x2b40), 0x1e87209b87409c87609d87809e87a00088400588600688801b88a01c88c01d88) // quotient_program - mstore(add(payload, 0x2b60), 0xe01e890085c00b85c06b85e06c86009b87409c87609d87809e87a02987c00d85) // quotient_program - mstore(add(payload, 0x2b80), 0xe085e09b85e086009c85e087409d85e087609e85e087809f85e087a020860086) // quotient_program - mstore(add(payload, 0x2ba0), 0x009d860087409e860087609f86008780a0860087a022874087409f87408760a0) // quotient_program - mstore(add(payload, 0x2bc0), 0x87408780a1874087a05687608760a187608780a2876087a05887808780a38780) // quotient_program - mstore(add(payload, 0x2be0), 0x87a05a87a087a00d000b090001191f0000000000000000000000000000000000) // quotient_program + mstore(add(payload, 0x1a20), 0x0594e0109a0005958008060d000b0200010594a01194a01194a005950008060d) // quotient_program + mstore(add(payload, 0x1a40), 0x000b0300000594c01194c01194c005952008060d000b0300010594e01194e011) // quotient_program + mstore(add(payload, 0x1a60), 0x94e00595a008060d000b0300011b00001b000105958008109aa00594a01194a0) // quotient_program + mstore(add(payload, 0x1a80), 0x1195000d01060594c01194c01195200d02060594e01194e01195a00d03060d00) // quotient_program + mstore(add(payload, 0x1aa0), 0x0b0300011b000221020403070002000094a00594c00694e00795000895200095) // quotient_program + mstore(add(payload, 0x1ac0), 0x400595600695800995a00a95c00b95e00c96000d96200e96400f966010968011) // quotient_program + mstore(add(payload, 0x1ae0), 0x96a00796c00896e00997000a972094a00095400595600695800796c00896e009) // quotient_program + mstore(add(payload, 0x1b00), 0x97000a972094c00595400695600795800896c00996e00a970012972094e00695) // quotient_program + mstore(add(payload, 0x1b20), 0x400795600895800996c00a96e012970013972095000795400895600995800a96) // quotient_program + mstore(add(payload, 0x1b40), 0xc01296e013970014972095200895400995600a95801296c01396e01497001597) // quotient_program + mstore(add(payload, 0x1b60), 0x2095a00995400a95601295801396c01496e015970016972095c00a9540129560) // quotient_program + mstore(add(payload, 0x1b80), 0x1395801496c01596e01697001797201897401997800b04000121021a03070001) // quotient_program + mstore(add(payload, 0x1ba0), 0x000094a00594c00694e01b95001c95200095400595600695801d95a01e95c00b) // quotient_program + mstore(add(payload, 0x1bc0), 0x95e00c96000d96201f96402096602196802296a01b96c01c96e01d97001e9720) // quotient_program + mstore(add(payload, 0x1be0), 0x94a00095400595600695801b96c01c96e01d97001e972094c00595400695601b) // quotient_program + mstore(add(payload, 0x1c00), 0x95801c96c01d96e01e970023972094e00695401b95601c95801d96c01e96e023) // quotient_program + mstore(add(payload, 0x1c20), 0x970024972095001b95401c95601d95801e96c02396e024970025972095201c95) // quotient_program + mstore(add(payload, 0x1c40), 0x401d95601e95802396c02496e025970026972095a01d95401e95602395802496) // quotient_program + mstore(add(payload, 0x1c60), 0xc02596e026970027972095c01e95402395602495802596c02696e02797002897) // quotient_program + mstore(add(payload, 0x1c80), 0x202997400b0400011b000321022a01000009000995a00a95c00b95e00c96000d) // quotient_program + mstore(add(payload, 0x1ca0), 0x96200e96400f96600094a00594c00694e00795000895201096801196a0189740) // quotient_program + mstore(add(payload, 0x1cc0), 0x1997800b05000121022b01000008001d95a01e95c00b95e00c96000d96201f96) // quotient_program + mstore(add(payload, 0x1ce0), 0x402096600094a00594c00694e01b95001c95202196802296a02997400b050001) // quotient_program + mstore(add(payload, 0x1d00), 0x210397a02c0000000b2b0b94a00c94c00d94e02d95402e95602f95800b95e00c) // quotient_program + mstore(add(payload, 0x1d20), 0x96000d96203097403197600b94a095e00c94a096000d94a096200c94c095e00d) // quotient_program + mstore(add(payload, 0x1d40), 0x94c096003294c096a00d94e095e03294e096803394e096a03295009660339500) // quotient_program + mstore(add(payload, 0x1d60), 0x968034950096a032952096403395209660349520968035952096a00095409540) // quotient_program + mstore(add(payload, 0x1d80), 0x2e954095602f9540958006956095603695609720369580970037958097203295) // quotient_program + mstore(add(payload, 0x1da0), 0xa096203395a096403495a096603595a096803895a096a03295c096003395c096) // quotient_program + mstore(add(payload, 0x1dc0), 0x203495c096403595c096603895c096803995c096a03696c096e03796c097003a) // quotient_program + mstore(add(payload, 0x1de0), 0x96c097203b96e096e03a96e097003c96e097203d970097003e970097203f9720) // quotient_program + mstore(add(payload, 0x1e00), 0x97200d000b060000210397a04003080002150b94a00c94c00d94e00e95000f95) // quotient_program + mstore(add(payload, 0x1e20), 0x202d95402e95602f95801095a01195c00b95e00c96000d96200e96400f966010) // quotient_program + mstore(add(payload, 0x1e40), 0x96801196a04196c04296e043970044972094a00b95e00c96000d96200e96400f) // quotient_program + mstore(add(payload, 0x1e60), 0x96601096801196a094c00c95e00d96000e96200f96401096601196804596a094) // quotient_program + mstore(add(payload, 0x1e80), 0xe00d95e00e96000f96201096401196604596804696a095000e95e00f96001096) // quotient_program + mstore(add(payload, 0x1ea0), 0x201196404596604696804796a095200f95e01096001196204596404696604796) // quotient_program + mstore(add(payload, 0x1ec0), 0x804896a095400095402e95602f95804196c04296e043970044972095a01095e0) // quotient_program + mstore(add(payload, 0x1ee0), 0x1196004596204696404796604896804996a095c01195e0459600469620479640) // quotient_program + mstore(add(payload, 0x1f00), 0x4896604996804a96a01897401997800695609560419560958042956096c04395) // quotient_program + mstore(add(payload, 0x1f20), 0x6096e044956097004b95609720089580958043958096c044958096e04b958097) // quotient_program + mstore(add(payload, 0x1f40), 0x004c958097200a96c096c04b96c096e04c96c097004d96c097201396e096e04d) // quotient_program + mstore(add(payload, 0x1f60), 0x96e097004e96e0972015970097004f9700972017972097200d000b0600012103) // quotient_program + mstore(add(payload, 0x1f80), 0x97a05003080001150b94a00c94c00d94e01f95002095202d95402e95602f9580) // quotient_program + mstore(add(payload, 0x1fa0), 0x2195a02295c00b95e00c96000d96201f96402096602196802296a05196c05296) // quotient_program + mstore(add(payload, 0x1fc0), 0xe053970054972094a00b95e00c96000d96201f96402096602196802296a094c0) // quotient_program + mstore(add(payload, 0x1fe0), 0x0c95e00d96001f96202096402196602296805596a094e00d95e01f9600209620) // quotient_program + mstore(add(payload, 0x2000), 0x2196402296605596805696a095001f95e0209600219620229640559660569680) // quotient_program + mstore(add(payload, 0x2020), 0x5796a095202095e02196002296205596405696605796805896a095400095402e) // quotient_program + mstore(add(payload, 0x2040), 0x95602f95805196c05296e053970054972095a02195e022960055962056964057) // quotient_program + mstore(add(payload, 0x2060), 0x96605896805996a095c02295e05596005696205796405896605996805a96a029) // quotient_program + mstore(add(payload, 0x2080), 0x97400695609560519560958052956096c053956096e054956097005b95609720) // quotient_program + mstore(add(payload, 0x20a0), 0x1c9580958053958096c054958096e05b958097005c958097201e96c096c05b96) // quotient_program + mstore(add(payload, 0x20c0), 0xc096e05c96c097005d96c097202496e096e05d96e097005e96e0972026970097) // quotient_program + mstore(add(payload, 0x20e0), 0x005f9700972028972097200d000b060001210397a0600000000c390b94a00c94) // quotient_program + mstore(add(payload, 0x2100), 0xc00d94e03097403197600097a00097c00597e00698000b98a00c98c00d98e000) // quotient_program + mstore(add(payload, 0x2120), 0x954097c005954097e006954098000b954098a00c954098c00d954098e0059560) // quotient_program + mstore(add(payload, 0x2140), 0x97c006956097e061956098800c956098a00d956098c0329560996006958097c0) // quotient_program + mstore(add(payload, 0x2160), 0x61958098603b958098800d958098a0329580994033958099600095e097a00596) // quotient_program + mstore(add(payload, 0x2180), 0x0097a006962097a06196c098403b96c098606296c098803296c099203396c099) // quotient_program + mstore(add(payload, 0x21a0), 0x403496c099606196e098203b96e098406296e098603d96e098803296e0990033) // quotient_program + mstore(add(payload, 0x21c0), 0x96e099203496e099403596e0996061970098003b9700982062970098403d9700) // quotient_program + mstore(add(payload, 0x21e0), 0x9860639700988032970098e03397009900349700992035970099403897009960) // quotient_program + mstore(add(payload, 0x2200), 0x61972097e03b9720980062972098203d9720984063972098603f972098803297) // quotient_program + mstore(add(payload, 0x2220), 0x2098c033972098e034972099003597209920389720994039972099600d000b07) // quotient_program + mstore(add(payload, 0x2240), 0x0000210397a064020f000a001997800097a00097c00597e00698000798200898) // quotient_program + mstore(add(payload, 0x2260), 0x400998600a98800b98a00c98c00d98e00e99000f992097a00095e00596000696) // quotient_program + mstore(add(payload, 0x2280), 0x200796400896600996800a96a097c00095400595600695800796c00896e00997) // quotient_program + mstore(add(payload, 0x22a0), 0x000a972097e00595400695600795800896c00996e00a97001297209800069540) // quotient_program + mstore(add(payload, 0x22c0), 0x0795600895800996c00a96e012970013972098200795400895600995800a96c0) // quotient_program + mstore(add(payload, 0x22e0), 0x1296e013970014972098400895400995600a95801296c01396e0149700159720) // quotient_program + mstore(add(payload, 0x2300), 0x98600995400a95601295801396c01496e015970016972098800a954012956013) // quotient_program + mstore(add(payload, 0x2320), 0x95801496c01596e016970017972095400b98a00c98c00d98e00e99000f992010) // quotient_program + mstore(add(payload, 0x2340), 0x994011996095600c98a00d98c00e98e00f990010992011994045996095800d98) // quotient_program + mstore(add(payload, 0x2360), 0xa00e98c00f98e010990011992045994046996096c00e98a00f98c01098e01199) // quotient_program + mstore(add(payload, 0x2380), 0x0045992046994047996096e00f98a01098c01198e04599004699204799404899) // quotient_program + mstore(add(payload, 0x23a0), 0x6097001098a01198c04598e046990047992048994049996097201198a04598c0) // quotient_program + mstore(add(payload, 0x23c0), 0x4698e04799004899204999404a99600b94a00c94c00d94e00e95000f95201095) // quotient_program + mstore(add(payload, 0x23e0), 0xa01195c01897401099401199600d000b070001210397a065020f0009000097a0) // quotient_program + mstore(add(payload, 0x2400), 0x0097c00597e00698001b98201c98401d98601e98800b98a00c98c00d98e01f99) // quotient_program + mstore(add(payload, 0x2420), 0x0020992021994097a00095e00596000696201b96401c96601d96801e96a097c0) // quotient_program + mstore(add(payload, 0x2440), 0x0095400595600695801b96c01c96e01d97001e972097e00595400695601b9580) // quotient_program + mstore(add(payload, 0x2460), 0x1c96c01d96e01e970023972098000695401b95601c95801d96c01e96e0239700) // quotient_program + mstore(add(payload, 0x2480), 0x24972098201b95401c95601d95801e96c02396e024970025972098401c95401d) // quotient_program + mstore(add(payload, 0x24a0), 0x95601e95802396c02496e025970026972098601d95401e95602395802496c025) // quotient_program + mstore(add(payload, 0x24c0), 0x96e026970027972098801e95402395602495802596c02696e027970028972095) // quotient_program + mstore(add(payload, 0x24e0), 0x400b98a00c98c00d98e01f990020992021994022996095600c98a00d98c01f98) // quotient_program + mstore(add(payload, 0x2500), 0xe020990021992022994055996095800d98a01f98c02098e02199002299205599) // quotient_program + mstore(add(payload, 0x2520), 0x4056996096c01f98a02098c02198e022990055992056994057996096e02098a0) // quotient_program + mstore(add(payload, 0x2540), 0x2198c02298e055990056992057994058996097002198a02298c05598e0569900) // quotient_program + mstore(add(payload, 0x2560), 0x57992058994059996097202298a05598c05698e05799005899205999405a9960) // quotient_program + mstore(add(payload, 0x2580), 0x0b94a00c94c00d94e01f95002095202195a02295c02997402299600d000b0700) // quotient_program + mstore(add(payload, 0x25a0), 0x01210397a0660000000b2b6794a06894c06994e06a95406b95606c95806a95e0) // quotient_program + mstore(add(payload, 0x25c0), 0x6b96006c96203097403197606d94a094a06894a094c06994a094e06e94c094c0) // quotient_program + mstore(add(payload, 0x25e0), 0x6f94c095c06f94e095a07094e095c06f9500952070950095a071950095c07295) // quotient_program + mstore(add(payload, 0x2600), 0x20952071952095a073952095c06a954095e06b954096006c954096206b956095) // quotient_program + mstore(add(payload, 0x2620), 0xe06c9560960074956096a06c958095e0749580968075958096a07695a095a077) // quotient_program + mstore(add(payload, 0x2640), 0x95a095c07895c095c074960097207496209700759620972074964096e0759640) // quotient_program + mstore(add(payload, 0x2660), 0x9700799640972074966096c075966096e079966097007a9660972075968096c0) // quotient_program + mstore(add(payload, 0x2680), 0x79968096e07a968097007b968097207996a096c07a96a096e07b96a097007c96) // quotient_program + mstore(add(payload, 0x26a0), 0xa097200d000b080000210397a07d03080002156794a06894c06994e07e95007f) // quotient_program + mstore(add(payload, 0x26c0), 0x95206a95406b95606c95808095a08195c06a95e06b96006c9620829640839660) // quotient_program + mstore(add(payload, 0x26e0), 0x8496808596a08296c08396e084970085972094a06d94a06894c06994e07e9500) // quotient_program + mstore(add(payload, 0x2700), 0x7f95208095a08195c095406a95e06b96006c96208296408396608496808596a0) // quotient_program + mstore(add(payload, 0x2720), 0x95606b95e06c96008296208396408496608596808696a095806c95e082960083) // quotient_program + mstore(add(payload, 0x2740), 0x96208496408596608696808796a096c08295e083960084962085964086966087) // quotient_program + mstore(add(payload, 0x2760), 0x96808896a096e08395e08496008596208696408796608896808996a097008495) // quotient_program + mstore(add(payload, 0x2780), 0xe08596008696208796408896608996808a96a097208595e08696008796208896) // quotient_program + mstore(add(payload, 0x27a0), 0x408996608a96808b96a01897401997806e94c094c07e94c094e07f94c0950080) // quotient_program + mstore(add(payload, 0x27c0), 0x94c095208194c095a08c94c095c08d94e094e08094e095008194e095208c94e0) // quotient_program + mstore(add(payload, 0x27e0), 0x95a08e94e095c08f950095008c950095208e950095a090950095c09195209520) // quotient_program + mstore(add(payload, 0x2800), 0x90952095a092952095c09395a095a09495a095c09595c095c00d000b08000121) // quotient_program + mstore(add(payload, 0x2820), 0x0397a09603080001156794a06894c06994e09795009895206a95406b95606c95) // quotient_program + mstore(add(payload, 0x2840), 0x809995a09a95c06a95e06b96006c96209b96409c96609d96809e96a09b96c09c) // quotient_program + mstore(add(payload, 0x2860), 0x96e09d97009e972094a06d94a06894c06994e09795009895209995a09a95c095) // quotient_program + mstore(add(payload, 0x2880), 0x406a95e06b96006c96209b96409c96609d96809e96a095606b95e06c96009b96) // quotient_program + mstore(add(payload, 0x28a0), 0x209c96409d96609e96809f96a095806c95e09b96009c96209d96409e96609f96) // quotient_program + mstore(add(payload, 0x28c0), 0x80a096a096c09b95e09c96009d96209e96409f9660a09680a196a096e09c95e0) // quotient_program + mstore(add(payload, 0x28e0), 0x9d96009e96209f9640a09660a19680a296a097009d95e09e96009f9620a09640) // quotient_program + mstore(add(payload, 0x2900), 0xa19660a29680a396a097209e95e09f9600a09620a19640a29660a39680a496a0) // quotient_program + mstore(add(payload, 0x2920), 0x2997406e94c094c09794c094e09894c095009994c095209a94c095a0a594c095) // quotient_program + mstore(add(payload, 0x2940), 0xc0a694e094e09994e095009a94e09520a594e095a0a794e095c0a895009500a5) // quotient_program + mstore(add(payload, 0x2960), 0x95009520a7950095a0a9950095c0aa95209520a9952095a0ab952095c0ac95a0) // quotient_program + mstore(add(payload, 0x2980), 0x95a0ad95a095c0ae95c095c00d000b080001210397a0af0000000e100094a005) // quotient_program + mstore(add(payload, 0x29a0), 0x94c00694e06a95406b95606c95800095e00596000696203097403197600097c0) // quotient_program + mstore(add(payload, 0x29c0), 0x0597e00698000b954095406b954095606c954095800d95609560749560972074) // quotient_program + mstore(add(payload, 0x29e0), 0x9580970075958097207496c096e07596c097007996c097203396e096e07996e0) // quotient_program + mstore(add(payload, 0x2a00), 0x97007a96e0972035970097007b9700972039972097200d000b090000210397a0) // quotient_program + mstore(add(payload, 0x2a20), 0xb004010002150094a00594c00694e00795000895206a95406b95606c95800995) // quotient_program + mstore(add(payload, 0x2a40), 0xa00a95c00095e00596000696200796400896600996800a96a08296c08396e084) // quotient_program + mstore(add(payload, 0x2a60), 0x97008597200097c00597e00698000798200898400998600a988095400b95406b) // quotient_program + mstore(add(payload, 0x2a80), 0x95606c95808296c08396e08497008597201897401997800d9560956082956095) // quotient_program + mstore(add(payload, 0x2aa0), 0x8083956096c084956096e0859560970086956097200f9580958084958096c085) // quotient_program + mstore(add(payload, 0x2ac0), 0x958096e0869580970087958097201196c096c08696c096e08796c097008896c0) // quotient_program + mstore(add(payload, 0x2ae0), 0x97204696e096e08896e097008996e0972048970097008a970097204a97209720) // quotient_program + mstore(add(payload, 0x2b00), 0x0d000b090001210397a0b104010001150094a00594c00694e01b95001c95206a) // quotient_program + mstore(add(payload, 0x2b20), 0x95406b95606c95801d95a01e95c00095e00596000696201b96401c96601d9680) // quotient_program + mstore(add(payload, 0x2b40), 0x1e96a09b96c09c96e09d97009e97200097c00597e00698001b98201c98401d98) // quotient_program + mstore(add(payload, 0x2b60), 0x601e988095400b95406b95606c95809b96c09c96e09d97009e97202997400d95) // quotient_program + mstore(add(payload, 0x2b80), 0x6095609b956095809c956096c09d956096e09e956097009f9560972020958095) // quotient_program + mstore(add(payload, 0x2ba0), 0x809d958096c09e958096e09f95809700a0958097202296c096c09f96c096e0a0) // quotient_program + mstore(add(payload, 0x2bc0), 0x96c09700a196c097205696e096e0a196e09700a296e097205897009700a39700) // quotient_program + mstore(add(payload, 0x2be0), 0x97205a972097200d000b090001191f0000000000000000000000000000000000) // quotient_program // Fixed-column commitment 0, stored as one // EIP-2537 padded uncompressed G1 slot. mstore(add(payload, 0x2c00), 0x00000000000000000000000000000000055f7961345dce7ce57401dd993cc81a) // fixed_comms[0].x_hi diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index e5f1b4029..8a2e5f8cf 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -43,7 +43,7 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 4576; uint256 internal constant EXPECTED_VK_LENGTH = 4577; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0xf2c10777bfd922a3700fb18f2e9a2894dfa51dd920f6261bba71ed8b5363e495; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x233a1a8063ef1a9bfd30983d3034d3d90ab75ff6ac95c0e72d770bf08dcff51b; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -55,8 +55,8 @@ contract Halo2Verifier { uint256 internal constant INSTANCE_CPTR = 0x1164; // First general-purpose memory words reserved by the generated verifier. // RETURN_MPTR is a single word set to 1 on success. - uint256 internal constant TRANSCRIPT_MPTR = 0x80; - uint256 internal constant RETURN_MPTR = 0x80; + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; // ---------------------------------------------------------------------- // Verifying-key memory map. The VK header lives at VK_MPTR, followed @@ -64,84 +64,84 @@ contract Halo2Verifier { // runtime comes the challenge slots (challenge_mptr..) and the // per-stage scratch (theta_mptr..). // ---------------------------------------------------------------------- - uint256 internal constant VK_MPTR = 0x1980; - uint256 internal constant VK_DIGEST_MPTR = 0x1980; - uint256 internal constant NUM_INSTANCES_MPTR = 0x19a0; - uint256 internal constant K_MPTR = 0x19c0; - uint256 internal constant N_INV_MPTR = 0x19e0; - uint256 internal constant OMEGA_MPTR = 0x1a00; - uint256 internal constant OMEGA_INV_MPTR = 0x1a20; - uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x1a40; - uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x1a60; - uint256 internal constant ACC_OFFSET_MPTR = 0x1a80; - uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x1aa0; - uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x1ac0; - uint256 internal constant G1_BASE_MPTR = 0x1ae0; - uint256 internal constant G2_BASE_MPTR = 0x1b60; - uint256 internal constant NEG_S_G2_BASE_MPTR = 0x1c60; - - uint256 internal constant CHALLENGE_MPTR = 0x2b60; + uint256 internal constant VK_MPTR = 0x2900; + uint256 internal constant VK_DIGEST_MPTR = 0x2900; + uint256 internal constant NUM_INSTANCES_MPTR = 0x2920; + uint256 internal constant K_MPTR = 0x2940; + uint256 internal constant N_INV_MPTR = 0x2960; + uint256 internal constant OMEGA_MPTR = 0x2980; + uint256 internal constant OMEGA_INV_MPTR = 0x29a0; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x29c0; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x29e0; + uint256 internal constant ACC_OFFSET_MPTR = 0x2a00; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x2a20; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x2a40; + uint256 internal constant G1_BASE_MPTR = 0x2a60; + uint256 internal constant G2_BASE_MPTR = 0x2ae0; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x2be0; + + uint256 internal constant CHALLENGE_MPTR = 0x3ae0; // Challenge layout. Squeeze order in midnight-proofs: // user_phase challenges (variable count) // theta -> beta, gamma -> trash_challenge -> y -> x -> // x1, x2 -> x3 -> x4 - uint256 internal constant THETA_MPTR = 0x2b60; - uint256 internal constant BETA_MPTR = 0x2b80; - uint256 internal constant GAMMA_MPTR = 0x2ba0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x2bc0; - uint256 internal constant Y_MPTR = 0x2be0; - uint256 internal constant X_MPTR = 0x2c00; - uint256 internal constant X1_MPTR = 0x2c20; - uint256 internal constant X2_MPTR = 0x2c40; - uint256 internal constant X3_MPTR = 0x2c60; - uint256 internal constant X4_MPTR = 0x2c80; + uint256 internal constant THETA_MPTR = 0x3ae0; + uint256 internal constant BETA_MPTR = 0x3b00; + uint256 internal constant GAMMA_MPTR = 0x3b20; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x3b40; + uint256 internal constant Y_MPTR = 0x3b60; + uint256 internal constant X_MPTR = 0x3b80; + uint256 internal constant X1_MPTR = 0x3ba0; + uint256 internal constant X2_MPTR = 0x3bc0; + uint256 internal constant X3_MPTR = 0x3be0; + uint256 internal constant X4_MPTR = 0x3c00; // Batch-open commitments live in 4-word EIP-2537 padded slots. - uint256 internal constant F_COM_MPTR = 0x2ca0; - uint256 internal constant PI_MPTR = 0x2d20; + uint256 internal constant F_COM_MPTR = 0x3c20; + uint256 internal constant PI_MPTR = 0x3ca0; // Accumulator (KZG IVC). - uint256 internal constant ACC_LHS_MPTR = 0x2da0; - uint256 internal constant ACC_RHS_MPTR = 0x2e20; + uint256 internal constant ACC_LHS_MPTR = 0x3d20; + uint256 internal constant ACC_RHS_MPTR = 0x3da0; // Lagrange / linearization scratch. - uint256 internal constant X_N_MPTR = 0x2ea0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x2ec0; - uint256 internal constant L_LAST_MPTR = 0x2ee0; - uint256 internal constant L_BLIND_MPTR = 0x2f00; - uint256 internal constant L_0_MPTR = 0x2f20; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x2f40; + uint256 internal constant X_N_MPTR = 0x3e20; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x3e40; + uint256 internal constant L_LAST_MPTR = 0x3e60; + uint256 internal constant L_BLIND_MPTR = 0x3e80; + uint256 internal constant L_0_MPTR = 0x3ea0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x3ec0; // Legacy name: this is not h(x). It stores the expected opening // scalar for the linearized commitment, i.e. the negated y-batched // identity numerator reconstructed from the alleged evals at x. - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x2f60; - uint256 internal constant QUOTIENT_MPTR = 0x2f80; // 4 words - uint256 internal constant F_EVAL_MPTR = 0x3020; - uint256 internal constant V_MPTR = 0x3040; - uint256 internal constant FINAL_COM_MPTR = 0x3060; // 4 words - uint256 internal constant PAIRING_LHS_MPTR = 0x30e0; // 4 words - uint256 internal constant PAIRING_RHS_MPTR = 0x3160; // 4 words + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x3ee0; + uint256 internal constant QUOTIENT_MPTR = 0x3f00; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x3fa0; + uint256 internal constant V_MPTR = 0x3fc0; + uint256 internal constant FINAL_COM_MPTR = 0x3fe0; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x4060; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x40e0; // 4 words // Multi-prepare scratch (sized at codegen time). - uint256 internal constant ROT_POINTS_MPTR = 0x31e0; - uint256 internal constant X1_POWERS_MPTR = 0x3560; + uint256 internal constant ROT_POINTS_MPTR = 0x4160; + uint256 internal constant X1_POWERS_MPTR = 0x44e0; // Q_COM materialization is currently fused into the final MSM scratch, // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero // reserved capacity until a future emitter starts writing Q_COM_MPTR. - uint256 internal constant Q_COM_MPTR = 0x3d80; - uint256 internal constant Q_EVAL_SET_MPTR = 0x3d80; + uint256 internal constant Q_COM_MPTR = 0x4d00; + uint256 internal constant Q_EVAL_SET_MPTR = 0x4d00; // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals // block of the proof; we keep it as a memory slot for symmetry. - uint256 internal constant Q_EVAL_CPTR_MPTR = 0x4480; + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x5400; // Reserved 4-word slot for the G1 identity (point at infinity) in // EIP-2537 padded form. EVM memory is zero-initialised, and we // never write to this region, so the four `mload`s below produce // 0,0,0,0 which is exactly the identity encoding the EIP-2537 // ec_add / ec_mul precompiles accept. - uint256 internal constant G1_IDENTITY_MPTR = 0x4580; + uint256 internal constant G1_IDENTITY_MPTR = 0x5500; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain // Solidity proof shim rewrites proof scalars into canonical BE words, @@ -149,11 +149,11 @@ contract Halo2Verifier { // side `evaluations` loop range-checks and spills that value here so // downstream eval references (gate evaluator + PCS q_eval Horner) // become 3-gas `mload(...)` instead of calldata reads. - uint256 internal constant REVERSED_EVALS_MPTR = 0x46e0; - uint256 internal constant SELECTOR_ACC_MPTR = 0x5660; - uint256 internal constant QUOTIENT_RETURN_MPTR = 0x80; - uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x5660; - uint256 internal constant TRACE_U256_MPTR = 0x7440; + uint256 internal constant REVERSED_EVALS_MPTR = 0x5660; + uint256 internal constant SELECTOR_ACC_MPTR = 0x65e0; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x65e0; + uint256 internal constant TRACE_U256_MPTR = 0x83c0; // ---------------------------------------------------------------------- // Per-category bases for EIP-2537 padded G1 commitments. The proof @@ -170,13 +170,13 @@ contract Halo2Verifier { // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans // ---------------------------------------------------------------------- - uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x4ce0; - uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x50e0; - uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x5160; - uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x52e0; - uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x5360; - uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x53e0; - uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x5460; + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x5c60; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x6060; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x60e0; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x6260; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x62e0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x6360; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x63e0; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. @@ -198,7 +198,7 @@ contract Halo2Verifier { function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Scratch is reused for every runtime-prerequisite probe. - let scratch := 0x80 + let scratch := 0x1000 // MCOPY must be available because the verifier uses it for // proof-time point/scratch staging. Execute the opcode here so a @@ -222,11 +222,44 @@ contract Halo2Verifier { revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair // smoke call. - let msm_scratch := 0x5660 + let msm_scratch := 0x65e0 for { let off := 0 } lt(off, 0x1d60) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } @@ -329,7 +362,7 @@ contract Halo2Verifier { // guards against a future emitter passing a raw scalar. if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } - let p := 0x1880 + let p := 0x2800 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] mstore(add(p, 0x00), 0x20) // base len @@ -566,7 +599,11 @@ contract Halo2Verifier { mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } @@ -598,7 +635,13 @@ contract Halo2Verifier { // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div @@ -1386,15 +1429,15 @@ contract Halo2Verifier { // q_const_mptr points to Fr constants used by the VM. // q_program_mptr points to the bytecode stream. // Constants are stored as consecutive 32-byte Fr words. - let q_const_mptr := 0x1d60 + let q_const_mptr := 0x2ce0 // Program bytes are also stored in the VK payload, packed into // 32-byte words by PackedProgramCodec. - let q_program_mptr := 0x1d80 + let q_program_mptr := 0x2d00 // Running Horner accumulator for fully evaluated identities. // After all identities, this is nu_y(x) for the `None` // identity group. // Initialize A = 0 before scanning the identity stream. - mstore(0x56e0, 0) + mstore(0x6660, 0) // Simple selectors are grouped into separate linearization // buckets. They start at zero for every proof. // q_sel_zero_off walks selector bucket byte offsets. @@ -1415,13 +1458,13 @@ contract Halo2Verifier { // block multiplies by mload(selector_power_mptr + offset) // unconditionally -- so initialize the slot rather than // leaving correctness to two filters in another file. - mstore(0x5720, 1) + mstore(0x66a0, 1) // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 22) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) // Store y^i at selector_power_mptr + 32*i. - mstore(add(0x5720, shl(5, q_y_power_i)), q_y_power) + mstore(add(0x66a0, shl(5, q_y_power_i)), q_y_power) } } @@ -1430,102 +1473,102 @@ contract Halo2Verifier { // VM/native identities, so they occupy the same y-batch order. { let var0 := 0x1 - let f_3 := mload(0x4980) - let f_4 := mload(0x4880) - let a_0 := mload(0x4700) + let f_3 := mload(0x5900) + let f_4 := mload(0x5800) + let a_0 := mload(0x5680) let var1 := mulmod(f_4, a_0, r) let var2 := addmod(f_3, var1, r) - let f_5 := mload(0x48a0) - let a_1 := mload(0x4720) + let f_5 := mload(0x5820) + let a_1 := mload(0x56a0) let var3 := mulmod(f_5, a_1, r) let var4 := addmod(var2, var3, r) - let f_6 := mload(0x48c0) - let a_2 := mload(0x4740) + let f_6 := mload(0x5840) + let a_2 := mload(0x56c0) let var5 := mulmod(f_6, a_2, r) let var6 := addmod(var4, var5, r) - let f_7 := mload(0x48e0) - let a_3 := mload(0x4760) + let f_7 := mload(0x5860) + let a_3 := mload(0x56e0) let var7 := mulmod(f_7, a_3, r) let var8 := addmod(var6, var7, r) - let f_8 := mload(0x4900) - let a_4 := mload(0x4780) + let f_8 := mload(0x5880) + let a_4 := mload(0x5700) let var9 := mulmod(f_8, a_4, r) let var10 := addmod(var8, var9, r) - let f_0 := mload(0x4920) - let a_0_next_1 := mload(0x47a0) + let f_0 := mload(0x58a0) + let a_0_next_1 := mload(0x5720) let var11 := mulmod(f_0, a_0_next_1, r) let var12 := addmod(var10, var11, r) - let f_1 := mload(0x4940) + let f_1 := mload(0x58c0) let var13 := mulmod(f_1, a_0, r) let var14 := mulmod(var13, a_1, r) let var15 := addmod(var12, var14, r) - let f_2 := mload(0x4960) + let f_2 := mload(0x58e0) let var16 := mulmod(f_2, a_0, r) let var17 := mulmod(var16, a_2, r) let var18 := addmod(var15, var17, r) let var19 := mulmod(var0, var18, r) - mstore(0x59e0, var19) + mstore(0x6960, var19) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } { let var0 := 0x1 - let a_1 := mload(0x4720) - let a_2 := mload(0x4740) + let a_1 := mload(0x56a0) + let a_2 := mload(0x56c0) let var1 := addmod(a_1, a_2, r) - let a_3 := mload(0x4760) + let a_3 := mload(0x56e0) let var2 := addmod(0, sub(r, a_3), r) let var3 := addmod(var1, var2, r) - let a_4 := mload(0x4780) + let a_4 := mload(0x5700) let var4 := addmod(0, sub(r, a_4), r) let var5 := addmod(var3, var4, r) let var6 := mulmod(var0, var5, r) - mstore(0x59e0, var6) + mstore(0x6960, var6) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } { let var0 := 0x1 - let a_0 := mload(0x4700) - let f_4 := mload(0x4880) + let a_0 := mload(0x5680) + let f_4 := mload(0x5800) let var1 := addmod(a_0, f_4, r) - let a_0_next_1 := mload(0x47a0) + let a_0_next_1 := mload(0x5720) let var2 := addmod(0, sub(r, a_0_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x59e0, var4) + mstore(0x6960, var4) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } { let var0 := 0x1 - let a_1 := mload(0x4720) - let f_5 := mload(0x48a0) + let a_1 := mload(0x56a0) + let f_5 := mload(0x5820) let var1 := addmod(a_1, f_5, r) - let a_1_next_1 := mload(0x47c0) + let a_1_next_1 := mload(0x5740) let var2 := addmod(0, sub(r, a_1_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x59e0, var4) + mstore(0x6960, var4) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5720, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x66a0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } // VM registers: @@ -1545,7 +1588,7 @@ contract Halo2Verifier { // q_end is an exclusive byte pointer for the VM loop. let q_end := add(q_program_mptr, 0x58) // q_sp starts at the first free stack word. - let q_sp := 0x59e0 + let q_sp := 0x6960 // q_top is meaningless until q_has_top is set. let q_top := 0 // q_has_top = 0 means the VM stack is empty. @@ -1645,69 +1688,69 @@ contract Halo2Verifier { // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := 0x59e0 + q_sp := 0x6960 // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. { let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 - let q_perm_vals := 0x59e0 - let q_perm_sigmas := 0x5ae0 - let q_perm_z_cur := 0x5be0 - let q_perm_z_next := 0x5c40 - let q_perm_z_last := 0x5ca0 - let q_perm_delta_base_ptr := 0x5ce0 + let q_perm_vals := 0x6960 + let q_perm_sigmas := 0x6a60 + let q_perm_z_cur := 0x6b60 + let q_perm_z_next := 0x6bc0 + let q_perm_z_last := 0x6c20 + let q_perm_delta_base_ptr := 0x6c60 let q_perm_num_cols := 8 let q_perm_num_sets := 3 let q_perm_chunk_len := 3 let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 - mstore(add(q_perm_vals, 0x0), mload(0x4860)) + mstore(add(q_perm_vals, 0x0), mload(0x57e0)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x4700, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x5680, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0xc0), mload(0x46e0)) + mstore(add(q_perm_vals, 0xc0), mload(0x5660)) mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) { for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 8) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off - mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x4a40, q_perm_sigma_load_src_off))) + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x59c0, q_perm_sigma_load_src_off))) } } { for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 3) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) - mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x4b40, q_perm_z_cur_load_src_off))) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x5ac0, q_perm_z_cur_load_src_off))) } } { for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 3) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) - mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x4b60, q_perm_z_next_load_src_off))) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x5ae0, q_perm_z_next_load_src_off))) } } - mstore(add(q_perm_z_last, 0x0), mload(0x4b80)) - mstore(add(q_perm_z_last, 0x20), mload(0x4be0)) + mstore(add(q_perm_z_last, 0x0), mload(0x5b00)) + mstore(add(q_perm_z_last, 0x20), mload(0x5b60)) let q_perm_eval := 0 q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_perm_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_perm_eval, r)) let q_perm_zn := mload(add(q_perm_z_cur, 0x40)) q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_perm_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_perm_eval, r)) for { let q_perm_i := 1 } lt(q_perm_i, 3) { q_perm_i := add(q_perm_i, 1) } { let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_perm_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_perm_eval, r)) } mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) for { let q_perm_set := 0 } lt(q_perm_set, 3) { q_perm_set := add(q_perm_set, 1) } { @@ -1726,8 +1769,8 @@ contract Halo2Verifier { q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) } q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_perm_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_perm_eval, r)) mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) } } @@ -1748,13 +1791,13 @@ contract Halo2Verifier { // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := 0x59e0 + q_sp := 0x6960 // Generated LogUp code follows the same y-batch order // as the Rust identity stream. { - let q_lookup_f := 0x59e0 - let q_lookup_prefix := 0x5a00 - let q_lookup_suffix := 0x5a20 + let q_lookup_f := 0x6960 + let q_lookup_prefix := 0x6980 + let q_lookup_suffix := 0x69a0 let q_lookup_l0 := mload(L_0_MPTR) let q_lookup_llast := mload(L_LAST_MPTR) let q_lookup_lblind := mload(L_BLIND_MPTR) @@ -1764,33 +1807,33 @@ contract Halo2Verifier { let q_lookup_theta := mload(THETA_MPTR) { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x4c80), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x5c00), r) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_lookup_eval, r)) } { - let f_10 := mload(0x49a0) + let f_10 := mload(0x5920) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) - let a_1 := mload(0x4720) + let a_1 := mload(0x56a0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_1, r) - let q_lookup_eval := addmod(mulmod(mload(0x4c60), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x5be0), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x4c60) - let f_16 := mload(0x4a00) - let f_11 := mload(0x49c0) + let q_lookup_sum_h := mload(0x5be0) + let f_16 := mload(0x5980) + let f_11 := mload(0x5940) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) - let f_12 := mload(0x49e0) + let f_12 := mload(0x5960) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) let q_lookup_s_sum_h := mulmod(f_16, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x4ca0), sub(r, addmod(mload(0x4c80), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x5c20), sub(r, addmod(mload(0x5c00), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x4c40), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x5bc0), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_lookup_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_lookup_eval, r)) } } } @@ -1811,124 +1854,124 @@ contract Halo2Verifier { // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := 0x59e0 + q_sp := 0x6960 // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx case 0 { { let var0 := 0x1 - let f_0 := mload(0x4920) - let a_0_next_1 := mload(0x47a0) + let f_0 := mload(0x58a0) + let a_0_next_1 := mload(0x5720) let var1 := addmod(0, sub(r, a_0_next_1), r) let var2 := addmod(f_0, var1, r) let var3 := 0x1b8114c381b922fd5d6d241210e2d8a68ad5744053ba9e776118de4107b51ace - let a_0 := mload(0x4700) + let a_0 := mload(0x5680) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x4760) + let a_3 := mload(0x56e0) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0x3df32e4cc4cb2ed20e5d21899cf5331775990ccaec4c09b4e3717213fcc0d763 - let a_1 := mload(0x4720) + let a_1 := mload(0x56a0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x4780) + let a_4 := mload(0x5700) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_2 := mload(0x4740) + let a_2 := mload(0x56c0) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x4800) + let a_5 := mload(0x5780) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x59e0, var18) + mstore(0x6960, var18) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5720, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x66a0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } } case 1 { { let var0 := 0x1 - let f_1 := mload(0x4940) - let a_1_next_1 := mload(0x47c0) + let f_1 := mload(0x58c0) + let a_1_next_1 := mload(0x5740) let var1 := addmod(0, sub(r, a_1_next_1), r) let var2 := addmod(f_1, var1, r) let var3 := 0x404d21073985d14e432a4ad76d3fae06ca74314b950fe7b1d7f501cd31a8b374 - let a_0 := mload(0x4700) + let a_0 := mload(0x5680) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x4760) + let a_3 := mload(0x56e0) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0xb2cc8704264c6bd81bc620e9e524d4b73e9b2317679422ff7fa1603955649f1 - let a_1 := mload(0x4720) + let a_1 := mload(0x56a0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x4780) + let a_4 := mload(0x5700) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0xfdf664da55059fa5a9388c641035d496d0bb519834348b4e2a8fc8c637f1a1f - let a_2 := mload(0x4740) + let a_2 := mload(0x56c0) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x4800) + let a_5 := mload(0x5780) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x59e0, var18) + mstore(0x6960, var18) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5720, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x66a0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } } case 2 { { let var0 := 0x1 - let f_2 := mload(0x4960) - let a_2_next_1 := mload(0x47e0) + let f_2 := mload(0x58e0) + let a_2_next_1 := mload(0x5760) let var1 := addmod(0, sub(r, a_2_next_1), r) let var2 := addmod(f_2, var1, r) let var3 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 - let a_0 := mload(0x4700) + let a_0 := mload(0x5680) let var4 := mulmod(a_0, a_0, r) - let a_3 := mload(0x4760) + let a_3 := mload(0x56e0) let var5 := mulmod(var4, a_3, r) let var6 := mulmod(var3, var5, r) let var7 := addmod(var2, var6, r) let var8 := 0x6bd72f9cfc53af9d931896e77ea5c61244cb6d5fae8954f37dc7b9002f5aa78a - let a_1 := mload(0x4720) + let a_1 := mload(0x56a0) let var9 := mulmod(a_1, a_1, r) - let a_4 := mload(0x4780) + let a_4 := mload(0x5700) let var10 := mulmod(var9, a_4, r) let var11 := mulmod(var8, var10, r) let var12 := addmod(var7, var11, r) let var13 := 0x4997c5aa3a5fa07bcaf880a9054bef831effbd9cd58e46d9bb4fb88ef99de0db - let a_2 := mload(0x4740) + let a_2 := mload(0x56c0) let var14 := mulmod(a_2, a_2, r) - let a_5 := mload(0x4800) + let a_5 := mload(0x5780) let var15 := mulmod(var14, a_5, r) let var16 := mulmod(var13, var15, r) let var17 := addmod(var12, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x59e0, var18) + mstore(0x6960, var18) } - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5720, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x59e0), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x66a0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } } default { revert(0, 0) } @@ -1952,14 +1995,14 @@ contract Halo2Verifier { // The global fully-evaluated accumulator is still // multiplied by y so later main identities land at the // same y powers as Rust's reverse fold. - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) let q_sel_acc := mload(q_target_ptr) if q_sel_gap { // Selector buckets are sparse in the global // identity stream. Precomputed y^gap advances only // this selector's local accumulator. - q_sel_acc := mulmod(q_sel_acc, mload(add(0x5720, shl(5, q_sel_gap))), r) + q_sel_acc := mulmod(q_sel_acc, mload(add(0x66a0, shl(5, q_sel_gap))), r) } mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) } @@ -1979,7 +2022,7 @@ contract Halo2Verifier { // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x59e0)) { revert(0, 0) } + if iszero(eq(q_sp, 0x6960)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -1991,52 +2034,52 @@ contract Halo2Verifier { { let q_trash_tau := mload(TRASH_CHALLENGE_MPTR) { - let f_0 := mload(0x4920) - let a_0_next_1 := mload(0x47a0) + let f_0 := mload(0x58a0) + let a_0_next_1 := mload(0x5720) let var0 := 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000 let var1 := mulmod(a_0_next_1, var0, r) let var2 := addmod(f_0, var1, r) let var3 := 0x590ba402032e82eb1f660ef09796c5686345a5054ed96dae8e2d233633788771 - let a_0 := mload(0x4700) + let a_0 := mload(0x5680) let var4 := mulmod(var3, a_0, r) let var5 := addmod(var2, var4, r) let var6 := 0x52f789e4afc3801f7411102ee2f47cc5954a744e71cac98e75ea962a55a0a76f - let a_1 := mload(0x4720) + let a_1 := mload(0x56a0) let var7 := mulmod(var6, a_1, r) let var8 := addmod(var5, var7, r) let var9 := 0x3509dd2fe3aac0080783557fec090fb1cb4b2b0901253c55282024331d1fe1a8 - let a_2 := mload(0x4740) + let a_2 := mload(0x56c0) let var10 := q_pow5(a_2) let var11 := mulmod(var9, var10, r) let var12 := addmod(var8, var11, r) let var13 := 0x333f8046ece5579cbd6872449c57f2703dfc8864cfadc06d587ff104a0d0c1f2 - let a_3 := mload(0x4760) + let a_3 := mload(0x56e0) let var14 := q_pow5(a_3) let var15 := mulmod(var13, var14, r) let var16 := addmod(var12, var15, r) let var17 := 0x412c98232b6ab8a47aa76ee814ef7ec6261987c9802f2cfc490e007951a60ca5 - let a_4 := mload(0x4780) + let a_4 := mload(0x5700) let var18 := q_pow5(a_4) let var19 := mulmod(var17, var18, r) let var20 := addmod(var16, var19, r) let var21 := 0x53fded36d490ba6b05a5d10fd99ffe5456baec6a6a8753199d5ebdc33c99790e - let a_5 := mload(0x4800) + let a_5 := mload(0x5780) let var22 := q_pow5(a_5) let var23 := mulmod(var21, var22, r) let var24 := addmod(var20, var23, r) let var25 := 0x6ccb1c7d87f3c12a2bde4e68ac7f1e8b03481ba15d7f88f9a7f9b8310dd6d34 - let a_6 := mload(0x4820) + let a_6 := mload(0x57a0) let var26 := q_pow5(a_6) let var27 := mulmod(var25, var26, r) let var28 := addmod(var24, var27, r) let var29 := 0x3f05c4df7a6664dabe258779bf548eb4007f33601591080b3ecd34aea0e1edc1 - let a_7 := mload(0x4840) + let a_7 := mload(0x57c0) let var30 := q_pow5(a_7) let var31 := mulmod(var29, var30, r) let var32 := addmod(var28, var31, r) let var33 := addmod(mulmod(0, q_trash_tau, r), var32, r) - let f_1 := mload(0x4940) - let a_1_next_1 := mload(0x47c0) + let f_1 := mload(0x58c0) + let a_1_next_1 := mload(0x5740) let var34 := mulmod(a_1_next_1, var0, r) let var35 := addmod(f_1, var34, r) let var36 := 0x5b1fc262a28cbb8bf75d9b1a6edaa74591ec24cd9a209512213cec3a3c0f1a5d @@ -2064,7 +2107,7 @@ contract Halo2Verifier { let var58 := mulmod(var57, var30, r) let var59 := addmod(var56, var58, r) let var60 := addmod(mulmod(var33, q_trash_tau, r), var59, r) - let f_2 := mload(0x4960) + let f_2 := mload(0x58e0) let var61 := mulmod(a_3, var0, r) let var62 := addmod(f_2, var61, r) let var63 := 0x5e1d3dbecda6214343e24a47f45c5d033197ad01b65a730af95dc57e90c49140 @@ -2077,7 +2120,7 @@ contract Halo2Verifier { let var70 := mulmod(var69, var10, r) let var71 := addmod(var68, var70, r) let var72 := addmod(mulmod(var60, q_trash_tau, r), var71, r) - let f_3 := mload(0x4980) + let f_3 := mload(0x5900) let var73 := mulmod(a_4, var0, r) let var74 := addmod(f_3, var73, r) let var75 := 0x222e83e70453dfee19b402e9fa8dfe2c4987b034d0be3ceb478b3022e97934c1 @@ -2092,7 +2135,7 @@ contract Halo2Verifier { let var84 := mulmod(var69, var14, r) let var85 := addmod(var83, var84, r) let var86 := addmod(mulmod(var72, q_trash_tau, r), var85, r) - let f_4 := mload(0x4880) + let f_4 := mload(0x5800) let var87 := mulmod(a_5, var0, r) let var88 := addmod(f_4, var87, r) let var89 := 0x726df1506749848155630b86ae25a82b281ecd050fe3a52d85a181fa87202e4b @@ -2109,7 +2152,7 @@ contract Halo2Verifier { let var100 := mulmod(var69, var18, r) let var101 := addmod(var99, var100, r) let var102 := addmod(mulmod(var86, q_trash_tau, r), var101, r) - let f_5 := mload(0x48a0) + let f_5 := mload(0x5820) let var103 := mulmod(a_6, var0, r) let var104 := addmod(f_5, var103, r) let var105 := 0x2f5908b169c6cf1bd26dcf0f9e5105481f5164f3ece0582bf3098312167751a7 @@ -2128,7 +2171,7 @@ contract Halo2Verifier { let var118 := mulmod(var69, var22, r) let var119 := addmod(var117, var118, r) let var120 := addmod(mulmod(var102, q_trash_tau, r), var119, r) - let f_6 := mload(0x48c0) + let f_6 := mload(0x5840) let var121 := mulmod(a_7, var0, r) let var122 := addmod(f_6, var121, r) let var123 := 0x6d05a41959f539a7fc9ec0972ea1e3dbb6fc67dd51daf3414f7fbbb091c7274a @@ -2149,8 +2192,8 @@ contract Halo2Verifier { let var138 := mulmod(var69, var26, r) let var139 := addmod(var137, var138, r) let var140 := addmod(mulmod(var120, q_trash_tau, r), var139, r) - let f_7 := mload(0x48e0) - let a_2_next_1 := mload(0x47e0) + let f_7 := mload(0x5860) + let a_2_next_1 := mload(0x5760) let var141 := mulmod(a_2_next_1, var0, r) let var142 := addmod(f_7, var141, r) let var143 := 0x70d8f2a733a64d650faccc9b1c2a766a9544bb3ff1a11ee73cb43947ef386633 @@ -2173,12 +2216,12 @@ contract Halo2Verifier { let var160 := mulmod(var69, var30, r) let var161 := addmod(var159, var160, r) let var162 := addmod(mulmod(var140, q_trash_tau, r), var161, r) - let f_18 := mload(0x4a20) + let f_18 := mload(0x59a0) let q_trash_one_minus_selector := addmod(1, sub(r, f_18), r) - let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0x4cc0), r) + let q_trash_scaled := mulmod(q_trash_one_minus_selector, mload(0x5c40), r) let q_trash_eval := addmod(var162, sub(r, q_trash_scaled), r) - mstore(0x56e0, mulmod(mload(0x56e0), y, r)) - mstore(0x56e0, addmod(mload(0x56e0), q_trash_eval, r)) + mstore(0x6660, mulmod(mload(0x6660), y, r)) + mstore(0x6660, addmod(mload(0x6660), q_trash_eval, r)) } } // Finish selector buckets by applying the codegen-known tail @@ -2190,25 +2233,25 @@ contract Halo2Verifier { // selector commitment in the linearized MSM. { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5720, 0x02a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x66a0, 0x02a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5720, 0x0280)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x66a0, 0x0280)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5720, 0x0220)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x66a0, 0x0220)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5720, 0x0160)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x66a0, 0x0160)), r)) } // Fully evaluated identities are the constant-polynomial side // of the linearization query. Rust subtracts that grouped // scalar into expected_eval, so Solidity stores -nu_y(x). - let linearization_expected_eval := addmod(0, sub(r, mload(0x56e0)), r) + let linearization_expected_eval := addmod(0, sub(r, mload(0x6660)), r) mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) pop(y) } @@ -2310,42 +2353,42 @@ contract Halo2Verifier { { // q_eval_set[0]: 33 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x56e0, 0x4760) - mstore(0x5700, 0x4780) - mstore(0x5720, 0x4800) - mstore(0x5740, 0x4820) - mstore(0x5760, 0x4840) - mstore(0x5780, 0x46e0) - mstore(0x57a0, 0x4c40) - mstore(0x57c0, 0x4c60) - mstore(0x57e0, 0x4cc0) - mstore(0x5800, 0x4860) - mstore(0x5820, 0x4880) - mstore(0x5840, 0x48a0) - mstore(0x5860, 0x48c0) - mstore(0x5880, 0x48e0) - mstore(0x58a0, 0x4900) - mstore(0x58c0, 0x4920) - mstore(0x58e0, 0x4940) - mstore(0x5900, 0x4960) - mstore(0x5920, 0x4980) - mstore(0x5940, 0x49a0) - mstore(0x5960, 0x49c0) - mstore(0x5980, 0x49e0) - mstore(0x59a0, 0x4a00) - mstore(0x59c0, 0x4a20) - mstore(0x59e0, 0x4a40) - mstore(0x5a00, 0x4a60) - mstore(0x5a20, 0x4a80) - mstore(0x5a40, 0x4aa0) - mstore(0x5a60, 0x4ac0) - mstore(0x5a80, 0x4ae0) - mstore(0x5aa0, 0x4b00) - mstore(0x5ac0, 0x4b20) - mstore(0x5ae0, QUOTIENT_EVAL_MPTR) - let q_eval_set_0 := mload(0x4760) + mstore(0x6660, 0x56e0) + mstore(0x6680, 0x5700) + mstore(0x66a0, 0x5780) + mstore(0x66c0, 0x57a0) + mstore(0x66e0, 0x57c0) + mstore(0x6700, 0x5660) + mstore(0x6720, 0x5bc0) + mstore(0x6740, 0x5be0) + mstore(0x6760, 0x5c40) + mstore(0x6780, 0x57e0) + mstore(0x67a0, 0x5800) + mstore(0x67c0, 0x5820) + mstore(0x67e0, 0x5840) + mstore(0x6800, 0x5860) + mstore(0x6820, 0x5880) + mstore(0x6840, 0x58a0) + mstore(0x6860, 0x58c0) + mstore(0x6880, 0x58e0) + mstore(0x68a0, 0x5900) + mstore(0x68c0, 0x5920) + mstore(0x68e0, 0x5940) + mstore(0x6900, 0x5960) + mstore(0x6920, 0x5980) + mstore(0x6940, 0x59a0) + mstore(0x6960, 0x59c0) + mstore(0x6980, 0x59e0) + mstore(0x69a0, 0x5a00) + mstore(0x69c0, 0x5a20) + mstore(0x69e0, 0x5a40) + mstore(0x6a00, 0x5a60) + mstore(0x6a20, 0x5a80) + mstore(0x6a40, 0x5aa0) + mstore(0x6a60, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x56e0) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x56e0, 0x20) + let eval_p := add(0x6660, 0x20) for { let i := 1 } lt(i, 0x21) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2360,20 +2403,20 @@ contract Halo2Verifier { { // q_eval_set[1]: 5 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x56e0, 0x4700) - mstore(0x5700, 0x47a0) - mstore(0x5720, 0x4720) - mstore(0x5740, 0x47c0) - mstore(0x5760, 0x4740) - mstore(0x5780, 0x47e0) - mstore(0x57a0, 0x4c00) - mstore(0x57c0, 0x4c20) - mstore(0x57e0, 0x4c80) - mstore(0x5800, 0x4ca0) - let q_eval_set_0 := mload(0x4700) - let q_eval_set_1 := mload(0x47a0) + mstore(0x6660, 0x5680) + mstore(0x6680, 0x5720) + mstore(0x66a0, 0x56a0) + mstore(0x66c0, 0x5740) + mstore(0x66e0, 0x56c0) + mstore(0x6700, 0x5760) + mstore(0x6720, 0x5b80) + mstore(0x6740, 0x5ba0) + mstore(0x6760, 0x5c00) + mstore(0x6780, 0x5c20) + let q_eval_set_0 := mload(0x5680) + let q_eval_set_1 := mload(0x5720) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x56e0, 0x40) + let eval_p := add(0x6660, 0x40) for { let i := 1 } lt(i, 0x5) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2389,12 +2432,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[2]: 2 commitment(s) - let q_eval_set_0 := mload(0x4b40) - let q_eval_set_1 := mload(0x4b60) - let q_eval_set_2 := mload(0x4b80) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x4ba0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x4bc0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x4be0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + let q_eval_set_0 := mload(0x5ac0) + let q_eval_set_1 := mload(0x5ae0) + let q_eval_set_2 := mload(0x5b00) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x5b20), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x5b40), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x5b60), mload(add(X1_POWERS_MPTR, 0x20)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0xa0), q_eval_set_2) @@ -2514,107 +2557,107 @@ contract Halo2Verifier { v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), x4_pow_1, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_3, r), r) - mcopy(0x56e0, 0x4e60, 0x80) - mstore(0x5760, 1) - mcopy(0x5780, 0x4ee0, 0x80) - mstore(0x5800, mload(add(X1_POWERS_MPTR, 0x20))) - mcopy(0x5820, 0x4f60, 0x80) - mstore(0x58a0, mload(add(X1_POWERS_MPTR, 0x40))) - mcopy(0x58c0, 0x4fe0, 0x80) - mstore(0x5940, mload(add(X1_POWERS_MPTR, 0x60))) - mcopy(0x5960, 0x5060, 0x80) - mstore(0x59e0, mload(add(X1_POWERS_MPTR, 0x80))) - mcopy(0x5a00, 0x50e0, 0x80) - mstore(0x5a80, mload(add(X1_POWERS_MPTR, 0xc0))) - mcopy(0x5aa0, 0x52e0, 0x80) - mstore(0x5b20, mload(add(X1_POWERS_MPTR, 0xe0))) - mcopy(0x5b40, 0x53e0, 0x80) - mstore(0x5bc0, mload(add(X1_POWERS_MPTR, 0x100))) - mcopy(0x5be0, 0x2260, 0x80) - mstore(0x5c60, mload(add(X1_POWERS_MPTR, 0x120))) - mcopy(0x5c80, 0x1fe0, 0x80) - mstore(0x5d00, mload(add(X1_POWERS_MPTR, 0x140))) - mcopy(0x5d20, 0x2060, 0x80) - mstore(0x5da0, mload(add(X1_POWERS_MPTR, 0x160))) - mcopy(0x5dc0, 0x20e0, 0x80) - mstore(0x5e40, mload(add(X1_POWERS_MPTR, 0x180))) - mcopy(0x5e60, 0x2160, 0x80) - mstore(0x5ee0, mload(add(X1_POWERS_MPTR, 0x1a0))) - mcopy(0x5f00, 0x21e0, 0x80) - mstore(0x5f80, mload(add(X1_POWERS_MPTR, 0x1c0))) - mcopy(0x5fa0, 0x1de0, 0x80) - mstore(0x6020, mload(add(X1_POWERS_MPTR, 0x1e0))) - mcopy(0x6040, 0x1e60, 0x80) - mstore(0x60c0, mload(add(X1_POWERS_MPTR, 0x200))) - mcopy(0x60e0, 0x1ee0, 0x80) - mstore(0x6160, mload(add(X1_POWERS_MPTR, 0x220))) - mcopy(0x6180, 0x1f60, 0x80) - mstore(0x6200, mload(add(X1_POWERS_MPTR, 0x240))) - mcopy(0x6220, 0x22e0, 0x80) - mstore(0x62a0, mload(add(X1_POWERS_MPTR, 0x260))) - mcopy(0x62c0, 0x2360, 0x80) - mstore(0x6340, mload(add(X1_POWERS_MPTR, 0x280))) - mcopy(0x6360, 0x23e0, 0x80) - mstore(0x63e0, mload(add(X1_POWERS_MPTR, 0x2a0))) - mcopy(0x6400, 0x25e0, 0x80) - mstore(0x6480, mload(add(X1_POWERS_MPTR, 0x2c0))) - mcopy(0x64a0, 0x26e0, 0x80) - mstore(0x6520, mload(add(X1_POWERS_MPTR, 0x2e0))) - mcopy(0x6540, 0x2760, 0x80) - mstore(0x65c0, mload(add(X1_POWERS_MPTR, 0x300))) - mcopy(0x65e0, 0x27e0, 0x80) - mstore(0x6660, mload(add(X1_POWERS_MPTR, 0x320))) - mcopy(0x6680, 0x2860, 0x80) - mstore(0x6700, mload(add(X1_POWERS_MPTR, 0x340))) - mcopy(0x6720, 0x28e0, 0x80) - mstore(0x67a0, mload(add(X1_POWERS_MPTR, 0x360))) - mcopy(0x67c0, 0x2960, 0x80) - mstore(0x6840, mload(add(X1_POWERS_MPTR, 0x380))) - mcopy(0x6860, 0x29e0, 0x80) - mstore(0x68e0, mload(add(X1_POWERS_MPTR, 0x3a0))) - mcopy(0x6900, 0x2a60, 0x80) - mstore(0x6980, mload(add(X1_POWERS_MPTR, 0x3c0))) - mcopy(0x69a0, 0x2ae0, 0x80) - mstore(0x6a20, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0x6660, 0x5de0, 0x80) + mstore(0x66e0, 1) + mcopy(0x6700, 0x5e60, 0x80) + mstore(0x6780, mload(add(X1_POWERS_MPTR, 0x20))) + mcopy(0x67a0, 0x5ee0, 0x80) + mstore(0x6820, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0x6840, 0x5f60, 0x80) + mstore(0x68c0, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0x68e0, 0x5fe0, 0x80) + mstore(0x6960, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0x6980, 0x6060, 0x80) + mstore(0x6a00, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0x6a20, 0x6260, 0x80) + mstore(0x6aa0, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0x6ac0, 0x6360, 0x80) + mstore(0x6b40, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0x6b60, 0x31e0, 0x80) + mstore(0x6be0, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0x6c00, 0x2f60, 0x80) + mstore(0x6c80, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0x6ca0, 0x2fe0, 0x80) + mstore(0x6d20, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0x6d40, 0x3060, 0x80) + mstore(0x6dc0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0x6de0, 0x30e0, 0x80) + mstore(0x6e60, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0x6e80, 0x3160, 0x80) + mstore(0x6f00, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0x6f20, 0x2d60, 0x80) + mstore(0x6fa0, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0x6fc0, 0x2de0, 0x80) + mstore(0x7040, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0x7060, 0x2e60, 0x80) + mstore(0x70e0, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0x7100, 0x2ee0, 0x80) + mstore(0x7180, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0x71a0, 0x3260, 0x80) + mstore(0x7220, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0x7240, 0x32e0, 0x80) + mstore(0x72c0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0x72e0, 0x3360, 0x80) + mstore(0x7360, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0x7380, 0x3560, 0x80) + mstore(0x7400, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0x7420, 0x3660, 0x80) + mstore(0x74a0, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0x74c0, 0x36e0, 0x80) + mstore(0x7540, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0x7560, 0x3760, 0x80) + mstore(0x75e0, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0x7600, 0x37e0, 0x80) + mstore(0x7680, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0x76a0, 0x3860, 0x80) + mstore(0x7720, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0x7740, 0x38e0, 0x80) + mstore(0x77c0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0x77e0, 0x3960, 0x80) + mstore(0x7860, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0x7880, 0x39e0, 0x80) + mstore(0x7900, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0x7920, 0x3a60, 0x80) + mstore(0x79a0, mload(add(X1_POWERS_MPTR, 0x3e0))) let lin_query_scalar_31 := mload(add(X1_POWERS_MPTR, 0x400)) let lin_cur_scalar_31 := mulmod(lin_query_scalar_31, lin_one_minus_x_n, r) - mcopy(0x6a40, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) - mstore(0x6ac0, lin_cur_scalar_31) + mcopy(0x79c0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0x7a40, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x6ae0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) - mstore(0x6b60, lin_cur_scalar_31) + mcopy(0x7a60, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0x7ae0, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x6b80, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) - mstore(0x6c00, lin_cur_scalar_31) + mcopy(0x7b00, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0x7b80, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x6c20, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) - mstore(0x6ca0, lin_cur_scalar_31) - mcopy(0x6cc0, 0x2460, 0x80) - mstore(0x6d40, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) - mcopy(0x6d60, 0x24e0, 0x80) - mstore(0x6de0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) - mcopy(0x6e00, 0x2560, 0x80) - mstore(0x6e80, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) - mcopy(0x6ea0, 0x2660, 0x80) - mstore(0x6f20, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) - mcopy(0x6f40, 0x4ce0, 0x80) - mstore(0x6fc0, x4_pow_1) - mcopy(0x6fe0, 0x4d60, 0x80) - mstore(0x7060, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) - mcopy(0x7080, 0x4de0, 0x80) - mstore(0x7100, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) - mcopy(0x7120, 0x5260, 0x80) - mstore(0x71a0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_1, r)) - mcopy(0x71c0, 0x5360, 0x80) - mstore(0x7240, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_1, r)) - mcopy(0x7260, 0x5160, 0x80) - mstore(0x72e0, x4_pow_2) - mcopy(0x7300, 0x51e0, 0x80) - mstore(0x7380, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) - mcopy(0x73a0, F_COM_MPTR, 0x80) - mstore(0x7420, x4_pow_3) + mcopy(0x7ba0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0x7c20, lin_cur_scalar_31) + mcopy(0x7c40, 0x33e0, 0x80) + mstore(0x7cc0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0x7ce0, 0x3460, 0x80) + mstore(0x7d60, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0x7d80, 0x34e0, 0x80) + mstore(0x7e00, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0x7e20, 0x35e0, 0x80) + mstore(0x7ea0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0x7ec0, 0x5c60, 0x80) + mstore(0x7f40, x4_pow_1) + mcopy(0x7f60, 0x5ce0, 0x80) + mstore(0x7fe0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0x8000, 0x5d60, 0x80) + mstore(0x8080, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0x80a0, 0x61e0, 0x80) + mstore(0x8120, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_1, r)) + mcopy(0x8140, 0x62e0, 0x80) + mstore(0x81c0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_1, r)) + mcopy(0x81e0, 0x60e0, 0x80) + mstore(0x8260, x4_pow_2) + mcopy(0x8280, 0x6160, 0x80) + mstore(0x8300, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0x8320, F_COM_MPTR, 0x80) + mstore(0x83a0, x4_pow_3) if success { - success := staticcall(gas(), 0x0c, 0x56e0, 0x1d60, FINAL_COM_MPTR, 0x80) + success := staticcall(gas(), 0x0c, 0x6660, 0x1d60, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2626,28 +2669,28 @@ contract Halo2Verifier { // Scale z*pi - vG before the final pairing check // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) - mcopy(0x80, G1_BASE_MPTR, 0x80) - mstore(0x100, addmod(0, sub(r, mload(V_MPTR)), r)) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x80, 0xa0, 0x80, 0x80) + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, FINAL_COM_MPTR, 0x80) + mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, PI_MPTR, 0x80) - mstore(0x180, mload(X3_MPTR)) + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x100, 0xa0, 0x100, 0x80) + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(PAIRING_RHS_MPTR, 0x80, 0x80) + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol index 895f2a4d2..1ee722abf 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol @@ -94,9 +94,9 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x03a0), 0x00000000000000000000000000000000006d57f79a18220d1e5ef04bd519e995) // neg_s_g2_y_c1_hi mstore(add(payload, 0x03c0), 0x9a9cc71553bb761b5422a6b6971b75c8d3695bfa07b861c4b1c958da426efc45) // neg_s_g2_y_c1_lo mstore(add(payload, 0x03e0), 0x0000000000000000000000000000000000000000000000000000000000000001) // quotient_const - mstore(add(payload, 0x0400), 0x0547401048c00547e008060d000b02000105470011470011470005476008060d) // quotient_program - mstore(add(payload, 0x0420), 0x000b03000005472011472011472005478008060d000b03000105474011474011) // quotient_program - mstore(add(payload, 0x0440), 0x474005480008060d000b0300011b00001b00011b0002191f0000000000000000) // quotient_program + mstore(add(payload, 0x0400), 0x0556c010584005576008060d000b0200010556801156801156800556e008060d) // quotient_program + mstore(add(payload, 0x0420), 0x000b0300000556a01156a01156a005570008060d000b0300010556c01156c011) // quotient_program + mstore(add(payload, 0x0440), 0x56c005578008060d000b0300011b00001b00011b0002191f0000000000000000) // quotient_program // Fixed-column commitment 0, stored as one // EIP-2537 padded uncompressed G1 slot. mstore(add(payload, 0x0460), 0x0000000000000000000000000000000016742a8c4f331d1be5bc8622ba92b271) // fixed_comms[0].x_hi diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index d0caa0941..dea9593f8 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -55,8 +55,8 @@ contract Halo2Verifier { uint256 internal constant INSTANCE_CPTR = 0xec4; // First general-purpose memory words reserved by the generated verifier. // RETURN_MPTR is a single word set to 1 on success. - uint256 internal constant TRANSCRIPT_MPTR = 0x80; - uint256 internal constant RETURN_MPTR = 0x80; + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; // ---------------------------------------------------------------------- // Verifying-key memory map. The VK header lives at VK_MPTR, followed @@ -64,84 +64,84 @@ contract Halo2Verifier { // runtime comes the challenge slots (challenge_mptr..) and the // per-stage scratch (theta_mptr..). // ---------------------------------------------------------------------- - uint256 internal constant VK_MPTR = 0x16e0; - uint256 internal constant VK_DIGEST_MPTR = 0x16e0; - uint256 internal constant NUM_INSTANCES_MPTR = 0x1700; - uint256 internal constant K_MPTR = 0x1720; - uint256 internal constant N_INV_MPTR = 0x1740; - uint256 internal constant OMEGA_MPTR = 0x1760; - uint256 internal constant OMEGA_INV_MPTR = 0x1780; - uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x17a0; - uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x17c0; - uint256 internal constant ACC_OFFSET_MPTR = 0x17e0; - uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x1800; - uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x1820; - uint256 internal constant G1_BASE_MPTR = 0x1840; - uint256 internal constant G2_BASE_MPTR = 0x18c0; - uint256 internal constant NEG_S_G2_BASE_MPTR = 0x19c0; - - uint256 internal constant CHALLENGE_MPTR = 0x2760; + uint256 internal constant VK_MPTR = 0x2660; + uint256 internal constant VK_DIGEST_MPTR = 0x2660; + uint256 internal constant NUM_INSTANCES_MPTR = 0x2680; + uint256 internal constant K_MPTR = 0x26a0; + uint256 internal constant N_INV_MPTR = 0x26c0; + uint256 internal constant OMEGA_MPTR = 0x26e0; + uint256 internal constant OMEGA_INV_MPTR = 0x2700; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x2720; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x2740; + uint256 internal constant ACC_OFFSET_MPTR = 0x2760; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x2780; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x27a0; + uint256 internal constant G1_BASE_MPTR = 0x27c0; + uint256 internal constant G2_BASE_MPTR = 0x2840; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x2940; + + uint256 internal constant CHALLENGE_MPTR = 0x36e0; // Challenge layout. Squeeze order in midnight-proofs: // user_phase challenges (variable count) // theta -> beta, gamma -> trash_challenge -> y -> x -> // x1, x2 -> x3 -> x4 - uint256 internal constant THETA_MPTR = 0x2760; - uint256 internal constant BETA_MPTR = 0x2780; - uint256 internal constant GAMMA_MPTR = 0x27a0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x27c0; - uint256 internal constant Y_MPTR = 0x27e0; - uint256 internal constant X_MPTR = 0x2800; - uint256 internal constant X1_MPTR = 0x2820; - uint256 internal constant X2_MPTR = 0x2840; - uint256 internal constant X3_MPTR = 0x2860; - uint256 internal constant X4_MPTR = 0x2880; + uint256 internal constant THETA_MPTR = 0x36e0; + uint256 internal constant BETA_MPTR = 0x3700; + uint256 internal constant GAMMA_MPTR = 0x3720; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x3740; + uint256 internal constant Y_MPTR = 0x3760; + uint256 internal constant X_MPTR = 0x3780; + uint256 internal constant X1_MPTR = 0x37a0; + uint256 internal constant X2_MPTR = 0x37c0; + uint256 internal constant X3_MPTR = 0x37e0; + uint256 internal constant X4_MPTR = 0x3800; // Batch-open commitments live in 4-word EIP-2537 padded slots. - uint256 internal constant F_COM_MPTR = 0x28a0; - uint256 internal constant PI_MPTR = 0x2920; + uint256 internal constant F_COM_MPTR = 0x3820; + uint256 internal constant PI_MPTR = 0x38a0; // Accumulator (KZG IVC). - uint256 internal constant ACC_LHS_MPTR = 0x29a0; - uint256 internal constant ACC_RHS_MPTR = 0x2a20; + uint256 internal constant ACC_LHS_MPTR = 0x3920; + uint256 internal constant ACC_RHS_MPTR = 0x39a0; // Lagrange / linearization scratch. - uint256 internal constant X_N_MPTR = 0x2aa0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x2ac0; - uint256 internal constant L_LAST_MPTR = 0x2ae0; - uint256 internal constant L_BLIND_MPTR = 0x2b00; - uint256 internal constant L_0_MPTR = 0x2b20; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x2b40; + uint256 internal constant X_N_MPTR = 0x3a20; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x3a40; + uint256 internal constant L_LAST_MPTR = 0x3a60; + uint256 internal constant L_BLIND_MPTR = 0x3a80; + uint256 internal constant L_0_MPTR = 0x3aa0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x3ac0; // Legacy name: this is not h(x). It stores the expected opening // scalar for the linearized commitment, i.e. the negated y-batched // identity numerator reconstructed from the alleged evals at x. - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x2b60; - uint256 internal constant QUOTIENT_MPTR = 0x2b80; // 4 words - uint256 internal constant F_EVAL_MPTR = 0x2c20; - uint256 internal constant V_MPTR = 0x2c40; - uint256 internal constant FINAL_COM_MPTR = 0x2c60; // 4 words - uint256 internal constant PAIRING_LHS_MPTR = 0x2ce0; // 4 words - uint256 internal constant PAIRING_RHS_MPTR = 0x2d60; // 4 words + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x3ae0; + uint256 internal constant QUOTIENT_MPTR = 0x3b00; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x3ba0; + uint256 internal constant V_MPTR = 0x3bc0; + uint256 internal constant FINAL_COM_MPTR = 0x3be0; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x3c60; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x3ce0; // 4 words // Multi-prepare scratch (sized at codegen time). - uint256 internal constant ROT_POINTS_MPTR = 0x2de0; - uint256 internal constant X1_POWERS_MPTR = 0x3160; + uint256 internal constant ROT_POINTS_MPTR = 0x3d60; + uint256 internal constant X1_POWERS_MPTR = 0x40e0; // Q_COM materialization is currently fused into the final MSM scratch, // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero // reserved capacity until a future emitter starts writing Q_COM_MPTR. - uint256 internal constant Q_COM_MPTR = 0x3980; - uint256 internal constant Q_EVAL_SET_MPTR = 0x3980; + uint256 internal constant Q_COM_MPTR = 0x4900; + uint256 internal constant Q_EVAL_SET_MPTR = 0x4900; // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals // block of the proof; we keep it as a memory slot for symmetry. - uint256 internal constant Q_EVAL_CPTR_MPTR = 0x4080; + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x5000; // Reserved 4-word slot for the G1 identity (point at infinity) in // EIP-2537 padded form. EVM memory is zero-initialised, and we // never write to this region, so the four `mload`s below produce // 0,0,0,0 which is exactly the identity encoding the EIP-2537 // ec_add / ec_mul precompiles accept. - uint256 internal constant G1_IDENTITY_MPTR = 0x4180; + uint256 internal constant G1_IDENTITY_MPTR = 0x5100; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain // Solidity proof shim rewrites proof scalars into canonical BE words, @@ -149,11 +149,11 @@ contract Halo2Verifier { // side `evaluations` loop range-checks and spills that value here so // downstream eval references (gate evaluator + PCS q_eval Horner) // become 3-gas `mload(...)` instead of calldata reads. - uint256 internal constant REVERSED_EVALS_MPTR = 0x42e0; - uint256 internal constant SELECTOR_ACC_MPTR = 0x4fc0; - uint256 internal constant QUOTIENT_RETURN_MPTR = 0x80; - uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x4fc0; - uint256 internal constant TRACE_U256_MPTR = 0x7000; + uint256 internal constant REVERSED_EVALS_MPTR = 0x5260; + uint256 internal constant SELECTOR_ACC_MPTR = 0x5f40; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x5f40; + uint256 internal constant TRACE_U256_MPTR = 0x7940; // ---------------------------------------------------------------------- // Per-category bases for EIP-2537 padded G1 commitments. The proof @@ -170,13 +170,13 @@ contract Halo2Verifier { // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans // ---------------------------------------------------------------------- - uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x4840; - uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x4ac0; - uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x4b40; - uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x4cc0; - uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x4d40; - uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x4dc0; - uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x4dc0; + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x57c0; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x5a40; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x5ac0; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x5c40; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x5cc0; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x5d40; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x5d40; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. @@ -198,7 +198,7 @@ contract Halo2Verifier { function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Scratch is reused for every runtime-prerequisite probe. - let scratch := 0x80 + let scratch := 0x1000 // MCOPY must be available because the verifier uses it for // proof-time point/scratch staging. Execute the opcode here so a @@ -222,11 +222,44 @@ contract Halo2Verifier { revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair // smoke call. - let msm_scratch := 0x4fc0 + let msm_scratch := 0x5f40 for { let off := 0 } lt(off, 0x19a0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } @@ -329,7 +362,7 @@ contract Halo2Verifier { // guards against a future emitter passing a raw scalar. if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } - let p := 0x15e0 + let p := 0x2560 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] mstore(add(p, 0x00), 0x20) // base len @@ -566,7 +599,11 @@ contract Halo2Verifier { mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } @@ -598,7 +635,13 @@ contract Halo2Verifier { // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div @@ -1358,15 +1401,15 @@ contract Halo2Verifier { // q_const_mptr points to Fr constants used by the VM. // q_program_mptr points to the bytecode stream. // Constants are stored as consecutive 32-byte Fr words. - let q_const_mptr := 0x1ac0 + let q_const_mptr := 0x2a40 // Program bytes are also stored in the VK payload, packed into // 32-byte words by PackedProgramCodec. - let q_program_mptr := 0x1ac0 + let q_program_mptr := 0x2a40 // Running Horner accumulator for fully evaluated identities. // After all identities, this is nu_y(x) for the `None` // identity group. // Initialize A = 0 before scanning the identity stream. - mstore(0x5020, 0) + mstore(0x5fa0, 0) // Simple selectors are grouped into separate linearization // buckets. They start at zero for every proof. // q_sel_zero_off walks selector bucket byte offsets. @@ -1387,13 +1430,13 @@ contract Halo2Verifier { // block multiplies by mload(selector_power_mptr + offset) // unconditionally -- so initialize the slot rather than // leaving correctness to two filters in another file. - mstore(0x5060, 1) + mstore(0x5fe0, 1) // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 15) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) // Store y^i at selector_power_mptr + 32*i. - mstore(add(0x5060, shl(5, q_y_power_i)), q_y_power) + mstore(add(0x5fe0, shl(5, q_y_power_i)), q_y_power) } } @@ -1402,102 +1445,102 @@ contract Halo2Verifier { // VM/native identities, so they occupy the same y-batch order. { let var0 := 0x1 - let f_3 := mload(0x4520) - let f_4 := mload(0x4420) - let a_0 := mload(0x4300) + let f_3 := mload(0x54a0) + let f_4 := mload(0x53a0) + let a_0 := mload(0x5280) let var1 := mulmod(f_4, a_0, r) let var2 := addmod(f_3, var1, r) - let f_5 := mload(0x4440) - let a_1 := mload(0x4320) + let f_5 := mload(0x53c0) + let a_1 := mload(0x52a0) let var3 := mulmod(f_5, a_1, r) let var4 := addmod(var2, var3, r) - let f_6 := mload(0x4460) - let a_2 := mload(0x4340) + let f_6 := mload(0x53e0) + let a_2 := mload(0x52c0) let var5 := mulmod(f_6, a_2, r) let var6 := addmod(var4, var5, r) - let f_7 := mload(0x4480) - let a_3 := mload(0x4360) + let f_7 := mload(0x5400) + let a_3 := mload(0x52e0) let var7 := mulmod(f_7, a_3, r) let var8 := addmod(var6, var7, r) - let f_8 := mload(0x44a0) - let a_4 := mload(0x4380) + let f_8 := mload(0x5420) + let a_4 := mload(0x5300) let var9 := mulmod(f_8, a_4, r) let var10 := addmod(var8, var9, r) - let f_0 := mload(0x44c0) - let a_0_next_1 := mload(0x43a0) + let f_0 := mload(0x5440) + let a_0_next_1 := mload(0x5320) let var11 := mulmod(f_0, a_0_next_1, r) let var12 := addmod(var10, var11, r) - let f_1 := mload(0x44e0) + let f_1 := mload(0x5460) let var13 := mulmod(f_1, a_0, r) let var14 := mulmod(var13, a_1, r) let var15 := addmod(var12, var14, r) - let f_2 := mload(0x4500) + let f_2 := mload(0x5480) let var16 := mulmod(f_2, a_0, r) let var17 := mulmod(var16, a_2, r) let var18 := addmod(var15, var17, r) let var19 := mulmod(var0, var18, r) - mstore(0x5240, var19) + mstore(0x61c0, var19) } - mstore(0x5020, mulmod(mload(0x5020), y, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x5240), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } { let var0 := 0x1 - let a_1 := mload(0x4320) - let a_2 := mload(0x4340) + let a_1 := mload(0x52a0) + let a_2 := mload(0x52c0) let var1 := addmod(a_1, a_2, r) - let a_3 := mload(0x4360) + let a_3 := mload(0x52e0) let var2 := addmod(0, sub(r, a_3), r) let var3 := addmod(var1, var2, r) - let a_4 := mload(0x4380) + let a_4 := mload(0x5300) let var4 := addmod(0, sub(r, a_4), r) let var5 := addmod(var3, var4, r) let var6 := mulmod(var0, var5, r) - mstore(0x5240, var6) + mstore(0x61c0, var6) } - mstore(0x5020, mulmod(mload(0x5020), y, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x5240), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } { let var0 := 0x1 - let a_0 := mload(0x4300) - let f_4 := mload(0x4420) + let a_0 := mload(0x5280) + let f_4 := mload(0x53a0) let var1 := addmod(a_0, f_4, r) - let a_0_next_1 := mload(0x43a0) + let a_0_next_1 := mload(0x5320) let var2 := addmod(0, sub(r, a_0_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x5240, var4) + mstore(0x61c0, var4) } - mstore(0x5020, mulmod(mload(0x5020), y, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x5240), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } { let var0 := 0x1 - let a_1 := mload(0x4320) - let f_5 := mload(0x4440) + let a_1 := mload(0x52a0) + let f_5 := mload(0x53c0) let var1 := addmod(a_1, f_5, r) - let a_1_next_1 := mload(0x43c0) + let a_1_next_1 := mload(0x5340) let var2 := addmod(0, sub(r, a_1_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x5240, var4) + mstore(0x61c0, var4) } - mstore(0x5020, mulmod(mload(0x5020), y, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5060, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x5240), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x5fe0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } // VM registers: @@ -1517,7 +1560,7 @@ contract Halo2Verifier { // q_end is an exclusive byte pointer for the VM loop. let q_end := add(q_program_mptr, 0x05) // q_sp starts at the first free stack word. - let q_sp := 0x5240 + let q_sp := 0x61c0 // q_top is meaningless until q_has_top is set. let q_top := 0 // q_has_top = 0 means the VM stack is empty. @@ -1567,69 +1610,69 @@ contract Halo2Verifier { // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := 0x5240 + q_sp := 0x61c0 // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. { let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 - let q_perm_vals := 0x5240 - let q_perm_sigmas := 0x5340 - let q_perm_z_cur := 0x5440 - let q_perm_z_next := 0x54a0 - let q_perm_z_last := 0x5500 - let q_perm_delta_base_ptr := 0x5540 + let q_perm_vals := 0x61c0 + let q_perm_sigmas := 0x62c0 + let q_perm_z_cur := 0x63c0 + let q_perm_z_next := 0x6420 + let q_perm_z_last := 0x6480 + let q_perm_delta_base_ptr := 0x64c0 let q_perm_num_cols := 8 let q_perm_num_sets := 3 let q_perm_chunk_len := 3 let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 - mstore(add(q_perm_vals, 0x0), mload(0x4400)) + mstore(add(q_perm_vals, 0x0), mload(0x5380)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x4300, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x5280, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0xc0), mload(0x42e0)) + mstore(add(q_perm_vals, 0xc0), mload(0x5260)) mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) { for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 8) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off - mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x45c0, q_perm_sigma_load_src_off))) + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x5540, q_perm_sigma_load_src_off))) } } { for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 3) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) - mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x46c0, q_perm_z_cur_load_src_off))) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x5640, q_perm_z_cur_load_src_off))) } } { for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 3) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) - mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x46e0, q_perm_z_next_load_src_off))) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x5660, q_perm_z_next_load_src_off))) } } - mstore(add(q_perm_z_last, 0x0), mload(0x4700)) - mstore(add(q_perm_z_last, 0x20), mload(0x4760)) + mstore(add(q_perm_z_last, 0x0), mload(0x5680)) + mstore(add(q_perm_z_last, 0x20), mload(0x56e0)) let q_perm_eval := 0 q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_perm_eval, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_perm_eval, r)) let q_perm_zn := mload(add(q_perm_z_cur, 0x40)) q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_perm_eval, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_perm_eval, r)) for { let q_perm_i := 1 } lt(q_perm_i, 3) { q_perm_i := add(q_perm_i, 1) } { let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_perm_eval, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_perm_eval, r)) } mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) for { let q_perm_set := 0 } lt(q_perm_set, 3) { q_perm_set := add(q_perm_set, 1) } { @@ -1648,8 +1691,8 @@ contract Halo2Verifier { q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) } q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_perm_eval, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_perm_eval, r)) mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) } } @@ -1670,13 +1713,13 @@ contract Halo2Verifier { // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := 0x5240 + q_sp := 0x61c0 // Generated LogUp code follows the same y-batch order // as the Rust identity stream. { - let q_lookup_f := 0x5240 - let q_lookup_prefix := 0x52c0 - let q_lookup_suffix := 0x5340 + let q_lookup_f := 0x61c0 + let q_lookup_prefix := 0x6240 + let q_lookup_suffix := 0x62c0 let q_lookup_l0 := mload(L_0_MPTR) let q_lookup_llast := mload(L_LAST_MPTR) let q_lookup_lblind := mload(L_BLIND_MPTR) @@ -1686,17 +1729,17 @@ contract Halo2Verifier { let q_lookup_theta := mload(THETA_MPTR) { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x4800), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x5780), r) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_lookup_eval, r)) } { - let f_10 := mload(0x4540) + let f_10 := mload(0x54c0) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) let var1 := mulmod(var0, q_lookup_theta, r) for { let q_lookup_shared_i := 0 } lt(q_lookup_shared_i, 4) { q_lookup_shared_i := add(q_lookup_shared_i, 1) } { let q_lookup_shared_off := shl(5, q_lookup_shared_i) - let q_lookup_shared_tail := mload(add(0x4320, q_lookup_shared_off)) + let q_lookup_shared_tail := mload(add(0x52a0, q_lookup_shared_off)) let q_lookup_shared_compressed := addmod(var1, q_lookup_shared_tail, r) mstore(add(q_lookup_f, q_lookup_shared_off), addmod(q_lookup_shared_compressed, q_lookup_beta, r)) } @@ -1718,24 +1761,24 @@ contract Halo2Verifier { for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 4) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) } - let q_lookup_eval := addmod(mulmod(mload(0x47e0), q_lookup_product, r), sub(r, q_lookup_sum), r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x5760), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x47e0) - let f_16 := mload(0x45a0) - let f_11 := mload(0x4560) + let q_lookup_sum_h := mload(0x5760) + let f_16 := mload(0x5520) + let f_11 := mload(0x54e0) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) - let f_12 := mload(0x4580) + let f_12 := mload(0x5500) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) let q_lookup_s_sum_h := mulmod(f_16, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x4820), sub(r, addmod(mload(0x4800), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x57a0), sub(r, addmod(mload(0x5780), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x47c0), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x5740), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x5020, mulmod(mload(0x5020), y, r)) - mstore(0x5020, addmod(mload(0x5020), q_lookup_eval, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) + mstore(0x5fa0, addmod(mload(0x5fa0), q_lookup_eval, r)) } } } @@ -1756,27 +1799,27 @@ contract Halo2Verifier { // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := 0x5240 + q_sp := 0x61c0 // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx case 0 { { let var0 := 0x1 - let a_2 := mload(0x4340) - let f_6 := mload(0x4460) + let a_2 := mload(0x52c0) + let f_6 := mload(0x53e0) let var1 := addmod(a_2, f_6, r) - let a_2_next_1 := mload(0x43e0) + let a_2_next_1 := mload(0x5360) let var2 := addmod(0, sub(r, a_2_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x5240, var4) + mstore(0x61c0, var4) } - mstore(0x5020, mulmod(mload(0x5020), y, r)) + mstore(0x5fa0, mulmod(mload(0x5fa0), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x5060, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x5240), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x5fe0, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } } default { revert(0, 0) } @@ -1797,7 +1840,7 @@ contract Halo2Verifier { // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x5240)) { revert(0, 0) } + if iszero(eq(q_sp, 0x61c0)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -1815,21 +1858,21 @@ contract Halo2Verifier { // selector commitment in the linearized MSM. { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5060, 0x01c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5fe0, 0x01c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5060, 0x01a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5fe0, 0x01a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5060, 0x0140)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x5fe0, 0x0140)), r)) } // Fully evaluated identities are the constant-polynomial side // of the linearization query. Rust subtracts that grouped // scalar into expected_eval, so Solidity stores -nu_y(x). - let linearization_expected_eval := addmod(0, sub(r, mload(0x5020)), r) + let linearization_expected_eval := addmod(0, sub(r, mload(0x5fa0)), r) mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) pop(y) } @@ -1930,37 +1973,37 @@ contract Halo2Verifier { { // q_eval_set[0]: 28 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x5020, 0x4360) - mstore(0x5040, 0x4380) - mstore(0x5060, 0x42e0) - mstore(0x5080, 0x47c0) - mstore(0x50a0, 0x47e0) - mstore(0x50c0, 0x4400) - mstore(0x50e0, 0x4420) - mstore(0x5100, 0x4440) - mstore(0x5120, 0x4460) - mstore(0x5140, 0x4480) - mstore(0x5160, 0x44a0) - mstore(0x5180, 0x44c0) - mstore(0x51a0, 0x44e0) - mstore(0x51c0, 0x4500) - mstore(0x51e0, 0x4520) - mstore(0x5200, 0x4540) - mstore(0x5220, 0x4560) - mstore(0x5240, 0x4580) - mstore(0x5260, 0x45a0) - mstore(0x5280, 0x45c0) - mstore(0x52a0, 0x45e0) - mstore(0x52c0, 0x4600) - mstore(0x52e0, 0x4620) - mstore(0x5300, 0x4640) - mstore(0x5320, 0x4660) - mstore(0x5340, 0x4680) - mstore(0x5360, 0x46a0) - mstore(0x5380, QUOTIENT_EVAL_MPTR) - let q_eval_set_0 := mload(0x4360) + mstore(0x5fa0, 0x52e0) + mstore(0x5fc0, 0x5300) + mstore(0x5fe0, 0x5260) + mstore(0x6000, 0x5740) + mstore(0x6020, 0x5760) + mstore(0x6040, 0x5380) + mstore(0x6060, 0x53a0) + mstore(0x6080, 0x53c0) + mstore(0x60a0, 0x53e0) + mstore(0x60c0, 0x5400) + mstore(0x60e0, 0x5420) + mstore(0x6100, 0x5440) + mstore(0x6120, 0x5460) + mstore(0x6140, 0x5480) + mstore(0x6160, 0x54a0) + mstore(0x6180, 0x54c0) + mstore(0x61a0, 0x54e0) + mstore(0x61c0, 0x5500) + mstore(0x61e0, 0x5520) + mstore(0x6200, 0x5540) + mstore(0x6220, 0x5560) + mstore(0x6240, 0x5580) + mstore(0x6260, 0x55a0) + mstore(0x6280, 0x55c0) + mstore(0x62a0, 0x55e0) + mstore(0x62c0, 0x5600) + mstore(0x62e0, 0x5620) + mstore(0x6300, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x52e0) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x5020, 0x20) + let eval_p := add(0x5fa0, 0x20) for { let i := 1 } lt(i, 0x1c) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -1975,20 +2018,20 @@ contract Halo2Verifier { { // q_eval_set[1]: 5 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x5020, 0x4300) - mstore(0x5040, 0x43a0) - mstore(0x5060, 0x4320) - mstore(0x5080, 0x43c0) - mstore(0x50a0, 0x4340) - mstore(0x50c0, 0x43e0) - mstore(0x50e0, 0x4780) - mstore(0x5100, 0x47a0) - mstore(0x5120, 0x4800) - mstore(0x5140, 0x4820) - let q_eval_set_0 := mload(0x4300) - let q_eval_set_1 := mload(0x43a0) + mstore(0x5fa0, 0x5280) + mstore(0x5fc0, 0x5320) + mstore(0x5fe0, 0x52a0) + mstore(0x6000, 0x5340) + mstore(0x6020, 0x52c0) + mstore(0x6040, 0x5360) + mstore(0x6060, 0x5700) + mstore(0x6080, 0x5720) + mstore(0x60a0, 0x5780) + mstore(0x60c0, 0x57a0) + let q_eval_set_0 := mload(0x5280) + let q_eval_set_1 := mload(0x5320) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x5020, 0x40) + let eval_p := add(0x5fa0, 0x40) for { let i := 1 } lt(i, 0x5) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2004,12 +2047,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[2]: 2 commitment(s) - let q_eval_set_0 := mload(0x46c0) - let q_eval_set_1 := mload(0x46e0) - let q_eval_set_2 := mload(0x4700) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x4720), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x4740), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x4760), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + let q_eval_set_0 := mload(0x5640) + let q_eval_set_1 := mload(0x5660) + let q_eval_set_2 := mload(0x5680) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x56a0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x56c0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x56e0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0xa0), q_eval_set_2) @@ -2129,95 +2172,95 @@ contract Halo2Verifier { v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x20)), x4_pow_1, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_3, r), r) - mcopy(0x5020, 0x49c0, 0x80) - mstore(0x50a0, 1) - mcopy(0x50c0, 0x4a40, 0x80) - mstore(0x5140, mload(add(X1_POWERS_MPTR, 0x20))) - mcopy(0x5160, 0x4ac0, 0x80) - mstore(0x51e0, mload(add(X1_POWERS_MPTR, 0x60))) - mcopy(0x5200, 0x4cc0, 0x80) - mstore(0x5280, mload(add(X1_POWERS_MPTR, 0x80))) - mcopy(0x52a0, 0x1f60, 0x80) - mstore(0x5320, mload(add(X1_POWERS_MPTR, 0xa0))) - mcopy(0x5340, 0x1ce0, 0x80) - mstore(0x53c0, mload(add(X1_POWERS_MPTR, 0xc0))) - mcopy(0x53e0, 0x1d60, 0x80) - mstore(0x5460, mload(add(X1_POWERS_MPTR, 0xe0))) - mcopy(0x5480, 0x1de0, 0x80) - mstore(0x5500, mload(add(X1_POWERS_MPTR, 0x100))) - mcopy(0x5520, 0x1e60, 0x80) - mstore(0x55a0, mload(add(X1_POWERS_MPTR, 0x120))) - mcopy(0x55c0, 0x1ee0, 0x80) - mstore(0x5640, mload(add(X1_POWERS_MPTR, 0x140))) - mcopy(0x5660, 0x1ae0, 0x80) - mstore(0x56e0, mload(add(X1_POWERS_MPTR, 0x160))) - mcopy(0x5700, 0x1b60, 0x80) - mstore(0x5780, mload(add(X1_POWERS_MPTR, 0x180))) - mcopy(0x57a0, 0x1be0, 0x80) - mstore(0x5820, mload(add(X1_POWERS_MPTR, 0x1a0))) - mcopy(0x5840, 0x1c60, 0x80) - mstore(0x58c0, mload(add(X1_POWERS_MPTR, 0x1c0))) - mcopy(0x58e0, 0x1fe0, 0x80) - mstore(0x5960, mload(add(X1_POWERS_MPTR, 0x1e0))) - mcopy(0x5980, 0x2060, 0x80) - mstore(0x5a00, mload(add(X1_POWERS_MPTR, 0x200))) - mcopy(0x5a20, 0x20e0, 0x80) - mstore(0x5aa0, mload(add(X1_POWERS_MPTR, 0x220))) - mcopy(0x5ac0, 0x22e0, 0x80) - mstore(0x5b40, mload(add(X1_POWERS_MPTR, 0x240))) - mcopy(0x5b60, 0x2360, 0x80) - mstore(0x5be0, mload(add(X1_POWERS_MPTR, 0x260))) - mcopy(0x5c00, 0x23e0, 0x80) - mstore(0x5c80, mload(add(X1_POWERS_MPTR, 0x280))) - mcopy(0x5ca0, 0x2460, 0x80) - mstore(0x5d20, mload(add(X1_POWERS_MPTR, 0x2a0))) - mcopy(0x5d40, 0x24e0, 0x80) - mstore(0x5dc0, mload(add(X1_POWERS_MPTR, 0x2c0))) - mcopy(0x5de0, 0x2560, 0x80) - mstore(0x5e60, mload(add(X1_POWERS_MPTR, 0x2e0))) - mcopy(0x5e80, 0x25e0, 0x80) - mstore(0x5f00, mload(add(X1_POWERS_MPTR, 0x300))) - mcopy(0x5f20, 0x2660, 0x80) - mstore(0x5fa0, mload(add(X1_POWERS_MPTR, 0x320))) - mcopy(0x5fc0, 0x26e0, 0x80) - mstore(0x6040, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0x5fa0, 0x5940, 0x80) + mstore(0x6020, 1) + mcopy(0x6040, 0x59c0, 0x80) + mstore(0x60c0, mload(add(X1_POWERS_MPTR, 0x20))) + mcopy(0x60e0, 0x5a40, 0x80) + mstore(0x6160, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0x6180, 0x5c40, 0x80) + mstore(0x6200, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0x6220, 0x2ee0, 0x80) + mstore(0x62a0, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0x62c0, 0x2c60, 0x80) + mstore(0x6340, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0x6360, 0x2ce0, 0x80) + mstore(0x63e0, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0x6400, 0x2d60, 0x80) + mstore(0x6480, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0x64a0, 0x2de0, 0x80) + mstore(0x6520, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0x6540, 0x2e60, 0x80) + mstore(0x65c0, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0x65e0, 0x2a60, 0x80) + mstore(0x6660, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0x6680, 0x2ae0, 0x80) + mstore(0x6700, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0x6720, 0x2b60, 0x80) + mstore(0x67a0, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0x67c0, 0x2be0, 0x80) + mstore(0x6840, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0x6860, 0x2f60, 0x80) + mstore(0x68e0, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0x6900, 0x2fe0, 0x80) + mstore(0x6980, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0x69a0, 0x3060, 0x80) + mstore(0x6a20, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0x6a40, 0x3260, 0x80) + mstore(0x6ac0, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0x6ae0, 0x32e0, 0x80) + mstore(0x6b60, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0x6b80, 0x3360, 0x80) + mstore(0x6c00, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0x6c20, 0x33e0, 0x80) + mstore(0x6ca0, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0x6cc0, 0x3460, 0x80) + mstore(0x6d40, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0x6d60, 0x34e0, 0x80) + mstore(0x6de0, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0x6e00, 0x3560, 0x80) + mstore(0x6e80, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0x6ea0, 0x35e0, 0x80) + mstore(0x6f20, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0x6f40, 0x3660, 0x80) + mstore(0x6fc0, mload(add(X1_POWERS_MPTR, 0x340))) let lin_query_scalar_26 := mload(add(X1_POWERS_MPTR, 0x360)) let lin_cur_scalar_26 := mulmod(lin_query_scalar_26, lin_one_minus_x_n, r) - mcopy(0x6060, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) - mstore(0x60e0, lin_cur_scalar_26) + mcopy(0x6fe0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0x7060, lin_cur_scalar_26) lin_cur_scalar_26 := mulmod(lin_cur_scalar_26, lin_x_split, r) - mcopy(0x6100, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) - mstore(0x6180, lin_cur_scalar_26) + mcopy(0x7080, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0x7100, lin_cur_scalar_26) lin_cur_scalar_26 := mulmod(lin_cur_scalar_26, lin_x_split, r) - mcopy(0x61a0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) - mstore(0x6220, lin_cur_scalar_26) + mcopy(0x7120, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0x71a0, lin_cur_scalar_26) lin_cur_scalar_26 := mulmod(lin_cur_scalar_26, lin_x_split, r) - mcopy(0x6240, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) - mstore(0x62c0, lin_cur_scalar_26) - mcopy(0x62e0, 0x2160, 0x80) - mstore(0x6360, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) - mcopy(0x6380, 0x21e0, 0x80) - mstore(0x6400, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) - mcopy(0x6420, 0x2260, 0x80) - mstore(0x64a0, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) - mcopy(0x64c0, 0x4840, 0x80) - mstore(0x6540, x4_pow_1) - mcopy(0x6560, 0x48c0, 0x80) - mstore(0x65e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) - mcopy(0x6600, 0x4940, 0x80) - mstore(0x6680, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) - mcopy(0x66a0, 0x4c40, 0x80) - mstore(0x6720, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_1, r)) - mcopy(0x6740, 0x4d40, 0x80) - mstore(0x67c0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_1, r)) - mcopy(0x67e0, 0x4b40, 0x80) - mstore(0x6860, x4_pow_2) - mcopy(0x6880, 0x4bc0, 0x80) - mstore(0x6900, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) - mcopy(0x6920, F_COM_MPTR, 0x80) - mstore(0x69a0, x4_pow_3) + mcopy(0x71c0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0x7240, lin_cur_scalar_26) + mcopy(0x7260, 0x30e0, 0x80) + mstore(0x72e0, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0x7300, 0x3160, 0x80) + mstore(0x7380, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0x73a0, 0x31e0, 0x80) + mstore(0x7420, mulmod(lin_query_scalar_26, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0x7440, 0x57c0, 0x80) + mstore(0x74c0, x4_pow_1) + mcopy(0x74e0, 0x5840, 0x80) + mstore(0x7560, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0x7580, 0x58c0, 0x80) + mstore(0x7600, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0x7620, 0x5bc0, 0x80) + mstore(0x76a0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_1, r)) + mcopy(0x76c0, 0x5cc0, 0x80) + mstore(0x7740, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_1, r)) + mcopy(0x7760, 0x5ac0, 0x80) + mstore(0x77e0, x4_pow_2) + mcopy(0x7800, 0x5b40, 0x80) + mstore(0x7880, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0x78a0, F_COM_MPTR, 0x80) + mstore(0x7920, x4_pow_3) if success { - success := staticcall(gas(), 0x0c, 0x5020, 0x19a0, FINAL_COM_MPTR, 0x80) + success := staticcall(gas(), 0x0c, 0x5fa0, 0x19a0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2229,28 +2272,28 @@ contract Halo2Verifier { // Scale z*pi - vG before the final pairing check // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) - mcopy(0x80, G1_BASE_MPTR, 0x80) - mstore(0x100, addmod(0, sub(r, mload(V_MPTR)), r)) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x80, 0xa0, 0x80, 0x80) + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, FINAL_COM_MPTR, 0x80) + mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, PI_MPTR, 0x80) - mstore(0x180, mload(X3_MPTR)) + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x100, 0xa0, 0x100, 0x80) + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(PAIRING_RHS_MPTR, 0x80, 0x80) + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 9a8fd44af..150bbd4be 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -43,7 +43,7 @@ contract Halo2Verifier { // EXPECTED_VK_PAYLOAD_LENGTH. uint256 internal constant EXPECTED_VK_PAYLOAD_LENGTH = 8032; uint256 internal constant EXPECTED_VK_LENGTH = 8033; - uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x327e3a0642d1a157521eb891596256086b59006348710f0cd960b89ed35e5854; + uint256 internal constant EXPECTED_VK_CODEHASH_WORD = 0x677b7b26592c167d44fd428a1d743abb1eb2fd8040804bd032440791caeb7471; bytes32 internal constant EXPECTED_VK_CODEHASH = bytes32(EXPECTED_VK_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -55,8 +55,8 @@ contract Halo2Verifier { uint256 internal constant INSTANCE_CPTR = 0x1504; // First general-purpose memory words reserved by the generated verifier. // RETURN_MPTR is a single word set to 1 on success. - uint256 internal constant TRANSCRIPT_MPTR = 0x80; - uint256 internal constant RETURN_MPTR = 0x80; + uint256 internal constant TRANSCRIPT_MPTR = 0x1000; + uint256 internal constant RETURN_MPTR = 0x1000; // ---------------------------------------------------------------------- // Verifying-key memory map. The VK header lives at VK_MPTR, followed @@ -64,84 +64,84 @@ contract Halo2Verifier { // runtime comes the challenge slots (challenge_mptr..) and the // per-stage scratch (theta_mptr..). // ---------------------------------------------------------------------- - uint256 internal constant VK_MPTR = 0x1d20; - uint256 internal constant VK_DIGEST_MPTR = 0x1d20; - uint256 internal constant NUM_INSTANCES_MPTR = 0x1d40; - uint256 internal constant K_MPTR = 0x1d60; - uint256 internal constant N_INV_MPTR = 0x1d80; - uint256 internal constant OMEGA_MPTR = 0x1da0; - uint256 internal constant OMEGA_INV_MPTR = 0x1dc0; - uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x1de0; - uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x1e00; - uint256 internal constant ACC_OFFSET_MPTR = 0x1e20; - uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x1e40; - uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x1e60; - uint256 internal constant G1_BASE_MPTR = 0x1e80; - uint256 internal constant G2_BASE_MPTR = 0x1f00; - uint256 internal constant NEG_S_G2_BASE_MPTR = 0x2000; - - uint256 internal constant CHALLENGE_MPTR = 0x3c80; + uint256 internal constant VK_MPTR = 0x2ca0; + uint256 internal constant VK_DIGEST_MPTR = 0x2ca0; + uint256 internal constant NUM_INSTANCES_MPTR = 0x2cc0; + uint256 internal constant K_MPTR = 0x2ce0; + uint256 internal constant N_INV_MPTR = 0x2d00; + uint256 internal constant OMEGA_MPTR = 0x2d20; + uint256 internal constant OMEGA_INV_MPTR = 0x2d40; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x2d60; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x2d80; + uint256 internal constant ACC_OFFSET_MPTR = 0x2da0; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x2dc0; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x2de0; + uint256 internal constant G1_BASE_MPTR = 0x2e00; + uint256 internal constant G2_BASE_MPTR = 0x2e80; + uint256 internal constant NEG_S_G2_BASE_MPTR = 0x2f80; + + uint256 internal constant CHALLENGE_MPTR = 0x4c00; // Challenge layout. Squeeze order in midnight-proofs: // user_phase challenges (variable count) // theta -> beta, gamma -> trash_challenge -> y -> x -> // x1, x2 -> x3 -> x4 - uint256 internal constant THETA_MPTR = 0x3c80; - uint256 internal constant BETA_MPTR = 0x3ca0; - uint256 internal constant GAMMA_MPTR = 0x3cc0; - uint256 internal constant TRASH_CHALLENGE_MPTR = 0x3ce0; - uint256 internal constant Y_MPTR = 0x3d00; - uint256 internal constant X_MPTR = 0x3d20; - uint256 internal constant X1_MPTR = 0x3d40; - uint256 internal constant X2_MPTR = 0x3d60; - uint256 internal constant X3_MPTR = 0x3d80; - uint256 internal constant X4_MPTR = 0x3da0; + uint256 internal constant THETA_MPTR = 0x4c00; + uint256 internal constant BETA_MPTR = 0x4c20; + uint256 internal constant GAMMA_MPTR = 0x4c40; + uint256 internal constant TRASH_CHALLENGE_MPTR = 0x4c60; + uint256 internal constant Y_MPTR = 0x4c80; + uint256 internal constant X_MPTR = 0x4ca0; + uint256 internal constant X1_MPTR = 0x4cc0; + uint256 internal constant X2_MPTR = 0x4ce0; + uint256 internal constant X3_MPTR = 0x4d00; + uint256 internal constant X4_MPTR = 0x4d20; // Batch-open commitments live in 4-word EIP-2537 padded slots. - uint256 internal constant F_COM_MPTR = 0x3dc0; - uint256 internal constant PI_MPTR = 0x3e40; + uint256 internal constant F_COM_MPTR = 0x4d40; + uint256 internal constant PI_MPTR = 0x4dc0; // Accumulator (KZG IVC). - uint256 internal constant ACC_LHS_MPTR = 0x3ec0; - uint256 internal constant ACC_RHS_MPTR = 0x3f40; + uint256 internal constant ACC_LHS_MPTR = 0x4e40; + uint256 internal constant ACC_RHS_MPTR = 0x4ec0; // Lagrange / linearization scratch. - uint256 internal constant X_N_MPTR = 0x3fc0; - uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x3fe0; - uint256 internal constant L_LAST_MPTR = 0x4000; - uint256 internal constant L_BLIND_MPTR = 0x4020; - uint256 internal constant L_0_MPTR = 0x4040; - uint256 internal constant INSTANCE_EVAL_MPTR = 0x4060; + uint256 internal constant X_N_MPTR = 0x4f40; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x4f60; + uint256 internal constant L_LAST_MPTR = 0x4f80; + uint256 internal constant L_BLIND_MPTR = 0x4fa0; + uint256 internal constant L_0_MPTR = 0x4fc0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x4fe0; // Legacy name: this is not h(x). It stores the expected opening // scalar for the linearized commitment, i.e. the negated y-batched // identity numerator reconstructed from the alleged evals at x. - uint256 internal constant QUOTIENT_EVAL_MPTR = 0x4080; - uint256 internal constant QUOTIENT_MPTR = 0x40a0; // 4 words - uint256 internal constant F_EVAL_MPTR = 0x4140; - uint256 internal constant V_MPTR = 0x4160; - uint256 internal constant FINAL_COM_MPTR = 0x4180; // 4 words - uint256 internal constant PAIRING_LHS_MPTR = 0x4200; // 4 words - uint256 internal constant PAIRING_RHS_MPTR = 0x4280; // 4 words + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x5000; + uint256 internal constant QUOTIENT_MPTR = 0x5020; // 4 words + uint256 internal constant F_EVAL_MPTR = 0x50c0; + uint256 internal constant V_MPTR = 0x50e0; + uint256 internal constant FINAL_COM_MPTR = 0x5100; // 4 words + uint256 internal constant PAIRING_LHS_MPTR = 0x5180; // 4 words + uint256 internal constant PAIRING_RHS_MPTR = 0x5200; // 4 words // Multi-prepare scratch (sized at codegen time). - uint256 internal constant ROT_POINTS_MPTR = 0x4300; - uint256 internal constant X1_POWERS_MPTR = 0x4680; + uint256 internal constant ROT_POINTS_MPTR = 0x5280; + uint256 internal constant X1_POWERS_MPTR = 0x5600; // Q_COM materialization is currently fused into the final MSM scratch, // so this marker intentionally aliases Q_EVAL_SET_MPTR and has zero // reserved capacity until a future emitter starts writing Q_COM_MPTR. - uint256 internal constant Q_COM_MPTR = 0x4ea0; - uint256 internal constant Q_EVAL_SET_MPTR = 0x4ea0; + uint256 internal constant Q_COM_MPTR = 0x5e20; + uint256 internal constant Q_EVAL_SET_MPTR = 0x5e20; // Q_EVAL_CPTR is set at runtime once the verifier reaches the q_evals // block of the proof; we keep it as a memory slot for symmetry. - uint256 internal constant Q_EVAL_CPTR_MPTR = 0x55a0; + uint256 internal constant Q_EVAL_CPTR_MPTR = 0x6520; // Reserved 4-word slot for the G1 identity (point at infinity) in // EIP-2537 padded form. EVM memory is zero-initialised, and we // never write to this region, so the four `mload`s below produce // 0,0,0,0 which is exactly the identity encoding the EIP-2537 // ec_add / ec_mul precompiles accept. - uint256 internal constant G1_IDENTITY_MPTR = 0x56a0; + uint256 internal constant G1_IDENTITY_MPTR = 0x6620; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain // Solidity proof shim rewrites proof scalars into canonical BE words, @@ -149,11 +149,11 @@ contract Halo2Verifier { // side `evaluations` loop range-checks and spills that value here so // downstream eval references (gate evaluator + PCS q_eval Horner) // become 3-gas `mload(...)` instead of calldata reads. - uint256 internal constant REVERSED_EVALS_MPTR = 0x5800; - uint256 internal constant SELECTOR_ACC_MPTR = 0x6b00; - uint256 internal constant QUOTIENT_RETURN_MPTR = 0x80; - uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x6b00; - uint256 internal constant TRACE_U256_MPTR = 0x9420; + uint256 internal constant REVERSED_EVALS_MPTR = 0x6780; + uint256 internal constant SELECTOR_ACC_MPTR = 0x7a80; + uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; + uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x7a80; + uint256 internal constant TRACE_U256_MPTR = 0xa3a0; // ---------------------------------------------------------------------- // Per-category bases for EIP-2537 padded G1 commitments. The proof @@ -170,13 +170,13 @@ contract Halo2Verifier { // TRASHCAN_COMMS_MPTR_BASE + ... + 4*num_lookups // QUOTIENT_LIMB_COMMS_MPTR_BASE + ... + 4*num_trashcans // ---------------------------------------------------------------------- - uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x6080; - uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x6480; - uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x6580; - uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x6700; - uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x6800; - uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x6900; - uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x6900; + uint256 internal constant ADVICE_COMMS_MPTR_BASE = 0x7000; + uint256 internal constant LOOKUP_M_COMMS_MPTR_BASE = 0x7400; + uint256 internal constant PERM_Z_COMMS_MPTR_BASE = 0x7500; + uint256 internal constant LOOKUP_HELPER_COMMS_MPTR_BASE = 0x7680; + uint256 internal constant LOOKUP_Z_COMMS_MPTR_BASE = 0x7780; + uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x7880; + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x7880; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. @@ -198,7 +198,7 @@ contract Halo2Verifier { function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Scratch is reused for every runtime-prerequisite probe. - let scratch := 0x80 + let scratch := 0x1000 // MCOPY must be available because the verifier uses it for // proof-time point/scratch staging. Execute the opcode here so a @@ -222,11 +222,44 @@ contract Halo2Verifier { revert(0, 0) } + // Known-answer probe: G1ADD(G, G) == 2G. + // + // Every probe above uses the point at infinity, which is exactly + // the input an implementation gets right without doing any curve + // arithmetic -- a precompile that returns its zero-filled input, or + // zeros for anything, satisfies them. The identity is also the one + // input on which an implementation that omits the EIP-2537 subgroup + // check still answers correctly, and the production verifier leans + // on G1MSM as its subgroup validator for absorbed commitments. So + // add one vector whose answer a stub cannot guess. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mcopy(add(scratch, 0x80), scratch, 0x80) + if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { + mstore(add(scratch, off), 0) + } + // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input // length rendered by this verifier instead of only a one-pair // smoke call. - let msm_scratch := 0x6b00 + let msm_scratch := 0x7a80 for { let off := 0 } lt(off, 0x2760) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } @@ -329,7 +362,7 @@ contract Halo2Verifier { // guards against a future emitter passing a raw scalar. if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } if iszero(x) { revert(0, 0) } - let p := 0x1c20 + let p := 0x2ba0 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] mstore(add(p, 0x00), 0x20) // base len @@ -566,7 +599,11 @@ contract Halo2Verifier { mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) - ret := and(ret, mload(scratch)) + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. + ret := and(ret, eq(mload(scratch), 1)) if iszero(ret) { revert(0, 0) } ret := 1 } @@ -598,7 +635,13 @@ contract Halo2Verifier { // public input. `first_adjust` removes the identity flag // base from the first x word when present. let packed := calldataload(add(src, mul(div(i, limbs_per_word), 0x20))) - if and(iszero(div(i, limbs_per_word)), first_adjust) { + // `and` here is bitwise, so it must not be fed the raw + // `first_adjust` (a radix base, i.e. a high power of two): + // `iszero(...)` is 0 or 1 and shares no bit with it, which + // would make the guard false for every call. Subtracting is + // already a no-op when `first_adjust` is zero, so gate on + // the word index alone. + if iszero(div(i, limbs_per_word)) { packed := sub(packed, first_adjust) } // Select limb i from its packed field word. The mod/div @@ -1374,15 +1417,15 @@ contract Halo2Verifier { // q_const_mptr points to Fr constants used by the VM. // q_program_mptr points to the bytecode stream. // Constants are stored as consecutive 32-byte Fr words. - let q_const_mptr := 0x2100 + let q_const_mptr := 0x3080 // Program bytes are also stored in the VK payload, packed into // 32-byte words by PackedProgramCodec. - let q_program_mptr := 0x2660 + let q_program_mptr := 0x35e0 // Running Horner accumulator for fully evaluated identities. // After all identities, this is nu_y(x) for the `None` // identity group. // Initialize A = 0 before scanning the identity stream. - mstore(0x6cc0, 0) + mstore(0x7c40, 0) // Simple selectors are grouped into separate linearization // buckets. They start at zero for every proof. // q_sel_zero_off walks selector bucket byte offsets. @@ -1403,13 +1446,13 @@ contract Halo2Verifier { // block multiplies by mload(selector_power_mptr + offset) // unconditionally -- so initialize the slot rather than // leaving correctness to two filters in another file. - mstore(0x6d00, 1) + mstore(0x7c80, 1) // Start at i=1 because y^0 = 1 is written above. for { let q_y_power_i := 1 } lt(q_y_power_i, 35) { q_y_power_i := add(q_y_power_i, 1) } { // Advance from y^(i-1) to y^i modulo Fr. q_y_power := mulmod(q_y_power, y, r) // Store y^i at selector_power_mptr + 32*i. - mstore(add(0x6d00, shl(5, q_y_power_i)), q_y_power) + mstore(add(0x7c80, shl(5, q_y_power_i)), q_y_power) } } @@ -1418,102 +1461,102 @@ contract Halo2Verifier { // VM/native identities, so they occupy the same y-batch order. { let var0 := 0x1 - let f_3 := mload(0x5c40) - let f_4 := mload(0x5b40) - let a_0 := mload(0x5820) + let f_3 := mload(0x6bc0) + let f_4 := mload(0x6ac0) + let a_0 := mload(0x67a0) let var1 := mulmod(f_4, a_0, r) let var2 := addmod(f_3, var1, r) - let f_5 := mload(0x5b60) - let a_1 := mload(0x5840) + let f_5 := mload(0x6ae0) + let a_1 := mload(0x67c0) let var3 := mulmod(f_5, a_1, r) let var4 := addmod(var2, var3, r) - let f_6 := mload(0x5b80) - let a_2 := mload(0x5860) + let f_6 := mload(0x6b00) + let a_2 := mload(0x67e0) let var5 := mulmod(f_6, a_2, r) let var6 := addmod(var4, var5, r) - let f_7 := mload(0x5ba0) - let a_3 := mload(0x5880) + let f_7 := mload(0x6b20) + let a_3 := mload(0x6800) let var7 := mulmod(f_7, a_3, r) let var8 := addmod(var6, var7, r) - let f_8 := mload(0x5bc0) - let a_4 := mload(0x58a0) + let f_8 := mload(0x6b40) + let a_4 := mload(0x6820) let var9 := mulmod(f_8, a_4, r) let var10 := addmod(var8, var9, r) - let f_0 := mload(0x5be0) - let a_0_next_1 := mload(0x58c0) + let f_0 := mload(0x6b60) + let a_0_next_1 := mload(0x6840) let var11 := mulmod(f_0, a_0_next_1, r) let var12 := addmod(var10, var11, r) - let f_1 := mload(0x5c00) + let f_1 := mload(0x6b80) let var13 := mulmod(f_1, a_0, r) let var14 := mulmod(var13, a_1, r) let var15 := addmod(var12, var14, r) - let f_2 := mload(0x5c20) + let f_2 := mload(0x6ba0) let var16 := mulmod(f_2, a_0, r) let var17 := mulmod(var16, a_2, r) let var18 := addmod(var15, var17, r) let var19 := mulmod(var0, var18, r) - mstore(0x7160, var19) + mstore(0x80e0, var19) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } { let var0 := 0x1 - let a_1 := mload(0x5840) - let a_2 := mload(0x5860) + let a_1 := mload(0x67c0) + let a_2 := mload(0x67e0) let var1 := addmod(a_1, a_2, r) - let a_3 := mload(0x5880) + let a_3 := mload(0x6800) let var2 := addmod(0, sub(r, a_3), r) let var3 := addmod(var1, var2, r) - let a_4 := mload(0x58a0) + let a_4 := mload(0x6820) let var4 := addmod(0, sub(r, a_4), r) let var5 := addmod(var3, var4, r) let var6 := mulmod(var0, var5, r) - mstore(0x7160, var6) + mstore(0x80e0, var6) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x20) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } { let var0 := 0x1 - let a_0 := mload(0x5820) - let f_4 := mload(0x5b40) + let a_0 := mload(0x67a0) + let f_4 := mload(0x6ac0) let var1 := addmod(a_0, f_4, r) - let a_0_next_1 := mload(0x58c0) + let a_0_next_1 := mload(0x6840) let var2 := addmod(0, sub(r, a_0_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x7160, var4) + mstore(0x80e0, var4) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } { let var0 := 0x1 - let a_1 := mload(0x5840) - let f_5 := mload(0x5b60) + let a_1 := mload(0x67c0) + let f_5 := mload(0x6ae0) let var1 := addmod(a_1, f_5, r) - let a_1_next_1 := mload(0x58e0) + let a_1_next_1 := mload(0x6860) let var2 := addmod(0, sub(r, a_1_next_1), r) let var3 := addmod(var1, var2, r) let var4 := mulmod(var0, var3, r) - mstore(0x7160, var4) + mstore(0x80e0, var4) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x40) let q_selector_acc := mload(q_selector_ptr) - q_selector_acc := mulmod(q_selector_acc, mload(add(0x6d00, 0x20)), r) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + q_selector_acc := mulmod(q_selector_acc, mload(add(0x7c80, 0x20)), r) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } // VM registers: @@ -1533,7 +1576,7 @@ contract Halo2Verifier { // q_end is an exclusive byte pointer for the VM loop. let q_end := add(q_program_mptr, 0x019b) // q_sp starts at the first free stack word. - let q_sp := 0x7160 + let q_sp := 0x80e0 // q_top is meaningless until q_has_top is set. let q_top := 0 // q_has_top = 0 means the VM stack is empty. @@ -1864,70 +1907,70 @@ contract Halo2Verifier { // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := 0x7160 + q_sp := 0x80e0 // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. { let delta := 0x8634d0aa021aaf843cab354fabb0062f6502437c6a09c006c083479590189d7 - let q_perm_vals := 0x7160 - let q_perm_sigmas := 0x7280 - let q_perm_z_cur := 0x73a0 - let q_perm_z_next := 0x7400 - let q_perm_z_last := 0x7460 - let q_perm_delta_base_ptr := 0x74a0 + let q_perm_vals := 0x80e0 + let q_perm_sigmas := 0x8200 + let q_perm_z_cur := 0x8320 + let q_perm_z_next := 0x8380 + let q_perm_z_last := 0x83e0 + let q_perm_delta_base_ptr := 0x8420 let q_perm_num_cols := 9 let q_perm_num_sets := 3 let q_perm_chunk_len := 3 let q_perm_delta_chunk := 0x4285088329c399ea457a8ca1d30f8957e74c7f529842a1579b4fee55b3982923 - mstore(add(q_perm_vals, 0x0), mload(0x5b20)) + mstore(add(q_perm_vals, 0x0), mload(0x6aa0)) { for { let q_perm_val_load_i := 0 } lt(q_perm_val_load_i, 5) { q_perm_val_load_i := add(q_perm_val_load_i, 1) } { let q_perm_val_load_dst_off := shl(5, q_perm_val_load_i) let q_perm_val_load_src_off := q_perm_val_load_dst_off - mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x5820, q_perm_val_load_src_off))) + mstore(add(add(q_perm_vals, 0x20), q_perm_val_load_dst_off), mload(add(0x67a0, q_perm_val_load_src_off))) } } - mstore(add(q_perm_vals, 0xc0), mload(0x5800)) + mstore(add(q_perm_vals, 0xc0), mload(0x6780)) mstore(add(q_perm_vals, 0xe0), mload(INSTANCE_EVAL_MPTR)) - mstore(add(q_perm_vals, 0x100), mload(0x5920)) + mstore(add(q_perm_vals, 0x100), mload(0x68a0)) { for { let q_perm_sigma_load_i := 0 } lt(q_perm_sigma_load_i, 9) { q_perm_sigma_load_i := add(q_perm_sigma_load_i, 1) } { let q_perm_sigma_load_dst_off := shl(5, q_perm_sigma_load_i) let q_perm_sigma_load_src_off := q_perm_sigma_load_dst_off - mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x5d60, q_perm_sigma_load_src_off))) + mstore(add(add(q_perm_sigmas, 0x0), q_perm_sigma_load_dst_off), mload(add(0x6ce0, q_perm_sigma_load_src_off))) } } { for { let q_perm_z_cur_load_i := 0 } lt(q_perm_z_cur_load_i, 3) { q_perm_z_cur_load_i := add(q_perm_z_cur_load_i, 1) } { let q_perm_z_cur_load_dst_off := shl(5, q_perm_z_cur_load_i) let q_perm_z_cur_load_src_off := mul(q_perm_z_cur_load_i, 0x60) - mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x5e80, q_perm_z_cur_load_src_off))) + mstore(add(add(q_perm_z_cur, 0x0), q_perm_z_cur_load_dst_off), mload(add(0x6e00, q_perm_z_cur_load_src_off))) } } { for { let q_perm_z_next_load_i := 0 } lt(q_perm_z_next_load_i, 3) { q_perm_z_next_load_i := add(q_perm_z_next_load_i, 1) } { let q_perm_z_next_load_dst_off := shl(5, q_perm_z_next_load_i) let q_perm_z_next_load_src_off := mul(q_perm_z_next_load_i, 0x60) - mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x5ea0, q_perm_z_next_load_src_off))) + mstore(add(add(q_perm_z_next, 0x0), q_perm_z_next_load_dst_off), mload(add(0x6e20, q_perm_z_next_load_src_off))) } } - mstore(add(q_perm_z_last, 0x0), mload(0x5ec0)) - mstore(add(q_perm_z_last, 0x20), mload(0x5f20)) + mstore(add(q_perm_z_last, 0x0), mload(0x6e40)) + mstore(add(q_perm_z_last, 0x20), mload(0x6ea0)) let q_perm_eval := 0 q_perm_eval := mulmod(mload(L_0_MPTR), addmod(1, sub(r, mload(q_perm_z_cur)), r), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_perm_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_perm_eval, r)) let q_perm_zn := mload(add(q_perm_z_cur, 0x40)) q_perm_eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(q_perm_zn, q_perm_zn, r), sub(r, q_perm_zn), r), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_perm_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_perm_eval, r)) for { let q_perm_i := 1 } lt(q_perm_i, 3) { q_perm_i := add(q_perm_i, 1) } { let q_perm_cur := mload(add(q_perm_z_cur, shl(5, q_perm_i))) let q_perm_prev := mload(add(q_perm_z_last, shl(5, sub(q_perm_i, 1)))) q_perm_eval := mulmod(mload(L_0_MPTR), addmod(q_perm_cur, sub(r, q_perm_prev), r), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_perm_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_perm_eval, r)) } mstore(q_perm_delta_base_ptr, mulmod(mload(BETA_MPTR), mload(X_MPTR), r)) for { let q_perm_set := 0 } lt(q_perm_set, 3) { q_perm_set := add(q_perm_set, 1) } { @@ -1946,8 +1989,8 @@ contract Halo2Verifier { q_perm_delta_pow := mulmod(q_perm_delta_pow, delta, r) } q_perm_eval := mulmod(addmod(1, sub(r, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)), r), addmod(q_perm_left, sub(r, q_perm_right), r), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_perm_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_perm_eval, r)) mstore(q_perm_delta_base_ptr, mulmod(mload(q_perm_delta_base_ptr), q_perm_delta_chunk, r)) } } @@ -1968,13 +2011,13 @@ contract Halo2Verifier { // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := 0x7160 + q_sp := 0x80e0 // Generated LogUp code follows the same y-batch order // as the Rust identity stream. { - let q_lookup_f := 0x7160 - let q_lookup_prefix := 0x71a0 - let q_lookup_suffix := 0x71e0 + let q_lookup_f := 0x80e0 + let q_lookup_prefix := 0x8120 + let q_lookup_suffix := 0x8160 let q_lookup_l0 := mload(L_0_MPTR) let q_lookup_llast := mload(L_LAST_MPTR) let q_lookup_lblind := mload(L_BLIND_MPTR) @@ -1984,54 +2027,54 @@ contract Halo2Verifier { let q_lookup_theta := mload(THETA_MPTR) { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x5fc0), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x6f40), r) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } { - let f_10 := mload(0x5c60) + let f_10 := mload(0x6be0) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_10, r) - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_1, r) - let q_lookup_eval := addmod(mulmod(mload(0x5fa0), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x6f20), addmod(var1, q_lookup_beta, r), r), sub(r, 1), r) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x5fa0) - let f_19 := mload(0x5d20) - let f_11 := mload(0x5c80) + let q_lookup_sum_h := mload(0x6f20) + let f_19 := mload(0x6ca0) + let f_11 := mload(0x6c00) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_11, r) - let f_12 := mload(0x5ca0) + let f_12 := mload(0x6c20) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_12, r) let q_lookup_s_sum_h := mulmod(f_19, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x5fe0), sub(r, addmod(mload(0x5fc0), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x6f60), sub(r, addmod(mload(0x6f40), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var1, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x5f80), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x6f00), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } } { { - let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x6040), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + let q_lookup_eval := mulmod(q_lookup_lsum, mload(0x6fc0), r) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } { - let f_0 := mload(0x5be0) + let f_0 := mload(0x6b60) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_0, r) - let a_6 := mload(0x5940) + let a_6 := mload(0x68c0) let var1 := addmod(mulmod(var0, q_lookup_theta, r), a_6, r) - let a_0 := mload(0x5820) + let a_0 := mload(0x67a0) let var2 := addmod(mulmod(var1, q_lookup_theta, r), a_0, r) mstore(add(q_lookup_f, 0x0), addmod(var2, q_lookup_beta, r)) - let f_1 := mload(0x5c00) + let f_1 := mload(0x6b80) let var3 := addmod(mulmod(0, q_lookup_theta, r), f_1, r) - let a_7 := mload(0x5960) + let a_7 := mload(0x68e0) let var4 := addmod(mulmod(var3, q_lookup_theta, r), a_7, r) - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var5 := addmod(mulmod(var4, q_lookup_theta, r), a_1, r) mstore(add(q_lookup_f, 0x20), addmod(var5, q_lookup_beta, r)) let q_lookup_product := 1 @@ -2052,26 +2095,26 @@ contract Halo2Verifier { for { let q_lookup_sum_i := 0 } lt(q_lookup_sum_i, 2) { q_lookup_sum_i := add(q_lookup_sum_i, 1) } { q_lookup_sum := addmod(q_lookup_sum, mulmod(mload(add(q_lookup_prefix, shl(5, q_lookup_sum_i))), mload(add(q_lookup_suffix, shl(5, q_lookup_sum_i))), r), r) } - let q_lookup_eval := addmod(mulmod(mload(0x6020), q_lookup_product, r), sub(r, q_lookup_sum), r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + let q_lookup_eval := addmod(mulmod(mload(0x6fa0), q_lookup_product, r), sub(r, q_lookup_sum), r) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } { - let q_lookup_sum_h := mload(0x6020) - let f_20 := mload(0x5d40) - let f_13 := mload(0x5cc0) + let q_lookup_sum_h := mload(0x6fa0) + let f_20 := mload(0x6cc0) + let f_13 := mload(0x6c40) let var0 := addmod(mulmod(0, q_lookup_theta, r), f_13, r) - let f_14 := mload(0x5ce0) + let f_14 := mload(0x6c60) let var1 := addmod(mulmod(var0, q_lookup_theta, r), f_14, r) - let f_15 := mload(0x5d00) + let f_15 := mload(0x6c80) let var2 := addmod(mulmod(var1, q_lookup_theta, r), f_15, r) let q_lookup_s_sum_h := mulmod(f_20, q_lookup_sum_h, r) - let q_lookup_diff := addmod(mload(0x6060), sub(r, addmod(mload(0x6040), q_lookup_s_sum_h, r)), r) + let q_lookup_diff := addmod(mload(0x6fe0), sub(r, addmod(mload(0x6fc0), q_lookup_s_sum_h, r)), r) let q_lookup_t_beta := addmod(var2, q_lookup_beta, r) - let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x6000), r) + let q_lookup_core := addmod(mulmod(q_lookup_diff, q_lookup_t_beta, r), mload(0x6f80), r) let q_lookup_eval := mulmod(q_lookup_active, q_lookup_core, r) - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) - mstore(0x6cc0, addmod(mload(0x6cc0), q_lookup_eval, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) + mstore(0x7c40, addmod(mload(0x7c40), q_lookup_eval, r)) } } } @@ -2092,100 +2135,100 @@ contract Halo2Verifier { // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := 0x7160 + q_sp := 0x80e0 // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx case 0 { { let var0 := 0x1 - let a_3_prev_1 := mload(0x5980) - let a_4_prev_1 := mload(0x59a0) + let a_3_prev_1 := mload(0x6900) + let a_4_prev_1 := mload(0x6920) let var1 := addmod(a_3_prev_1, a_4_prev_1, r) - let a_3 := mload(0x5880) + let a_3 := mload(0x6800) let var2 := addmod(var1, a_3, r) let var3 := 0x40000000000 - let a_1_prev_1 := mload(0x59e0) + let a_1_prev_1 := mload(0x6960) let var4 := mulmod(var3, a_1_prev_1, r) let var5 := 0x100000 - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var6 := mulmod(var5, a_1, r) let var7 := addmod(var4, var6, r) - let a_1_next_1 := mload(0x58e0) + let a_1_next_1 := mload(0x6860) let var8 := addmod(var7, a_1_next_1, r) let var9 := 0x2 - let a_0_prev_1 := mload(0x59c0) + let a_0_prev_1 := mload(0x6940) let var10 := mulmod(var3, a_0_prev_1, r) - let a_0 := mload(0x5820) + let a_0 := mload(0x67a0) let var11 := mulmod(var5, a_0, r) let var12 := addmod(var10, var11, r) - let a_0_next_1 := mload(0x58c0) + let a_0_next_1 := mload(0x6840) let var13 := addmod(var12, a_0_next_1, r) let var14 := mulmod(var9, var13, r) let var15 := addmod(var8, var14, r) let var16 := addmod(0, sub(r, var15), r) let var17 := addmod(var2, var16, r) let var18 := mulmod(var0, var17, r) - mstore(0x7160, var18) + mstore(0x80e0, var18) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x60) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } } case 1 { { let var0 := 0x1 - let a_3_prev_1 := mload(0x5980) - let a_4_prev_1 := mload(0x59a0) + let a_3_prev_1 := mload(0x6900) + let a_4_prev_1 := mload(0x6920) let var1 := addmod(a_3_prev_1, a_4_prev_1, r) let var2 := 0x40000000000 - let a_1_prev_1 := mload(0x59e0) + let a_1_prev_1 := mload(0x6960) let var3 := mulmod(var2, a_1_prev_1, r) let var4 := 0x100000 - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var5 := mulmod(var4, a_1, r) let var6 := addmod(var3, var5, r) - let a_1_next_1 := mload(0x58e0) + let a_1_next_1 := mload(0x6860) let var7 := addmod(var6, a_1_next_1, r) let var8 := 0x2 - let a_0_prev_1 := mload(0x59c0) + let a_0_prev_1 := mload(0x6940) let var9 := mulmod(var2, a_0_prev_1, r) - let a_0 := mload(0x5820) + let a_0 := mload(0x67a0) let var10 := mulmod(var4, a_0, r) let var11 := addmod(var9, var10, r) - let a_0_next_1 := mload(0x58c0) + let a_0_next_1 := mload(0x6840) let var12 := addmod(var11, a_0_next_1, r) let var13 := mulmod(var8, var12, r) let var14 := addmod(var7, var13, r) let var15 := addmod(0, sub(r, var14), r) let var16 := addmod(var1, var15, r) let var17 := mulmod(var0, var16, r) - mstore(0x7160, var17) + mstore(0x80e0, var17) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0x80) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } } case 2 { { let var0 := 0x1 let var1 := 0x1000000000000000 - let a_4 := mload(0x58a0) + let a_4 := mload(0x6820) let var2 := mulmod(var1, a_4, r) let var3 := 0x10000000000 - let a_3_prev_1 := mload(0x5980) + let a_3_prev_1 := mload(0x6900) let var4 := mulmod(var3, a_3_prev_1, r) let var5 := addmod(var2, var4, r) let var6 := 0x400000 - let a_4_prev_1 := mload(0x59a0) + let a_4_prev_1 := mload(0x6920) let var7 := mulmod(var6, a_4_prev_1, r) let var8 := addmod(var5, var7, r) - let a_3 := mload(0x5880) + let a_3 := mload(0x6800) let var9 := addmod(var8, a_3, r) let var10 := 0x40000000000 let var11 := mulmod(var10, a_3, r) @@ -2207,54 +2250,54 @@ contract Halo2Verifier { let var27 := addmod(var24, var26, r) let var28 := addmod(var27, a_3_prev_1, r) let var29 := addmod(var19, var28, r) - let a_0_prev_1 := mload(0x59c0) + let a_0_prev_1 := mload(0x6940) let var30 := mulmod(var10, a_0_prev_1, r) - let a_0 := mload(0x5820) + let a_0 := mload(0x67a0) let var31 := mulmod(var25, a_0, r) let var32 := addmod(var30, var31, r) - let a_0_next_1 := mload(0x58c0) + let a_0_next_1 := mload(0x6840) let var33 := addmod(var32, a_0_next_1, r) let var34 := 0x2 - let a_1_prev_1 := mload(0x59e0) + let a_1_prev_1 := mload(0x6960) let var35 := mulmod(var10, a_1_prev_1, r) - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var36 := mulmod(var25, a_1, r) let var37 := addmod(var35, var36, r) - let a_1_next_1 := mload(0x58e0) + let a_1_next_1 := mload(0x6860) let var38 := addmod(var37, a_1_next_1, r) let var39 := mulmod(var34, var38, r) let var40 := addmod(var33, var39, r) let var41 := addmod(0, sub(r, var40), r) let var42 := addmod(var29, var41, r) let var43 := mulmod(var0, var42, r) - mstore(0x7160, var43) + mstore(0x80e0, var43) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xa0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } } case 3 { { let var0 := 0x1 let var1 := 0x10000000000000 - let a_3_next_1 := mload(0x5a00) + let a_3_next_1 := mload(0x6980) let var2 := mulmod(var1, a_3_next_1, r) let var3 := 0x4000000000 - let a_3_prev_1 := mload(0x5980) + let a_3_prev_1 := mload(0x6900) let var4 := mulmod(var3, a_3_prev_1, r) let var5 := addmod(var2, var4, r) let var6 := 0x4000 - let a_4_prev_1 := mload(0x59a0) + let a_4_prev_1 := mload(0x6920) let var7 := mulmod(var6, a_4_prev_1, r) let var8 := addmod(var5, var7, r) let var9 := 0x400 - let a_3 := mload(0x5880) + let a_3 := mload(0x6800) let var10 := mulmod(var9, a_3, r) let var11 := addmod(var8, var10, r) - let a_4 := mload(0x58a0) + let a_4 := mload(0x6820) let var12 := addmod(var11, a_4, r) let var13 := 0x40000000000000 let var14 := mulmod(var13, a_4, r) @@ -2281,34 +2324,34 @@ contract Halo2Verifier { let var35 := addmod(var33, var34, r) let var36 := addmod(var35, a_3_prev_1, r) let var37 := addmod(var25, var36, r) - let a_0_prev_1 := mload(0x59c0) + let a_0_prev_1 := mload(0x6940) let var38 := mulmod(var15, a_0_prev_1, r) let var39 := 0x100000 - let a_0 := mload(0x5820) + let a_0 := mload(0x67a0) let var40 := mulmod(var39, a_0, r) let var41 := addmod(var38, var40, r) - let a_0_next_1 := mload(0x58c0) + let a_0_next_1 := mload(0x6840) let var42 := addmod(var41, a_0_next_1, r) let var43 := 0x2 - let a_1_prev_1 := mload(0x59e0) + let a_1_prev_1 := mload(0x6960) let var44 := mulmod(var15, a_1_prev_1, r) - let a_1 := mload(0x5840) + let a_1 := mload(0x67c0) let var45 := mulmod(var39, a_1, r) let var46 := addmod(var44, var45, r) - let a_1_next_1 := mload(0x58e0) + let a_1_next_1 := mload(0x6860) let var47 := addmod(var46, a_1_next_1, r) let var48 := mulmod(var43, var47, r) let var49 := addmod(var42, var48, r) let var50 := addmod(0, sub(r, var49), r) let var51 := addmod(var37, var50, r) let var52 := mulmod(var0, var51, r) - mstore(0x7160, var52) + mstore(0x80e0, var52) } - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) { let q_selector_ptr := add(SELECTOR_ACC_MPTR, 0xc0) let q_selector_acc := mload(q_selector_ptr) - mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x7160), r)) + mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } } default { revert(0, 0) } @@ -2332,14 +2375,14 @@ contract Halo2Verifier { // The global fully-evaluated accumulator is still // multiplied by y so later main identities land at the // same y powers as Rust's reverse fold. - mstore(0x6cc0, mulmod(mload(0x6cc0), y, r)) + mstore(0x7c40, mulmod(mload(0x7c40), y, r)) let q_target_ptr := add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)) let q_sel_acc := mload(q_target_ptr) if q_sel_gap { // Selector buckets are sparse in the global // identity stream. Precomputed y^gap advances only // this selector's local accumulator. - q_sel_acc := mulmod(q_sel_acc, mload(add(0x6d00, shl(5, q_sel_gap))), r) + q_sel_acc := mulmod(q_sel_acc, mload(add(0x7c80, shl(5, q_sel_gap))), r) } mstore(q_target_ptr, addmod(q_sel_acc, q_eval, r)) } @@ -2359,7 +2402,7 @@ contract Halo2Verifier { // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x7160)) { revert(0, 0) } + if iszero(eq(q_sp, 0x80e0)) { revert(0, 0) } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2377,65 +2420,65 @@ contract Halo2Verifier { // selector commitment in the linearized MSM. { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x00) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0440)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0440)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x20) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0420)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0420)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x40) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x03c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x03c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x60) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x03a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x03a0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x80) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0360)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0360)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xa0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0340)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0340)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xc0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0320)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0320)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0xe0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0300)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0300)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0100) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x02e0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x02e0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0120) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x02c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x02c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0140) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0280)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0280)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0160) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x0240)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x0240)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x0180) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x01c0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x01c0)), r)) } { let q_sel_ptr := add(SELECTOR_ACC_MPTR, 0x01a0) - mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x6d00, 0x01a0)), r)) + mstore(q_sel_ptr, mulmod(mload(q_sel_ptr), mload(add(0x7c80, 0x01a0)), r)) } // Fully evaluated identities are the constant-polynomial side // of the linearization query. Rust subtracts that grouped // scalar into expected_eval, so Solidity stores -nu_y(x). - let linearization_expected_eval := addmod(0, sub(r, mload(0x6cc0)), r) + let linearization_expected_eval := addmod(0, sub(r, mload(0x7c40)), r) mstore(QUOTIENT_EVAL_MPTR, linearization_expected_eval) pop(y) } @@ -2538,42 +2581,42 @@ contract Halo2Verifier { { // q_eval_set[0]: 33 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x6cc0, 0x5800) - mstore(0x6ce0, 0x5f80) - mstore(0x6d00, 0x5fa0) - mstore(0x6d20, 0x6000) - mstore(0x6d40, 0x6020) - mstore(0x6d60, 0x5b20) - mstore(0x6d80, 0x5b40) - mstore(0x6da0, 0x5b60) - mstore(0x6dc0, 0x5b80) - mstore(0x6de0, 0x5ba0) - mstore(0x6e00, 0x5bc0) - mstore(0x6e20, 0x5be0) - mstore(0x6e40, 0x5c00) - mstore(0x6e60, 0x5c20) - mstore(0x6e80, 0x5c40) - mstore(0x6ea0, 0x5c60) - mstore(0x6ec0, 0x5c80) - mstore(0x6ee0, 0x5ca0) - mstore(0x6f00, 0x5cc0) - mstore(0x6f20, 0x5ce0) - mstore(0x6f40, 0x5d00) - mstore(0x6f60, 0x5d20) - mstore(0x6f80, 0x5d40) - mstore(0x6fa0, 0x5d60) - mstore(0x6fc0, 0x5d80) - mstore(0x6fe0, 0x5da0) - mstore(0x7000, 0x5dc0) - mstore(0x7020, 0x5de0) - mstore(0x7040, 0x5e00) - mstore(0x7060, 0x5e20) - mstore(0x7080, 0x5e40) - mstore(0x70a0, 0x5e60) - mstore(0x70c0, QUOTIENT_EVAL_MPTR) - let q_eval_set_0 := mload(0x5800) + mstore(0x7c40, 0x6780) + mstore(0x7c60, 0x6f00) + mstore(0x7c80, 0x6f20) + mstore(0x7ca0, 0x6f80) + mstore(0x7cc0, 0x6fa0) + mstore(0x7ce0, 0x6aa0) + mstore(0x7d00, 0x6ac0) + mstore(0x7d20, 0x6ae0) + mstore(0x7d40, 0x6b00) + mstore(0x7d60, 0x6b20) + mstore(0x7d80, 0x6b40) + mstore(0x7da0, 0x6b60) + mstore(0x7dc0, 0x6b80) + mstore(0x7de0, 0x6ba0) + mstore(0x7e00, 0x6bc0) + mstore(0x7e20, 0x6be0) + mstore(0x7e40, 0x6c00) + mstore(0x7e60, 0x6c20) + mstore(0x7e80, 0x6c40) + mstore(0x7ea0, 0x6c60) + mstore(0x7ec0, 0x6c80) + mstore(0x7ee0, 0x6ca0) + mstore(0x7f00, 0x6cc0) + mstore(0x7f20, 0x6ce0) + mstore(0x7f40, 0x6d00) + mstore(0x7f60, 0x6d20) + mstore(0x7f80, 0x6d40) + mstore(0x7fa0, 0x6d60) + mstore(0x7fc0, 0x6d80) + mstore(0x7fe0, 0x6da0) + mstore(0x8000, 0x6dc0) + mstore(0x8020, 0x6de0) + mstore(0x8040, QUOTIENT_EVAL_MPTR) + let q_eval_set_0 := mload(0x6780) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x6cc0, 0x20) + let eval_p := add(0x7c40, 0x20) for { let i := 1 } lt(i, 0x21) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2587,12 +2630,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[1]: 3 commitment(s) - let q_eval_set_0 := mload(0x5f40) - let q_eval_set_1 := mload(0x5f60) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x5fc0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x5fe0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6040), mload(add(X1_POWERS_MPTR, 0x40)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6060), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + let q_eval_set_0 := mload(0x6ec0) + let q_eval_set_1 := mload(0x6ee0) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6f40), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6f60), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6fc0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6fe0), mload(add(X1_POWERS_MPTR, 0x40)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) } @@ -2602,35 +2645,35 @@ contract Halo2Verifier { { // q_eval_set[2]: 8 commitment(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses - mstore(0x6cc0, 0x5820) - mstore(0x6ce0, 0x58c0) - mstore(0x6d00, 0x59c0) - mstore(0x6d20, 0x5840) - mstore(0x6d40, 0x58e0) - mstore(0x6d60, 0x59e0) - mstore(0x6d80, 0x5860) - mstore(0x6da0, 0x5900) - mstore(0x6dc0, 0x5a80) - mstore(0x6de0, 0x5880) - mstore(0x6e00, 0x5a00) - mstore(0x6e20, 0x5980) - mstore(0x6e40, 0x58a0) - mstore(0x6e60, 0x5a20) - mstore(0x6e80, 0x59a0) - mstore(0x6ea0, 0x5920) - mstore(0x6ec0, 0x5ae0) - mstore(0x6ee0, 0x5ac0) - mstore(0x6f00, 0x5940) - mstore(0x6f20, 0x5a60) - mstore(0x6f40, 0x5a40) - mstore(0x6f60, 0x5960) - mstore(0x6f80, 0x5b00) - mstore(0x6fa0, 0x5aa0) - let q_eval_set_0 := mload(0x5820) - let q_eval_set_1 := mload(0x58c0) - let q_eval_set_2 := mload(0x59c0) + mstore(0x7c40, 0x67a0) + mstore(0x7c60, 0x6840) + mstore(0x7c80, 0x6940) + mstore(0x7ca0, 0x67c0) + mstore(0x7cc0, 0x6860) + mstore(0x7ce0, 0x6960) + mstore(0x7d00, 0x67e0) + mstore(0x7d20, 0x6880) + mstore(0x7d40, 0x6a00) + mstore(0x7d60, 0x6800) + mstore(0x7d80, 0x6980) + mstore(0x7da0, 0x6900) + mstore(0x7dc0, 0x6820) + mstore(0x7de0, 0x69a0) + mstore(0x7e00, 0x6920) + mstore(0x7e20, 0x68a0) + mstore(0x7e40, 0x6a60) + mstore(0x7e60, 0x6a40) + mstore(0x7e80, 0x68c0) + mstore(0x7ea0, 0x69e0) + mstore(0x7ec0, 0x69c0) + mstore(0x7ee0, 0x68e0) + mstore(0x7f00, 0x6a80) + mstore(0x7f20, 0x6a20) + let q_eval_set_0 := mload(0x67a0) + let q_eval_set_1 := mload(0x6840) + let q_eval_set_2 := mload(0x6940) let pow_p := add(X1_POWERS_MPTR, 0x20) - let eval_p := add(0x6cc0, 0x60) + let eval_p := add(0x7c40, 0x60) for { let i := 1 } lt(i, 0x8) { i := add(i, 1) } { let pow := mload(pow_p) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(mload(eval_p)), pow, r), r) @@ -2648,12 +2691,12 @@ contract Halo2Verifier { // grouped so gas checkpoints can attribute their cost. { // q_eval_set[3]: 2 commitment(s) - let q_eval_set_0 := mload(0x5e80) - let q_eval_set_1 := mload(0x5ea0) - let q_eval_set_2 := mload(0x5ec0) - q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x5ee0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x5f00), mload(add(X1_POWERS_MPTR, 0x20)), r), r) - q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x5f20), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + let q_eval_set_0 := mload(0x6e00) + let q_eval_set_1 := mload(0x6e20) + let q_eval_set_2 := mload(0x6e40) + q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6e60), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_1 := addmod(q_eval_set_1, mulmod(mload(0x6e80), mload(add(X1_POWERS_MPTR, 0x20)), r), r) + q_eval_set_2 := addmod(q_eval_set_2, mulmod(mload(0x6ea0), mload(add(X1_POWERS_MPTR, 0x20)), r), r) mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0x100), q_eval_set_2) @@ -2821,139 +2864,139 @@ contract Halo2Verifier { v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x40)), x4_pow_2, r), r) v := addmod(v, mulmod(calldataload(add(Q_EVAL_CPTR, 0x60)), x4_pow_3, r), r) v := addmod(v, mulmod(mload(F_EVAL_MPTR), x4_pow_4, r), r) - mcopy(0x6cc0, 0x6480, 0x80) - mstore(0x6d40, mload(add(X1_POWERS_MPTR, 0x20))) - mcopy(0x6d60, 0x6700, 0x80) - mstore(0x6de0, mload(add(X1_POWERS_MPTR, 0x40))) - mcopy(0x6e00, 0x6500, 0x80) - mstore(0x6e80, mload(add(X1_POWERS_MPTR, 0x60))) - mcopy(0x6ea0, 0x6780, 0x80) - mstore(0x6f20, mload(add(X1_POWERS_MPTR, 0x80))) - mcopy(0x6f40, 0x2c80, 0x80) - mstore(0x6fc0, mload(add(X1_POWERS_MPTR, 0xa0))) - mcopy(0x6fe0, 0x2a00, 0x80) - mstore(0x7060, mload(add(X1_POWERS_MPTR, 0xc0))) - mcopy(0x7080, 0x2a80, 0x80) - mstore(0x7100, mload(add(X1_POWERS_MPTR, 0xe0))) - mcopy(0x7120, 0x2b00, 0x80) - mstore(0x71a0, mload(add(X1_POWERS_MPTR, 0x100))) - mcopy(0x71c0, 0x2b80, 0x80) - mstore(0x7240, mload(add(X1_POWERS_MPTR, 0x120))) - mcopy(0x7260, 0x2c00, 0x80) - mstore(0x72e0, mload(add(X1_POWERS_MPTR, 0x140))) - mcopy(0x7300, 0x2800, 0x80) - mstore(0x7380, mload(add(X1_POWERS_MPTR, 0x160))) - mcopy(0x73a0, 0x2880, 0x80) - mstore(0x7420, mload(add(X1_POWERS_MPTR, 0x180))) - mcopy(0x7440, 0x2900, 0x80) - mstore(0x74c0, mload(add(X1_POWERS_MPTR, 0x1a0))) - mcopy(0x74e0, 0x2980, 0x80) - mstore(0x7560, mload(add(X1_POWERS_MPTR, 0x1c0))) - mcopy(0x7580, 0x2d00, 0x80) - mstore(0x7600, mload(add(X1_POWERS_MPTR, 0x1e0))) - mcopy(0x7620, 0x2d80, 0x80) - mstore(0x76a0, mload(add(X1_POWERS_MPTR, 0x200))) - mcopy(0x76c0, 0x2e00, 0x80) - mstore(0x7740, mload(add(X1_POWERS_MPTR, 0x220))) - mcopy(0x7760, 0x2e80, 0x80) - mstore(0x77e0, mload(add(X1_POWERS_MPTR, 0x240))) - mcopy(0x7800, 0x2f00, 0x80) - mstore(0x7880, mload(add(X1_POWERS_MPTR, 0x260))) - mcopy(0x78a0, 0x2f80, 0x80) - mstore(0x7920, mload(add(X1_POWERS_MPTR, 0x280))) - mcopy(0x7940, 0x3180, 0x80) - mstore(0x79c0, mload(add(X1_POWERS_MPTR, 0x2a0))) - mcopy(0x79e0, 0x3200, 0x80) - mstore(0x7a60, mload(add(X1_POWERS_MPTR, 0x2c0))) - mcopy(0x7a80, 0x3800, 0x80) - mstore(0x7b00, mload(add(X1_POWERS_MPTR, 0x2e0))) - mcopy(0x7b20, 0x3880, 0x80) - mstore(0x7ba0, mload(add(X1_POWERS_MPTR, 0x300))) - mcopy(0x7bc0, 0x3900, 0x80) - mstore(0x7c40, mload(add(X1_POWERS_MPTR, 0x320))) - mcopy(0x7c60, 0x3980, 0x80) - mstore(0x7ce0, mload(add(X1_POWERS_MPTR, 0x340))) - mcopy(0x7d00, 0x3a00, 0x80) - mstore(0x7d80, mload(add(X1_POWERS_MPTR, 0x360))) - mcopy(0x7da0, 0x3a80, 0x80) - mstore(0x7e20, mload(add(X1_POWERS_MPTR, 0x380))) - mcopy(0x7e40, 0x3b00, 0x80) - mstore(0x7ec0, mload(add(X1_POWERS_MPTR, 0x3a0))) - mcopy(0x7ee0, 0x3b80, 0x80) - mstore(0x7f60, mload(add(X1_POWERS_MPTR, 0x3c0))) - mcopy(0x7f80, 0x3c00, 0x80) - mstore(0x8000, mload(add(X1_POWERS_MPTR, 0x3e0))) + mcopy(0x7c40, 0x7400, 0x80) + mstore(0x7cc0, mload(add(X1_POWERS_MPTR, 0x20))) + mcopy(0x7ce0, 0x7680, 0x80) + mstore(0x7d60, mload(add(X1_POWERS_MPTR, 0x40))) + mcopy(0x7d80, 0x7480, 0x80) + mstore(0x7e00, mload(add(X1_POWERS_MPTR, 0x60))) + mcopy(0x7e20, 0x7700, 0x80) + mstore(0x7ea0, mload(add(X1_POWERS_MPTR, 0x80))) + mcopy(0x7ec0, 0x3c00, 0x80) + mstore(0x7f40, mload(add(X1_POWERS_MPTR, 0xa0))) + mcopy(0x7f60, 0x3980, 0x80) + mstore(0x7fe0, mload(add(X1_POWERS_MPTR, 0xc0))) + mcopy(0x8000, 0x3a00, 0x80) + mstore(0x8080, mload(add(X1_POWERS_MPTR, 0xe0))) + mcopy(0x80a0, 0x3a80, 0x80) + mstore(0x8120, mload(add(X1_POWERS_MPTR, 0x100))) + mcopy(0x8140, 0x3b00, 0x80) + mstore(0x81c0, mload(add(X1_POWERS_MPTR, 0x120))) + mcopy(0x81e0, 0x3b80, 0x80) + mstore(0x8260, mload(add(X1_POWERS_MPTR, 0x140))) + mcopy(0x8280, 0x3780, 0x80) + mstore(0x8300, mload(add(X1_POWERS_MPTR, 0x160))) + mcopy(0x8320, 0x3800, 0x80) + mstore(0x83a0, mload(add(X1_POWERS_MPTR, 0x180))) + mcopy(0x83c0, 0x3880, 0x80) + mstore(0x8440, mload(add(X1_POWERS_MPTR, 0x1a0))) + mcopy(0x8460, 0x3900, 0x80) + mstore(0x84e0, mload(add(X1_POWERS_MPTR, 0x1c0))) + mcopy(0x8500, 0x3c80, 0x80) + mstore(0x8580, mload(add(X1_POWERS_MPTR, 0x1e0))) + mcopy(0x85a0, 0x3d00, 0x80) + mstore(0x8620, mload(add(X1_POWERS_MPTR, 0x200))) + mcopy(0x8640, 0x3d80, 0x80) + mstore(0x86c0, mload(add(X1_POWERS_MPTR, 0x220))) + mcopy(0x86e0, 0x3e00, 0x80) + mstore(0x8760, mload(add(X1_POWERS_MPTR, 0x240))) + mcopy(0x8780, 0x3e80, 0x80) + mstore(0x8800, mload(add(X1_POWERS_MPTR, 0x260))) + mcopy(0x8820, 0x3f00, 0x80) + mstore(0x88a0, mload(add(X1_POWERS_MPTR, 0x280))) + mcopy(0x88c0, 0x4100, 0x80) + mstore(0x8940, mload(add(X1_POWERS_MPTR, 0x2a0))) + mcopy(0x8960, 0x4180, 0x80) + mstore(0x89e0, mload(add(X1_POWERS_MPTR, 0x2c0))) + mcopy(0x8a00, 0x4780, 0x80) + mstore(0x8a80, mload(add(X1_POWERS_MPTR, 0x2e0))) + mcopy(0x8aa0, 0x4800, 0x80) + mstore(0x8b20, mload(add(X1_POWERS_MPTR, 0x300))) + mcopy(0x8b40, 0x4880, 0x80) + mstore(0x8bc0, mload(add(X1_POWERS_MPTR, 0x320))) + mcopy(0x8be0, 0x4900, 0x80) + mstore(0x8c60, mload(add(X1_POWERS_MPTR, 0x340))) + mcopy(0x8c80, 0x4980, 0x80) + mstore(0x8d00, mload(add(X1_POWERS_MPTR, 0x360))) + mcopy(0x8d20, 0x4a00, 0x80) + mstore(0x8da0, mload(add(X1_POWERS_MPTR, 0x380))) + mcopy(0x8dc0, 0x4a80, 0x80) + mstore(0x8e40, mload(add(X1_POWERS_MPTR, 0x3a0))) + mcopy(0x8e60, 0x4b00, 0x80) + mstore(0x8ee0, mload(add(X1_POWERS_MPTR, 0x3c0))) + mcopy(0x8f00, 0x4b80, 0x80) + mstore(0x8f80, mload(add(X1_POWERS_MPTR, 0x3e0))) let lin_query_scalar_31 := mload(add(X1_POWERS_MPTR, 0x400)) let lin_cur_scalar_31 := mulmod(lin_query_scalar_31, lin_one_minus_x_n, r) - mcopy(0x8020, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) - mstore(0x80a0, lin_cur_scalar_31) + mcopy(0x8fa0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x0), 0x80) + mstore(0x9020, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x80c0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) - mstore(0x8140, lin_cur_scalar_31) + mcopy(0x9040, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x80), 0x80) + mstore(0x90c0, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x8160, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) - mstore(0x81e0, lin_cur_scalar_31) + mcopy(0x90e0, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x100), 0x80) + mstore(0x9160, lin_cur_scalar_31) lin_cur_scalar_31 := mulmod(lin_cur_scalar_31, lin_x_split, r) - mcopy(0x8200, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) - mstore(0x8280, lin_cur_scalar_31) - mcopy(0x82a0, 0x3000, 0x80) - mstore(0x8320, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) - mcopy(0x8340, 0x3080, 0x80) - mstore(0x83c0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) - mcopy(0x83e0, 0x3100, 0x80) - mstore(0x8460, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) - mcopy(0x8480, 0x3280, 0x80) - mstore(0x8500, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) - mcopy(0x8520, 0x3300, 0x80) - mstore(0x85a0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) - mcopy(0x85c0, 0x3380, 0x80) - mstore(0x8640, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) - mcopy(0x8660, 0x3400, 0x80) - mstore(0x86e0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) - mcopy(0x8700, 0x3480, 0x80) - mstore(0x8780, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) - mcopy(0x87a0, 0x3500, 0x80) - mstore(0x8820, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) - mcopy(0x8840, 0x3580, 0x80) - mstore(0x88c0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) - mcopy(0x88e0, 0x3600, 0x80) - mstore(0x8960, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x140)), r)) - mcopy(0x8980, 0x3680, 0x80) - mstore(0x8a00, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x160)), r)) - mcopy(0x8a20, 0x3700, 0x80) - mstore(0x8aa0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x180)), r)) - mcopy(0x8ac0, 0x3780, 0x80) - mstore(0x8b40, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x1a0)), r)) - mcopy(0x8b60, 0x6680, 0x80) - mstore(0x8be0, x4_pow_1) - mcopy(0x8c00, 0x6800, 0x80) - mstore(0x8c80, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) - mcopy(0x8ca0, 0x6880, 0x80) - mstore(0x8d20, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) - mcopy(0x8d40, 0x6080, 0x80) - mstore(0x8dc0, x4_pow_2) - mcopy(0x8de0, 0x6100, 0x80) - mstore(0x8e60, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) - mcopy(0x8e80, 0x6180, 0x80) - mstore(0x8f00, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) - mcopy(0x8f20, 0x6200, 0x80) - mstore(0x8fa0, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_2, r)) - mcopy(0x8fc0, 0x6280, 0x80) - mstore(0x9040, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_2, r)) - mcopy(0x9060, 0x6300, 0x80) - mstore(0x90e0, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_2, r)) - mcopy(0x9100, 0x6380, 0x80) - mstore(0x9180, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_2, r)) - mcopy(0x91a0, 0x6400, 0x80) - mstore(0x9220, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_2, r)) - mcopy(0x9240, 0x6580, 0x80) - mstore(0x92c0, x4_pow_3) - mcopy(0x92e0, 0x6600, 0x80) - mstore(0x9360, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) - mcopy(0x9380, F_COM_MPTR, 0x80) - mstore(0x9400, x4_pow_4) + mcopy(0x9180, add(QUOTIENT_LIMB_COMMS_MPTR_BASE, 0x180), 0x80) + mstore(0x9200, lin_cur_scalar_31) + mcopy(0x9220, 0x3f80, 0x80) + mstore(0x92a0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x0)), r)) + mcopy(0x92c0, 0x4000, 0x80) + mstore(0x9340, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x20)), r)) + mcopy(0x9360, 0x4080, 0x80) + mstore(0x93e0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x40)), r)) + mcopy(0x9400, 0x4200, 0x80) + mstore(0x9480, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x60)), r)) + mcopy(0x94a0, 0x4280, 0x80) + mstore(0x9520, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x80)), r)) + mcopy(0x9540, 0x4300, 0x80) + mstore(0x95c0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xa0)), r)) + mcopy(0x95e0, 0x4380, 0x80) + mstore(0x9660, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xc0)), r)) + mcopy(0x9680, 0x4400, 0x80) + mstore(0x9700, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0xe0)), r)) + mcopy(0x9720, 0x4480, 0x80) + mstore(0x97a0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x100)), r)) + mcopy(0x97c0, 0x4500, 0x80) + mstore(0x9840, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x120)), r)) + mcopy(0x9860, 0x4580, 0x80) + mstore(0x98e0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x140)), r)) + mcopy(0x9900, 0x4600, 0x80) + mstore(0x9980, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x160)), r)) + mcopy(0x99a0, 0x4680, 0x80) + mstore(0x9a20, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x180)), r)) + mcopy(0x9a40, 0x4700, 0x80) + mstore(0x9ac0, mulmod(lin_query_scalar_31, mload(add(SELECTOR_ACC_MPTR, 0x1a0)), r)) + mcopy(0x9ae0, 0x7600, 0x80) + mstore(0x9b60, x4_pow_1) + mcopy(0x9b80, 0x7780, 0x80) + mstore(0x9c00, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_1, r)) + mcopy(0x9c20, 0x7800, 0x80) + mstore(0x9ca0, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_1, r)) + mcopy(0x9cc0, 0x7000, 0x80) + mstore(0x9d40, x4_pow_2) + mcopy(0x9d60, 0x7080, 0x80) + mstore(0x9de0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_2, r)) + mcopy(0x9e00, 0x7100, 0x80) + mstore(0x9e80, mulmod(mload(add(X1_POWERS_MPTR, 0x40)), x4_pow_2, r)) + mcopy(0x9ea0, 0x7180, 0x80) + mstore(0x9f20, mulmod(mload(add(X1_POWERS_MPTR, 0x60)), x4_pow_2, r)) + mcopy(0x9f40, 0x7200, 0x80) + mstore(0x9fc0, mulmod(mload(add(X1_POWERS_MPTR, 0x80)), x4_pow_2, r)) + mcopy(0x9fe0, 0x7280, 0x80) + mstore(0xa060, mulmod(mload(add(X1_POWERS_MPTR, 0xa0)), x4_pow_2, r)) + mcopy(0xa080, 0x7300, 0x80) + mstore(0xa100, mulmod(mload(add(X1_POWERS_MPTR, 0xc0)), x4_pow_2, r)) + mcopy(0xa120, 0x7380, 0x80) + mstore(0xa1a0, mulmod(mload(add(X1_POWERS_MPTR, 0xe0)), x4_pow_2, r)) + mcopy(0xa1c0, 0x7500, 0x80) + mstore(0xa240, x4_pow_3) + mcopy(0xa260, 0x7580, 0x80) + mstore(0xa2e0, mulmod(mload(add(X1_POWERS_MPTR, 0x20)), x4_pow_3, r)) + mcopy(0xa300, F_COM_MPTR, 0x80) + mstore(0xa380, x4_pow_4) if success { - success := staticcall(gas(), 0x0c, 0x6cc0, 0x2760, FINAL_COM_MPTR, 0x80) + success := staticcall(gas(), 0x0c, 0x7c40, 0x2760, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2965,28 +3008,28 @@ contract Halo2Verifier { // Scale z*pi - vG before the final pairing check // pairing inputs (LHS = pi; RHS = final_com - v*G + x3*pi) mcopy(PAIRING_LHS_MPTR, PI_MPTR, 0x80) - mcopy(0x80, G1_BASE_MPTR, 0x80) - mstore(0x100, addmod(0, sub(r, mload(V_MPTR)), r)) + mcopy(0x1000, G1_BASE_MPTR, 0x80) + mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x80, 0xa0, 0x80, 0x80) + success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, FINAL_COM_MPTR, 0x80) + mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(0x100, PI_MPTR, 0x80) - mstore(0x180, mload(X3_MPTR)) + mcopy(0x1080, PI_MPTR, 0x80) + mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x100, 0xa0, 0x100, 0x80) + success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x80, 0x100, 0x80, 0x80) + success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } - mcopy(PAIRING_RHS_MPTR, 0x80, 0x80) + mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol index 7b15639cf..dc1527a1e 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol @@ -136,19 +136,19 @@ contract Halo2VerifyingKey { mstore(add(payload, 0x08e0), 0x0000000000000000000000000000000000000000000000000000000000080000) // quotient_const mstore(add(payload, 0x0900), 0x0000000000000000000000000000000000000000000000000000000000020000) // quotient_const mstore(add(payload, 0x0920), 0x0000000000000000000000000000000000000000000000000000000100000000) // quotient_const - mstore(add(payload, 0x0940), 0x055860105b8005590008060d000b0200011b00001b00010558601058800558a0) // quotient_program - mstore(add(payload, 0x0960), 0x08060d000b0400011b00021b0003210001000007000158200258400358600458) // quotient_program - mstore(add(payload, 0x0980), 0x800558a00658c00758e00859000959800a59a00b59c00c59e00d5a000e5a200b) // quotient_program - mstore(add(payload, 0x09a0), 0x070000210001000007000158200258400f58601058801158a00658c00758e012) // quotient_program - mstore(add(payload, 0x09c0), 0x59001359801459a00b59c00c59e0155a00165a200b0800000918115a40135940) // quotient_program - mstore(add(payload, 0x09e0), 0x17105a60055a8008060d000b090000091b115a40135aa01a1359401910596005) // quotient_program - mstore(add(payload, 0x0a00), 0x5a8008060d000b0a0000091e1159c01359e01d1358201c10584005586008060d) // quotient_program - mstore(add(payload, 0x0a20), 0x000b0a00010921115a40135aa01a135940201359601f105a60055a8008060d00) // quotient_program - mstore(add(payload, 0x0a40), 0x0b0b000009231159c01359e01d1358201b135840221058c005586008060d000b) // quotient_program - mstore(add(payload, 0x0a60), 0x0b00011c245920255940265960275a40175aa0285ac0295ae0105a60055a8008) // quotient_program - mstore(add(payload, 0x0a80), 0x060d000b0c0000090008105ac0115ac00d000b0c00010900081059201159200d) // quotient_program - mstore(add(payload, 0x0aa0), 0x000b0c0001090008105ae0115ae00d000b0c00011c0058800058a00059000059) // quotient_program - mstore(add(payload, 0x0ac0), 0x800059a0005a00005a20055a80135b002a08060d000b0d0000191f0000000000) // quotient_program + mstore(add(payload, 0x0940), 0x0567e0106b0005688008060d000b0200011b00001b00010567e0106800056820) // quotient_program + mstore(add(payload, 0x0960), 0x08060d000b0400011b00021b0003210001000007000167a00267c00367e00468) // quotient_program + mstore(add(payload, 0x0980), 0x000568200668400768600868800969000a69200b69400c69600d69800e69a00b) // quotient_program + mstore(add(payload, 0x09a0), 0x070000210001000007000167a00267c00f67e010680011682006684007686012) // quotient_program + mstore(add(payload, 0x09c0), 0x68801369001469200b69400c69601569801669a00b08000009181169c01368c0) // quotient_program + mstore(add(payload, 0x09e0), 0x171069e0056a0008060d000b090000091b1169c0136a201a1368c0191068e005) // quotient_program + mstore(add(payload, 0x0a00), 0x6a0008060d000b0a0000091e1169401369601d1367a01c1067c00567e008060d) // quotient_program + mstore(add(payload, 0x0a20), 0x000b0a000109211169c0136a201a1368c0201368e01f1069e0056a0008060d00) // quotient_program + mstore(add(payload, 0x0a40), 0x0b0b000009231169401369601d1367a01b1367c0221068400567e008060d000b) // quotient_program + mstore(add(payload, 0x0a60), 0x0b00011c2468a02568c02668e02769c0176a20286a40296a601069e0056a0008) // quotient_program + mstore(add(payload, 0x0a80), 0x060d000b0c0000090008106a40116a400d000b0c00010900081068a01168a00d) // quotient_program + mstore(add(payload, 0x0aa0), 0x000b0c0001090008106a60116a600d000b0c00011c0068000068200068800069) // quotient_program + mstore(add(payload, 0x0ac0), 0x000069200069800069a0056a00136a802a08060d000b0d0000191f0000000000) // quotient_program // Fixed-column commitment 0, stored as one // EIP-2537 padded uncompressed G1 slot. mstore(add(payload, 0x0ae0), 0x000000000000000000000000000000001197f0fef4c3a1846341b3c9bbaf1bab) // fixed_comms[0].x_hi From 0b274854bb39710fe3939d0796123aa8ffdf6dac Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 20:34:48 +0100 Subject: [PATCH 068/108] Self-certify emitted quotient VM bytecode at render time The quotient lowering runs a peephole optimizer whose shape recognizers and run-compaction pass rewrite seven-limb foreign-field expressions into superinstructions. Both are pure encoding choices that must preserve the evaluated polynomial exactly, but their correctness was only checked indirectly by fixture-circuit trace differentials in CI. A recognizer bug on a previously unseen gate shape could therefore ship a wrong verifier without any generator-time failure. Add a two-part certification pass that runs on every LoweringPlan: * vm/reference.rs is an independent interpreter for finalized quotient bytecode, deliberately written against the ABI without sharing execution code with the emitter. * vm/certify.rs re-executes the emitted program with that reference interpreter and compares each identity against direct evaluation of the QuotientExpr tree it was lowered from, then repeats the check against a second build produced with the limb superinstructions disabled. Any disagreement fails the render before the bytecode can be pinned into a verifying key. Wire this in from LoweringPlan::new and validate_generator_invariants so the check runs unconditionally, not just in tests. Expose QuotientProgramBuilder::with_limb_vm_ops outside cfg(test) so the generator can build the baseline program, and add build_quotient_program_items_with_limb_ops to lower the same item stream under an explicit opcode policy. Add QuotientVmTestCircuit and lowering_plan_certifies_emitted_quotient_bytecode so the fast test suite actually reaches the VM path (the existing LoweringPlanTestCircuit has only one gate and fits entirely in the inline prefix). The test also asserts that the emitted program uses LIN7, so it fails loudly if the planner ever stops routing these identities through the recognizer. Update QUOTIENT_EVALUATOR_9KB_BYTECODE.md to fix the stale module path and document the new certification gate. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../QUOTIENT_EVALUATOR_9KB_BYTECODE.md | 12 +- proofs/solidity-verifier/src/lowering/plan.rs | 24 +- .../src/lowering/quotient.rs | 21 +- .../lowering/quotient_numerator/vm/certify.rs | 270 +++++++++ .../src/lowering/quotient_numerator/vm/mod.rs | 4 +- .../quotient_numerator/vm/reference.rs | 548 ++++++++++++++++++ .../solidity-verifier/src/lowering/tests.rs | 141 +++++ 7 files changed, 1015 insertions(+), 5 deletions(-) create mode 100644 proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs create mode 100644 proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs diff --git a/proofs/solidity-verifier/docs/reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md b/proofs/solidity-verifier/docs/reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md index 63e06a6b2..64e5c6230 100644 --- a/proofs/solidity-verifier/docs/reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md +++ b/proofs/solidity-verifier/docs/reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md @@ -104,8 +104,16 @@ normal ABI call. The largest win was the compact quotient VM. Instead of rendering most identities as Yul source, the generator lowers them to -a small bytecode language in `src/lowering/quotient/mod.rs`. The runtime consumer -is `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul`. +a small bytecode language in `src/lowering/quotient_numerator/vm/mod.rs`. The +runtime consumer is +`templates/partials/quotient_numerator/QuotientNumeratorBlock.yul`. + +Every emitted program is certified before it can be pinned into a verifying key: +`src/lowering/quotient_numerator/vm/certify.rs` re-executes the finalized +bytecode with the independent interpreter in +`src/lowering/quotient_numerator/vm/reference.rs` and compares each identity +against direct evaluation of the expression tree it was lowered from, and +against a second build with the limb superinstructions disabled. The VK payload carries: diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index f8aaea1ad..9f3f60017 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -12,7 +12,9 @@ use crate::lowering::{ kzg, layout, layout::memory::{PcsMemoryRequirements, VerifierMemoryLayout, VerifierMemoryLayoutConfig}, quotient::{QuotientComputationBlocks, QuotientHelperFlags, QuotientStateSlots}, - quotient_numerator::vm::{QuotientProgramBuild, QuotientProgramPlan, RepackedProofLayoutPlan}, + quotient_numerator::vm::{ + certify, QuotientProgramBuild, QuotientProgramPlan, RepackedProofLayoutPlan, + }, render::{Halo2VerifyingKey, QuotientExternal, QuotientProgram}, VerifierBuildInputs, }; @@ -163,6 +165,22 @@ impl LoweringPlan { }; plan.validate_generator_invariants() .unwrap_or_else(|err| panic!("generator invariant violation: {err}")); + + // Certify the limb superinstructions against a generic-opcode build of + // the same identity stream. This needs `inputs`, so it runs here rather + // than inside `validate_generator_invariants`. + let baseline_build = inputs.build_quotient_program_items_with_limb_ops( + &plan.quotient.plan.items, + &plan.quotient.plan.selector_fold, + false, + ); + certify::certify_quotient_builds_agree( + &plan.quotient.plan, + &plan.quotient.build, + &baseline_build, + ) + .unwrap_or_else(|err| panic!("quotient dual-build certification failed: {err}")); + plan } @@ -320,6 +338,10 @@ impl LoweringPlan { self.quotient.program.eval_numer_mptr, self.quotient.state_slots.eval_numer_mptr )); } + // Prove the emitted bytecode still evaluates the identities it was + // lowered from, before it can be pinned into a verifying key. + certify::certify_quotient_program(&self.quotient.plan, &self.quotient.build) + .map_err(|err| format!("quotient program certification failed: {err}"))?; Ok(()) } diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index f1b38498b..b9b0bf28e 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -1959,7 +1959,26 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { items: &[QuotientProgramItem], selector_fold: &SelectorFoldPlan, ) -> QuotientProgramBuild { - let mut builder = QuotientProgramBuilder::default(); + self.build_quotient_program_items_with_limb_ops( + items, + selector_fold, + crate::lowering::config::DEFAULT_QUOTIENT_LIMB_VM_OPS, + ) + } + + /// Lower the same item stream under an explicit limb-opcode policy. + /// + /// Rendering always uses the crate default. The `false` build exists so the + /// generator can cross-check the limb superinstructions against a program + /// that uses only generic Fr opcodes; see + /// `quotient_numerator::vm::certify::certify_quotient_builds_agree`. + pub(super) fn build_quotient_program_items_with_limb_ops( + &self, + items: &[QuotientProgramItem], + selector_fold: &SelectorFoldPlan, + limb_vm_ops: bool, + ) -> QuotientProgramBuild { + let mut builder = QuotientProgramBuilder::with_limb_vm_ops(limb_vm_ops); // Lower the logical plan into bytecode in one pass. Repeated // subexpressions are emitted directly; native callbacks remain opaque // markers because their arithmetic is emitted as separate Yul kernels diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs new file mode 100644 index 000000000..a166ed24e --- /dev/null +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: CC0-1.0 +//! Render-time self-certification of the emitted quotient VM program. +//! +//! The quotient lowering runs a peephole optimizer: shape recognizers rewrite +//! seven-limb foreign-field expressions into superinstructions, and a +//! run-compaction pass rewrites adjacent affine terms into counted opcodes. Both +//! are pure encoding choices that must preserve the evaluated polynomial +//! exactly. This module proves that they did, for the specific program this +//! render is about to emit, by executing the finalized bytecode with the +//! independent interpreter in [`super::reference`] and comparing each identity +//! against direct evaluation of the [`QuotientExpr`] tree it was lowered from. +//! +//! This is a generator-time gate, not a test: every artifact the generator +//! produces is certified before it can be pinned into a verifying key, so a +//! recognizer bug on a previously unseen gate shape fails the render instead of +//! shipping a wrong verifier. +//! +//! See [`super::reference`] for what this does and does not cover. + +use ff::Field; +use midnight_curves::Fq; + +use super::{ + quotient_op_len, + reference::{eval_quotient_expr, eval_quotient_identity, QuotientRefMemory}, + QuotientProgramBuild, QuotientProgramItem, QuotientProgramPlan, QuotientTarget, Q_OP_FOLD_MAIN, + Q_OP_FOLD_SELECTOR, Q_OP_NATIVE_IDENTITY, Q_OP_NATIVE_LOOKUP, Q_OP_NATIVE_PERMUTATION, +}; + +/// Seed for the certification assignment. +/// +/// Fixed rather than random so a failing render reproduces exactly. The check +/// does not need unpredictability: the program is fixed at codegen time and +/// cannot adapt to the seed. +const QUOTIENT_CERTIFY_SEED: u64 = 0x6d69_6466_616c_6c01; + +/// Certify that the emitted bytecode evaluates the planned identities. +/// +/// Runs after [`super::validate_quotient_program`], which has already proven the +/// stream decodes and is stack-safe; this pass assumes well-formedness and +/// checks *meaning*. +pub(crate) fn certify_quotient_program( + plan: &QuotientProgramPlan, + build: &QuotientProgramBuild, +) -> Result<(), String> { + let mut mem = QuotientRefMemory::new(QUOTIENT_CERTIFY_SEED); + let bytes = &build.bytes; + let mut cursor = 0usize; + + for (item_idx, item) in plan.items.iter().enumerate() { + match item { + QuotientProgramItem::Identity(identity) => { + let (expr_end, fold_op) = identity_segment(bytes, cursor) + .map_err(|err| format!("quotient item {item_idx}: {err}"))?; + + let actual = + eval_quotient_identity(&bytes[cursor..expr_end], &build.consts, &mut mem) + .map_err(|err| { + format!( + "quotient identity {} ({:?}): {err}", + identity.meta.global_index, identity.meta.source + ) + })?; + let expected = eval_quotient_expr(&identity.expr, &mut mem); + + if actual != expected { + return Err(format!( + "quotient VM miscompiled identity {} ({:?}): bytecode evaluates to {:?} \ + but its expression evaluates to {:?}. This is a codegen bug in the \ + quotient lowering (shape recognizer, operand packing, or run \ + compaction), not a proof or verifying-key problem.", + identity.meta.global_index, identity.meta.source, actual, expected + )); + } + + check_fold(bytes, expr_end, fold_op, identity, plan).map_err(|err| { + format!( + "quotient identity {} ({:?}): {err}", + identity.meta.global_index, identity.meta.source + ) + })?; + + cursor = expr_end + quotient_op_len(bytes, expr_end); + } + QuotientProgramItem::NativePermutation + | QuotientProgramItem::NativeLookup + | QuotientProgramItem::NativeIdentity(_) => { + // Native markers carry no arithmetic here: the Yul template + // substitutes generated straight-line kernels. Certify only + // that the marker sits at the planned stream position. + let expected_op = match item { + QuotientProgramItem::NativePermutation => Q_OP_NATIVE_PERMUTATION, + QuotientProgramItem::NativeLookup => Q_OP_NATIVE_LOOKUP, + _ => Q_OP_NATIVE_IDENTITY, + }; + let actual_op = *bytes.get(cursor).ok_or_else(|| { + format!("quotient item {item_idx}: program ended before native marker") + })?; + if actual_op != expected_op { + return Err(format!( + "quotient item {item_idx}: expected native marker {expected_op:#x} at byte \ + {cursor}, found {actual_op:#x}" + )); + } + if let QuotientProgramItem::NativeIdentity(native_idx) = item { + // The marker index is a big-endian u16, not a single byte. + let hi = *bytes.get(cursor + 1).ok_or_else(|| { + format!("quotient item {item_idx}: truncated native identity index") + })?; + let lo = *bytes.get(cursor + 2).ok_or_else(|| { + format!("quotient item {item_idx}: truncated native identity index") + })?; + let encoded = u16::from_be_bytes([hi, lo]) as usize; + if encoded != *native_idx { + return Err(format!( + "quotient item {item_idx}: native identity index {encoded} does not \ + match planned index {native_idx}" + )); + } + } + cursor += quotient_op_len(bytes, cursor); + } + } + } + + if cursor != bytes.len() { + return Err(format!( + "quotient program has {} trailing byte(s) after the planned item stream", + bytes.len() - cursor + )); + } + + Ok(()) +} + +/// Find the end of one identity expression and the fold opcode that closes it. +fn identity_segment(bytes: &[u8], start: usize) -> Result<(usize, u8), String> { + let mut idx = start; + while idx < bytes.len() { + let op = bytes[idx]; + match op { + Q_OP_FOLD_MAIN | Q_OP_FOLD_SELECTOR => return Ok((idx, op)), + Q_OP_NATIVE_PERMUTATION | Q_OP_NATIVE_LOOKUP | Q_OP_NATIVE_IDENTITY => { + return Err(format!( + "native marker {op:#x} at byte {idx} interrupts an identity expression" + )); + } + _ => idx += quotient_op_len(bytes, idx), + } + } + Err(format!( + "identity expression starting at byte {start} is never folded" + )) +} + +/// Check that the emitted fold matches the planned target and selector gap. +fn check_fold( + bytes: &[u8], + fold_idx: usize, + fold_op: u8, + identity: &super::QuotientIdentity, + plan: &QuotientProgramPlan, +) -> Result<(), String> { + match (fold_op, identity.target) { + (Q_OP_FOLD_MAIN, QuotientTarget::Main) => Ok(()), + (Q_OP_FOLD_SELECTOR, QuotientTarget::Selector(selector_idx)) => { + let encoded_idx = *bytes + .get(fold_idx + 1) + .ok_or_else(|| "truncated selector fold index".to_string())? + as usize; + if encoded_idx != selector_idx { + return Err(format!( + "selector fold targets bucket {encoded_idx} but the plan says {selector_idx}" + )); + } + let hi = *bytes + .get(fold_idx + 2) + .ok_or_else(|| "truncated selector fold gap".to_string())?; + let lo = *bytes + .get(fold_idx + 3) + .ok_or_else(|| "truncated selector fold gap".to_string())?; + let encoded_gap = u16::from_be_bytes([hi, lo]) as usize; + let planned_gap = plan + .selector_fold + .gap_for(identity) + .ok_or_else(|| "selector identity has no planned fold gap".to_string())?; + if encoded_gap != planned_gap { + return Err(format!( + "selector fold gap {encoded_gap} does not match planned gap {planned_gap}" + )); + } + Ok(()) + } + (fold_op, target) => Err(format!( + "fold opcode {fold_op:#x} does not match planned target {target:?}" + )), + } +} + +/// Certify that two builds of the same identity stream agree. +/// +/// The limb-aware superinstructions are the least principled part of the +/// lowering: they pattern-match algebraic shapes out of a commutative-ring +/// expression tree. Building the same stream with those recognizers disabled +/// yields a program using only `PUSH`/`ADD`/`MUL`/`NEG`, which is +/// straightforward to audit. Requiring the two to agree identity-by-identity +/// turns every recognizer from trusted code into a checked optimization. +pub(crate) fn certify_quotient_builds_agree( + plan: &QuotientProgramPlan, + optimized: &QuotientProgramBuild, + baseline: &QuotientProgramBuild, +) -> Result<(), String> { + let mut mem = QuotientRefMemory::new(QUOTIENT_CERTIFY_SEED); + + let optimized_values = identity_values(plan, optimized, &mut mem)?; + let baseline_values = identity_values(plan, baseline, &mut mem)?; + + if optimized_values.len() != baseline_values.len() { + return Err(format!( + "quotient dual build disagrees on identity count: {} with limb opcodes, {} without", + optimized_values.len(), + baseline_values.len() + )); + } + + for (position, (lhs, rhs)) in optimized_values.iter().zip(baseline_values.iter()).enumerate() { + if lhs != rhs { + return Err(format!( + "quotient limb superinstructions changed the value of interpreted identity at \ + stream position {position}: {lhs:?} with limb opcodes, {rhs:?} without. One of \ + the shape recognizers is unsound for this gate shape." + )); + } + } + + Ok(()) +} + +/// Evaluate every interpreted identity in one build, in stream order. +fn identity_values( + plan: &QuotientProgramPlan, + build: &QuotientProgramBuild, + mem: &mut QuotientRefMemory, +) -> Result, String> { + let bytes = &build.bytes; + let mut values = Vec::new(); + let mut cursor = 0usize; + + for item in &plan.items { + match item { + QuotientProgramItem::Identity(_) => { + let (expr_end, _) = identity_segment(bytes, cursor)?; + values.push(eval_quotient_identity( + &bytes[cursor..expr_end], + &build.consts, + mem, + )?); + cursor = expr_end + quotient_op_len(bytes, expr_end); + } + _ => { + // Native markers evaluate no bytecode; both builds emit the + // same marker at the same stream position. + values.push(Fq::ZERO); + cursor += quotient_op_len(bytes, cursor); + } + } + } + + Ok(values) +} diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 3c26bee4b..67a17b82f 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -52,6 +52,9 @@ //! underflow, and identity-boundary stack leaks before the bytes can be pinned //! into a VK runtime. +pub(crate) mod certify; +pub(crate) mod reference; + use std::collections::{HashMap, HashSet}; use ff::{Field, PrimeField}; @@ -1096,7 +1099,6 @@ impl Default for QuotientProgramBuilder { impl QuotientProgramBuilder { /// Create a builder, optionally enabling limb-specialized opcode emission. - #[cfg(test)] pub(crate) fn with_limb_vm_ops(enabled: bool) -> Self { Self { limb_vm_ops: enabled, diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs new file mode 100644 index 000000000..7cd60866e --- /dev/null +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: CC0-1.0 +//! Independent reference interpreter for finalized quotient VM bytecode. +//! +//! This is the second implementation of the quotient VM ABI. It exists so the +//! generator can certify its own output: for every render, the emitted bytecode +//! is executed here and compared against direct evaluation of the +//! [`QuotientExpr`] trees the bytecode was lowered from. A disagreement means +//! the emitter, one of its shape recognizers, or the run-compaction pass +//! miscompiled an identity, and the render is rejected before any artifact is +//! produced. +//! +//! Why a random-assignment check is sufficient: the quotient program is fixed +//! per verifying key and never sees attacker input, and Fr arithmetic has no +//! edge cases. Any miscompilation therefore yields a *value-independent* wrong +//! polynomial, which disagrees with the correct one at a random assignment with +//! probability `1 - deg/|Fr|`. One evaluation at a pseudorandom point is enough +//! to catch it with overwhelming probability. +//! +//! Scope. This certifies the **emitter to reference-interpreter** leg, which is +//! where the shape recognizers in the parent module live. The +//! **reference-interpreter to Yul** leg is covered separately by the opcode and +//! memory-token table conformance tests and by the per-identity Rust/Solidity +//! trace differential on fixture circuits. Identities executed as inline Yul, +//! native callbacks, or the structured tail are not lowered to bytecode at all, +//! so this module evaluates them directly from their expression trees and they +//! remain covered only by those other two mechanisms. + +use std::collections::HashMap; + +use ff::{Field, PrimeField}; +use midnight_curves::Fq; +use ruint::aliases::U256; +use sha3::{Digest, Keccak256}; + +use super::{ + QuotientExpr, QuotientMem, QUOTIENT_VM_LIMBS, QUOTIENT_VM_PAIRWISE_COEFFS, + Q_MODARITH7_FLAG_COND, Q_MODARITH7_FLAG_CONST, Q_OP_ADD, Q_OP_ADD_CONST, Q_OP_ADD_CONST_U8, + Q_OP_ADD_MEM_U16, Q_OP_ADD_MUL_CONST_U8_MEM_U16, Q_OP_ADD_MUL_MEM_MEM, + Q_OP_ADD_MUL_MEM_MEM_CONST_U8, Q_OP_AFFINE_SUM, Q_OP_BILIN7_PAIRWISE, Q_OP_BILIN7_ROW, + Q_OP_FOLD_MAIN, Q_OP_FOLD_SELECTOR, Q_OP_LIN7, Q_OP_MODARITH7, Q_OP_MUL, Q_OP_MUL_CONST, + Q_OP_MUL_CONST_U8, Q_OP_MUL_MEM_U16, Q_OP_NATIVE_IDENTITY, Q_OP_NATIVE_LOOKUP, + Q_OP_NATIVE_PERMUTATION, Q_OP_NEG, Q_OP_POW5, Q_OP_PUSH_CONST, Q_OP_PUSH_CONST_U8, + Q_OP_PUSH_MEM_LITERAL, Q_OP_PUSH_MEM_TOKEN, Q_OP_PUSH_MEM_TOKEN_OFFSET, Q_OP_PUSH_MEM_U16, + Q_OP_RUN_ADD_MUL_CONST_U8_MEM_U16, Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8, +}; +use crate::lowering::layout::WORD_BYTES; + +/// Deterministic pseudorandom assignment for every verifier memory slot. +/// +/// The bytecode addresses memory by absolute pointer or by symbolic token, and +/// the expression trees address the exact same slots. Deriving each value from +/// its own address means both sides observe identical memory without the +/// certifier having to enumerate the live address set up front, which in turn +/// means a pointer-packing bug shows up as a value mismatch rather than as a +/// missing map key. +#[derive(Clone, Debug)] +pub(crate) struct QuotientRefMemory { + seed: u64, + cache: HashMap<(u8, u32), Fq>, +} + +impl QuotientRefMemory { + /// Build an assignment for one certification run. + pub(crate) fn new(seed: u64) -> Self { + Self { + seed, + cache: HashMap::new(), + } + } + + /// Value at an absolute memory pointer. + pub(crate) fn literal(&mut self, ptr: u32) -> Fq { + self.derive(0, ptr) + } + + /// Value behind a symbolic memory token, optionally offset. + pub(crate) fn token(&mut self, token: u8, offset: u32) -> Fq { + // Tokens resolve to generated addresses disjoint from the literal + // pointer space, so they get their own domain tag. + self.derive(1 + token, offset) + } + + /// Derive one field element from a domain-separated address. + fn derive(&mut self, domain: u8, address: u32) -> Fq { + if let Some(value) = self.cache.get(&(domain, address)) { + return *value; + } + let mut hasher = Keccak256::new(); + hasher.update(b"midfall/quotient-vm/reference-memory/v1"); + hasher.update(self.seed.to_be_bytes()); + hasher.update([domain]); + hasher.update(address.to_be_bytes()); + let lo = hasher.finalize(); + + let mut hasher = Keccak256::new(); + hasher.update(b"midfall/quotient-vm/reference-memory/v1/hi"); + hasher.update(lo); + let hi = hasher.finalize(); + + let mut wide = [0u8; 64]; + wide[..32].copy_from_slice(&lo); + wide[32..].copy_from_slice(&hi); + let value = >::from_uniform_bytes(&wide); + self.cache.insert((domain, address), value); + value + } +} + +/// Evaluate a typed quotient expression directly, without going through the VM. +/// +/// This is the oracle side of the certification: it follows the same shape as +/// `Expression::evaluate` in the native verifier and knows nothing about +/// opcodes, shape recognizers, or operand packing. +pub(crate) fn eval_quotient_expr(expr: &QuotientExpr, mem: &mut QuotientRefMemory) -> Fq { + match expr { + QuotientExpr::Const(value) => fq_from_u256(*value), + QuotientExpr::Mem(QuotientMem::Literal(ptr)) => mem.literal(*ptr), + QuotientExpr::Mem(QuotientMem::Token(token)) => mem.token(*token, 0), + QuotientExpr::Mem(QuotientMem::TokenOffset(token, offset)) => mem.token(*token, *offset), + QuotientExpr::Add(lhs, rhs) => eval_quotient_expr(lhs, mem) + eval_quotient_expr(rhs, mem), + QuotientExpr::Mul(lhs, rhs) => eval_quotient_expr(lhs, mem) * eval_quotient_expr(rhs, mem), + QuotientExpr::Neg(inner) => -eval_quotient_expr(inner, mem), + } +} + +/// Evaluate one identity expression subprogram, up to but excluding its fold. +/// +/// Returns an error rather than panicking: this runs inside the generator, and +/// a malformed stream must surface as a `GeneratorError`, not a process abort. +pub(crate) fn eval_quotient_identity( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, +) -> Result { + let mut stack: Vec = Vec::new(); + let mut idx = 0usize; + + // Pop helpers keep the error path uniform; the offline validator has + // already proven depth safety, so these only fire on validator drift. + macro_rules! pop { + () => { + stack + .pop() + .ok_or_else(|| format!("reference VM stack underflow at byte {idx}"))? + }; + } + + while idx < bytes.len() { + let op = bytes[idx]; + match op { + Q_OP_PUSH_CONST => { + let slot = read_u16(bytes, idx + 1)? as usize; + stack.push(const_at(consts, slot, idx)?); + idx += 3; + } + Q_OP_PUSH_CONST_U8 => { + let slot = byte_at(bytes, idx + 1)? as usize; + stack.push(const_at(consts, slot, idx)?); + idx += 2; + } + Q_OP_PUSH_MEM_LITERAL => { + let ptr = read_u32(bytes, idx + 1)?; + stack.push(mem.literal(ptr)); + idx += 5; + } + Q_OP_PUSH_MEM_U16 => { + let ptr = read_u16(bytes, idx + 1)? as u32; + stack.push(mem.literal(ptr)); + idx += 3; + } + Q_OP_PUSH_MEM_TOKEN => { + let token = byte_at(bytes, idx + 1)?; + stack.push(mem.token(token, 0)); + idx += 2; + } + Q_OP_PUSH_MEM_TOKEN_OFFSET => { + let token = byte_at(bytes, idx + 1)?; + let offset = read_u32(bytes, idx + 2)?; + stack.push(mem.token(token, offset)); + idx += 6; + } + Q_OP_ADD => { + let rhs = pop!(); + let lhs = pop!(); + stack.push(lhs + rhs); + idx += 1; + } + Q_OP_MUL => { + let rhs = pop!(); + let lhs = pop!(); + stack.push(lhs * rhs); + idx += 1; + } + Q_OP_NEG => { + let value = pop!(); + stack.push(-value); + idx += 1; + } + Q_OP_POW5 => { + let value = pop!(); + let squared = value * value; + stack.push(value * squared * squared); + idx += 1; + } + Q_OP_ADD_CONST_U8 | Q_OP_MUL_CONST_U8 => { + let slot = byte_at(bytes, idx + 1)? as usize; + let value = const_at(consts, slot, idx)?; + let acc = pop!(); + stack.push(if op == Q_OP_ADD_CONST_U8 { + acc + value + } else { + acc * value + }); + idx += 2; + } + Q_OP_ADD_CONST | Q_OP_MUL_CONST => { + let slot = read_u16(bytes, idx + 1)? as usize; + let value = const_at(consts, slot, idx)?; + let acc = pop!(); + stack.push(if op == Q_OP_ADD_CONST { + acc + value + } else { + acc * value + }); + idx += 3; + } + Q_OP_ADD_MEM_U16 | Q_OP_MUL_MEM_U16 => { + let ptr = read_u16(bytes, idx + 1)? as u32; + let value = mem.literal(ptr); + let acc = pop!(); + stack.push(if op == Q_OP_ADD_MEM_U16 { + acc + value + } else { + acc * value + }); + idx += 3; + } + Q_OP_ADD_MUL_MEM_MEM_CONST_U8 => { + let acc = pop!(); + let (term, len) = affine_product_term(bytes, consts, mem, idx + 1)?; + stack.push(acc + term); + idx += 1 + len; + } + Q_OP_ADD_MUL_CONST_U8_MEM_U16 => { + let acc = pop!(); + let (term, len) = affine_linear_term(bytes, consts, mem, idx + 1)?; + stack.push(acc + term); + idx += 1 + len; + } + Q_OP_ADD_MUL_MEM_MEM => { + let lhs = read_u16(bytes, idx + 1)? as u32; + let rhs = read_u16(bytes, idx + 3)? as u32; + let acc = pop!(); + stack.push(acc + mem.literal(lhs) * mem.literal(rhs)); + idx += 5; + } + Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8 | Q_OP_RUN_ADD_MUL_CONST_U8_MEM_U16 => { + // Run compaction is a pure encoding change: the same terms in + // the same order, with one shared count instead of repeated + // opcode bytes. + let count = read_u16(bytes, idx + 1)? as usize; + if count == 0 { + return Err(format!("reference VM zero-length run at byte {idx}")); + } + let mut cursor = idx + 3; + let mut acc = pop!(); + for _ in 0..count { + let (term, len) = if op == Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8 { + affine_product_term(bytes, consts, mem, cursor)? + } else { + affine_linear_term(bytes, consts, mem, cursor)? + }; + acc += term; + cursor += len; + } + stack.push(acc); + idx = cursor; + } + Q_OP_AFFINE_SUM => { + // Mixed run: all linear terms first, then all product terms, + // matching `compact_quotient_runs`. + let lin_count = read_u16(bytes, idx + 1)? as usize; + let product_count = read_u16(bytes, idx + 3)? as usize; + if lin_count == 0 || product_count == 0 { + return Err(format!( + "reference VM AFFINE_SUM at byte {idx} requires nonzero counts" + )); + } + let mut cursor = idx + 5; + let mut acc = pop!(); + for _ in 0..lin_count { + let (term, len) = affine_linear_term(bytes, consts, mem, cursor)?; + acc += term; + cursor += len; + } + for _ in 0..product_count { + let (term, len) = affine_product_term(bytes, consts, mem, cursor)?; + acc += term; + cursor += len; + } + stack.push(acc); + idx = cursor; + } + Q_OP_LIN7 => { + let (value, len) = limb_linear_form(bytes, consts, mem, idx + 1)?; + stack.push(value); + idx += 1 + len; + } + Q_OP_BILIN7_ROW => { + let (value, len) = limb_row_form(bytes, consts, mem, idx + 1)?; + stack.push(value); + idx += 1 + len; + } + Q_OP_BILIN7_PAIRWISE => { + let (value, len) = limb_pairwise_form(bytes, consts, mem, idx + 1)?; + stack.push(value); + idx += 1 + len; + } + Q_OP_MODARITH7 => { + let (value, len) = modarith7_form(bytes, consts, mem, idx + 1)?; + stack.push(value); + idx += 1 + len; + } + Q_OP_FOLD_MAIN + | Q_OP_FOLD_SELECTOR + | Q_OP_NATIVE_PERMUTATION + | Q_OP_NATIVE_LOOKUP + | Q_OP_NATIVE_IDENTITY => { + return Err(format!( + "reference VM found stream opcode {op:#x} inside an identity expression at byte {idx}" + )); + } + _ => { + return Err(format!("reference VM unknown opcode {op:#x} at byte {idx}")); + } + } + } + + if stack.len() != 1 { + return Err(format!( + "reference VM identity left {} value(s) on the stack, expected 1", + stack.len() + )); + } + Ok(stack.pop().expect("checked length")) +} + +/// Decode one `const * mload(ptr)` term and return its byte length. +fn affine_linear_term( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let ptr = read_u16(bytes, idx)? as u32; + let slot = byte_at(bytes, idx + 2)? as usize; + Ok((const_at(consts, slot, idx)? * mem.literal(ptr), 3)) +} + +/// Decode one `mload(lhs) * mload(rhs) * const` term and return its byte length. +fn affine_product_term( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let lhs = read_u16(bytes, idx)? as u32; + let rhs = read_u16(bytes, idx + 2)? as u32; + let slot = byte_at(bytes, idx + 4)? as usize; + Ok(( + mem.literal(lhs) * mem.literal(rhs) * const_at(consts, slot, idx)?, + 5, + )) +} + +/// Decode a seven-limb linear form `sum_i const_i * mload(ptr_i)`. +fn limb_linear_form( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let mut acc = Fq::ZERO; + let mut cursor = idx; + for _ in 0..QUOTIENT_VM_LIMBS { + let slot = byte_at(bytes, cursor)? as usize; + let ptr = read_u16(bytes, cursor + 1)? as u32; + acc += const_at(consts, slot, cursor)? * mem.literal(ptr); + cursor += 3; + } + Ok((acc, cursor - idx)) +} + +/// Decode `mload(lhs) * sum_i const_i * mload(rhs_i)`. +fn limb_row_form( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let lhs = read_u16(bytes, idx)? as u32; + let lhs_value = mem.literal(lhs); + let (inner, len) = limb_linear_form(bytes, consts, mem, idx + 2)?; + Ok((lhs_value * inner, 2 + len)) +} + +/// Decode a 7x7 pairwise product with `i + j` indexed coefficients. +fn limb_pairwise_form( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let lhs_base = read_u16(bytes, idx)? as u32; + let rhs_base = read_u16(bytes, idx + 2)? as u32; + let coeff_idx = idx + 4; + // Bounds-check the whole coefficient block once so the inner loop cannot + // read past the program. + byte_at(bytes, coeff_idx + QUOTIENT_VM_PAIRWISE_COEFFS - 1)?; + + let mut acc = Fq::ZERO; + for i in 0..QUOTIENT_VM_LIMBS { + let lhs = mem.literal(lhs_base + (i as u32) * WORD_BYTES as u32); + for j in 0..QUOTIENT_VM_LIMBS { + let rhs = mem.literal(rhs_base + (j as u32) * WORD_BYTES as u32); + let slot = bytes[coeff_idx + i + j] as usize; + acc += lhs * rhs * const_at(consts, slot, coeff_idx)?; + } + } + Ok((acc, 4 + QUOTIENT_VM_PAIRWISE_COEFFS)) +} + +/// Decode the dynamic mixed seven-limb affine form. +fn modarith7_form( + bytes: &[u8], + consts: &[U256], + mem: &mut QuotientRefMemory, + idx: usize, +) -> Result<(Fq, usize), String> { + let mut cursor = idx; + let flags = byte_at(bytes, cursor)?; + if flags & !(Q_MODARITH7_FLAG_COND | Q_MODARITH7_FLAG_CONST) != 0 { + return Err(format!( + "reference VM MODARITH7 unknown flag bits {flags:#x} at byte {idx}" + )); + } + cursor += 1; + + let cond = if flags & Q_MODARITH7_FLAG_COND != 0 { + let ptr = read_u16(bytes, cursor)? as u32; + cursor += 2; + Some(ptr) + } else { + None + }; + + let mut acc = Fq::ZERO; + if flags & Q_MODARITH7_FLAG_CONST != 0 { + let slot = byte_at(bytes, cursor)? as usize; + acc += const_at(consts, slot, cursor)?; + cursor += 1; + } + + let lin_count = byte_at(bytes, cursor)? as usize; + let row_count = byte_at(bytes, cursor + 1)? as usize; + let pairwise_count = byte_at(bytes, cursor + 2)? as usize; + let mem_count = byte_at(bytes, cursor + 3)? as usize; + let product_count = byte_at(bytes, cursor + 4)? as usize; + cursor += 5; + + for _ in 0..lin_count { + let (value, len) = limb_linear_form(bytes, consts, mem, cursor)?; + acc += value; + cursor += len; + } + for _ in 0..row_count { + let (value, len) = limb_row_form(bytes, consts, mem, cursor)?; + acc += value; + cursor += len; + } + for _ in 0..pairwise_count { + let (value, len) = limb_pairwise_form(bytes, consts, mem, cursor)?; + acc += value; + cursor += len; + } + for _ in 0..mem_count { + // Note the operand order here is const-slot first, unlike the standalone + // `ADD_MUL_CONST_U8_MEM_U16` term, so this cannot reuse the helper. + let slot = byte_at(bytes, cursor)? as usize; + let ptr = read_u16(bytes, cursor + 1)? as u32; + acc += const_at(consts, slot, cursor)? * mem.literal(ptr); + cursor += 3; + } + for _ in 0..product_count { + let slot = byte_at(bytes, cursor)? as usize; + let lhs = read_u16(bytes, cursor + 1)? as u32; + let rhs = read_u16(bytes, cursor + 3)? as u32; + acc += const_at(consts, slot, cursor)? * mem.literal(lhs) * mem.literal(rhs); + cursor += 5; + } + + if let Some(cond) = cond { + acc *= mem.literal(cond); + } + Ok((acc, cursor - idx)) +} + +/// Read one byte with an explicit bounds error. +fn byte_at(bytes: &[u8], idx: usize) -> Result { + bytes + .get(idx) + .copied() + .ok_or_else(|| format!("reference VM read past end of program at byte {idx}")) +} + +/// Read a big-endian `u16` operand. +fn read_u16(bytes: &[u8], idx: usize) -> Result { + Ok(u16::from_be_bytes([ + byte_at(bytes, idx)?, + byte_at(bytes, idx + 1)?, + ])) +} + +/// Read a big-endian `u32` operand. +fn read_u32(bytes: &[u8], idx: usize) -> Result { + Ok(u32::from_be_bytes([ + byte_at(bytes, idx)?, + byte_at(bytes, idx + 1)?, + byte_at(bytes, idx + 2)?, + byte_at(bytes, idx + 3)?, + ])) +} + +/// Look up a constant-table slot with an explicit bounds error. +fn const_at(consts: &[U256], slot: usize, idx: usize) -> Result { + consts + .get(slot) + .copied() + .map(fq_from_u256) + .ok_or_else(|| format!("reference VM constant slot {slot} out of range at byte {idx}")) +} + +/// Convert a canonical `U256` constant-table entry into Fr. +fn fq_from_u256(value: U256) -> Fq { + let bytes = value.to_le_bytes::<32>(); + let repr = ::Repr::from(bytes); + Option::::from(Fq::from_repr(repr)).expect("constant table holds canonical field elements") +} diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index e562978ab..c79674a82 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -278,6 +278,147 @@ impl Circuit for LoweringPlanTestCircuit { } } +/// Number of advice columns backing one seven-limb foreign-field shape. +const QUOTIENT_VM_TEST_LIMBS: usize = 7; +/// Gate count chosen to exceed the inline prefix plus the native-gate budget, +/// so identities are left over for the compact VM. +const QUOTIENT_VM_TEST_GATES: usize = + DEFAULT_HYBRID_QUOTIENT_INLINE_IDENTITIES + DEFAULT_QUOTIENT_NATIVE_GATES + 8; + +#[derive(Clone, Debug)] +struct QuotientVmTestConfig { + limbs: [Column; QUOTIENT_VM_TEST_LIMBS], + selector: Selector, +} + +/// Circuit whose quotient identities are numerous enough to reach the VM. +/// +/// `LoweringPlanTestCircuit` has a single gate, so its whole identity stream +/// fits in the inline prefix and the compact VM never runs. This circuit exists +/// so the fast test suite exercises the bytecode path — and therefore the +/// generator's own program certification — on a real `LoweringPlan`. +#[derive(Clone, Debug, Default)] +struct QuotientVmTestCircuit; + +impl Circuit for QuotientVmTestCircuit { + type Config = QuotientVmTestConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let limbs: [Column; QUOTIENT_VM_TEST_LIMBS] = + core::array::from_fn(|_| meta.advice_column()); + let selector = meta.selector(); + // The generator only supports one identity-committed plus one + // non-committed instance column, so mirror that shape here. + let committed_instance = meta.instance_column(); + let public_instance = meta.instance_column(); + + meta.create_gate("quotient vm instance balance", |meta| { + let advice = meta.query_advice(limbs[0], Rotation::cur()); + let committed = meta.query_instance(committed_instance, Rotation::cur()); + let public = meta.query_instance(public_instance, Rotation::cur()); + Constraints::without_selector(vec![advice + committed + public]) + }); + + // Seven-limb linear forms: the shape the LIN7 recognizer is built for. + // Distinct per-gate coefficients keep the gates from deduplicating. + for gate in 0..QUOTIENT_VM_TEST_GATES { + meta.create_gate("quotient vm limb form", move |meta| { + let terms = limbs + .iter() + .enumerate() + .map(|(limb, column)| { + let coeff = Fq::from(((gate + 1) * 16 + limb + 1) as u64); + meta.query_advice(*column, Rotation::cur()) * Expression::Constant(coeff) + }) + .reduce(|acc, term| acc + term) + .expect("limb count is nonzero"); + Constraints::without_selector(vec![terms]) + }); + } + + // One simple-selector gate so the selector fold path is covered too. + meta.create_gate("quotient vm selector form", |meta| { + let lhs = meta.query_advice(limbs[0], Rotation::cur()); + let rhs = meta.query_advice(limbs[1], Rotation::cur()); + Constraints::with_selector(selector, vec![("quotient vm selector form", lhs - rhs)]) + }); + + QuotientVmTestConfig { limbs, selector } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), PlonkError> { + layouter.assign_region( + || "quotient vm row", + |mut region| { + config.selector.enable(&mut region, 0)?; + for column in config.limbs { + region.assign_advice(|| "limb", column, 0, || Value::known(Fq::ZERO))?; + } + Ok(()) + }, + ) + } +} + +/// Generate parameters and VK for the VM-exercising lowering-plan tests. +fn quotient_vm_test_vk() -> ( + ParamsKZG, + VerifyingKey>, +) { + let mut rng = ChaCha8Rng::seed_from_u64(11); + let params = ParamsKZG::::unsafe_setup(6, &mut rng); + let circuit = QuotientVmTestCircuit; + let vk = keygen_vk_with_k::, _>(¶ms, &circuit, 6) + .expect("quotient VM test circuit VK should build"); + (params, vk) +} + +/// The generator certifies its own quotient bytecode on a real plan. +/// +/// `LoweringPlan::new` runs `certify_quotient_program` and the dual-build +/// agreement check, both of which panic on mismatch, so simply building the +/// plan is the assertion. The explicit checks below guard against this test +/// silently going vacuous if the planner ever stops routing these identities +/// through the VM. +#[test] +fn lowering_plan_certifies_emitted_quotient_bytecode() { + let (params, vk) = quotient_vm_test_vk(); + let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); + let plan = generator.inputs().lowering_plan(); + + let interpreted = plan + .quotient + .plan + .items + .iter() + .filter(|item| matches!(item, QuotientProgramItem::Identity(_))) + .count(); + assert!( + interpreted > 0, + "test circuit no longer routes any identity through the compact VM, so the \ + certification path is untested" + ); + assert!( + !plan.quotient.build.bytes.is_empty(), + "interpreted identities should emit bytecode" + ); + assert!( + plan.quotient.build.used_ops.contains(&Q_OP_LIN7), + "test circuit should exercise the seven-limb linear recognizer; used ops: {:?}", + plan.quotient.build.used_ops + ); +} + /// Generate parameters and VK for lowering-plan integration tests. fn lowering_plan_test_vk() -> ( ParamsKZG, From 94dfe37419dcec197969bf378dac5d911a5b1544 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sun, 19 Jul 2026 21:54:39 +0100 Subject: [PATCH 069/108] Refresh moonlight-wrap fixture calldata Re-ran Moonlight's wrap Solidity bench (wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs with MOONLIGHT_RUN_WRAP_SOLIDITY_BENCH=1) against current codegen using the sibling-worktree pattern documented in the fixture README. Halo2Verifier.sol and Halo2VerifyingKey.sol come out byte-identical, so only calldata.bin needs refreshing to match the freshly serialized transcript. The bench reports 1,277,811 gas under revm Prague and 244 matched trace points; the CI replay wrap_point_pair_decoder_rejects_malformed_public_accumulator continues to pass against the updated calldata. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../fixtures/moonlight-wrap/README.md | 4 ++-- .../fixtures/moonlight-wrap/calldata.bin | Bin 8516 -> 8516 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 07efdfa66..0eaeca341 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -14,12 +14,12 @@ the replay deploys the verifier with the verifying key alone. | Field | Value | | --- | --- | -| Source commit | `5209a9c` | +| Source commit | `9bf8c51` | | Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | | Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | | Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | | Public inputs | 19 (accumulator occupies the trailing 8 words) | -| Verified on-chain | yes, 1,277,823 gas under revm Prague | +| Verified on-chain | yes, 1,277,811 gas under revm Prague | | Native/Solidity trace | 244 trace points matched | ## Regenerating diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin b/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin index f19116b45b7a7b4a91f8cfd6990d9cb2af063bbd..b7b53e880f17a7187619a670ee5b1ac5ccf58ae0 100644 GIT binary patch literal 8516 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 literal 8516 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 From 60f842be7c59e532e5832c44ca7eaee846d50744 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 20 Jul 2026 19:59:18 +0100 Subject: [PATCH 070/108] Move the pairing-batch and final-pairing frames above solc's spill window The accumulator/KZG pairing-batch hash frame (0x100) and the ec_pairing two-pair input frame (0x320) sat inside the [0x80, reserved_end) window solc's via-IR stack-to-memory mover uses for spill slots (observed up to 0x8e0), so the alpha Fiat-Shamir preimage and the final pairing inputs were protected only by an unenforced liveness coincidence. Root PAIRING_BATCH_PTR at LOW_MEMORY_SCRATCH_START like every other low-memory base, make VerifierMemoryLayout::validate() reject any generated region below that base, add the batch-frame end to the VK_MPTR floor, and extend the memoryguard test to also compile the accumulator-bearing variants whose FinalPairing block was never handed to solc by that guard. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../docs/architecture/MEMORY_LAYOUT.md | 18 +-- .../src/lowering/layout/memory.rs | 25 ++++- .../src/lowering/layout/mod.rs | 22 +++- proofs/solidity-verifier/src/lowering/vk.rs | 8 +- proofs/solidity-verifier/src/test.rs | 104 +++++++++++------- .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 2 +- .../poseidon-fixture-dump/Halo2Verifier.sol | 2 +- .../Halo2Verifier.sol | 2 +- .../Halo2Verifier.sol | 2 +- 9 files changed, 127 insertions(+), 58 deletions(-) diff --git a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md index 5ad79c2eb..6e669b3d3 100644 --- a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md +++ b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md @@ -44,11 +44,13 @@ own transcript buffer in the same bytes, separated only by live ranges that nothing enforced -- a recompilation could silently place a live spill across a verifier write and corrupt a challenge or pairing input. So the streaming transcript buffer, the main verifier return word, the split quotient return -frame, and low-memory precompile scratch are rooted at +frame, low-memory precompile scratch, the accumulator/KZG pairing-batch hash +frame, and the final two-pair pairing frame are rooted at `LOW_MEMORY_SCRATCH_START` (`0x1000`), above the largest observed reservation. -`compiled_memoryguard_does_not_overlap_generated_layout` compiles each rendered -variant and fails the build if a future circuit or compiler pushes the -reservation past that base. +`VerifierMemoryLayout::validate()` rejects any generated region below that +base, and `compiled_memoryguard_does_not_overlap_generated_layout` compiles +each rendered variant -- including the accumulator-bearing ones -- and fails +the build if a future circuit or compiler pushes the reservation past it. The VK constructor payload buffer is the exception: it lives in `Halo2VerifyingKey`, whose assembly carries no `memory-safe` annotation, so @@ -163,6 +165,8 @@ which changes the transcript-buffer bound. The verifier reserves: - unaligned starts or lengths; - any generated region inside Solidity-reserved memory `[0x00..0x80)`; +- any generated region below `LOW_MEMORY_SCRATCH_START` (`0x1000`), where a + live via-IR spill slot could share its bytes; - overlapping permanent regions; - overlapping scratch regions that are live in the same `MemoryPhase`; - PCS fixed-window overflows. @@ -268,7 +272,7 @@ The planner validates by lifetime, not just by address. | Phase | Region examples | Notes | | --- | --- | --- | -| `Transcript` | `[0, transcript_words * 0x20)` | Must stay below `VK_MPTR`. | +| `Transcript` | `[0x1000, 0x1000 + transcript_words * 0x20)` | Must stay below `VK_MPTR`. | | `ScalarInv` | `VK_MPTR - 0x100` frame | Historical modexp scratch near the VK payload. | | `LagrangeBatchInvert` | `batch_invert_scratch_mptr` | Reuses selector bytes before selector accumulators are live. | | `QuotientVm` | quotient temps and stack | Used before PCS final MSM. | @@ -276,8 +280,8 @@ The planner validates by lifetime, not just by address. | `PcsQComTrace` | optional q_com trace MSM | Aliases `pcs_scratch_mptr`; trace-only. | | `PcsFinalMsm` | final MSM input and selector accumulators | Selector accumulators and final MSM must not overlap in this phase. | | `AccumulatorMsm` | public accumulator MSM input | Length is derived from accumulator/VK shape. | -| `AccumulatorPairingBatch` | `[0x100, 0x320)` | Hash domain plus four G1 points for accumulator pairing batching. | -| `FinalPairing` | two-pair KZG pairing frame | Low-memory final precompile frame. | +| `AccumulatorPairingBatch` | `[0x1000, 0x1220)` | Hash domain plus four G1 points for accumulator pairing batching. | +| `FinalPairing` | `[0x1220, 0x1540)` two-pair KZG pairing frame | Final precompile frame, placed past the pairing-batch frame by construction. | ## Update Rules diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index fd91314d3..54a565c73 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -36,9 +36,10 @@ use crate::lowering::{ }; /// Accumulator pairing-batch hash frame. /// -/// The template starts this frame at `0x100`, writes a one-word domain tag, -/// then four G1 points: KZG rhs/lhs and accumulator rhs/lhs. The last copy ends -/// at `0x320`, so the registered range is `[0x100, 0x320)`. +/// The template starts this frame at `PAIRING_BATCH_PTR` (`0x1000`), writes a +/// one-word domain tag, then four G1 points: KZG rhs/lhs and accumulator +/// rhs/lhs. The last copy ends `0x220` bytes later, so the registered range is +/// `[0x1000, 0x1220)`. const ACCUMULATOR_PAIRING_BATCH_BYTES: usize = PAIRING_BATCH_HASH_BYTES; // Fixed word offsets from `THETA_MPTR`. @@ -1067,6 +1068,24 @@ impl VerifierMemoryLayout { } } + // The verifier body runs inside `assembly ("memory-safe")`, so solc's + // via-IR stack-to-memory mover reserves spill slots upward from 0x80. + // A generated region below `LOW_MEMORY_SCRATCH_START` could share + // bytes with a live spill slot, and the lifetime model cannot see + // solc's opaque spill liveness -- so enforce disjointness by address. + // `compiled_memoryguard_does_not_overlap_generated_layout` checks the + // complementary bound, `reserved_end <= LOW_MEMORY_SCRATCH_START`, + // against real compiled bytecode. + for region in &self.map.regions { + if region.len != 0 && region.start < LOW_MEMORY_SCRATCH_START { + return Err(format!( + "memory region {} starts at {:#x}, below LOW_MEMORY_SCRATCH_START ({:#x}); \ + it can overlap solc's via-IR stack-to-memory spill window [0x80, reserved_end)", + region.name, region.start, LOW_MEMORY_SCRATCH_START + )); + } + } + let expected_scalar_inv = self.vk_mptr.value().as_usize().saturating_sub(MODEXP_SCRATCH_BYTES); if self.scalar_inv_scratch_mptr != expected_scalar_inv { diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 76a08f82f..6425310a4 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -112,8 +112,8 @@ pub(crate) const PAIRING_STATIC_WORKING_WORDS: usize = PAIRING_TWO_PAIR_BYTES / /// /// Placed past the end of the accumulator pairing-batch hash frame, which /// occupies `[PAIRING_BATCH_PTR, PAIRING_BATCH_PTR + PAIRING_BATCH_HASH_BYTES)` -/// = `[0x100, 0x320)`. Starting at `PAIRING_TWO_PAIR_BYTES` (0x300) instead -/// would put the last word of the hashed ACC_LHS copy inside this scratch. +/// = `[0x1000, 0x1220)`. Starting lower would put the last word of the hashed +/// ACC_LHS copy inside this scratch. /// The two regions carry different `MemoryPhase`s, and `MemoryLifetime:: /// intersects` treats distinct phases as never co-live, so the planner cannot /// catch that overlap -- it has to be avoided by construction here. @@ -170,7 +170,13 @@ pub(crate) mod accumulator { pub(crate) const CARRIED_SCALARS: usize = 2; /// Low-memory hash frame for batching the accumulator pairing with KZG: /// domain tag word, KZG rhs/lhs G1s, then accumulator rhs/lhs G1s. - pub(crate) const PAIRING_BATCH_PTR: usize = 0x100; + /// + /// Rooted at [`super::LOW_MEMORY_SCRATCH_START`] like every other + /// low-memory scratch base: the frame historically sat at `0x100`, inside + /// the `[0x80, reserved_end)` window solc's via-IR stack-to-memory mover + /// reserves for spill slots, so a live spill could silently corrupt the + /// alpha Fiat-Shamir preimage or the pairing inputs built here. + pub(crate) const PAIRING_BATCH_PTR: usize = super::LOW_MEMORY_SCRATCH_START; /// Domain-separation word for the accumulator pairing batch. /// /// This is a 29-byte numeric literal: ASCII `"pairing-batch-acc-kzg"` @@ -774,8 +780,16 @@ mod tests { assert_eq!(accumulator::LIMB_BITS, 56); assert_eq!(accumulator::LIMBS, 7); assert_eq!(accumulator::LIMBS_PER_WORD, 4); - assert_eq!(accumulator::PAIRING_BATCH_PTR, 0x100); + // Above solc's via-IR spill window like every other low-memory base. + assert_eq!( + accumulator::PAIRING_BATCH_PTR, + super::LOW_MEMORY_SCRATCH_START + ); assert_eq!(accumulator::PAIRING_BATCH_HASH_BYTES, 0x220); + assert_eq!( + super::FINAL_PAIRING_SCRATCH_START, + super::LOW_MEMORY_SCRATCH_START + 0x220 + ); assert_eq!(quotient_limb::LIMBS, 7); assert_eq!(quotient_limb::PAIRWISE_TERMS, 49); assert_eq!(quotient_limb::PAIRWISE_COEFFS, 13); diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index 33e173465..1e5d97623 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -387,6 +387,8 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { Self::transcript_buffer_layout_for_meta(meta, self.num_instances).words; let transcript_end = layout::TRANSCRIPT_BUFFER_START + transcript_words * WORD_BYTES; let pcs_end = layout::PCS_PAIRING_SCRATCH_START + pcs_computation * WORD_BYTES; + let pairing_batch_end = layout::accumulator::PAIRING_BATCH_PTR + + layout::accumulator::PAIRING_BATCH_HASH_BYTES; let final_pairing_end = layout::FINAL_PAIRING_SCRATCH_START + layout::PAIRING_STATIC_WORKING_WORDS * WORD_BYTES; let verifier_return_end = layout::VERIFIER_RETURN_BUFFER_START + WORD_BYTES; @@ -402,8 +404,12 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { transcript_end, // PCS computation scratch pcs_end, + // Accumulator/KZG pairing-batch hash frame. Currently ends where + // the final pairing frame starts, but list it explicitly so the + // bound survives if that derivation changes. + pairing_batch_end, // Pairing: two-pair input frame plus output word, rooted above - // Solidity's reserved memory prefix. + // solc's via-IR spill window. final_pairing_end, // Low-memory return frames. The quotient evaluator's output grows // with the number of simple selector buckets. diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 5eab7d99b..02cbc706c 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1370,18 +1370,20 @@ fn pinned_quotient_verifier_rejects_wrong_vk_and_quotient_contracts() { /// is not fixed -- observed values range from `0x80` to `0x8e0` depending on /// the circuit, the solc release, and the optimizer schedule -- so assert the /// property against real compiled bytecode rather than assuming it holds. +/// +/// `VerifierMemoryLayout::validate()` enforces the complementary bound: every +/// generated region starts at or above `LOW_MEMORY_SCRATCH_START`, so +/// `reserved_end <= LOW_MEMORY_SCRATCH_START` here proves full disjointness. +/// The accumulator-bearing variants are checked too, because their +/// FinalPairing pairing-batch block adds frames and live values the property +/// fixture never renders. #[test] fn compiled_memoryguard_does_not_overlap_generated_layout() { if !poseidon_inputs_available_for_evm() { return; } - let fixture = create_property_poseidon_fixture(); - for (name, source) in [ - ("embedded", fixture.embedded_verifier_solidity.as_str()), - ("separate", fixture.separate_verifier_solidity.as_str()), - ("quotient", fixture.quotient_verifier_solidity.as_str()), - ] { + fn assert_memoryguard_clears_generated_layout(name: &str, source: &str) { let runtime = compile_solidity_runtime(source); let reserved_end = runtime_free_memory_pointer_init(&runtime).unwrap_or_else(|| { panic!("{name}: could not read the free-memory-pointer prologue from runtime bytecode") @@ -1395,6 +1397,19 @@ fn compiled_memoryguard_does_not_overlap_generated_layout() { crate::lowering::layout::LOW_MEMORY_SCRATCH_START ); } + + let fixture = create_property_poseidon_fixture(); + for (name, source) in [ + ("embedded", fixture.embedded_verifier_solidity.as_str()), + ("separate", fixture.separate_verifier_solidity.as_str()), + ("quotient", fixture.quotient_verifier_solidity.as_str()), + ] { + assert_memoryguard_clears_generated_layout(name, source); + } + + for (name, _, artifacts) in render_accumulator_verifier_variants() { + assert_memoryguard_clears_generated_layout(name, &artifacts.verifier); + } } /// `Halo2VerifyingKey` is size-checked at render time by @@ -1637,27 +1652,10 @@ fn accumulator_fixed_base_tail_must_match_verifying_key() { } } -/// Compile the accumulator render arm. -/// -/// No production fixture enables `with_accumulator`, so before this test the -/// whole `{%- if self.expected_has_accumulator %}` branch of -/// AccumulatorHelpers.yul -- the limb decoder, the pre-transcript -/// public-accumulator MSM, and the fixed-base scalar tail -- was never handed -/// to solc by the default gate. Only the opt-in `ivc_keccak_solidity` bench -/// (k = 20, release, external SRS assets) rendered it, so a Yul syntax error -/// or a solc stack-depth regression in that branch could reach a release -/// unnoticed. -/// -/// This does not execute the accumulator logic against a real recursive proof -/// -- that still needs a decider circuit carrying a genuine accumulator in its -/// public inputs. It does guarantee the branch compiles, and it pins the -/// canonicality checks on the scalars the helper feeds to G1MSM. -#[test] -fn accumulator_verifier_variants_compile_with_pinned_solc() { - if !poseidon_inputs_available_for_evm() { - return; - } - +/// Render the three accumulator-bearing verifier variants over the Poseidon +/// fixture VK: fully collapsed, fixed-base scalar tail, and point-pair +/// encodings. Returns `(name, has_carried_scalars, artifacts)` per variant. +fn render_accumulator_verifier_variants() -> Vec<(&'static str, bool, crate::RenderedArtifacts)> { let srs_dir = srs_dir(); env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; @@ -1696,19 +1694,47 @@ fn accumulator_verifier_variants_compile_with_pinned_solc() { ), ]; - for (name, num_instances, acc, has_carried_scalars) in variants { - let generator = SolidityGenerator::new( - &srs, - vk.vk(), - GeneratorConfig::new(num_instances, 1).with_accumulator(acc), - ); - let artifacts = generator - .render(RenderOptions { - vk: RenderVk::Separate, - ..RenderOptions::default() - }) - .unwrap_or_else(|err| panic!("{name} should render: {err}")); + variants + .into_iter() + .map(|(name, num_instances, acc, has_carried_scalars)| { + let generator = SolidityGenerator::new( + &srs, + vk.vk(), + GeneratorConfig::new(num_instances, 1).with_accumulator(acc), + ); + let artifacts = generator + .render(RenderOptions { + vk: RenderVk::Separate, + ..RenderOptions::default() + }) + .unwrap_or_else(|err| panic!("{name} should render: {err}")); + (name, has_carried_scalars, artifacts) + }) + .collect() +} + +/// Compile the accumulator render arm. +/// +/// No production fixture enables `with_accumulator`, so before this test the +/// whole `{%- if self.expected_has_accumulator %}` branch of +/// AccumulatorHelpers.yul -- the limb decoder, the pre-transcript +/// public-accumulator MSM, and the fixed-base scalar tail -- was never handed +/// to solc by the default gate. Only the opt-in `ivc_keccak_solidity` bench +/// (k = 20, release, external SRS assets) rendered it, so a Yul syntax error +/// or a solc stack-depth regression in that branch could reach a release +/// unnoticed. +/// +/// This does not execute the accumulator logic against a real recursive proof +/// -- that still needs a decider circuit carrying a genuine accumulator in its +/// public inputs. It does guarantee the branch compiles, and it pins the +/// canonicality checks on the scalars the helper feeds to G1MSM. +#[test] +fn accumulator_verifier_variants_compile_with_pinned_solc() { + if !poseidon_inputs_available_for_evm() { + return; + } + for (name, has_carried_scalars, artifacts) in render_accumulator_verifier_variants() { let verifier = artifacts.verifier; assert!( verifier.contains("function validate_public_accumulator"), diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index 6c05c2567..7f5d40d89 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -592,7 +592,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index 8a2e5f8cf..7a6702aef 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -592,7 +592,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index dea9593f8..f897a9c32 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -592,7 +592,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 150bbd4be..88bdcc4b8 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -592,7 +592,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) From aa62d19dd95d7f747849ee9f47d65eab520a74fa Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 20 Jul 2026 20:32:56 +0100 Subject: [PATCH 071/108] Reject non-canonical scalars in batch_invert's general path The single-element fast path fails closed on any word >= r, but the multi-element path folded raw words straight through mulmod, so a non-canonical scalar was silently reduced and its slot filled with inverse(x mod r): accept/reject semantics depended on batch length. Unreachable from the one production call site (the Lagrange block feeds addmod/mulmod outputs), but a latent divergence inside a shared primitive whose other inversion helper, scalar_inv, already rejects x >= r. Guard every element of the forward pass like the singleton path, pin the guard text in the template greps, and add a revm harness test that executes the rendered helper on adversarial words in both paths (it reproduces the acceptance on the unfixed template) and checks canonical batches against native inverses. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../solidity-verifier/src/lowering/tests.rs | 20 +++ proofs/solidity-verifier/src/lowering/vk.rs | 4 +- proofs/solidity-verifier/src/test.rs | 162 ++++++++++++++++++ .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 22 ++- .../poseidon-fixture-dump/Halo2Verifier.sol | 22 ++- .../Halo2Verifier.sol | 22 ++- .../Halo2Verifier.sol | 22 ++- .../partials/verifier/AssemblyHelpers.yul | 22 ++- 8 files changed, 284 insertions(+), 12 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index c79674a82..4f0b880d7 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -2071,6 +2071,26 @@ fn batch_invert_handles_empty_and_singleton_ranges() { verifier_template.contains("if ret { mstore(mptr_start, mload(single_scratch)) }"), "singleton batch inversion must store the single inverse in place" ); + // The general path must reject non-canonical words (x >= r) like the + // singleton path, so accept/reject semantics do not depend on batch + // length: one guard on the first element, one inside the prefix-product + // loop, one on the final element. + assert_eq!( + verifier_template.matches("if iszero(lt(gp, r)) {").count(), + 1, + "general batch inversion path must range-check the first element" + ); + assert_eq!( + verifier_template.matches("if iszero(lt(x, r)) {").count(), + 2, + "batch inversion must range-check the singleton element and every \ + prefix-product loop element" + ); + assert_eq!( + verifier_template.matches("if iszero(lt(x_last, r)) {").count(), + 1, + "general batch inversion path must range-check the final element" + ); } #[test] diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index 1e5d97623..af26bc0f7 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -387,8 +387,8 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { Self::transcript_buffer_layout_for_meta(meta, self.num_instances).words; let transcript_end = layout::TRANSCRIPT_BUFFER_START + transcript_words * WORD_BYTES; let pcs_end = layout::PCS_PAIRING_SCRATCH_START + pcs_computation * WORD_BYTES; - let pairing_batch_end = layout::accumulator::PAIRING_BATCH_PTR - + layout::accumulator::PAIRING_BATCH_HASH_BYTES; + let pairing_batch_end = + layout::accumulator::PAIRING_BATCH_PTR + layout::accumulator::PAIRING_BATCH_HASH_BYTES; let final_pairing_end = layout::FINAL_PAIRING_SCRATCH_START + layout::PAIRING_STATIC_WORKING_WORDS * WORD_BYTES; let verifier_return_end = layout::VERIFIER_RETURN_BUFFER_START + WORD_BYTES; diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 02cbc706c..1a4f07793 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1443,6 +1443,168 @@ fn compiled_verifier_runtime_fits_the_eip170_limit() { } } +/// Extract one rendered Yul function (signature through matching close brace) +/// from generated verifier source. The rendered helpers contain no string +/// literals, so plain brace counting is sufficient. +fn extract_yul_function<'a>(source: &'a str, signature_prefix: &str) -> &'a str { + let start = source + .find(signature_prefix) + .unwrap_or_else(|| panic!("rendered source should define {signature_prefix}")); + let tail = &source[start..]; + let open = tail.find('{').expect("function definition must open a brace"); + let mut depth = 0usize; + for (idx, byte) in tail.bytes().enumerate().skip(open) { + match byte { + b'{' => depth += 1, + b'}' => { + depth -= 1; + if depth == 0 { + return &tail[..=idx]; + } + } + _ => {} + } + } + panic!("unbalanced braces while extracting {signature_prefix}"); +} + +/// Test-only contract that runs the rendered `batch_invert` helper on +/// caller-chosen memory words. Raw calldata is `n || r || n words`; raw +/// returndata is `success flag || the n (possibly inverted) words`. +fn batch_invert_harness_source(verifier_solidity: &str) -> String { + let batch_invert = extract_yul_function( + verifier_solidity, + "function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret", + ); + format!( + r#"// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.24; + +contract BatchInvertHarness {{ + fallback() external {{ + assembly {{ + {batch_invert} + + let n := calldataload(0x00) + let r := calldataload(0x20) + let base := 0x1000 + calldatacopy(base, 0x40, mul(n, 0x20)) + let ok := batch_invert(1, base, add(base, mul(n, 0x20)), 0x8000, r) + mstore(0x80, ok) + mcopy(0xa0, base, mul(n, 0x20)) + return(0x80, add(0x20, mul(n, 0x20))) + }} + }} +}} +"# + ) +} + +/// Execute the rendered `batch_invert` helper against adversarial words. +/// +/// The template greps in `lowering/tests.rs` pin the guard text; this pins +/// the behavior: the singleton and general paths must both fail closed on +/// words outside the canonical range (`x >= r`, including invertible +/// residues, `x = r`, and literal zero) without touching the input run, +/// so accept/reject semantics never depend on batch length. Canonical +/// batches must produce exactly the native inverses. +#[test] +fn batch_invert_fails_closed_on_noncanonical_words_in_all_paths() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let fixture = create_property_poseidon_fixture(); + let harness = batch_invert_harness_source(&fixture.embedded_verifier_solidity); + let mut evm = Evm::default(); + let address = evm.create(compile_solidity(&harness)); + + let r = fr_modulus_u256(); + let mut run = |elems: &[U256]| -> (bool, Vec) { + let mut calldata = Vec::with_capacity((2 + elems.len()) * 0x20); + calldata.extend_from_slice(&U256::from(elems.len()).to_be_bytes::<0x20>()); + calldata.extend_from_slice(&r.to_be_bytes::<0x20>()); + for elem in elems { + calldata.extend_from_slice(&elem.to_be_bytes::<0x20>()); + } + match evm.try_call(address, calldata) { + CallOutcome::Success { output, .. } => { + assert_eq!( + output.len(), + (1 + elems.len()) * 0x20, + "harness returndata shape" + ); + let flag = U256::try_from_be_slice(&output[..0x20]).unwrap(); + assert!(flag <= U256::from(1), "success flag must be boolean"); + let words = output[0x20..] + .chunks_exact(0x20) + .map(|word| U256::try_from_be_slice(word).unwrap()) + .collect(); + (flag == U256::from(1), words) + } + outcome => panic!("harness must not revert or halt: {outcome:?}"), + } + }; + + let word = |value: u64| U256::from(value); + let inv = + |value: u64| crate::lowering::encoding::fe_to_u256::(F::from(value).invert().unwrap()); + + // Canonical batches succeed and invert every element in place; the + // lengths cover the empty, singleton, two-element, and looped general + // paths. + let (ok, out) = run(&[]); + assert!(ok, "empty batch must be a no-op success"); + assert!(out.is_empty()); + for elems in [vec![7u64], vec![2, 3], vec![1, 2, 3, 5, 7]] { + let input: Vec = elems.iter().copied().map(word).collect(); + let (ok, out) = run(&input); + assert!(ok, "canonical batch of {} must succeed", elems.len()); + let expected: Vec = elems.iter().copied().map(inv).collect(); + assert_eq!( + out, + expected, + "batch of {} must produce native inverses", + elems.len() + ); + } + + // Every rejection leaves the input run untouched: zero and anything + // congruent to zero mod r has no inverse, and non-canonical words with + // invertible residues (x = r + 5, 2^256 - 1) must fail closed in both + // paths rather than being reduced by mulmod. The three r + 5 positions + // hit the general path's first-element, loop, and final-element guards. + let r_plus_5 = r + word(5); + for (name, elems) in [ + ("singleton literal zero", vec![U256::ZERO]), + ("singleton x = r", vec![r]), + ("singleton x = r + 5", vec![r_plus_5]), + ("singleton x = 2^256 - 1", vec![U256::MAX]), + ("general literal zero", vec![word(2), U256::ZERO, word(3)]), + ("general x = r", vec![word(2), r, word(3)]), + ( + "general first element x = r + 5", + vec![r_plus_5, word(2), word(3)], + ), + ( + "general loop element x = r + 5", + vec![word(2), r_plus_5, word(3)], + ), + ( + "general final element x = r + 5", + vec![word(2), word(3), r_plus_5], + ), + ( + "general two-element x = 2^256 - 1", + vec![word(2), U256::MAX], + ), + ] { + let (ok, out) = run(&elems); + assert!(!ok, "{name} must fail closed"); + assert_eq!(out, elems, "{name} must leave the input words untouched"); + } +} + #[test] fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { if !poseidon_inputs_available_for_evm() { diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index 7f5d40d89..40e7e6568 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -524,16 +524,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index 7a6702aef..ee59832c1 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -524,16 +524,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index f897a9c32..7679a069d 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -524,16 +524,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 88bdcc4b8..36d30c3e4 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -524,16 +524,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index 589fe1273..5ba918b36 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -175,16 +175,34 @@ // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { From 0cd1bdb1971ccc350ad784a3181a8a213e8a1cc7 Mon Sep 17 00:00:00 2001 From: Julian Date: Tue, 21 Jul 2026 00:52:02 +0100 Subject: [PATCH 072/108] Harden quotient certification and spill-window coverage Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../src/lowering/layout/memory.rs | 2 +- proofs/solidity-verifier/src/lowering/plan.rs | 3 +- .../lowering/quotient_numerator/vm/certify.rs | 111 ++++++++++++++++-- .../quotient_numerator/vm/reference.rs | 19 +-- .../solidity-verifier/src/lowering/tests.rs | 84 +++++++++++++ proofs/solidity-verifier/src/test.rs | 41 +++++-- 6 files changed, 230 insertions(+), 30 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 54a565c73..5be8d69a1 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -1075,7 +1075,7 @@ impl VerifierMemoryLayout { // solc's opaque spill liveness -- so enforce disjointness by address. // `compiled_memoryguard_does_not_overlap_generated_layout` checks the // complementary bound, `reserved_end <= LOW_MEMORY_SCRATCH_START`, - // against real compiled bytecode. + // against real compiled verifier and quotient-evaluator bytecode. for region in &self.map.regions { if region.len != 0 && region.start < LOW_MEMORY_SCRATCH_START { return Err(format!( diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index 9f3f60017..6e001d3e6 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -178,6 +178,7 @@ impl LoweringPlan { &plan.quotient.plan, &plan.quotient.build, &baseline_build, + &plan.vk, ) .unwrap_or_else(|err| panic!("quotient dual-build certification failed: {err}")); @@ -340,7 +341,7 @@ impl LoweringPlan { } // Prove the emitted bytecode still evaluates the identities it was // lowered from, before it can be pinned into a verifying key. - certify::certify_quotient_program(&self.quotient.plan, &self.quotient.build) + certify::certify_quotient_program(&self.quotient.plan, &self.quotient.build, &self.vk) .map_err(|err| format!("quotient program certification failed: {err}"))?; Ok(()) } diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs index a166ed24e..a8348ec77 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs @@ -19,20 +19,107 @@ use ff::Field; use midnight_curves::Fq; +use sha3::{Digest, Keccak256}; use super::{ quotient_op_len, reference::{eval_quotient_expr, eval_quotient_identity, QuotientRefMemory}, - QuotientProgramBuild, QuotientProgramItem, QuotientProgramPlan, QuotientTarget, Q_OP_FOLD_MAIN, - Q_OP_FOLD_SELECTOR, Q_OP_NATIVE_IDENTITY, Q_OP_NATIVE_LOOKUP, Q_OP_NATIVE_PERMUTATION, + QuotientExpr, QuotientMem, QuotientProgramBuild, QuotientProgramItem, QuotientProgramPlan, + QuotientTarget, Q_OP_FOLD_MAIN, Q_OP_FOLD_SELECTOR, Q_OP_NATIVE_IDENTITY, Q_OP_NATIVE_LOOKUP, + Q_OP_NATIVE_PERMUTATION, }; +use crate::lowering::render::Halo2VerifyingKey; /// Seed for the certification assignment. /// -/// Fixed rather than random so a failing render reproduces exactly. The check -/// does not need unpredictability: the program is fixed at codegen time and -/// cannot adapt to the seed. -const QUOTIENT_CERTIFY_SEED: u64 = 0x6d69_6466_616c_6c01; +/// The seed is deterministic so failing renders reproduce exactly, but it is +/// derived from the finalized artifact rather than fixed globally. This keeps +/// the sampled assignment independent of any circuit author's pre-render view +/// of the quotient program while preserving reproducible diagnostics. +const QUOTIENT_CERTIFY_SEED_DOMAIN: &[u8] = b"midfall/quotient-vm/certify-seed/v3"; + +/// Derive the random-assignment seed from every compared artifact. +/// +/// Binding the oracle expressions closes the case where a miscompile drops a +/// tunable constant before it reaches the emitted constant table. Binding both +/// builds makes the dual-build challenge depend on the optimized and baseline +/// representations. The VK payload is included after generator invariants have +/// checked that its quotient sections match the finalized build. +pub(crate) fn derive_certify_seed( + builds: &[&QuotientProgramBuild], + exprs: &[&QuotientExpr], + vk_payload: &[u8], +) -> [u8; 32] { + let mut hasher = Keccak256::new(); + hasher.update(QUOTIENT_CERTIFY_SEED_DOMAIN); + + hasher.update((builds.len() as u64).to_be_bytes()); + for build in builds { + hasher.update((build.bytes.len() as u64).to_be_bytes()); + hasher.update(&build.bytes); + + hasher.update((build.consts.len() as u64).to_be_bytes()); + for value in &build.consts { + hasher.update(value.to_be_bytes::<32>()); + } + } + + hasher.update((exprs.len() as u64).to_be_bytes()); + for expr in exprs { + hash_quotient_expr(&mut hasher, expr); + } + + hasher.update((vk_payload.len() as u64).to_be_bytes()); + hasher.update(vk_payload); + + hasher.finalize().into() +} + +/// Hash one expression with explicit node and memory-address tags. +fn hash_quotient_expr(hasher: &mut Keccak256, expr: &QuotientExpr) { + match expr { + QuotientExpr::Const(value) => { + hasher.update([0]); + hasher.update(value.to_be_bytes::<32>()); + } + QuotientExpr::Mem(QuotientMem::Literal(ptr)) => { + hasher.update([1]); + hasher.update(ptr.to_be_bytes()); + } + QuotientExpr::Mem(QuotientMem::Token(token)) => { + hasher.update([2, *token]); + } + QuotientExpr::Mem(QuotientMem::TokenOffset(token, offset)) => { + hasher.update([3, *token]); + hasher.update(offset.to_be_bytes()); + } + QuotientExpr::Add(lhs, rhs) => { + hasher.update([4]); + hash_quotient_expr(hasher, lhs); + hash_quotient_expr(hasher, rhs); + } + QuotientExpr::Mul(lhs, rhs) => { + hasher.update([5]); + hash_quotient_expr(hasher, lhs); + hash_quotient_expr(hasher, rhs); + } + QuotientExpr::Neg(inner) => { + hasher.update([6]); + hash_quotient_expr(hasher, inner); + } + } +} + +/// Expressions evaluated by the compact quotient program. +fn interpreted_exprs(plan: &QuotientProgramPlan) -> Vec<&QuotientExpr> { + plan.items + .iter() + .filter_map(|item| match item { + QuotientProgramItem::Identity(identity) => Some(&identity.expr), + _ => None, + }) + .collect() +} /// Certify that the emitted bytecode evaluates the planned identities. /// @@ -42,8 +129,12 @@ const QUOTIENT_CERTIFY_SEED: u64 = 0x6d69_6466_616c_6c01; pub(crate) fn certify_quotient_program( plan: &QuotientProgramPlan, build: &QuotientProgramBuild, + vk: &Halo2VerifyingKey, ) -> Result<(), String> { - let mut mem = QuotientRefMemory::new(QUOTIENT_CERTIFY_SEED); + let exprs = interpreted_exprs(plan); + let vk_payload = vk.bytes(); + let seed = derive_certify_seed(&[build], &exprs, &vk_payload); + let mut mem = QuotientRefMemory::new(seed); let bytes = &build.bytes; let mut cursor = 0usize; @@ -209,8 +300,12 @@ pub(crate) fn certify_quotient_builds_agree( plan: &QuotientProgramPlan, optimized: &QuotientProgramBuild, baseline: &QuotientProgramBuild, + vk: &Halo2VerifyingKey, ) -> Result<(), String> { - let mut mem = QuotientRefMemory::new(QUOTIENT_CERTIFY_SEED); + let exprs = interpreted_exprs(plan); + let vk_payload = vk.bytes(); + let seed = derive_certify_seed(&[optimized, baseline], &exprs, &vk_payload); + let mut mem = QuotientRefMemory::new(seed); let optimized_values = identity_values(plan, optimized, &mut mem)?; let baseline_values = identity_values(plan, baseline, &mut mem)?; diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs index 7cd60866e..ceb954afb 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs @@ -9,12 +9,13 @@ //! miscompiled an identity, and the render is rejected before any artifact is //! produced. //! -//! Why a random-assignment check is sufficient: the quotient program is fixed -//! per verifying key and never sees attacker input, and Fr arithmetic has no -//! edge cases. Any miscompilation therefore yields a *value-independent* wrong -//! polynomial, which disagrees with the correct one at a random assignment with -//! probability `1 - deg/|Fr|`. One evaluation at a pseudorandom point is enough -//! to catch it with overwhelming probability. +//! Why a random-assignment check is sufficient: the certifier samples a +//! deterministic challenge from the finalized quotient bytecode, constant +//! table, oracle expression trees, and VK payload, then evaluates the fixed +//! program at that assignment. Any miscompilation therefore yields a wrong +//! polynomial that was fixed before the challenge was known, and it disagrees +//! with the correct one with probability `1 - deg/|Fr|`. One challenge-derived +//! evaluation is enough to catch it with overwhelming probability. //! //! Scope. This certifies the **emitter to reference-interpreter** leg, which is //! where the shape recognizers in the parent module live. The @@ -55,13 +56,13 @@ use crate::lowering::layout::WORD_BYTES; /// missing map key. #[derive(Clone, Debug)] pub(crate) struct QuotientRefMemory { - seed: u64, + seed: [u8; 32], cache: HashMap<(u8, u32), Fq>, } impl QuotientRefMemory { /// Build an assignment for one certification run. - pub(crate) fn new(seed: u64) -> Self { + pub(crate) fn new(seed: [u8; 32]) -> Self { Self { seed, cache: HashMap::new(), @@ -87,7 +88,7 @@ impl QuotientRefMemory { } let mut hasher = Keccak256::new(); hasher.update(b"midfall/quotient-vm/reference-memory/v1"); - hasher.update(self.seed.to_be_bytes()); + hasher.update(self.seed); hasher.update([domain]); hasher.update(address.to_be_bytes()); let lo = hasher.finalize(); diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 4f0b880d7..d4c1c7f25 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -419,6 +419,90 @@ fn lowering_plan_certifies_emitted_quotient_bytecode() { ); } +#[test] +fn quotient_certification_seed_binds_all_compared_artifacts() { + let build = QuotientProgramBuild { + bytes: vec![Q_OP_PUSH_CONST_U8, 0], + consts: vec![U256::from(11u64)], + max_stack: 1, + used_ops: vec![Q_OP_PUSH_CONST_U8], + used_mem_tokens: Vec::new(), + }; + let baseline = QuotientProgramBuild { + bytes: vec![Q_OP_PUSH_CONST, 0, 0], + consts: vec![U256::from(13u64)], + max_stack: 1, + used_ops: vec![Q_OP_PUSH_CONST], + used_mem_tokens: Vec::new(), + }; + let expr = QuotientExpr::Add( + Box::new(QuotientExpr::Mem(QuotientMem::Literal(0x120))), + Box::new(QuotientExpr::Const(U256::from(17u64))), + ); + let vk_payload = [0xabu8; 64]; + let seed = super::quotient_numerator::vm::certify::derive_certify_seed( + &[&build, &baseline], + &[&expr], + &vk_payload, + ); + + let mut changed_bytecode = build.clone(); + changed_bytecode.bytes[0] ^= 1; + assert_ne!( + seed, + super::quotient_numerator::vm::certify::derive_certify_seed( + &[&changed_bytecode, &baseline], + &[&expr], + &vk_payload, + ) + ); + + let mut changed_const = build.clone(); + changed_const.consts[0] = U256::from(19u64); + assert_ne!( + seed, + super::quotient_numerator::vm::certify::derive_certify_seed( + &[&changed_const, &baseline], + &[&expr], + &vk_payload, + ) + ); + + let mut changed_baseline = baseline.clone(); + changed_baseline.consts[0] = U256::from(23u64); + assert_ne!( + seed, + super::quotient_numerator::vm::certify::derive_certify_seed( + &[&build, &changed_baseline], + &[&expr], + &vk_payload, + ) + ); + + let changed_expr = QuotientExpr::Add( + Box::new(QuotientExpr::Mem(QuotientMem::Literal(0x120))), + Box::new(QuotientExpr::Const(U256::from(29u64))), + ); + assert_ne!( + seed, + super::quotient_numerator::vm::certify::derive_certify_seed( + &[&build, &baseline], + &[&changed_expr], + &vk_payload, + ) + ); + + let changed_vk_payload = [0xcdu8; 64]; + assert_ne!( + seed, + super::quotient_numerator::vm::certify::derive_certify_seed( + &[&build, &baseline], + &[&expr], + &changed_vk_payload, + ) + ); +} + /// Generate parameters and VK for lowering-plan integration tests. fn lowering_plan_test_vk() -> ( ParamsKZG, diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 1a4f07793..e3e8747ab 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1371,12 +1371,14 @@ fn pinned_quotient_verifier_rejects_wrong_vk_and_quotient_contracts() { /// the circuit, the solc release, and the optimizer schedule -- so assert the /// property against real compiled bytecode rather than assuming it holds. /// -/// `VerifierMemoryLayout::validate()` enforces the complementary bound: every -/// generated region starts at or above `LOW_MEMORY_SCRATCH_START`, so -/// `reserved_end <= LOW_MEMORY_SCRATCH_START` here proves full disjointness. -/// The accumulator-bearing variants are checked too, because their -/// FinalPairing pairing-batch block adds frames and live values the property -/// fixture never renders. +/// `VerifierMemoryLayout::validate()` enforces the complementary bound for the +/// generated layout: every generated region starts at or above +/// `LOW_MEMORY_SCRATCH_START`, so `reserved_end <= LOW_MEMORY_SCRATCH_START` +/// here proves full disjointness. Check both verifier and quotient evaluator +/// runtimes, because each via-IR compilation unit receives its own independent +/// spill reservation. The accumulator-bearing variants are checked too, +/// because their FinalPairing pairing-batch block adds frames and live values +/// the property fixture never renders. #[test] fn compiled_memoryguard_does_not_overlap_generated_layout() { if !poseidon_inputs_available_for_evm() { @@ -1403,12 +1405,24 @@ fn compiled_memoryguard_does_not_overlap_generated_layout() { ("embedded", fixture.embedded_verifier_solidity.as_str()), ("separate", fixture.separate_verifier_solidity.as_str()), ("quotient", fixture.quotient_verifier_solidity.as_str()), + ( + "quotient evaluator", + fixture.quotient_evaluator_solidity.as_str(), + ), + ( + "trace quotient evaluator", + fixture.trace_quotient_evaluator_solidity.as_str(), + ), ] { assert_memoryguard_clears_generated_layout(name, source); } - for (name, _, artifacts) in render_accumulator_verifier_variants() { + for (name, _, artifacts, quotient_evaluator) in render_accumulator_verifier_variants() { assert_memoryguard_clears_generated_layout(name, &artifacts.verifier); + assert_memoryguard_clears_generated_layout( + &format!("{name} quotient evaluator"), + "ient_evaluator, + ); } } @@ -1816,8 +1830,10 @@ fn accumulator_fixed_base_tail_must_match_verifying_key() { /// Render the three accumulator-bearing verifier variants over the Poseidon /// fixture VK: fully collapsed, fixed-base scalar tail, and point-pair -/// encodings. Returns `(name, has_carried_scalars, artifacts)` per variant. -fn render_accumulator_verifier_variants() -> Vec<(&'static str, bool, crate::RenderedArtifacts)> { +/// encodings. Returns `(name, has_carried_scalars, artifacts, evaluator)` per +/// variant. +fn render_accumulator_verifier_variants( +) -> Vec<(&'static str, bool, crate::RenderedArtifacts, String)> { let srs_dir = srs_dir(); env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; @@ -1870,7 +1886,10 @@ fn render_accumulator_verifier_variants() -> Vec<(&'static str, bool, crate::Ren ..RenderOptions::default() }) .unwrap_or_else(|err| panic!("{name} should render: {err}")); - (name, has_carried_scalars, artifacts) + let quotient_evaluator = generator + .render_quotient_evaluator(RenderDiagnostics::default()) + .unwrap_or_else(|err| panic!("{name} quotient evaluator should render: {err}")); + (name, has_carried_scalars, artifacts, quotient_evaluator) }) .collect() } @@ -1896,7 +1915,7 @@ fn accumulator_verifier_variants_compile_with_pinned_solc() { return; } - for (name, has_carried_scalars, artifacts) in render_accumulator_verifier_variants() { + for (name, has_carried_scalars, artifacts, _) in render_accumulator_verifier_variants() { let verifier = artifacts.verifier; assert!( verifier.contains("function validate_public_accumulator"), From ffd39db98e2d305e6f5df272de5fc1ae10782006 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 22:40:23 +0100 Subject: [PATCH 073/108] Run the Solidity verifier test suite in root CI proofs/solidity-verifier/.github/workflows/ci.yml never executed: GitHub Actions only reads workflows from the repository root, and root ci.yaml has a per-package test job for every workspace member except halo2_solidity_verifier. No test in that crate gated any pull request, so the adversarial calldata/VK mutation suite, the non-canonical scalar and G1 rejection tests, the EIP-170 runtime size check, the memoryguard overlap check against compiled bytecode, the layout unit tests, and the native/Solidity trace differentials were all unenforced. Lint was already covered: the root manifest is virtual with no default-members, so cargo fmt --all and cargo clippy --all-targets --all-features already reach the package. Port the three fast jobs into ci.yaml following the existing per-package convention. Split the two IVC jobs out into solidity_verifier_bench.yml on push-to-main, a weekly cron, and workflow_dispatch: each generates a real recursive proof and takes up to ~90 minutes, which is not proportionate for every monorepo PR. That workflow also carries the release bytecode size/hash gate, so a runtime crossing EIP-170 or a published hash drifting from REPRODUCIBLE_BUILDS.md still fails a run, just not a PR run; dispatch it against a branch before merging memory-layout, proof-layout, quotient VM, or template changes. The fast EVM jobs reuse the existing fixed-srs-cache rather than ensure_srs_assets.sh: srs_dir() defaults to zk_stdlib/examples/assets and POSEIDON_K is 6, so poseidon_srs_available()'s bls_filecoin_2p19 fallback is enough. Only the bench workflow needs the full 2p19/2p20/2p22 fetch. Delete the crate-local workflow so it stops implying coverage it never provided. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yaml | 119 ++++++++++++++ .github/workflows/solidity_verifier_bench.yml | 110 +++++++++++++ .../.github/workflows/ci.yml | 153 ------------------ 3 files changed, 229 insertions(+), 153 deletions(-) create mode 100644 .github/workflows/solidity_verifier_bench.yml delete mode 100644 proofs/solidity-verifier/.github/workflows/ci.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 01e3707db..24d2d12f4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -151,6 +151,125 @@ jobs: package: midnight-zkir args: --release --all-features + # --------------------------------------------------------------------- + # Solidity verifier generator (halo2_solidity_verifier). + # + # These three jobs are the per-PR gate. The heavy IVC proof benches and + # the release bytecode size/hash checks live in + # `.github/workflows/solidity_verifier_bench.yml`, which runs on pushes to + # `main`, on a weekly schedule, and on demand. + # + # Every job needs the pinned solc from + # `proofs/solidity-verifier/scripts/install_pinned_solc.sh`; the EVM jobs + # additionally need the Filecoin SRS that the rest of this workflow already + # caches at `zk_stdlib/examples/assets/bls_filecoin_2p19`, which is where + # the crate's `srs_dir()` looks by default. + # --------------------------------------------------------------------- + test-solidity-verifier: + if: github.event.pull_request.draft == false + name: Test Solidity verifier + runs-on: ubuntu-latest + + env: + SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + # Codegen/layout tests compile Solidity; the heavy proof/EVM cases + # self-skip because HALO2_SOLIDITY_RUN_EVM_TESTS is unset here. + - name: Install pinned solc + run: | + echo "SOLC=$(proofs/solidity-verifier/scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" + + - uses: ./.github/actions/cargo-test + with: + package: halo2_solidity_verifier + args: --all-features --all-targets -- --nocapture + + test-solidity-verifier-evm: + if: github.event.pull_request.draft == false + needs: download-srs + name: Test Solidity verifier real EVM + runs-on: ubuntu-latest + + env: + SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc + HALO2_SOLIDITY_RUN_EVM_TESTS: 1 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Restore SRS from cache + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: zk_stdlib/examples/assets/bls_filecoin_2p19 + key: fixed-srs-cache + + - name: Install pinned solc + run: | + echo "SOLC=$(proofs/solidity-verifier/scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" + + - name: 'Install rust-toolchain.toml' + run: rustup toolchain install + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + shared-key: "ci" + + # Adversarial property tests: proof/VK/calldata mutations, non-canonical + # scalar and G1 rejection, EIP-170 runtime size, and the memoryguard + # overlap check against real compiled bytecode. + - name: Real EVM property tests + run: cargo test -p halo2_solidity_verifier --release --all-features pbt_ -- --nocapture + + # End-to-end: real proof -> render -> solc -> Prague revm verification. + - name: Poseidon fixture + run: | + cargo test -p halo2_solidity_verifier --release \ + --features evm,truncated-challenges --test poseidon_fixture -- --nocapture + + test-solidity-verifier-trace: + if: github.event.pull_request.draft == false + needs: download-srs + name: Test Solidity verifier trace equivalence + runs-on: ubuntu-latest + + env: + SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc + HALO2_SOLIDITY_RUN_EVM_TESTS: 1 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Restore SRS from cache + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: zk_stdlib/examples/assets/bls_filecoin_2p19 + key: fixed-srs-cache + + - name: Install pinned solc + run: | + echo "SOLC=$(proofs/solidity-verifier/scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" + + - name: 'Install rust-toolchain.toml' + run: rustup toolchain install + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + shared-key: "ci" + + # Per-identity differential between the native Midfall verifier and the + # generated Solidity verifier. This is the only check that compares + # quotient VM semantics against the Rust verifier end to end. + - name: Poseidon native/Solidity trace equivalence + run: | + cargo test -p halo2_solidity_verifier --release \ + --features evm,truncated-challenges,rust-verifier-trace,solidity-trace \ + --lib native_midfall_verifier_trace_matches_solidity_trace -- --nocapture + doc-links: if: github.event.pull_request.draft == false name: Intra-doc links diff --git a/.github/workflows/solidity_verifier_bench.yml b/.github/workflows/solidity_verifier_bench.yml new file mode 100644 index 000000000..4194a340b --- /dev/null +++ b/.github/workflows/solidity_verifier_bench.yml @@ -0,0 +1,110 @@ +name: Solidity verifier IVC bench + +# The two IVC jobs below each generate a real recursive proof and take up to +# ~90 minutes, so they are deliberately not part of the per-PR gate in +# `ci.yaml`. The fast Solidity verifier jobs (codegen/layout tests, real EVM +# property tests, Poseidon fixture, Poseidon trace equivalence) run there on +# every pull request. +# +# Run these here on pushes to `main`, weekly, and on demand. Trigger a run +# against a branch from the Actions tab (`workflow_dispatch`) before merging a +# change to memory layout, proof layout, the quotient VM, or the templates. +on: + push: + branches: + - main + schedule: + # Mondays 04:00 UTC. + - cron: "0 4 * * 1" + workflow_dispatch: + +jobs: + full-ivc-bench: + name: Full IVC bench and release bytecode sizes + runs-on: ubuntu-latest + timeout-minutes: 90 + + env: + SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc + SRS_DIR: ${{ github.workspace }}/.srs + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + # `ensure_srs_assets.sh` fetches bls_filecoin_2p19 plus the + # midnight-srs 2p19/2p20/2p22 powers the decider proof needs. + - name: Cache SRS assets + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: .srs + key: srs-solidity-verifier-ivc-v1 + + - name: Install pinned solc + run: | + echo "SOLC=$(proofs/solidity-verifier/scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" + + - name: 'Install rust-toolchain.toml' + run: rustup toolchain install + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + shared-key: "ci" + + - name: Ensure SRS assets + run: proofs/solidity-verifier/scripts/ensure_srs_assets.sh + + - name: Full IVC bench + run: proofs/solidity-verifier/scripts/run_ivc_bench.sh --skip-srs-download + + # Fails the run when a generated runtime crosses EIP-170 or when the + # published verifier/VK/quotient runtime hashes drift from the values + # recorded in docs/reference/REPRODUCIBLE_BUILDS.md. + - name: Release bytecode size/hash checks + run: proofs/solidity-verifier/scripts/check_release_bytecode_sizes.sh + + - name: Upload IVC artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + if: always() + with: + name: ivc-keccak-solidity-dump + path: proofs/solidity-verifier/target/ivc-keccak-solidity-dump + + ivc-trace-equivalence: + name: IVC native/Solidity trace equivalence + runs-on: ubuntu-latest + timeout-minutes: 90 + + env: + SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc + SRS_DIR: ${{ github.workspace }}/.srs + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Cache SRS assets + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: .srs + key: srs-solidity-verifier-ivc-v1 + + - name: Install pinned solc + run: | + echo "SOLC=$(proofs/solidity-verifier/scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" + + - name: 'Install rust-toolchain.toml' + run: rustup toolchain install + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + shared-key: "ci" + + - name: Ensure SRS assets + run: proofs/solidity-verifier/scripts/ensure_srs_assets.sh + + # Compares the native Midfall verifier trace against the generated + # Solidity trace on the IVC decider proof, including quotient identity + # trace ids from the pinned external Halo2QuotientEvaluator. + - name: IVC trace equivalence + run: proofs/solidity-verifier/scripts/run_ivc_bench.sh --trace --skip-srs-download diff --git a/proofs/solidity-verifier/.github/workflows/ci.yml b/proofs/solidity-verifier/.github/workflows/ci.yml deleted file mode 100644 index a41ec7a69..000000000 --- a/proofs/solidity-verifier/.github/workflows/ci.yml +++ /dev/null @@ -1,153 +0,0 @@ -name: CI - -on: - pull_request: - push: - branches: - - main - - "codex/**" - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - SOLC_INSTALL_DIR: ${{ github.workspace }}/.solc - SRS_DIR: ${{ github.workspace }}/.srs - -jobs: - default-rust-tests: - name: default Rust tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Install pinned solc - run: | - echo "SOLC=$(scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" - - run: cargo test --workspace --all-features --all-targets -- --nocapture - - real-evm-pbt-and-poseidon: - name: real EVM, PBT, Poseidon fixture - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Cache SRS assets - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 - with: - path: .srs - key: srs-poseidon-ivc-v1 - - name: Install pinned solc - run: | - echo "SOLC=$(scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" - - name: Ensure SRS assets - run: scripts/ensure_srs_assets.sh - - name: Real EVM PBT - run: | - HALO2_SOLIDITY_RUN_EVM_TESTS=1 \ - cargo test --release --all-features pbt_ -- --nocapture - - name: Poseidon fixture - run: | - HALO2_SOLIDITY_RUN_EVM_TESTS=1 \ - cargo test --release --features evm,truncated-challenges --test poseidon_fixture -- --nocapture - - poseidon-trace-equivalence: - name: Poseidon native/Solidity trace equivalence - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Cache SRS assets - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 - with: - path: .srs - key: srs-poseidon-ivc-v1 - - name: Install pinned solc - run: | - echo "SOLC=$(scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" - - name: Ensure SRS assets - run: scripts/ensure_srs_assets.sh - - name: Poseidon trace equivalence - run: | - HALO2_SOLIDITY_RUN_EVM_TESTS=1 \ - cargo test --release \ - --features evm,truncated-challenges,rust-verifier-trace,solidity-trace \ - --lib native_midfall_verifier_trace_matches_solidity_trace \ - -- --nocapture - - full-ivc-bench: - name: full IVC bench and release bytecode sizes - runs-on: ubuntu-latest - timeout-minutes: 90 - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Cache SRS assets - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 - with: - path: .srs - key: srs-poseidon-ivc-v1 - - name: Install pinned solc - run: | - echo "SOLC=$(scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" - - name: Ensure SRS assets - run: scripts/ensure_srs_assets.sh - - name: Full IVC bench - run: scripts/run_ivc_bench.sh --skip-srs-download - - name: Release bytecode size/hash checks - run: scripts/check_release_bytecode_sizes.sh - - name: Upload IVC artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 - if: always() - with: - name: ivc-keccak-solidity-dump - path: target/ivc-keccak-solidity-dump - - ivc-trace-equivalence: - name: IVC native/Solidity trace equivalence - runs-on: ubuntu-latest - timeout-minutes: 90 - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Cache SRS assets - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 - with: - path: .srs - key: srs-poseidon-ivc-v1 - - name: Install pinned solc - run: | - echo "SOLC=$(scripts/install_pinned_solc.sh "$SOLC_INSTALL_DIR" | tail -1)" >> "$GITHUB_ENV" - - name: Ensure SRS assets - run: scripts/ensure_srs_assets.sh - - name: IVC trace equivalence - run: scripts/run_ivc_bench.sh --trace --skip-srs-download - - lint: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: 1.90.0 - components: rustfmt, clippy - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 - - name: Rust format - run: cargo fmt --all -- --check - - name: Clippy - run: cargo clippy --workspace --all-features --all-targets -- -D warnings From 277c0962264b05a744c8957bb0b35c973abc0c3a Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 22:40:38 +0100 Subject: [PATCH 074/108] Refresh the lowering architecture spec's stale references The spec named four files that no longer exist (generator.rs, evaluator.rs, src/lowering/quotient/, template.rs), linked CODEGEN_ASSURANCE_DOSSIER.md from the wrong directory, and gave a test command for a nonexistent target alongside an absolute path into a local Moonlight checkout. This is the document reviewers navigate the codebase by, so stale paths cost review time and undercut confidence in the claims the spec does make. Point every reference at the module that actually owns the concern: convergence to lowering/vk.rs and lowering/plan.rs, the quotient system to its real three-module split (quotient.rs plans, vm/mod.rs produces, yul_emit.rs emits inline Yul), and new scratch memory to render/models.rs. Fill in the module table with plan.rs, config.rs, diagnostics.rs, evm.rs, vm/certify.rs, vm/reference.rs, and fuzz/. Replace the commands with repo-root ones and state which CI jobs now gate a pull request. Add 12.1 for the render-time bytecode certification, which the spec did not mention at all despite being the main correctness argument for the quotient lowering, and state its scope limit explicitly: emitter to reference interpreter is proven per render, reference interpreter to Yul is not covered per opcode. Record the matching limit for the memory planner in 20: the overlap checker proves registered regions do not conflict, not that emitted Yul stays inside them. Every backticked repo path and markdown link in the file now resolves. Co-Authored-By: Claude Opus 5 --- .../LOWERING_ARCHITECTURE_SPEC.md | 176 ++++++++++++++---- 1 file changed, 135 insertions(+), 41 deletions(-) diff --git a/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md b/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md index 2b1fea580..ff760b3cd 100644 --- a/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md +++ b/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md @@ -21,7 +21,7 @@ templates, and provides helper APIs to repack native Halo2 proof bytes into the generated verifier ABI. For the audit-facing correctness and security argument, use -[`CODEGEN_ASSURANCE_DOSSIER.md`](./CODEGEN_ASSURANCE_DOSSIER.md). This +[`CODEGEN_ASSURANCE_DOSSIER.md`](../audit/CODEGEN_ASSURANCE_DOSSIER.md). This architecture document explains how the system is built; the dossier states the bounded claim, artifact manifest, threat model, and required evidence gates. @@ -63,22 +63,30 @@ pipeline. | --- | --- | | `src/lib.rs` | Public exports, feature flags, calldata helpers, EVM helpers. | | `src/api.rs` | Public configuration and diagnostic types, supported-shape errors, accumulator encoding metadata. | +| `src/evm.rs` | `verifyProof` calldata encoding, plus pinned-solc compilation and the `revm` harness behind the `evm` feature. | | `src/builder/` | Thin `SolidityGenerator` facade, constructor validation, public render/calldata/diagnostic wrappers. | +| `src/lowering/plan.rs` | `LoweringPlan`: the converged, reusable fact set every render/repack path is built from, plus post-convergence invariant checks. | | `src/lowering/artifacts.rs` | Verifier, VK, and quotient evaluator artifact assembly. | | `src/lowering/vk.rs` | Metadata convergence, VK payload generation, and static memory layout entrypoints. | | `src/lowering/calldata.rs` | Proof repacking and Solidity calldata encoding plan. | -| `src/lowering/quotient.rs` | Quotient identity planning, selector folds, and generated quotient blocks. | +| `src/lowering/config.rs` | Constants pinning the single generated verifier shape (VM prefix size, native callbacks, structured trash suffix, limb opcodes). | +| `src/lowering/diagnostics.rs` | Host-side diagnostics (evaluation counts, quotient identity manifest) derived from the same plan used for rendering. | +| `src/lowering/quotient.rs` | Quotient identity planning, selector folds, native callback selection, and generated quotient blocks. | | `src/lowering/protocol/` | Typed protocol plan derived from the verifying key. | | `src/lowering/abi/` | Static proof calldata and transcript-buffer layout. | | `src/lowering/render/` | Askama template data models and Yul formatting boundary. | | `src/lowering/layout/` | Static Yul memory planner, VK payload layout, numeric layout facts, and overlap validation. | | `src/lowering/kzg/` | KZG multi-open verifier emitter and pairing-input construction. | -| `src/lowering/quotient_numerator/yul_emit.rs` | Batched identity numerator reconstruction emitter. | -| `src/lowering/quotient_numerator/vm/` | Compact quotient numerator VM compiler and metadata. | +| `src/lowering/quotient_numerator/yul_emit.rs` | Batched identity numerator reconstruction emitter (inline Yul, not the VM). | +| `src/lowering/quotient_numerator/vm/mod.rs` | Compact quotient numerator VM compiler, opcode table, packed codec, and the physical-program validators. | +| `src/lowering/quotient_numerator/vm/reference.rs` | Independent interpreter for finalized VM bytecode, used only by certification. | +| `src/lowering/quotient_numerator/vm/certify.rs` | Render-time certification of emitted VM bytecode against the identity expressions it was lowered from. | | `src/lowering/encoding/` | Pointer, word, field, curve, calldata, and Yul formatting helpers. | | `templates/contracts/` | Generated Solidity contract templates consumed by Askama. | | `templates/partials/` | Shared Solidity/Yul fragments included by contract templates. | -| `tests/` | End-to-end rendering, EVM, trace, gas, and compatibility tests. | +| `tests/` | End-to-end fixture, EVM, trace, and compatibility integration tests. | +| `src/test.rs`, `src/lowering/tests.rs` | Gated Solidity/EVM verifier tests and codegen/layout unit tests. | +| `fuzz/` | `cargo-fuzz` targets for proof repacking and Solidity calldata. | | `docs/` | Grouped architecture, audit, benchmark, plan, and reference material. | The public API deliberately hides most of the planning machinery. Users usually @@ -337,18 +345,38 @@ Several generated sizes depend on earlier generated artifacts: - PCS dummy query count depends on protocol metadata and feature flags. - Template scratch requirements depend on finalized memory addresses. -`generator.rs` handles these dependencies with bounded convergence loops. It -builds provisional metadata, derives sizes, rebuilds with the new sizes, and -checks that the stable static layout has converged. If section sizes do not -settle within the allowed iteration count, generation fails instead of emitting -ambiguous bytecode. +`src/lowering/vk.rs` handles these dependencies with bounded convergence loops. +`generate_vk` reserves zero-filled quotient sections, recompiles against the +resulting layout, and repeats until the reserved sizes cover the compiled +program; `meta_data_for_stable_static_layout` iterates the VK memory base until +it matches the requirements derived from the resulting metadata. Both fail +loudly if they do not settle within the allowed iteration count, rather than +emitting ambiguous bytecode. + +`src/lowering/plan.rs` consumes the converged result. `LoweringPlan::new` +assembles it into one value and then re-checks the cross-module invariants that +convergence is supposed to establish: protocol/meta agreement, memory-region +non-overlap, absorbed-G1 precompile coverage, PCS memory requirements, and a +word-for-word comparison between the quotient constants and bytecode embedded in +the VK payload and the tables rebuilt from the plan. Rendering, diagnostics, and +proof repacking all read this same plan, so no call site can independently +re-derive a slice of the verifier shape. ## 12. Quotient Numerator Codegen -The quotient system in `src/lowering/quotient/` compiles Halo2 quotient numerator -logic into a compact VM representation. +The quotient system compiles Halo2 quotient numerator logic into a compact VM +representation. It is split across three modules: -The compiler: +- `src/lowering/quotient.rs` plans the identity stream for the concrete + verifying key: identity order, selector folds, which identities become native + Yul callbacks, and the execution manifest. +- `src/lowering/quotient_numerator/vm/mod.rs` is the producer. It lowers planned + identities into a compact byte-oriented program plus a constant table. +- `src/lowering/quotient_numerator/yul_emit.rs` is the inline Yul emitter for + the identities that are not lowered to bytecode, and for linearization-related + scalar preparation. + +The compiler in `vm/mod.rs`: - Lowers gate, permutation, lookup, and trash identities. - Assigns constants. @@ -358,20 +386,61 @@ The compiler: - Tracks memory tokens and native callback requirements. - Preserves the identity stream order expected by Midfall. -At runtime, the Yul quotient VM reconstructs the batched identity numerator. +At runtime, the Yul quotient VM in +`templates/partials/quotient_numerator/QuotientNumeratorBlock.yul` reconstructs +the batched identity numerator. It is the only consumer of the emitted bytecode, +so the opcode set, operand widths, and memory-token map are an ABI between the +VK payload and that template rather than an implementation detail. Opcode and +token numbers reach the template through `template_constants.quotient_vm`, so +both sides read one Rust definition. + The emitted verifier stores the negative numerator value as the expected opening scalar, while the commitment side carries the `(1 - x^n)` factor. -The codebase uses two related but distinct pieces: - -- `quotient/`: compiler for compact numerator programs. -- `evaluator.rs`: Yul emitter for batched identity numerator reconstruction and - linearization-related scalar preparation. - The quotient evaluator is not an arbitrary Solidity subroutine. It is tied to a specific proof layout, VK layout, transcript schedule, and quotient program artifact. +### 12.1 Emitted-Bytecode Certification + +The lowering runs a peephole optimizer: shape recognizers rewrite seven-limb +foreign-field expressions into superinstructions, and a run-compaction pass +rewrites adjacent affine terms into counted opcodes. Both are pure encoding +choices that must preserve the evaluated polynomial exactly. + +Rather than trusting them, the generator proves it for the specific program each +render is about to emit. Before any artifact is produced: + +1. `validate_quotient_program` proves the byte stream decodes, that every memory + token is known, and that the expression stack is balanced; it returns the + maximum stack depth the memory planner then reserves. +2. `validate_quotient_const_slots` bounds-checks every constant-table index + against the emitted table, so a planner regression cannot make the deployed + verifier load a trailing VK word as a gate coefficient. +3. `certify::certify_quotient_program` executes the finalized bytecode with the + independent interpreter in `vm/reference.rs` at a deterministic assignment + derived from the artifact itself, and compares each identity against direct + evaluation of the `QuotientExpr` tree it was lowered from. +4. `certify::certify_quotient_builds_agree` rebuilds the same identity stream + with the limb superinstructions disabled — yielding a program of only + `PUSH`/`ADD`/`MUL`/`NEG` — and requires the two builds to agree + identity-by-identity. This turns every shape recognizer from trusted code + into a checked optimization. + +This is a generator-time gate, not a test. A recognizer bug on a previously +unseen gate shape fails the render instead of shipping a wrong verifier. + +Scope, stated precisely because it bounds what the gate proves: certification +covers the **emitter to reference-interpreter** leg. The +**reference-interpreter to Yul** leg is covered by the opcode/token table +conformance test in `src/lowering/tests.rs` — which checks that the template has +a `case` for every opcode, not that the case body is correct — and by the +per-identity native/Solidity trace differentials on fixture circuits. An opcode +that no fixture circuit emits therefore has unverified runtime semantics. +Identities executed as inline Yul, native callbacks, or the structured tail are +not lowered to bytecode at all and are covered only by those trace +differentials. + ## 13. PCS Codegen `src/lowering/kzg/mod.rs` emits the KZG multi-open verifier logic. It mirrors the @@ -510,28 +579,39 @@ The repository tests the generator through several layers: - Gas checkpoint builds for section-level profiling. - IVC and Moonlight integration benches for realistic proof shapes. -Representative local commands: +Which of these run automatically is part of the design, not an afterthought. +`.github/workflows/ci.yaml` gates every pull request on three jobs: +`test-solidity-verifier` (codegen, layout, and template invariants, with the +heavy proof/EVM cases self-skipping), `test-solidity-verifier-evm` (adversarial +property tests plus the Poseidon end-to-end fixture), and +`test-solidity-verifier-trace` (Poseidon native/Solidity trace equivalence). +The two IVC proof benches and the release bytecode size/hash gate are too slow +for a per-PR job and live in `.github/workflows/solidity_verifier_bench.yml`, +which runs on pushes to `main`, weekly, and on demand. Trigger that workflow +against a branch before merging changes to memory layout, proof layout, the +quotient VM, or the templates. + +Representative local commands, run from the Midfall repository root: ```bash -cargo test --lib +cargo test -p halo2_solidity_verifier --all-features --all-targets -- --nocapture ``` ```bash -cargo test --features evm --test codegen +HALO2_SOLIDITY_RUN_EVM_TESTS=1 \ +SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ +cargo test -p halo2_solidity_verifier --release --all-features pbt_ -- --nocapture ``` ```bash -MOONLIGHT_RUN_WRAP_SOLIDITY_BENCH=1 \ -cargo test --manifest-path /Users/Julien.Coolen/Moonlight/aggregation/Cargo.toml \ - wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs --release \ - --lib -- --ignored --nocapture +SRS_DIR=/path/to/midfall/zk_stdlib/examples/assets \ +proofs/solidity-verifier/scripts/run_ivc_bench.sh ``` -The Moonlight command runs from this repository's Solidity verifier integration -when Moonlight has a local path dependency pointing back to this checkout. It -generates Moonlight wrap proof material, repacks it for the Solidity verifier, -deploys the generated verifier path, and checks the proof on-chain in the local -EVM harness. +Solidity-touching tests require `solc 0.8.30+commit.73712a01` on `PATH` or via +`SOLC`; `scripts/install_pinned_solc.sh` fetches it. The full command inventory, +including the Moonlight wrap-recursion bench against a sibling Moonlight +checkout, is in the [README](../../README.md). ## 20. Extension Guidelines @@ -557,12 +637,24 @@ For a new VK section: For new Yul scratch memory: -1. Add a named range to `VerifierMemoryLayout`. -2. Assign the correct `MemoryPhase`. +1. Add a named range to `VerifierMemoryLayout` in + `src/lowering/layout/memory.rs`. +2. Assign the correct `MemoryPhase`, keeping the enum in runtime order — its + derived `Ord` is what makes `MemoryLifetime::intersects` answer the right + question. 3. Let the overlap checker validate reuse. -4. Thread the address through `template.rs`. +4. Thread the address through the Askama models in + `src/lowering/render/models.rs`. 5. Avoid hard-coded addresses in templates. +Note the limit of step 3: `MemoryMap::validate` proves that *registered* regions +do not conflict when live. It cannot prove that the emitted Yul only touches +registered regions. Ranges that intentionally spill outside the region model — +notably the Lagrange batch-inversion input run, which is capacity-checked in +`VerifierMemoryLayout::validate` instead — carry an explicit `INVARIANT` comment +naming the test that pins the assumption. Add new scratch as a registered region +unless there is a documented reason it cannot be one. + For quotient VM changes: 1. Extend the opcode, token, or constant model in Rust. @@ -602,9 +694,11 @@ proof order, memory addresses, transcript absorbs, or public input packing. This specification is the architectural overview. More focused details live in: -- `docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md` -- `docs/architecture/MEMORY_LAYOUT.md` -- `docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md` -- `docs/reference/QUOTIENT_NUMERATOR_EVALUATOR.md` -- `docs/reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md` -- `docs/reference/TEAM_DEMO_SETUP.md` +- [`HALO2_MIDNIGHT_VERIFIER_SPEC.md`](../reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md) +- [`MEMORY_LAYOUT.md`](./MEMORY_LAYOUT.md) +- [`ASKAMA_TEMPLATE_RUST_MAPPING.md`](../reference/ASKAMA_TEMPLATE_RUST_MAPPING.md) +- [`QUOTIENT_NUMERATOR_EVALUATOR.md`](../reference/QUOTIENT_NUMERATOR_EVALUATOR.md) +- [`QUOTIENT_EVALUATOR_9KB_BYTECODE.md`](../reference/QUOTIENT_EVALUATOR_9KB_BYTECODE.md) +- [`TEAM_DEMO_SETUP.md`](../reference/TEAM_DEMO_SETUP.md) +- [`CODEGEN_ASSURANCE_DOSSIER.md`](../audit/CODEGEN_ASSURANCE_DOSSIER.md) +- [`REPRODUCIBLE_BUILDS.md`](../reference/REPRODUCIBLE_BUILDS.md) From 20766cb796269e5c4980bd0a9938b8f6c42d248a Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 23:01:43 +0100 Subject: [PATCH 075/108] Bounds-check the quotient VM's emitted memory pointers validate_quotient_const_slots covers constant-table indices; the other half of the operand space was unchecked. The pointers baked into the emitted bytecode are absolute generated addresses, so an emitter or planner regression that computes one incorrectly makes the deployed verifier load a live challenge, a commitment word, or uninitialized scratch as a gate value -- silently flipping accept/reject rather than reverting. Render-time certification does not cover this. It compares the bytecode against the QuotientExpr tree it was lowered from, and QuotientRefMemory derives a value from whatever address it is handed, so a pointer that disagrees between the two surfaces as a value mismatch. A pointer that is already wrong *in the tree* -- a Data or planner bug upstream of the VM -- makes both sides agree on the wrong address and certifies cleanly. Add validate_quotient_mem_ptrs, checking every literal, u16, token, limb and pairwise-span address against the windows this layout actually populates before the VM runs: the VK payload, the user-challenge block, the theta-rooted challenge/common slots, and the decoded proof evaluations. Those are the same ranges Halo2QuotientEvaluator:: validate_layout already requires the copied external frame to contain, so a read outside them is uninitialized memory in the split path and live verifier state in the inline path. Run it from LoweringPlan::validate_generator_invariants, where the converged memory layout is available. The walker's fallback arm is an error rather than a no-op, so a new opcode with pointer operands that forgets to extend it fails the render instead of silently losing its bounds check; quotient_pointer_walker_covers_every_opcode pins that the walker is total over QUOTIENT_OPCODE_TABLE. The negative test corrupts a real LIN7 limb pointer to an address in low-memory scratch and checks that validate_quotient_program and validate_quotient_const_slots both still pass on those bytes, so the new coverage is not redundant with theirs. Co-Authored-By: Claude Opus 5 --- proofs/solidity-verifier/src/lowering/plan.rs | 64 +++- .../src/lowering/quotient_numerator/vm/mod.rs | 300 ++++++++++++++++++ .../solidity-verifier/src/lowering/tests.rs | 105 ++++++ 3 files changed, 468 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index 6e001d3e6..58ff79a7e 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -13,7 +13,7 @@ use crate::lowering::{ layout::memory::{PcsMemoryRequirements, VerifierMemoryLayout, VerifierMemoryLayoutConfig}, quotient::{QuotientComputationBlocks, QuotientHelperFlags, QuotientStateSlots}, quotient_numerator::vm::{ - certify, QuotientProgramBuild, QuotientProgramPlan, RepackedProofLayoutPlan, + self as vm, certify, QuotientProgramBuild, QuotientProgramPlan, RepackedProofLayoutPlan, }, render::{Halo2VerifyingKey, QuotientExternal, QuotientProgram}, VerifierBuildInputs, @@ -339,6 +339,13 @@ impl LoweringPlan { self.quotient.program.eval_numer_mptr, self.quotient.state_slots.eval_numer_mptr )); } + // Bounds-check every address the emitted bytecode loads from against + // the windows this layout actually populates before the VM runs. + // Certification cannot do this: it compares the bytecode against the + // expression tree, so a pointer that is wrong in both agrees with + // itself. + vm::validate_quotient_mem_ptrs(&self.quotient.build.bytes, &self.quotient_read_model()) + .map_err(|err| format!("quotient memory pointer validation failed: {err}"))?; // Prove the emitted bytecode still evaluates the identities it was // lowered from, before it can be pinned into a verifying key. certify::certify_quotient_program(&self.quotient.plan, &self.quotient.build, &self.vk) @@ -346,6 +353,61 @@ impl LoweringPlan { Ok(()) } + /// Addresses the compact quotient VM is allowed to load from. + /// + /// These are exactly the ranges the verifier has populated by the time the + /// VM runs, and they are the same ranges + /// `Halo2QuotientEvaluator::validate_layout` requires the external frame to + /// contain -- a read outside them is either uninitialized memory in the + /// split path or live verifier state in the inline path. + pub(crate) fn quotient_read_model(&self) -> vm::QuotientReadModel { + let theta = self.data.theta_mptr.value().as_usize(); + let instance_eval = self.memory.instance_eval_mptr.value().as_usize(); + vm::QuotientReadModel { + windows: vec![ + vm::QuotientReadWindow { + name: "vk_payload", + start: self.vk_mptr.value().as_usize(), + len: self.vk.len(), + }, + vm::QuotientReadWindow { + name: "user_challenges", + start: self.data.challenge_mptr.value().as_usize(), + len: self.meta.num_user_challenges.iter().sum::() + * layout::memory::WORD_BYTES, + }, + vm::QuotientReadWindow { + name: "challenge_and_common_slots", + // Ends one word past `instance_eval`, matching the frame + // window in `Halo2QuotientEvaluator::validate_layout`. + // `quotient_eval` sits immediately above and is a write + // target, not a VM input. + start: theta, + len: (instance_eval + layout::memory::WORD_BYTES).saturating_sub(theta), + }, + vm::QuotientReadWindow { + name: "decoded_proof_evals", + start: self.memory.reversed_evals_mptr.value().as_usize(), + len: self.meta.num_evals * layout::memory::WORD_BYTES, + }, + ], + token_bases: vec![ + (vm::Q_MEM_L0, self.memory.l_0_mptr.value().as_usize()), + (vm::Q_MEM_L_LAST, self.memory.l_last_mptr.value().as_usize()), + (vm::Q_MEM_L_BLIND, self.memory.l_blind_mptr.value().as_usize()), + (vm::Q_MEM_BETA, self.memory.beta_mptr.value().as_usize()), + (vm::Q_MEM_GAMMA, self.memory.gamma_mptr.value().as_usize()), + (vm::Q_MEM_X, self.memory.x_mptr.value().as_usize()), + (vm::Q_MEM_THETA, self.memory.theta_mptr.value().as_usize()), + ( + vm::Q_MEM_TRASH_CHALLENGE, + self.memory.trash_challenge_mptr.value().as_usize(), + ), + (vm::Q_MEM_INSTANCE_EVAL, instance_eval), + ], + } + } + /// Number of `(G1, scalar)` terms required by the optional accumulator MSM. fn acc_msm_terms(inputs: &VerifierBuildInputs<'_, '_>) -> usize { inputs diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 67a17b82f..c8dadde70 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2195,6 +2195,306 @@ pub(crate) fn validate_quotient_const_slots(bytes: &[u8], const_len: usize) -> R Ok(()) } +/// One byte range the compact quotient VM is allowed to load from. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) struct QuotientReadWindow { + /// Stable name used in validation errors. + pub(crate) name: &'static str, + /// Start byte offset in verifier memory. + pub(crate) start: usize, + /// Length in bytes. Zero-length windows never accept a pointer. + pub(crate) len: usize, +} + +impl QuotientReadWindow { + /// Whether a full 32-byte `mload` at `ptr` stays inside this window. + fn contains_word(&self, ptr: usize) -> bool { + self.len != 0 + && ptr >= self.start + && ptr.saturating_add(WORD_BYTES) <= self.start.saturating_add(self.len) + } +} + +/// Legal read set for one finalized quotient program. +/// +/// Built from the converged memory layout, so it describes the addresses this +/// concrete verifier actually populates before the VM runs. +#[derive(Clone, Debug, Default)] +pub(crate) struct QuotientReadModel { + /// Ranges the VM may load from. + pub(crate) windows: Vec, + /// Resolved base address for each symbolic memory token. + pub(crate) token_bases: Vec<(u8, usize)>, +} + +impl QuotientReadModel { + /// Resolve a symbolic memory token to its generated base address. + fn token_base(&self, token: u8) -> Option { + self.token_bases + .iter() + .find_map(|(candidate, base)| (*candidate == token).then_some(*base)) + } + + /// Name the window covering a word-sized load, if any. + fn window_for(&self, ptr: usize) -> Option<&'static str> { + self.windows.iter().find(|window| window.contains_word(ptr)).map(|window| window.name) + } +} + +/// Bounds-check every memory pointer a finalized program loads from. +/// +/// `validate_quotient_const_slots` covers constant-table indices; this covers +/// the other half of the operand space. The pointers baked into the bytecode are +/// absolute generated addresses, so an emitter or planner regression that +/// computes one incorrectly makes the deployed verifier read a live challenge, +/// commitment word, or uninitialized scratch as a gate value -- silently +/// flipping accept/reject rather than reverting. +/// +/// Note what the render-time certification in [`super::certify`] does *not* +/// cover here. It compares the bytecode against the `QuotientExpr` tree it was +/// lowered from, and [`super::reference::QuotientRefMemory`] derives a value +/// from whatever address it is handed, so a pointer that disagrees between the +/// two shows up as a value mismatch. A pointer that is already wrong *in the +/// tree* -- a `Data` or planner bug upstream of the VM -- makes both sides agree +/// on the wrong address and certifies cleanly. This check is what catches that +/// class. +/// +/// Run after [`validate_quotient_program`], whose byte-length validation +/// guarantees the operand layout walked here is in bounds. +pub(crate) fn validate_quotient_mem_ptrs( + bytes: &[u8], + model: &QuotientReadModel, +) -> Result<(), String> { + for (idx, op, _len) in quotient_bytecode_ops(bytes) { + let mut check = |kind: &str, ptr: usize| -> Result<(), String> { + if !ptr.is_multiple_of(WORD_BYTES) { + return Err(format!( + "quotient VM {kind} pointer {ptr:#x} at byte {idx} is not 32-byte aligned" + )); + } + if model.window_for(ptr).is_none() { + return Err(format!( + "quotient VM {kind} pointer {ptr:#x} at byte {idx} is outside every window \ + the verifier populates before the quotient VM runs ({})", + describe_read_windows(model) + )); + } + Ok(()) + }; + quotient_read_pointers(bytes, idx, op, model, &mut check)?; + } + + Ok(()) +} + +/// Render the legal read set for a validation error message. +fn describe_read_windows(model: &QuotientReadModel) -> String { + model + .windows + .iter() + .map(|window| { + format!( + "{}=[{:#x}..{:#x})", + window.name, + window.start, + window.start + window.len + ) + }) + .collect::>() + .join(", ") +} + +/// Visit every memory address one instruction loads from. +/// +/// Unlike [`validate_quotient_const_slots`], the fallback arm is an error rather +/// than a no-op: a new opcode with pointer operands that forgets to extend this +/// walker fails the render instead of silently losing its bounds check. +/// `quotient_pointer_walker_covers_every_opcode` pins that the walker is total +/// over `QUOTIENT_OPCODE_TABLE`. +pub(crate) fn quotient_read_pointers( + bytes: &[u8], + idx: usize, + op: u8, + model: &QuotientReadModel, + check: &mut impl FnMut(&str, usize) -> Result<(), String>, +) -> Result<(), String> { + let u16_at = |offset: usize| read_u16(bytes, offset) as usize; + let u32_at = |offset: usize| { + u32::from_be_bytes([ + bytes[offset], + bytes[offset + 1], + bytes[offset + 2], + bytes[offset + 3], + ]) as usize + }; + // `const_slot, u16 ptr` -- the LIN7 limb operand and the MODARITH7 mem term. + let limb_terms = |base: usize, check: &mut dyn FnMut(&str, usize) -> Result<(), String>| { + for k in 0..QUOTIENT_VM_LIMBS { + check("limb", u16_at(base + k * (1 + QUOTIENT_VM_BYTE_U16_BYTES) + 1))?; + } + Ok::<(), String>(()) + }; + // Both pairwise bases are indexed `base + i * 0x20` for seven limbs, so the + // whole span has to be in range, not just the base word. + let limb_span = |base_ptr: usize, + kind: &str, + check: &mut dyn FnMut(&str, usize) -> Result<(), String>| { + for k in 0..QUOTIENT_VM_LIMBS { + check(kind, base_ptr + k * WORD_BYTES)?; + } + Ok::<(), String>(()) + }; + + match op { + // No memory operands. + Q_OP_PUSH_CONST + | Q_OP_PUSH_CONST_U8 + | Q_OP_ADD + | Q_OP_MUL + | Q_OP_NEG + | Q_OP_POW5 + | Q_OP_ADD_CONST + | Q_OP_ADD_CONST_U8 + | Q_OP_MUL_CONST + | Q_OP_MUL_CONST_U8 + | Q_OP_FOLD_MAIN + | Q_OP_FOLD_SELECTOR + | Q_OP_NATIVE_PERMUTATION + | Q_OP_NATIVE_LOOKUP + | Q_OP_NATIVE_IDENTITY => Ok(()), + + Q_OP_PUSH_MEM_LITERAL => check("literal", u32_at(idx + 1)), + Q_OP_PUSH_MEM_U16 | Q_OP_ADD_MEM_U16 | Q_OP_MUL_MEM_U16 => check("u16", u16_at(idx + 1)), + + Q_OP_PUSH_MEM_TOKEN | Q_OP_PUSH_MEM_TOKEN_OFFSET => { + let token = bytes[idx + 1]; + let base = model.token_base(token).ok_or_else(|| { + format!( + "quotient VM memory token {token:#x} at byte {idx} has no generated base \ + address in this layout" + ) + })?; + let offset = + if op == Q_OP_PUSH_MEM_TOKEN_OFFSET { u32_at(idx + 2) } else { 0 }; + check("token", base + offset) + } + + Q_OP_ADD_MUL_MEM_MEM => { + check("u16", u16_at(idx + 1))?; + check("u16", u16_at(idx + 3)) + } + Q_OP_ADD_MUL_MEM_MEM_CONST_U8 => { + check("u16", u16_at(idx + 1))?; + check("u16", u16_at(idx + 3)) + } + Q_OP_ADD_MUL_CONST_U8_MEM_U16 => check("u16", u16_at(idx + 1)), + + Q_OP_RUN_ADD_MUL_MEM_MEM_CONST_U8 => { + let count = u16_at(idx + 1); + let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; + let stride = 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; + for k in 0..count { + check("u16", u16_at(base + k * stride))?; + check("u16", u16_at(base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES))?; + } + Ok(()) + } + Q_OP_RUN_ADD_MUL_CONST_U8_MEM_U16 => { + let count = u16_at(idx + 1); + let base = idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES; + let stride = QUOTIENT_VM_BYTE_U16_BYTES + 1; + for k in 0..count { + check("u16", u16_at(base + k * stride))?; + } + Ok(()) + } + Q_OP_AFFINE_SUM => { + let lin_count = u16_at(idx + 1); + let product_count = u16_at(idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES); + let mut cursor = idx + 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES; + for _ in 0..lin_count { + check("u16", u16_at(cursor))?; + cursor += QUOTIENT_VM_BYTE_U16_BYTES + 1; + } + for _ in 0..product_count { + check("u16", u16_at(cursor))?; + check("u16", u16_at(cursor + QUOTIENT_VM_BYTE_U16_BYTES))?; + cursor += 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; + } + Ok(()) + } + + Q_OP_LIN7 => limb_terms(idx + 1, check), + Q_OP_BILIN7_ROW => { + check("u16", u16_at(idx + 1))?; + limb_terms(idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES, check) + } + Q_OP_BILIN7_PAIRWISE => { + limb_span(u16_at(idx + 1), "pairwise_lhs", check)?; + limb_span(u16_at(idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES), "pairwise_rhs", check) + } + Q_OP_MODARITH7 => { + let mut cursor = idx + 1; + let flags = bytes[cursor]; + cursor += 1; + let cond = if flags & Q_MODARITH7_FLAG_COND != 0 { + let ptr = u16_at(cursor); + cursor += QUOTIENT_VM_BYTE_U16_BYTES; + Some(ptr) + } else { + None + }; + if flags & Q_MODARITH7_FLAG_CONST != 0 { + cursor += 1; + } + let lin_count = bytes[cursor] as usize; + let row_count = bytes[cursor + 1] as usize; + let pairwise_count = bytes[cursor + 2] as usize; + let mem_count = bytes[cursor + 3] as usize; + let product_count = bytes[cursor + 4] as usize; + cursor += 5; + let limb_stride = QUOTIENT_VM_LIMBS * (1 + QUOTIENT_VM_BYTE_U16_BYTES); + for _ in 0..lin_count { + limb_terms(cursor, check)?; + cursor += limb_stride; + } + for _ in 0..row_count { + check("u16", u16_at(cursor))?; + cursor += QUOTIENT_VM_BYTE_U16_BYTES; + limb_terms(cursor, check)?; + cursor += limb_stride; + } + for _ in 0..pairwise_count { + limb_span(u16_at(cursor), "pairwise_lhs", check)?; + limb_span( + u16_at(cursor + QUOTIENT_VM_BYTE_U16_BYTES), + "pairwise_rhs", + check, + )?; + cursor += 2 * QUOTIENT_VM_BYTE_U16_BYTES + QUOTIENT_VM_PAIRWISE_COEFFS; + } + for _ in 0..mem_count { + check("u16", u16_at(cursor + 1))?; + cursor += 1 + QUOTIENT_VM_BYTE_U16_BYTES; + } + for _ in 0..product_count { + check("u16", u16_at(cursor + 1))?; + check("u16", u16_at(cursor + 1 + QUOTIENT_VM_BYTE_U16_BYTES))?; + cursor += 1 + 2 * QUOTIENT_VM_BYTE_U16_BYTES; + } + if let Some(cond) = cond { + check("modarith_cond", cond)?; + } + Ok(()) + } + + _ => Err(format!( + "quotient VM pointer walker does not handle opcode {op:#x} at byte {idx}; extend \ + `quotient_read_pointers` so the new opcode's memory operands stay bounds-checked" + )), + } +} + /// Decode one instruction and validate token operands. fn decode_byte_quotient_instruction(bytes: &[u8], idx: usize) -> Result<(u8, usize), String> { require_quotient_bytes(bytes, idx, 1, "opcode")?; diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index d4c1c7f25..9ae1da137 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -3901,3 +3901,108 @@ fn fq_from_u256(value: U256) -> Fq { let repr = ::Repr::from(bytes); Option::::from(Fq::from_repr(repr)).expect("canonical field element") } + + +/// The pointer walker must know every opcode's memory operands. +/// +/// `quotient_read_pointers` fails closed on an unhandled opcode rather than +/// skipping it, so this test is what makes the fallback arm reachable +/// information: a new opcode added to `QUOTIENT_OPCODE_TABLE` without extending +/// the walker fails here instead of silently shipping unchecked pointers. +#[test] +fn quotient_pointer_walker_covers_every_opcode() { + let model = QuotientReadModel::default(); + for spec in QUOTIENT_VM_SPEC.opcodes { + // Zero operands keep every embedded count at zero, so the walk + // terminates for the dynamic opcodes without needing a hand-built + // program per shape. + let mut bytes = vec![spec.opcode]; + bytes.extend(std::iter::repeat_n(0u8, 64)); + let result = quotient_read_pointers(&bytes, 0, spec.opcode, &model, &mut |_, _| Ok(())); + if let Err(err) = result { + assert!( + !err.contains("pointer walker does not handle"), + "opcode {} ({:#x}) has no arm in quotient_read_pointers: {err}", + spec.name, + spec.opcode + ); + } + } +} + +/// Every pointer a real plan emits lands in a window the verifier populates. +/// +/// The positive assertion alone could pass on a program with no memory +/// operands at all, so this also pins that the fixture actually exercises the +/// walker. +#[test] +fn quotient_program_pointers_stay_inside_populated_windows() { + let (params, vk) = quotient_vm_test_vk(); + let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); + let plan = generator.inputs().lowering_plan(); + let model = plan.quotient_read_model(); + + let mut pointers = Vec::new(); + for (idx, op, _len) in quotient_bytecode_ops(&plan.quotient.build.bytes) { + quotient_read_pointers( + &plan.quotient.build.bytes, + idx, + op, + &model, + &mut |_kind, ptr| { + pointers.push(ptr); + Ok(()) + }, + ) + .expect("pointer walk should decode a validated program"); + } + assert!( + !pointers.is_empty(), + "test circuit emits no VM memory operands, so the pointer validator is vacuous here" + ); + + // `LoweringPlan::new` already ran this; assert directly so the failure + // message points at this invariant rather than at plan construction. + validate_quotient_mem_ptrs(&plan.quotient.build.bytes, &model) + .expect("emitted pointers should all land in populated windows"); +} + +/// A pointer outside the populated windows is rejected. +/// +/// Walks the real program, finds the first `LIN7` limb pointer, and rewrites it +/// to an address inside the verifier's low-memory scratch -- readable at +/// runtime, but holding transcript/pairing state rather than the proof +/// evaluation the identity expects. This is the shape a `Data` or planner +/// regression would take, and it is exactly what certification cannot see. +#[test] +fn quotient_pointer_validator_rejects_out_of_window_reads() { + let (params, vk) = quotient_vm_test_vk(); + let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); + let plan = generator.inputs().lowering_plan(); + let model = plan.quotient_read_model(); + + let mut corrupted = plan.quotient.build.bytes.clone(); + let limb_ptr_offset = quotient_bytecode_ops(&plan.quotient.build.bytes) + .find_map(|(idx, op, _)| (op == Q_OP_LIN7).then_some(idx + 2)) + .expect("test circuit should emit a seven-limb linear form"); + let stray = u16::try_from(layout::LOW_MEMORY_SCRATCH_START).expect("scratch base fits u16"); + corrupted[limb_ptr_offset..limb_ptr_offset + 2].copy_from_slice(&stray.to_be_bytes()); + assert_ne!( + corrupted, plan.quotient.build.bytes, + "corruption should change the program" + ); + + let err = validate_quotient_mem_ptrs(&corrupted, &model) + .expect_err("a pointer into low-memory scratch must be rejected"); + assert!( + err.contains("outside every window"), + "unexpected rejection reason: {err}" + ); + + // The stack-safety and const-slot validators pass on the same bytes, so + // this really is coverage they do not provide. + validate_quotient_program(&corrupted) + .expect("corrupting a pointer must not change structural validity"); + validate_quotient_const_slots(&corrupted, plan.quotient.build.consts.len()) + .expect("corrupting a pointer must not change const-slot validity"); +} From 743d5dac001084731414a8333c92186afe2b6b74 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 23:02:11 +0100 Subject: [PATCH 076/108] Unblock the clippy gate for the Solidity verifier package `cargo clippy --all-targets --all-features -- -Dwarnings`, which root CI runs across the workspace, fails on clean HEAD with four errors inside halo2_solidity_verifier. The package was not in any CI test job until the previous commits, and lint rot followed the same path: nothing reported these because nothing ran them against this crate. Four sites, all mechanical: * ConstraintSystemMeta::new and ProtocolPlan::from_constraint_system are the panicking wrappers superseded by their try_ counterparts, now reachable only from tests, so gate them on cfg(test) rather than deleting them -- the protocol and lowering test modules still use both. * Two word-alignment asserts and one test assertion use manual modulo where clippy now wants is_multiple_of. * A test computes `1 * g1` for symmetry with the surrounding sizing expression, and a layout test asserts a relation between two constants; make the first a plain term and the second a const assertion, which is what it was always checking. No behavior change. `cargo clippy -p halo2_solidity_verifier --all-targets --all-features -- -Dwarnings` is clean afterwards, and the 201 default-feature tests still pass. Co-Authored-By: Claude Opus 5 --- proofs/solidity-verifier/src/lowering/abi/proof.rs | 2 +- proofs/solidity-verifier/src/lowering/encoding/mod.rs | 5 ++++- proofs/solidity-verifier/src/lowering/layout/mod.rs | 4 +++- proofs/solidity-verifier/src/lowering/protocol/mod.rs | 4 +++- .../src/lowering/quotient_numerator/vm/mod.rs | 4 ++-- proofs/solidity-verifier/tests/ivc_accumulator_replay.rs | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/abi/proof.rs b/proofs/solidity-verifier/src/lowering/abi/proof.rs index 4a8d061d4..61ba2ae6a 100644 --- a/proofs/solidity-verifier/src/lowering/abi/proof.rs +++ b/proofs/solidity-verifier/src/lowering/abi/proof.rs @@ -534,7 +534,7 @@ mod tests { // The old bound counted only phase 0's advice and therefore under-sized // the buffer below the true run — confirm the fix was load-bearing. - let phase0_only_run = word + g1 + word + num_instances * word + 1 * g1; + let phase0_only_run = word + g1 + word + num_instances * word + g1; assert!(phase0_only_run < true_initial_run); assert!(phase0_only_run + cushion < true_initial_run); } diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index a2ec9c7f4..c3a63a5ca 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -140,7 +140,10 @@ impl ConstraintSystemMeta { /// for IVC-style fixtures with committed inputs it would be > 0. /// /// Panics if the constraint system is outside the supported verifier shape. - /// Use [`ConstraintSystemMeta::try_new`] on fallible paths. + /// Use [`ConstraintSystemMeta::try_new`] on fallible paths. Production + /// codegen goes through `SolidityGenerator::try_new`, which promises a typed + /// error, so this panicking form is test-only. + #[cfg(test)] pub(crate) fn new(cs: &ConstraintSystem, nb_committed_instances: usize) -> Self { Self::try_new(cs, nb_committed_instances) .unwrap_or_else(|err| panic!("invalid protocol plan: {err}")) diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 6425310a4..1f7618081 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -694,7 +694,9 @@ mod tests { ); // Above Solidity's allocatable start on purpose: solc reserves // via-IR spill slots upward from 0x80 in this contract. - assert!(super::LOW_MEMORY_SCRATCH_START > super::SOLIDITY_ALLOCATABLE_MEMORY_START); + const _: () = assert!( + super::LOW_MEMORY_SCRATCH_START > super::SOLIDITY_ALLOCATABLE_MEMORY_START + ); assert_eq!(super::VK_CONSTRUCTOR_PAYLOAD_START, 0x80); } diff --git a/proofs/solidity-verifier/src/lowering/protocol/mod.rs b/proofs/solidity-verifier/src/lowering/protocol/mod.rs index 41f004e59..ba89d3b0a 100644 --- a/proofs/solidity-verifier/src/lowering/protocol/mod.rs +++ b/proofs/solidity-verifier/src/lowering/protocol/mod.rs @@ -328,7 +328,9 @@ impl ProtocolPlan { /// Panics if the resulting plan fails [`ProtocolPlan::validate`]. Callers on /// a fallible path — notably [`SolidityGenerator::try_new`], which promises /// a typed error for unsupported constraint systems — must use - /// [`ProtocolPlan::try_from_constraint_system`] instead. + /// [`ProtocolPlan::try_from_constraint_system`] instead. Every production + /// path is fallible, so this panicking form is test-only. + #[cfg(test)] pub(crate) fn from_constraint_system( cs: &ConstraintSystem, nb_committed_instances: usize, diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index c8dadde70..eb5ebc8a3 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2991,7 +2991,7 @@ pub(crate) fn ptr_to_quotient_mem(ptr: Ptr) -> QuotientMem { // the VM mload a straddling window; reject it at the single // construction choke point rather than emit a corrupt verifier. assert!( - offset as usize % WORD_BYTES == 0, + (offset as usize).is_multiple_of(WORD_BYTES), "quotient memory pointer {offset:#x} is not 32-byte word aligned" ); QuotientMem::Literal(offset) @@ -3001,7 +3001,7 @@ pub(crate) fn ptr_to_quotient_mem(ptr: Ptr) -> QuotientMem { "quotient memory token offset must be a non-negative offset that fits in u32", ); assert!( - offset as usize % WORD_BYTES == 0, + (offset as usize).is_multiple_of(WORD_BYTES), "quotient memory token offset {offset:#x} is not 32-byte word aligned" ); let token = quotient_mem_token_from_name(name) diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs index a8f000c4f..90687f574 100644 --- a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -413,7 +413,7 @@ fn replay_accumulator_fixture(fixture: &str) { let evals_start = PROOF_PAYLOAD_START + g1_count * G1_PADDED_BYTES; let evals_end = PROOF_PAYLOAD_START + proof_len; assert!( - evals_start < evals_end && (evals_end - evals_start) % 0x20 == 0, + evals_start < evals_end && (evals_end - evals_start).is_multiple_of(0x20), "evaluation block is not a whole number of words" ); From 11928d1e65a8a0941752a9c467be43422ed11b83 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 23:24:03 +0100 Subject: [PATCH 077/108] Apply rustfmt to the quotient pointer validator Formatting-only follow-up to the two preceding commits. `cargo fmt --all -- --check` was left dirty in the new pointer-walker code, the read-model construction, and the const assertion; no behavior change. Co-Authored-By: Claude Opus 5 --- .../src/lowering/layout/mod.rs | 5 +-- proofs/solidity-verifier/src/lowering/plan.rs | 5 ++- .../src/lowering/quotient_numerator/vm/mod.rs | 43 +++++++++++++------ .../solidity-verifier/src/lowering/tests.rs | 1 - 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 1f7618081..184d0059b 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -694,9 +694,8 @@ mod tests { ); // Above Solidity's allocatable start on purpose: solc reserves // via-IR spill slots upward from 0x80 in this contract. - const _: () = assert!( - super::LOW_MEMORY_SCRATCH_START > super::SOLIDITY_ALLOCATABLE_MEMORY_START - ); + const _: () = + assert!(super::LOW_MEMORY_SCRATCH_START > super::SOLIDITY_ALLOCATABLE_MEMORY_START); assert_eq!(super::VK_CONSTRUCTOR_PAYLOAD_START, 0x80); } diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index 58ff79a7e..ed1046335 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -394,7 +394,10 @@ impl LoweringPlan { token_bases: vec![ (vm::Q_MEM_L0, self.memory.l_0_mptr.value().as_usize()), (vm::Q_MEM_L_LAST, self.memory.l_last_mptr.value().as_usize()), - (vm::Q_MEM_L_BLIND, self.memory.l_blind_mptr.value().as_usize()), + ( + vm::Q_MEM_L_BLIND, + self.memory.l_blind_mptr.value().as_usize(), + ), (vm::Q_MEM_BETA, self.memory.beta_mptr.value().as_usize()), (vm::Q_MEM_GAMMA, self.memory.gamma_mptr.value().as_usize()), (vm::Q_MEM_X, self.memory.x_mptr.value().as_usize()), diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index eb5ebc8a3..825714ab9 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -2237,7 +2237,10 @@ impl QuotientReadModel { /// Name the window covering a word-sized load, if any. fn window_for(&self, ptr: usize) -> Option<&'static str> { - self.windows.iter().find(|window| window.contains_word(ptr)).map(|window| window.name) + self.windows + .iter() + .find(|window| window.contains_word(ptr)) + .map(|window| window.name) } } @@ -2330,20 +2333,22 @@ pub(crate) fn quotient_read_pointers( // `const_slot, u16 ptr` -- the LIN7 limb operand and the MODARITH7 mem term. let limb_terms = |base: usize, check: &mut dyn FnMut(&str, usize) -> Result<(), String>| { for k in 0..QUOTIENT_VM_LIMBS { - check("limb", u16_at(base + k * (1 + QUOTIENT_VM_BYTE_U16_BYTES) + 1))?; + check( + "limb", + u16_at(base + k * (1 + QUOTIENT_VM_BYTE_U16_BYTES) + 1), + )?; } Ok::<(), String>(()) }; // Both pairwise bases are indexed `base + i * 0x20` for seven limbs, so the // whole span has to be in range, not just the base word. - let limb_span = |base_ptr: usize, - kind: &str, - check: &mut dyn FnMut(&str, usize) -> Result<(), String>| { - for k in 0..QUOTIENT_VM_LIMBS { - check(kind, base_ptr + k * WORD_BYTES)?; - } - Ok::<(), String>(()) - }; + let limb_span = + |base_ptr: usize, kind: &str, check: &mut dyn FnMut(&str, usize) -> Result<(), String>| { + for k in 0..QUOTIENT_VM_LIMBS { + check(kind, base_ptr + k * WORD_BYTES)?; + } + Ok::<(), String>(()) + }; match op { // No memory operands. @@ -2374,8 +2379,11 @@ pub(crate) fn quotient_read_pointers( address in this layout" ) })?; - let offset = - if op == Q_OP_PUSH_MEM_TOKEN_OFFSET { u32_at(idx + 2) } else { 0 }; + let offset = if op == Q_OP_PUSH_MEM_TOKEN_OFFSET { + u32_at(idx + 2) + } else { + 0 + }; check("token", base + offset) } @@ -2395,7 +2403,10 @@ pub(crate) fn quotient_read_pointers( let stride = 2 * QUOTIENT_VM_BYTE_U16_BYTES + 1; for k in 0..count { check("u16", u16_at(base + k * stride))?; - check("u16", u16_at(base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES))?; + check( + "u16", + u16_at(base + k * stride + QUOTIENT_VM_BYTE_U16_BYTES), + )?; } Ok(()) } @@ -2431,7 +2442,11 @@ pub(crate) fn quotient_read_pointers( } Q_OP_BILIN7_PAIRWISE => { limb_span(u16_at(idx + 1), "pairwise_lhs", check)?; - limb_span(u16_at(idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES), "pairwise_rhs", check) + limb_span( + u16_at(idx + 1 + QUOTIENT_VM_BYTE_U16_BYTES), + "pairwise_rhs", + check, + ) } Q_OP_MODARITH7 => { let mut cursor = idx + 1; diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 9ae1da137..5b2219ee1 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -3902,7 +3902,6 @@ fn fq_from_u256(value: U256) -> Fq { Option::::from(Fq::from_repr(repr)).expect("canonical field element") } - /// The pointer walker must know every opcode's memory operands. /// /// `quotient_read_pointers` fails closed on an unhandled opcode rather than From 0aab0cf698e9501612c892a598fe767f70af28da Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 23:24:26 +0100 Subject: [PATCH 078/108] Make the gated EVM tests work under --all-features `HALO2_SOLIDITY_RUN_EVM_TESTS=1 cargo test --all-features` failed every Poseidon and shape-fuzz test with `SrsError(64, 252)` during proof generation, long after the VK built cleanly at k. Two independent feature interactions, neither previously exercised because the crate's workflow never ran. SRS sizing. `outer-single-h-commitment` forwards `single-h-commitment` to midnight-proofs but deliberately not to midnight-zk-stdlib, because recursive proofs checked inside the decider circuit stay on the multi-limb layout. `srs_for_test` lives in zk-stdlib, so its `load_srs` branches on *zk-stdlib's* setting and returns a plain 2^k SRS, while the prover -- built from midnight-proofs *with* the feature -- commits to one unsplit quotient polynomial and needs k + ceil(log2(cs_degree - 1)) monomial powers. Mirror `load_srs`'s single-h branch in the fixtures instead. Real-SRS fixtures combine base and extended `load_srs` results through `with_extended_monomial`; the generated shape-fuzz circuits draw their own toxic secret, so they instead `unsafe_setup` at the extended size and `downsize_lagrange` back to the circuit domain -- the recipe documented on that method. Shape degree comes from configuring a throwaway constraint system; keygen's selector compression can only lower it, so the uncompressed value is a safe upper bound. `tests/ivc_keccak_solidity.rs` already does this for the decider proof; these are the same pattern applied to the Poseidon and shape-fuzz fixtures. Diagnostic renders. `--all-features` also enables `solidity-trace` and `solidity-gas-checkpoints`, so `RenderDiagnostics::default()` produces a build that emits LOG1 and is not `view` -- by design. Two tests assert the opposite of that on fixture variants rendered with the default diagnostics: one requires `verifyProof` to survive STATICCALL, the other requires no LOG1 in the source. `production_renders_do_not_emit_gas_ checkpoints` already skipped on gas-checkpoint builds; extend both to skip on trace builds too, matching that convention. Verified with the EVM gate on across three feature sets -- `--all-features`, `evm,truncated-challenges,rust-verifier-trace,solidity-trace`, and `evm,truncated-challenges,rust-verifier-trace` -- 201 passed, 0 failed in each. The same three fixture families in `tests/*_fixture.rs` still call `srs_for_test` directly and would need the same treatment to run under `--all-features`. Co-Authored-By: Claude Opus 5 --- proofs/solidity-verifier/src/test.rs | 127 ++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index e3e8747ab..9e30b5e3c 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -30,9 +30,14 @@ use midnight_proofs::{ poly::{commitment::Guard as _, kzg::KZGCommitmentScheme, Rotation}, transcript::{CircuitTranscript, Transcript}, }; +#[cfg(not(feature = "outer-single-h-commitment"))] +use midnight_zk_stdlib::utils::plonk_api::srs_for_test; +#[cfg(feature = "outer-single-h-commitment")] use midnight_zk_stdlib::{ - setup_vk, utils::plonk_api::srs_for_test, MidnightVK, Relation, ZkStdLib, ZkStdLibArch, + cost_model, + utils::plonk_api::{load_srs, SrsSource}, }; +use midnight_zk_stdlib::{setup_vk, MidnightVK, Relation, ZkStdLib, ZkStdLibArch}; use proptest::{ prelude::any, test_runner::{Config as ProptestConfig, TestRunner}, @@ -465,7 +470,7 @@ fn lookup_shape_verifier_compiles_with_native_lookup_callback() { }; let circuit = ShapeFuzzCircuit::new(case.spec, case.seed); let mut setup_rng = ChaCha8Rng::seed_from_u64(case.seed ^ 0x5eed_5eed); - let params = PoseidonParams::unsafe_setup(case.k, &mut setup_rng); + let params = shape_fuzz_params(&[(case.spec, case.k)], &mut setup_rng); let vk = keygen_vk_with_k::, _>(¶ms, &circuit, case.k) .unwrap_or_else(|err| panic!("shape fuzz `{}` vk generation failed: {err:?}", case.name)); @@ -634,7 +639,8 @@ fn same_srs_distinct_shape_matrix_rejects_cross_wiring() { ]; let mut setup_rng = ChaCha8Rng::seed_from_u64(0x5a5a_5151); - let params = PoseidonParams::unsafe_setup(cases[0].k, &mut setup_rng); + let shapes: Vec<_> = cases.iter().map(|case| (case.spec, case.k)).collect(); + let params = shape_fuzz_params(&shapes, &mut setup_rng); let fixtures: Vec<_> = cases .iter() .map(|case| build_shape_solidity_case_with_params(¶ms, case)) @@ -807,7 +813,7 @@ fn build_shape_solidity_case_with_params( fn run_supported_shape_fuzz_case(case: &ShapeFuzzCase) -> bool { let circuit = ShapeFuzzCircuit::new(case.spec, case.seed); let mut setup_rng = ChaCha8Rng::seed_from_u64(case.seed ^ 0x5eed_5eed); - let params = PoseidonParams::unsafe_setup(case.k, &mut setup_rng); + let params = shape_fuzz_params(&[(case.spec, case.k)], &mut setup_rng); let vk = keygen_vk_with_k::, _>(¶ms, &circuit, case.k) .unwrap_or_else(|err| panic!("shape fuzz `{}` vk generation failed: {err:?}", case.name)); let pk = keygen_pk(vk, &circuit) @@ -924,13 +930,65 @@ fn generated_shape_fuzz_spec(seed: u64) -> ShapeFuzzSpec { } } +/// Circuit domain size used by the transcript differential shape fuzzer. +#[cfg(feature = "rust-verifier-trace")] +const SHAPE_FUZZ_K: u32 = 5; + +/// Build test parameters covering every supplied `(shape, k)` pair. +/// +/// Under `outer-single-h-commitment` the prover commits to one unsplit quotient +/// polynomial of degree `(n - 1) * quotient_poly_degree`, so a plain +/// `unsafe_setup(k)` is too small and proof generation fails with a `SrsError` +/// long after the VK builds cleanly at `k`. The monomial basis has to be larger +/// than the circuit domain while the Lagrange basis stays at `2^k` -- exactly +/// the recipe documented on `ParamsKZG::downsize_lagrange`. +/// +/// Loading a real SRS is not an option for these circuits: they are generated +/// per seed, so each fixture draws its own toxic secret. Callers that share one +/// parameter set across several shapes pass them all here, and the monomial +/// basis is sized for the most demanding one. +fn shape_fuzz_params(shapes: &[(ShapeFuzzSpec, u32)], rng: &mut ChaCha8Rng) -> PoseidonParams { + let (_, lagrange_k) = shapes.first().copied().expect("at least one shape"); + assert!( + shapes.iter().all(|(_, k)| *k == lagrange_k), + "one parameter set can only serve shapes that share a circuit domain size" + ); + + #[cfg(not(feature = "outer-single-h-commitment"))] + { + PoseidonParams::unsafe_setup(lagrange_k, rng) + } + #[cfg(feature = "outer-single-h-commitment")] + { + let extended_k = shapes + .iter() + .map(|(spec, k)| { + // Configure a throwaway constraint system to learn this shape's + // degree. keygen may compress selectors, which can only lower + // the degree, so the uncompressed value is a safe upper bound. + let mut cs = ConstraintSystem::::default(); + >::configure_with_params(&mut cs, *spec); + // Same exponent `midnight_zk_stdlib::utils::plonk_api::load_srs` + // uses for the single-h monomial basis. + k + ((cs.degree() - 1) as f64).log2().ceil() as u32 + }) + .max() + .expect("at least one shape"); + let mut params = PoseidonParams::unsafe_setup(extended_k, rng); + // Keep the monomial basis extended; shrink only the Lagrange basis back + // to the circuit domain so commitments stay at 2^k. + params.downsize_lagrange(lagrange_k); + params + } +} + #[cfg(feature = "rust-verifier-trace")] fn run_transcript_differential_shape_fuzz_case(seed: u64) { let spec = generated_shape_fuzz_spec(seed); let context = format!("transcript differential seed={seed:#018x} spec={spec:?}"); let circuit = ShapeFuzzCircuit::new(spec, seed); let mut setup_rng = ChaCha8Rng::seed_from_u64(seed ^ 0x7ace_f00d); - let params = PoseidonParams::unsafe_setup(5, &mut setup_rng); + let params = shape_fuzz_params(&[(spec, SHAPE_FUZZ_K)], &mut setup_rng); let vk = keygen_vk_with_k::, _>(¶ms, &circuit, 5) .unwrap_or_else(|err| panic!("{context} vk generation failed: {err:?}")); let pk = keygen_pk(vk, &circuit) @@ -1659,7 +1717,11 @@ fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { #[test] fn production_renders_do_not_emit_gas_checkpoints() { - if crate::SOLIDITY_GAS_CHECKPOINTS_ENABLED { + // The fixture's base variants follow `RenderDiagnostics::default()`, so a + // `solidity-trace` build makes them emit LOG1 and drop `view` for the same + // reason a gas-checkpoint build does. Both are intended diagnostic shapes, + // not production renders, so neither can satisfy the assertions below. + if crate::SOLIDITY_GAS_CHECKPOINTS_ENABLED || crate::SOLIDITY_TRACE_ENABLED { return; } if !poseidon_inputs_available_for_evm() { @@ -1692,6 +1754,14 @@ fn production_renders_do_not_emit_gas_checkpoints() { #[test] fn production_separate_verifier_accepts_valid_proof_under_staticcall() { + // The fixture renders its base variants with `RenderDiagnostics::default()`, + // which follows the crate's feature flags. A trace or gas-checkpoint build + // emits LOG1 and is deliberately not `view`, so it cannot be STATICCALL-ed + // -- that is the documented contract, not a regression. Skip on those + // builds, matching `production_renders_do_not_emit_gas_checkpoints`. + if crate::SOLIDITY_TRACE_ENABLED || crate::SOLIDITY_GAS_CHECKPOINTS_ENABLED { + return; + } if !poseidon_inputs_available_for_evm() { return; } @@ -1766,7 +1836,7 @@ fn accumulator_fixed_base_tail_must_match_verifying_key() { let srs_dir = srs_dir(); env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; - let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let srs = poseidon_srs_for_test(&relation); let vk = setup_vk(&srs, &relation); let num_fixed_comms = vk.vk().fixed_commitments().len(); @@ -1837,7 +1907,7 @@ fn render_accumulator_verifier_variants( let srs_dir = srs_dir(); env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; - let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let srs = poseidon_srs_for_test(&relation); let vk = setup_vk(&srs, &relation); // A fully collapsed accumulator occupies FULLY_COLLAPSED_PUBLIC_INPUT_WORDS @@ -2337,7 +2407,7 @@ fn load_poseidon_vk_sources_fixture() -> PoseidonVkSourcesFixture { env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; - let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let srs = poseidon_srs_for_test(&relation); let vk = setup_vk(&srs, &relation); assert_eq!(vk.k() as u32, POSEIDON_K, "unexpected Poseidon VK k"); @@ -2369,7 +2439,7 @@ fn load_property_poseidon_fixture() -> PropertyPoseidonFixture { env::set_var("SRS_DIR", &srs_dir); let relation = PoseidonExample; - let srs = srs_for_test(&relation, Some(POSEIDON_K)); + let srs = poseidon_srs_for_test(&relation); let vk = setup_vk(&srs, &relation); assert_eq!(vk.k() as u32, POSEIDON_K, "unexpected Poseidon VK k"); @@ -4430,6 +4500,43 @@ fn env_flag_enabled(name: &str) -> bool { .unwrap_or(false) } +/// Load the Poseidon test SRS for the feature set this crate was built with. +/// +/// `outer-single-h-commitment` forwards `single-h-commitment` to +/// `midnight-proofs` but deliberately *not* to `midnight-zk-stdlib` (see the +/// feature comment in `Cargo.toml`: recursive proofs checked inside the decider +/// circuit stay on the multi-limb layout). The consequence is that +/// `srs_for_test` cannot be used under that feature: it calls `load_srs`, which +/// decides whether to extend the monomial basis from *zk-stdlib's own* +/// `single-h-commitment` setting. With the feature off there, `load_srs` returns +/// a plain `2^k`-element SRS, while the prover -- compiled from `midnight-proofs` +/// *with* the feature -- commits to one full-degree quotient polynomial and +/// needs `k + ceil(log2(cs_degree - 1))` monomial powers. The mismatch surfaces +/// as `SrsError(64, 252)` at proof generation, i.e. long after the VK builds +/// cleanly at `k`. +/// +/// Mirror `load_srs`'s single-h branch here instead, so `--all-features` is a +/// working configuration rather than one that fails inside the prover. +/// `tests/ivc_keccak_solidity.rs` already does the same thing for the decider +/// proof (`outer_single_h_extended_srs_k`); this is that pattern applied to the +/// Poseidon property fixtures. +fn poseidon_srs_for_test(relation: &PoseidonExample) -> PoseidonParams { + #[cfg(not(feature = "outer-single-h-commitment"))] + { + srs_for_test(relation, Some(POSEIDON_K)) + } + #[cfg(feature = "outer-single-h-commitment")] + { + let cs_degree = cost_model(relation, Some(POSEIDON_K)).max_deg; + // Same exponent `load_srs` uses: enough monomial powers to hold the + // unsplit quotient polynomial. + let extended_k = POSEIDON_K + ((cs_degree - 1) as f64).log2().ceil() as u32; + let base = load_srs(SrsSource::Filecoin, POSEIDON_K, cs_degree); + let extended = load_srs(SrsSource::Filecoin, extended_k, cs_degree); + base.with_extended_monomial(extended) + } +} + /// Require the Poseidon test SRS on disk. /// /// Only called once the EVM gate has been explicitly requested, so a missing From 3f89a98e614209d1b6216b0bd58d90858764344f Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 3 Aug 2026 23:55:32 +0100 Subject: [PATCH 079/108] Correct the I-12 challenge-sampling bias analysis AUDIT.md I-12 claimed "the bias is ~2^256 / r - 1 ~= 2^-254, completely negligible". 2^256 / r - 1 = 1.208, not 2^-254. The arithmetic only gives a negligible quantity when r ~= 2^256; here r ~= 2^254.86, so 2^256 / r ~= 2.208. An auditor reading the item would reasonably skip it on the strength of a number that is off by ~254 orders of magnitude. The conclusion survives, but the real analysis is different. sample_keccak_digest_be_mod_r reduces one 256-bit Keccak digest mod r, and the generated Yul mirrors it exactly in squeeze_to, so: r / 2^256 = 0.452845 floor(2^256 / r) = 2 R = 2^256 mod r = 0.094310 * 2^256 Residues below R have three preimages and the rest have two, giving a max/min density ratio of exactly 1.5 and a statistical distance from uniform of ~0.0747. The quantity that actually enters a soundness reduction is max density over uniform, 3r / 2^256 ~= 1.3585 (0.442 bits); 1.5 is the most-to-least-likely spread and a looser bound. Of the ten squeezed challenges, x3 is truncated at squeeze time and x1 / x4 are consumed only through truncated powers, so seven are used at full width. Compounding over those: ~8.5x on the tight factor (3.09 bits), ~17.1x on the loose one (4.09 bits) -- moving a 2^-254 soundness error to roughly 2^-251. Still Informational, now for a stated reason. Also record that the bias is inherited from the native Midfall transcript rather than introduced by this codegen, that both sides agree bit-for-bit, and that any future fix has to change the Rust and Yul sampling together. Co-Authored-By: Claude Opus 5 --- proofs/solidity-verifier/docs/audit/AUDIT.md | 38 ++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT.md b/proofs/solidity-verifier/docs/audit/AUDIT.md index aba140bf0..67a2c5ee9 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT.md @@ -798,7 +798,7 @@ The current `templates/contracts/Halo2Verifier.sol` blocks this path via `AUTHOR F-9 │ Low │ `if mload(HAS_ACCUMULATOR_MPTR)` is read from VK but it is not cross-checked against the codegen-side `acc_encoding` I-10 │ Informational │ Generator forces `vk.cs().num_instance_columns() <= 1` and `Rotation::cur()` only - silent "not yet implemented" panics if violated I-11 │ Informational │ `n_inv` and `omega_inv_to_l` are never re-derived from `k`/`omega` on chain - a malicious VK that bypasses the codehash pin can lie - I-12 │ Informational │ `mod(hash, r)` introduces ~2^-255 bias; standard practice, kept for completeness + I-12 │ Informational │ `mod(hash, r)` is measurably biased (1.5x max/min density, ~0.075 statistical distance), not ~2^-255; bounded soundness cost, no action The mitigations that have already landed (in particular the AUTHORIZED_VK + EXPECTED_VK_CODEHASH pinning at constructor time, commit 54b2943) close the original "caller-controlled VK" hole from AUDIT.md finding #1, and the EIP-2537 pairing precompile transitively covers G2 subgroup checks (BN254 audit finding #2). @@ -1056,7 +1056,41 @@ The current `templates/contracts/Halo2Verifier.sol` blocks this path via `AUTHOR I-12 - Bias in `mod(hash, r)` - r = 0x73eda7…00000001 ≈ 2^254.86. With a 256-bit hash, the bias is ~2^256 / r - 1 ≈ 2^-254, completely negligible. Standard practice; no action. + Correction. An earlier revision of this item stated "the bias is ~2^256 / r - 1 ≈ 2^-254, completely negligible". That is wrong: 2^256 / r - 1 = 1.208, not 2^-254. The + arithmetic only yields a negligible quantity when r ≈ 2^256, and here r ≈ 2^254.86, so 2^256 / r ≈ 2.208. The conclusion (informational, no action) still holds, but for a + different reason and with a much larger constant than the original text implied. The numbers below are the actual ones. + + Where. `sample_keccak_digest_be_mod_r` (midfall/proofs/src/transcript/implementors.rs:19) reduces one 256-bit Keccak digest mod r: + `BigUint::from_bytes_be(&hash_output) % modulus`. The generated Yul mirrors it exactly in `squeeze_to` + (templates/partials/verifier/AssemblyHelpers.yul, `mstore(mptr, mod(h0, r))`). The bias is therefore inherited from the native Midfall transcript, not introduced by this + codegen, and the two sides agree bit-for-bit. Removing it would be a transcript change on both sides, not a Solidity-only fix. + + Magnitude. With r = 0x73eda753…00000001: + + r / 2^256 = 0.452845 + floor(2^256 / r) = 2 + R = 2^256 mod r = 0.094310 * 2^256 + + So residues in [0, R) have 3 preimages under the reduction and residues in [R, r) have 2. That gives: + + max/min density ratio = exactly 1.5 + statistical distance ≈ 0.0747 + max density / uniform = 3r / 2^256 ≈ 1.3585 (0.442 bits) + + The last line is the quantity that enters a soundness reduction: any event has probability at most 1.3585x its probability under a uniform challenge. The 1.5 figure is the + spread between the most and least likely residue, which is a valid but looser bound. + + Impact. Ten challenges are squeezed. Three do not consume a full-width sample: `x3` is truncated to 128 bits at squeeze time, and `x1` / `x4` are consumed only through + truncated powers (see the `truncated-challenges` feature). The remaining seven - theta, beta, gamma, trash_challenge, y, x, x2 - are used at full width. Compounding the + per-challenge factor over those seven: + + tight 1.3585^7 ≈ 8.5x (3.09 bits) + loose 1.5^7 ≈ 17.1x (4.09 bits) + + Against a ~254.86-bit challenge space, that moves a 2^-254 soundness error to roughly 2^-251. Negligible in absolute terms, which is why this stays Informational. + + Recommendation. No action for the current deployment. If the transcript is ever revised, sample challenges by rejection or by reducing a wider digest (e.g. 512 bits, giving + statistical distance < 2^-250), and change the Rust and Yul sides together. Do not "fix" only the Solidity side: the two must produce identical challenges. ────────────────────────────────────────── From 6753679aab14cd01c2cc3a39b7c686d8c416b243 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 6 Aug 2026 10:52:25 +0100 Subject: [PATCH 080/108] Register the Lagrange denominator run as planner-owned scratch The Lagrange block wrote its batch-inversion input run in place at X_N_MPTR, overlaying theta words 27..51 and spilling into the rot_points window for >= 16 public instances (the deployed Sepolia artifact spills 4 words). Safety rested on write-ordering coincidence, guarded by a capacity check at the ~165-instance live-memory cliff, a TooManyInstances rejection in try_new, and a rendered-source ordering test covering only one of the three windows the invariant comment named. Move the run into a dedicated "lagrange_denoms" phase-scratch region (MemoryPhase::LagrangeBatchInvert), allocated after batch_invert_scratch from the same allocator so both same-phase regions stay disjoint and the scratch base stays pinned to SELECTOR_ACC_MPTR. The arena's overlap model now enforces the run's disjointness structurally, so the overlay, the spill, and the instance-count cliff disappear, and with them: - the capacity check in VerifierMemoryLayout::validate - the batch_invert_input_words layout field (the sizing fn stays) - theta_window::LAGRANGE_RUN_CAP_WORDS - the try_new instance-count guard and GeneratorError::TooManyInstances - the rot_points write-ordering test New tests pin the region shape (including the num_instances == 0 branch), a 500-instance layout beyond the old cliff, a 200-instance try_new -> layout -> render path, and rendered source basing the run at LAGRANGE_DENOMS_MPTR with only the permanent mstore(X_N_MPTR, x_n) remaining on the theta slot. Verified end-to-end before the guard deletions: the poseidon fixture renders with the repointed block, compiles under pinned solc, and verifies a real proof in revm. Frozen fixture replays pass untouched. Co-Authored-By: Claude Opus 5 --- .../LOWERING_ARCHITECTURE_SPEC.md | 11 +- .../docs/architecture/MEMORY_LAYOUT.md | 14 +- .../reference/ASKAMA_TEMPLATE_RUST_MAPPING.md | 4 +- proofs/solidity-verifier/src/api.rs | 24 --- proofs/solidity-verifier/src/builder/api.rs | 18 -- .../src/lowering/layout/memory.rs | 156 ++++++++++-------- .../src/lowering/layout/mod.rs | 19 --- .../solidity-verifier/src/lowering/tests.rs | 92 +++++------ .../poseidon-fixture-dump/Halo2Verifier.sol | 24 ++- .../templates/partials/verifier/Constants.sol | 4 + .../templates/partials/verifier/Lagrange.yul | 20 ++- 11 files changed, 179 insertions(+), 207 deletions(-) diff --git a/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md b/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md index ff760b3cd..3dd62dba8 100644 --- a/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md +++ b/proofs/solidity-verifier/docs/architecture/LOWERING_ARCHITECTURE_SPEC.md @@ -649,11 +649,12 @@ For new Yul scratch memory: Note the limit of step 3: `MemoryMap::validate` proves that *registered* regions do not conflict when live. It cannot prove that the emitted Yul only touches -registered regions. Ranges that intentionally spill outside the region model — -notably the Lagrange batch-inversion input run, which is capacity-checked in -`VerifierMemoryLayout::validate` instead — carry an explicit `INVARIANT` comment -naming the test that pins the assumption. Add new scratch as a registered region -unless there is a documented reason it cannot be one. +registered regions — that agreement is pinned by rendered-source tests such as +`lagrange_denominator_run_uses_registered_scratch_region`, which asserts the +Lagrange block bases its batch-inversion input run at the registered +`lagrange_denoms` region rather than a theta slot. All generated scratch is +planner-registered; add new scratch as a registered region and pin its use +with a rendered-source test. For quotient VM changes: diff --git a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md index 6e669b3d3..0a71e7d81 100644 --- a/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md +++ b/proofs/solidity-verifier/docs/architecture/MEMORY_LAYOUT.md @@ -172,9 +172,9 @@ which changes the transcript-buffer bound. The verifier reserves: - PCS fixed-window overflows. Intentional reuse is represented by giving the same byte range disjoint -lifetimes. For example, `batch_invert_scratch`, quotient VM scratch, q_eval -source tables, q_com trace scratch, and final MSM scratch can share bytes when -their phases do not overlap. +lifetimes. For example, `batch_invert_scratch`, `lagrange_denoms`, quotient VM +scratch, q_eval source tables, q_com trace scratch, and final MSM scratch can +share bytes when their phases do not overlap. The `trace_u256` log word is deliberately not a historical fixed constant. Trace hooks can run between reads from long-lived VK/eval/commitment memory, so @@ -237,6 +237,12 @@ addresses. The offsets below are in 32-byte words from `THETA_MPTR`. The gaps between fixed windows are deliberate historical padding. Do not use them as scratch without registering a `MemoryRegion` and a phase. +The Lagrange batch-inversion input run historically wrote its denominators in +place starting at `x_n` (word 26), overlaying words 27..51 and spilling into +`rot_points` for large instance counts. The run now lives in the registered +`lagrange_denoms` phase region above the decompressed commitments; word 26 is +a plain one-word permanent slot again. + ## Dynamic Commitment Region The commitment region begins at: @@ -274,7 +280,7 @@ The planner validates by lifetime, not just by address. | --- | --- | --- | | `Transcript` | `[0x1000, 0x1000 + transcript_words * 0x20)` | Must stay below `VK_MPTR`. | | `ScalarInv` | `VK_MPTR - 0x100` frame | Historical modexp scratch near the VK payload. | -| `LagrangeBatchInvert` | `batch_invert_scratch_mptr` | Reuses selector bytes before selector accumulators are live. | +| `LagrangeBatchInvert` | `batch_invert_scratch_mptr`, `lagrange_denoms_mptr` | Prefix-product scratch plus the batch-inversion input run; both reuse selector/quotient bytes before those phases are live. | | `QuotientVm` | quotient temps and stack | Used before PCS final MSM. | | `PcsQEvalSourceTable` | rolled q_eval address table | Aliases `pcs_scratch_mptr`. | | `PcsQComTrace` | optional q_com trace MSM | Aliases `pcs_scratch_mptr`; trace-only. | diff --git a/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md b/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md index 39f58aca9..13ab2052e 100644 --- a/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md +++ b/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md @@ -87,7 +87,7 @@ with Midfall transcript and KZG details rendered directly into Yul. | `y`, quotient commitment(s) | Squeezes identity-batching challenge and reads quotient commitment(s) | `verify_algebraic_constraints`: `read_n(transcript, nb_quotient_coms)` before `x` | `proof_layout.rs`, `memory.rs` | | `x` and evaluation scalars | Squeezes opening challenge, range-checks proof evals, stores them in `REVERSED_EVALS_MPTR`, and absorbs them | `verify_algebraic_constraints`: committed-instance evals, advice evals, fixed evals, permutation/common evals, lookup evals, trash evals | `Protocol` eval order, `proof_layout.rs`, `evaluator.rs` | | `x1`, `x2`, `f_com`, `x3`, `q_evals`, `x4`, `pi` | Completes Midfall KZG transcript for multi-opening proof | KZG `multi_prepare` in `../midfall/proofs/src/poly/kzg` | `pcs.rs`, `proof_layout.rs` | -| Lagrange and instance evaluation | Computes `x^n`, `(x^n-1)^-1`, `l_last`, `l_blind`, `l_0`, and the public instance evaluation | `verify_algebraic_constraints`: `domain.l_i_range` and `compute_inner_product` | `templates/contracts/Halo2Verifier.sol`, `memory.rs` | +| Lagrange and instance evaluation | Computes `x^n`, `(x^n-1)^-1`, `l_last`, `l_blind`, `l_0`, and the public instance evaluation; the batch-inversion input run lives in the registered `LAGRANGE_DENOMS_MPTR` region | `verify_algebraic_constraints`: `domain.l_i_range` and `compute_inner_product` | `templates/contracts/Halo2Verifier.sol`, `memory.rs` | | Batched identity numerator reconstruction | Reconstructs `nu_y(x)` from the claimed evals and stores the linearization expected scalar `-nu_y(x)` | `plonk/mod.rs::partially_evaluate_identities`; trace loop for `quotient_numerator` and selector folds | `evaluator.rs`, `quotient/mod.rs`, `QuotientNumeratorBlock.yul` | | Linearization scalar prep | Computes `x_split = x^(n-1)` and `1 - x^n`; prepares selector buckets and quotient-limb scalars | `linearization/verifier.rs::compute_linearization_commitment` | `templates/contracts/Halo2Verifier.sol`, `pcs.rs` | | PCS computation blocks | Constructs point sets, folds evaluations/commitments, computes `f_eval`, `v`, final commitment, and pairing inputs | `CS::multi_prepare` and KZG final guard verification | `src/lowering/kzg/mod.rs` | @@ -391,7 +391,7 @@ comparison against the instrumented Rust verifier. | Quotient constants/program in VK payload | `artifact.rs`, `generate_vk` | Avoids verifier-side immediate constants | VK hash changes when the quotient program changes | | Decoded eval spill buffer | `REVERSED_EVALS_MPTR` | Turns later eval references into cheap `mload`s | Proof scalar order must match protocol metadata exactly | | Off-chain proof repacking | `quotient::RepackedProofLayoutPlan` and ABI docs | On-chain verifier consumes BE scalar words and EIP-2537 G1s directly | Calldata is Solidity-facing, not native Midnight proof bytes | -| Lagrange batch inversion | `batch_invert` helper | Computes all needed inverse denominators with one modexp | Scratch region must not overlap permanent memory | +| Lagrange batch inversion | `batch_invert` helper | Computes all needed inverse denominators with one modexp | Input run (`lagrange_denoms`) and prefix-product scratch (`batch_invert_scratch`) are planner-registered phase regions | | Simple-selector bucket grouping | `compute_linearization_commitment`, `SELECTOR_ACC_MPTR` | Removes simple selector proof evals and groups MSM terms | Selector identity order and final `y` scaling must match Rust | | Fused linearization into PCS MSM | `pcs.rs` | Avoids a standalone production G1MSM for linearization | Trace builds may materialize it only for comparison | | Point-set planning at lowering time | `pcs.rs::intermediate_sets` | Removes dynamic query sorting/grouping from Solidity | Generated verifier is circuit-specialized | diff --git a/proofs/solidity-verifier/src/api.rs b/proofs/solidity-verifier/src/api.rs index e2213b9eb..0cf0be6e1 100644 --- a/proofs/solidity-verifier/src/api.rs +++ b/proofs/solidity-verifier/src/api.rs @@ -477,19 +477,6 @@ pub enum GeneratorError { /// Permutation commitments in the verifying key. num_permutation_comms: usize, }, - /// The public instance count pushes the Lagrange batch-inversion input run - /// past the verifier memory that is already live when Lagrange executes. - /// - /// The run is written in place from `X_N_MPTR` and is - /// `num_instances + abs(rotation_last) + 1` words long. - TooManyInstances { - /// Requested public instance count. - num_instances: usize, - /// Largest public instance count this constraint system can support. - max_num_instances: usize, - /// Negative-row denominators contributed by `rotation_last`. - rotation_last_words: usize, - }, /// Internal render/layout planning failed before Solidity was emitted. Planning { /// Planning stage. @@ -556,17 +543,6 @@ impl fmt::Display for GeneratorError { {min_fixed_scalar_count}..={max_fixed_scalar_count}; adjust num_instances or the \ accumulator offset" ), - Self::TooManyInstances { - num_instances, - max_num_instances, - rotation_last_words, - } => write!( - f, - "public instance count {num_instances} is too large: the Lagrange \ - batch-inversion run writes num_instances + {rotation_last_words} + 1 words from \ - X_N_MPTR and would overrun verifier memory that is live at that point; \ - the maximum for this constraint system is {max_num_instances}" - ), Self::Planning { stage, message } => { write!(f, "generator planning failed during {stage}: {message}") } diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 7afc789f9..6eee59cb2 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -6,7 +6,6 @@ //! stable caller-facing knobs before lower-level generation starts. use super::*; -use crate::lowering::layout::{memory::batch_invert_input_words, theta_window}; impl<'a> SolidityGenerator<'a> { /// Number of committed instance columns supported by the generated ABI. @@ -106,23 +105,6 @@ impl<'a> SolidityGenerator<'a> { }, )?; - // Bound the public instance count here rather than leaving it to - // `VerifierMemoryLayout::validate`. The Lagrange block writes its - // batch-inversion input run in place from `X_N_MPTR`, and that run - // grows with `num_instances`; the layout does catch an overrun, but - // only much later and phrased in theta-word offsets. `rotation_last` - // is only known once `meta` is built, hence the position of this check. - let run_words = batch_invert_input_words(&meta, config.num_instances); - if run_words > theta_window::LAGRANGE_RUN_CAP_WORDS { - let rotation_last_words = meta.rotation_last.unsigned_abs() as usize; - return Err(GeneratorError::TooManyInstances { - num_instances: config.num_instances, - max_num_instances: theta_window::LAGRANGE_RUN_CAP_WORDS - .saturating_sub(rotation_last_words + 1), - rotation_last_words, - }); - } - Ok(Self { params, vk, diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 5be8d69a1..233fb4ecd 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -520,9 +520,10 @@ pub(crate) struct VerifierMemoryLayout { /// Reuses selector-accumulator bytes during the earlier Lagrange batch /// inversion phase. pub(crate) batch_invert_scratch_mptr: usize, - /// Number of Fr words the generated Lagrange block writes in place at - /// `X_N_MPTR` as the batch-inversion input run. - pub(crate) batch_invert_input_words: usize, + /// Batch-inversion input run: denominators, then their in-place inverses, + /// then Lagrange values, distilled into named theta slots at the end of + /// the Lagrange block. + pub(crate) lagrange_denoms_mptr: usize, /// First quotient VM temporary. Also the canonical PCS scratch base once /// selector accumulators are accounted for. pub(crate) quotient_tmp_mptr: usize, @@ -641,7 +642,8 @@ impl VerifierMemoryLayout { .max() .expect("constructor G1MSM smoke bounds are non-empty"); let batch_invert_len = batch_invert_scratch_bytes(meta, config.num_instances); - let batch_invert_input_words = batch_invert_input_words(meta, config.num_instances); + let lagrange_denoms_len = + batch_invert_input_words(meta, config.num_instances) * WORD_BYTES; let quotient_return_len = (2 + meta.num_simple_selectors) * WORD_BYTES; let mut arena = MemoryArena::default(); @@ -824,13 +826,33 @@ impl VerifierMemoryLayout { end: MemoryPhase::PcsFinalMsm, }, ); - let batch_invert_scratch_mptr = { + // Both Lagrange-phase regions come from ONE allocator so the second + // lands sequentially after the first: a fresh allocator would reset the + // per-phase cursor back to `selector_acc_mptr` and register a same-phase + // overlap, which `MemoryMap::validate` rejects. Order also matters: + // `batch_invert_scratch` is allocated first so its address stays pinned + // to `selector_acc_mptr` (asserted by + // `selector_accumulators_are_live_from_quotient_to_final_msm`). + // + // `lagrange_denoms` holds the batch-inversion input run (denominators, + // then in-place inverses, then Lagrange values). It was historically + // written in place at `X_N_MPTR`, overlaying theta words 27..51 and + // spilling into the PCS fixed windows for large instance counts; as a + // registered region the arena's overlap model enforces disjointness + // structurally instead of by write-ordering coincidence. + let (batch_invert_scratch_mptr, lagrange_denoms_mptr) = { let mut scratch = arena.scratch_allocator(selector_acc_mptr); - scratch.alloc_phase_scratch( + let batch_invert_scratch_mptr = scratch.alloc_phase_scratch( "batch_invert_scratch", batch_invert_len, MemoryPhase::LagrangeBatchInvert, - ) + ); + let lagrange_denoms_mptr = scratch.alloc_phase_scratch( + "lagrange_denoms", + lagrange_denoms_len, + MemoryPhase::LagrangeBatchInvert, + ); + (batch_invert_scratch_mptr, lagrange_denoms_mptr) }; let quotient_tmp_base = (selector_acc_mptr + selector_len).next_multiple_of(WORD_BYTES); let (quotient_tmp_mptr, quotient_stack_mptr) = { @@ -930,6 +952,7 @@ impl VerifierMemoryLayout { comms_mptr_base.value().as_usize() + commitments_len, selector_acc_mptr + selector_len, batch_invert_scratch_mptr + batch_invert_len, + lagrange_denoms_mptr + lagrange_denoms_len, quotient_stack_mptr + quotient_stack_len.max(MODEXP_FRAME_BYTES), linearization_trace_msm_mptr + lin_trace_len, pcs_q_eval_source_table_mptr + q_eval_source_len, @@ -1007,7 +1030,7 @@ impl VerifierMemoryLayout { quotient_limb_comms_mptr_base, selector_acc_mptr, batch_invert_scratch_mptr, - batch_invert_input_words, + lagrange_denoms_mptr, quotient_tmp_mptr, quotient_stack_mptr, pcs_q_eval_source_table_mptr, @@ -1121,37 +1144,9 @@ impl VerifierMemoryLayout { )); } - // The Lagrange block writes its batch-inversion input run in place at - // `X_N_MPTR` (theta word 26). The run intentionally spills past the - // theta band into the PCS fixed windows, which are written only after - // the Lagrange phase, so it cannot be registered as a region without - // fake overlaps; it is capacity-checked here instead. The first bytes - // that are already live at Lagrange time are the q_eval calldata - // cursor (written by the proof parser), the G1 identity slot (must - // stay virgin zero memory), and the decoded proof evaluations. - // - // INVARIANT: this cap is sound only while rot_points, x1_powers and - // q_eval_set are first touched *after* the Lagrange phase. The arena's - // overlap loop cannot enforce that, because the run is not a - // registered region -- registering it would report overlaps that are - // correct by phase ordering. The ordering is pinned instead by - // `rot_points_window_is_written_after_the_lagrange_denominator_run`, - // which asserts it against rendered verifier source. - let lagrange_run_end = ThetaSlot::XN.word() + self.batch_invert_input_words; - let lagrange_run_cap = windows - .q_eval_cptr_word - .min(windows.g1_identity_word) - .min(windows.reversed_evals_word); - if lagrange_run_end > lagrange_run_cap { - return Err(format!( - "Lagrange batch-inversion input run overflows live verifier memory: \ - [X_N_MPTR, X_N_MPTR + {} word(s)) ends at theta word {lagrange_run_end}, \ - but Q_EVAL_CPTR_MPTR/G1_IDENTITY_MPTR/decoded evaluations are live from \ - theta word {lagrange_run_cap}; reduce the public instance count", - self.batch_invert_input_words - )); - } - + // The Lagrange batch-inversion input run lives in the registered + // `lagrange_denoms` phase region, so `map.validate()` below covers its + // disjointness structurally; no separate capacity check is needed. self.map.validate()?; Ok(()) @@ -1169,8 +1164,8 @@ pub(crate) fn commitment_g1_count(meta: &ConstraintSystemMeta) -> usize { + meta.num_quotients } -/// Number of Fr words the generated Lagrange block writes in place starting at -/// `X_N_MPTR` as the batch-inversion input run. +/// Number of Fr words the generated Lagrange block writes into the +/// `lagrange_denoms` region as the batch-inversion input run. /// /// The input range covers: /// - num_instances public Lagrange denominators, or one fallback word when @@ -1722,43 +1717,74 @@ mod tests { } #[test] - fn lagrange_batch_invert_input_run_is_bounded_by_live_memory() { + fn lagrange_denoms_region_tracks_instance_shape() { let meta = ConstraintSystemMeta { rotation_last: -3, ..ConstraintSystemMeta::default() }; let vk = synthetic_vk(); - let windows = ThetaWindowLayout::compatibility(); - let cap_words = windows - .q_eval_cptr_word - .min(windows.g1_identity_word) - .min(windows.reversed_evals_word) - - ThetaSlot::XN.word(); - // `SolidityGenerator::try_new` rejects oversized instance counts up - // front against the constant form of this cap. The two must agree, or - // the early bound and the layout check would disagree about what fits. - assert_eq!(cap_words, theta_window::LAGRANGE_RUN_CAP_WORDS); - - // Largest instance count whose denominator run plus `x_n - 1` still - // fits below the q_eval calldata cursor: num + |rotation_last| + 1. - let max_instances = cap_words - 3 - 1; let config = VerifierMemoryLayoutConfig { - num_instances: max_instances, + num_instances: 5, ..VerifierMemoryLayoutConfig::default() }; let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); - assert_eq!(layout.batch_invert_input_words, cap_words); - layout.validate().expect("run ending below Q_EVAL_CPTR_MPTR is valid"); + let region = layout + .map + .region("lagrange_denoms") + .expect("lagrange denominator region registered"); + + // num_instances + |rotation_last| denominators plus the trailing + // `x_n - 1` word. + assert_eq!(region.len, (5 + 3 + 1) * WORD_BYTES); + assert_eq!(region.lifetime, MemoryLifetime::Phase(MemoryPhase::LagrangeBatchInvert)); + assert_eq!(layout.lagrange_denoms_mptr, region.start); + // Sequential same-phase allocation: the run sits directly above the + // prefix-product scratch, which itself stays pinned to the selector + // accumulator base. + let scratch = layout + .map + .region("batch_invert_scratch") + .expect("batch invert scratch region registered"); + assert_eq!(region.start, scratch.start + scratch.len); + layout.validate().expect("layout with registered denominator run is valid"); + // Zero public instances still needs one denominator slot for L_0 + // recovery: |rotation_last| + 2 words total. let config = VerifierMemoryLayoutConfig { - num_instances: max_instances + 1, + num_instances: 0, ..VerifierMemoryLayoutConfig::default() }; let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); - let err = layout.validate().unwrap_err(); - assert!( - err.contains("Lagrange batch-inversion input run"), - "unexpected validation error: {err}" - ); + let region = layout + .map + .region("lagrange_denoms") + .expect("lagrange denominator region registered"); + assert_eq!(region.len, (3 + 2) * WORD_BYTES); + layout.validate().expect("zero-instance layout is valid"); + } + + /// The registered denominator region removes the historical instance-count + /// cliff: a count far beyond the old 175-word live-memory cap now simply + /// grows the region, and the arena still validates. + #[test] + fn lagrange_denoms_region_scales_beyond_the_old_live_memory_cliff() { + let meta = ConstraintSystemMeta { + rotation_last: -3, + ..ConstraintSystemMeta::default() + }; + let vk = synthetic_vk(); + let config = VerifierMemoryLayoutConfig { + num_instances: 500, + ..VerifierMemoryLayoutConfig::default() + }; + let layout = VerifierMemoryLayout::new(&meta, &vk, Ptr::memory(0x2000), config); + let region = layout + .map + .region("lagrange_denoms") + .expect("lagrange denominator region registered"); + assert_eq!(region.len, (500 + 3 + 1) * WORD_BYTES); + layout + .validate() + .expect("large instance counts are structurally valid with a registered run"); } } diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 184d0059b..6df86b3af 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -628,25 +628,6 @@ pub(crate) mod theta_window { /// Word offset where reversed proof evaluations begin. pub(crate) const REVERSED_EVALS_WORD: usize = G1_IDENTITY_WORD + G1_WORDS + G1_IDENTITY_PADDING_WORDS; - - /// Largest Lagrange batch-inversion input run that fits below live memory. - /// - /// The run starts in place at `X_N_MPTR` and deliberately spills past the - /// theta band into the rot_points / x1_powers / q_eval_set windows, which - /// are written only after the Lagrange phase. The first words that are - /// already live when Lagrange runs are the q_eval calldata cursor, the G1 - /// identity slot (which must stay virgin zero memory), and the decoded - /// proof evaluations, so the run must end at or before the lowest of those. - pub(crate) const LAGRANGE_RUN_CAP_WORDS: usize = { - let mut cap = Q_EVAL_CPTR_WORD; - if G1_IDENTITY_WORD < cap { - cap = G1_IDENTITY_WORD; - } - if REVERSED_EVALS_WORD < cap { - cap = REVERSED_EVALS_WORD; - } - cap - ThetaSlot::XN.word() - }; } pub(crate) mod trace { diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 5b2219ee1..9a51f337e 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -673,20 +673,14 @@ fn external_quotient_output_uses_planned_return_buffer() { ); } -/// The Lagrange denominator run is deliberately allowed to spill out of the -/// theta band into the rot_points / x1_powers / q_eval_set windows, so -/// `VerifierMemoryLayout::validate` caps it against the *live* boundary -/// (`Q_EVAL_CPTR_MPTR`) rather than against `ROT_POINTS_MPTR`. That is only -/// sound while those three windows are written strictly after the Lagrange -/// phase and never read before being rewritten. -/// -/// Because the run is not registered as a `MemoryRegion` -- registering it -/// would report overlaps that are correct by phase ordering -- the arena's -/// overlap loop cannot enforce this. Pin the ordering here instead, so moving -/// a rot_points write earlier fails a test rather than silently corrupting the -/// denominators. -#[test] -fn rot_points_window_is_written_after_the_lagrange_denominator_run() { +/// The Lagrange denominator run must live entirely in the planner-registered +/// `lagrange_denoms` region. Historically it was written in place at +/// `X_N_MPTR`, overlaying theta words 27..51 and spilling into the rot_points +/// window for large instance counts -- safety then rested on write-ordering +/// coincidence. Pin the rendered source so the run cannot silently move back +/// onto the theta band. +#[test] +fn lagrange_denominator_run_uses_registered_scratch_region() { let (params, vk) = lowering_plan_test_vk(); let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); let source = generator @@ -694,50 +688,44 @@ fn rot_points_window_is_written_after_the_lagrange_denominator_run() { .expect("test verifier should render") .verifier; - let lagrange_end = source - .find("batch_invert(success, X_N_MPTR") - .expect("Lagrange block must call batch_invert over the denominator run"); - // Any access at all, read or write: the run leaves garbage in this window, - // so an early read is as wrong as an early write being clobbered. - let first_rot_points_access = source - .find("add(ROT_POINTS_MPTR") - .expect("verifier must access the rot_points window"); - assert!( - first_rot_points_access > lagrange_end, - "ROT_POINTS_MPTR is accessed at byte {first_rot_points_access}, before the Lagrange \ - batch_invert at byte {lagrange_end}; the denominator run spills into that window, so \ - touching it earlier would either corrupt the denominators or read their leftovers" + source.contains("batch_invert(success, LAGRANGE_DENOMS_MPTR"), + "Lagrange batch inversion must run over the registered denominator region" + ); + assert!( + source.contains("let mptr := LAGRANGE_DENOMS_MPTR"), + "the denominator write cursor must start at the registered region" + ); + assert!( + source.contains("mstore(X_N_MPTR, x_n)"), + "the permanent x_n theta slot must still be written by the distill step" + ); + assert!( + !source.contains("batch_invert(success, X_N_MPTR"), + "the denominator run must not be based at the X_N_MPTR theta slot" + ); + assert!( + !source.contains("add(X_N_MPTR"), + "no offset-based access to the X_N_MPTR theta slot may survive; the \ + run's offsets all belong to LAGRANGE_DENOMS_MPTR now" ); } -/// The Lagrange denominator run grows with `num_instances`, so an oversized -/// instance count must be rejected at construction with a typed error rather -/// than surfacing later as a memory-layout failure. +/// The Lagrange denominator run lives in a registered scratch region that +/// grows with `num_instances`, so counts far past the historical 165-instance +/// live-memory cliff must build, validate, and render. #[test] -fn generator_rejects_instance_counts_that_overrun_the_lagrange_run() { +fn generator_accepts_instance_counts_beyond_the_old_lagrange_cliff() { let (params, vk) = lowering_plan_test_vk(); - let meta = ConstraintSystemMeta::new(vk.cs(), 1); - let rotation_last_words = meta.rotation_last.unsigned_abs() as usize; - let max_num_instances = - crate::lowering::layout::theta_window::LAGRANGE_RUN_CAP_WORDS - rotation_last_words - 1; - - SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(max_num_instances, 1)) - .expect("the largest fitting instance count must still be accepted"); - - let err = - SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(max_num_instances + 1, 1)) - .expect_err("one instance past the cap must be rejected"); - assert!( - matches!( - err, - GeneratorError::TooManyInstances { - max_num_instances: reported, - .. - } if reported == max_num_instances - ), - "unexpected error: {err:?}" - ); + let generator = SolidityGenerator::try_new(¶ms, &vk, GeneratorConfig::new(200, 1)) + .expect("large instance counts are supported with a registered denominator region"); + + let plan = generator.inputs().lowering_plan(); + plan.memory.validate().expect("layout with a 200-instance denominator run is valid"); + + generator + .render(crate::RenderOptions::default()) + .expect("verifier with a 200-instance denominator run renders"); } #[test] diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index ee59832c1..3b9d726c2 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -153,6 +153,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0x65e0; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x65e0; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0x67c0; uint256 internal constant TRACE_U256_MPTR = 0x83c0; // ---------------------------------------------------------------------- @@ -1267,8 +1271,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x0140) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1278,11 +1284,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1293,9 +1299,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0120) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0120) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1318,8 +1324,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0120)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0120)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index 69b965f26..48b95afe2 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -136,6 +136,10 @@ uint256 internal constant SELECTOR_ACC_MPTR = {{ memory.selector_acc_mptr|hex() }}; uint256 internal constant QUOTIENT_RETURN_MPTR = {{ memory.quotient_return_mptr|hex() }}; uint256 internal constant BATCH_INV_SCRATCH_MPTR = {{ memory.batch_invert_scratch_mptr|hex() }}; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = {{ memory.lagrange_denoms_mptr|hex() }}; uint256 internal constant TRACE_U256_MPTR = {{ memory.trace_u256_mptr|hex() }}; // ---------------------------------------------------------------------- diff --git a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul index 6eb05fce4..0f6d5a85e 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul @@ -15,8 +15,10 @@ // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, {{ ((num_instances + num_neg_lagranges) * 32)|hex() }}) {%- if num_instances == 0 %} // No public instances still need one denominator slot so @@ -31,11 +33,11 @@ } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -46,9 +48,9 @@ // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }}) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, {{ (num_neg_lagranges * 32)|hex() }}) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -71,8 +73,8 @@ // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }})) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, {{ (num_neg_lagranges * 32)|hex() }})) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) From 78556d07ee2152fc3a4b2a008f165559a3055290 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 6 Aug 2026 11:11:29 +0100 Subject: [PATCH 081/108] Regenerate the IVC replay fixture on the registered Lagrange scratch layout Re-render fixtures/ivc from commit 6753679 so the checked-in verifier uses the planner-registered LAGRANGE_DENOMS_MPTR region instead of the historical in-place run at X_N_MPTR. Halo2VerifyingKey.sol and Halo2QuotientEvaluator.sol are byte-identical to the previous render, confirming the change is confined to the Lagrange block; calldata.bin carries the fresh proof from the regeneration run (same 8356-byte layout). Rendered by ivc_final_keccak_solidity_e2e with midnight-srs-2p19/2p20; the fresh proof verified on revm Prague in 1,286,780 gas (+1,506 vs the previous fixture, memory-expansion cost of the relocated denominator run). ivc_accumulator_replay passes against the new sources. Co-Authored-By: Claude Opus 5 --- .../fixtures/ivc/Halo2Verifier.sol | 50 +++++++++++++----- .../solidity-verifier/fixtures/ivc/README.md | 4 +- .../fixtures/ivc/calldata.bin | Bin 8356 -> 8356 bytes 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol index 6f66ad7c7..48f05f35a 100644 --- a/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol @@ -161,6 +161,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0xb4e0; uint256 internal constant TRACE_U256_MPTR = 0xe340; // ---------------------------------------------------------------------- @@ -547,16 +551,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { @@ -615,7 +637,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1422,8 +1444,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x0300) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1433,11 +1457,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1448,9 +1472,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0140) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1473,8 +1497,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0140)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0140)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -2205,7 +2229,7 @@ contract Halo2Verifier { // If either original equation is bad, this combined equation // holds for at most one alpha in Fr. { - let batch_ptr := 0x0100 + let batch_ptr := 0x1000 // Domain || KZG rhs/lhs || accumulator rhs/lhs. mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md index 350fbe00f..2f44e95c7 100644 --- a/proofs/solidity-verifier/fixtures/ivc/README.md +++ b/proofs/solidity-verifier/fixtures/ivc/README.md @@ -14,11 +14,11 @@ is what makes a vk.bin-based replay unusable in CI. | Field | Value | | --- | --- | -| Source commit | `f5b7466` | +| Source commit | `6753679` | | Rendered by | `tests/ivc_keccak_solidity.rs` (`ivc_final_keccak_solidity_e2e`) | | Circuit | IVC k=19 leaves, k=20 decider | | Accumulator | `AccumulatorEncoding::new(offset=4, num_limbs=7, num_limb_bits=56)` | -| Verified on-chain | yes, 1,285,274 gas under revm Prague | +| Verified on-chain | yes, 1,286,780 gas under revm Prague | ## Regenerating diff --git a/proofs/solidity-verifier/fixtures/ivc/calldata.bin b/proofs/solidity-verifier/fixtures/ivc/calldata.bin index 9aed1ca8961ee78ba7fde25b9914805108918db6..66e2fad5af082449ef70a1d61af4083c79a60a0f 100644 GIT binary patch literal 8356 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 S*JegLc)ZB}%>OTA`2PaT_%IUy literal 8356 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 S-r{X~M&0oI&-}kB!~Z|Q2_ESH From 3fb6d841bcf95496313599fe4b406b308905c1b8 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 6 Aug 2026 11:11:57 +0100 Subject: [PATCH 082/108] Refresh the tracked IVC bench dump for the Lagrange scratch layout Same regeneration run as the fixture promotion; keeps the tracked target/ivc-keccak-solidity-dump render in sync with the template. Co-Authored-By: Claude Opus 5 --- .../Halo2Verifier.sol | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol index 6f66ad7c7..48f05f35a 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol @@ -161,6 +161,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0xb4e0; uint256 internal constant TRACE_U256_MPTR = 0xe340; // ---------------------------------------------------------------------- @@ -547,16 +551,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { @@ -615,7 +637,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1422,8 +1444,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x0300) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1433,11 +1457,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1448,9 +1472,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0140) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1473,8 +1497,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0140)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0140)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -2205,7 +2229,7 @@ contract Halo2Verifier { // If either original equation is bad, this combined equation // holds for at most one alpha in Fr. { - let batch_ptr := 0x0100 + let batch_ptr := 0x1000 // Domain || KZG rhs/lhs || accumulator rhs/lhs. mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) From d6b248e37cbb5d8e18f794d2ac914d54d1d9a557 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 6 Aug 2026 11:25:39 +0100 Subject: [PATCH 083/108] Regenerate the Moonlight wrap fixture on the registered Lagrange scratch layout Re-render fixtures/moonlight-wrap from commit 3fb6d84 via the Moonlight wrap bench (origin/codex/wrap-bench-cherry-picks at 1940ea9, run in a temporary worktree) so the checked-in point_pair verifier uses the planner-registered LAGRANGE_DENOMS_MPTR region. Halo2VerifyingKey.sol is byte-identical to the previous render; calldata.bin carries the fresh proof (same 8516-byte layout). The trace-enabled run matched all 244 native Rust/Solidity trace points, differentially validating the repointed Lagrange block, and the fresh proof verified on revm Prague in 1,279,482 gas (+1,671 vs the previous fixture, memory-expansion cost of the relocated denominator run). Both ivc_accumulator_replay arms pass against the new sources. Co-Authored-By: Claude Opus 5 --- .../fixtures/moonlight-wrap/Halo2Verifier.sol | 50 +++++++++++++----- .../fixtures/moonlight-wrap/README.md | 4 +- .../fixtures/moonlight-wrap/calldata.bin | Bin 8516 -> 8516 bytes 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol index 026c4e8a6..c80ed093b 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol @@ -153,6 +153,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0xb140; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0xb140; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0xb580; uint256 internal constant TRACE_U256_MPTR = 0xe340; // ---------------------------------------------------------------------- @@ -524,16 +528,34 @@ contract Halo2Verifier { // Forward pass: scratch stores prefix products up to, but not // including, the final element. `gp` becomes the total product. + // + // Match the single-element path: reject non-canonical words + // (x >= r) instead of letting mulmod reduce them silently, so + // accept/reject semantics do not depend on batch length. let gp_mptr := scratch_mptr let gp := mload(mptr_start) + if iszero(lt(gp, r)) { + ret := 0 + leave + } let mptr := add(mptr_start, 0x20) for {} lt(mptr, sub(mptr_end, 0x20)) {} { - gp := mulmod(gp, mload(mptr), r) + let x := mload(mptr) + if iszero(lt(x, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x, r) mstore(gp_mptr, gp) mptr := add(mptr, 0x20) gp_mptr := add(gp_mptr, 0x20) } - gp := mulmod(gp, mload(mptr), r) + let x_last := mload(mptr) + if iszero(lt(x_last, r)) { + ret := 0 + leave + } + gp := mulmod(gp, x_last, r) // A zero total product means at least one denominator was // zero, so no batch inverse exists. if iszero(gp) { @@ -592,7 +614,7 @@ contract Halo2Verifier { // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x0320 + let scratch := 0x1220 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -1393,8 +1415,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x03a0) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1404,11 +1428,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1419,9 +1443,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0140) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1444,8 +1468,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0140)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0140)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -3582,7 +3606,7 @@ contract Halo2Verifier { // If either original equation is bad, this combined equation // holds for at most one alpha in Fr. { - let batch_ptr := 0x0100 + let batch_ptr := 0x1000 // Domain || KZG rhs/lhs || accumulator rhs/lhs. mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 0eaeca341..614c9cebe 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -14,12 +14,12 @@ the replay deploys the verifier with the verifying key alone. | Field | Value | | --- | --- | -| Source commit | `9bf8c51` | +| Source commit | `3fb6d84` | | Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | | Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | | Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | | Public inputs | 19 (accumulator occupies the trailing 8 words) | -| Verified on-chain | yes, 1,277,811 gas under revm Prague | +| Verified on-chain | yes, 1,279,482 gas under revm Prague | | Native/Solidity trace | 244 trace points matched | ## Regenerating diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin b/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin index b7b53e880f17a7187619a670ee5b1ac5ccf58ae0..55dbae62e6963dfa4e7abf45201a8c5dd2cdf2fd 100644 GIT binary patch literal 8516 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 From bee1833ecd100c3fe14f96e1b4441c650d59f87b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 6 Aug 2026 12:08:15 +0100 Subject: [PATCH 084/108] ci: fix changelog, formatting, and docs --- aggregation/CHANGELOG.md | 1 + proofs/CHANGELOG.md | 1 + proofs/solidity-verifier/src/builder/api.rs | 10 +++--- .../src/lowering/abi/proof.rs | 12 +++---- .../src/lowering/encoding/mod.rs | 6 ++-- .../src/lowering/layout/memory.rs | 8 +++-- .../src/lowering/protocol/mod.rs | 9 ++--- .../src/lowering/quotient.rs | 13 +++---- .../lowering/quotient_numerator/vm/certify.rs | 8 ++--- .../src/lowering/quotient_numerator/vm/mod.rs | 36 ++++++++++--------- .../quotient_numerator/vm/reference.rs | 3 +- .../solidity-verifier/src/lowering/tests.rs | 4 ++- proofs/solidity-verifier/src/test.rs | 12 +++---- .../tests/ivc_accumulator_replay.rs | 5 +-- 14 files changed, 70 insertions(+), 58 deletions(-) diff --git a/aggregation/CHANGELOG.md b/aggregation/CHANGELOG.md index 0c6bd7622..7183efcf3 100644 --- a/aggregation/CHANGELOG.md +++ b/aggregation/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview * truncated_challenges feature to allow --all-features compilation [#146](https://github.com/midnightntwrk/midnight-zk/pull/146) * Rebase to new `circuits/` with `keccak` and `blake2b` [#135](https://github.com/midnightntwrk/midnight-zk/pull/135) ### Fixed +* Restore the transcript input bound required by `LightAggregator::verify`. * Fix cost model to pass correct number of committed instances [#280](https://github.com/midnightntwrk/midnight-zk/pull/280) ### Changed diff --git a/proofs/CHANGELOG.md b/proofs/CHANGELOG.md index 0037caefa..cc85f592a 100644 --- a/proofs/CHANGELOG.md +++ b/proofs/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Blind logup multiplicities polynomial on non-usable rows for ZK [#312](https://github.com/midnightntwrk/midnight-zk/pull/312) ### Changed +* Rework the Solidity verifier lowering pipeline and refresh its generated fixtures. * Simplify `CommitmentReference` by removing unused `Chopped` variant [#314](https://github.com/midnightntwrk/midnight-zk/pull/314) * Split linearization polynomial into non-constant and constant parts, removing the generator point from the MSM [#313](https://github.com/midnightntwrk/midnight-zk/pull/313) * Remove unnecessary polynomial padding in KZG multi-open [#276](https://github.com/midnightntwrk/midnight-zk/pull/276) diff --git a/proofs/solidity-verifier/src/builder/api.rs b/proofs/solidity-verifier/src/builder/api.rs index 6eee59cb2..47b178786 100644 --- a/proofs/solidity-verifier/src/builder/api.rs +++ b/proofs/solidity-verifier/src/builder/api.rs @@ -53,11 +53,11 @@ impl<'a> SolidityGenerator<'a> { // then `fixed_comm_mptr + i * G1_BYTES` per fixed base, then the // permutation commitments. Two tail lengths break that mapping: // - // * Too long: the generated fixed-base pointers run past the end - // of the fixed-commitment region, silently aliasing permutation - // commitments and then arbitrary VK payload words as G1 bases. - // * Shorter than `-G` plus the permutation commitments: the base - // count underflows in the artifact emitter. + // * Too long: the generated fixed-base pointers run past the end of the + // fixed-commitment region, silently aliasing permutation commitments and + // then arbitrary VK payload words as G1 bases. + // * Shorter than `-G` plus the permutation commitments: the base count + // underflows in the artifact emitter. // // A tail inside the range is left alone -- it covers a prefix of // the fixed commitments, which keeps every pointer in region. diff --git a/proofs/solidity-verifier/src/lowering/abi/proof.rs b/proofs/solidity-verifier/src/lowering/abi/proof.rs index 61ba2ae6a..d841dffe1 100644 --- a/proofs/solidity-verifier/src/lowering/abi/proof.rs +++ b/proofs/solidity-verifier/src/lowering/abi/proof.rs @@ -309,12 +309,12 @@ impl TranscriptBufferLayout { /// Derive transcript-buffer bounds from proof calldata shape and instances. /// /// `phase_challenge_counts[i]` is the number of Fiat-Shamir challenges the - /// native schedule squeezes for user phase `i` (i.e. `num_user_challenges`). - /// It selects which advice commitments share the pre-first-squeeze run: a - /// phase that owns no challenge does not trigger a squeeze, so its advices - /// accumulate into the same run as the following phase's. An empty slice is - /// treated as "no phase owns a challenge", which sums every advice phase as - /// a safe upper bound. + /// native schedule squeezes for user phase `i` (i.e. + /// `num_user_challenges`). It selects which advice commitments share + /// the pre-first-squeeze run: a phase that owns no challenge does not + /// trigger a squeeze, so its advices accumulate into the same run as + /// the following phase's. An empty slice is treated as "no phase owns a + /// challenge", which sums every advice phase as a safe upper bound. pub(crate) fn from_proof_layout( proof: &ProofCalldataLayout, num_instances: usize, diff --git a/proofs/solidity-verifier/src/lowering/encoding/mod.rs b/proofs/solidity-verifier/src/lowering/encoding/mod.rs index c3a63a5ca..8918484ec 100644 --- a/proofs/solidity-verifier/src/lowering/encoding/mod.rs +++ b/proofs/solidity-verifier/src/lowering/encoding/mod.rs @@ -141,15 +141,15 @@ impl ConstraintSystemMeta { /// /// Panics if the constraint system is outside the supported verifier shape. /// Use [`ConstraintSystemMeta::try_new`] on fallible paths. Production - /// codegen goes through `SolidityGenerator::try_new`, which promises a typed - /// error, so this panicking form is test-only. + /// codegen goes through `SolidityGenerator::try_new`, which promises a + /// typed error, so this panicking form is test-only. #[cfg(test)] pub(crate) fn new(cs: &ConstraintSystem, nb_committed_instances: usize) -> Self { Self::try_new(cs, nb_committed_instances) .unwrap_or_else(|err| panic!("invalid protocol plan: {err}")) } - /// Fallible counterpart of [`ConstraintSystemMeta::new`]. + /// Fallible counterpart of the test-only `ConstraintSystemMeta::new`. pub(crate) fn try_new( cs: &ConstraintSystem, nb_committed_instances: usize, diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 233fb4ecd..50039236d 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -642,8 +642,7 @@ impl VerifierMemoryLayout { .max() .expect("constructor G1MSM smoke bounds are non-empty"); let batch_invert_len = batch_invert_scratch_bytes(meta, config.num_instances); - let lagrange_denoms_len = - batch_invert_input_words(meta, config.num_instances) * WORD_BYTES; + let lagrange_denoms_len = batch_invert_input_words(meta, config.num_instances) * WORD_BYTES; let quotient_return_len = (2 + meta.num_simple_selectors) * WORD_BYTES; let mut arena = MemoryArena::default(); @@ -1736,7 +1735,10 @@ mod tests { // num_instances + |rotation_last| denominators plus the trailing // `x_n - 1` word. assert_eq!(region.len, (5 + 3 + 1) * WORD_BYTES); - assert_eq!(region.lifetime, MemoryLifetime::Phase(MemoryPhase::LagrangeBatchInvert)); + assert_eq!( + region.lifetime, + MemoryLifetime::Phase(MemoryPhase::LagrangeBatchInvert) + ); assert_eq!(layout.lagrange_denoms_mptr, region.start); // Sequential same-phase allocation: the run sits directly above the // prefix-product scratch, which itself stays pinned to the selector diff --git a/proofs/solidity-verifier/src/lowering/protocol/mod.rs b/proofs/solidity-verifier/src/lowering/protocol/mod.rs index ba89d3b0a..42cd838c6 100644 --- a/proofs/solidity-verifier/src/lowering/protocol/mod.rs +++ b/proofs/solidity-verifier/src/lowering/protocol/mod.rs @@ -325,9 +325,9 @@ impl ProtocolPlan { /// The plan preserves that order so the Solidity transcript and proof /// cursors stay byte-compatible with the Rust verifier. /// - /// Panics if the resulting plan fails [`ProtocolPlan::validate`]. Callers on - /// a fallible path — notably [`SolidityGenerator::try_new`], which promises - /// a typed error for unsupported constraint systems — must use + /// Panics if the resulting plan fails [`ProtocolPlan::validate`]. Callers + /// on a fallible path — notably [`SolidityGenerator::try_new`], which + /// promises a typed error for unsupported constraint systems — must use /// [`ProtocolPlan::try_from_constraint_system`] instead. Every production /// path is fallible, so this panicking form is test-only. #[cfg(test)] @@ -339,7 +339,8 @@ impl ProtocolPlan { .unwrap_or_else(|err| panic!("invalid protocol plan: {err}")) } - /// Fallible counterpart of [`ProtocolPlan::from_constraint_system`]. + /// Fallible counterpart of the test-only + /// `ProtocolPlan::from_constraint_system`. /// /// Returns the validation failure rather than panicking, so constraint /// systems outside the supported verifier shape can be surfaced as a typed diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index b9b0bf28e..e0d295d68 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -608,15 +608,16 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { /// This is a size/gas PROXY consumed only by the native-vs-VM gate /// selection heuristic (native_gate_candidates); it is never emitted. The /// real native blocks are produced by compact_quotient_computation_blocks - /// with `selector_fold.gap_for(identity)`, but that fold plan does not exist - /// yet at selection time (it is derived from the selection outcome), so we - /// use a fixed proxy gap: Some(1) for selector targets, None otherwise. + /// with `selector_fold.gap_for(identity)`, but that fold plan does not + /// exist yet at selection time (it is derived from the selection + /// outcome), so we use a fixed proxy gap: Some(1) for selector targets, + /// None otherwise. /// /// Any divergence between this proxy and the eventual `gap_for` only /// perturbs which gates get promoted to native callbacks; it can never - /// change the correctness of the generated verifier, because actual emission - /// always uses the real gap. Do not "fix" this to call `gap_for` here: the - /// plan is intentionally unavailable at this point. + /// change the correctness of the generated verifier, because actual + /// emission always uses the real gap. Do not "fix" this to call + /// `gap_for` here: the plan is intentionally unavailable at this point. fn native_identity_estimate_block(identity: &QuotientIdentity) -> Vec { let state_slots = QuotientStateSlots { eval_numer_mptr: 0x2000, diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs index a8348ec77..22dcc0456 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/certify.rs @@ -3,8 +3,8 @@ //! //! The quotient lowering runs a peephole optimizer: shape recognizers rewrite //! seven-limb foreign-field expressions into superinstructions, and a -//! run-compaction pass rewrites adjacent affine terms into counted opcodes. Both -//! are pure encoding choices that must preserve the evaluated polynomial +//! run-compaction pass rewrites adjacent affine terms into counted opcodes. +//! Both are pure encoding choices that must preserve the evaluated polynomial //! exactly. This module proves that they did, for the specific program this //! render is about to emit, by executing the finalized bytecode with the //! independent interpreter in [`super::reference`] and comparing each identity @@ -123,8 +123,8 @@ fn interpreted_exprs(plan: &QuotientProgramPlan) -> Vec<&QuotientExpr> { /// Certify that the emitted bytecode evaluates the planned identities. /// -/// Runs after [`super::validate_quotient_program`], which has already proven the -/// stream decodes and is stack-safe; this pass assumes well-formedness and +/// Runs after [`super::validate_quotient_program`], which has already proven +/// the stream decodes and is stack-safe; this pass assumes well-formedness and /// checks *meaning*. pub(crate) fn certify_quotient_program( plan: &QuotientProgramPlan, diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs index 825714ab9..c993c5351 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/mod.rs @@ -1385,14 +1385,16 @@ impl QuotientProgramBuilder { true } - /// Emit `Σ terms[i]` with generic stack ops, leaving one value on the stack. + /// Emit `Σ terms[i]` with generic stack ops, leaving one value on the + /// stack. /// /// Each entry is one recognized affine/bilinear term (a scaled memory load /// or product), so emitting it cannot re-enter the limb-decomposition - /// peephole, and its coefficients use `emit_const`'s u16-capable slots. This - /// is the panic-free fallback for a recognized limb shape whose coefficients - /// no longer fit one-byte constant slots after intervening emission. The - /// slice is always non-empty (a recognized subshape uses at least one term). + /// peephole, and its coefficients use `emit_const`'s u16-capable slots. + /// This is the panic-free fallback for a recognized limb shape whose + /// coefficients no longer fit one-byte constant slots after intervening + /// emission. The slice is always non-empty (a recognized subshape uses + /// at least one term). fn emit_affine_terms(&mut self, terms: &[QuotientExpr]) { for (idx, term) in terms.iter().enumerate() { self.emit_expr(term); @@ -2247,20 +2249,20 @@ impl QuotientReadModel { /// Bounds-check every memory pointer a finalized program loads from. /// /// `validate_quotient_const_slots` covers constant-table indices; this covers -/// the other half of the operand space. The pointers baked into the bytecode are -/// absolute generated addresses, so an emitter or planner regression that +/// the other half of the operand space. The pointers baked into the bytecode +/// are absolute generated addresses, so an emitter or planner regression that /// computes one incorrectly makes the deployed verifier read a live challenge, /// commitment word, or uninitialized scratch as a gate value -- silently /// flipping accept/reject rather than reverting. /// -/// Note what the render-time certification in [`super::certify`] does *not* +/// Note what the render-time certification in [`certify`] does *not* /// cover here. It compares the bytecode against the `QuotientExpr` tree it was -/// lowered from, and [`super::reference::QuotientRefMemory`] derives a value +/// lowered from, and [`reference::QuotientRefMemory`] derives a value /// from whatever address it is handed, so a pointer that disagrees between the /// two shows up as a value mismatch. A pointer that is already wrong *in the -/// tree* -- a `Data` or planner bug upstream of the VM -- makes both sides agree -/// on the wrong address and certifies cleanly. This check is what catches that -/// class. +/// tree* -- a `Data` or planner bug upstream of the VM -- makes both sides +/// agree on the wrong address and certifies cleanly. This check is what catches +/// that class. /// /// Run after [`validate_quotient_program`], whose byte-length validation /// guarantees the operand layout walked here is in bounds. @@ -2309,11 +2311,11 @@ fn describe_read_windows(model: &QuotientReadModel) -> String { /// Visit every memory address one instruction loads from. /// -/// Unlike [`validate_quotient_const_slots`], the fallback arm is an error rather -/// than a no-op: a new opcode with pointer operands that forgets to extend this -/// walker fails the render instead of silently losing its bounds check. -/// `quotient_pointer_walker_covers_every_opcode` pins that the walker is total -/// over `QUOTIENT_OPCODE_TABLE`. +/// Unlike [`validate_quotient_const_slots`], the fallback arm is an error +/// rather than a no-op: a new opcode with pointer operands that forgets to +/// extend this walker fails the render instead of silently losing its bounds +/// check. `quotient_pointer_walker_covers_every_opcode` pins that the walker is +/// total over `QUOTIENT_OPCODE_TABLE`. pub(crate) fn quotient_read_pointers( bytes: &[u8], idx: usize, diff --git a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs index ceb954afb..baf4eaf22 100644 --- a/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs +++ b/proofs/solidity-verifier/src/lowering/quotient_numerator/vm/reference.rs @@ -358,7 +358,8 @@ fn affine_linear_term( Ok((const_at(consts, slot, idx)? * mem.literal(ptr), 3)) } -/// Decode one `mload(lhs) * mload(rhs) * const` term and return its byte length. +/// Decode one `mload(lhs) * mload(rhs) * const` term and return its byte +/// length. fn affine_product_term( bytes: &[u8], consts: &[U256], diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 9a51f337e..bd18947ef 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -721,7 +721,9 @@ fn generator_accepts_instance_counts_beyond_the_old_lagrange_cliff() { .expect("large instance counts are supported with a registered denominator region"); let plan = generator.inputs().lowering_plan(); - plan.memory.validate().expect("layout with a 200-instance denominator run is valid"); + plan.memory + .validate() + .expect("layout with a 200-instance denominator run is valid"); generator .render(crate::RenderOptions::default()) diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 9e30b5e3c..2eb2469c3 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -4508,12 +4508,12 @@ fn env_flag_enabled(name: &str) -> bool { /// circuit stay on the multi-limb layout). The consequence is that /// `srs_for_test` cannot be used under that feature: it calls `load_srs`, which /// decides whether to extend the monomial basis from *zk-stdlib's own* -/// `single-h-commitment` setting. With the feature off there, `load_srs` returns -/// a plain `2^k`-element SRS, while the prover -- compiled from `midnight-proofs` -/// *with* the feature -- commits to one full-degree quotient polynomial and -/// needs `k + ceil(log2(cs_degree - 1))` monomial powers. The mismatch surfaces -/// as `SrsError(64, 252)` at proof generation, i.e. long after the VK builds -/// cleanly at `k`. +/// `single-h-commitment` setting. With the feature off there, `load_srs` +/// returns a plain `2^k`-element SRS, while the prover -- compiled from +/// `midnight-proofs` *with* the feature -- commits to one full-degree quotient +/// polynomial and needs `k + ceil(log2(cs_degree - 1))` monomial powers. The +/// mismatch surfaces as `SrsError(64, 252)` at proof generation, i.e. long +/// after the VK builds cleanly at `k`. /// /// Mirror `load_srs`'s single-h branch here instead, so `--all-features` is a /// working configuration rather than one that fails inside the prover. diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs index 90687f574..fcb83a763 100644 --- a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 //! CI-runnable adversarial replay of the public-accumulator decode path. //! -//! The accumulator decoder in `templates/partials/verifier/AccumulatorHelpers.yul` -//! had no executing test coverage. The tests that looked like they covered it +//! The accumulator decoder in +//! `templates/partials/verifier/AccumulatorHelpers.yul` had no executing test +//! coverage. The tests that looked like they covered it //! -- `accumulator_decoder_rejects_noncanonical_infinity` and friends in //! `src/lowering/tests.rs` -- are `verifier_template.contains("...")` string //! greps over the raw template. They assert the guard *text* exists and never From 07d9a9dfc4d8452702ead8cb407811670c612211 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Fri, 7 Aug 2026 23:37:49 +0100 Subject: [PATCH 085/108] Cover instance binding and the two unreachable accumulator decode guards The replay suite mutated ~229 inputs per fixture but every one was caught by an independent range, packing, or framing check, so nothing exercised the verifier's most important negative property: a valid proof must not verify against different public inputs. If instance absorption regressed -- wrong order, count, endianness, or dropped entirely -- the whole suite would still have passed. The only binding test lived in tests/ivc_keccak_solidity.rs behind HALO2_SOLIDITY_RUN_IVC_BENCH=1 and a 300 MB SRS, so it never ran in CI. Add three CI-runnable cases, all replaying the frozen fixtures: - Instance binding: flip the low bit of each non-accumulator public input to the nearest other canonical value (15 cases across both fixtures -- acc_offset is 4 for ivc, 11 for moonlight-wrap). Nothing but the Fiat-Shamir challenges can reject these. - Identity flag on x with an honest y. write_encoded_identity always wrote the full canonical quadruple, so is_acc_encoded_identity short-circuited and load_acc_point's malformed-infinity check was never reached with x_is_id set. - Both coordinates carrying the codec's p-1 zero sentinel without the identity flag, which every packing and field check accepts, leaving the decoded_zero guard as the only separation between the codec's zero and EIP-2537's point at infinity. Both decode guards were previously covered only by string greps over the template in src/lowering/tests.rs. Because accumulator words are themselves absorbed into the transcript, any mutation there also perturbs the challenges, so a bare revert cannot distinguish "the guard fired" from "the transcript changed" -- deleting a guard would leave its test passing. Anchor the new assertions on the accepted run's gas instead: a decode guard fires before the transcript (~311k, under half of a full run) while a binding failure costs a complete verification (~1.287m). Measured separation is ~4x. Co-Authored-By: Claude Opus 5 --- .../tests/ivc_accumulator_replay.rs | 175 +++++++++++++++++- 1 file changed, 172 insertions(+), 3 deletions(-) diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs index fcb83a763..86d4a1ea7 100644 --- a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -112,9 +112,9 @@ fn read_u256_word(calldata: &[u8], offset: usize) -> u64 { u64::from_be_bytes(word[24..].try_into().unwrap()) } -fn assert_reverts(outcome: CallOutcome, case: &str) { +fn assert_reverts(outcome: CallOutcome, case: &str) -> u64 { match outcome { - CallOutcome::Revert { .. } => {} + CallOutcome::Revert { gas_used, .. } => gas_used, CallOutcome::Success { output, .. } => panic!( "{case}: verifier accepted a proof it must reject (output = 0x{})", hex::encode(output) @@ -125,6 +125,45 @@ fn assert_reverts(outcome: CallOutcome, case: &str) { } } +/// Assert a revert that happened *before* the transcript was built. +/// +/// Every accumulator word is also absorbed into the Keccak transcript, so any +/// mutation inside the instance region changes the challenges and would fail at +/// the pairing even if its dedicated decoder guard were deleted. Anchoring on +/// gas distinguishes the two: `validate_public_accumulator` runs before the +/// transcript, so a guard that fires costs a small fraction of a full run. +/// Without this, a deleted guard would leave the test passing for the wrong +/// reason. +fn assert_reverts_before_transcript(outcome: CallOutcome, accepted_gas: u64, case: &str) { + let gas_used = assert_reverts(outcome, case); + let ceiling = accepted_gas / 2; + assert!( + gas_used < ceiling, + "{case}: reverted after {gas_used} gas, but an accumulator decode guard should \ + fire before the transcript (under {ceiling}, vs {accepted_gas} for a full \ + accepted run). This revert came from a later stage, so the guard under test \ + may no longer be reachable." + ); +} + +/// Assert a revert that happened only *after* the full verification ran. +/// +/// This is the signature of a Fiat-Shamir binding failure: the input was +/// structurally valid, so every range, packing, and framing check passed and +/// the proof failed at the final pairing. A cheap revert here would mean some +/// earlier check rejected the input instead, which proves nothing about +/// binding. +fn assert_reverts_at_pairing(outcome: CallOutcome, accepted_gas: u64, case: &str) { + let gas_used = assert_reverts(outcome, case); + let floor = accepted_gas / 4 * 3; + assert!( + gas_used > floor, + "{case}: reverted after only {gas_used} gas (expected over {floor}, near the \ + {accepted_gas} of a full accepted run). An early check rejected this input, so \ + it does not exercise instance binding." + ); +} + /// The IVC decider carries explicit lhs/rhs scalars /// (`AccumulatorEncoding::new`). #[test] @@ -231,13 +270,20 @@ fn replay_accumulator_fixture(fixture: &str) { None => evm.create_with_address_arg(verifier_code, vk_address), }; + // Cost of a full accepted run, used below to attribute reverts to a stage: + // an accumulator decode guard fires long before this, a binding failure + // costs almost exactly this much. + let accepted_gas; match evm.try_call_with_gas(verifier_address, calldata.clone(), GAS_CAP) { - CallOutcome::Success { output, .. } => { + CallOutcome::Success { + output, gas_used, .. + } => { let expected: Vec = [vec![0u8; 31], vec![1]].concat(); assert_eq!( output, expected, "fixture proof should verify; the fixture and calldata may be out of sync" ); + accepted_gas = gas_used; } CallOutcome::Revert { gas_used, output } => panic!( "fixture proof was rejected (gas_used = {gas_used}, output = 0x{}); \ @@ -306,6 +352,65 @@ fn replay_accumulator_fixture(fixture: &str) { ); } + // The canonical infinity above short-circuits at `is_acc_encoded_identity`, + // so it never enters `load_acc_point`'s coordinate-decoding branch. The two + // cases below are the non-canonical routes to the same nulled operand, and + // each is caught by a different guard inside that branch. + // + // 1. Identity flag on `x`, honest `y`. `x` decodes to zero and sets + // `x_is_id`, but `y` does not, so the malformed-infinity check + // (`iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))`) must reject. Without + // it, `load_acc_point` would still write EIP-2537 infinity into the + // accumulator slot while `y` was arbitrary. + for (case, point_word) in [ + ( + "LHS accumulator identity flag with honest y", + first_acc_word, + ), + ( + "RHS accumulator identity flag with honest y", + rhs_first_word, + ), + ] { + let mut flagged = calldata.clone(); + // Only the two `x` words; `y` keeps its honest value. + write_encoded_coordinate(&mut flagged, point_word, true, &verifier_solidity); + assert_reverts_before_transcript( + evm.try_call_with_gas(verifier_address, flagged, GAS_CAP), + accepted_gas, + case, + ); + } + + // 2. Both coordinates carry the codec's zero sentinel (`p - 1`) with no + // identity flag. Every packing and field check accepts this, so the + // `decoded_zero` guard is the only thing separating "the codec's zero" + // from "EIP-2537's point at infinity". + for (case, point_word) in [ + ( + "LHS accumulator decodes to zero without the identity flag", + first_acc_word, + ), + ( + "RHS accumulator decodes to zero without the identity flag", + rhs_first_word, + ), + ] { + let mut decoded_zero = calldata.clone(); + write_encoded_coordinate(&mut decoded_zero, point_word, false, &verifier_solidity); + write_encoded_coordinate( + &mut decoded_zero, + point_word + 2 * 0x20, + false, + &verifier_solidity, + ); + assert_reverts_before_transcript( + evm.try_call_with_gas(verifier_address, decoded_zero, GAS_CAP), + accepted_gas, + case, + ); + } + // --------------------------------------------------------------------- // Calldata framing. These attacks need no layout knowledge at all. // --------------------------------------------------------------------- @@ -442,6 +547,45 @@ fn replay_accumulator_fixture(fixture: &str) { &format!("public input {index} set to the Fr modulus"), ); } + + // --------------------------------------------------------------------- + // Instance binding: a valid proof must not verify against different public + // inputs. + // + // Every other mutation in this file is independently caught by a range, + // packing, or framing check, so all of them would still revert if instance + // absorption regressed -- wrong order, wrong count, wrong endianness, or + // instances simply never absorbed. This case is the only one that fails + // *because* the transcript binds the instances: the mutated word stays a + // canonical field element and well inside its slot, so nothing but the + // Fiat-Shamir challenges can distinguish it. + // + // The accumulator words are excluded because they have their own decode + // guards; a revert there would not be attributable to binding. + assert!( + final_acc_offset > 0, + "fixture has no non-accumulator public input to test instance binding with" + ); + for index in 0..final_acc_offset { + let at = first_instance_word + index * 0x20; + let mut rebound = calldata.clone(); + // Flip the low bit: the nearest possible value, still canonical. + rebound[at + 31] ^= 0x01; + assert!( + rebound[at..at + 0x20] < fr_modulus[..], + "public input {index} left non-canonical by the bit flip; pick another mutation" + ); + assert_ne!( + &rebound[at..at + 0x20], + &calldata[at..at + 0x20], + "public input {index} was not actually modified" + ); + assert_reverts_at_pairing( + evm.try_call_with_gas(verifier_address, rebound, GAS_CAP), + accepted_gas, + &format!("public input {index} changed to a different canonical value"), + ); + } } /// EIP-2537 padded G1: `x_hi, x_lo, y_hi, y_lo`. @@ -503,6 +647,31 @@ fn solidity_constant(source: &str, name: &str) -> [u8; 0x20] { /// This is the exact quadruple `is_acc_encoded_identity` accepts: `p - 1` in /// every packed word, with the identity flag (one radix base) folded into the /// first word of `x`. +/// Overwrite the two packed words of one accumulator coordinate at +/// `coord_word` with the codec's zero sentinel `p - 1`, optionally folding in +/// the identity flag (one radix base) as the encoder does for `x`. +/// +/// Unlike [`write_encoded_identity`] this touches a single coordinate, so the +/// result is deliberately *not* the canonical infinity quadruple and does not +/// short-circuit `is_acc_encoded_identity`. +fn write_encoded_coordinate( + calldata: &mut [u8], + coord_word: usize, + with_identity_flag: bool, + verifier_solidity: &str, +) { + let first = if with_identity_flag { + "BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG" + } else { + "BLS_P_MINUS_ONE_PACKED_0" + }; + for (index, name) in [first, "BLS_P_MINUS_ONE_PACKED_1"].into_iter().enumerate() { + let word = solidity_constant(verifier_solidity, name); + let at = coord_word + index * 0x20; + calldata[at..at + 0x20].copy_from_slice(&word); + } +} + fn write_encoded_identity(calldata: &mut [u8], point_word: usize, verifier_solidity: &str) { for (index, name) in [ "BLS_P_MINUS_ONE_PACKED_0_WITH_ID_FLAG", From 4ae80536dbdca883232ebfd3ea729cbfb1a77635 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Sat, 8 Aug 2026 21:57:47 +0100 Subject: [PATCH 086/108] docs: add independent architecture review and redesign proposals (2026-08) Two review-snapshot documents for the Solidity verifier code generator: - docs/architecture/ARCHITECTURE_REVIEW_2026-08.md: as-built architecture (layering, lowering pipeline, design decisions, generated runtime, trust/assurance table, cross-cutting contracts). - docs/plans/REDESIGN_PROPOSALS_2026-08.md: robustness/quality assessment with per-finding verified evidence, and prioritized P0-P3 redesign proposals (CI test selection, runtime FMP guard, Result threading, plan caching, operand-layout descriptor, statement IR, doc refresh). Co-Authored-By: Claude Fable 5 --- .../ARCHITECTURE_REVIEW_2026-08.md | 466 ++++++++++++++++ .../docs/plans/REDESIGN_PROPOSALS_2026-08.md | 498 ++++++++++++++++++ 2 files changed, 964 insertions(+) create mode 100644 proofs/solidity-verifier/docs/architecture/ARCHITECTURE_REVIEW_2026-08.md create mode 100644 proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md diff --git a/proofs/solidity-verifier/docs/architecture/ARCHITECTURE_REVIEW_2026-08.md b/proofs/solidity-verifier/docs/architecture/ARCHITECTURE_REVIEW_2026-08.md new file mode 100644 index 000000000..b47eac771 --- /dev/null +++ b/proofs/solidity-verifier/docs/architecture/ARCHITECTURE_REVIEW_2026-08.md @@ -0,0 +1,466 @@ +# Halo2 Solidity Verifier Code Generator — Architecture Review + +> Independent as-built architecture review, produced 2026-08-08 against the +> `misc-fixes` branch. This document describes the system as it exists in the +> source tree, from a full multi-reviewer pass over every module; it is a +> snapshot, not a maintained spec. The maintained specification is +> [`LOWERING_ARCHITECTURE_SPEC.md`](./LOWERING_ARCHITECTURE_SPEC.md); +> design-choice notes are in [`ARCHITECTURE.md`](./ARCHITECTURE.md). The +> companion assessment and redesign proposals are in +> [`../plans/REDESIGN_PROPOSALS_2026-08.md`](../plans/REDESIGN_PROPOSALS_2026-08.md). +> Reported line numbers and counts are as of this snapshot; verify against +> current sources before relying on them. + +## 1. What this crate is + +`halo2_solidity_verifier` is a **code generator**, not a verifier library. It +consumes a `midnight-proofs` verifying key plus BLS12-381 KZG parameters and +emits up to three Solidity contracts: + +| Artifact | Role | +| --- | --- | +| `Halo2Verifier.sol` | The verifier: one `verifyProof(bytes,uint256[])` entry point wrapping a single terminal Yul assembly block. | +| `Halo2VerifyingKey.sol` | Optional split VK data contract: runtime bytecode = `0xfe` (INVALID) prefix + the raw VK payload (header words, compact quotient VM constants + bytecode, fixed/permutation commitments). | +| `Halo2QuotientEvaluator.sol` | Optional split quotient evaluator: a `fallback()` that receives a raw verifier memory frame by calldata, re-runs the quotient VM, and returns `[magic, -nu_y(x), selector buckets]`. | + +It also provides the off-chain per-proof shim: `repack_proof` / +`encode_calldata` convert a native compressed proof (48-byte G1s, LE scalars) +into the EIP-2537-padded big-endian calldata the generated verifier reads. + +The supported protocol envelope is deliberately narrow and validated up +front: Midfall/Midnight KZG proofs on BLS12-381, exactly one identity-committed +instance column plus one non-committed public-input column, no rotated instance +queries, at least one advice column, Keccak transcript, optional IVC +accumulator tail in radix-2^56 limbs (7 limbs × 56 bits, 4 limbs per word). +The generator emits exactly **one verifier shape** — there is no runtime +configurability in the artifact; every knob is resolved at generation time. + +Scale at this snapshot: ~35k lines of Rust (of which ~8.6k are tests inside +`src/`), ~3.8k lines of Askama templates, 18 template files, 37 documentation +files, 2 libFuzzer targets, 7 integration test files, and committed replay +fixtures for IVC and Moonlight-wrap shapes. + +## 2. System at a glance + +```mermaid +flowchart TD + subgraph public["builder/ + api.rs + evm.rs (public facade)"] + A["SolidityGenerator::try_new\n(shape validation)"] --> B["VerifierBuildInputs\n(read-only snapshot)"] + end + subgraph lowering["lowering/ (private pipeline)"] + B --> C["ProtocolPlan\n(protocol/)"] + C --> D["ProofCalldataLayout +\nTranscriptBufferLayout (abi/)"] + C --> E["Quotient identity stream\n(quotient.rs + yul_emit.rs)"] + E --> F["Compact VM program\n(vm/mod.rs)"] + F --> G["VK payload w/ embedded\nprogram (vk.rs, layout/vk_payload.rs)"] + G --> H["VerifierMemoryLayout\n(layout/memory.rs)"] + C --> I["PCS query plan + Yul blocks\n(kzg/)"] + D & F & G & H & I --> J["LoweringPlan (plan.rs)\nconverged + invariant-checked\n+ certified"] + end + subgraph render["render models + Askama templates"] + J --> K["Halo2Verifier /\nHalo2VerifyingKey /\nHalo2QuotientEvaluator models\n(render/models.rs, artifacts.rs)"] + K --> L["templates/*.sol + *.yul\n→ Solidity source"] + end + subgraph perproof["per proof (off-chain)"] + J --> M["RepackedProofLayoutPlan\n(calldata.rs)"] + M --> N["verifyProof calldata"] + end +``` + +Two properties define the architecture: + +1. **Layout-first, plan-once.** The generated Yul uses absolute memory + addresses and packed bytecode sections, so *every* address, offset, count, + and byte length is computed and validated in Rust before a single template + line renders. One converged `LoweringPlan` per `render()` call feeds the + verifier, the VK, and the quotient evaluator, so one call can never emit + artifacts from divergent plans (`src/builder/render.rs:34`). +2. **Templates consume facts.** Askama templates receive already-planned data + (pointers, counts, code-line vectors, opcode tables) and are forbidden by + convention from re-deriving layout. Every template constant traces to a + single Rust definition via `TemplateConstants` / `VkHeaderTemplateSlots`. + +## 3. Layering and dependency rules + +``` +src/lib.rs public exports, feature constants +src/api.rs public config/error/diagnostic types (no codegen logic) +src/builder/ thin validating facade: SolidityGenerator + api.rs try_new + shape validation, diagnostics entry points + render.rs render(RenderOptions) → RenderedArtifacts + repack.rs repack_proof / encode_calldata wrappers +src/lowering/ private pipeline (all pub(crate)) + protocol/ typed ProtocolPlan from the constraint system + abi/ proof calldata + transcript buffer layout + encoding/ ConstraintSystemMeta, Data, Ptr/Word/EcPoint handles, + EIP-2537 encoders + layout/ memory planner, VK header/payload section maps + quotient.rs quotient identity planning + routing + selector folds + quotient_numerator/ yul_emit.rs (identity Yul emitter), + vm/ (compact VM compiler, validators, reference + interpreter, certifier) + kzg/ PCS multi-open planner and Yul emitter + plan.rs LoweringPlan: convergence + cross-module invariants + vk.rs VK payload generation, convergence loops + artifacts.rs Askama model assembly + render/ models.rs (dumb template carriers + validators) + calldata.rs proof repacking + diagnostics.rs host-side manifests/counts +src/evm.rs calldata ABI encoder; pinned-solc + revm harness (evm feature) +templates/ Askama contract templates + partials +``` + +Dependency rules that hold in the imports (verified, not just documented): + +- `builder` → `lowering` only; **zero** reverse dependencies from `lowering` + into `builder`. +- All pipeline entry points are methods on `VerifierBuildInputs`, a `Copy`, + read-only snapshot of the generator's borrowed state + (`src/lowering/mod.rs:36`). +- `render/models.rs` structs are dumb carriers; planning types do not depend + on Askama. +- Templates reach Rust constants only through model fields; opcode/token bytes + come from `QUOTIENT_VM_SPEC` (`src/lowering/quotient_numerator/vm/mod.rs:908`), + the single ABI description shared by emitter, validators, tests, and + template rendering. + +## 4. The lowering pipeline, stage by stage + +### 4.1 Constructor validation (`builder/api.rs`) + +`SolidityGenerator::try_new` rejects, with typed `GeneratorError`s: missing +advice columns, any instance-column split other than 1 committed + 1 +non-committed, invalid accumulator limb schema (only 7×56 supported), +accumulator fixed-base scalar tails outside +`[1 + num_permutation_comms, 1 + num_permutation_comms + num_fixed_comms]` +(which would otherwise alias arbitrary VK payload words as G1 bases), +rotated instance queries, and any constraint-system shape +`ProtocolPlan::validate` refuses (~15 cross-field invariants, e.g. an advice +column absorbed but never opened). `new()` is the panicking wrapper. + +### 4.2 Protocol planning (`protocol/`) + +`ProtocolPlan::try_from_constraint_system` derives the typed source of truth: +commitment/eval read order in transcript order, the PCS query schedule (ending +in a synthetic Linearization query), per-family quotient identity counts, +phase remappings, the simple-selector column set, common-poly needs, and trace +IDs. Everything downstream — proof ABI, transcript sizing, quotient stream, +PCS sets — is derived from this plan, and `ConstraintSystemMeta` carries its +scalar summary with a `validate_against_protocol` cross-check. + +### 4.3 Proof ABI (`abi/proof.rs`) + +`ProofCalldataLayout` replays the protocol commitment order into byte offsets +(per-phase advice, lookup m/helpers/accumulators, permutation products, trash, +quotient limbs, evals, `f_com`, q_eval sets, public inputs), asserting order +drift. `TranscriptBufferLayout` conservatively sizes the streaming Keccak +buffer (largest absorb run between squeezes, at 128 bytes per uncompressed G1) +— this bound decides `VK_MPTR`, and an under-estimate would let the transcript +buffer overrun the VK region mid-verify (the comment at +`src/lowering/vk.rs:437` records exactly this historical bug class). + +### 4.4 Quotient identity planning (`quotient.rs`, `yul_emit.rs`) + +The `yul_emit::Evaluator` walks gates, permutation, lookup (LogUp), and trash +arguments in the canonical `partially_evaluate_identities` order, emitting +per-identity Yul lines **and** a typed `QuotientExpr` tree per identity, each +tagged `Main` (folds into the numerator accumulator) or `Selector(i)` (folds +into a simple-selector bucket). `quotient_program_plan` then routes each +identity to one of four execution representations: + +| Representation | What | Why | +| --- | --- | --- | +| Inline Yul prefix | First `DEFAULT_HYBRID_QUOTIENT_INLINE_IDENTITIES = 4` gates | Straight-line speed for the cheap head | +| Compact VM bytecode | Bulk of the identities | Code size: bytecode lives in the VK payload, not the verifier runtime | +| Native Yul callbacks | Knapsack-selected heavy gates (`DEFAULT_QUOTIENT_NATIVE_GATES = 4` budget) + the whole permutation/lookup families | Gas: loops with scratch tables beat interpretation for heavy shapes | +| Structured trash tail | Trash identities | Compressed fixed-shape tail | + +`validate_execution_manifest` re-expands the routed plan back to a flat +per-identity stream and proves position-by-position equality of index, source, +and target against the original — the routing is provably order-preserving. +`selector_fold_plan` computes per-bucket y-power gaps/tails so selector buckets +fold sparsely. Cost models used by the knapsack are explicitly documented as +proxies whose divergence cannot affect correctness. + +### 4.5 Compact quotient VM compilation (`quotient_numerator/vm/`) + +`QuotientProgramBuilder` lowers `QuotientExpr` trees into a byte-oriented +program plus a deduplicated Fr constant table: constant pooling (u16 slots with +a u8 fast path), stack-depth accounting, peepholes (pow5, fused add-mul +accumulators), and **structural** shape recognizers that rewrite 7-limb +foreign-field algebra (LIN7 / BILIN7 / MODARITH7 shapes) and affine sums into +superinstructions; a run-compaction pass turns ≥4 adjacent fused terms into +counted `RUN_*` opcodes. Recognizers never dispatch on gate names and always +have a value-equal generic fallback. + +The finalized bytecode passes a three-stage offline validator +(decode/operand-bounds/stack-effects; const-slot bounds; memory-pointer +whitelist against a `QuotientReadModel` of exactly the windows the verifier +populates), then two certification passes (§8). + +### 4.6 VK payload and convergence (`vk.rs`, `layout/vk_payload.rs`) + +The VK payload is a monotonic section map: 31-word header (digest, domain +constants, accumulator config, EIP-2537 G1/G2/−sG2 base points) built by a +checked `VkHeaderBuilder`, quotient constants, packed quotient program +(big-endian U256 words, padding verified on decode), fixed commitments, +permutation commitments. + +Two bounded fixed-point loops resolve circular size dependencies, failing +loudly on non-convergence: + +- `generate_vk` (≤8 iterations): program size depends on memory addresses, + which depend on VK length — reserve zero-filled sections, recompile, repeat + until the reservation covers the program. +- `meta_data_for_stable_static_layout` (≤3 iterations): `VK_MPTR` must sit + above the low-memory working set (transcript buffer, PCS scratch, pairing + frames, return buffers), which itself depends on planned metadata (including + the two-pass dummy-eval/point-set planning for `outer-fewer-point-sets`). + +`generate_base_vk` also asserts at build time that the SRS G1 base (sum of +`g_lagrange`) equals the canonical generator — otherwise the emitted `G1_BASE` +would diverge from the commitment base and the contract would enforce a +different pairing equation than the native verifier (`src/lowering/vk.rs:74-92`). + +### 4.7 Memory planning (`layout/memory.rs`) + +Because the generated Yul never uses the free-memory pointer for its main work +areas, `VerifierMemoryLayout::new` registers ~30 named regions in a +`MemoryArena`: fixed low-memory frames at `LOW_MEMORY_SCRATCH_START = 0x1000` +(transcript buffer, return words, pairing scratch, constructor smoke), +permanent bands (VK payload, challenges, theta window, decoded evals, +decompressed commitments), and phase-scoped scratch (batch inversion, quotient +VM stack, PCS tables/MSMs, accumulator MSM). Each region carries a lifetime: +`Permanent`, `Phase(p)`, or `PhaseSpan(a..=b)` over a 16-variant `MemoryPhase` +enum declared in verifier runtime order — the derived `Ord` is what makes +`MemoryLifetime::intersects` meaningful. `validate()` pins fixed pointers, +rejects regions below 0x1000, checks PCS window capacities (rotation points +≤ 28, x1 powers ≤ 65, q_eval sets ≤ 56), and runs pairwise overlap checking +gated by lifetime intersection — so intentional scratch aliasing across +disjoint phases is declared and machine-checked rather than coincidental. + +The 0x80–0x1000 band is deliberately left to solc: the terminal assembly block +carries a *factually false* `("memory-safe")` annotation (required to compile +without stack-too-deep), and disjointness from solc's via-IR spill window is +established by testing the compiled bytecode's memoryguard against the layout +(observed spill reservations up to 0x8e0; see §8 and the companion assessment). + +### 4.8 PCS planning and emission (`kzg/`) + +The KZG multi-open lowering mirrors `midnight-proofs` `multi_prepare`: +`queries()` resolves the typed plan sources to concrete memory handles; +optional dummy-query augmentation collapses rotation sets +(`outer-fewer-point-sets`); `construct_intermediate_sets_impl` simulates the +prover's set construction (dedup by pointer identity, cardinality-sorted); +`memory_requirements` sizes the scratch windows; `computations()` emits six Yul +blocks — rotation points `x·ω^rot`, x1 powers (rolled loop, optional 128-bit +truncation), per-set q_eval folds (rolled when >4 sets), `f_eval` via Horner +with a single-modexp Montgomery batch inversion, the fused final G1MSM through +precompile 0x0c, and pairing inputs `(π, final_com − v·G + x3·π)`. + +`validate_absorbed_g1_precompile_coverage` machine-checks the crate's central +soundness delegation: **every** proof G1 absorbed into Fiat-Shamir must later +be consumed by an EIP-2537 G1MSM or pairing input (which subgroup-check), +because the verifier itself never subgroup-checks; `G1ADD` (which does not) is +only ever applied to precompile outputs. + +### 4.9 Render models and templates (`render/models.rs`, `artifacts.rs`, `templates/`) + +`artifacts.rs` assembles the three Askama models from the converged plan and +calls their `validate_layout()` / `validate_payload_layout()` before rendering +(pointer/count cross-checks against the typed layouts, external-frame +containment, EIP-170 bound on the VK runtime). Templates are organized as one +contract shell per artifact plus partials in phase order: precompile smoke, +constructors (2×2: embedded/split VK × inline/external quotient, pinning +dependencies by `code.length` **and** `codehash`), VK loading + full ABI +calldata-shape validation, transcript parser, Lagrange block, quotient block +(dual-mode: inline VM or external staticcall over a raw frame), PCS injection, +accumulator batching, final pairing, trace/return. + +### 4.10 Per-proof repacking (`calldata.rs`, `evm.rs`) + +`repack_proof` decompresses each 48-byte G1 (rejecting invalid points), +pads to the 128-byte EIP-2537 form, rewrites LE scalars into canonical BE +words (rejecting non-canonical Fr with typed `RepackError`s carrying byte +offsets and hex payloads), preserving exactly the generator's group ordering; +`evm::encode_calldata` wraps the result in the `verifyProof(bytes,uint256[])` +ABI (selector `0x1e8e1e13`). + +## 5. Design decisions and their rationale + +1. **Narrow supported envelope, validated up front.** The generator refuses + at construction what the templates cannot verify at runtime. This converts + a whole class of "generated verifier silently wrong" into "generation + fails with a typed error." +2. **Static absolute memory layout.** Predictable, cheap Yul (no FMP + bookkeeping), auditable addresses, and a planner that can *prove* + non-overlap. The cost: the planner is load-bearing for memory safety, and + the 0x80–0x1000 solc band must be established out-of-band (§4.7). +3. **Compact quotient VM in the pinned VK payload.** The quotient block was + the dominant contract-size contributor (straight-line Yul put the IVC + verifier over EIP-170). Moving identity programs into VK data and + interpreting them trades gas for size; macro/run opcodes and limb + superinstructions claw the gas back (quotient section: 2.58M → 1.05M gas; + verifier runtime: 30,278 → ~12k bytes, each artifact below 24KB). +4. **Pinning by runtime length + codehash, both at construction and per + call.** The verifier accepts exactly one VK runtime hash and (in split + mode) one quotient evaluator hash. Deployment is a two-phase flow (render + evaluator → compile/deploy → re-render verifier with `ExternalPinned`); + the older unpinned APIs deliberately panic. +5. **Bounded convergence instead of two-pass guesswork.** Circular size + dependencies are resolved by explicit fixed-point loops that fail loudly, + and `LoweringPlan::new` re-checks the cross-module invariants convergence + was supposed to establish — including a *word-for-word* comparison of the + VK-embedded quotient constants/bytecode against an independently + recompiled build (`src/lowering/plan.rs:307-329`). +6. **Render-time certification of emitted bytecode** (§8). Optimizers are + checked per artifact, not trusted: a recognizer bug on an unseen gate + shape fails the render instead of shipping a wrong verifier. +7. **Subgroup checks delegated to EIP-2537 under a machine-checked coverage + invariant** (§4.8), with a constructor smoke test that fails deployment on + forks without the precompiles. +8. **One verifier shape per build.** Feature flags (`truncated-challenges`, + `outer-fewer-point-sets`, `outer-single-h-commitment`) select codegen + behavior at compile time; the artifact has no runtime configuration + surface. (The flip side — the artifact records its feature profile + nowhere — is assessed in the companion document.) + +## 6. The generated runtime + +Execution order of a rendered verifier (each phase maps to a template partial +and a `MemoryPhase` variant): + +1. ABI guard: proof head must be exactly `0x40`, instances head pinned, proof + length, instance count, and **exact** `calldatasize` checked before the + parser touches a byte. +2. VK load: embedded `mstore`s, or `extcodesize`/`extcodehash` re-check + + `extcodecopy` from byte 1 of the pinned VK contract; loaded header words + cross-checked against generated constants (`num_instances`, `k`, + accumulator config). +3. Optional accumulator pre-validation: radix-2^56 limb decode (injective; + canonical identity encoding; packing canonicality) with every decoded point + routed through G1MSM for curve/subgroup validation. +4. Streaming Keccak transcript: absorb VK digest, identity committed-PI + (128 zero bytes), instance count + canonicality-checked instance scalars, + then per-phase advice G1s (128-byte padded form) interleaved with + challenge squeezes (theta, beta/gamma, trash, y, x, x1..x4; optional + 128-bit truncation); evals spill to `REVERSED_EVALS_MPTR`; final + `proof_cptr == NUM_INSTANCE_CPTR` consumption check. +5. Lagrange block: `x^n` by squaring, denominator batch-inversion + (fail-closed on non-canonical words / failed modexp), `L_i(x)`, + `instance_eval`. +6. Quotient numerator: interpret the pinned VM bytecode (cached-top-of-stack + interpreter; only the opcode cases the program uses are rendered; unknown + opcodes revert; terminal `q_pc`/`q_has_top`/`q_sp` balance checks) plus + native permutation/lookup/heavy-gate kernels; or staticcall the pinned + external evaluator with a raw memory frame, checking returndata size and a + magic word. Result: `-nu_y(x)` at `QUOTIENT_EVAL_MPTR`. +7. PCS blocks 1–6 (§4.8) ending in `PAIRING_LHS`/`PAIRING_RHS`. +8. Optional accumulator batching: Keccak-derived alpha (zero remapped to 1) + folds the carried accumulator equation into the pairing inputs via + G1MSM + G1ADD. +9. Two-pair pairing via `ec_pairing` (MCOPY-staged, result compared + `eq(..., 1)`); `mstore(RETURN_MPTR, 1)`; return. + +Every staticcall checks success **and** exact returndatasize; every scalar +ingress is canonical-Fr-checked; every G1 coordinate checks the 16-byte pad +and `coord < p`. Failure direction is uniformly revert. + +## 7. Trust and assurance architecture + +The correctness argument is a chain with explicitly different assurance per +leg (honestly documented in `LOWERING_ARCHITECTURE_SPEC.md` §12.1 and +`vm/reference.rs`): + +| Leg | Mechanism | Strength | +| --- | --- | --- | +| Identity expressions → VM bytecode | Render-time: 3-stage validator; `certify_quotient_program` executes finalized bytecode on an **independent reference interpreter** at an artifact-seeded challenge vs direct `QuotientExpr` evaluation; `certify_quotient_builds_agree` dual-builds with recognizers disabled and requires identity-by-identity agreement; VK-embedded words re-compared word-for-word | Per-render, machine-checked | +| Bytecode → Yul interpreter semantics | Opcode/token table conformance tests (a `case` exists per opcode) + native-vs-Solidity per-identity trace differentials on fixture circuits | Fixture-sampled; an opcode no fixture emits has unverified runtime semantics | +| Inline/native/tail identities (never bytecode) | Trace differentials only | Fixture-sampled | +| Pointer bindings wrong-in-both-representations | `validate_quotient_mem_ptrs` whitelist (certification can't catch these: a pointer wrong in both sides agrees with itself) | Per-render | +| Memory non-overlap | Lifetime-aware `MemoryMap::validate` per render; *registered-regions-only* — agreement between emitted Yul and registered regions is pinned by rendered-source tests | Per-render + tests | +| solc spill window vs 0x1000 layout | Compiled-bytecode memoryguard test (env-gated) | Test-time only, one pinned compiler | +| EIP-2537 semantics (incl. subgroup checks) | Assumed per spec; constructor smoke proves existence/arithmetic, not rejection behavior | Assumed | +| Transcript equivalence with native verifier | Byte-for-byte mirror + trace differential + real-proof fixtures | Fixture-sampled | + +Complementing this, the adversarial test tiers: proof/VK/calldata mutation +PBTs, per-offset G1 canonicality/off-curve rejection sweeps cross-checked +against the native verifier, batch-invert fail-closed harness on extracted +generated Yul, EIP-170 fit, a 7-case supported-shape fuzz matrix with +cross-wiring rejection, SRS-free replay fixtures with gas-based stage +attribution, and two libFuzzer targets. (Which of these actually run in CI is +a finding in the companion assessment.) + +## 8. Cross-cutting contracts + +Things that must stay in sync, and how they currently are: + +| Contract | Mechanism | +| --- | --- | +| Quotient VM opcode/token bytes ↔ Yul interpreter | One `QUOTIENT_VM_SPEC` constant feeds emitter, validators, template constants, conformance tests | +| VK payload section order ↔ runtime `extcodecopy` offsets | Typed `VkPayloadLayout`, validated contiguity, tests | +| Proof read order ↔ transcript absorbs ↔ repacker | All derived from `ProtocolPlan` / `ProofCalldataLayout`; drift asserted | +| `MemoryPhase` enum order ↔ template include order | **Comment-enforced only** (see assessment) | +| Injected Yul code lines ↔ template-scope identifiers | **Naming convention only** (see assessment) | +| `verifyProof` selector + ABI head layout ↔ templates | Constant + duplicated in tests/fuzz targets | +| Feature flags ↔ expected proof schema | **Recorded nowhere in the artifact** (see assessment) | +| Accumulator limb packing ↔ `midnight-circuits` encoder | Mirrored constants (7×56), replay fixtures | + +## 9. Feature flags and build modes + +`evm` (revm + pinned-solc test harness), `solidity-trace` (LOG1 trace events; +trace renders also switch the external-evaluator staticcall to CALL), +`solidity-gas-checkpoints` (per-section LOG1 gas checkpoints, ~12k gas +overhead), `truncated-challenges` (128-bit x3/x1/x4 truncation — must match +the prover), `in-circuit-fewer-point-sets` / `outer-fewer-point-sets` / +`fewer-point-sets` (dummy-query PCS collapsing, split between recursive and +Solidity-facing proofs), `outer-single-h-commitment` (single-H quotient +layout, outer only), `rust-verifier-trace` (native trace hooks for +differentials). Trace/gas modes must not change verifier semantics; the +schema-changing trio must match the prover's build or all proofs are +(fail-closed) rejected. + +## 10. Testing and CI architecture + +Three tiers: (1) pure codegen tests (`src/lowering/tests.rs` ~4.0k lines, +`src/builder/tests.rs`) needing no EVM/SRS — VM differentials, manifest +ordering, layout facts, template-text pins; (2) env-gated EVM tests +(`src/test.rs` ~4.6k lines behind `HALO2_SOLIDITY_RUN_EVM_TESTS`, integration +fixtures for Poseidon/SHA/RSA/hybrid-MT, the k=20 IVC decider bench behind +`HALO2_SOLIDITY_RUN_IVC_BENCH`) — prove → render → pinned solc 0.8.30 → +Prague revm with blst-backed EIP-2537 → verify → mutate; (3) SRS-free replay +tests over committed fixtures, libFuzzer targets, bench/deploy scripts +(including live Sepolia deployment records under `deployments/`). + +CI (`.github/workflows/ci.yaml`): a default test job (EVM tests self-skip), +an EVM job running `cargo test ... pbt_` + the Poseidon fixture, and a trace +equivalence job; the heavy IVC benches and release size/hash gates live in a +weekly/push-to-main workflow (`solidity_verifier_bench.yml`). + +## 11. Documentation landscape + +37 files under `docs/{architecture,audit,benchmarks,plans,reference}`: a +bounded, falsifiable correctness claim with named exclusions +(`CODEGEN_ASSURANCE_DOSSIER.md`), a reviewer handoff packet, a rebuild-grade +verifier spec (`HALO2_MIDNIGHT_VERIFIER_SPEC.md`, 1.7k lines), memory-layout +and template-mapping references, reproducible-build manifest with published +runtime hashes, and honest limitation notes (the docs themselves flag the +memory-safe annotation as factually untrue and scope precisely what VM +certification does not prove). Parts of the audit chain have drifted from the +tree; the companion assessment enumerates the drift. + +## 12. Summary of architectural character + +The macro-architecture is disciplined and verified to hold in the imports: +facade → snapshot → converged plan → declarative render, with fail-closed +seams and unusually good rationale comments. The system's characteristic +strength is that security-relevant assumptions are *checked at generation +time* (SRS base, absorbed-G1 coverage, memory overlap, bytecode +certification, payload re-comparison) rather than trusted. Its characteristic +weakness is the residue of places where **strings and conventions do work +that types should do** (Yul text as an internal IR, comment-enforced enum +ordering, name-coupled injected code lines, five parallel operand decoders), +plus assurance-process gaps (CI test selection, artifact-recorded feature +profiles, panic-vs-Result at the public boundary). Those are quantified, with +verified evidence and prioritized redesign proposals, in +[`REDESIGN_PROPOSALS_2026-08.md`](../plans/REDESIGN_PROPOSALS_2026-08.md). diff --git a/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md b/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md new file mode 100644 index 000000000..3a0a542a4 --- /dev/null +++ b/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md @@ -0,0 +1,498 @@ +# Robustness & Quality Assessment and Redesign Proposals + +> Companion to +> [`../architecture/ARCHITECTURE_REVIEW_2026-08.md`](../architecture/ARCHITECTURE_REVIEW_2026-08.md). +> Produced 2026-08-08 against the `misc-fixes` branch by an independent +> multi-reviewer pass: nine subsystem mapping reviews, four assessment lenses +> (soundness, library robustness, on-chain security, architecture quality), +> and a second adversarial pass in which every finding cited below was +> re-verified against the source by a reviewer instructed to refute it. +> Findings are labeled **Confirmed** (every element checked in code) or +> **Partial** (core claim holds; stated corrections apply). Line numbers are +> as of this snapshot. As with any review, verify accuracy and completeness +> against the current sources before acting on it. + +## 1. Overall verdict + +| Lens | Score | Summary | +| --- | :-: | --- | +| Soundness of generated verifiers | 8/10 | No accept-invalid path or calldata malleability found. Calldata parsing is injective and fully pinned; every scalar/coordinate ingress is canonicality-checked; subgroup checking is delegated under a machine-checked coverage invariant; the quotient-VM certification chain is genuine defense-in-depth. Residual risk sits in what is assumed rather than proven (§3.2) and in assurance-process gaps (F1). | +| Robustness as a library | 7/10 | Two well-executed tiers — typed errors at the boundary, fail-closed asserts inside — that contradict each other's contracts: legal-but-unusual circuits pass `try_new` and then panic inside `render()`/`encode_calldata()` (F2), and per-proof encoding rebuilds the whole pipeline (F4). | +| Security of generated on-chain code | 8/10 | Precompile discipline, pinning, and fail-closed parsing are unusually strong. Must-fix hardening: the false `memory-safe` annotation + floating pragma with no runtime guard (F3), and dead unpinned-quotient template branches (F13). | +| Architecture quality & maintainability | 7/10 | Clean, verified macro-architecture (facade → snapshot → converged plan → declarative render). Liabilities are consistent in kind: strings and conventions doing work types should do (F7, F8, F10, F11), two oversized modules (F14), and measurable docs rot in the audit chain (F6, F15). | + +The failure direction is consistently **crash-or-reject** — the right default +for this domain. Nothing found blocks the bounded correctness claim in +`docs/audit/CODEGEN_ASSURANCE_DOSSIER.md`; most of what follows lowers the +cost and raises the credibility of the external audit this repo is explicitly +preparing for. + +## 2. What is strong — and should not be redesigned + +Explicit non-goals for any redesign; these choices are earning their keep: + +- **The narrow supported envelope** and fail-fast `try_new` validation. +- **The static absolute memory layout** with the lifetime-aware overlap + validator. (Harden its seams — F5, F9 — do not replace it with FMP-based + allocation.) +- **The compact quotient VM in the codehash-pinned VK payload**, and the + render-time certification chain: 3-stage validators, pointer whitelist, + reference-interpreter certification at an artifact-seeded challenge, + dual-build (recognizers on/off) agreement, and word-for-word re-comparison + of VK-embedded program bytes. Keep `vm/reference.rs` deliberately + independent of the emitter — the N-version leg is the point. +- **Single converged `LoweringPlan` per `render()` call** (extend it with + caching, F4 — don't weaken it). +- **Pinning by runtime length + codehash, re-checked per call.** +- **Templates-consume-facts** and `QUOTIENT_VM_SPEC` as the single VM ABI + source. +- **Loud-failure test prerequisites, gas-based stage attribution in replay + tests, and self-describing fixtures.** + +## 3. Findings register + +### 3.1 High severity (all Confirmed) + +**F1 — The adversarial EVM suite is excluded from every CI workflow by the +`pbt_` name filter; the CI comment claims otherwise.** +`.github/workflows/ci.yaml` (EVM job) runs +`cargo test -p halo2_solidity_verifier --release --all-features pbt_` plus the +Poseidon fixture; the default job leaves `HALO2_SOLIDITY_RUN_EVM_TESTS` unset +so EVM tests self-skip; the bench workflow runs only the IVC bench scripts. +Tests that therefore run in **no** workflow include the strongest +security-relevant negatives: `every_proof_g1_rejects_noncanonical_coordinates` +(`src/test.rs:2868`), `..._base_modulus_coordinates` (:2914), +`..._off_curve_coordinates` (:2948), +`compiled_memoryguard_does_not_overlap_generated_layout` (:1441), +`compiled_verifier_runtime_fits_the_eip170_limit` (:1495), +`batch_invert_fails_closed_on_noncanonical_words_in_all_paths` (:1584), +`malformed_embedded_calldata_variants_are_rejected` (:1284), +`vk_payload_section_mutations_are_rejected` (:1349), +`supported_shape_circuit_fuzz_e2e` (:501), and +`same_srs_distinct_shape_matrix_rejects_cross_wiring` (:629). The CI step +comment explicitly claims "non-canonical scalar and G1 rejection, EIP-170 +runtime size, and the memoryguard overlap check" run in that step — they do +not. A regression in any of these merges green. → Proposal P0.1. + +**F2 — Extensive panic surface behind the Result-typed public API.** +`render()`, `render_quotient_evaluator()`, `repack_proof()`, +`encode_calldata()`, and both diagnostics route through `LoweringPlan::new`, +which converts every post-constructor failure into a panic +(`src/lowering/plan.rs:167,183`; convergence panics at +`src/lowering/vk.rs:231-234,367`; model validation at +`src/lowering/artifacts.rs:66,296`; plan validation `.expect` at +`src/lowering/quotient.rs:469`). Legal shapes that pass `try_new` and then +panic include: >28 distinct PCS rotation points, rotation spans >4096, +circuits whose VK payload exceeds EIP-170, and VKs with unremoved virtual +selectors — while `try_new`'s docs promise "a typed error when the supplied +constraint system is outside the currently supported shape" and +`GeneratorConfig`'s docs claim the constructor validates the entire shape up +front. `vm/reference.rs:129-130` even documents that a malformed stream "must +surface as a `GeneratorError`, not a process abort," yet its only production +call site converts the `Result` to a panic. → Proposal P1.1. + +**F3 — False `("memory-safe")` annotation + floating `pragma ^0.8.24`, with +no per-PR or on-chain enforcement of spill-window disjointness.** +The terminal assembly block writes absolute addresses from 0x1000 up and +never allocates via the free-memory pointer; the annotation is documented +in-repo as "a false promise" that is load-bearing (the block does not compile +without it). Disjointness of solc's via-IR spill reservation (observed up to +0x8e0 of the 0xF80 headroom) from the generated layout is checked only by +`compiled_memoryguard_does_not_overlap_generated_layout` — env-gated and, per +F1, not run in CI. The floating pragma permits deployers to compile with any +0.8.x ≥ 24, unbinding the artifact from the pinned compiler the check was +measured against. Nothing at deploy or run time detects an overlap; a live +spill slot sharing bytes with the transcript buffer would corrupt verifier +state silently. → Proposal P0.2. + +**F4 — Every per-proof `repack_proof`/`encode_calldata` call rebuilds the +entire lowering pipeline, including an O(2^k) SRS fold and two certification +passes.** `src/lowering/calldata.rs:157-159` calls +`self.lowering_plan().repacked_proof_layout_plan()` per proof; +`LoweringPlan::new` runs `generate_vk` — whose `generate_base_vk` folds every +`g_lagrange` point to assert the SRS base (`src/lowering/vk.rs:81-92`; k=20 +for the IVC shape) — plus both convergence loops, full VM compilation, and +both certifications. `render()`, `proof_evaluation_counts()`, and +`quotient_identity_manifest()` each independently rebuild the same plan; +nothing on `SolidityGenerator` caches it, and the doc comment states each +path builds its own plan. Cross-call consistency rests on determinism by +convention (pinned by one repeated-plan test). This is seconds of latency and +a realistic DoS surface for a service encoding many proofs. → Proposal P1.2. + +**F5 — Cross-phase memory-overlap soundness hangs on `MemoryPhase` +declaration order matching template include order, enforced only by a +comment.** `MemoryLifetime::intersects` treats distinct `Phase` lifetimes as +never co-live and compares `PhaseSpan`s with the derived `Ord` +(`src/lowering/layout/memory.rs:192`); the sync requirement with +`Halo2Verifier.sol` include order exists only as a doc comment +(memory.rs:121-127). A mis-ordered variant silently disables overlap +detection for the affected pair. The model's acknowledged blind spot — the +0x1000-band `AccumulatorPairingBatch`/`FinalPairing` frames — is asserted +disjoint only under `cfg(test)` (memory.rs:1522-1539), not in +`VerifierMemoryLayout::validate()`. (Correction from verification: that +specific pair is currently disjoint *by construction* — +`FINAL_PAIRING_SCRATCH_START = PAIRING_BATCH_PTR + PAIRING_BATCH_HASH_BYTES` +— so the exposure is to future edits, not the current layout.) → Proposal +P0.3 / P2.2. + +**F6 — `REPRODUCIBLE_BUILDS.md`'s dependency-pinning claim contradicts +`Cargo.toml`.** The doc claims "All Midfall crates are resolved from the +pinned git revision in Cargo.toml"; `Cargo.toml` declares only workspace path +dependencies (`midnight-proofs = { path = ".." }`, etc.), so published +runtime hashes are a function of the enclosing workspace checkout. Mitigating +nuance: the doc records the Midfall revision in prose, so a careful reader +can still reproduce — but the stated mechanism is false in the document that +underwrites the hashes. → Proposal P0.4. + +### 3.2 Residual assurance boundary (documented, not a defect) + +The certification chain proves the **emitter → reference-interpreter** leg +per render. The **reference-interpreter → Yul** leg rests on opcode-table +conformance tests (a `case` exists per opcode — not that the case body is +correct) plus native/Solidity trace differentials on fixture circuits; an +opcode no fixture emits has unverified runtime semantics. Identities executed +as inline Yul, native callbacks, or the structured tail are never lowered to +bytecode and are covered only by the trace differentials. This is honestly +documented (`LOWERING_ARCHITECTURE_SPEC.md` §12.1, `vm/reference.rs:20-27`) +— listed here because Proposal P2.5 can close most of it, and because the +trace differential that covers it is itself env-gated (F1). + +### 3.3 Medium severity + +**F7 — Yul text is an internal IR** *(Partial — corrected)*. The evaluator +emits Yul strings; permutation/lookup/trash identities are re-parsed from +those strings into `QuotientExpr` trees by a shallow parser +(`src/lowering/quotient.rs:939-945` → `vm/mod.rs:1236-1279`); limb7 fusion is +textual pattern-matching (`quotient.rs:1172-1311`); helper inclusion is +substring scanning (`quotient.rs:93-118`). Correction from verification: in +actual builds the parsed families become native callbacks/structured tail, +which `certify_quotient_program` **skips** (certify.rs:176-180) — interpreted +gate identities are certified against trees from typed `Expression` +lowering, not the parse. Net effect stands: no check compares the parsed +trees against an independent source, so a parser bug on those families is +invisible to certification and caught only by the env-gated EVM trace +differential. → Proposal P2.6. + +**F8 — MODARITH7/AFFINE_SUM operand layouts hand-decoded in five Rust sites +plus the template** *(Confirmed, sites enumerated)*: +`validate_quotient_const_slots` (vm/mod.rs:2134-2192), the pointer walker +`quotient_read_pointers` (:2424-2506), the checked length walkers +(:2578-2680), the separate trusted length walkers (:3073-3105), the reference +interpreter (reference.rs:280-376, 436+), and +`QuotientNumeratorBlock.yul:715-757, 896-1052`. Certification cannot catch a +validator walker diverging from the emitter/reference pair. → Proposal P2.1. + +**F9 — Panicking "trusted" bytecode walkers are safe only under a +validate-first convention** *(Confirmed)*. `quotient_op_len` panics on +unknown opcodes and reads without bounds checks; the run-after-validation +convention lives in doc comments only, and one call site +(`compact_quotient_runs`, vm/mod.rs:1931-1983) walks builder-emitted bytes +*before* validation runs in `finish()`. → Proposal P2.1. + +**F10 — Injected code blocks couple to template scope by naming convention** +*(Confirmed)*. `Vec>` Yul lines (models.rs:519-526, 635-640) are +spliced verbatim and reference template locals (`r`, `y`, `delta`, +`quotient_eval_numer`, …) with no identifier validation; only solc would +catch a mismatch. Related *(Partial)*: models validate at construction inside +`generate_*_from_plan` (panicking), but `render()` itself does not enforce +`validate_layout()` — a future direct-construction call site could render an +unvalidated model. → Proposals P1.3, P2.6. + +**F11 — Template security behavior pinned by raw-text `contains()` +assertions** *(Partial — incident nuance)*. Guard tests assert substrings of +the **unrendered** template corpus (`src/lowering/tests.rs:1624-1690`). +Verification surfaced a concrete prior incident: commit `72bc1b2` +(2026-07-19) fixed an always-false Yul guard in `AccumulatorHelpers.yul` +that left `load_acc_point`'s `if is_id` branch dead while the adjacent +`contains()` test stayed green (the decoder remained fail-closed; no forgery +was possible — the incident shows the test style's blindness, not a +vulnerability). → Proposal P2.5. + +**F12 — Feature profile recorded nowhere machine-readable in artifacts** +*(Partial)*. `truncated-challenges`, `outer-fewer-point-sets`, and +`outer-single-h-commitment` change the proof schema the rendered verifier +expects; a mismatch fails as bare `revert(0,0)` (hardcoded proof-length check +or failed pairing) with no diagnostic. Correction: truncated-challenges is +human-discernible via a rendered comment; the other two leave no named trace. +Also *(Confirmed)*: `RenderDiagnostics::default()` is intentionally +feature-gated, so default render shape depends on compile features. +→ Proposal P1.4. + +**F13 — Dead unpinned external-quotient template branches** *(Partial — +guards stronger than claimed)*. `Constructors.sol:63-82` (and the two-arg +variant) render a constructor without a codehash `require` when +`expected_quotient_codehash` is `None`, and `QuotientAndLinearization.yul` +omits the pre-call codehash re-check in the same case. Corrections: the +configuration is unrepresentable through the public API (`RenderQuotient` has +only `Inline` and `ExternalPinned`), and the "deprecated panicking APIs" +mentioned in the spec no longer exist in source — the guards are the enum +shape plus an `artifacts.rs` assert. The hole-shaped template text is still +dead weight that an auditor must reason away. → Proposal P1.3. + +**F14 — Module hygiene: two monoliths** *(Confirmed)*. `vm/mod.rs` is 4,382 +lines mixing the opcode ABI, builder, three validators, shape recognizers, +the Yul parser, and proof-repack layout types that belong to the calldata +boundary (`RepackedProofLayoutPlan`). `kzg::computations` is one 1,014-line +function (kzg/mod.rs:834-1847) whose trace-only q_com walk (:1226-1334) +structurally duplicates Block 5's final-MSM term enumeration (:1673-1731). +→ Proposal P2.3. + +**F15 — Audit-chain docs rot** *(Confirmed)*. +`CODEGEN_ASSURANCE_DOSSIER.md:59-64`, `AUDIT.md`, and `AUDIT_FINDINGS.md` +cite the vanished `src/codegen/` tree (REVIEW_PACKET.md is current — the +audit docs disagree with each other); README carries two stale, +self-contradictory test counts (167+4 at line 49, 177 at line 389; actual at +snapshot: 202 lib + 9 integration) and a broken `./TESTING_STRATEGY.md` link; +`ROADMAP.md` links a nonexistent `./AUDIT.md` and presents fixed blockers as +open; STATUS/dossier are a dated snapshot ("suite was not rerun") with no +re-assessment trigger. → Proposal P0.4. + +**F16 — Diagnostics re-derivation** *(Partial)*. Public +`quotient_identity_manifest` re-derives gates/targets from `vk.cs()` without +consulting the executed plan; the plan-derived manifest exists but is +`cfg(test)`-only (vm/mod.rs:258-282). Correction: the selector-detection +method is identical to the plan's, not divergent as originally claimed; +`ProofEvaluationCounts` hand-duplicates protocol formulas with a total-sum +assert as the only cross-check. → Proposal P1.5. + +**F17 — Test-hygiene trio** *(Confirmed)*. (a) The bit-flip malleation PBT +reaches only the first 512 proof bytes (`bit_idx ∈ 0..4096`, byte 511 max; +the repacked proof is several thousand bytes — the tail G1s/q_evals/π are +never flipped by this test; scalar-sweep tests do cover deeper offsets +structurally). (b) Nine adversarial tests pass vacuously (stderr notice only) +when the accept baseline breaks, via `solidity_output_is_true_or_skip` +(test.rs:3411-3429); a loud variant exists and is used by the malleation +baseline. (c) The PBT runner defaults to 3 cases with +`failure_persistence: None` (test.rs:4295-4306); the two libFuzzer targets +are wired to no workflow. → Proposal P0.1. + +### 3.4 Low severity (verified; batch as hygiene) + +- **L1** `scalar_inv` scratch registers 0xc0 of the historical 0x100 window; + the 0x40 gap is unused padding but unregistered/unvalidated + (memory.rs:700-705). +- **L2** `num_instances` has no sanity bound on the non-accumulator path (an + absurd value renders a verifier demanding `num_instances*32` bytes of + calldata); accumulator configs do bound it via the fixed-base tail check. +- **L3** `evm.rs` harness: pervasive documented panics, substring parsing of + solc's human-readable output (single-contract, trailing-newline + assumptions), publicly re-exported behind the `evm` feature; + `Evm::code_size` doc/impl mismatch. +- **L4** Several consistency checks are `debug_assert!`-only and compile out + in release (diagnostics.rs:18, calldata.rs:127, memory.rs:97-103/277, + encoding/mod.rs:881/970, protocol/mod.rs:676, kzg/mod.rs:1117-1119); + `Constants.sol:24` unwraps `expected_quotient_len` inside the + `expected_quotient_codehash` match arm — safe only via the artifacts.rs + pairing invariant. +- **L5** The constructor precompile smoke cannot detect a G1MSM + implementation that omits subgroup checks (its MSM probe is identity-only; + acknowledged in the file's own comments) — the exact property the + verifier's soundness delegates to the precompile. +- **L6** Stale NatSpec in the template and every rendered fixture/deployment + claims generated scratch starts at 0x80; the actual base is 0x1000. +- **L7** Trace renders switch the evaluator staticcall to CALL and drop + `view` with no structured non-production marker (buried comments only; + state change limited to LOG1 by the pinned callee). +- **L8** Small duplications/dead code reported by reviewers: `u256_string` + duplicated verbatim (yul_emit.rs:1175 / vm/mod.rs:4168), two pow5 + recognizers, dead `_quotient_max_stack` binding (quotient.rs:134), empty + `render/yul.rs`, dead `hex_padded` branch and duplicate `proof_len` check + in models.rs. (Note: the hardcoded 8/10 accumulator word constants in + `api.rs` originally reported here turned out to have a tying test — + `lowering/tests.rs:1692-1707` — and are dropped as a finding.) + +## 4. Redesign proposals + +Ordered by (leverage ÷ risk). P0 items are small and should land before the +audit; none change verifier semantics. Items marked ⚠ change rendered +bytecode and require regenerating pinned fixtures and the +`REPRODUCIBLE_BUILDS.md` hashes — batch them into one regeneration. + +### P0 — Assurance-process fixes (small, high leverage) + +**P0.1 Fix CI test selection and skip semantics** *(F1, F17)*. +Enumerate the env-gated EVM tests explicitly in `ci.yaml` (or adopt one +enforced prefix and add a meta-test asserting the filter matches every +`#[test]` in `src/test.rs`); add a post-step check that the executed-test +count is non-zero and matches expectation so a filter regression fails +loudly. Replace `solidity_output_is_true_or_skip` with the existing loud +variant when `HALO2_SOLIDITY_RUN_EVM_TESTS=1` (matching the suite's own +loud-prerequisite philosophy). Draw `bit_idx` from `0..proof_len*8`. Wire the +two libFuzzer targets into a scheduled workflow with a committed corpus; give +the PBT runner a persistence file and a higher default in CI. Move the +slowest tests to the weekly workflow if per-PR time matters — but into *some* +workflow. Fix the misleading CI step comment. *Risk: CI minutes.* + +**P0.2 Runtime free-memory-pointer guard + pragma pin** *(F3)* ⚠. +Emit `if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }` as the first +statement of the terminal assembly block in both `Halo2Verifier` and +`Halo2QuotientEvaluator` — via-IR initializes the FMP to the memoryguard +value, so this converts the spill-window assumption into a fail-closed +on-chain check for ~10 gas per proof. Pin the pragma to the audited compiler +(or document why not). Keep the memoryguard host test and run it per-PR +(P0.1). *Risk: minimal; confirm the legacy pipeline also initializes 0x40 +before the block (it does).* + +**P0.3 Promote by-construction frame checks into `validate()`** *(F5)*. +Move the `AccumulatorPairingBatch`/`FinalPairing` disjointness assertion from +`cfg(test)` into `VerifierMemoryLayout::validate()` so every generation is +gated on it. Cheap, generation-time only. + +**P0.4 One documentation-refresh pass with drift guards** *(F6, F15, L6)*. +Correct the `REPRODUCIBLE_BUILDS.md` pinning claim and record the workspace +commit alongside published hashes (the bench script can emit it into +`contract-sizes.txt`); update `src/codegen` paths in the dossier and audit +docs; replace README test counts with the command that produces them; fix +broken links; add status markers to ROADMAP; fix the 0x80 NatSpec ⚠; define a +re-assessment trigger (any change under `src/lowering` or `templates/` bumps +a dated stamp). Guard recurrence with a CI link checker plus a small test +asserting every path cited in `docs/audit` exists. *No code risk; high +audit-readiness leverage.* + +### P1 — API contract and performance (small–medium) + +**P1.1 Make the lowering pipeline fallible end-to-end** *(F2, F9-adjacent)*. +The leaf validators already return `Result<_, String>`: change +`LoweringPlan::new` to `try_new -> Result`, +threading through `generate_vk`, `meta_data_for_stable_static_layout`, +model validation, and certification. Introduce an internal error taxonomy +{UnsupportedShape, ResourceLimit, InternalInvariant} carried in +`GeneratorError::Planning` so callers can distinguish rejection classes. +Keep panics only for true internal-invariant bugs, and document them under +`# Panics` on every public method that retains one. Honor the +`reference.rs` contract that certification failures surface as +`GeneratorError`. *Risk: low functionally; moderate churn (~8 modules); keep +the current panic messages as error text.* + +**P1.2 Cache one converged plan per generator; decouple repacking** *(F4)*. +Store `OnceCell, GeneratorError>>` on +`SolidityGenerator` (inputs are already immutable; determinism is pinned by +the repeated-plan test) and route every entry point through it — this also +*structurally* guarantees render/repack/diagnostics agree on one plan instead +of by convention. Additionally derive `RepackedProofLayoutPlan` directly from +`ProofCalldataLayout::from_protocol` + meta counts so per-proof calldata +encoding never needs VK generation or certification at all. *Risk: low.* + +**P1.3 Make invalid render states unrepresentable** *(F10, F13, L4)* ⚠. +Collapse `quotient_external` + `expected_quotient_{len,codehash}` into one +`Option` model field; delete the +`when None` codehash-free branches from `Constructors.sol` and +`QuotientAndLinearization.yul` (already unreachable; removing them deletes +the hole-shaped text and the template-level `unwrap()`). Seal model +construction behind validating constructors (or have `render()` call +`validate_layout()` first) so an unvalidated model cannot render. *Risk: +none functionally; fixture regeneration.* + +**P1.4 Record the feature/build profile in rendered artifacts** *(F12)* ⚠. +Emit a feature-profile constant (bitmask or three booleans + crate version) +and a NatSpec line in `Halo2Verifier.sol`; expose it as a typed field on +`RenderedArtifacts`; include it in the reproducible-builds manifest; surface +it in `RepackError` context so an off-chain repack against the wrong profile +is diagnosable in one step. Consider making `RenderDiagnostics::default()` +feature-independent (breaking change to a documented-intentional behavior — +decide explicitly). Add a CI matrix job compiling + running lib tests under +default features and each outer-* feature alone. *Risk: pinned-hash +regeneration.* + +**P1.5 Plan-derived diagnostics only** *(F16)*. +Remove the `cfg(test)` gate on the plan-derived manifest and implement +`quotient_identity_manifest` as `plan.quotient_identity_parts().manifest()` +via the cached plan; derive `ProofEvaluationCounts` from the protocol plan's +per-family counts, keeping the `meta.num_evals` assert as the net. *Risk: +low; output shape already pinned by tests.* + +### P2 — Structural improvements (medium–large) + +**P2.1 Single operand-layout descriptor + `ValidatedProgram` newtype** +*(F8, F9)*. Define each opcode's operand schema once (typed field sequence: +u8 const-slot, u16 ptr, counted blocks) attached to `QUOTIENT_VM_SPEC`, and +drive the checked length walker, const-slot validator, pointer walker, and +trusted walker from it; render the schema into the template's case +documentation so the Yul reviewer diffs against the same source. Keep +`reference.rs`'s decoder deliberately independent (document that choice — it +is the N-version defense). Add `ValidatedProgram<'a>` constructible only via +`validate_quotient_program`, and make the panicking walkers take it. *Risk: +touches the trusted emission path; land under the existing conformance tests ++ dual-build certification as the net.* + +**P2.2 Mechanize the `MemoryPhase` ↔ template-schedule contract** *(F5)*. +Introduce a schedule manifest — a const ordered list of (phase, template +partial, marker) — that (a) the enum order is asserted against and (b) a lib +test extracts from rendered verifier output (per-section markers already +exist in gas-checkpoint form; add a non-feature-gated comment marker) so a +reordered include or misplaced enum variant fails a test instead of silently +disabling overlap detection. Optionally add explicit sub-phase ordering for +the 0x1000 band so its aliasing becomes checkable rather than exempt. + +**P2.3 Split the monoliths; move repack types to the ABI boundary** *(F14)*. +Mechanical split of `vm/mod.rs` into `vm/{spec,builder,validate,recognize, +yul_parse}.rs`; move `RepackedProofLayoutPlan` (and friends) to +`lowering/abi/`. Split `kzg::computations` into per-block functions sharing +one linearization-term enumeration source, eliminating the trace/Block-5 +duplicate walk. *Risk: low; no output change; pure `pub(crate)` refactor.* + +**P2.4 Negative-conformance subgroup probe at deployment** *(L5)* ⚠. +Embed one constant on-curve, non-subgroup G1 point in the constructor smoke +and require the G1MSM staticcall on it to *fail* (optionally a non-subgroup +G2 for the pairing). This makes the deployment gate test the exact rejection +behavior the runtime soundness delegates to the precompile. Generate the +constants once with a Rust-side test proving on-curve ∧ outside r-torsion. +*Risk: slight deployment gas.* + +**P2.5 Render-time differential execution of the assembled quotient Yul** +*(§3.2, F7, F11)*. Behind the `evm` feature (or a release-render gate), +execute the rendered quotient block on revm against a memory image generated +from `QuotientRefMemory`'s address-derived assignment and compare `-nu_y(x)` +plus every selector bucket with the reference interpreter. This closes the +reference→Yul leg and covers inline/native/tail identities per artifact +instead of per fixture — converting the two weakest assurance legs into a +render gate. Complements, not replaces, the raw-text template tests (which +should migrate to rendered-output assertions where feasible). *Risk: needs +the EVM harness inside generation (feature-gated); the memory image must +respect the structural constraints native kernels assume — the read-model +windows already describe them.* + +**P2.6 Typed statement IR instead of the Yul-string round-trip** *(F7, F10)* +⚠ *(large; do last)*. Extend `QuotientExpr` into a small statement IR +(let-bindings + expression), make `yul_emit::Evaluator` produce it once per +identity, and derive everything from it: (a) one printer to Yul text for +inline/native blocks, (b) direct VM compilation (`emit_expr` already consumes +`QuotientExpr`), (c) limb7 fusion and pow5/helper detection as structural +rewrites/queries. Delete the assignment parser, the textual +`specialize_limb7_chains` matcher, one of the two pow5 recognizers, and the +substring helper-flag scan. This removes the largest class of convention +coupling and the certification blind spot at the parse seam. *Risk: medium — +output text will change, churning fixtures and published hashes; stage with +output-identity checks first, then the P2.5 differential as the semantic +net.* + +### P3 — Hygiene batch (small, opportunistic) + +Bound `num_instances` sanely at `try_new` (L2); promote the +security-adjacent `debug_assert!`s to `assert!` or `validate()` checks — +codegen is not hot enough to care (L4); register the full `scalar_inv` +0x100 window or update the stale comment (L1); harden `evm.rs` (solc +`--combined-json` output instead of substring parsing, fix the `code_size` +doc, deduplicate the two compile/two run-tx paths) (L3); add a structured +non-production marker to trace renders (contract-name suffix or NatSpec tag) +(L7) ⚠; delete the small duplications/dead code (L8). + +## 5. Suggested sequencing + +1. **Week 1 (audit-readiness):** P0.1–P0.4. Nothing here changes semantics; + P0.2 and the NatSpec fix change bytecode — do one coordinated fixture/hash + regeneration. +2. **Next:** P1.2 (caching — smallest high-value code change), then P1.1 + (Result threading) since its churn benefits from the single cached entry + point; P1.3–P1.5 ride the same fixture regeneration as P0.2. +3. **Then:** P2.1–P2.4 in any order (independent); P2.5 before P2.6 so the + IR migration lands under a per-render semantic differential. + +## 6. Verification note + +This assessment was produced by automated review with per-finding +adversarial re-verification against the source; corrections discovered +during that pass are recorded inline. Findings describe the snapshot above. +Review the accuracy and completeness of both documents against the current +tree before relying on them — responsibility for verification remains with +the reader. From ac9604d6911b0aa380bf8dd83c93b36e658763e6 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Mon, 10 Aug 2026 09:16:06 +0100 Subject: [PATCH 087/108] fmt: apply nightly rustfmt (import grouping, comment wrap) cargo +nightly fmt --all -- --check was failing in CI on unstable options (imports_granularity, wrap_comments) that stable rustfmt silently ignores locally. Co-Authored-By: Claude Sonnet 5 --- .../fuzz/fuzz_targets/proof_repack.rs | 5 ++++- .../fuzz/fuzz_targets/solidity_calldata.rs | 5 ++++- .../tests/ivc_accumulator_replay.rs | 14 +++++++------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/proofs/solidity-verifier/fuzz/fuzz_targets/proof_repack.rs b/proofs/solidity-verifier/fuzz/fuzz_targets/proof_repack.rs index 49c7d08a8..01b51130e 100644 --- a/proofs/solidity-verifier/fuzz/fuzz_targets/proof_repack.rs +++ b/proofs/solidity-verifier/fuzz/fuzz_targets/proof_repack.rs @@ -12,7 +12,10 @@ use midnight_proofs::{ plonk::{ keygen_vk_with_k, Advice, Circuit, Column, ConstraintSystem, Constraints, Error, Selector, }, - poly::{kzg::params::ParamsKZG, kzg::KZGCommitmentScheme, Rotation}, + poly::{ + kzg::{params::ParamsKZG, KZGCommitmentScheme}, + Rotation, + }, }; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; diff --git a/proofs/solidity-verifier/fuzz/fuzz_targets/solidity_calldata.rs b/proofs/solidity-verifier/fuzz/fuzz_targets/solidity_calldata.rs index 616943c14..7fc515812 100644 --- a/proofs/solidity-verifier/fuzz/fuzz_targets/solidity_calldata.rs +++ b/proofs/solidity-verifier/fuzz/fuzz_targets/solidity_calldata.rs @@ -14,7 +14,10 @@ use midnight_proofs::{ create_proof, keygen_pk, keygen_vk_with_k, Advice, Circuit, Column, ConstraintSystem, Constraints, Error, Selector, }, - poly::{kzg::params::ParamsKZG, kzg::KZGCommitmentScheme, Rotation}, + poly::{ + kzg::{params::ParamsKZG, KZGCommitmentScheme}, + Rotation, + }, transcript::{CircuitTranscript, Transcript}, }; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; diff --git a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs index 86d4a1ea7..d225ce495 100644 --- a/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs +++ b/proofs/solidity-verifier/tests/ivc_accumulator_replay.rs @@ -357,11 +357,11 @@ fn replay_accumulator_fixture(fixture: &str) { // cases below are the non-canonical routes to the same nulled operand, and // each is caught by a different guard inside that branch. // - // 1. Identity flag on `x`, honest `y`. `x` decodes to zero and sets - // `x_is_id`, but `y` does not, so the malformed-infinity check - // (`iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))`) must reject. Without - // it, `load_acc_point` would still write EIP-2537 infinity into the - // accumulator slot while `y` was arbitrary. + // 1. Identity flag on `x`, honest `y`. `x` decodes to zero and sets `x_is_id`, + // but `y` does not, so the malformed-infinity check (`iszero(or(or(x_hi, + // x_lo), or(y_hi, y_lo)))`) must reject. Without it, `load_acc_point` would + // still write EIP-2537 infinity into the accumulator slot while `y` was + // arbitrary. for (case, point_word) in [ ( "LHS accumulator identity flag with honest y", @@ -384,8 +384,8 @@ fn replay_accumulator_fixture(fixture: &str) { // 2. Both coordinates carry the codec's zero sentinel (`p - 1`) with no // identity flag. Every packing and field check accepts this, so the - // `decoded_zero` guard is the only thing separating "the codec's zero" - // from "EIP-2537's point at infinity". + // `decoded_zero` guard is the only thing separating "the codec's zero" from + // "EIP-2537's point at infinity". for (case, point_word) in [ ( "LHS accumulator decodes to zero without the identity flag", From 513fa8725bf1a249957625d677e72e103badb210 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Wed, 12 Aug 2026 16:12:57 +0000 Subject: [PATCH 088/108] docs: add independent Solidity verifier review and audit (2026-08) Review of the moonlight-wrap render (Halo2Verifier.sol 3861a403, Halo2VerifyingKey.sol ec94cabe) against midfall/proofs, covering architecture, conformance and security across crypto/soundness, EVM implementation, and operational/supply-chain lenses. Static analysis was cross-checked by execution: both contracts compiled with the pinned toolchain and run under revm 19 / SpecId::PRAGUE against fixtures/moonlight-wrap/calldata.bin plus 40 adversarial mutations. The fixture reproduces its documented 1,279,482 gas exactly. Verdict: sound as rendered. No critical or high soundness break in the contract; every phase checkable against the Rust reference conforms. 23 findings. Highest is H-1: NEG_S_G2_BASE is taken verbatim from the supplied SRS with no ceremony binding and no build-time consistency check, while every other control in the repo verifies only self-consistency and would pass on a substituted setup. Includes patches/P11_srs_binding.patch (proposed fix for H-1, needs cargo check) and patches/review-proposed-all.patch (full proposed set). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PhfUFgvirfyTF9eidjSMRe --- .../audit/HALO2_VERIFIER_REVIEW_2026-08.md | 1423 +++++++++++++++++ .../docs/audit/patches/P11_srs_binding.patch | 63 + .../audit/patches/review-proposed-all.patch | 177 ++ 3 files changed, 1663 insertions(+) create mode 100644 proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md create mode 100644 proofs/solidity-verifier/docs/audit/patches/P11_srs_binding.patch create mode 100644 proofs/solidity-verifier/docs/audit/patches/review-proposed-all.patch diff --git a/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md new file mode 100644 index 000000000..b15de510e --- /dev/null +++ b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md @@ -0,0 +1,1423 @@ +# Halo2 BLS12-381 Solidity Verifier — Architecture Review, Conformance Check and Security Audit + +**Artefacts under review** + +| File | SHA-256 | Size | +| --- | --- | --- | +| `Halo2Verifier.sol` | `3861a403f7319e767610fc71a3ff5500b2c14e787a68703188d2f2629928e756` | 213,670 B / 3,682 lines | +| `Halo2VerifyingKey.sol` | `ec94cabe5691703e240b116c59bc2e7c83cbdefe2e4d02dbd64020d6a0294f19` | 78,098 B / 692 lines | + +Both files are **byte-identical** to `midfall/proofs/solidity-verifier/fixtures/moonlight-wrap/`. This is the `AccumulatorEncoding::point_pair` replay fixture, rendered by Moonlight's `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` at solidity-verifier commit `3fb6d84`. + +**Reference implementation:** `midfall/proofs` (`src/plonk/*`, `src/poly/kzg/*`, `src/transcript/*`) and the generator at `midfall/proofs/solidity-verifier`. + +**Method.** Four independent passes were run and reconciled: a line-by-line conformance diff against the Rust verifier; a cryptographic/soundness pass; an EVM/implementation pass; and an operational/key-management/supply-chain pass. Findings were then **executed**: both contracts were compiled with solc 0.8.30 (`--via-ir --optimize --optimize-runs=1 --evm-version cancun`, CBOR metadata stripped) and run under `revm 19` with `SpecId::PRAGUE` and the `blst` BLS12-381 precompiles, against the fixture calldata and 40 adversarial mutations. + +--- + +## Executive summary + +**The verifier is sound as rendered.** No Critical or High soundness break was found in the contract. Every phase that could be checked against staged reference code — transcript schedule and encodings, challenge order, instance handling, all four identity families, the y-batching algebra, linearization and quotient reconstruction, the multi-open reduction, and the pairing equation including which side carries the negation — conforms to `midfall/proofs`. The domain constants, the permutation `DELTA`, the base points and the VK codehash were all recomputed independently and match. + +The code is also, by a wide margin, better defended than a typical generated verifier. It re-pins the VK by `extcodehash` **on every proof**, not just at construction. It pins both ABI head words, the proof length, the instance count and `calldatasize()` before touching any data-dependent calldata. It range-checks every scalar against `r` with `lt`, not `mod`. It rejects non-canonical EIP-2537 padding rather than normalising it (which would create transcript aliases). It routes every prover-supplied G1 through a subgroup-checking precompile. It compares the pairing result `== 1` rather than masking the low bit. And it asserts structural post-conditions on its own quotient interpreter (`q_pc == q_end`, empty stack, no live operand). + +**The risk is not in the Solidity — it is around it.** The highest-severity finding is that `NEG_S_G2_BASE`, the trusted-setup element on which all soundness rests, is taken verbatim from whatever SRS the generator was handed, with no ceremony binding, no SRS hash, and no build-time consistency check — even though the generator *does* defend the G1 base with exactly such a check. Below that sit a cluster of build-reproducibility and deployment-assurance gaps, a compiler-configuration dependency that is not self-enforcing in the shipped artefact, and a weak deployment-time probe of precisely the two precompiles that decide acceptance. + +One new, empirically-demonstrated issue: **a single off-curve point in the proof causes the verifier to consume ≈98.5% of whatever gas limit is supplied** (29.5M of a 30M limit, versus 316k for a structural rejection and 1.28M for a valid proof), because a failing EIP-2537 precompile consumes all gas forwarded to it. This is a griefing vector for any relayer, paymaster or batching wrapper. + +### Findings at a glance + +| ID | Severity | Title | +| --- | --- | --- | +| **H-1** | High | Trusted-setup element `NEG_S_G2_BASE` is unverifiable: no ceremony binding, no SRS pin, no build-time consistency check | +| **M-1** | Medium | `assembly ("memory-safe")` is factually false; the invariant that protects it is enforced only by an external test, under a floating pragma | +| **M-2** | Medium | Malformed curve points burn ~63/64 of the supplied gas instead of reverting cheaply (demonstrated) | +| **M-3** | Medium | Deployment probe is weakest exactly where acceptance is decided: `PAIRING_CHECK` and `G1MSM` are tested only with identity inputs | +| **M-4** | Medium | `vk_digest` does not cover the SRS points, the quotient program, the accumulator schema or the feature profile — the team's own TA-2 remediation is still open | +| **M-5** | Medium | Build is not reproducible as documented: three conflicting provenance stamps, empty artefact manifest, `--optimize-runs` unrecorded and environment-overridable, solc pinned by version string not hash | +| **L-1** | Low | Codegen certification covers the emitter→reference leg only; the Yul VM and native kernels are fixture-sampled, and the replay test recompiles committed fixtures | +| **L-2** | Low | Committed-instance commitment hard-wired to the identity; one MSM term silently omitted while the emitted comment claims otherwise | +| **L-3** | Low | 41 bare `revert(0, 0)` sites; `verifyProof` can never return `false` despite its signature | +| **L-4** | Low | Exact-`calldatasize` pin makes the verifier uncallable through ERC-2771 forwarders and similar calldata-appending relayers | +| **L-5** | Low | `CHALLENGE_MPTR` aliases `THETA_MPTR` — inert here, silent corruption for any circuit with user-phase challenges | +| **L-6** | Low | Quotient-VM operands are unvalidated raw memory pointers; safety rests entirely on codehash pinning plus emitter correctness | +| **L-7** | Low | Zero-slack memory adjacencies; `batch_invert` scratch ends exactly at `LAGRANGE_DENOMS_MPTR` and would corrupt silently, without reverting | +| **L-8** | Low | No on-chain provenance: no build id, no feature profile, CBOR metadata stripped | +| **L-9** | Low | No incident-response or migration story; no domain binding, so a valid proof replays across every chain and deployment | +| **L-10** | Low | 128-bit truncated challenges cap PCS soundness at ≈2⁻¹⁰⁸ (intentional; should be a recorded accepted risk) | +| **I-1…I-7** | Info | Comments contradicting constants, dead code and constants, unreachable defensive branch, stale audit-doc anchors, missing transcript domain separation, two latent codegen divergences, unbound batching randomiser | + +--- + +# Part I — How it works + +## 1.1 Two contracts, and why + +The system is a **circuit-specialised** verifier: the proof layout, memory map, quotient program and every constant are generated for exactly one `VerifyingKey>`. It is not a generic Halo2 verifier and cannot verify a proof for any other circuit. + +It ships as two contracts because the verifying key is too large to sit comfortably inside the verifier's own bytecode: + +- **`Halo2VerifyingKey`** — a *data* contract. Its constructor writes a byte-blob into memory and `return`s it as runtime code. There is no executable logic in the deployed runtime at all. +- **`Halo2Verifier`** — the logic. A thin Solidity shell (`AUTHORIZED_VK`, a constructor, and `verifyProof`) wrapped around one very large `assembly` block that does the entire verification. + +The verifier binds to its key by **address, byte length and codehash** (`EXPECTED_VK_LENGTH = 17025`, `EXPECTED_VK_CODEHASH = 0xe68d8936…cf52`), and re-checks that binding before every single proof, not just at deployment. + +## 1.2 The VK contract: data as code + +```solidity +constructor() { + assembly { + let runtime := 0x80 + let payload := add(runtime, 0x01) + mstore8(runtime, 0xfe) // INVALID opcode + mstore(add(payload, 0x0000), 0x56c0…) // vk_digest + …532 words total… + return(runtime, 0x4281) // 17025 bytes + } +} +``` + +Byte 0 is an unconditional `INVALID` (`0xfe`), so a direct call to the VK address cannot execute the payload as code. The verifier copies from byte 1 onward: + +```yul +extcodecopy(vk, VK_MPTR, 0x01, EXPECTED_VK_PAYLOAD_LENGTH) // 17024 bytes +``` + +I reconstructed the runtime from the 532 `mstore`s, prepended the `0xfe`, and confirmed `keccak256` equals `EXPECTED_VK_CODEHASH` and the length equals 17025 — so the pinned hash covers the `INVALID` prefix, and the two contracts are mutually consistent. Because the runtime is pure returned data, **this codehash is compiler- and optimiser-independent**, which is a genuinely good design property: the VK half of the system is trivially reproducible even though the verifier half is not (see M-5). + +The payload layout, in 32-byte words from `VK_MPTR = 0x3680`: + +| Words | Content | Value in this artefact | +| --- | --- | --- | +| 0 | `vk_digest` (Blake2b-512 over the pinned constraint system, reduced) | `0x56c0824f…4f66` | +| 1 | `num_instances` | 19 | +| 2 | `k` (log₂ domain size) | 20 | +| 3 | `n_inv` | 1/2²⁰ mod r | +| 4–6 | `omega`, `omega_inv`, `omega_inv_to_l` | order-2²⁰ root; ω⁻¹⁰ | +| 7–10 | `has_accumulator`, `acc_offset`, `num_acc_limbs`, `num_acc_limb_bits` | 1, 11, 7, 56 | +| 11–14 | `G1_BASE` (4 words, EIP-2537 padded) | canonical BLS12-381 G1 generator | +| 15–22 | `G2_BASE` (8 words) | canonical G2 generator | +| 23–30 | `NEG_S_G2_BASE` (8 words) | −[s]G₂ from the trusted setup | +| 31… | quotient VM constant pool (178 words) + packed program (143 words, `0x11cf` bytes) | | +| … | 27 fixed commitments, then 18 permutation commitments (4 words each) | | + +The header ends exactly at `0x7900 = CHALLENGE_MPTR` — the VK region and the challenge region abut with zero slack. + +I verified numerically: `n_inv · 2²⁰ ≡ 1 (mod r)`; `omega` has exact multiplicative order 2²⁰; `omega · omega_inv ≡ 1`; `omega_inv_to_l = omega_inv¹⁰`, consistent with `|rotation_last| = 10` and `blinding_factors = 9`; `G1_BASE` and `G2_BASE` are the canonical generators; `NEG_S_G2_BASE` is on the twist, in the r-order subgroup, and is not ±G₂; all 45 VK G1 commitments are on-curve and in the r-subgroup; and none of the 10 simple-selector commitments is the point at infinity (an identity selector commitment would have silently zeroed every identity in its bucket). + +## 1.3 The verifier's memory map + +The single most unusual design decision: the generated code **does not use Solidity's free-memory pointer at all**. Every address is an absolute constant baked in at codegen time, starting at `0x1000`. + +``` +0x0000–0x005f Solidity scratch (never written) +0x0040 free-memory pointer (never written, never read) +0x0080–0x0fff solc's via-IR stack-spill reservation +0x1000 TRANSCRIPT_MPTR = RETURN_MPTR = QUOTIENT_RETURN_MPTR + ↳ streaming Keccak buffer, peaks at 0x1ce0 + ↳ later reused for PCS scaling, the acc-batch preimage, + the ec_pairing frame, and finally the returned word +0x3580–0x363f scalar_inv modexp frame +0x3680–0x78ff VK payload (copied by extcodecopy) +0x7900–0x7a3f challenges: theta β γ trash y x x1 x2 x3 x4 +0x7a40–0x7f7f f_com, pi, acc lhs/rhs, Lagrange scratch, quotient, pairing slots +0x7f80–0x931f rotation points, x1 powers, q_eval sets +0x9480–0xa13f REVERSED_EVALS (102 spilled proof evaluations) +0xa140–0xb13f proof G1 commitments, by category +0xb140 SELECTOR_ACC_MPTR = BATCH_INV_SCRATCH_MPTR +0xb280–0xe33f the fused 78-pair final G1MSM input (0x30c0 bytes) +0xe340 end +``` + +Three addresses are deliberately aliased (`0x1000` three ways, `0xb140` two ways). I traced the write map in program order and confirmed all of them are **lifetime-disjoint reuse, not collisions**: the transcript is dead by line 1377, long before `0x1000` is next touched at line 3570; `batch_invert` runs exactly once (line 1431) and finishes before the selector buckets are zeroed at line 1612. + +The strategy is fast — an absolute `mload` costs 3 gas and needs no pointer arithmetic — and it is why this verifier lands at ~1.28M gas. It is also the source of finding **M-1**: the annotation `assembly ("memory-safe")` that unlocks solc's stack-to-memory mover is, on its own terms, false, and the invariant that keeps it safe (`solc's spill reservation < 0x1000`) is checked only by a test in the generator repo, never in the shipped bytecode. + +## 1.4 The verification flow + +`verifyProof(bytes proof, uint256[] instances)` — selector `0x1e8e1e13`. For this circuit: proof = 7,776 bytes, instances = 19 words, total calldata = 8,516 bytes exactly. + +**Phase 0 — envelope.** Before touching anything data-dependent, four independent pins: + +```yul +calldataload(0x04) == 0x40 // proof head +calldataload(0x24) == 0x1ec0 // instances head +calldataload(0x44) == 0x1e60 // proof length +calldataload(0x1ec4) == 19 // instance count +calldatasize() == 0x2144 // no missing or trailing bytes +``` + +This closes the classic hand-rolled-parser hole where an attacker supplies arbitrary ABI offsets and relocates the instance array. All five were confirmed by mutation testing (Appendix A, N23–N30, D-block). + +**Phase 1 — VK load.** `extcodesize` and `extcodehash` are both re-checked, then `extcodecopy` from byte 1. Six header words are cross-checked against constants baked into the verifier (`19, 20, 1, 11, 7, 56`). + +**Phase 2 — accumulator pre-validation.** Runs *before* the transcript, so malformed accumulator public inputs cannot influence challenge derivation. Described in §1.6. + +**Phase 3 — transcript.** A streaming Keccak buffer. `common_word` appends a 32-byte big-endian word; `common_uncompressed_g1` validates and appends 128 bytes; `squeeze_to` hashes the buffer, **reseeds the buffer with the digest**, and samples `digest mod r`. That reseed is exactly equivalent to the Rust `squeeze()`, which finalises a clone and re-inits a fresh `Keccak256` over the output. + +The absorb/squeeze schedule, verified byte-for-byte against `src/plonk/verifier.rs` and `src/poly/kzg/mod.rs`: + +``` +vk_digest → committed_pi (128 zero bytes) → 19 → 19 instances +→ 15 advice → [θ] → 2 lookup-m → [β] [γ] → 6 perm-Z +→ (helper + acc) ×2 → [trash] → 1 trashcan → [y] +→ 4 quotient limbs → [x] → 102 evaluations → [x1] [x2] +→ f_com → [x3, truncated to 128 bits] → 5 q_evals → [x4] → pi +``` + +Every prover-controlled value is absorbed strictly before any challenge that depends on it. `pi` is last and no challenge depends on it. + +Two validation policies matter here: + +- **Scalars** (19 instances, 102 evaluations, 5 q_evals) are checked `lt(v, r)` — a strict canonicality check, so `v = r` is rejected, not silently reduced. Non-canonical encodings would otherwise create transcript aliases. +- **G1 points** get their EIP-2537 padding checked (top 16 bytes of each `_hi` word must be zero) and each coordinate bounded by `p−1`, but **no on-curve or subgroup check here**. Validity is deferred: the code relies on every absorbed point later reaching an EIP-2537 `G1MSM` or `PAIRING_CHECK`, both of which do perform subgroup checks. That is a *codegen-time* invariant (`ProtocolPlan::validate`), and it is why the malformed-point gas behaviour in M-2 exists. + +**Phase 4 — Lagrange.** One 30-element batch inversion computes `x−ω^i` inverses plus `(xⁿ−1)⁻¹`; from these come `l_last` (index 0), `l_blind` (Σ indices 1–9), `l_0` (index 10) and `L_0…L_18` (indices 10–28) for the instance evaluation. If `x` lands on the domain, the batch product is zero, `batch_invert` returns 0, and the verifier reverts — so the `xⁿ = 1` degeneracy fails closed. + +**Phase 5 — quotient identity.** See §1.5. + +**Phase 6 — PCS.** Halo2's multipoint reduction (GWC-style with r-polynomial interpolation, not SHPLONK). 5 rotation sets of cardinality 1, 2, 2, 3, 3 over rotations {−10, −1, 0, +1}; batching by truncated powers of `x1` within a set and `x4` across sets; the whole commitment side collapses into **one fused 78-pair `G1MSM`**. + +**Phase 7 — pairing.** §1.7. + +## 1.5 The quotient identity — a bytecode interpreter in Yul + +The interesting engineering choice. Rather than emitting ~49 straight-line polynomial identities as Yul (which blows past the 24KB contract limit), the generator compiles them to a small stack-machine bytecode, stores that program **inside the VK payload**, and ships an interpreter in the verifier. + +Consequences: +- The program is covered by `EXPECTED_VK_CODEHASH`, so it cannot be tampered with post-deployment. +- The verifier avoids thousands of `PUSH32`/`mstore` immediates. +- The interpreter is ~1,500 lines of Yul with 11 implemented opcodes, including two "native kernels" (`NATIVE_PERMUTATION 0x19`, `NATIVE_LOOKUP 0x1f`) that run the permutation and LogUp arguments as hand-written Yul rather than interpreted arithmetic. + +The 49 identities are `y`-batched by Horner: `A := A·y + eval_j`, so identity *j* receives coefficient `y^(48−j)`, matching the Rust reverse fold in `linearization/verifier.rs`. Ten "simple selector" buckets accumulate separately and are multiplied into the commitment side at `x1^42`, which is how selector-compressed gates are handled. + +The interpreter asserts three structural post-conditions before proceeding: + +```yul +q_pc == q_end // consumed exactly the program +q_has_top == 0 // no live expression left +q_sp == 0xb8e0 // stack pointer restored +``` + +An unknown opcode hits `default { revert(0, 0) }`. These are good defences; the residual concern is **L-6** (operands are raw memory pointers with no bound check). + +## 1.6 The accumulator — recursive-proof handling + +`has_accumulator = 1`, `acc_offset = 11`: public inputs 11–18 encode **two G1 points**, each as 2 coordinates × 2 packed words, with each 381-bit `Fp` coordinate carried as 7 limbs of 56 bits packed 4-per-word. + +The codec is a shifted one: an encoded value `c` decodes to `c + 1`, and encoded `p−1` decodes to `0`. The point at infinity gets a single canonical encoding — `x = p−1 + 2⁵⁶` (the identity flag), `y = p−1` — checked by exact 4-word equality against pinned constants. + +The decoder is carefully written and I could not break it: + +- `check_acc_coord_packing` bounds packed word 0 below `2²²⁴` and word 1 below `2¹⁶⁸`, making the limb split a **bijection** — no two encodings of the same coordinate. +- The reconstructed coordinate is bounded by `p−1`, and `hi < 2¹²⁸` (the EIP-2537 pad rule). +- A decoded `(0, 0)` outside the sentinel path is explicitly rejected, so affine infinity has exactly one accepted encoding. +- `PACKED_0_WITH_ID_FLAG − PACKED_0 = 2⁵⁶` exactly — no carry into the neighbouring limb. +- The `sub(packed, first_adjust)` cannot underflow: the identity probe only runs behind a `calldataload(src) >= base` prefilter. + +Both decoded points are then forced through `G1MSM` with scalar 1 — not to compute anything, but because **the precompile is the on-curve/subgroup validator**. The comment says so explicitly, and the code does it even for identity points and unit scalars, which is exactly right: skipping the call would let a malformed non-identity point hide behind a zero scalar. + +The accumulator's own pairing equation `e(acc_rhs, G₂) = e(acc_lhs, [s]G₂)` is then folded into the KZG pairing by **randomised batching** rather than naive multiplication (which would let two false equations cancel): + +```yul +alpha = keccak256("pairing-batch-acc-kzg" ‖ kzg_rhs ‖ kzg_lhs ‖ acc_rhs ‖ acc_lhs) mod r +if alpha == 0 { alpha = 1 } +PAIRING_RHS += alpha · ACC_RHS +PAIRING_LHS += alpha · ACC_LHS +``` + +`alpha` is drawn only after all four G1 points are final, so if either equation is false the combined one holds for at most one `alpha` in `Fr` — a ~2⁻²⁵⁵ forgery probability. The zero-draw guard prevents the accumulator equation from being accidentally dropped. This is correct. + +## 1.7 The final pairing + +``` +e(final_com − v·G + x3·π, G₂) · e(π, −[s]G₂) = 1 +``` + +which rearranges to the standard KZG single-opening identity `e(C − vG + x3·π, G₂) = e(π, [s]G₂)`. The Rust reference negates the G₂ *generator* instead of `s·G₂`; algebraically the same equation, and the generated comment (lines 3653–3665) explains the LHS/RHS naming inversion honestly. + +`ec_pairing` checks three things — staticcall success, `returndatasize() == 0x20`, and `mload(scratch) == 1` (strict equality, not a low-bit mask) — and reverts on entry if `success` is already false, so no path hands control back to a caller that would report success for an unverified proof. + +--- + +# Part II — Conformance against `midfall/proofs` + +Every phase of the Rust verifier was diffed against the Solidity. The recovered circuit shape, derived from the artefacts and cross-checked for internal consistency: `k=20`, `cs_degree=5`, `blinding_factors=9`, `rotation_last=−10`, 15 advice columns (1 phase, 0 user challenges), 27 fixed columns of which 10 are simple selectors, 18 permutation columns → 6 sets of `chunk_len=3`, 2 LogUp lookups × 1 chunk, 1 trashcan, 4 quotient limbs, 2 instance columns (1 committed + 1 non-committed with 19 public inputs), 49 quotient identities (29 gate + 13 permutation + 6 lookup + 1 trash), 102 evaluations, 34 proof G1s, 5 KZG point sets, 78 final-MSM terms. Feature profile implied: `keccak-transcript` + `committed-instances` + `truncated-challenges` ON; `single-h-commitment` and `fewer-point-sets` OFF. + +## 2.1 Conformance matrix + +| # | Phase | Rust reference | Solidity | Verdict | +| --- | --- | --- | --- | --- | +| 1 | Hash function | Keccak256, plain `update`, no domain prefix (the `BLAKE2B_PREFIX_*` tags apply only to the Blake2b impl) | Streaming buffer, one `keccak256` per squeeze (`:399,:460`) | **MATCH** | +| 2 | Squeeze / reseed | `out = clone().finalize()`, then `state := Keccak::new().update(out)` (`implementors.rs:198`) | `h0 = keccak(buf)`, `mstore(TRANSCRIPT_MPTR, h0)`, cursor → +32 (`:461-467`) | **MATCH** | +| 3 | Digest → Fr | `BigUint::from_bytes_be(digest) % r` — modular reduction, not rejection sampling | `mod(h0, r)` (`:466`) | **MATCH** (identical, incl. identical bias — see note below) | +| 4 | Scalar absorb encoding | `to_repr()` (LE) reversed → 32 BE bytes | Calldata word verbatim (BE); shim pre-reverses off-chain | **MATCH** | +| 5 | Point absorb encoding | 128-byte EIP-2537 padded uncompressed; identity = 128 zero bytes (`implementors.rs:283`) | `common_uncompressed_g1` copies 4 words verbatim after pad/`Fp` checks (`:434-455`) | **MATCH** | +| 6 | Initial seeding | `vk.hash_into` → `common(&transcript_repr)`, one Fq → 32 BE bytes | `common_word(buf_len, mload(VK_DIGEST_MPTR))` (`:1091`) | **MATCH** on encoding; digest *value* not independently recomputable | +| 7 | Committed-instance commitments | Caller-supplied, absorbed and opened as real PCS queries (`verifier.rs:90,356,610`) | Hard-coded 128 zero bytes = identity (`:1101-1111`) | **MATCH only under `committed_instances = [identity]`** → **L-2** | +| 8 | Instance count + values | Absorb `F::from_u128(len)` then each value | `common_word(…, 19)` then 19 range-checked words (`:1118-1132`) | **MATCH** | +| 9 | Advice / phase order | Per phase: all advice, then that phase's challenges | One phase, 15 G1s, no user-challenge squeeze | **MATCH** | +| 10 | Challenge schedule | θ → lookup-m → β → γ → perm-Z → helpers+acc → trash (unconditional) → trashcans → y → quotient limbs → x → evals → x1,x2 → f_com → x3 → q_evals → x4 → π | Identical (`:1178,1196,1197,1256,1273,1296,1330,1331,1343,1377`) | **MATCH** — verified byte-for-byte | +| 11 | `x3` truncation | `truncate(x3)` = low 128 bits (`kzg/mod.rs:456`) | `and(mload(X3_MPTR), 2¹²⁸−1)` immediately after squeeze (`:1353`) | **MATCH** | +| 12 | `x1`/`x4` power truncation | Accumulator full precision, each emitted power truncated | `acc := mulmod(acc,x1,r)` full; stored value masked (`:3011,:3379`) | **MATCH** | +| 13 | `x2` | Not truncated | Unmasked | **MATCH** | +| 14 | Trailing-data check | `Transcript::assert_empty` | `proof_cptr == NUM_INSTANCE_CPTR` (`:1395`) + exact `calldatasize` | **MATCH** (Solidity stricter) | +| 15 | Instance evaluation | `l_i_range(x, xⁿ, …)`, inner product | Fixed `L_0…L_18` (`:1457-1466`) | **MATCH** given `max_rotation == 0` over instance queries (codegen-enforced) | +| 16 | Lagrange formula | `L_i(x) = ωⁱ(xⁿ−1)/(n(x−ωⁱ))` | `l_i_common · inv(x−ωⁱ) · ωⁱ` (`:1436-1442`) | **MATCH** | +| 17 | `l_last` / `l_blind` / `l_0` | `l_evals = l_i_range(x, xⁿ, −(b+1)..=0)`; `b = 9` | slot 0 / Σ slots 1–9 / slot 10 (`:1446-1452`) | **MATCH** | +| 18 | Identity family order | gates → permutation → lookups → trash (`plonk/mod.rs:516-607`) | Inline gate prefix → VM (gates, `NATIVE_PERMUTATION`, `NATIVE_LOOKUP`) → trash suffix | **MATCH** | +| 19 | `y`-power aggregation | Reverse fold: identity *j* gets `y^(m−1−j)`, `m = 49` | Horner from the front + selector gap/tail bookkeeping — same exponents | **MATCH** (all 21 in-bytecode gaps and 10 selector tails checked arithmetically) | +| 20 | Selector compression | Simple-selector fixed evals replaced by `ONE`, identity attributed to the gate's first simple selector | Selector eval hard-coded `0x1`; 10 buckets × `x1^42` paired with the right fixed commitments (`:3491-3510`) | **MATCH** | +| 21 | Permutation argument | `l_0(1−z_0)`; `l_last(z_L²−z_L)`; `l_0(z_i − z_{i−1}^last)`; per-chunk with `βx·DELTA^(chunk·len)` | Identical (`:2095-2130`); `DELTA = 7^(2³²)` and `DELTA³` verified numerically | **MATCH** | +| 22 | LogUp argument | `(l_0+l_last)Z`; `h·Πf − Σ_j Π_{k≠j} f_k`; `((Z_next−Z−sΣh)(t+β)+m)·active`; θ-compression | Identical, but prefix/suffix products instead of `product · f⁻¹` (`:2179-2196`) | **MATCH** on value; see L-2 note below | +| 23 | Trash argument | `fold(acc·τ + e) − (1−q)·trash_eval` | `:2861-2865` | **MATCH** | +| 24 | Quotient reconstruction | limb scalars `(1−xⁿ)(x^{n−1})^k` | `x_split = x^(2²⁰−1)`, `one_minus_x_n` (`:2942-2965, 3479-3490`) | **MATCH** | +| 25 | Expected opening scalar | `expected_eval −= eval` for the `None` group | `QUOTIENT_EVAL_MPTR := −A` (`:2921`), 43rd eval of set 0 at `x1^42` | **MATCH** | +| 26 | PCS scheme | Halo2 multipoint (GWC-style with r-poly interpolation), **not** SHPLONK | Same reduction shape | **MATCH** | +| 27 | Rotation sets | `construct_intermediate_sets` then `sort_by_key((len, i))` | 4 rotations, 5 sets of size 1,2,2,3,3 | **MATCH** for this VK | +| 28 | `x1` batching | `q_com[s] = Σ x1ⁱ C_{s,i}`, `q_eval_set[s] = Σ x1ⁱ e_{s,i}` | 43 truncated powers; per-set folds; MSM scalars `x1ⁱ·x4ˢ` | **MATCH** | +| 29 | `f_eval` | Reverse fold `acc = acc·x2 + (q_eval_s − r_s(x3))/Π(x3−p)` | Sets 4→0 (`:3214-3366`), algebraically identical form | **MATCH** | +| 30 | `v` | `inner_product([q_evals…, f_eval], truncated_powers(x4))` | `:3390-3395` | **MATCH** | +| 31 | `final_com` | `msm_inner_product([q_coms…, f_com], truncated_powers(x4))` | Single fused 78-term G1MSM (`:3396-3559`) | **MATCH** | +| 32 | Pairing / negation | `e(π, s_g2)·e(final_com − vG + x3π, n_g2) = 1` — G₂ **generator** negated | `e(final_com − vG + x3π, G₂)·e(π, −[s]G₂) = 1` — `s·G₂` negated | **MATCH** — same equation, sign carried on the other element | +| 33 | Domain constants | `EvaluationDomain` | VK words 2–6 | **MATCH — verified numerically** | +| 34 | `blinding_factors` / `rotation_last` | `max(3, max_advice_queries) + n_trash + Σchunks + 3 = 9`; `−10` | 9 negative Lagranges; `ω⁻¹⁰` | **MATCH** | +| 35 | `quotient_poly_degree` | `cs_degree − 1 = 4` | 4 quotient limbs | **MATCH** | +| 36 | G1/G2 bases | `G1Affine::generator()`, `params.g2()`, `−params.s_g2()` | VK words 11–30 | **MATCH** for G1/G2 (byte-compared to canonical generators); `NEG_S_G2` unverifiable → **H-1** | + +### Note on challenge sampling bias + +Both sides compute `keccak256(...) mod r` on a **256-bit** digest reduced into a **255-bit** prime field. This is *not* the usual "wide hash, negligible bias" situation: `floor(2²⁵⁶/r) = 2`, so 20.8% of residues have three preimages and the rest have two. Statistical distance from uniform is **7.47%**. + +That sounds bad and is not. Soundness bounds depend on the *maximum* challenge probability, which is inflated by `3/(2²⁵⁶·(1/r)) = 1.3585×` — **0.44 bits**. Negligible, and bit-identical to the Rust reference, so it is a shared property rather than a divergence. Recorded here because the naive "≈2⁻¹²⁷ bias" figure often quoted for Fiat-Shamir reductions does not apply at this digest/field width and should not be carried into a security argument. + +## 2.2 Where Solidity is *stricter* than Rust + +Worth recording, because a reader of the Rust cannot assume these: + +1. ABI head words, proof length, instance count and `calldatasize()` are all pinned (Rust takes typed arguments). +2. The VK runtime is re-pinned by `extcodesize` **and** `extcodehash` on **every** proof. +3. Six VK header words are cross-checked against baked-in constants. +4. Public instances are range-checked `< r` before absorption. +5. EIP-2537 pad canonicality is enforced — top 16 bytes zero, coordinate ≤ `p−1`. +6. `scalar_inv` rejects both `x ≥ r` and `x == 0`; Rust's `invert().unwrap()` **panics** instead. +7. `batch_invert` rejects any non-canonical or zero denominator; Rust's `ff::BatchInvert` silently **skips** zeros, yielding `L_i = 0` and continuing. +8. Quotient-VM structural post-conditions; unknown opcode reverts. +9. Every precompile call checks `returndatasize()` exactly; the pairing result is compared `== 1`, not masked. +10. Deploy-time smoke tests for MCOPY and three EIP-2537 precompiles, including a known-answer `G1ADD(G,G) = 2G` vector. +11. `ec_pairing` reverts on entry when `success` is already false. +12. Accumulator canonical-encoding checks (exact identity sentinel, unused-bit rejection, `Fp` bound, decoded-`(0,0)` rejection). +13. Every decoded accumulator point is forced through `G1MSM` even at scalar 1, purely for the precompile's validation. +14. An extra, randomised pairing equation for the public accumulator. + +## 2.3 Where Solidity is *laxer* or behaviourally different + +| Item | Difference | Assessment | +| --- | --- | --- | +| **Point validity timing** | Rust's `G1Projective::read` does on-curve + subgroup checks at read time. Solidity absorbs raw calldata into Fiat-Shamir with only pad/`Fp` checks, deferring validity to a later `G1MSM`/pairing. | Fails closed at runtime for all 34 absorbed points — I traced each to a validating precompile. But coverage is a **codegen-time** invariant, not a runtime one: an emitter change that drops a point from the MSM removes its only validation. It is also the direct cause of **M-2**. | +| **Committed instances** | Hard-coded identity; no ABI channel. | **L-2**. Sound as rendered (empirically confirmed below), unsound if the assumption is ever violated. | +| **LogUp with `f_j + β = 0`** | Solidity's prefix/suffix product computes the correct `Σ_j Π_{k≠j}(f_k+β)` and proceeds; Rust's `product * f.invert().unwrap()` **panics**. | Solidity accepts proofs on which Rust aborts. The Solidity value matches the *documented* identity, so this is a robustness gain — but it is a genuine accept/reject divergence on adversarial input and should be recorded as intentional. | +| **`x` landing on the domain** | Solidity reverts; Rust continues with `L_i = 0`. | Negligible-probability divergence. | +| **Multi-proof** | Solidity is single-proof only. | Documented non-goal. | +| **Feature coupling** | Prover and verifier must be built with matching `truncated-challenges` / `fewer-point-sets` / `single-h-commitment`. A mismatch changes the proof length and is caught by the length pin — fails closed, but with no diagnostic. | Feeds **L-8**. | + +## 2.4 Two latent codegen divergences (inert for this VK) + +- **Permutation `z_last` query order.** Rust emits all `(x, z_i)`/`(ωx, z_i)` pairs first, then the `x_last` queries in **reverse** set order. The generator emits `Cur, Next, Last` interleaved per set in forward order. For this VK the resulting point-set structure is identical, because no new rotation and no new commitment is introduced between the two placements — I traced it. It is **not** an order-insensitive transformation in general. +- **Fixed-eval counting.** Rust reads `num_fixed_columns − num_simple_selectors` (column-based); the generator counts non-simple *queries*. Both equal 17 here. A circuit with a rotated fixed query would make Rust under-read and Solidity over-read. + +Neither is a live bug. Both should become explicit generator assertions rather than accidents. + +## 2.5 What could not be verified against the reference + +1. **The accumulator path has no Rust counterpart** in `midfall/proofs` — decoding, the second pairing equation and the randomised batching are all application-level (`midnight-circuits` / Moonlight). The construction is internally sound, but the *orientation contract* (that instances 11–14 are the `[s]`-side and 15–18 the `[1]`-side, matching what the producing circuit exposes) is an assumption. Getting it backwards breaks completeness, not soundness. +2. **`vk_digest = 0x56c0824f…4f66`** cannot be recomputed without the concrete `ConstraintSystem`. +3. **`NEG_S_G2_BASE`** cannot be checked without the ceremony transcript → **H-1**. +4. **The quotient VM bytecode's arithmetic content.** All *structural* properties were verified — 49 identities in the right order, correct `y` exponents, every operand pointer landing inside the absorbed-evaluation window `[0x9480, 0xb140)`, constant-table indices within the 178-word reservation, clean termination. What was not verified is that the ~29 emitted gate expressions encode the intended circuit; that needs the circuit definition. +5. **Upstream `construct_intermediate_sets`** (`src/poly/kzg/utils.rs`) was not available; the generator's re-implementation could only be checked for internal consistency. Note the generator's own caveat: it groups commitments **by memory pointer** where Rust groups **by value**, which is only safe under the single-committed-instance restriction. + +--- + +# Part III — Findings + +Severity reflects impact on the *deployed system*, not on the Solidity in isolation. Line references without a filename are `Halo2Verifier.sol`. + +--- + +## H-1 — High — `NEG_S_G2_BASE` is unverifiable trusted-setup material with no ceremony binding and no build-time consistency check + +**Where:** VK contract lines 88–95 (`neg_s_g2_*`); generator `src/lowering/vk.rs:93-98`. + +```rust +let g1_pt: G1Affine = G1Affine::generator(); +let g2_pt: G2Affine = self.params.g2().to_affine(); +let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); +``` + +`neg_s_g2` is taken verbatim from whatever `params` the generator was handed. The G1 side **is** defended — `vk.rs:81-92` asserts `sum(g_lagrange) == G1Affine::generator()` with a good comment explaining why. There is no analogous check on the G2 side: + +- nothing asserts `params.g2() == G2Affine::generator()`; +- nothing checks that `s_g2` corresponds to the *same* τ that produced `g_lagrange`; +- nothing binds either point to a named ceremony transcript; +- no SRS file hash, ceremony id or transcript URL is recorded anywhere. `CODEGEN_ASSURANCE_DOSSIER.md:46` lists "SRS assumption | Midnight SRS asset names, sizes, and expected source" as a **required manifest record**; no such record exists. The only provenance is a URL in `README.md:192` and `SRS_DIR=…/zk_stdlib/examples/assets` in the fixture README. + +**What I could verify:** `G1_BASE` and `G2_BASE` are exactly the canonical BLS12-381 generators. `NEG_S_G2_BASE` is a valid on-curve point of E′(Fp2) with `b = 4(1+i)`, in the r-order subgroup, and is not ±G₂. That is the limit of what is checkable without the transcript. + +**Failure scenario.** An attacker substitutes the SRS file in `SRS_DIR` with one whose τ they know — or a build host is compromised. The generator emits `neg_s_g2 = −[τ_evil]G₂`. Every downstream control passes: `certify_quotient_program`, `certify_quotient_builds_agree`, `validate_generator_invariants`, the codehash pin, the trace differential, the replay fixture. All of them check *self-consistency*, and the artefact is perfectly self-consistent. The attacker then forges KZG openings for arbitrary statements and `verifyProof` returns `true`. Nothing on-chain or at build time detects it. + +**Remediation** (all implementable with the API already in use): + +1. `assert_eq!(self.params.g2().to_affine(), G2Affine::generator())`. +2. Add a build-time SRS pairing consistency check: commit the polynomial `f(X) = X` in the Lagrange basis (`Σ ωⁱ·L_i`, from the `g_lagrange` the generator already consumes) to obtain `[τ]G1`, then assert `e([τ]G1, G2) == e(G1, s_g2)`. This proves `neg_s_g2` is the negation of the same τ that generated the commitment basis. +3. Pin the SRS by SHA-256 in the generator; record it and the ceremony transcript reference in the artefact manifest; fail the render on mismatch. +4. Publish `neg_s_g2` alongside the ceremony's published τ point so a third party can verify the negation independently. + +Patch **P11** implements (1) and (2). + +--- + +## M-1 — Medium — `assembly ("memory-safe")` is factually false, and the invariant that protects it is enforced only outside the artefact, under a floating pragma + +**Where:** lines 203, 336, 345 (the annotations); lines 58–59 (`TRANSCRIPT_MPTR = RETURN_MPTR = 0x1000`); first write at line 463. Template: `templates/contracts/Halo2Verifier.sol:2,98`. + +All three assembly blocks are annotated `("memory-safe")` but write to absolute addresses (`0x1000 … 0xe340`) never derived from the free-memory pointer. The generator's own documentation admits it (`docs/architecture/MEMORY_LAYOUT.md`, "Solidity Memory Model Boundary"): + +> "…also factually untrue … The annotation is what enables solc's stack-to-memory mover, which reserves spill slots upward from `0x80` … Observed reservations range from `0x80` (none) to `0x8e0`." + +The mitigation lives entirely **outside** the shipped artefact: a generator-side test, `compiled_memoryguard_does_not_overlap_generated_layout`. The `.sol` has no runtime assertion, and the pragma is floating (`^0.8.24`), so a downstream integrator recompiling with a different solc release, `--via-ir` setting or optimiser schedule can move the reservation with no signal. + +**Measured headroom.** I compiled the artefact across four compiler versions and extracted the runtime prologue's `mstore(0x40, X)`: + +| solc | viaIR | runs | runtime bytes | FMP init | headroom to `0x1000` | +| --- | --- | --- | --- | --- | --- | +| 0.8.24 | true | 1 | 29,567 | `0x8c0` | 1,856 B | +| 0.8.26 | true | 1 | 21,295 | `0x8e0` | 1,824 B | +| 0.8.28 | true | 1 | 21,286 | `0x8e0` | 1,824 B | +| 0.8.30 | true | 1 | **21,286** | `0x8e0` | 1,824 B | +| 0.8.30 | true | 200 | 21,318 | `0x8e0` | 1,824 B | +| 0.8.30 | true | 100000 | 29,836 | `0x8e0` | 1,824 B | + +So the reservation **does vary with compiler version** (`0x8c0` vs `0x8e0`) — the invariant is not a fixed quantity — and the surviving margin is 57 words, unmonitored at runtime. + +**Failure scenario.** Compile with a solc/optimiser combination whose stack-limit evader reserves ≥ `0xF80` bytes. The prologue then emits `mstore(0x40, X)` with `X > 0x1000` and a live Yul spill slot sits at ≥ `0x1000`. The first transcript write — `mstore(TRANSCRIPT_MPTR, h0)` at line 463, or `calldatacopy(buf_len, cptr, 0x80)` at line 453 — overwrites it. If the clobbered local is `success` (line 974) or `proof_cptr` (line 1155), the terminal checks at 1395 / 3666 / 3678 read attacker-influenced garbage. + +**A second, immediately concrete consequence.** The floating pragma is not merely theoretical. I compiled and attempted deployment under `revm` Prague: + +``` +solc 0.8.24 runs=1 : DEPLOY FAILED -- HALT CreateContractSizeLimit (29,567 B > 24,576) +solc 0.8.30 runs=1e5 : DEPLOY FAILED -- HALT CreateContractSizeLimit (29,836 B > 24,576) +solc 0.8.30 runs=1 : DEPLOYED +``` + +**The contract as shipped is undeployable at the minimum compiler version its own pragma permits.** `^0.8.24` advertises compatibility the artefact does not have. + +**Remediation.** Two lines, both cheap: + +```solidity +pragma solidity 0.8.30; // pin exactly +``` +```yul +if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } // ~6 gas, once +``` + +The guard makes the invariant self-enforcing in the deployed bytecode instead of depending on a test in another repository. Patches **P2** and **P3**. + +*Related:* the constructor's `require_eip2537_precompiles()` runs in the **creation** frame under the same false annotation and writes `0x1000`–`0xe200`, but the generator's guard test inspects only the *runtime* prologue (`src/evm.rs:233-268` is explicitly typed for runtime). Fail-closed in practice (a corrupted `authorizedVk` spill would fail the codehash `require`), but the asymmetry looks unintended. Also: the shipped comments at lines 316–317 and 347 claim "generated scratch starts at `0x80`", contradicting `TRANSCRIPT_MPTR = 0x1000` on line 58 — this is precisely the stale belief the team's own TA-5 finding identified as the hazard, and it is hardcoded in the template so **every** render ships it (**I-1**). + +--- + +## M-2 — Medium — A malformed curve point burns ≈63/64 of the supplied gas instead of reverting cheaply + +**Where:** every `staticcall(gas(), 0x0c, …)` — lines 911, 956, 3558, 3573, 3584, 3629, 3643 — and the deferred-validation policy documented at lines 425–429. + +Because `common_uncompressed_g1` deliberately does **not** run a curve check (§2.3), an invalid point survives until it reaches a `G1MSM`. EIP-2537 precompiles that reject their input **consume all gas forwarded to them**, and `staticcall(gas(), …)` forwards 63/64 of what remains. + +**Measured** (revm Prague, single flipped byte in `advice[0].x_lo`): + +| tx gas limit | off-curve point | invalid evaluation | bad EIP-2537 pad | valid proof | +| --- | --- | --- | --- | --- | +| 2,000,000 | **1,979,170** | 1,279,485 | 315,950 | — | +| 5,000,000 | **4,932,295** | 1,279,485 | 315,950 | — | +| 30,000,000 | **29,541,670** | 1,279,485 | 315,950 | — | +| 500,000,000 | **492,197,920** | 1,279,485 | 315,950 | 1,279,482 | + +A cryptographically-invalid proof costs a bounded 1.28M. A structurally-malformed one costs 316k. But a proof containing **one byte** that puts a point off-curve costs whatever you were willing to spend — 98.5% of it, at zero marginal cost to the person who chose that byte. + +**Failure scenario.** Any component that pays gas on someone else's behalf or continues after a failed verification: + +- A relayer / paymaster / ERC-4337 bundler submitting user proofs pays 30M instead of 1.3M — a 23× amplification, chosen by the user, per transaction. +- A wrapper doing `try verifier.verifyProof(…) { } catch { }` regains control with 1/64 of the gas, almost certainly too little to finish, so the whole transaction reverts anyway — the `catch` branch becomes unreachable in practice. +- A batch verifier looping over N proofs is destroyed by one bad point in the first. + +**Remediation.** Cap the gas forwarded to the validating calls. EIP-2537 `G1MSM` pricing is a pure function of input length (`k · 12000 · discount[k] / 1000`), with no data dependence, so an **exact** constant is computable at codegen time; a 2× margin absorbs any schedule change: + +```yul +// was: staticcall(gas(), 0x0c, ptr, len, out, 0x80) +staticcall(G1MSM_GAS_78, 0x0c, ptr, len, out, 0x80) +``` + +This turns a 30M burn into a bounded ~1M. Patch **P1**. Note the cap must be generous and codegen-derived — a hand-tuned value that is too tight becomes a liveness bug on a chain with a different schedule. + +--- + +## M-3 — Medium — The deployment probe is weakest exactly where acceptance is decided + +**Where:** lines 202–286 (`require_eip2537_precompiles`); template `PrecompileSmoke.sol`. + +The smoke test hardens `G1ADD` with a known-answer vector and states the reasoning explicitly and correctly (lines 229–238): + +> "Every probe above uses the point at infinity, which is exactly the input an implementation gets right without doing any curve arithmetic — a precompile that returns its zero-filled input, or zeros for anything, satisfies them… So add one vector whose answer a stub cannot guess." + +That reasoning was **not applied to the two precompiles that decide the outcome**: + +- **`0x0f` PAIRING_CHECK** (line 282) is probed only as `PAIRING_CHECK([(0,0),(0,0)]) == 1`. A chain whose `0x0f` returns `1` unconditionally, or omits G2 subgroup checks, passes deployment and then accepts **every** proof — `ec_pairing` is the sole accept gate. +- **`0x0c` G1MSM** (line 272) is probed with `0x30c0` bytes of all-zero terms. Line 270 says "the production verifier uses G1MSM… **as the subgroup validator** for absorbed proof points" — and then tests it with 78 identity terms, exercising no rejection behaviour at all. + +The team already found this. `AUDIT.md` **TA-6, "Precompile Smoke Tests Are Too Weak For Deployment Confidence"**, is rated **Low**, carries **no `Status:` line** (it is un-triaged — every other TA item has one), and recommends exactly: known-valid and known-invalid pairing equations, invalid G1/G2 encodings that must fail, and boundary scalars `0, 1, r−1, r`. None are present. `ARCHITECTURE_REVIEW_2026-08.md` §7 concedes the residual state: *"EIP-2537 semantics (incl. subgroup checks) | Assumed per spec; constructor smoke proves existence/arithmetic, not rejection behavior | **Assumed**"*. + +**Verified good:** the strict `returndatasize()` checks do make the verifier fail closed on a chain **without** EIP-2537 — a staticcall to an empty account succeeds with `returndatasize() == 0`. I confirmed this: the constructor reverts under `SpecId::CANCUN`, `SHANGHAI` and `MERGE`. So *existence* is genuinely proven; *correctness* is not. + +**Remediation.** Add constant-size known-answer probes (deployment-gas cost only): a true pairing `e(G,G₂)·e(−G,G₂) == 1`, a **false** pairing `e(G,G₂)·e(G,G₂) == 0`, a `G1MSM` known answer `[2]·G == 2G`, and a negative probe with a known wrong-subgroup encoding that must cause the precompile to fail. Give TA-6 a `Status:` and re-rate it — with the whole accept path resting on `0x0f`, Low is too low. Patch **P5**. + +--- + +## M-4 — Medium — `vk_digest` does not cover the SRS points, the quotient program, the accumulator schema, or the feature profile + +**Where:** `../proofs/src/plonk/mod.rs:246-277`; line 1091 (absorption); lines 1018–1023 (header cross-check). Team's own finding: `AUDIT.md` TA-2, and item 2 of their "Time-Boxed Audit Priorities Before Production". + +`transcript_repr` hashes `VERSION`, `k`, fixed commitments, permutation commitments, and the `Debug` strings of `domain.pinned()` / `cs.pinned()`. It does **not** cover `G1_BASE` / `G2_BASE` / `NEG_S_G2_BASE`, the quotient VM constant pool or bytecode, the accumulator schema, or the Cargo feature profile (`truncated-challenges`, `outer-fewer-point-sets`, `outer-single-h-commitment`). The transcript therefore does not bind them. + +The on-chain header cross-check covers 6 of 31 header words (`num_instances`, `k`, `has_accumulator`, `acc_offset`, `num_acc_limbs`, `num_acc_limb_bits`). `vk_digest`, `n_inv`, `omega`, `omega_inv`, `omega_inv_to_l` and all three base points are not cross-checked. Codehash pinning makes this non-exploitable post-deploy, but the comment's claim that these checks "catch generator drift" is narrower than it reads. + +**On the wrong-VK question specifically:** a wrong-but-well-formed VK **cannot** be paired with this verifier — the constructor reverts on codehash mismatch, and the loader re-checks on every proof. I confirmed both empirically (a 1-bit-mutated VK and an EOA address both revert the constructor). But a VK generated from a *different SRS or feature profile* for the same circuit produces a self-consistent verifier+VK pair that no digest distinguishes. That residual compounds H-1 and L-8. + +**Remediation.** Absorb `EXPECTED_VK_CODEHASH` into the transcript, or redefine `vk_digest` over the full runtime payload — the team's own TA-2 recommendation, still open. + +--- + +## M-5 — Medium — The build is not reproducible as documented + +**Where:** `fixtures/moonlight-wrap/README.md:17`, `docs/audit/REVIEW_PACKET.md:60-84`, `docs/audit/CODEGEN_ASSURANCE_DOSSIER.md:34-47`, `src/evm.rs:179-183,208`, `tests/ivc_accumulator_replay.rs:55`, `scripts/install_pinned_solc.sh:29-34`. + +Three mutually unreconcilable provenance stamps exist for this artefact: + +| Source | Stamp | +| --- | --- | +| `fixtures/moonlight-wrap/README.md:17` | solidity-verifier commit `3fb6d84` | +| `REVIEW_PACKET.md:67` | repository commit `a096e71746e401404f250817ca4e857bac1eef56` | +| `CODEGEN_ASSURANCE_DOSSIER.md:37` | Midfall revision `53dc872f495104046d96bdac0a690f903dc0c537` | + +`REVIEW_PACKET.md` §4 "Artifact Manifest" — the table meant to pin *this* artefact — reads `fill per artifact` for all eleven hash rows. `docs/reference/REPRODUCIBLE_BUILDS.md`, cited from three places as where the hashes live, was not in scope. + +The recorded solc flag list is also incomplete. Both the dossier (`:40`) and the packet (`:71`) record `--bin --optimize --via-ir --evm-version cancun --no-cbor-metadata` — **`--optimize-runs` is missing**. `src/evm.rs:179-183` reads it from the environment (`SOLC_OPTIMIZE_RUNS`, default `200`), while the one test that exercises this fixture pins a *different* value (`tests/ivc_accumulator_replay.rs:55: const SOLC_OPTIMIZE_RUNS: u32 = 1`). + +**This is not cosmetic.** As measured under M-1, the setting is load-bearing for *deployability*: at `runs=100000` the runtime is 29,836 bytes and the deployment halts with `CreateContractSizeLimit`. A "reproducible" build whose success depends on an unrecorded environment variable is not reproducible. + +Separately, `install_pinned_solc.sh` downloads the compiler over HTTPS and validates it only by its own `--version` output, which a substituted binary forges trivially. `binaries.soliditylang.org` publishes SHA-256 and keccak-256 for every release in `list.json`; the script uses neither. For a project whose entire reproducibility claim rests on the string `0.8.30+commit.73712a01`, pinning by version string rather than content hash is the wrong pin. (`Darwin-arm64` also maps to `macosx-amd64`, so Apple Silicon developers run an x86 compiler under Rosetta — a different binary from CI, unchecked.) + +**Remediation.** Fill the manifest for the real deployment artefact; add `--optimize-runs ` to the recorded flags and remove the env override from the reproducible path; reconcile the three stamps to one; ship `REPRODUCIBLE_BUILDS.md` with the artefact; verify solc by SHA-256. Patch **P13**. + +**Credit where due:** the VK half *is* solidly reproducible. Its runtime is pure returned data, so `keccak256(0xfe ‖ payload) = 0xe68d8936…cf52` at length 17,025 is solc- and optimiser-independent. I recomputed it from source and it matches. That is a good design property worth preserving. + +--- + +## L-1 — Low — Codegen certification covers the emitter leg only; the leg that executes on-chain is fixture-sampled + +**Where:** `src/lowering/quotient_numerator/vm/certify.rs:129-225`, `vm/reference.rs:20-27`, `src/lowering/plan.rs:167-183`, `tests/ivc_accumulator_replay.rs:18-45`. + +The certification is real and unconditional — `LoweringPlan::new` panics the render if `certify_quotient_program` or `certify_quotient_builds_agree` fails, the challenge seed derives from the finalised bytecode + constant table + expression trees + VK payload, and the dual build with recognizers disabled turns every shape recognizer into a checked optimisation. That is better than most generated-verifier projects. Its coverage boundary is narrow, though, and the boundary is where a supply-chain attack would land: + +1. **The front end is uncovered.** Certification compares emitted bytecode against the `QuotientExpr` the lowering itself produced. A bug in the halo2-`Expression` → `QuotientExpr` translation is wrong on both sides and agrees with itself. The team identified this exact hazard for *pointers* and built `validate_quotient_mem_ptrs` (`plan.rs:346-348`: *"certification cannot do this: it compares the bytecode against the expression tree, so a pointer that is wrong in both agrees with itself"*) — but not for expressions. +2. **Native kernels are uncovered.** `NATIVE_PERMUTATION` / `NATIVE_LOOKUP` / `NATIVE_IDENTITY` are checked only for stream position (`certify.rs:180`: *"Native markers carry no arithmetic here."*). The permutation and LogUp kernels are trusted code. +3. **The on-chain Yul VM is uncovered.** `reference.rs:20-27` scopes it explicitly: the reference-interpreter → Yul leg is covered "by the opcode and memory-token table conformance tests and by the per-identity Rust/Solidity trace differential on fixture circuits". §7 adds: *"an opcode no fixture emits has unverified runtime semantics."* + +**Direct answer to "could a malicious edit produce an accepting verifier that still passes the repo's own tests": yes.** Edit `templates/partials/quotient_numerator/*.yul` or a native kernel. `certify` never touches Yul. The SRS-free replay test compiles **committed pre-rendered `.sol` from the fixture directory**, not fresh template output — its own header says so: *"the replay keeps passing after a codegen change — it just stops testing current output."* The only gate that would catch it is the SRS-gated trace differential, which per §10 runs weekly / on push-to-main, not in the default CI job. + +**Remediation.** Pin a digest of the `templates/` tree as a constant checked by a CI test, so any template edit forces an explicit fixture re-render and README commit-stamp bump. Needs no SRS. Longer term: extend certification to the front end by evaluating `vk.cs()` expressions directly at the same challenge assignment, and add a native-kernel differential independent of fixture coverage. Patch **P14**. + +--- + +## L-2 — Low — Committed-instance commitment hard-wired to the identity; one MSM term silently omitted while the emitted comment claims otherwise + +**Where:** lines 1101–1111 (128 zero bytes absorbed); line 3023 (`// q_eval_set[0]: 43 commitment(s)`); lines 3397–3399 (the MSM skips `x1^1`). Generator: `src/lowering/encoding/mod.rs:255-258, 409-415`. + +The eval side computes `q_eval_set_0 = Σ_{i=0..42} x1ⁱ · eval[table[i]]` — 43 terms. The commitment side materialises only 42: line 3397 stores scalar `1`, then line 3399 jumps straight to `x1^2`. The orphaned eval is `table[1] = REVERSED_EVALS[0] = 0x9480`, the committed-instance column's evaluation. The omission is consistent with `committed_pi = G1Affine::identity()` (an identity commitment contributes nothing to an MSM), but **no comment, constant or runtime check states it**, and the emitted comment on line 3023 actively contradicts the emitted code. + +**Empirically confirmed sound as rendered.** In the fixture, `eval[0] = 0x0000…0000`. Setting it to any other value is rejected (test N4, reject at 1,279,485 gas — i.e. it runs to the pairing and fails there). This is exactly the expected behaviour: with an identity commitment the batch check pins the claimed opening to zero, and `x1^1 ≠ 0`, so the column is fully constrained. Omitting the identity term from the MSM is a gas optimisation, not a soundness gap. + +**The risk is drift, not the current render.** If a future render ever needs a non-identity committed-instance commitment, this verifier would keep hashing 128 zero bytes and keep omitting the term, verifying the wrong statement with no runtime signal. The counts (43 vs 42), the exponent multiset, and the `0x30c0` MSM length are all independently hardcoded, so the discrepancy is invisible to every existing check. + +**Remediation.** Either emit the identity term explicitly (`G1_IDENTITY_MPTR` at line 144 exists for exactly this and is currently unused — dead), or add a generator invariant asserting that per point set the multiset of `x1` exponents in the MSM equals `{0 … m−1}` minus exactly the indices of commitments *proven* to be the identity, and render a comment naming the omitted index. Patch **P7**. + +--- + +## L-3 — Low — 41 bare `revert(0, 0)` sites; `verifyProof` can never return `false` + +**Where:** 41 sites including 212, 338, 367, 439, 610, 1007, 1024, 1048, 1064, 1133, 1316, 1369, 1395, 1482, 2620, 3666, 3678. The only reason-carrying failure is the constructor's `require(…, "invalid vk")`. + +At the call site, "malformed calldata shape" (338), "VK code changed under us" (1007), "non-canonical instance" (1133), "bad proof" (3666) and out-of-gas are all indistinguishable — empty returndata. That materially degrades incident response: you cannot tell a VK swap from a bad proof. + +Separately, line 3679 unconditionally stores `1`, so `verifyProof` returns `true` or reverts; it never returns `false` despite `returns (bool)`. This is documented at line 324, but integrators writing the idiomatic `if (!verifier.verifyProof(p, i)) { … }` get a bubbled empty revert rather than the false branch. + +**Remediation.** Give each failure class a 4-byte custom-error selector — `mstore(0x00, shl(224, sel)); revert(0x00, 0x04)` — writing at `0x00`/`0x04` is legitimate scratch and does not disturb the layout. At minimum distinguish ABI-shape, VK-mismatch, canonicality, precompile-failure and pairing-failure. Patch **P4**. + +--- + +## L-4 — Low — The exact-`calldatasize` pin makes the verifier uncallable through calldata-appending relayers + +**Where:** lines 1042–1045 (`calldatasize() == 0x2144`). + +The check is correct and fail-closed, but it means the verifier cannot be called through anything that appends calldata: ERC-2771 trusted forwarders append the 20-byte original sender; several relayer, multicall and paymaster patterns append context words. Confirmed empirically — test N25 (20 appended bytes) reverts, as does N24 (32 appended zero bytes). + +The four other pins (head words at 337, proof length at 1037, instance count at 1038, terminal `proof_cptr == NUM_INSTANCE_CPTR` at 1395) already make trailing bytes unreadable by the parser, so relaxing to `>=` loses nothing. Either relax it, or state the constraint in the `verifyProof` NatSpec — right now an integrator hits an empty revert with no diagnostic (see L-3). + +--- + +## L-5 — Low — `CHALLENGE_MPTR` aliases `THETA_MPTR` + +**Where:** line 83 (`CHALLENGE_MPTR = 0x7900`), line 89 (`THETA_MPTR = 0x7900`), line 1178. Template `TranscriptProofParser.yul:127`, `Constants.sol:66`. + +Inert here: this circuit has zero user-phase challenges, so the template's per-phase squeeze loop rendered nothing, and `CHALLENGE_MPTR` is referenced only by its own declaration. + +**For any circuit with ≥ 1 user-phase challenge**, the template emits `squeeze_to(buf_len, add(CHALLENGE_MPTR, 0x0))` → writes `0x7900`; line 1178 then unconditionally does `squeeze_to(buf_len, THETA_MPTR)` → overwrites `0x7900`. Every later read of the user challenge silently returns theta. The transcript still matches the prover (the squeezes happen in order), so the proof simply fails to verify — a permanent, silent liveness break; and if a gate happens to be satisfied under the substitution, a soundness break. + +**Remediation.** Give `CHALLENGE_MPTR` its own window and add a planner assertion that the challenge window and the theta-window slots do not intersect. Patch **P8**. + +--- + +## L-6 — Low — Quotient-VM operands are unvalidated raw memory pointers + +**Where:** `q_ptr := shr(240, mload(q_pc))` at 1798, 1832, 1839, 1885, 1931; `and(shr(232, q_word), 0xffff)` at 1919, 1937, 1981; `q_sel_idx` / `q_sel_gap` at 2628–2648; stack arithmetic at 1801, 1811, 1910. + +Every operand is a `u8`/`u16` used directly as a memory address (`mload(q_ptr)`, `mload(add(q_const_mptr, shl(5, qconst)))`, `mstore(add(SELECTOR_ACC_MPTR, shl(5, q_sel_idx)))`) with no bound check. `q_sel_gap` is 16 bits but the y-power table holds only 49 entries, so `gap > 48` reads into the VM stack region. `case 0x06` does `q_sp := sub(q_sp, 0x20)` with no underflow guard, and the terminal `eq(q_sp, 0xb8e0)` check does **not** catch a *balanced* underflow. + +None of this is attacker-reachable today: the program lives in the codehash-pinned VK payload, and I confirmed no code path writes into `0x3680…0x7900` after the `extcodecopy`. The safety argument is entirely "the emitter never produces such a program" — there is no on-chain validator. **This becomes Critical if the VK is ever made upgradeable or parameterised.** + +**Remediation.** Clamp operands at decode time (~10 gas each): `if or(lt(q_ptr, 0x9480), gt(q_ptr, 0xb140)) { revert(0,0) }`; `q_sel_gap < 49`; `q_sel_idx < 10`; `if lt(q_sp, 0xb900) { revert(0,0) }` before the `sub`. Patch **P12**. + +--- + +## L-7 — Low — Zero-slack memory adjacencies; `batch_invert` scratch would corrupt silently + +**Where:** lines 486–599, 1431; `BATCH_INV_SCRATCH_MPTR = 0xb140`, `LAGRANGE_DENOMS_MPTR = 0xb580`. + +I recomputed all of these; every one is exactly correct and every one has **zero** slack: + +- With the 30 Lagrange inputs, `batch_invert`'s forward pass writes 28 prefix products to `0xb140…0xb4c0` and the modexp frame to `0xb4c0…0xb580` — ending *exactly* at `LAGRANGE_DENOMS_MPTR`. One more denominator and the frame's first word (the literal `0x20` base-length) overwrites `denominator[0]`; the backward pass then reads it and produces silently wrong inverses **with no revert** — the modexp still succeeds and `ret` stays 1. +- VK payload `0x3680 + 0x4280 = 0x7900` = `CHALLENGE_MPTR` exactly. +- `REVERSED_EVALS 0x9480 + 0xcc0 = 0xa140` = `ADVICE_COMMS_MPTR_BASE` exactly. +- The proof-commitment regions chain exactly to `0xb140`. +- Fused MSM `0xb280 + 0x30c0 = 0xe340` exactly. + +The `batch_invert` case is the dangerous one because it fails *silently*. Add an explicit planner assertion `scratch_len >= (n−2)·32 + 0xc0`. Patch **P9**. + +*(I also hand-verified `batch_invert`'s algorithm for n = 2, 3, 4 and 30 — the prefix/backward-pass indexing is correct, and the one-past-the-end `gp_mptr` decrement in the final iteration is computed but never dereferenced.)* + +--- + +## L-8 — Low — No on-chain provenance + +**Where:** artefact-wide; `src/evm.rs:208` (`--no-cbor-metadata`); `ARCHITECTURE_REVIEW_2026-08.md` §8: *"Feature flags ↔ expected proof schema | **Recorded nowhere in the artifact**"*. + +Nothing in the deployed runtime identifies the generator commit, the feature profile, the circuit, or the SRS. CBOR metadata is stripped, so Sourcify/Etherscan metadata matching is unavailable and source verification requires exact-flag recompilation — which M-5 shows is not fully specified. + +Proof-schema mismatches fail closed (rejected proofs, not accepted ones), so this is an incident-response problem rather than a soundness one. But during an incident, "which of our deployed verifiers has the affected codegen?" is unanswerable from chain state. + +**Remediation.** Emit `bytes32 public immutable BUILD_ID = H(generator_commit ‖ feature_list ‖ vk_digest ‖ EXPECTED_VK_CODEHASH ‖ srs_hash)`. One immutable, zero runtime cost on the verify path, and fleet inventory becomes mechanical. Patch **P10**. + +--- + +## L-9 — Low — No incident-response story, and no domain binding + +**Where:** artefact (zero `sstore` / `delegatecall` / `selfdestruct` / owner / pause / upgrade); line 1091; `AUDIT.md` TA-8, F-4. + +Immutability is the right call here: no admin key means no admin-key compromise, and `verifyProof` stays `external view`. Deploy ordering is enforced fail-closed (VK first; a wrong VK reverts the constructor — confirmed empirically). Two consequences are undocumented: + +**(a) Incident response.** If a soundness bug is found post-deployment there is no on-chain mitigation whatsoever. The only lever is the application wrapper. Nothing in the repo states the corollary requirement: **every wrapper must hold the verifier behind a replaceable address and must have its own pause.** A wrapper that hardcodes the verifier as `immutable` or `constant` has no recovery path at all. This belongs in the generated NatSpec. + +**(b) Cross-chain / cross-deployment replay.** The transcript begins at `vk_digest`. There is no `chainid`, no verifier address, no domain separator anywhere. A proof valid against this bytecode is valid against **every** deployment of this bytecode on **every** chain, forever. The NatSpec does tell wrappers to bind chain/domain — the right architectural split for a raw verifier — but a deployer who treats `verifyProof == true` as authorisation has an unconditional cross-chain replay. + +--- + +## L-10 — Low — 128-bit truncated challenges cap PCS soundness at ≈2⁻¹⁰⁸ + +**Where:** line 1353 (`x3`), 3010–3017 (`x1` powers), 3379–3389 (`x4` powers). Mirrors `truncated-challenges` in `src/poly/kzg/mod.rs` and `src/utils/arithmetic.rs:246-256`. + +**Derivation.** `x3` is the dominant term, so take it precisely. After `x1`/`x2` batching the prover commits `f_com`, and only then is `x3` squeezed. Let + +``` +g(X) = Σ_s x2^s · (q_s(X) − r_s(X)) / Z_s(X) +``` + +where `r_s` interpolates the *claimed* evaluations on point set `s`. If every claim is honest, each `(q_s − r_s)` vanishes on set `s` and `g` is a polynomial; if any claim is false, `g` acquires a pole and is not a polynomial at all. The prover must nevertheless commit `f_com` to some polynomial `f′` of degree `< n`. Clearing denominators with `B = Π_s Z_s`: + +``` +N(X) = f′(X)·B(X) − Σ_s x2^s · (q_s(X) − r_s(X)) · Π_{t≠s} Z_t(X) +``` + +`N ≢ 0` exactly when the prover is lying, and the verifier accepts iff `N(x3) = 0`. + +- **Degree.** `deg f′ ≤ n − 2`; `deg B = 1+2+2+3+3 = 11` (the five point-set cardinalities in this render); so `deg N ≤ n + 9 = 2²⁰ + 9`, i.e. `log₂ = 20.0000124`. +- **Sampling set.** `and(x3, 2¹²⁸−1)` leaves `x3` essentially uniform on `2¹²⁸` values. +- **Bound.** `(n+9)/2¹²⁸ = 2^−107.99999`. Untruncated it would be `2^−234.5`, so the mask costs ~127 bits. + +**The bound is essentially tight.** With `A` and `B` fixed, an adversary can choose `f′` to interpolate `A/B` at `2²⁰` values of their choosing inside `[0, 2¹²⁸)` — `2²⁰` constraints uniquely determine a degree-`<2²⁰` polynomial, and any such polynomial is committable with the SRS. So all roots of `N` really can be placed in range. `x3` is hashed after `f_com`, so the attack is grinding: perturb a free part of the proof and test whether `x3` lands on a root. **Expected work `2¹⁰⁸`.** Not a practical threat, but it is the real figure rather than a loose upper bound. + +The `x1`/`x4` truncations contribute less: the clean failure mode is `truncate(x1ⁱ) = 0`, which silently drops query *i* from **both** sides at probability `2⁻¹²⁸`. So `2⁻¹⁰⁸` dominates and is a fair statement of the PCS soundness level. + +**Assumptions:** this isolates the `x3` step and assumes KZG binding (so `f_com` fixes a unique `f′`); it assumes `x3` avoids the poles of `g`, which fails with probability `11/2¹²⁸`; and it is a per-attempt probability. The `mod r` sampling bias above multiplies it by 1.3585, giving `2^−107.6`. + +The upstream docstring itself warns that "128 bits may not be enough entropy depending on the application". + +**This is faithful, not a bug** — and importantly the truncated coefficient is used **identically on the commitment and evaluation sides** (verified: `mload(X1_POWERS_MPTR + 0x40)` at line 3399 vs the same slot in the `q_eval_set` Horner at 3072), so there is no asymmetry. Record it as an explicit accepted risk with a stated target security level, and note that `truncate(x1ⁱ) = 0` with probability 2⁻¹²⁸ would silently drop query *i* from both sides. + +--- + +## Informational + +**I-1 — Comments contradict constants.** Lines 316–317 and 347 claim "generated scratch starts at `0x80`"; line 58 says `TRANSCRIPT_MPTR = 0x1000`. Hardcoded in `templates/contracts/Halo2Verifier.sol:54-59,98-99`, so every render ships it. Both also cite `docs/MEMORY_LAYOUT.md`; the real path is `docs/architecture/MEMORY_LAYOUT.md`. This is exactly the stale belief TA-5 identified as the hazard. Patch **P6**. + +**I-2 — Dead code and contradictory documentation.** `QUOTIENT_RETURN_MPTR` (154), `Q_COM_MPTR` (132), `G1_IDENTITY_MPTR` (144, whose comment describes "the four `mload`s below" that do not exist), `TRACE_U256_MPTR` (160) are all declared and never used. `X_N_MINUS_1_INV_MPTR` is written at 1475 and never read. The `r` parameter of `validate_public_accumulator` (869) is never used in the body. The VM opcode table (1765–1776) documents ~22 opcodes; 11 are implemented — `FOLD_MAIN (0x0a)` and `MUL (0x07)` are described in prose but have no `case`. The constructor's MSM smoke window (`0xb140…0xe200`) differs from the production window (`0xb280…0xe340`); same length, different base, so it does not pre-expand the actual range despite the comment's claim. + +**I-3 — Unreachable defensive branch.** `load_acc_point` lines 830–839 handle "x carried the identity flag but the whole-point sentinel did not match". Given the packing check makes the codec a bijection, `x_is_id` implies x's words are exactly the canonical identity words, and requiring `y` to decode to zero implies y's words are too — so `is_acc_encoded_identity` would already have returned true. Harmless defensive dead code; worth a comment saying so rather than leaving a reader to derive it. + +**I-4 — The audit chain's evidence map points at a source tree that no longer exists.** `CODEGEN_ASSURANCE_DOSSIER.md:57-65` maps every checkpoint to `src/codegen/protocol.rs`, `src/codegen/evaluator.rs`, `src/codegen/pcs.rs`, `src/transcript.rs` and `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul`. **None exist.** The tree is `src/lowering/*` and the template is `QuotientHelpers.yul`. `AUDIT_FINDINGS.md`'s "Files reviewed (deep read)" list is entirely `src/codegen/*`; finding M1 anchors at `src/codegen/util.rs:443-448`. `ARCHITECTURE_REVIEW_2026-08.md` §11 concedes the drift and defers to a companion assessment that was not in scope. Consequence: the ~20 findings marked "Fixed with named tests" in the 2026-05-11 addendum could not be re-verified against the current tree. + +**I-5 — No transcript domain separation.** The Keccak transcript is a bare `keccak256` over concatenated raw bytes, matching Rust. This is weaker than the Blake2b transcript in the same file, which uses a personalisation string plus `COMMON`/`CHALLENGE` byte tags. Not exploitable here — every absorb is fixed-length and every count is pinned and re-checked, so no two distinct valid inputs produce the same byte stream, and `vk_digest` provides cross-circuit separation. A missing defence-in-depth layer, not a vulnerability. + +**I-6 — Two latent codegen divergences.** See §2.4 — permutation `z_last` query order, and column-vs-query fixed-eval counting. Inert for this VK; should be explicit assertions. + +**I-7 — The accumulator batching randomiser is not bound to `vk_digest`.** `alpha = keccak256("pairing-batch-acc-kzg" ‖ 4 G1 points)` (line 3612). Sound as-is — the four points transitively commit to everything, and `alpha` is drawn after they are final. Including `vk_digest` in the preimage is free and would make the binding local rather than transitive. + +--- + +## Prior-findings hygiene + +| ID | Claim | Verdict against this artefact | +| --- | --- | --- | +| 2026-05-06 #1 | VK codehash only checked in constructor | **Closed.** Re-checked per proof, lines 1004–1007. Confirmed empirically. | +| F-4.1 | Pathological `num_limb_bits` from VK | **Closed.** Header cross-check hardcodes 56/7. | +| F-4.2 | Dead `if and(eq(coord,1), 0)` branches | **Closed.** Absent. | +| F-6 | `delta` literal only checked off-line | **Value verified** (`0x8634d0aa…189d7` is the correct `Fr::DELTA`), but still a bare literal — the "nothing in the build forces a check" complaint stands. | +| TA-4 / F-3 | Gas checkpoints in production | **Closed.** Zero LOG opcodes; `external view`; single terminal return. | +| TA-5 | False `memory-safe` annotation | **Consequence removed** (layout at `0x1000`); annotation still false; guard is runtime-only; shipped comments still say `0x80`. → **M-1**, **I-1**. | +| TA-5 rec. | "Use `pragma solidity 0.8.24;` or the exact version tested" | **Not done.** Both artefacts still carry `^0.8.24` while the pinned compiler is 0.8.30 — and 0.8.24 does not produce a deployable contract. → **M-1**. | +| TA-2 / priority #2 | Define and test `vk_digest` coverage | **Open.** → **M-4**. | +| TA-6 | Precompile smoke tests too weak | **Partially addressed** (G1ADD known-answer only); no `Status:` line; pairing/G1MSM recommendations unimplemented. → **M-3**. | +| TA-7 | Zero-denominator / root-of-unity cases | **No status recorded.** The code does fail closed (verified), but the recommended forced-challenge negative tests were not found. | +| TA-8 / F-4 | Raw verifier binds no application semantics | **Documented** in NatSpec, correctly. Residual: no incident-response/migration guidance. → **L-9**. | +| 2026-05-11 #9 | Identity committed-instance policy | **Accepted restriction**, correctly scoped. → **L-2**. | +| 2026-05-11 #1–#8, #10; M1, M2 | Various, marked Fixed | **Could not re-verify** — anchors point at `src/codegen/*`, which no longer exists. → **I-4**. | + +--- + +# Part IV — Improvements + +Grouped by the axes you asked about. Items marked **[P*n*]** have a corresponding diff in the patch set. + +## 4.1 Readability + +The code is already unusually well commented — the comments explain *why*, not *what*, and several of them (the `first_adjust` bitwise-vs-arithmetic note at 660–665, the `batch_invert` early-`leave` rationale at 575–579, the pairing LHS/RHS naming inversion at 3653–3665) are exactly the kind of thing that saves a reviewer an hour. Keep that. The problems are specific: + +1. **Comments that contradict the code must go.** The `0x80` claim (316–317, 347) is worse than no comment: it asserts the property that TA-5 was about, and asserts it wrongly. Interpolate `{{ memory.low_memory_scratch_start|hex() }}` instead of hardcoding. Fix the `docs/MEMORY_LAYOUT.md` path. **[P6]** +2. **Delete dead constants, or explain them.** `QUOTIENT_RETURN_MPTR`, `Q_COM_MPTR`, `G1_IDENTITY_MPTR`, `TRACE_U256_MPTR`, `X_N_MINUS_1_INV_MPTR`, the unused `r` parameter. `G1_IDENTITY_MPTR`'s comment describing non-existent `mload`s is actively misleading. If they are placeholders for future emitter modes, say so in one line each. +3. **The VM opcode table should list what is implemented.** Documenting 22 opcodes when 11 have `case` arms sends a reviewer looking for handlers that do not exist. +4. **Emitted counts must match emitted code.** Line 3023 says "43 commitment(s)" and emits 42. Whatever the resolution to L-2, the comment and the code have to agree — a generated comment that lies is a defect in the generator. **[P7]** +5. **Name the aliases.** `TRANSCRIPT_MPTR = RETURN_MPTR = QUOTIENT_RETURN_MPTR = 0x1000` and `SELECTOR_ACC_MPTR = BATCH_INV_SCRATCH_MPTR = 0xb140` are correct but invisible. Emit a short "lifetime map" comment block at each alias site stating which phase owns the window and which line the previous owner dies at. A future reader should not have to trace 2,000 lines to establish it, as I did. +6. **Mark the unreachable branch.** `load_acc_point` 830–839 is dead by construction; one sentence saying why turns a puzzle into a defence. + +## 4.2 Correctness + +Nothing found is wrong today. These are the places where correctness rests on something invisible: + +1. **Make the memory invariant self-enforcing.** One `if gt(mload(0x40), TRANSCRIPT_MPTR) { revert }`. This is the single highest value-per-byte change in the whole set. **[P2]** +2. **Pin the pragma.** `pragma solidity 0.8.30;`. The current `^0.8.24` claims compatibility that demonstrably does not exist — 0.8.24 produces a 29,567-byte runtime that cannot be deployed. **[P3]** +3. **Assert the `batch_invert` scratch capacity in the planner** rather than relying on the arithmetic landing exactly on `LAGRANGE_DENOMS_MPTR`. This one fails *silently*, which makes it worse than the others. **[P9]** +4. **Turn the two latent codegen divergences into assertions** — permutation `z_last` emission order, and column-vs-query fixed-eval counting. Both are currently "happens to be inert". +5. **Wire the declared generator errors.** `GeneratorError::RotatedInstanceQuery` and `UnsupportedInstanceColumnShape` have `Display` impls but no construction site anywhere in the reviewed tree. Either wire them or delete them — a declared-but-unreachable error reads as a guarantee that is not there. +6. **Fix `CHALLENGE_MPTR`'s aliasing** before any circuit with user-phase challenges is rendered. **[P8]** + +## 4.3 Soundness + +1. **Bind the SRS.** The build-time pairing check `e([τ]G1, G₂) == e(G1, s_g2)` closes the gap between "the generator emitted what it was given" and "what it was given is the ceremony's key". Plus `assert params.g2() == G2Affine::generator()`. **[P11]** +2. **Extend `vk_digest` coverage**, or absorb `EXPECTED_VK_CODEHASH` into the transcript, so the base points, the quotient program, the accumulator schema and the feature profile are bound rather than merely pinned. (The team's own TA-2.) +3. **Strengthen the deployment probe** with a false-pairing case and a wrong-subgroup rejection case. The current probe proves the precompiles *exist*; the accept decision needs them to be *correct*. **[P5]** +4. **Bound the quotient-VM operands.** Defence in depth today; mandatory the moment the VK stops being immutable. **[P12]** +5. **Assert the committed-instance identity invariant at codegen**, or plumb the commitment through calldata. **[P7]** +6. **Record the truncated-challenge security level explicitly.** ~2⁻¹⁰⁸ is a decision, not an accident; it should appear in the deployment record next to the target security level, not only in an upstream docstring. + +## 4.4 Robustness + +1. **Cap the gas forwarded to validating precompile calls.** This is the change with real operational impact: it converts an attacker-chosen 30M-gas burn into a bounded ~1M. **[P1]** +2. **Custom errors for every revert class.** Five selectors, ~4 bytes of returndata each, and incident response stops being guesswork. **[P4]** +3. **Relax the `calldatasize` pin to `>=`,** or document the constraint. The other four pins already carry the security property. Today, calling through an ERC-2771 forwarder produces an empty revert that no one will diagnose quickly. +4. **Emit a `BUILD_ID` immutable.** Fleet inventory and incident scoping become mechanical instead of archaeological. **[P10]** +5. **Verify solc by SHA-256, not by version string.** **[P13]** +6. **Pin a `templates/` tree digest in CI.** This is the cheapest possible closure of the L-1 gap: it does not need the SRS, and it forces a template edit to be accompanied by an explicit fixture re-render. **[P14]** +7. **Write the incident-response section.** Wrapper-held replaceable verifier address; wrapper pause; migration means redeploy VK → verifier → repoint every wrapper; wrappers must absorb `block.chainid` and their own address into the statement. + +## 4.5 What not to change + +Some things that look like smells are correct and should be left alone: + +- **The absolute memory layout.** It is why this verifier costs 1.28M rather than 2M+. Guard it (P2); do not rewrite it to use the free-memory pointer. +- **Deferring curve checks to the precompiles.** Implementing on-curve checks for 381-bit coordinates in Yul would be far more expensive and far more error-prone than letting `G1MSM` do it. The right fix for the resulting gas behaviour is the gas cap (P1), not in-Yul validation. +- **Success-or-revert instead of returning `false`.** It is the safer default for a verifier. Just make the reverts distinguishable (P4). +- **Immutability with no admin, no pause, no upgrade.** Correct for a raw verifier. The gap is documentation of the wrapper's obligations, not the design. +- **The randomised accumulator batching.** Multiplying the two pairing equations would have been the obvious and wrong thing to do; this is the right construction, correctly ordered. +- **The VK-as-data contract with an `INVALID` prefix.** Cheap, tamper-evident, and compiler-independent to reproduce. + +--- + +# Part V — Patch set + +Diffs are against `midfall/proofs/solidity-verifier`. The generated `.sol` files are build outputs, so every fix belongs in a template or in the generator. Patches are ordered by value-per-line-changed, not by finding severity. + +Applicable diffs are in `patches/`. Where a fix needs generator logic rather than a template edit, the diff is a precise sketch with the exact insertion point named. + +| Patch | Fixes | Type | Risk | +| --- | --- | --- | --- | +| **P1** | M-2 | gas cap on validating precompile calls | low — needs a codegen-derived constant | +| **P2** | M-1 | runtime free-memory-pointer guard | trivial | +| **P3** | M-1 | pin the pragma | trivial | +| **P4** | L-3 | custom error selectors | mechanical, touches every revert site | +| **P5** | M-3 | strengthen the deployment probe | low; deploy-gas only | +| **P6** | I-1 | fix contradictory comments | trivial | +| **P7** | L-2 | committed-instance invariant + honest comment | generator assertion | +| **P8** | L-5 | un-alias `CHALLENGE_MPTR` | planner change | +| **P9** | L-7 | assert `batch_invert` scratch capacity | planner assertion | +| **P10** | L-8 | `BUILD_ID` immutable | trivial | +| **P11** | H-1 | SRS ceremony consistency check | build-time only | +| **P12** | L-6 | quotient-VM operand bounds | ~10 gas/operand | +| **P13** | M-5 | pin solc by SHA-256 | trivial | +| **P14** | L-1 | template-tree digest gate in CI | test-only | + +--- + +## P2 — runtime memory-safety guard *(do this one first)* + +Six gas, once per call, and it converts M-1 from "protected by a test in another repo" to "protected by the deployed bytecode". + +```diff +--- a/templates/contracts/Halo2Verifier.sol ++++ b/templates/contracts/Halo2Verifier.sol +@@ + assembly ("memory-safe") { ++ // The generated layout below writes absolute addresses starting at ++ // TRANSCRIPT_MPTR. The `memory-safe` annotation above is what lets ++ // solc's stack-to-memory mover reserve spill slots upward from ++ // 0x80; that reservation is compiler-version and optimiser ++ // dependent (observed 0x8c0 on 0.8.24, 0x8e0 on 0.8.26+). If it ++ // ever reaches TRANSCRIPT_MPTR, the first transcript write would ++ // clobber a live Yul local. Assert the invariant here so it is ++ // enforced by the deployed bytecode rather than by a generator-side ++ // test the integrator does not run. ++ if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. +``` + +Add the same guard at the top of `require_eip2537_precompiles`, which runs in the **creation** frame that the generator's existing guard test does not inspect. + +--- + +## P3 — pin the pragma + +`0.8.24` does not produce a deployable contract (29,567 B runtime vs the 24,576 B EIP-170 limit — verified under revm Prague). The floating pragma advertises compatibility the artefact does not have. + +```diff +--- a/templates/contracts/Halo2Verifier.sol ++++ b/templates/contracts/Halo2Verifier.sol +@@ -1,2 +1,6 @@ + // SPDX-License-Identifier: CC0-1.0 +-pragma solidity ^0.8.24; ++// Pinned, not floating. The generated layout's correctness depends on solc's ++// stack-spill reservation staying below TRANSCRIPT_MPTR, and the runtime size ++// depends on --optimize-runs. Verified: 0.8.24 emits a 29,567-byte runtime, ++// which exceeds EIP-170 and cannot be deployed. ++pragma solidity {{ template_constants.pinned_solc_version }}; +``` + +Same change in `templates/contracts/Halo2VerifyingKey.sol` and `templates/contracts/Halo2QuotientEvaluator.sol`. Emit `--optimize-runs` into a comment header at the same time, so the artefact records the setting it was built with. + +--- + +## P1 — bound the gas forwarded to validating precompile calls + +EIP-2537 `G1MSM` pricing is `k · 12000 · discount[k] / 1000` — a pure function of input length, no data dependence — so an exact constant is computable at codegen time. A 2× margin absorbs any future schedule change while still bounding the burn. + +```diff +--- a/templates/partials/verifier/Constants.sol ++++ b/templates/partials/verifier/Constants.sol +@@ ++ // Gas caps for the EIP-2537 calls that double as curve/subgroup ++ // validators. A precompile that rejects its input consumes ALL gas ++ // forwarded to it, and `staticcall(gas(), ...)` forwards 63/64 of the ++ // remainder -- so an unbounded call turns one malformed proof byte into a ++ // full-gas-limit burn for whoever pays. These are the EIP-2537 costs for ++ // the exact input lengths this verifier renders, doubled for margin. ++ uint256 internal constant G1MSM_GAS_1PAIR = {{ g1msm_gas_1pair }}; ++ uint256 internal constant G1MSM_GAS_FUSED = {{ g1msm_gas_fused }}; ++ uint256 internal constant G1ADD_GAS = {{ g1add_gas }}; ++ uint256 internal constant PAIRING_GAS_2 = {{ pairing_gas_2pair }}; +``` + +```diff +--- a/templates/partials/verifier/AccumulatorHelpers.yul ++++ b/templates/partials/verifier/AccumulatorHelpers.yul +@@ -292 +- out := staticcall(gas(), {{ ...g1msm_address|hex() }}, acc_scratch, {{ ...g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ ...g1_bytes|hex() }}) ++ out := staticcall(G1MSM_GAS_1PAIR, {{ ...g1msm_address|hex() }}, acc_scratch, {{ ...g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ ...g1_bytes|hex() }}) +@@ -397 + out := staticcall( +- gas(), ++ G1MSM_GAS_1PAIR, + {{ ...g1msm_address|hex() }}, +``` + +The same substitution is needed at the six emitter-generated sites (generated lines 3558, 3573, 3584, 3629, 3643 and the `ec_pairing` call at 622), which come from `src/lowering/kzg/mod.rs` and `templates/partials/verifier/FinalPairing.yul`. + +**Add the gas-cost model next to the plan** so the constants cannot drift from the input lengths: + +```rust +// src/lowering/plan.rs +/// EIP-2537 G1MSM gas for `k` pairs: k * 12000 * discount[k] / 1000. +fn g1msm_gas(k: usize) -> u64 { /* EIP-2537 discount table */ } + +// asserted at plan time: +assert_eq!(fused_msm_pairs * G1_MSM_PAIR_BYTES, fused_msm_input_bytes); +let g1msm_gas_fused = 2 * g1msm_gas(fused_msm_pairs); +``` + +**Caveat.** The cap must be generous and codegen-derived. A hand-tuned value that is too tight becomes a liveness bug on a chain with a different gas schedule — which is a worse failure than the griefing it prevents. If you would rather not take that risk, the weaker alternative is to document the behaviour loudly in the NatSpec so integrators know to bound the gas they hand the verifier themselves. + +--- + +## P5 — strengthen the deployment probe + +Currently `G1ADD` gets a known-answer vector and the two precompiles that decide acceptance get identity inputs only. Add three probes; all are constant-size and cost deployment gas only. + +```diff +--- a/templates/partials/verifier/PrecompileSmoke.sol ++++ b/templates/partials/verifier/PrecompileSmoke.sol +@@ (after the existing G1ADD known-answer block) ++ // Known-answer G1MSM: [2]*G == 2G. The identity-input probe below ++ // is satisfied by any implementation that echoes zeros; this one ++ // is not. G1MSM is the verifier's subgroup validator for every ++ // absorbed proof commitment, so a wrong G1MSM is a soundness bug, ++ // not a liveness bug. ++ mstore(add(scratch, 0x00), {{ g1_gen_x_hi }}) ++ mstore(add(scratch, 0x20), {{ g1_gen_x_lo }}) ++ mstore(add(scratch, 0x40), {{ g1_gen_y_hi }}) ++ mstore(add(scratch, 0x60), {{ g1_gen_y_lo }}) ++ mstore(add(scratch, 0x80), 2) ++ if iszero(staticcall(gas(), 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } ++ if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } ++ if iszero(and( ++ and(eq(mload(add(scratch, 0x00)), {{ g1_two_x_hi }}), ++ eq(mload(add(scratch, 0x20)), {{ g1_two_x_lo }})), ++ and(eq(mload(add(scratch, 0x40)), {{ g1_two_y_hi }}), ++ eq(mload(add(scratch, 0x60)), {{ g1_two_y_lo }})) ++ )) { revert(0, 0) } ++ ++ // Negative G1MSM probe: a point that is on the curve but NOT in ++ // the r-order subgroup must make the precompile fail. This is the ++ // one property the whole deferred-validation strategy rests on and ++ // the one property no existing probe tests. ++ mstore(add(scratch, 0x00), {{ g1_wrong_subgroup_x_hi }}) ++ mstore(add(scratch, 0x20), {{ g1_wrong_subgroup_x_lo }}) ++ mstore(add(scratch, 0x40), {{ g1_wrong_subgroup_y_hi }}) ++ mstore(add(scratch, 0x60), {{ g1_wrong_subgroup_y_lo }}) ++ mstore(add(scratch, 0x80), 1) ++ if staticcall(gas(), 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } ++ ++ // Known-FALSE pairing: e(G, G2) * e(G, G2) != 1. The identity probe ++ // below only proves the precompile can say "true"; the verifier's ++ // entire accept decision is `PAIRING_CHECK(...) == 1`, so an ++ // implementation that always returns 1 must be caught here. ++ // ... build the two-pair input (G, G2), (G, G2) ... ++ if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } ++ if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } ++ if iszero(iszero(mload(scratch))) { revert(0, 0) } // must be 0 ++ ++ // Known-TRUE pairing: e(G, G2) * e(-G, G2) == 1. ++ // ... build the two-pair input (G, G2), (-G, G2) ... ++ if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } ++ if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } ++ if iszero(eq(mload(scratch), 1)) { revert(0, 0) } +``` + +The generator already has `G1_BASE` and `G2_BASE`, so the generator/two-G constants are free. A wrong-subgroup point can be produced once, offline, and baked in as a constant (any point on E(Fp) with order ≠ r — e.g. map a fixed seed into E(Fp) and skip cofactor clearing). + +Also: give `AUDIT.md` TA-6 a `Status:` line and re-rate it. With the accept path resting entirely on `0x0f`, Low is too low. + +--- + +## P11 — bind the trusted setup at build time *(highest-severity fix)* + +The generator already runs the analogous check for G1 and explains why. Extend it to G2 and to τ. + +```diff +--- a/src/lowering/vk.rs ++++ b/src/lowering/vk.rs +@@ + let g1_pt: G1Affine = G1Affine::generator(); + let g2_pt: G2Affine = self.params.g2().to_affine(); + let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); ++ ++ // The G1 base is validated above by reconstructing it from ++ // g_lagrange. Do the same work on the G2 side, which is currently ++ // taken on trust from `params` and is the element every soundness ++ // guarantee rests on. ++ // ++ // 1. G2_BASE must be the canonical generator, for the same reason ++ // G1_BASE must be: the emitted pairing equation assumes it. ++ assert_eq!( ++ g2_pt, ++ G2Affine::generator(), ++ "SRS G2 base is not the canonical BLS12-381 generator; the \ ++ emitted pairing equation would not be the KZG identity" ++ ); ++ ++ // 2. NEG_S_G2 must be the negation of [tau]G2 for the SAME tau ++ // that produced g_lagrange. Without this the generator will ++ // happily emit a verifier keyed to an SRS whose toxic waste the ++ // submitter knows -- and every other control in this repo ++ // (certification, codehash pinning, trace differential, replay ++ // fixture) checks self-consistency only, so all of them pass. ++ // ++ // Commit f(X) = X in the Lagrange basis: [tau]G1 = sum_i w^i L_i. ++ let omega = self.vk.get_domain().get_omega(); ++ let mut w = ::ONE; ++ let tau_g1 = g_lagrange ++ .iter() ++ .map(|g| { let t = *g * w; w *= omega; t }) ++ .fold(G1Projective::identity(), |acc, t| acc + t) ++ .to_affine(); ++ assert!( ++ bls12_381::pairing_check(&[ ++ (&tau_g1, &G2Affine::generator()), ++ (&(-G1Affine::generator()), &self.params.s_g2().to_affine()), ++ ]), ++ "SRS inconsistency: s_g2 does not correspond to the tau that \ ++ generated g_lagrange; NEG_S_G2_BASE would be emitted from an \ ++ SRS unrelated to the commitment basis" ++ ); +``` + +Additionally, and outside the code: pin the SRS by SHA-256 in the generator, fail the render on mismatch, and record the hash plus the ceremony transcript reference in the artefact manifest. `CODEGEN_ASSURANCE_DOSSIER.md:46` already lists this as a required record; it is simply not being produced. + +--- + +## P10 — on-chain build identity + +```diff +--- a/templates/partials/verifier/Constants.sol ++++ b/templates/partials/verifier/Constants.sol +@@ ++ /// @notice Identifies the exact build that produced this verifier. ++ /// @dev keccak256(generator_commit || feature_list || vk_digest || ++ /// EXPECTED_VK_CODEHASH || srs_sha256). Nothing else in the deployed ++ /// runtime identifies the codegen, the feature profile, or the SRS ++ /// (CBOR metadata is stripped), so during an incident this is the ++ /// only way to answer "which of our deployments has the affected ++ /// codegen?" from chain state alone. ++ bytes32 public immutable BUILD_ID = {{ build_id }}; +``` + +Zero cost on the verify path. Publish the preimage components alongside the deployment record. + +--- + +## P4 — custom errors + +Every revert is currently `revert(0, 0)`. Writing a selector at `0x00` is legitimate scratch use and does not disturb the generated layout (which starts at `0x1000`). + +```yul +// helper, emitted once in AssemblyHelpers.yul +function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) +} +``` + +Minimum useful taxonomy: + +| Selector | Meaning | Current sites | +| --- | --- | --- | +| `BadCalldataShape()` | ABI heads, proof length, instance count, `calldatasize` | 338, 1048 | +| `VkMismatch()` | `extcodesize` / `extcodehash` / header cross-check | 1007, 1024 | +| `NonCanonicalScalar()` | instance, eval or q_eval ≥ r | 1133, 1316, 1369, 1399 | +| `BadPointEncoding()` | EIP-2537 pad, coordinate ≥ p, accumulator packing | 439, 440, 445, 448, 1064 | +| `PrecompileFailed()` | any precompile success/returndatasize failure | 212, 224, 273, 284, 610, 1482 | +| `ProofRejected()` | the final pairing | 3666, 3678 | +| `QuotientProgramInvalid()` | VM structural post-conditions | 2620, 2654, 2661, 2668 | + +Declare them in the contract so the ABI carries them and off-chain tooling can decode. + +--- + +## P7 — make the committed-instance invariant explicit + +Two changes, one in the generator, one in the emitted comment. + +```rust +// src/lowering/encoding/mod.rs -- where committed-instance commitments are pinned +assert!( + committed_instance_comms.iter().all(|c| *c == G1_IDENTITY_MPTR), + "committed-instance commitments are pinned to the G1 identity; a \ + non-identity commitment would require a calldata channel and an MSM \ + term that this emitter does not produce" +); +``` + +```rust +// src/lowering/kzg/mod.rs -- per-set MSM emission +// Emitted x1 exponents must be {0..m-1} minus exactly the indices of +// commitments proven to be the identity. Anything else means a real +// commitment was dropped from the batch while its eval stayed in q_eval_set. +let emitted: BTreeSet = /* exponents actually emitted */; +let omitted: BTreeSet = (0..m).collect::>() + .difference(&emitted).copied().collect(); +assert_eq!(omitted, identity_commitment_indices, + "point set {s}: MSM omits x1 exponents {omitted:?} but only \ + {identity_commitment_indices:?} are identity commitments"); +``` + +And fix the emitted comment so it stops lying: + +```diff +- // q_eval_set[0]: 43 commitment(s) ++ // q_eval_set[0]: 43 evaluation terms, 42 commitment terms. ++ // x1^1 is omitted because commitment 1 (the committed ++ // instance) is pinned to the G1 identity and contributes ++ // nothing to the MSM. The KZG batch still constrains its ++ // evaluation to zero. Asserted in kzg/mod.rs. +``` + +--- + +## P8 — un-alias `CHALLENGE_MPTR` + +```diff +--- a/templates/partials/verifier/Constants.sol ++++ b/templates/partials/verifier/Constants.sol +@@ +- uint256 internal constant CHALLENGE_MPTR = {{ memory.challenge_mptr }}; ++ // User-phase challenge window. MUST NOT overlap the named challenge slots ++ // below: TranscriptProofParser squeezes phase challenges to ++ // CHALLENGE_MPTR + 32*i and then unconditionally squeezes theta to ++ // THETA_MPTR. If the windows alias, phase-1 challenge 0 is silently ++ // overwritten by theta. ++ uint256 internal constant CHALLENGE_MPTR = {{ memory.user_challenge_mptr }}; +``` + +with a planner assertion: + +```rust +assert!( + memory.user_challenge_mptr + 32 * num_user_challenges <= memory.theta_mptr, + "user-phase challenge window overlaps the named challenge slots" +); +``` + +--- + +## P9 — assert `batch_invert` scratch capacity + +The current arithmetic lands *exactly* on `LAGRANGE_DENOMS_MPTR` with zero slack, and overflowing it corrupts silently — the modexp still succeeds, so nothing reverts. + +```rust +// src/lowering/layout/memory.rs, where BATCH_INV_SCRATCH is sized +// Forward pass writes (n-2) prefix products, then a 0xc0-byte EIP-198 frame. +let required = (n.saturating_sub(2)) * 32 + 0xc0; +assert!( + batch_inv_scratch_len >= required, + "batch_invert scratch is {batch_inv_scratch_len} bytes but needs \ + {required} for n={n}; overflow silently corrupts denominator[0] and the \ + backward pass returns wrong inverses WITHOUT reverting" +); +``` + +--- + +## P12 — bound the quotient-VM operands + +Defence in depth while the VK is immutable; mandatory if it ever stops being. + +```diff +--- a/templates/partials/quotient_numerator/QuotientHelpers.yul ++++ b/templates/partials/quotient_numerator/QuotientHelpers.yul +@@ (at each operand decode) + let q_ptr := shr(240, mload(q_pc)) ++ // Operands are raw memory addresses from the pinned program. The ++ // codehash pin is the only thing standing between a malformed ++ // program and arbitrary memory access; clamp anyway so the ++ // property is local to this file. ++ if or(lt(q_ptr, {{ memory.reversed_evals_mptr|hex() }}), ++ gt(q_ptr, {{ memory.vm_operand_max|hex() }})) { revert(0, 0) } +@@ (selector bucket write) ++ if iszero(lt(q_sel_idx, {{ num_simple_selectors }})) { revert(0, 0) } ++ if iszero(lt(q_sel_gap, {{ num_identities }})) { revert(0, 0) } +@@ (stack pop) ++ if lt(q_sp, {{ memory.vm_stack_floor|hex() }}) { revert(0, 0) } + q_sp := sub(q_sp, 0x20) +``` + +Note the existing terminal check `eq(q_sp, 0xb8e0)` does **not** catch a balanced underflow (pop-then-push restores the pointer), which is why the floor check is needed at the pop site. + +--- + +## P13 — pin solc by content hash + +```diff +--- a/scripts/install_pinned_solc.sh ++++ b/scripts/install_pinned_solc.sh +@@ ++# Content hash, not version string. `--version` output is trivially forged by a ++# substituted binary, and this project's entire reproducibility claim rests on ++# the compiler being exactly this one. ++PINNED_SOLC_SHA256="" ++ + if [[ ! -x "$solc_path" ]] || ! "$solc_path" --version | grep -q "Version: ${PINNED_SOLC_VERSION}"; then + url="https://binaries.soliditylang.org/${platform}/${binary}" + echo "[install-solc] downloading $url" + curl -fsSL "$url" -o "$solc_path" ++ actual="$(sha256sum "$solc_path" | cut -d' ' -f1)" ++ if [[ "$actual" != "$PINNED_SOLC_SHA256" ]]; then ++ echo "[install-solc] SHA-256 mismatch: got $actual, expected $PINNED_SOLC_SHA256" >&2 ++ rm -f "$solc_path" ++ exit 1 ++ fi + chmod +x "$solc_path" + fi +``` + +Also fix the `Darwin-arm64 → macosx-amd64` mapping, or record explicitly that Apple Silicon runs an x86 binary under Rosetta and is therefore not the CI compiler. + +--- + +## P14 — gate template edits in CI + +The cheapest closure of L-1. Needs no SRS, so it runs in the default CI job. + +```rust +// tests/template_digest.rs +/// The replay fixtures compile committed pre-rendered .sol, so a template edit +/// changes what deploys without changing what any SRS-free test compiles. Pin +/// the template tree so an edit must be accompanied by a fixture re-render and +/// a README commit-stamp bump. +#[test] +fn template_tree_digest_is_pinned() { + const EXPECTED: &str = ""; + assert_eq!(hash_dir("templates/"), EXPECTED, + "templates/ changed. Re-render the fixtures (see \ + fixtures/*/README.md), update the source-commit stamps, then update \ + this digest."); +} +``` + +--- + +## Patch validation + +P2 and P3 were applied to the generated `Halo2Verifier.sol`, recompiled with the pinned toolchain and re-run through the full test suite: + +| | baseline | with P2 + P3 | delta | +| --- | --- | --- | --- | +| runtime size | 21,286 B | 21,299 B | **+13 B** | +| deployment gas | 5,330,806 | 5,333,769 | +2,963 | +| valid-proof gas | 1,279,482 | 1,279,513 | **+31** | +| test outcomes (32 cases) | 1 accept / 31 reject | identical | — | + +Thirty-one gas and thirteen bytes to move the memory invariant from "enforced by a test in another repository" into the deployed bytecode. The other patches were not compiled, since they require generator changes. + +--- + +## Suggested sequencing + +1. **P3, P2, P6** — one afternoon, no behavioural risk, closes the compiler-configuration exposure and stops the artefact from shipping comments that contradict it. +2. **P11** — the only High. Build-time only, no on-chain change, no gas cost. +3. **P5, P1** — deployment assurance and the gas-griefing bound. P1 needs the gas model, so it is the longest of the group. +4. **P4, P10, P13, P14** — operational quality: diagnosable failures, fleet inventory, supply-chain pinning, template gating. +5. **P7, P8, P9, P12** — generator hardening. None affect the current artefact's behaviour; all convert "happens to be correct" into "asserted correct". + +--- + +# Part VI — Operational readiness checklist + +Before production deployment, a deployer should be able to produce evidence for every line. Items marked ✅ were verified during this review for this artefact; the rest are deployment-specific. + +**Trusted setup** + +1. Name the ceremony, its transcript URL, and the SHA-256 of the exact SRS file used for this render. Record all three in the manifest. +2. Independently recompute `−[τ]G₂` from the ceremony's published τ point and confirm it equals `NEG_S_G2_BASE` (VK words 23–30). Do not accept the generator's output as its own evidence. +3. ✅ `G2_BASE` (words 15–22) is the canonical BLS12-381 G2 generator and `G1_BASE` (words 11–14) the canonical G1 generator. +4. Run the build-time pairing check `e([τ]G1, G₂) == e(G1, s_g2)` (**P11**) before generating anything you intend to deploy. + +**Build reproducibility** + +5. Install solc by SHA-256, not by version string. Record the hash. +6. Record the complete flag set **including `--optimize-runs`**; confirm `SOLC_OPTIMIZE_RUNS` is unset in the build environment. ⚠️ At `runs=100000` the runtime exceeds EIP-170 and will not deploy. +7. Recompile from the pinned generator commit and confirm the verifier source hash matches the deployed source byte-for-byte. +8. Confirm the generator commit, Midfall revision and Cargo feature list are one consistent triple, and record the exact feature flags — `truncated-challenges`, `outer-fewer-point-sets`, `outer-single-h-commitment` — that the prover must match. + +**Key / VK binding** + +9. ✅ `keccak256(0xfe ‖ VK payload) = 0xe68d8936…cf52`, length 17,025 — recomputed from source and confirmed against `EXPECTED_VK_CODEHASH` / `EXPECTED_VK_LENGTH`. +10. Deploy VK first, then `Halo2Verifier(vkAddress)`. Confirm `AUTHORIZED_VK()` returns the intended address. ✅ A 1-bit-mutated VK and an EOA address both revert the constructor. +11. ✅ VK header words match the circuit: `num_instances=19`, `k=20`, `has_accumulator=1`, `acc_offset=11`, `num_acc_limbs=7`, `num_acc_limb_bits=56`. +12. ✅ Domain self-consistency: `n_inv · 2ᵏ ≡ 1`; `omega` of exact order `2ᵏ`; `omega · omega_inv ≡ 1`; `omega_inv_to_l = omega_inv^|rotation_last|`. + +**Chain** + +13. ✅ The target chain must be at Prague/Pectra with EIP-2537 at `0x0b`/`0x0c`/`0x0f` **and** MCOPY (Cancun). Pre-fork deployment reverts in the constructor — verified fail-closed under `CANCUN`, `SHANGHAI` and `MERGE`. +14. Do **not** rely on `require_eip2537_precompiles()` as a correctness gate (**M-3**). Independently run against the target chain: a true pairing, a **false** pairing, a non-identity `G1ADD`, a non-identity `G1MSM`, an off-curve G1 rejection, and a wrong-subgroup G1 rejection. +15. Confirm the deployment transaction supplies enough gas for the 78-pair (`0x30c0`-byte) G1MSM probe. ✅ Deployment cost 5,330,806 gas under revm Prague. + +**Application layer** + +16. The wrapper must hold the verifier behind a **replaceable** address and must have its own pause. There is no on-chain recovery in the verifier. +17. The wrapper must bind `block.chainid`, its own address, program/state identifiers, nullifiers and freshness into the statement. A proof valid here is valid on every chain and every deployment of this bytecode. +18. Record that `verifyProof` returns `true` or reverts — never `false`. Callers must not treat a failed `staticcall` as a decodable negative result. +19. ⚠️ The verifier cannot be called through ERC-2771 forwarders or any relayer that appends calldata (**L-4**), and a malformed point burns ~63/64 of the gas you hand it (**M-2**). Bound the gas passed to `verifyProof` from the wrapper. + +**Post-deployment** + +20. Publish the deployed runtime bytecode and its keccak for both contracts, plus the full manifest from steps 1–8. Nothing on-chain identifies the build (**L-8**), so this record is the only provenance that will exist. +21. Maintain an inventory mapping each deployed address to its generator commit, feature profile, SRS hash and circuit. Without a `BUILD_ID` immutable this cannot be reconstructed from chain state during an incident. + +--- + +# Appendix A — Empirical test log + +**Environment.** solc 0.8.30 (`--optimize --optimize-runs=1 --via-ir --evm-version cancun`, CBOR metadata off) → `revm 19`, `SpecId::PRAGUE`, `blst` feature. VK deployed with a 17,025-byte runtime and codehash `0xe68d8936…cf52`, matching `EXPECTED_VK_CODEHASH` exactly. Verifier deploy cost 5,330,806 gas. + +**Baseline.** The unmodified fixture calldata (8,516 bytes) verifies in **1,279,482 gas** — reproducing the figure in `fixtures/moonlight-wrap/README.md` exactly, which independently confirms the artefact, the fixture and the compiler settings are mutually consistent. + +**40 adversarial cases. 1 accepted (the valid proof), 39 rejected.** + +| # | Mutation | Result | Gas | +| --- | --- | --- | --- | +| P1 | unmodified fixture | **ACCEPT** | 1,279,482 | +| N1 | `advice[0].x_lo` last byte flipped | reject | 492,197,920 ⚠️ | +| N2 | `perm_z[0].x_lo` last byte flipped | reject | 492,197,920 ⚠️ | +| N3 | `quotient_limb[0].x_lo` flipped | reject | 492,197,920 ⚠️ | +| N4 | `eval[0]` (committed instance) + 1 | reject | 1,279,485 | +| N5 | `eval[50]` + 1 | reject | 1,279,473 | +| N6 | `f_com.x_lo` flipped | reject | 492,197,920 ⚠️ | +| N7 | `q_eval[0]` + 1 | reject | 1,279,473 | +| N8 | `pi.x_lo` flipped | reject | 492,205,857 ⚠️ | +| N9 | `eval[0]` set to 0 | ACCEPT — *no-op; fixture value is already 0* | 1,279,482 | +| N10 | `eval[0] = r` | reject | 316,790 | +| N11 | `q_eval[0] = r` | reject | 315,830 | +| N12 | `instance[0] = r` | reject | 316,760 | +| N13 | `instance[0] = r + 1` | reject | 316,760 | +| N14 | `instance[0]` + 1 | reject | 1,279,473 | +| N15 | `instance[10]` + 1 | reject | 1,279,473 | +| N16 | `instance[11]` + 1 (acc lhs) | reject | 492,197,436 ⚠️ | +| N17 | `instance[18]` + 1 (acc rhs) | reject | 492,190,350 ⚠️ | +| N18 | `advice[0].x_hi` top byte nonzero (bad pad) | reject | 315,950 | +| N19 | `advice[0].y_hi` top byte nonzero (bad pad) | reject | 315,950 | +| N20 | `advice[0].x = p` (coordinate = modulus) | reject | 315,920 | +| N21 | `advice[0] = (1,1)` off-curve | reject | 492,197,902 ⚠️ | +| N22 | `advice[0] = (0,0)` identity | reject *(valid encoding; fails at the pairing)* | 1,278,321 | +| N23 | calldata truncated by 32 B | reject | 315,000 | +| N24 | calldata + 32 trailing zero bytes | reject | 316,240 | +| N25 | calldata + 20 bytes (ERC-2771 style) | reject | 316,720 | +| N26 | ABI head[0] `0x40 → 0x60` | reject | 315,920 | +| N28 | proof length `0x1e60 → 0x1e5f` | reject | 315,920 | +| N29 | instance count `19 → 18` | reject | 315,920 | +| N30 | instance count `19 → 20` | reject | 315,920 | +| N31 | wrong function selector | reject | 315,920 | +| D1 | ABI head[1] `0x1ec0 → 0x1f00` | reject | 315,890 | +| D2 | ABI head[1] `0x1ec0 → 0x1ea0` | reject | 315,920 | +| D3 | ABI head[0] `0x40 → 0x20` | reject | 315,920 | +| D4 | proof length `0x1e60 → 0x1e80` | reject | 315,920 | +| E1 | both accumulator points = canonical identity encoding | reject | 1,265,123 | +| E2 | acc lhs = `p−1`/`p−1` without ID flag (decodes to `(0,0)`) | reject | 315,980 | +| E3 | acc lhs word0 bit ≥ 224 set (packing violation) | reject | 315,950 | +| E4 | acc lhs/rhs swapped | reject | 1,279,473 | + +*(N27 was a no-op — the mutation coincided with the original byte — and is superseded by D1/D2.)* + +**Deployment-time cases** + +| Case | Result | +| --- | --- | +| Deploy under `SpecId::CANCUN` / `SHANGHAI` / `MERGE` | constructor reverts — fail closed ✅ | +| Verifier pointed at a 1-bit-mutated VK | constructor reverts — codehash pin holds ✅ | +| Verifier pointed at an EOA address | constructor reverts ✅ | +| solc 0.8.24, runs=1 (29,567 B runtime) | `HALT CreateContractSizeLimit` ⚠️ | +| solc 0.8.30, runs=100000 (29,836 B runtime) | `HALT CreateContractSizeLimit` ⚠️ | +| solc 0.8.30, runs=1 (21,286 B runtime) | deploys ✅ | + +**What the log establishes** + +- Three distinct rejection gas signatures — ~316k structural, ~1.28M cryptographic, and ~63/64-of-limit for curve-validity failures. The third is **M-2**, and it is not a rounding artefact: it scales exactly with the supplied limit (1.98M of 2M; 29.5M of 30M; 492M of 500M). +- The committed-instance evaluation is pinned to zero by the KZG batch (N4 rejects, fixture value is 0), which empirically settles the **L-2** analysis: the omitted `x1^1` MSM term is a gas optimisation, not a soundness gap. +- Every ABI-envelope mutation is caught cheaply, before any curve work — the calldata parser has no zero-fill or relocation hole. +- The identity encoding is accepted as a *valid* G1 encoding (N22) but does not shortcut the pairing. +- The accumulator codec rejects non-canonical and packing-violating encodings early (E2, E3, 315–316k) and rejects a plausible-looking canonical identity substitution at the pairing (E1) — the accumulator instances are bound by the proof, so they cannot be swapped for the trivial case. + +--- + +# Appendix B — Verified-correct inventory + +Recording what was checked and found sound, so the report distinguishes "verified" from "not looked at". + +**Fiat–Shamir** +- The VK is bound: `vk_digest` is the first absorbed word, and `transcript_repr` covers the constraint system, all fixed commitments and all permutation commitments. No weak-Fiat-Shamir / "Frozen Heart". +- Absorb-before-squeeze ordering matches `src/plonk/verifier.rs` and `src/poly/kzg/mod.rs` exactly. Every prover-controlled value is absorbed strictly before any challenge depending on it; `π` is last and no challenge depends on it. +- Reseed semantics match Rust; back-to-back squeezes (β/γ, x1/x2) produce distinct challenges. +- No value used in the identity is unabsorbed: all 1,552 VM operand pointers and all 141 raw `mload`s in the identity code resolve into the absorbed-evaluation window `[0x9480, 0xa140)`. Zero point into uninitialised memory. +- No challenge can be influenced after derivation: slots `0x7900…0x7a40` are never rewritten except the intentional `x3` mask, which mirrors Rust. Verified by an exhaustive scan of every constant-address `mstore`/`mcopy`/`calldatacopy` destination. + +**Field elements** +- All 19 instances, 102 evaluations and 5 q_evals are checked `lt(v, r)` — so `v = r` is rejected, not reduced. +- No Fq/Fr confusion: every `addmod`/`mulmod` uses `FR_MODULUS`. Base-field comparisons use dedicated split `BLS_P_HI` / `BLS_P_MINUS_ONE_LO` constants, verified equal to the top 16 / bottom 32 bytes of `p−1`. +- The transcript absorbs the *same* word that was range-checked — no absorb/use divergence. + +**Curve points** +- EIP-2537 padding enforced for every proof G1; malformed encodings revert rather than being normalised (which would create transcript aliases). +- All 31 proof commitments plus `f_com` appear exactly once in the 78-pair fused G1MSM; `π` passes through its own G1MSM; both accumulator points are forced through G1MSM. **Every prover-supplied G1 reaches a subgroup-checking precompile.** +- No prover-supplied point reaches `0x0b` G1ADD (which does not subgroup-check) without prior validation. +- All 45 VK commitments are on-curve and in the r-subgroup; none of the 10 simple-selector commitments is the identity. + +**Accumulator** +- The limb decomposition is canonical and bijective; the coordinate is bounded by `p−1` and `hi < 2¹²⁸`; the identity has exactly one accepted encoding; a decoded `(0,0)` outside the sentinel is rejected; `PACKED_0_WITH_ID_FLAG − PACKED_0 = 2⁵⁶` exactly, with no carry. +- `acc_offset` is fixed at 11 and `11 + 2·2·2 = 19` matches the pinned instance count — not attacker-shiftable. +- The decoded accumulator is not decorative: it is folded into the pairing inputs before `ec_pairing`. +- The randomised batching is sound: `alpha` is drawn over exactly `0x220` bytes covering all four already-final points, with a zero-draw guard. + +**MSM and linear combinations** +- Exactly 49 identities, positions 0–48, each consuming one `y` step; order matches `partially_evaluate_identities`. All 21 in-bytecode selector gaps and 10 rendered tails are arithmetically correct — every bucket lands on `Σ y^(48−j)·eval_j`. No two identities share a coefficient. +- All 102 evaluations are opened exactly once across the 5 point sets (42+6+6+33+15 = 102). None missing, none double-counted. +- Truncated `x1`/`x4` powers are used identically on the commitment and evaluation sides. +- The 78 `(point, scalar)` pairs are written contiguously over exactly `0x30c0` bytes — no stale memory in the MSM buffer. +- `batch_invert` fails closed on zero and on non-canonical input, and correctly `leave`s before the backward pass on a failed modexp. Algorithm hand-verified for n = 2, 3, 4, 30. + +**Pairing** +- `ec_pairing` checks staticcall success, `returndatasize() == 0x20`, and `mload == 1` (strict), in that order — a short or empty return cannot be read as success. Input is `0x300` bytes = exactly 2 pairs. +- Orientation is the standard KZG identity at `x3`. + +**EVM level** +- Calldata bounds: four independent pins executed before any data-dependent read; ABI offsets cannot be attacker-chosen; proof section lengths sum to `0x1e60` exactly and the terminal cursor check re-proves it dynamically. +- VK pinning: `extcodesize` **and** `extcodehash` re-checked on every proof, before `extcodecopy`; the pinned hash covers the `INVALID` prefix (recomputed); no deploy-order footgun. +- Memory: all three address aliases are lifetime-disjoint reuse, proven by tracing the write map in program order. **No write anywhere below `0x1000`** — Solidity's scratch, free-memory pointer and zero slot are never touched. No write into the VK region after `extcodecopy`. Every constant-address `mload` reads a written region. +- Precompiles: all 13 call sites capture success, check `returndatasize()`, and are ultimately enforced. Input lengths are correct for the EIP-2537 ABI throughout. Input/output buffer aliasing is safe. +- Control flow: `success` is initialised once and every accumulation is converted to a revert at a section boundary. There is no path reaching the terminal `return` without the pairing having passed. `verifyProof` is correctly `view`. +- Arithmetic: no `signextend`/`sar`/`sdiv`/`smod`/`slt`/`sgt` anywhere; every `div`/`mod` has a nonzero constant or `r` as divisor; `scalar_inv` rejects `0` and `≥ r`, closing the "modexp returns 0 for `x ≡ 0 mod r`" alias; the accumulator's `sub(packed, first_adjust)` cannot underflow. +- Quotient VM: structural post-conditions fail closed on over-read, live operands and dropped stack entries; unknown opcodes revert; the constant-table index maximum is 177, exactly filling the 178-word reservation. +- Gas/DoS: every loop bound is a codegen constant or comes from the codehash-pinned VK; calldata size is pinned; peak memory is a constant `0xe340`. No attacker lever makes the cost depend on proof *contents* — **except** the precompile-failure path in M-2. + +**Documentation accuracy** +- `MEMORY_LAYOUT.md`'s theta-relative offset table matches the artefact exactly for all 26 entries. +- `HALO2_MIDNIGHT_VERIFIER_SPEC.md` §6's VK word layout matches the VK source word-for-word. +- `fixtures/moonlight-wrap/calldata.bin` is 8,516 bytes = `INSTANCE_CPTR (0x1ee4) + 19·32`, and `proof_len = 0x1ec4 − 0x64 = 7,776` — both exactly as the artefact's constants require. +- Selector `0x1e8e1e13 = keccak("verifyProof(bytes,uint256[])")[0:4]` ✅. +- Documentation drift is confined to I-1 (the `0x80` comments) and I-4 (stale `src/codegen/*` anchors in the audit chain). + + +--- + +*Review performed 12 August 2026 against `fixtures/moonlight-wrap` (`Halo2Verifier.sol` `3861a403…`, `Halo2VerifyingKey.sol` `ec94cabe…`). Static analysis was cross-checked by execution under revm 19 / `SpecId::PRAGUE` with solc 0.8.30. Items in §2.5 and Appendix B's caveats mark what could not be verified from the material available — in particular the trusted setup (H-1), the `vk_digest` preimage, the arithmetic content of the quotient bytecode, and the accumulator's orientation contract with the producing circuit.* diff --git a/proofs/solidity-verifier/docs/audit/patches/P11_srs_binding.patch b/proofs/solidity-verifier/docs/audit/patches/P11_srs_binding.patch new file mode 100644 index 000000000..7f25cad83 --- /dev/null +++ b/proofs/solidity-verifier/docs/audit/patches/P11_srs_binding.patch @@ -0,0 +1,63 @@ +--- a/src/lowering/vk.rs ++++ b/src/lowering/vk.rs +@@ -93,6 +93,60 @@ + let g1_pt: G1Affine = G1Affine::generator(); + let g2_pt: G2Affine = self.params.g2().to_affine(); + let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); ++ ++ // The G1 base is validated above by reconstructing it from ++ // `g_lagrange`. Do the same work on the G2 side. Until now ++ // `g2` and `s_g2` were taken on trust from `params`, and ++ // `NEG_S_G2_BASE` is the element every soundness guarantee in the ++ // deployed verifier rests on: the final pairing is ++ // e(final_com - v*G + x3*pi, G2_BASE) * e(pi, NEG_S_G2_BASE) == 1 ++ // and anyone who knows the tau behind NEG_S_G2_BASE can forge an ++ // opening for any statement. ++ // ++ // Every other control in this repository -- quotient ++ // certification, the dual build, generator invariants, the VK ++ // codehash pin, the trace differential, the replay fixtures -- ++ // checks SELF-CONSISTENCY. An SRS substituted at build time ++ // produces a perfectly self-consistent artifact, so all of them ++ // pass. This assertion is the only place that can catch it. ++ ++ // 1. G2_BASE must be the canonical generator, for the same reason ++ // G1_BASE must be: the emitted equation assumes it. ++ assert_eq!( ++ g2_pt, ++ G2Affine::generator(), ++ "SRS G2 base is not the canonical BLS12-381 G2 generator; the \ ++ emitted pairing equation would not be the KZG identity" ++ ); ++ ++ // 2. `s_g2` must correspond to the SAME tau that produced ++ // `g_lagrange`. Commit f(X) = X in the Lagrange basis to obtain ++ // [tau]G1 = sum_i omega^i * L_i, then check the pairing ++ // e([tau]G1, G2) == e(G1, s_g2). This ties the G2 side of the ++ // key to the commitment basis the prover actually uses. ++ let omega = self.vk.get_domain().get_omega(); ++ let mut w = ::ONE; ++ let tau_g1 = g_lagrange ++ .iter() ++ .map(|g| { ++ let term = *g * w; ++ w *= omega; ++ term ++ }) ++ .fold(G1Projective::identity(), |acc, t| acc + t) ++ .to_affine(); ++ assert!( ++ srs_tau_is_consistent(&tau_g1, &self.params.s_g2().to_affine()), ++ "SRS inconsistency: s_g2 does not correspond to the tau that \ ++ generated g_lagrange. NEG_S_G2_BASE would be emitted from an \ ++ SRS unrelated to the commitment basis -- i.e. from a key whose \ ++ toxic waste may be known to whoever supplied it." ++ ); ++ ++ // TODO(deployment): additionally pin the SRS asset by SHA-256 here ++ // and record it, plus the ceremony transcript reference, in the ++ // artifact manifest. CODEGEN_ASSURANCE_DOSSIER.md already lists ++ // this as a required record; nothing currently produces it. + let g1 = g1_to_u256s(g1_pt); + let g2 = g2_to_u256s(g2_pt); + let neg_s_g2 = g2_to_u256s(neg_s_g2_pt); diff --git a/proofs/solidity-verifier/docs/audit/patches/review-proposed-all.patch b/proofs/solidity-verifier/docs/audit/patches/review-proposed-all.patch new file mode 100644 index 000000000..b54093b53 --- /dev/null +++ b/proofs/solidity-verifier/docs/audit/patches/review-proposed-all.patch @@ -0,0 +1,177 @@ +--- a/templates/contracts/Halo2Verifier.sol 2026-08-12 15:35:48.921338927 +0000 ++++ b/templates/contracts/Halo2Verifier.sol 2026-08-12 15:36:19.199260815 +0000 +@@ -1,5 +1,19 @@ + // SPDX-License-Identifier: CC0-1.0 +-pragma solidity ^0.8.24; ++// Pinned, not floating. Two properties of this artifact are compiler- and ++// optimiser-dependent, and neither is self-evident from the source: ++// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR ++// upward, which is only safe while solc's stack-spill reservation stays ++// below it (observed 0x8c0 on 0.8.24, 0x8e0 on 0.8.26+). ++// 2. The runtime size depends on --optimize-runs. Measured: solc 0.8.24 at ++// runs=1 emits a 29,567-byte runtime and solc 0.8.30 at runs=100000 emits ++// 29,836 -- both exceed the EIP-170 24,576-byte limit and cannot be ++// deployed. Only the pinned (version, runs) pair is known to work. ++// A floating `^0.8.24` therefore advertises compatibility this contract does ++// not have. ++pragma solidity {{ pinned_solc_version }}; ++// Built with: solc {{ pinned_solc_version }} --via-ir --optimize ++// --optimize-runs {{ solc_optimize_runs }} --evm-version {{ solc_evm_version }} ++// --no-cbor-metadata + + /// @title Halo2 BLS12-381 KZG verifier. + /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 +@@ -51,12 +65,14 @@ + /// precompiles, or mismatched pinned dependency code revert. Trace and gas + /// renders keep the same failure policy. + /// @dev The generated verifier uses absolute Yul memory addresses instead +- /// of Solidity's free-memory pointer, but generated scratch starts at +- /// `0x80` so Solidity's reserved memory prefix is preserved. The main ++ /// of Solidity's free-memory pointer. Generated scratch starts at ++ /// `TRANSCRIPT_MPTR` ({{ memory.transcript_mptr|hex() }}), leaving ++ /// Solidity's reserved prefix AND solc's stack-spill reservation below it ++ /// untouched; the assembly block asserts that separation at entry. The main + /// assembly block remains terminal: accepted proofs return from assembly + /// and all rejected inputs revert. Do not inline this body into Solidity + /// code that continues executing after verification without reviewing the +- /// memory strategy; see `docs/MEMORY_LAYOUT.md`. ++ /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. + /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. + /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. + /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. +@@ -93,10 +109,21 @@ + {%- when None %} + {%- endmatch %} + assembly ("memory-safe") { ++ // The `memory-safe` annotation above is what enables solc's ++ // stack-to-memory mover, which reserves spill slots upward from ++ // 0x80. The generated layout below writes absolute addresses from ++ // TRANSCRIPT_MPTR upward and never consults the free-memory ++ // pointer, so the two regions must not meet. That reservation is ++ // compiler-version and optimiser dependent -- it is not a constant ++ // this file controls -- so assert the separation here rather than ++ // relying on a generator-side test the integrator does not run. ++ // ~6 gas, once per proof. ++ if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } ++ + // This block owns the call-frame memory and remains terminal. +- // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving ++ // Generated scratch starts at TRANSCRIPT_MPTR, preserving + // Solidity's reserved scratch, free-memory-pointer, and zero-slot +- // words. See docs/MEMORY_LAYOUT.md. ++ // words. See docs/architecture/MEMORY_LAYOUT.md. + // =============================================================== + // Helpers: modexp, transcript, EIP-2537 calls + // =============================================================== +--- a/templates/contracts/Halo2VerifyingKey.sol 2026-08-12 15:35:48.930600580 +0000 ++++ b/templates/contracts/Halo2VerifyingKey.sol 2026-08-12 15:36:19.199534819 +0000 +@@ -1,6 +1,9 @@ + // SPDX-License-Identifier: CC0-1.0 + +-pragma solidity ^0.8.24; ++// Pinned to match the verifier. This contract's runtime is pure returned data, ++// so its codehash is compiler-independent -- but the pin keeps the two halves ++// of the deployment provably built by one toolchain. ++pragma solidity {{ pinned_solc_version }}; + + /// @title Halo2 BLS12-381 verifying-key payload. + /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. +--- a/src/lowering/vk.rs 2026-08-12 15:35:48.939496697 +0000 ++++ b/src/lowering/vk.rs 2026-08-12 15:36:41.016340556 +0000 +@@ -93,6 +93,60 @@ + let g1_pt: G1Affine = G1Affine::generator(); + let g2_pt: G2Affine = self.params.g2().to_affine(); + let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); ++ ++ // The G1 base is validated above by reconstructing it from ++ // `g_lagrange`. Do the same work on the G2 side. Until now ++ // `g2` and `s_g2` were taken on trust from `params`, and ++ // `NEG_S_G2_BASE` is the element every soundness guarantee in the ++ // deployed verifier rests on: the final pairing is ++ // e(final_com - v*G + x3*pi, G2_BASE) * e(pi, NEG_S_G2_BASE) == 1 ++ // and anyone who knows the tau behind NEG_S_G2_BASE can forge an ++ // opening for any statement. ++ // ++ // Every other control in this repository -- quotient ++ // certification, the dual build, generator invariants, the VK ++ // codehash pin, the trace differential, the replay fixtures -- ++ // checks SELF-CONSISTENCY. An SRS substituted at build time ++ // produces a perfectly self-consistent artifact, so all of them ++ // pass. This assertion is the only place that can catch it. ++ ++ // 1. G2_BASE must be the canonical generator, for the same reason ++ // G1_BASE must be: the emitted equation assumes it. ++ assert_eq!( ++ g2_pt, ++ G2Affine::generator(), ++ "SRS G2 base is not the canonical BLS12-381 G2 generator; the \ ++ emitted pairing equation would not be the KZG identity" ++ ); ++ ++ // 2. `s_g2` must correspond to the SAME tau that produced ++ // `g_lagrange`. Commit f(X) = X in the Lagrange basis to obtain ++ // [tau]G1 = sum_i omega^i * L_i, then check the pairing ++ // e([tau]G1, G2) == e(G1, s_g2). This ties the G2 side of the ++ // key to the commitment basis the prover actually uses. ++ let omega = self.vk.get_domain().get_omega(); ++ let mut w = ::ONE; ++ let tau_g1 = g_lagrange ++ .iter() ++ .map(|g| { ++ let term = *g * w; ++ w *= omega; ++ term ++ }) ++ .fold(G1Projective::identity(), |acc, t| acc + t) ++ .to_affine(); ++ assert!( ++ srs_tau_is_consistent(&tau_g1, &self.params.s_g2().to_affine()), ++ "SRS inconsistency: s_g2 does not correspond to the tau that \ ++ generated g_lagrange. NEG_S_G2_BASE would be emitted from an \ ++ SRS unrelated to the commitment basis -- i.e. from a key whose \ ++ toxic waste may be known to whoever supplied it." ++ ); ++ ++ // TODO(deployment): additionally pin the SRS asset by SHA-256 here ++ // and record it, plus the ceremony transcript reference, in the ++ // artifact manifest. CODEGEN_ASSURANCE_DOSSIER.md already lists ++ // this as a required record; nothing currently produces it. + let g1 = g1_to_u256s(g1_pt); + let g2 = g2_to_u256s(g2_pt); + let neg_s_g2 = g2_to_u256s(neg_s_g2_pt); +--- a/scripts/install_pinned_solc.sh 2026-08-12 15:35:48.947553053 +0000 ++++ b/scripts/install_pinned_solc.sh 2026-08-12 15:36:19.199639949 +0000 +@@ -26,10 +26,33 @@ + mkdir -p "$INSTALL_DIR" + solc_path="$INSTALL_DIR/solc" + ++# Content hash, not version string. `--version` output is trivially forged by a ++# substituted binary, and this project's entire reproducibility claim rests on ++# the compiler being exactly this one. Hashes are published per platform in ++# https://binaries.soliditylang.org/${platform}/list.json. ++declare -A PINNED_SOLC_SHA256=( ++ ["linux-amd64"]="" ++ ["macosx-amd64"]="" ++) ++ + if [[ ! -x "$solc_path" ]] || ! "$solc_path" --version | grep -q "Version: ${PINNED_SOLC_VERSION}"; then + url="https://binaries.soliditylang.org/${platform}/${binary}" + echo "[install-solc] downloading $url" + curl -fsSL "$url" -o "$solc_path" ++ expected="${PINNED_SOLC_SHA256[$platform]:-}" ++ if [[ -z "$expected" || "$expected" == "" ]]; then ++ echo "[install-solc] no pinned SHA-256 recorded for platform '$platform'" >&2 ++ rm -f "$solc_path" ++ exit 1 ++ fi ++ actual="$(sha256sum "$solc_path" | cut -d' ' -f1)" ++ if [[ "$actual" != "$expected" ]]; then ++ echo "[install-solc] SHA-256 mismatch for $url" >&2 ++ echo "[install-solc] expected $expected" >&2 ++ echo "[install-solc] actual $actual" >&2 ++ rm -f "$solc_path" ++ exit 1 ++ fi + chmod +x "$solc_path" + fi + From 460a666b3418fb6d6dd1862a1191edd51e75373b Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Wed, 12 Aug 2026 16:13:25 +0000 Subject: [PATCH 089/108] fix(solidity-verifier): harden memory invariant, pin pragma, strengthen precompile probes Applies the four template-level fixes from the 2026-08 review that could be validated end to end. See docs/audit/FIXES_APPLIED_2026-08.md for what this does NOT fix. P2 (M-1) Assert solc's stack-spill reservation stays below the generated layout: `if gt(mload(0x40), TRANSCRIPT_MPTR) { revert }` in verifyProof, and the equivalent in require_eip2537_precompiles, which runs in the creation frame that compiled_memoryguard_does_not_overlap_generated_layout does not inspect. The invariant is now enforced by the deployed bytecode rather than by a generator-side test an integrator never runs. P3 (M-1) Pin the pragma to 0.8.30. Not cosmetic: solc 0.8.24 at runs=1 emits a 29,567-byte runtime and 0.8.30 at runs=100000 emits 29,836 -- both exceed EIP-170 and halt with CreateContractSizeLimit. The floating ^0.8.24 advertised a compiler that cannot produce a deployable contract. The spill reservation also moves with the version (0x8c0 on 0.8.24, 0x8e0 on 0.8.26+), which is why P2 is not theoretical. P5 (M-3) Four known-answer probes for the two precompiles that decide acceptance, which were previously tested with identity inputs only: G1MSM([2]G)==2G; G1MSM must reject an on-curve point outside the r-order subgroup (gas-bounded, since a rejecting precompile consumes everything forwarded); e(G,G2)e(-G,G2)==1; and e(G,G2)e(G,G2)!=1, which catches a 0x0f that always returns 1. Addresses AUDIT.md TA-6, still un-triaged. P6 (I-1) The NatSpec claimed generated scratch starts at 0x80 while TRANSCRIPT_MPTR is 0x1000 -- the exact stale belief TA-5 identified as the hazard, hardcoded so every render shipped it. Also corrects the docs/MEMORY_LAYOUT.md path. P13 (M-5) install_pinned_solc.sh now verifies the compiler by SHA-256 and fails closed. ACTION REQUIRED: the hashes are TODO placeholders, so the script refuses to install until they are filled from list.json. Measured on the moonlight-wrap render (solc 0.8.30, revm 19 Prague): runtime 21,286 -> 21,299 bytes (+13) deploy gas 5,330,806 -> 5,766,768 (one-time; probes are constructor-only) verify gas 1,279,482 -> 1,279,513 (+31) 40-case adversarial suite: outcomes identical NOTE: these are template changes, so the committed fixtures under fixtures/ and deployments/ are now stale relative to them and need a re-render. tests/ivc_accumulator_replay.rs compiles the committed .sol rather than fresh template output, so it will keep passing either way -- that is finding L-1. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PhfUFgvirfyTF9eidjSMRe --- .../docs/audit/FIXES_APPLIED_2026-08.md | 131 ++++++++++ .../audit/patches/applied-templates.patch | 230 ++++++++++++++++++ .../scripts/install_pinned_solc.sh | 26 ++ .../contracts/Halo2QuotientEvaluator.sol | 5 +- .../templates/contracts/Halo2Verifier.sol | 35 ++- .../templates/contracts/Halo2VerifyingKey.sol | 5 +- .../partials/verifier/PrecompileSmoke.sol | 89 +++++++ 7 files changed, 513 insertions(+), 8 deletions(-) create mode 100644 proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md create mode 100644 proofs/solidity-verifier/docs/audit/patches/applied-templates.patch mode change 100755 => 100644 proofs/solidity-verifier/scripts/install_pinned_solc.sh diff --git a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md new file mode 100644 index 000000000..577c670dd --- /dev/null +++ b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md @@ -0,0 +1,131 @@ +# Fixes applied — August 2026 verifier review + +Companion to `HALO2_VERIFIER_REVIEW.md`. This file records exactly what was changed, what was verified, and — importantly — **what the review found that these changes do not fix.** + +## Short answer: no, this does not address all the findings + +Of the 23 findings, **4 are closed or substantially closed by the changes below.** The rest fall into three groups: + +- **8 need generator logic** (Rust changes plus values computed at codegen time). They are fully specified in Part V of the review with exact insertion points, but were not written, because the generator cannot be compiled from this session — `solidity-verifier/Cargo.toml` depends on `../../curves`, `../../circuits` and `../../zk_stdlib`, which are outside the connected folder. Writing Rust into a workspace that cannot be `cargo check`ed would risk breaking your build to no benefit. +- **1 is patch-ready but unverified** (`patches/P11_srs_binding.patch`) for the same reason. +- **9 are not code problems.** They need data or decisions only you hold: the ceremony reference, the SRS hash, the artifact manifest, the incident-response policy, an accepted-risk sign-off on the truncated-challenge security level. No patch can close those. + +--- + +## Applied and validated + +Verified by compiling the rendered output with the pinned toolchain (solc 0.8.30, `--via-ir --optimize --optimize-runs=1 --evm-version cancun`, CBOR off) and running it under `revm 19` / `SpecId::PRAGUE` against the `moonlight-wrap` fixture plus 40 adversarial mutations. + +| Patch | Finding | File | +| --- | --- | --- | +| **P2** | M-1 | `templates/contracts/Halo2Verifier.sol`, `templates/partials/verifier/PrecompileSmoke.sol` | +| **P3** | M-1 | all three `templates/contracts/*.sol` | +| **P5** | M-3 | `templates/partials/verifier/PrecompileSmoke.sol` | +| **P6** | I-1 | `templates/contracts/Halo2Verifier.sol` | + +**P2 — free-memory-pointer guard.** `if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }` at the top of the main assembly block, and the equivalent in `require_eip2537_precompiles` (which runs in the *creation* frame that `compiled_memoryguard_does_not_overlap_generated_layout` does not inspect). The invariant is now enforced by the deployed bytecode rather than by a test in this repository that an integrator recompiling the `.sol` will never run. + +**P3 — pragma pinned to `0.8.30`.** Not cosmetic. Measured: + +``` +solc 0.8.24 runs=1 -> 29,567 B runtime -> HALT CreateContractSizeLimit +solc 0.8.30 runs=100000 -> 29,836 B runtime -> HALT CreateContractSizeLimit +solc 0.8.30 runs=1 -> 21,286 B runtime -> deploys +``` + +`^0.8.24` advertised a compiler that cannot produce a deployable contract. The spill reservation also moves with the version (`0x8c0` on 0.8.24, `0x8e0` on 0.8.26+), which is the concrete reason the P2 guard is not theoretical. + +**P5 — four known-answer precompile probes.** The existing smoke test hardened `G1ADD` with a known-answer vector and gave a good explanation of why identity inputs prove nothing — then tested `G1MSM` and `PAIRING_CHECK` with identity inputs only. Those are the two precompiles the verifier's security actually rests on: `G1MSM` is the curve/subgroup validator for every absorbed proof commitment, and `PAIRING_CHECK` is the sole accept gate. Added: + +- **(a)** `G1MSM([2]·G) == 2G` — a stub that echoes zeros fails this. +- **(b)** `G1MSM` **must reject** `(4, y)` — a point satisfying `y² = x³ + 4` over `Fp` that is provably *not* in the r-order subgroup (verified off-chain: `r·P ≠ O`). This is the one property the entire deferred-validation strategy depends on and the one no other probe exercised. Gas is deliberately bounded to 200,000: a rejecting precompile consumes everything forwarded to it, so an unbounded `gas()` here would burn 63/64 of the deployment gas. +- **(c)** `e(G, G₂)·e(−G, G₂) == 1`. +- **(d)** `e(G, G₂)·e(G, G₂) != 1` — catches a `0x0f` that always returns 1, which would otherwise accept every proof. + +This closes **M-3** and addresses `AUDIT.md` TA-6, which was still un-triaged (no `Status:` line). TA-6 should now be marked resolved and its severity reconsidered — with the accept path resting entirely on `0x0f`, Low was too low. + +**P6 — comments that contradicted the code.** The NatSpec claimed "generated scratch starts at `0x80`" while `TRANSCRIPT_MPTR = 0x1000`. That was the exact stale belief TA-5 identified as the hazard, hardcoded in the template so every render shipped it. Also corrected the `docs/MEMORY_LAYOUT.md` path to `docs/architecture/MEMORY_LAYOUT.md`. + +### Measured cost + +| | baseline | patched | delta | +| --- | --- | --- | --- | +| verifier runtime | 21,286 B | 21,299 B | **+13 B** | +| deployment gas | 5,330,806 | 5,766,768 | +435,962 (one-time) | +| valid-proof gas | 1,279,482 | 1,279,513 | **+31** | +| 40-case test suite | 1 accept / 39 reject | identical | — | +| non-Prague deploy (CANCUN/SHANGHAI/MERGE) | reverts | reverts | — | +| mutated-VK / EOA-VK deploy | reverts | reverts | — | + +The strengthened probes cost **nothing** at verify time — they run only in the constructor. That deployment succeeds is itself the validation: all four new known-answer probes pass against a correct EIP-2537 implementation, so the constants are right. + +--- + +## Applied, syntax-checked only + +**P13 — `scripts/install_pinned_solc.sh`** now verifies the downloaded compiler by SHA-256 and fails closed. `bash -n` passes. + +⚠️ **Action required:** the hashes are `TODO-fill-from-list.json`. Fetch them from `https://binaries.soliditylang.org/{linux-amd64,macosx-amd64}/list.json` and fill them in — until then the script refuses to install, which is the intended fail-closed behaviour but will block a fresh checkout. Also still open: `Darwin-arm64` maps to `macosx-amd64`, so Apple Silicon runs an x86 binary under Rosetta, which is a different binary from CI. + +--- + +## Patch supplied, not applied + +**`patches/P11_srs_binding.patch`** — the highest-severity finding (**H-1**). Adds two assertions to `src/lowering/vk.rs`: + +1. `params.g2() == G2Affine::generator()` — the G1 side is already defended this way; the G2 side was not. +2. A pairing consistency check that `s_g2` corresponds to the same τ that produced `g_lagrange`, by committing `f(X) = X` in the Lagrange basis to obtain `[τ]G1` and checking `e([τ]G1, G₂) == e(G1, s_g2)`. + +**Not applied because it cannot be compiled from here.** It will likely need small adjustments — the pairing helper's import path, and the exact `Fq`/domain accessor names. Please `cargo check` before committing. The `srs_tau_is_consistent` call in the patch is a placeholder for whatever pairing helper your curve crate exposes. + +This patch closes the *checkable* half of H-1. The other half is not code: name the ceremony, record the SRS SHA-256, and publish `NEG_S_G2_BASE` next to the ceremony's published τ point so a third party can verify the negation independently. `CODEGEN_ASSURANCE_DOSSIER.md:46` already lists the SRS record as required; nothing currently produces it. + +--- + +## Specified but not written — needs generator work + +Each is fully specified in Part V of the review, with the insertion point named. + +| Patch | Finding | Why it needs the generator | +| --- | --- | --- | +| **P1** | M-2 | Needs an EIP-2537 gas model in `plan.rs` to emit per-call-site caps. **This is the one with real operational impact** — a single off-curve byte currently burns ~98.5% of whatever gas limit you supply (29.5M of 30M). | +| **P4** | L-3 | Custom errors touch ~41 revert sites, some template-resident and some emitted from `src/lowering/kzg/mod.rs`; a partial application would leave the taxonomy inconsistent. | +| **P7** | L-2 | Codegen assertion that MSM `x1` exponents omit exactly the identity commitments, plus fixing the emitted comment that says "43 commitment(s)" and emits 42. | +| **P8** | L-5 | `CHALLENGE_MPTR` must get its own window in the memory planner. | +| **P9** | L-7 | Planner assertion on `batch_invert` scratch capacity. Note this one currently fails **silently** — the modexp still succeeds, so nothing reverts. | +| **P10** | L-8 | `BUILD_ID` needs generator commit, feature list and SRS hash plumbed into the render context. | +| **P12** | L-6 | Quotient-VM operand clamps need new template variables for the window bounds. | +| **P14** | L-1 | A `templates/` tree digest test. Cheapest closure of the codegen-trust gap, and needs no SRS, so it runs in default CI. | + +--- + +## Not fixable by patch — needs your data or a decision + +| Finding | What is needed | +| --- | --- | +| **H-1** (remainder) | Ceremony name and transcript URL; SRS file SHA-256; publish `NEG_S_G2_BASE` against the ceremony's τ. | +| **M-4** | Redefining `vk_digest` to cover the SRS points, quotient program, accumulator schema and feature profile is a protocol change affecting the prover — a design decision, not a patch. | +| **M-5** (remainder) | Fill the `REVIEW_PACKET.md` §4 manifest (currently `fill per artifact` in all 11 rows); reconcile the three conflicting provenance stamps (`3fb6d84` / `a096e71…` / `53dc872…`); add `--optimize-runs` to the recorded flag set and remove the `SOLC_OPTIMIZE_RUNS` env override from the reproducible path; ship `REPRODUCIBLE_BUILDS.md`. | +| **L-4** | Decide: relax the `calldatasize` pin to `>=`, or document that ERC-2771 forwarders cannot call this verifier. Both are defensible; the other four pins already carry the security property. | +| **L-9** | Write the incident-response and migration section, and state the wrapper obligations as requirements: replaceable verifier address, wrapper-held pause, and binding `block.chainid` + wrapper address into the statement. | +| **L-10** | Sign off on ~2⁻¹⁰⁸ PCS soundness from `truncated-challenges`, or disable the feature. Record the target security level in the deployment record. | +| **I-4** | Rewrite the `src/codegen/*` anchors in `CODEGEN_ASSURANCE_DOSSIER.md` and `AUDIT_FINDINGS.md` to the current `src/lowering/*` tree. Until then the ~20 findings marked "Fixed with named tests" in the 2026-05-11 addendum cannot be re-verified by a reviewer. | +| **I-2, I-3, I-6, I-7** | Cleanup and assertions; low value, no urgency. | + +--- + +## Re-render required + +The changes are to **templates**, so the committed fixtures under `fixtures/` and `deployments/` are now stale relative to them. Before relying on any of this: + +1. Re-render the fixtures (see each `fixtures/*/README.md` — needs the SRS and a Moonlight checkout). +2. Update the source-commit stamps in those READMEs. +3. Re-run the replay tests. Note that `tests/ivc_accumulator_replay.rs` compiles the **committed** `.sol`, not fresh template output, so it will keep passing either way — which is finding **L-1**, and the reason P14 matters. + +## Suggested next steps + +1. `cargo check` and commit `patches/P11_srs_binding.patch` — highest severity, build-time only, no on-chain change. +2. Fill the solc SHA-256 values so P13 stops blocking fresh checkouts. +3. P1 — the gas cap. It is the finding with day-one operational impact for any relayer or batching wrapper. +4. P14 — one test, no SRS needed, closes the widest assurance gap for the least work. +5. Fill the artifact manifest and reconcile the provenance stamps (M-5). diff --git a/proofs/solidity-verifier/docs/audit/patches/applied-templates.patch b/proofs/solidity-verifier/docs/audit/patches/applied-templates.patch new file mode 100644 index 000000000..60ca65b82 --- /dev/null +++ b/proofs/solidity-verifier/docs/audit/patches/applied-templates.patch @@ -0,0 +1,230 @@ +--- a/templates/contracts/Halo2Verifier.sol ++++ b/templates/contracts/Halo2Verifier.sol +@@ -1,5 +1,16 @@ + // SPDX-License-Identifier: CC0-1.0 +-pragma solidity ^0.8.24; ++// Pinned, not floating. Two properties of this artifact are compiler- and ++// optimiser-dependent, and neither is visible in the source: ++// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR ++// upward. That is only safe while solc's stack-spill reservation stays ++// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not ++// a constant this file controls. verifyProof now asserts the separation. ++// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 ++// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over ++// the EIP-170 24,576-byte limit, so neither can be deployed. Only the ++// pinned (version, runs) pair is known to produce a deployable contract. ++// A floating `^0.8.24` advertises compatibility this contract does not have. ++pragma solidity 0.8.30; + + /// @title Halo2 BLS12-381 KZG verifier. + /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 +@@ -51,12 +62,14 @@ + /// precompiles, or mismatched pinned dependency code revert. Trace and gas + /// renders keep the same failure policy. + /// @dev The generated verifier uses absolute Yul memory addresses instead +- /// of Solidity's free-memory pointer, but generated scratch starts at +- /// `0x80` so Solidity's reserved memory prefix is preserved. The main ++ /// of Solidity's free-memory pointer. Generated scratch starts at ++ /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's ++ /// stack-spill reservation below it untouched; the assembly block asserts ++ /// that separation on entry rather than assuming it. The main + /// assembly block remains terminal: accepted proofs return from assembly + /// and all rejected inputs revert. Do not inline this body into Solidity + /// code that continues executing after verification without reviewing the +- /// memory strategy; see `docs/MEMORY_LAYOUT.md`. ++ /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. + /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. + /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. + /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. +@@ -93,10 +106,20 @@ + {%- when None %} + {%- endmatch %} + assembly ("memory-safe") { ++ // The `memory-safe` annotation above is what enables solc's ++ // stack-to-memory mover, which reserves spill slots upward from ++ // 0x80. The generated layout below writes absolute addresses from ++ // TRANSCRIPT_MPTR upward and never consults the free-memory ++ // pointer, so the two regions must not meet. The size of that ++ // reservation is compiler-version and optimiser dependent, so ++ // assert the invariant in the deployed bytecode instead of relying ++ // on a generator-side test the integrator never runs. ~6 gas. ++ if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } ++ + // This block owns the call-frame memory and remains terminal. +- // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving ++ // Generated scratch starts at TRANSCRIPT_MPTR, preserving + // Solidity's reserved scratch, free-memory-pointer, and zero-slot +- // words. See docs/MEMORY_LAYOUT.md. ++ // words. See docs/architecture/MEMORY_LAYOUT.md. + // =============================================================== + // Helpers: modexp, transcript, EIP-2537 calls + // =============================================================== +--- a/templates/contracts/Halo2VerifyingKey.sol ++++ b/templates/contracts/Halo2VerifyingKey.sol +@@ -1,6 +1,9 @@ + // SPDX-License-Identifier: CC0-1.0 + +-pragma solidity ^0.8.24; ++// Pinned to match the verifier, so both halves of a deployment are provably ++// built by one toolchain. (This contract's runtime is pure returned data, so ++// its codehash is compiler-independent -- the pin is for the pair, not for it.) ++pragma solidity 0.8.30; + + /// @title Halo2 BLS12-381 verifying-key payload. + /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. +--- a/templates/contracts/Halo2QuotientEvaluator.sol ++++ b/templates/contracts/Halo2QuotientEvaluator.sol +@@ -1,5 +1,8 @@ + // SPDX-License-Identifier: CC0-1.0 +-pragma solidity ^0.8.24; ++// Pinned to match the verifier, so both halves of a deployment are provably ++// built by one toolchain. (This contract's runtime is pure returned data, so ++// its codehash is compiler-independent -- the pin is for the pair, not for it.) ++pragma solidity 0.8.30; + + /// @title Split Halo2 quotient numerator evaluator. + /// @notice Reconstructs the scalar side of the linearization query for a generated verifier. +--- a/templates/partials/verifier/PrecompileSmoke.sol ++++ b/templates/partials/verifier/PrecompileSmoke.sol +@@ -2,6 +2,11 @@ + /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + function require_eip2537_precompiles() private view { + assembly ("memory-safe") { ++ // Same free-memory-pointer guard as verifyProof. This body runs in ++ // the *creation* frame, which the generator's memoryguard test does ++ // not inspect (it parses the runtime prologue only). ++ if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) } ++ + // Scratch is reused for every runtime-prerequisite probe. + let scratch := {{ memory.constructor_smoke_scratch_mptr|hex() }} + +@@ -55,6 +60,90 @@ + ) + )) { revert(0, 0) } + ++ ++ // ---------------------------------------------------------------- ++ // Known-answer probes for the two precompiles that actually decide ++ // acceptance. ++ // ++ // Every probe above this point uses the point at infinity or a ++ // G1ADD vector. That leaves the two precompiles the verifier's ++ // security actually rests on untested for *rejection* behaviour: ++ // - 0x0c G1MSM is the curve/subgroup validator for every absorbed ++ // proof commitment (common_uncompressed_g1 runs no curve check); ++ // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose ++ // 0x0f always returns 1 accepts every proof. ++ // These four probes cost deployment gas only. ++ // ---------------------------------------------------------------- ++ ++ // (a) G1MSM known answer: [2]*G == 2G. ++ mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) ++ mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) ++ mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) ++ mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) ++ mstore(add(scratch, 0x80), 2) ++ if iszero(staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } ++ if iszero(and( ++ and( ++ eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), ++ eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) ++ ), ++ and( ++ eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), ++ eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) ++ ) ++ )) { revert(0, 0) } ++ ++ // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp ++ // but is NOT in the r-order subgroup (checked off-chain: r*P != O). ++ // EIP-2537 requires G1MSM to reject it. This is the one property ++ // the verifier's deferred-validation strategy depends on and the ++ // one property no other probe exercises. ++ // ++ // Gas is bounded on purpose: a precompile that rejects its input ++ // consumes everything forwarded to it, so an unbounded `gas()` here ++ // would burn 63/64 of the deployment gas before the probes below. ++ mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) ++ mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) ++ mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) ++ mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) ++ mstore(add(scratch, 0x80), 1) ++ if staticcall(200000, {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }}) { revert(0, 0) } ++ ++ // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: ++ // with G1' = -G the product is 1, with G1' = +G it is not. G2 is ++ // written literally because the VK payload is not loaded during ++ // construction. ++ mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) ++ mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) ++ mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) ++ mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) ++ mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) ++ mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) ++ mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) ++ mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) ++ mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) ++ mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) ++ mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) ++ mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) ++ mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) ++ mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) ++ mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) ++ mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) ++ mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) ++ ++ // (c) e(G, G2) * e(-G, G2) == 1. ++ if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } ++ ++ // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. ++ mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) ++ mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) ++ if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } ++ if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } ++ + // Restore the identity encoding for the probes below. + for { let off := 0 } lt(off, {{ template_constants.eip2537.smoke_scratch_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { + mstore(add(scratch, off), 0) +--- a/scripts/install_pinned_solc.sh ++++ b/scripts/install_pinned_solc.sh +@@ -26,10 +26,36 @@ + mkdir -p "$INSTALL_DIR" + solc_path="$INSTALL_DIR/solc" + ++# Content hash, not version string. `--version` output is trivially forged by a ++# substituted binary, and this project's entire reproducibility claim rests on ++# the compiler being exactly this one. Per-platform hashes are published in ++# https://binaries.soliditylang.org/${platform}/list.json -- fill these in and ++# record them in the artifact manifest alongside the flag set. ++declare -A PINNED_SOLC_SHA256=( ++ ["linux-amd64"]="TODO-fill-from-list.json" ++ ["macosx-amd64"]="TODO-fill-from-list.json" ++) ++ + if [[ ! -x "$solc_path" ]] || ! "$solc_path" --version | grep -q "Version: ${PINNED_SOLC_VERSION}"; then + url="https://binaries.soliditylang.org/${platform}/${binary}" + echo "[install-solc] downloading $url" + curl -fsSL "$url" -o "$solc_path" ++ expected="${PINNED_SOLC_SHA256[$platform]:-}" ++ if [[ -z "$expected" || "$expected" == TODO-* ]]; then ++ echo "[install-solc] no pinned SHA-256 recorded for platform '$platform'." >&2 ++ echo "[install-solc] Fetch it from https://binaries.soliditylang.org/${platform}/list.json" >&2 ++ echo "[install-solc] and set PINNED_SOLC_SHA256 in this script." >&2 ++ rm -f "$solc_path" ++ exit 1 ++ fi ++ actual="$(shasum -a 256 "$solc_path" 2>/dev/null | cut -d' ' -f1 || sha256sum "$solc_path" | cut -d' ' -f1)" ++ if [[ "$actual" != "$expected" ]]; then ++ echo "[install-solc] SHA-256 mismatch for $url" >&2 ++ echo "[install-solc] expected $expected" >&2 ++ echo "[install-solc] actual $actual" >&2 ++ rm -f "$solc_path" ++ exit 1 ++ fi + chmod +x "$solc_path" + fi + diff --git a/proofs/solidity-verifier/scripts/install_pinned_solc.sh b/proofs/solidity-verifier/scripts/install_pinned_solc.sh old mode 100755 new mode 100644 index 750092dc5..25fab697b --- a/proofs/solidity-verifier/scripts/install_pinned_solc.sh +++ b/proofs/solidity-verifier/scripts/install_pinned_solc.sh @@ -26,10 +26,36 @@ esac mkdir -p "$INSTALL_DIR" solc_path="$INSTALL_DIR/solc" +# Content hash, not version string. `--version` output is trivially forged by a +# substituted binary, and this project's entire reproducibility claim rests on +# the compiler being exactly this one. Per-platform hashes are published in +# https://binaries.soliditylang.org/${platform}/list.json -- fill these in and +# record them in the artifact manifest alongside the flag set. +declare -A PINNED_SOLC_SHA256=( + ["linux-amd64"]="TODO-fill-from-list.json" + ["macosx-amd64"]="TODO-fill-from-list.json" +) + if [[ ! -x "$solc_path" ]] || ! "$solc_path" --version | grep -q "Version: ${PINNED_SOLC_VERSION}"; then url="https://binaries.soliditylang.org/${platform}/${binary}" echo "[install-solc] downloading $url" curl -fsSL "$url" -o "$solc_path" + expected="${PINNED_SOLC_SHA256[$platform]:-}" + if [[ -z "$expected" || "$expected" == TODO-* ]]; then + echo "[install-solc] no pinned SHA-256 recorded for platform '$platform'." >&2 + echo "[install-solc] Fetch it from https://binaries.soliditylang.org/${platform}/list.json" >&2 + echo "[install-solc] and set PINNED_SOLC_SHA256 in this script." >&2 + rm -f "$solc_path" + exit 1 + fi + actual="$(shasum -a 256 "$solc_path" 2>/dev/null | cut -d' ' -f1 || sha256sum "$solc_path" | cut -d' ' -f1)" + if [[ "$actual" != "$expected" ]]; then + echo "[install-solc] SHA-256 mismatch for $url" >&2 + echo "[install-solc] expected $expected" >&2 + echo "[install-solc] actual $actual" >&2 + rm -f "$solc_path" + exit 1 + fi chmod +x "$solc_path" fi diff --git a/proofs/solidity-verifier/templates/contracts/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/templates/contracts/Halo2QuotientEvaluator.sol index a7e0f52df..f5a45dead 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2QuotientEvaluator.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2QuotientEvaluator.sol @@ -1,5 +1,8 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Split Halo2 quotient numerator evaluator. /// @notice Reconstructs the scalar side of the linearization query for a generated verifier. diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol index c715ece09..b0dfc4967 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -51,12 +62,14 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -93,10 +106,20 @@ contract Halo2Verifier { {%- when None %} {%- endmatch %} assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== diff --git a/proofs/solidity-verifier/templates/contracts/Halo2VerifyingKey.sol b/proofs/solidity-verifier/templates/contracts/Halo2VerifyingKey.sol index 955ae1072..756556d4d 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index 5fed51133..382004c96 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -2,6 +2,11 @@ /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := {{ memory.constructor_smoke_scratch_mptr|hex() }} @@ -55,6 +60,90 @@ ) )) { revert(0, 0) } + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }}) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, {{ template_constants.eip2537.smoke_scratch_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { mstore(add(scratch, off), 0) From 6f229c12a554ee7f5045fa37458d364d5f65818f Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 08:37:12 +0100 Subject: [PATCH 090/108] fix(solidity-verifier): stop forcing truncated-challenges through the aggregation dep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The midnight-aggregation dependency unconditionally enabled its truncated-challenges feature, which Cargo feature unification forced onto midnight-proofs in every build of this crate. The prover therefore always truncated challenges, while verifiers generated without this crate's own truncated-challenges feature did not mirror it — the exact "wrong setting on either side silently produces invalid pairings" hazard the feature's doc comment warns about. Every evm-only fixture test (rsa_signature, sha_preimage, hybrid_mt) had been failing with valid proofs reverting mid-PCS since the workspace merge that introduced the dependency. Truncation now flows exclusively through this crate's own truncated-challenges feature (which already forwards to midnight-proofs and midnight-aggregation), so both sides always agree. All fixture tests pass in both --features evm and --features evm,truncated-challenges. Co-Authored-By: Claude Fable 5 --- proofs/solidity-verifier/Cargo.toml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/Cargo.toml b/proofs/solidity-verifier/Cargo.toml index bb7b24f07..c5b9a7674 100644 --- a/proofs/solidity-verifier/Cargo.toml +++ b/proofs/solidity-verifier/Cargo.toml @@ -42,9 +42,19 @@ midnight-circuits = { path = "../../circuits", features = ["testing"] } midnight-zk-stdlib = { path = "../../zk_stdlib", features = ["testing"] } # IVC Poseidon-chain final-step Keccak proof end-to-end test # (tests/ivc_keccak_solidity.rs). +# +# Deliberately does NOT enable midnight-aggregation/truncated-challenges +# here: a dependency-level feature is unconditional, and via feature +# unification it forced midnight-proofs/truncated-challenges into EVERY +# build of this crate — including `--features evm` builds whose generated +# verifiers do not mirror the truncation. The prover then truncated while +# the rendered Solidity did not, and every valid proof from the +# `evm`-only fixture tests reverted mid-PCS ("using the wrong setting on +# either side silently produces invalid pairings", as the feature comment +# below puts it). Truncation is forwarded exclusively through this +# crate's own `truncated-challenges` feature so both sides always agree. midnight-aggregation = { path = "../../aggregation", features = [ "keccak-transcript", - "truncated-challenges", ] } [features] From f1840bdf6835a6b1d2fbba0a0921499a599919ec Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 08:37:38 +0100 Subject: [PATCH 091/108] fix(solidity-verifier): exact precompile gas bounds, SRS tau binding, MSM comment truth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three generator-side closures from the 2026-08 review (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): M-2/P1 — bound the gas forwarded to precompiles. A rejecting EIP-2537 or modexp call consumes ALL gas supplied to the STATICCALL, so a single malformed proof point burned 63/64 of the transaction budget (measured 29.5M of a 30M limit). Every precompile call site — templates, PCS emitter, and constructor probes — now forwards the exact EIP-2537/EIP-2565 scheduled cost from the new layout::gas model, rendered as generated constants (G1ADD_GAS, G1MSM_GAS_1PAIR, G1MSM_GAS_SMOKE, PAIRING_GAS_2PAIR, MODEXP_GAS, ACC_RHS_MSM_GAS) or per-site literals with the pair count in a comment. Exact-schedule bounds are sufficient by construction per EIP-2537's DDoS-protection rationale; an upward repricing fork requires regenerating and redeploying, and the constructor smoke probes forward the same bounds so deployment onto a repriced chain fails fast. The two pinned quotientEvaluator calls keep gas() deliberately: regular calls refund unused gas on failure. This reverses commit 2b2bf49's gas() forwarding (old finding M-04) with generated spec formulas instead of the hand-tuned literals that motivated it. Verified by eip2537_gas_schedule_matches_spec_vectors, eip2537_calls_forward_exact_schedule_gas, and the revm test malformed_proof_point_rejects_with_bounded_gas (rejection now costs no more than honest verification). H-1 (code half) — bind the SRS G2 side to the commitment basis. Applies the review's P11 patch with its two compile blockers repaired (omega shadowing; undefined helper): generate_base_vk now asserts g2 is the canonical generator and that s_g2 pairs consistently with the tau reconstructed from g_lagrange (srs_tau_is_consistent, Pippenger MSM so 2^20-point production SRSes stay fast). This is the only build-time control that can catch a substituted SRS; every other control checks self-consistency. Tested by srs_tau_binding_accepts_honest_params_and_rejects_foreign_s_g2 and the gated midnight_srs_assets_bind_s_g2_to_lagrange_tau, which validates the real midnight-srs-2p19/2p20 assets. L-2/P7 — the emitted q_eval_set comments now report evaluation terms and commitment terms separately (identity-pinned commitments are skipped by the MSM but kept in the eval fold), a whole-pairs assert guards the final-MSM gas derivation, and the generated opcode summary is rendered from the same op_usage predicates that gate the interpreter cases so each artifact documents exactly its own opcodes (I-2). The stale pragma test now pins 0.8.30, completing commit 460a666's M-1 fix. Co-Authored-By: Claude Fable 5 --- .../src/lowering/artifacts.rs | 17 ++ .../solidity-verifier/src/lowering/kzg/mod.rs | 45 ++++- .../src/lowering/layout/mod.rs | 80 +++++++++ .../src/lowering/render/models.rs | 37 ++++ .../solidity-verifier/src/lowering/tests.rs | 162 +++++++++++++++--- proofs/solidity-verifier/src/lowering/vk.rs | 75 +++++++- proofs/solidity-verifier/src/test.rs | 125 +++++++++++++- .../QuotientNumeratorBlock.yul | 111 ++++++++++-- .../partials/verifier/AccumulatorHelpers.yul | 7 +- .../partials/verifier/AssemblyHelpers.yul | 8 +- .../templates/partials/verifier/Constants.sol | 40 ++++- .../partials/verifier/FinalPairing.yul | 8 +- .../partials/verifier/PrecompileSmoke.sol | 18 +- .../verifier/QuotientAndLinearization.yul | 5 + 14 files changed, 663 insertions(+), 75 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/artifacts.rs b/proofs/solidity-verifier/src/lowering/artifacts.rs index fa61fabf8..9c37d89cf 100644 --- a/proofs/solidity-verifier/src/lowering/artifacts.rs +++ b/proofs/solidity-verifier/src/lowering/artifacts.rs @@ -229,6 +229,23 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { quotient_limb7_helper: quotient_helper_flags.limb7, quotient_wide_limb7_helper: quotient_helper_flags.wide_limb7, constructor_g1msm_smoke_input_bytes: plan.memory.constructor_g1msm_smoke_input_bytes, + constructor_g1msm_smoke_gas: { + let smoke_bytes = plan.memory.constructor_g1msm_smoke_input_bytes; + assert_eq!( + smoke_bytes % layout::G1_MSM_PAIR_BYTES, + 0, + "constructor G1MSM smoke input is not a whole number of pairs" + ); + layout::gas::g1msm_gas(smoke_bytes / layout::G1_MSM_PAIR_BYTES) + }, + acc_rhs_msm_gas: if expected_has_accumulator { + // Worst case: carried RHS point plus every fixed-base tail + // scalar nonzero. Zero scalars are omitted at runtime, which + // only shrinks the MSM below this bound. + layout::gas::g1msm_gas(1 + acc_fixed_bases.len()) + } else { + 0 + }, limb7_yul_coeffs: LIMB7_YUL_COEFFS, wide_limb7_yul_coeffs: WIDE_LIMB7_YUL_COEFFS, fr_delta: fr_delta_literal(), diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 2a607b6d5..3f2c7f98d 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -46,6 +46,7 @@ use crate::lowering::{ abi::proof::ProofCalldataLayout, encoding::{ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word}, layout::{ + gas, memory::{ FinalMsmShape, PcsMemoryRequirements, VerifierMemoryLayout, G1ADD_INPUT_BYTES, G1_BYTES, G1_MSM_PAIR_BYTES, PCS_STATIC_WORKING_WORDS, WORD_BYTES, @@ -1082,10 +1083,18 @@ pub(crate) fn computations( // ------------------------------------------------------------------ let eval_src_table_mptr: usize = memory.pcs_q_eval_source_table_mptr; + let comment_g1_identity = EcPoint::new(Ptr::memory("G1_IDENTITY_MPTR")); for (set_idx, commitments_in_set) in by_set.iter().enumerate() { let mut lines: Vec = Vec::new(); let q_eval_base = format!("add(Q_EVAL_SET_MPTR, {:#x})", set_idx * WORD_BYTES); let m = commitments_in_set.len(); + // The MSM emission (blocks 3 and 5) skips commitments pinned to + // the G1 identity while their evaluation contribution stays in + // q_eval_set, so the two counts differ whenever a set carries an + // identity commitment. Report both, or the emitted comment + // contradicts the pair count of the MSM right below it (L-2/P7). + let commitment_terms = + commitments_in_set.iter().filter(|c| c.comm != comment_g1_identity).count(); // q_eval_set[s] is itself a *vector* of |set| evaluations // (not a single scalar): one per rotation in the set's @@ -1106,7 +1115,8 @@ pub(crate) fn computations( if q_eval_strategy(commitments_in_set) == QEvalStrategy::Rolled { // -------- Rolled path (Opt I + Opt J merged) ---------- lines.push(format!( - "// q_eval_set[{set_idx}]: {m} commitment(s) (rolled, m>={Q_EVAL_ROLL_THRESHOLD})" + "// q_eval_set[{set_idx}]: {m} evaluation term(s), {commitment_terms} \ + commitment term(s) (rolled, m>={Q_EVAL_ROLL_THRESHOLD})" )); // 1. Pre-stage source-eval addresses at EVAL_SRC_TABLE_MPTR. Layout: row-major @@ -1180,7 +1190,10 @@ pub(crate) fn computations( } } else { // -------- Unrolled path (preserved for non-rolled sets) -- - lines.push(format!("// q_eval_set[{set_idx}]: {m} commitment(s)")); + lines.push(format!( + "// q_eval_set[{set_idx}]: {m} evaluation term(s), {commitment_terms} \ + commitment term(s)" + )); // Fr-only eval accumulation in stack locals. for (k, ev) in first.evals.iter().enumerate() { @@ -1318,7 +1331,11 @@ pub(crate) fn computations( ); let msm_len = non_identity_terms * G1_MSM_PAIR_BYTES; lines.push(format!( - "let q_com_trace_ok_{set_idx} := staticcall(gas(), 0x0c, {trace_scratch:#x}, {msm_len:#x}, {trace_scratch:#x}, {G1_BYTES:#x})" + "// exact EIP-2537 G1MSM cost for {non_identity_terms} pair(s)" + )); + lines.push(format!( + "let q_com_trace_ok_{set_idx} := staticcall({}, 0x0c, {trace_scratch:#x}, {msm_len:#x}, {trace_scratch:#x}, {G1_BYTES:#x})", + gas::g1msm_gas(non_identity_terms) )); lines.push(format!( "q_com_trace_ok_{set_idx} := and(q_com_trace_ok_{set_idx}, eq(returndatasize(), {G1_BYTES:#x}))" @@ -1603,6 +1620,14 @@ pub(crate) fn computations( let final_msm_shape = final_msm_shape(meta, data, &by_set); let final_msm_terms = final_msm_shape.terms; let final_msm_len = final_msm_shape.input_bytes; + // The forwarded gas bound below is derived from the term count, so + // the byte length handed to the precompile must be exactly that many + // whole pairs -- a mismatch would under-fund the MSM. + assert_eq!( + final_msm_terms * G1_MSM_PAIR_BYTES, + final_msm_len, + "final MSM input byte length is not a whole number of MSM pairs" + ); let final_msm_scratch = memory.pcs_final_msm_scratch_mptr; lines.push("// build final_com and v (KZG single-opening proof, fused MSM)".to_string()); @@ -1744,7 +1769,11 @@ pub(crate) fn computations( lines.push("if success {".to_string()); lines.push(format!( - " success := staticcall(gas(), 0x0c, {final_msm_scratch:#x}, {:#x}, FINAL_COM_MPTR, {G1_BYTES:#x})", + " // exact EIP-2537 G1MSM cost for {final_msm_terms} pair(s)" + )); + lines.push(format!( + " success := staticcall({}, 0x0c, {final_msm_scratch:#x}, {:#x}, FINAL_COM_MPTR, {G1_BYTES:#x})", + gas::g1msm_gas(final_msm_terms), final_msm_len )); lines.push(format!( @@ -1795,7 +1824,7 @@ pub(crate) fn computations( )); lines.push("if success {".to_string()); lines.push(format!( - " success := staticcall(gas(), 0x0c, {scratch:#x}, {G1_MSM_PAIR_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" + " success := staticcall(G1MSM_GAS_1PAIR, 0x0c, {scratch:#x}, {G1_MSM_PAIR_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" )); lines.push(format!( " success := and(success, eq(returndatasize(), {G1_BYTES:#x}))" @@ -1808,7 +1837,7 @@ pub(crate) fn computations( )); lines.push("if success {".to_string()); lines.push(format!( - " success := staticcall(gas(), 0x0b, {scratch:#x}, {G1ADD_INPUT_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" + " success := staticcall(G1ADD_GAS, 0x0b, {scratch:#x}, {G1ADD_INPUT_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" )); lines.push(format!( " success := and(success, eq(returndatasize(), {G1_BYTES:#x}))" @@ -1820,7 +1849,7 @@ pub(crate) fn computations( lines.push(format!("mstore({scratch_g1add_scalar:#x}, mload(X3_MPTR))")); lines.push("if success {".to_string()); lines.push(format!( - " success := staticcall(gas(), 0x0c, {scratch_g1_b:#x}, {G1_MSM_PAIR_BYTES:#x}, {scratch_g1_b:#x}, {G1_BYTES:#x})" + " success := staticcall(G1MSM_GAS_1PAIR, 0x0c, {scratch_g1_b:#x}, {G1_MSM_PAIR_BYTES:#x}, {scratch_g1_b:#x}, {G1_BYTES:#x})" )); lines.push(format!( " success := and(success, eq(returndatasize(), {G1_BYTES:#x}))" @@ -1828,7 +1857,7 @@ pub(crate) fn computations( lines.push("}".to_string()); lines.push("if success {".to_string()); lines.push(format!( - " success := staticcall(gas(), 0x0b, {scratch:#x}, {G1ADD_INPUT_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" + " success := staticcall(G1ADD_GAS, 0x0b, {scratch:#x}, {G1ADD_INPUT_BYTES:#x}, {scratch:#x}, {G1_BYTES:#x})" )); lines.push(format!( " success := and(success, eq(returndatasize(), {G1_BYTES:#x}))" diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 6df86b3af..709fc99e6 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -136,6 +136,86 @@ pub(crate) mod precompile { pub(crate) const PAIRING_ADDRESS: usize = 0x0f; } +pub(crate) mod gas { + //! Exact gas schedule for the precompiles the generated verifier calls, + //! from EIP-2537 (BLS12-381) and EIP-2565 (modexp). + //! + //! A failing EIP-2537 or modexp call consumes ALL gas supplied to the + //! `STATICCALL`, so every generated call site forwards the exact scheduled + //! cost instead of `gas()`: an attacker-supplied malformed point can then + //! burn at most the scheduled cost of the single failing call rather than + //! 63/64 of the transaction budget (measured 29.5M of a 30M limit before + //! this bound; see docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md, M-2). + //! + //! Sufficiency: EIP-2537's "DDoS protection" rationale guarantees the + //! schedule prices the worst case, so forwarding exactly the scheduled + //! amount succeeds by construction on any conformant implementation of + //! the current schedule. + //! + //! Liveness caveat: if a future fork reprices these precompiles UPWARD, + //! deployed verifiers start reverting on valid proofs and must be + //! regenerated and redeployed. The constructor smoke probes forward the + //! same bounds, so deployment onto an already-repriced chain fails fast + //! instead of bricking at proof time. + + /// EIP-2537 G1ADD flat cost. + pub(crate) const G1ADD_GAS: u64 = 375; + /// EIP-2537 G1 per-pair base multiplication cost. + const G1_MSM_MULTIPLICATION_COST: u64 = 12_000; + /// EIP-2537 MSM discount denominator. + const MSM_MULTIPLIER: u64 = 1_000; + /// EIP-2537 G1 MSM discount table for k = 1..=128 pairs, in parts per + /// [`MSM_MULTIPLIER`]. Entry `[k - 1]` is the discount for `k` pairs; + /// `k > 128` uses the final entry (`max_discount = 519`). + const G1_MSM_DISCOUNT: [u64; 128] = [ + 1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, + 665, 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, + 617, 615, 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, + 588, 586, 585, 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, + 566, 565, 564, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, + 548, 547, 547, 546, 545, 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, + 533, 532, 532, 531, 530, 529, 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, + 520, 519, + ]; + + /// EIP-2537 G1MSM cost for `k` (point, scalar) pairs: + /// `(k * 12000 * discount(k)) // 1000`. + pub(crate) fn g1msm_gas(pairs: usize) -> u64 { + assert!(pairs > 0, "G1MSM gas bound requested for an empty MSM"); + let discount = if pairs <= G1_MSM_DISCOUNT.len() { + G1_MSM_DISCOUNT[pairs - 1] + } else { + G1_MSM_DISCOUNT[G1_MSM_DISCOUNT.len() - 1] + }; + (pairs as u64) * G1_MSM_MULTIPLICATION_COST * discount / MSM_MULTIPLIER + } + + /// EIP-2537 pairing cost for `k` (G1, G2) pairs: `32600*k + 37700`. + pub(crate) const fn pairing_gas(pairs: u64) -> u64 { + 32_600 * pairs + 37_700 + } + + /// EIP-2565 modexp cost for the only frame shape the verifier emits: + /// 32-byte base, 32-byte exponent, 32-byte modulus. + /// + /// `words = ceil(32/8) = 4`, `multiplication_complexity = words^2 = 16`, + /// `iteration_count <= 255` (32-byte exponent), so + /// `max(200, 16 * 255 / 3) = 1360`. EIP-7883 (scheduled for Osaka) keeps + /// the same result for these operand sizes: it raises the floor to 500 + /// (< 1360) and only reprices operands wider than 32 bytes. + pub(crate) const fn modexp_gas_word_frame() -> u64 { + const WORDS: u64 = 4; + const MULTIPLICATION_COMPLEXITY: u64 = WORDS * WORDS; + const MAX_ITERATION_COUNT: u64 = 255; + let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT / 3; + if cost < 200 { + 200 + } else { + cost + } + } +} + pub(crate) mod modexp_frame { //! 32-byte base/exponent/modulus EIP-198 frame offsets. diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index 58974681b..e6fabab76 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -41,6 +41,8 @@ pub(crate) struct TemplateConstants { pub(crate) pairing_two_pair_bytes: usize, /// EIP-2537 precompile constants. pub(crate) eip2537: Eip2537TemplateConstants, + /// Exact EIP-2537/EIP-2565 gas bounds forwarded to precompile calls. + pub(crate) gas: GasTemplateConstants, /// EIP-198 modexp constants. pub(crate) modexp: ModexpTemplateConstants, /// Public accumulator layout constants. @@ -66,6 +68,24 @@ pub(crate) struct Eip2537TemplateConstants { pub(crate) g1_double_generator: G1Words, } +/// Exact precompile gas bounds rendered into templates. +/// +/// These are the EIP-2537/EIP-2565 scheduled costs, forwarded verbatim so a +/// failing precompile call burns at most its scheduled cost instead of the +/// full 63/64 of the transaction budget. See [`layout::gas`] for the model +/// and the upward-repricing liveness caveat. +#[derive(Clone, Copy, Debug)] +pub(crate) struct GasTemplateConstants { + /// EIP-2537 G1ADD flat cost. + pub(crate) g1add: u64, + /// EIP-2537 G1MSM cost for a single (point, scalar) pair. + pub(crate) g1msm_one_pair: u64, + /// EIP-2537 pairing cost for the verifier's two-pair check. + pub(crate) pairing_two_pair: u64, + /// EIP-2565 modexp cost for the 32-byte base/exp/mod frame. + pub(crate) modexp: u64, +} + /// EIP-198 modexp frame constants rendered into templates. #[derive(Clone, Copy, Debug)] pub(crate) struct ModexpTemplateConstants { @@ -180,6 +200,12 @@ impl Default for TemplateConstants { g1_words((g + g).to_affine()) }, }, + gas: GasTemplateConstants { + g1add: layout::gas::G1ADD_GAS, + g1msm_one_pair: layout::gas::g1msm_gas(1), + pairing_two_pair: layout::gas::pairing_gas(2), + modexp: layout::gas::modexp_gas_word_frame(), + }, modexp: ModexpTemplateConstants { address: layout::precompile::MODEXP_ADDRESS, frame_bytes: layout::MODEXP_FRAME_BYTES, @@ -457,6 +483,15 @@ pub(crate) struct Halo2Verifier { pub(crate) quotient_wide_limb7_helper: bool, /// Largest generated G1MSM input length, smoke-tested at deployment. pub(crate) constructor_g1msm_smoke_input_bytes: usize, + /// Exact EIP-2537 G1MSM cost for the deployment smoke probe over + /// [`Self::constructor_g1msm_smoke_input_bytes`]. + pub(crate) constructor_g1msm_smoke_gas: u64, + /// Exact EIP-2537 G1MSM cost bound for the accumulator RHS MSM, sized + /// for its worst case: the carried RHS point plus every generated + /// fixed-base tail scalar nonzero. Zero tail scalars are omitted at + /// runtime, which only lowers the actual cost below this bound. + /// Zero when the verifier has no public accumulator. + pub(crate) acc_rhs_msm_gas: u64, pub(crate) limb7_yul_coeffs: [&'static str; layout::quotient_limb::LIN_COEFFS], pub(crate) wide_limb7_yul_coeffs: [&'static str; layout::quotient_limb::LIN_COEFFS], pub(crate) fr_delta: String, @@ -1105,6 +1140,8 @@ mod tests { quotient_limb7_helper: false, quotient_wide_limb7_helper: false, constructor_g1msm_smoke_input_bytes: crate::lowering::layout::G1_MSM_PAIR_BYTES, + constructor_g1msm_smoke_gas: crate::lowering::layout::gas::g1msm_gas(1), + acc_rhs_msm_gas: 0, limb7_yul_coeffs: crate::lowering::quotient_numerator::vm::LIMB7_YUL_COEFFS, wide_limb7_yul_coeffs: crate::lowering::quotient_numerator::vm::WIDE_LIMB7_YUL_COEFFS, fr_delta: crate::lowering::quotient_numerator::vm::fr_delta_literal(), diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index bd18947ef..ceb8d02c8 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -383,6 +383,52 @@ fn quotient_vm_test_vk() -> ( (params, vk) } +/// H-1 (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): `NEG_S_G2_BASE` is the +/// element the deployed verifier's soundness rests on, and the tau-binding +/// pairing check in `vk.rs` is the only build-time control that ties it to +/// the commitment basis. Exercise both directions: an honest SRS passes, and +/// a G2 side taken from ANY other tau -- here the canonical generator, i.e. +/// s = 1, and a doubled s_g2, i.e. s' = 2s -- is rejected. +#[test] +fn srs_tau_binding_accepts_honest_params_and_rejects_foreign_s_g2() { + use group::{prime::PrimeCurveAffine, Curve}; + + let (params, vk) = quotient_vm_test_vk(); + let omega = vk.get_domain().get_omega(); + let honest_s_g2 = params.s_g2().to_affine(); + + assert!( + crate::lowering::vk::srs_tau_is_consistent(params.g_lagrange(), omega, honest_s_g2), + "an honestly generated SRS must pass the tau-binding pairing check" + ); + assert!( + !crate::lowering::vk::srs_tau_is_consistent( + params.g_lagrange(), + omega, + midnight_curves::G2Affine::generator(), + ), + "a G2 base substituted for s_g2 (s = 1) must fail the tau binding" + ); + assert!( + !crate::lowering::vk::srs_tau_is_consistent( + params.g_lagrange(), + omega, + (params.s_g2() + params.s_g2()).to_affine(), + ), + "a doubled s_g2 (s' = 2s) must fail the tau binding" + ); + // A mismatched domain also fails: omega from a different-sized domain + // reconstructs a different tau commitment. + assert!( + !crate::lowering::vk::srs_tau_is_consistent( + params.g_lagrange(), + omega * omega, + honest_s_g2, + ), + "a wrong domain generator must fail the tau binding" + ); +} + /// The generator certifies its own quotient bytecode on a real plan. /// /// `LoweringPlan::new` runs `certify_quotient_program` and the dual-build @@ -1332,35 +1378,94 @@ fn transcript_memory_bound_handles_wide_bls_advice_phase() { ); } +/// A failing EIP-2537/modexp call consumes ALL forwarded gas, so every +/// precompile call site must forward the exact scheduled cost instead of +/// `gas()`: a malformed proof point then burns at most the scheduled cost of +/// the single failing call (M-2, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). +/// +/// History: this is a deliberate reversal of `2b2bf49` ("Forward gas to +/// EIP-2537 precompiles"), which removed HAND-TUNED gas literals because +/// they could brick verification on repriced chains (audit finding M-04). +/// The bounds asserted here are different in kind: they are the EIP-2537 / +/// EIP-2565 schedule formulas evaluated at generation time (layout::gas), +/// and the constructor smoke probes forward the same bounds so deployment +/// onto a repriced chain fails fast instead of bricking at proof time. #[test] -fn eip2537_calls_forward_remaining_gas() { +fn eip2537_calls_forward_exact_schedule_gas() { let verifier_template = verifier_template_corpus(); let pcs_codegen = include_str!("kzg/mod.rs"); + // Every gas() forward left in the corpus must be one of the three + // intentional sites, all in QuotientAndLinearization.yul: + // 1. the pinned external quotient evaluator staticcall (regular-call refund + // semantics: a failing callee returns unused gas; only precompile ERRORS + // burn everything forwarded), + // 2. its trace-mode call() variant, + // 3. the trace-only linearization-commitment G1MSM (never rendered into + // production artifacts). + for source in [verifier_template, pcs_codegen] { + for line in source.lines() { + if line.contains("(gas()") { + assert!( + line.contains("quotientEvaluator") || line.contains("lin_trace_ok"), + "precompile calls must forward exact EIP-2537/EIP-2565 \ + schedule gas, not gas(): {line}" + ); + } + } + } assert!( verifier_template - .contains("staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}") - && verifier_template - .contains("staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}") + .contains("staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}") && verifier_template.contains( - "staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}" - ), - "main verifier template should forward remaining gas to EIP-2537 precompiles" + "staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}" + ) + && verifier_template.contains( + "staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}" + ) + && verifier_template + .contains("staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}") + // The accumulator RHS MSM staticcall is formatted multi-line, so + // match its first argument rather than the call prefix. + && verifier_template.contains("ACC_RHS_MSM_GAS,") + && verifier_template.contains("staticcall(G1MSM_GAS_SMOKE"), + "main verifier template should forward the generated exact gas bounds" ); assert!( - pcs_codegen.contains("staticcall(gas(), 0x0c") - && pcs_codegen.contains("staticcall(gas(), 0x0b"), - "PCS emitter should forward remaining gas to EIP-2537 precompiles" + pcs_codegen.contains("staticcall(G1MSM_GAS_1PAIR, 0x0c") + && pcs_codegen.contains("staticcall(G1ADD_GAS, 0x0b"), + "PCS emitter should forward the generated exact gas bounds" ); - for source in [verifier_template, pcs_codegen] { - assert!( - !source.contains("g1msm_gas_cap") - && !source.contains("G1ADD_GAS_CAP") - && !source.contains("PAIRING_SMOKE_GAS_CAP") - && !source.contains("final_pairing_gas_cap"), - "EIP-2537 gas-cap literals must not be rendered or computed" - ); - } + assert_eq!( + verifier_template.matches("(gas()").count(), + 3, + "unexpected gas() forwarding site added to the verifier templates" + ); +} + +/// Pin the generated schedule values against EIP-2537/EIP-2565 by hand so a +/// typo in the discount table or formulas cannot slip through rendering. +#[test] +fn eip2537_gas_schedule_matches_spec_vectors() { + use crate::lowering::layout::gas; + + assert_eq!(gas::G1ADD_GAS, 375); + // (k * 12000 * discount(k)) // 1000 at the table's edge cases. + assert_eq!(gas::g1msm_gas(1), 12_000); + assert_eq!(gas::g1msm_gas(2), 22_776); + assert_eq!(gas::g1msm_gas(128), 797_184); + // k > 128 keeps max_discount = 519. + assert_eq!(gas::g1msm_gas(200), 200 * 12_000 * 519 / 1_000); + // 32600*k + 37700 for the verifier's two-pair check. + assert_eq!(gas::pairing_gas(2), 102_900); + // EIP-2565, 32-byte base/exp/mod: max(200, 16 * 255 / 3). + assert_eq!(gas::modexp_gas_word_frame(), 1_360); + // The rendered template constants come from the same module. + let constants = crate::lowering::render::TemplateConstants::default().gas; + assert_eq!(constants.g1add, 375); + assert_eq!(constants.g1msm_one_pair, 12_000); + assert_eq!(constants.pairing_two_pair, 102_900); + assert_eq!(constants.modexp, 1_360); } #[test] @@ -1406,8 +1511,8 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { ); assert!( pcs_codegen.contains("if success {") - && pcs_codegen.contains("success := staticcall(gas(), 0x0c") - && pcs_codegen.contains("success := staticcall(gas(), 0x0b"), + && pcs_codegen.contains("success := staticcall(G1MSM_GAS_1PAIR, 0x0c") + && pcs_codegen.contains("success := staticcall(G1ADD_GAS, 0x0b"), "PCS emitter should guard final MSM/add precompile calls with if success" ); } @@ -1465,9 +1570,10 @@ fn verifier_constructor_smoke_tests_runtime_prerequisites() { "Worst-case generated G1MSM with all identity/zero terms", "constructor_g1msm_smoke_input_bytes", "PAIRING_CHECK([(identity_g1, identity_g2), (identity_g1, identity_g2)])", - "staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}", - "staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}", - "staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}", + "staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}", + "staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}", + "staticcall(G1MSM_GAS_SMOKE, {{ template_constants.eip2537.g1msm_address|hex() }}", + "staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}", "template_constants.eip2537.g1add_address", "template_constants.eip2537.g1msm_address", "template_constants.eip2537.pairing_address", @@ -1749,9 +1855,13 @@ fn generated_solidity_pragmas_require_mcopy_capable_compiler() { include_str!("../../templates/contracts/Halo2QuotientEvaluator.sol"), ), ] { + // Pinned (not ^-ranged) since the M-1 fix: the artifact hashes in the + // review packet are only reproducible against one compiler version, + // and 0.8.30 is the version the deployment pipeline pins. assert!( - source.contains("pragma solidity ^0.8.24;"), - "{name} must require Solidity 0.8.24+ for Cancun Yul opcodes" + source.contains("pragma solidity 0.8.30;"), + "{name} must pin the Solidity version the build pipeline pins \ + (0.8.30, MCOPY/Cancun-capable)" ); } } diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index af26bc0f7..1678e14a1 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -8,7 +8,7 @@ use ff::Field; use group::{prime::PrimeCurveAffine, Curve, Group}; use itertools::chain; -use midnight_curves::{Fq, G1Affine, G1Projective, G2Affine}; +use midnight_curves::{pairing::Engine, Bls12, Fq, G1Affine, G1Projective, G2Affine}; use ruint::aliases::U256; use crate::lowering::{ @@ -26,6 +26,33 @@ use crate::lowering::{ VerifierBuildInputs, }; +/// Return whether `s_g2` corresponds to the same tau that produced +/// `g_lagrange`. +/// +/// Commit f(X) = X in the Lagrange basis over the domain generated by +/// `omega` to obtain `[tau]G1 = sum_i omega^i * L_i(tau) * G`, then check +/// the pairing identity `e([tau]G1, G2) == e(G1, s_g2)`. This ties the G2 +/// side of the key -- the element the deployed verifier's final pairing +/// trusts as `[s]_2` -- to the commitment basis the prover actually uses. +pub(crate) fn srs_tau_is_consistent( + g_lagrange: &[G1Projective], + omega: Fq, + s_g2: G2Affine, +) -> bool { + // Pippenger MSM: production SRS sizes reach 2^20 Lagrange points, so a + // naive per-point scalar multiplication here would stall every build. + let mut omega_pow = Fq::ONE; + let omega_powers: Vec = (0..g_lagrange.len()) + .map(|_| { + let current = omega_pow; + omega_pow *= omega; + current + }) + .collect(); + let tau_g1 = G1Projective::multi_exp(g_lagrange, &omega_powers).to_affine(); + Bls12::pairing(&tau_g1, &G2Affine::generator()) == Bls12::pairing(&G1Affine::generator(), &s_g2) +} + impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { /// Generate the VK payload before compact quotient constants/program data. fn generate_base_vk(&self) -> Halo2VerifyingKey { @@ -93,6 +120,52 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { let g1_pt: G1Affine = G1Affine::generator(); let g2_pt: G2Affine = self.params.g2().to_affine(); let neg_s_g2_pt: G2Affine = (-self.params.s_g2()).to_affine(); + + // The G1 base is validated above by reconstructing it from + // `g_lagrange`. Do the same work on the G2 side. Until now `g2` + // and `s_g2` were taken on trust from `params`, and + // `NEG_S_G2_BASE` is the element every soundness guarantee in the + // deployed verifier rests on: the final pairing is + // e(final_com - v*G + x3*pi, G2_BASE) * e(pi, NEG_S_G2_BASE) == 1 + // and anyone who knows the tau behind NEG_S_G2_BASE can forge an + // opening for any statement. + // + // Every other control in this repository -- quotient + // certification, the dual build, generator invariants, the VK + // codehash pin, the trace differential, the replay fixtures -- + // checks SELF-CONSISTENCY. An SRS substituted at build time + // produces a perfectly self-consistent artifact, so all of them + // pass. These asserts are the only build-time control that can + // catch it. (H-1, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md.) + + // 1. G2_BASE must be the canonical generator, for the same reason G1_BASE must + // be: the emitted equation assumes it. + assert_eq!( + g2_pt, + G2Affine::generator(), + "SRS G2 base is not the canonical BLS12-381 G2 generator; the \ + emitted pairing equation would not be the KZG identity" + ); + + // 2. `s_g2` must correspond to the SAME tau that produced `g_lagrange`; see + // `srs_tau_is_consistent`. + assert!( + srs_tau_is_consistent( + g_lagrange, + domain.get_omega(), + self.params.s_g2().to_affine() + ), + "SRS inconsistency: s_g2 does not correspond to the tau that \ + generated g_lagrange. NEG_S_G2_BASE would be emitted from an \ + SRS unrelated to the commitment basis -- i.e. from a key whose \ + toxic waste may be known to whoever supplied it." + ); + + // TODO(deployment): additionally pin the SRS asset by SHA-256 and + // record it, plus the ceremony transcript reference, in + // docs/reference/REPRODUCIBLE_BUILDS.md; scripts/ + // record_srs_provenance.sh produces the hashes. + let g1 = g1_to_u256s(g1_pt); let g2 = g2_to_u256s(g2_pt); let neg_s_g2 = g2_to_u256s(neg_s_g2_pt); diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 2eb2469c3..0e64ad5f7 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1548,11 +1548,16 @@ fn batch_invert_harness_source(verifier_solidity: &str) -> String { verifier_solidity, "function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret", ); + let modexp_gas = crate::lowering::layout::gas::modexp_gas_word_frame(); format!( r#"// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.24; contract BatchInvertHarness {{ + // The extracted helper forwards the exact EIP-2565 modexp cost; mirror + // the generated constant it references. + uint256 internal constant MODEXP_GAS = {modexp_gas}; + fallback() external {{ assembly {{ {batch_invert} @@ -1687,18 +1692,18 @@ fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { for (name, needle, replacement) in [ ( "missing G1ADD precompile", - "staticcall(gas(), 0x0b", - "staticcall(gas(), 0x12", + "staticcall(G1ADD_GAS, 0x0b", + "staticcall(G1ADD_GAS, 0x12", ), ( "G1MSM routed to G1ADD", - "staticcall(gas(), 0x0c", - "staticcall(gas(), 0x0b", + "staticcall(G1MSM_GAS_1PAIR, 0x0c", + "staticcall(G1MSM_GAS_1PAIR, 0x0b", ), ( "pairing routed to G1MSM", - "staticcall(gas(), 0x0f", - "staticcall(gas(), 0x0c", + "staticcall(PAIRING_GAS_2PAIR, 0x0f", + "staticcall(PAIRING_GAS_2PAIR, 0x0c", ), ] { let verifier_solidity = replace_required_precompile_staticcall( @@ -2982,6 +2987,114 @@ fn every_proof_g1_rejects_off_curve_coordinates() { } } +/// M-2 (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): a rejecting EIP-2537 +/// precompile consumes ALL gas supplied to the STATICCALL, so before the +/// generated exact gas bounds a canonical-but-off-curve proof point burned +/// 63/64 of the transaction budget (measured 29.5M of a 30M limit). With the +/// bounds in place, rejecting a malformed point must cost no more than an +/// honest verification: the failing run is a prefix of the honest run plus +/// one precompile call whose forwarded gas is capped at its scheduled cost. +#[test] +fn malformed_proof_point_rejects_with_bounded_gas() { + const GAS_LIMIT: u64 = 30_000_000; + + if !poseidon_inputs_available_for_evm() { + return; + } + + let fixture = create_property_poseidon_fixture(); + let layout = proof_g1_layout(&fixture); + let solidity_bad = eip2537_padded_off_curve_g1_bytes(); + + let mut deployed = deployed_separate_verifier(&fixture); + if !deployed_call_accepts(&mut deployed, &fixture, &fixture.proof, "valid proof") { + return; + } + let honest_gas = match deployed.evm.try_call_with_gas( + deployed.verifier_address, + encode_calldata(&fixture.proof, &fixture.instances), + GAS_LIMIT, + ) { + CallOutcome::Success { gas_used, .. } => gas_used, + outcome => panic!("baseline honest verification failed: {outcome:?}"), + }; + + for (idx, repacked_offset) in layout.repacked_offsets.iter().copied().enumerate() { + let mut bad_solidity = fixture.proof.clone(); + bad_solidity[repacked_offset..repacked_offset + 128].copy_from_slice(&solidity_bad); + let gas_used = match deployed.evm.try_call_with_gas( + deployed.verifier_address, + encode_calldata(&bad_solidity, &fixture.instances), + GAS_LIMIT, + ) { + CallOutcome::Revert { gas_used, .. } | CallOutcome::Halt { gas_used, .. } => gas_used, + CallOutcome::Success { output, .. } => { + // Rejection-by-return-false also must not burn the budget. + assert_eq!( + output.last().copied(), + Some(0), + "off-curve G1 idx={idx} unexpectedly verified" + ); + continue; + } + }; + assert!( + gas_used <= honest_gas, + "rejecting off-curve G1 idx={idx} repacked_offset={repacked_offset} burned \ + {gas_used} gas, more than the honest verification's {honest_gas}: a \ + precompile call site is forwarding more than its scheduled cost" + ); + } +} + +/// H-1 provenance (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the +/// production Midnight SRS assets must bind their `s_g2` — the element the +/// deployed verifier's `NEG_S_G2_BASE` is derived from — to the same tau +/// that generated their Lagrange basis. The build-time assert in +/// `src/lowering/vk.rs` runs this check on whatever `params` a build was +/// handed; this test runs it directly against the distributed asset files, +/// so a corrupted or substituted download fails here even before any build. +#[test] +fn midnight_srs_assets_bind_s_g2_to_lagrange_tau() { + use ff::PrimeField; + use midnight_zk_stdlib::utils::plonk_api::{load_srs, SrsSource}; + + if !env_flag_enabled(RUN_EVM_TESTS_ENV) { + eprintln!("skipping Midnight SRS tau-binding check: set {RUN_EVM_TESTS_ENV}=1 to run it"); + return; + } + let srs_dir = srs_dir(); + env::set_var("SRS_DIR", &srs_dir); + + let mut checked = 0usize; + for (asset, k) in [("midnight-srs-2p19", 19u32), ("midnight-srs-2p20", 20u32)] { + if !PathBuf::from(&srs_dir).join(asset).exists() { + eprintln!("skipping {asset}: not present under {srs_dir}"); + continue; + } + let params = load_srs(SrsSource::Midnight, k, 2); + // omega for the 2^k evaluation domain the Lagrange basis is over. + let omega = + ::ROOT_OF_UNITY.pow_vartime([1u64 << (::S - k)]); + assert!( + crate::lowering::vk::srs_tau_is_consistent( + params.g_lagrange(), + omega, + params.s_g2().to_affine(), + ), + "{asset}: s_g2 does not correspond to the tau underlying g_lagrange; \ + the asset is corrupted or was substituted" + ); + checked += 1; + } + if checked == 0 { + eprintln!( + "no midnight-srs assets found under {srs_dir}; \ + fetch them with scripts/run_ivc_bench.sh or record_srs_provenance.sh" + ); + } +} + /// Produce a native Poseidon proof and verify it before Solidity tests use it. fn generate_poseidon_proof( srs: &PoseidonParams, diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul index f4de01c7b..a0b255e2c 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul @@ -176,18 +176,103 @@ // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + {%- if program.op_usage.push_const %} + // {{ template_constants.quotient_vm.op.push_const|hex() }} push_const + {%- endif %} + {%- if program.op_usage.push_mem_literal %} + // {{ template_constants.quotient_vm.op.push_mem_literal|hex() }} push_mem_literal + {%- endif %} + {%- if program.op_usage.push_mem_token %} + // {{ template_constants.quotient_vm.op.push_mem_token|hex() }} push_mem_token + {%- endif %} + {%- if program.op_usage.push_mem_token_offset %} + // {{ template_constants.quotient_vm.op.push_mem_token_offset|hex() }} push_mem_token_offset + {%- endif %} + {%- if program.op_usage.push_mem_u16 %} + // {{ template_constants.quotient_vm.op.push_mem_u16|hex() }} push_mem_u16 + {%- endif %} + {%- if program.op_usage.add %} + // {{ template_constants.quotient_vm.op.add|hex() }} add + {%- endif %} + {%- if program.op_usage.mul %} + // {{ template_constants.quotient_vm.op.mul|hex() }} mul + {%- endif %} + {%- if program.op_usage.neg %} + // {{ template_constants.quotient_vm.op.neg|hex() }} neg + {%- endif %} + {%- if program.op_usage.push_const_u8 %} + // {{ template_constants.quotient_vm.op.push_const_u8|hex() }} push_const_u8 + {%- endif %} + {%- if program.op_usage.fold_main %} + // {{ template_constants.quotient_vm.op.fold_main|hex() }} fold_main + {%- endif %} + {%- if program.op_usage.fold_selector %} + // {{ template_constants.quotient_vm.op.fold_selector|hex() }} fold_selector + {%- endif %} + {%- if program.op_usage.add_const_u8 %} + // {{ template_constants.quotient_vm.op.add_const_u8|hex() }} add_const_u8 + {%- endif %} + {%- if program.op_usage.mul_const_u8 %} + // {{ template_constants.quotient_vm.op.mul_const_u8|hex() }} mul_const_u8 + {%- endif %} + {%- if program.op_usage.add_const %} + // {{ template_constants.quotient_vm.op.add_const|hex() }} add_const + {%- endif %} + {%- if program.op_usage.mul_const %} + // {{ template_constants.quotient_vm.op.mul_const|hex() }} mul_const + {%- endif %} + {%- if program.op_usage.add_mem_u16 %} + // {{ template_constants.quotient_vm.op.add_mem_u16|hex() }} add_mem_u16 + {%- endif %} + {%- if program.op_usage.mul_mem_u16 %} + // {{ template_constants.quotient_vm.op.mul_mem_u16|hex() }} mul_mem_u16 + {%- endif %} + {%- if program.op_usage.add_mul_mem_mem_const_u8 %} + // {{ template_constants.quotient_vm.op.add_mul_mem_mem_const_u8|hex() }} add_mul_mem_mem_const_u8 + {%- endif %} + {%- if program.op_usage.add_mul_const_u8_mem_u16 %} + // {{ template_constants.quotient_vm.op.add_mul_const_u8_mem_u16|hex() }} add_mul_const_u8_mem_u16 + {%- endif %} + {%- if program.op_usage.add_mul_mem_mem %} + // {{ template_constants.quotient_vm.op.add_mul_mem_mem|hex() }} add_mul_mem_mem + {%- endif %} + {%- if program.op_usage.run_add_mul_mem_mem_const_u8 %} + // {{ template_constants.quotient_vm.op.run_add_mul_mem_mem_const_u8|hex() }} run_add_mul_mem_mem_const_u8 + {%- endif %} + {%- if program.op_usage.run_add_mul_const_u8_mem_u16 %} + // {{ template_constants.quotient_vm.op.run_add_mul_const_u8_mem_u16|hex() }} run_add_mul_const_u8_mem_u16 + {%- endif %} + {%- if program.op_usage.affine_sum %} + // {{ template_constants.quotient_vm.op.affine_sum|hex() }} affine_sum + {%- endif %} + {%- if program.op_usage.native_permutation %} + // {{ template_constants.quotient_vm.op.native_permutation|hex() }} native_permutation + {%- endif %} + {%- if program.op_usage.native_lookup %} + // {{ template_constants.quotient_vm.op.native_lookup|hex() }} native_lookup + {%- endif %} + {%- if program.op_usage.native_identity %} + // {{ template_constants.quotient_vm.op.native_identity|hex() }} native_identity + {%- endif %} + {%- if program.op_usage.lin7 %} + // {{ template_constants.quotient_vm.op.lin7|hex() }} lin7 + {%- endif %} + {%- if program.op_usage.bilin7_row %} + // {{ template_constants.quotient_vm.op.bilin7_row|hex() }} bilin7_row + {%- endif %} + {%- if program.op_usage.bilin7_pairwise %} + // {{ template_constants.quotient_vm.op.bilin7_pairwise|hex() }} bilin7_pairwise + {%- endif %} + {%- if program.op_usage.modarith7 %} + // {{ template_constants.quotient_vm.op.modarith7|hex() }} modarith7 + {%- endif %} + {%- if program.op_usage.pow5 %} + // {{ template_constants.quotient_vm.op.pow5|hex() }} pow5 + {%- endif %} // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -198,7 +283,7 @@ This comment documents the interpreter source without being emitted into generated Solidity. Runtime behavior lives in the switch blocks below; opcode numbers and operand layouts are - defined in src/codegen/quotient/mod.rs. + defined in src/lowering/quotient_numerator/vm/mod.rs. Shared stack model: - q_top caches the top stack value. diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul index 448df6991..1bdc89eb5 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul @@ -289,7 +289,7 @@ // Single-pair MSM output overwrites ACC_LHS_MPTR with // lhs_scalar * decoded_lhs. If lhs_scalar is one, this // is also a curve/subgroup validation round-trip. - out := staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, acc_scratch, {{ template_constants.g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) + out := staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, acc_scratch, {{ template_constants.g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) out := and(out, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) } } @@ -394,8 +394,11 @@ // // The precompile also validates every nonzero fixed // base embedded by codegen and the carried RHS point. + // ACC_RHS_MSM_GAS is the compile-time worst case + // (every tail scalar nonzero); acc_msm_len can only + // select a same-size-or-smaller MSM at runtime. out := staticcall( - gas(), + ACC_RHS_MSM_GAS, {{ template_constants.eip2537.g1msm_address|hex() }}, acc_scratch, acc_msm_len, diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index 5ba918b36..aac0dbc37 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -22,7 +22,7 @@ mstore(add(p, {{ template_constants.modexp.base_offset|hex() }}), x) mstore(add(p, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2)) mstore(add(p, {{ template_constants.modexp.mod_offset|hex() }}), FR_MODULUS) - if iszero(staticcall(gas(), {{ template_constants.modexp.address|hex() }}, p, {{ template_constants.modexp.frame_bytes|hex() }}, p, {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, p, {{ template_constants.modexp.frame_bytes|hex() }}, p, {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } inv := mload(p) } @@ -167,7 +167,7 @@ mstore(add(single_scratch, {{ template_constants.modexp.base_offset|hex() }}), x) mstore(add(single_scratch, {{ template_constants.modexp.exp_offset|hex() }}), sub(r, 2)) mstore(add(single_scratch, {{ template_constants.modexp.mod_offset|hex() }}), r) - ret := staticcall(gas(), {{ template_constants.modexp.address|hex() }}, single_scratch, {{ template_constants.modexp.frame_bytes|hex() }}, single_scratch, {{ template_constants.modexp.output_bytes|hex() }}) + ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, single_scratch, {{ template_constants.modexp.frame_bytes|hex() }}, single_scratch, {{ template_constants.modexp.output_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -217,7 +217,7 @@ mstore(add(gp_mptr, {{ template_constants.modexp.base_offset|hex() }}), gp) mstore(add(gp_mptr, {{ template_constants.modexp.exp_offset|hex() }}), sub(r, 2)) mstore(add(gp_mptr, {{ template_constants.modexp.mod_offset|hex() }}), r) - ret := staticcall(gas(), {{ template_constants.modexp.address|hex() }}, gp_mptr, {{ template_constants.modexp.frame_bytes|hex() }}, gp_mptr, {{ template_constants.modexp.output_bytes|hex() }}) + ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, gp_mptr, {{ template_constants.modexp.frame_bytes|hex() }}, gp_mptr, {{ template_constants.modexp.output_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -266,7 +266,7 @@ mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }}) + ret := staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index 48b95afe2..bddf29aef 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -120,10 +120,13 @@ uint256 internal constant Q_EVAL_CPTR_MPTR = {{ memory.q_eval_cptr_mptr }}; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = {{ memory.g1_identity_mptr }}; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -165,6 +168,35 @@ uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = {{ memory.trashcan_comms_mptr_base }}; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = {{ memory.quotient_limb_comms_mptr_base }}; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = {{ template_constants.gas.g1add }}; + uint256 internal constant G1MSM_GAS_1PAIR = {{ template_constants.gas.g1msm_one_pair }}; + uint256 internal constant PAIRING_GAS_2PAIR = {{ template_constants.gas.pairing_two_pair }}; + uint256 internal constant MODEXP_GAS = {{ template_constants.gas.modexp }}; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = {{ constructor_g1msm_smoke_gas }}; + {%- if self.expected_has_accumulator %} + // Worst-case accumulator RHS MSM: carried RHS point plus every generated + // fixed-base tail scalar nonzero. Zero tail scalars are omitted at + // runtime, which only lowers the actual cost below this bound. + uint256 internal constant ACC_RHS_MSM_GAS = {{ acc_rhs_msm_gas }}; + {%- endif %} + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; diff --git a/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul b/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul index 2d27318c9..758fc0d3a 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul @@ -33,12 +33,12 @@ mcopy(batch_ptr, ACC_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) mstore(add(batch_ptr, {{ template_constants.g1_bytes|hex() }}), acc_pair_alpha) if success { - success := staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, batch_ptr, {{ template_constants.g1_msm_pair_bytes|hex() }}, batch_ptr, {{ template_constants.g1_bytes|hex() }}) + success := staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, batch_ptr, {{ template_constants.g1_msm_pair_bytes|hex() }}, batch_ptr, {{ template_constants.g1_bytes|hex() }}) success := and(success, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) } mcopy(add(batch_ptr, {{ template_constants.g1_bytes|hex() }}), PAIRING_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) if success { - success := staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}, batch_ptr, {{ template_constants.g1add_input_bytes|hex() }}, PAIRING_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) + success := staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}, batch_ptr, {{ template_constants.g1add_input_bytes|hex() }}, PAIRING_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) success := and(success, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) } @@ -47,12 +47,12 @@ mcopy(batch_ptr, ACC_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) mstore(add(batch_ptr, {{ template_constants.g1_bytes|hex() }}), acc_pair_alpha) if success { - success := staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, batch_ptr, {{ template_constants.g1_msm_pair_bytes|hex() }}, batch_ptr, {{ template_constants.g1_bytes|hex() }}) + success := staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, batch_ptr, {{ template_constants.g1_msm_pair_bytes|hex() }}, batch_ptr, {{ template_constants.g1_bytes|hex() }}) success := and(success, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) } mcopy(add(batch_ptr, {{ template_constants.g1_bytes|hex() }}), PAIRING_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) if success { - success := staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}, batch_ptr, {{ template_constants.g1add_input_bytes|hex() }}, PAIRING_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) + success := staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}, batch_ptr, {{ template_constants.g1add_input_bytes|hex() }}, PAIRING_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) success := and(success, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) } } diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index 382004c96..fae7c3de8 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -1,5 +1,9 @@ /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Same free-memory-pointer guard as verifyProof. This body runs in @@ -26,7 +30,7 @@ // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}, scratch, {{ template_constants.g1add_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}, scratch, {{ template_constants.g1add_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -47,7 +51,7 @@ mstore(add(scratch, 0x40), {{ template_constants.eip2537.g1_generator.2|hex_padded(64) }}) mstore(add(scratch, 0x60), {{ template_constants.eip2537.g1_generator.3|hex_padded(64) }}) mcopy(add(scratch, {{ template_constants.g1_bytes|hex() }}), scratch, {{ template_constants.g1_bytes|hex() }}) - if iszero(staticcall(gas(), {{ template_constants.eip2537.g1add_address|hex() }}, scratch, {{ template_constants.g1add_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, {{ template_constants.eip2537.g1add_address|hex() }}, scratch, {{ template_constants.g1add_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(and( and( @@ -81,7 +85,7 @@ mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mstore(add(scratch, 0x80), 2) - if iszero(staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, scratch, 0xa0, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(and( and( @@ -133,14 +137,14 @@ mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) // (c) e(G, G2) * e(-G, G2) == 1. - if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) - if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, add(scratch, 0x300), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } @@ -159,7 +163,7 @@ } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), {{ template_constants.eip2537.g1msm_address|hex() }}, msm_scratch, {{ constructor_g1msm_smoke_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, {{ template_constants.eip2537.g1msm_address|hex() }}, msm_scratch, {{ constructor_g1msm_smoke_input_bytes|hex() }}, scratch, {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -169,7 +173,7 @@ // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } diff --git a/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul b/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul index a8d59eb26..f1242859c 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul @@ -27,6 +27,11 @@ {%- if self.trace %} if iszero(call(gas(), quotientEvaluator, 0, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { revert(0, 0) } {%- else %} + // gas() forwarding is deliberate here, unlike the precompile + // call sites: this is a regular contract call, so a reverting + // or failing callee refunds its unused gas -- only precompile + // ERRORS burn everything forwarded (EIP-2537). The callee is + // also pinned by codehash above, not attacker-supplied. if iszero(staticcall(gas(), quotientEvaluator, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { revert(0, 0) } {%- endif %} if iszero(eq(returndatasize(), {{ qext.output_len|hex() }})) { revert(0, 0) } From 5246b2187a8d61e3d33f0a608374b8a97ef84982 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 08:37:55 +0100 Subject: [PATCH 092/108] docs+scripts(solidity-verifier): reproducibility, SRS provenance, audit-trail truth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the documentation and reproducibility findings of the 2026-08 review (M-5, I-1..I-4, TA triage; tracker updated in FIXES_APPLIED_2026-08.md): - install_pinned_solc.sh: real official SHA-256 pins for solc 0.8.30+commit.73712a01 (linux-amd64, macosx-amd64), verified by a live download; fixed a latent bash-3.2 incompatibility (declare -A) that broke the script on stock macOS; Rosetta mapping documented. - New scripts/record_srs_provenance.sh + REPRODUCIBLE_BUILDS.md "SRS Provenance": asset hashes recorded and verified byte-identical against the Midnight trusted-setup ceremony's official MIDNIGHT_SRS_CATALOG.md (github.com/midnightntwrk/midnight-trusted-setup) — the non-code half of H-1. Ceremony citation flagged for deployment-owner confirmation. - New scripts/generate_artifact_manifest.sh produces the REVIEW_PACKET §4 manifest rows per fixture dump; --optimize-runs added to every recorded flag list with the runs=100000-undeployable warning; the three provenance stamps labeled by what they index (canonical table in REPRODUCIBLE_BUILDS.md "Provenance Identities"). - src/codegen/* path sweep: living reviewer docs rewritten to the current src/lowering tree; AUDIT.md / AUDIT_FINDINGS.md carry a path-migration map instead of rewritten history; AUDIT_FINDINGS #4 now cites validators and tests that actually exist. - TA-1..TA-8 triaged with Status lines (TA-1 fixed — the quoted scalar-0 skip no longer exists; TA-5/TA-6 fixed by 460a666; TA-7's fail-closed zero-denominator semantics now specified in the spec). - Spec/mapping docs updated for the exact gas bounds; the spec's supported-target section now states the schedule requirement and the deploy-time fail-fast on repriced chains. Co-Authored-By: Claude Fable 5 --- proofs/solidity-verifier/docs/audit/AUDIT.md | 73 ++++++++++++ .../docs/audit/AUDIT_FINDINGS.md | 9 +- .../docs/audit/CODEGEN_ASSURANCE_DOSSIER.md | 16 +-- .../docs/audit/FIXES_APPLIED_2026-08.md | 104 +++++++++++++++++ .../audit/HALO2_VERIFIER_REVIEW_2026-08.md | 15 ++- .../docs/audit/REVIEW_PACKET.md | 10 +- .../docs/benchmarks/BENCH.md | 21 ++-- .../docs/benchmarks/OPTIMISATION.md | 4 +- .../PCS_BLOCK5_FINAL_MSM_ANALYSIS.md | 2 +- .../docs/plans/REDESIGN_PROPOSALS_2026-08.md | 6 +- .../docs/plans/SPLIT_NWAY_NOTES.md | 4 +- .../docs/plans/TESTING_STRATEGY.md | 2 +- .../docs/plans/spec-migration.md | 8 +- .../reference/ASKAMA_TEMPLATE_RUST_MAPPING.md | 2 +- .../reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md | 43 +++++-- .../docs/reference/REPRODUCIBLE_BUILDS.md | 64 ++++++++++- .../fixtures/moonlight-wrap/README.md | 2 +- .../scripts/generate_artifact_manifest.sh | 107 ++++++++++++++++++ .../scripts/install_pinned_solc.sh | 25 ++-- .../scripts/record_srs_provenance.sh | 65 +++++++++++ 20 files changed, 525 insertions(+), 57 deletions(-) create mode 100755 proofs/solidity-verifier/scripts/generate_artifact_manifest.sh create mode 100755 proofs/solidity-verifier/scripts/record_srs_provenance.sh diff --git a/proofs/solidity-verifier/docs/audit/AUDIT.md b/proofs/solidity-verifier/docs/audit/AUDIT.md index 67a2c5ee9..eaa3e77da 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT.md @@ -1,5 +1,27 @@ # CTF Vulnerability Analysis: Halo2 Solidity Verifier +> **Path-migration note (2026-08-12).** The findings below were written +> against the pre-rename source tree. `src/codegen/` no longer exists; it was +> refactored into `src/lowering/`. The historical citations (including old +> line numbers) are preserved verbatim as the audit record; to re-verify a +> finding against the current tree, translate paths with this map: +> +> | Historical path | Current location | +> | --- | --- | +> | `src/codegen.rs`, `src/codegen/mod.rs` | `src/lowering/mod.rs` (pipeline root), `src/lowering/plan.rs` (planning), `src/lowering/artifacts.rs` (artifact assembly) | +> | `src/codegen/generator.rs` | `src/lowering/plan.rs` + `src/lowering/artifacts.rs` + `src/lowering/render/` | +> | `src/codegen/template.rs` | `src/lowering/render/models.rs` | +> | `src/codegen/protocol.rs` | `src/lowering/protocol/mod.rs` | +> | `src/codegen/proof_layout.rs` | `src/lowering/abi/proof.rs` | +> | `src/codegen/evaluator.rs` | `src/lowering/quotient_numerator/{mod,yul_emit,vm/mod}.rs` | +> | `src/codegen/quotient/mod.rs` | `src/lowering/quotient.rs` + `src/lowering/quotient_numerator/vm/mod.rs` | +> | `src/codegen/pcs.rs` | `src/lowering/kzg/mod.rs` | +> | `src/codegen/util.rs` | `src/lowering/encoding/mod.rs` + `src/lowering/layout/mod.rs` | +> | `src/transcript.rs` | `templates/partials/verifier/TranscriptProofParser.yul` + `src/lowering/abi/` | +> +> `templates/contracts/Halo2Verifier.sol` still exists but is now assembled +> from the partials in `templates/partials/verifier/`. + ## 2026-05-02 audit addendum: PCS scratch layout and instance-column shape Scope: current dirty worktree for the Halo2/Midnight Solidity verifier @@ -2154,6 +2176,13 @@ arithmetic assumes valid curve points. ### TA-1. Accumulator Points With Scalar Zero Bypass Curve/Subgroup Validation Severity: Medium/High, depending on circuit assumptions. +Status: Fixed. The quoted `switch lhs_scalar` construct no longer exists; +`templates/partials/verifier/AccumulatorHelpers.yul:277-293` (and the RHS +mirror at `:339-347`) unconditionally routes every decoded accumulator point +through EIP-2537 G1MSM — including identity encodings and zero/one scalars — +with an explicit comment stating that the precompile is the curve/subgroup +validator and that skipping it would let a malformed point hide behind +scalar 0. Triaged 2026-08-12. In `load_acc_point`, accumulator coordinates are decoded from public instances into `ACC_LHS_MPTR` and `ACC_RHS_MPTR`. The decoded point is range/canonical @@ -2229,6 +2258,13 @@ Recommendation: ### TA-2. Transcript Must Be Proven To Bind Every Verifier-Side Fixed Input Severity: Medium. +Status: Open. `vk_digest` covers the native VK contents but not the SRS +points, quotient VM program, accumulator schema constants, or feature +profile; widening its coverage is a protocol change affecting the prover and +is tracked as review item M-4 (out of scope for the 2026-08 fix set — +explicitly deferred). Partially mitigated at build time by the SRS tau +binding in `src/lowering/vk.rs` and on-chain by the VK codehash pin plus the +generated-constant cross-checks after `extcodecopy`. Triaged 2026-08-12. The verifier absorbs `vk_digest` rather than the full VK payload: @@ -2277,6 +2313,12 @@ Recommendation: ### TA-3. External Quotient Evaluator Is Pinned, But Not Transcript-Bound Severity: Low/Medium. +Status: Open. Inert for single-contract renders (e.g. the moonlight-wrap +fixture, which ships no `Halo2QuotientEvaluator.sol`), but LIVE for split +renders: the IVC fixture (`target/ivc-keccak-solidity-dump/`) ships a +`Halo2QuotientEvaluator.sol` and relies on the codehash pin alone. Folding +the evaluator identity into the transcript is part of the same digest +discussion as TA-2/M-4. Triaged 2026-08-12. `AUTHORIZED_QUOTIENT` is codehash-pinned, which is good. However, its output directly determines: @@ -2300,6 +2342,13 @@ Recommendation: ### TA-4. Gas Checkpoint Logs Make This Unsuitable As A Production Verifier Severity: Low/Medium. +Status: Resolved / diagnostic-only. Gas checkpoints are emitted only when +the `solidity-gas-checkpoints` feature sets +`SOLIDITY_GAS_CHECKPOINTS_ENABLED`; the feature is off by default and the +`production_renders_do_not_emit_gas_checkpoints` test asserts production +renders contain no LOG1 and stay `external view`. Bench profiles that enable +it are documented as non-production in REPRODUCIBLE_BUILDS.md. Triaged +2026-08-12. `verifyProof` can include gas checkpoint logging: @@ -2337,6 +2386,12 @@ Recommendation: ### TA-5. Dangerous Reliance On `assembly ("memory-safe")` With Absolute Memory Ownership Severity: Low/Medium. +Status: Fixed by P2 (commit `460a666`): the false `"memory-safe"` annotation +was removed from the main verifier block and a free-memory-pointer guard +(`if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }`, +`templates/contracts/Halo2Verifier.sol:117`) now enforces the layout +assumption at runtime instead of asserting it to the optimizer. Triaged +2026-08-12. The main assembly block is marked `"memory-safe"` while it intentionally owns the entire call-frame memory, writes to low memory, uses fixed absolute @@ -2389,6 +2444,12 @@ Recommendation: ### TA-6. Precompile Smoke Tests Are Too Weak For Deployment Confidence Severity: Low. +Status: Fixed by P5 (commit `460a666`): the constructor probes now include +known-answer vectors a stub cannot satisfy — G1ADD(G, G) == 2G, G1MSM +[2]*G == 2G, a NEGATIVE G1MSM probe with an on-curve but out-of-subgroup +point that must be rejected, and pairing probes with both a true and a false +product (`templates/partials/verifier/PrecompileSmoke.sol`). Triaged +2026-08-12. The constructor checks identity inputs for G1ADD, G1MSM, and pairing. That catches absent precompiles and gross return-size issues, but it does not catch: @@ -2411,6 +2472,12 @@ Recommendation: ### TA-7. Root-Of-Unity / Zero-Denominator Cases Revert Rather Than Being Specified Severity: Informational/Low. +Status: Open (documentation). Behavior is fail-closed by construction — +`batch_invert` and `scalar_inv` return failure/revert on any denominator +congruent to zero, and `verifier_rejects_when_x_is_forced_to_domain_root` +covers the x-at-domain-root case — but the spec does not yet state this as +the intended semantics. Needs a paragraph in +`docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md`. Triaged 2026-08-12. The Lagrange and PCS blocks intentionally batch-invert values like: @@ -2440,6 +2507,12 @@ Recommendation: ### TA-8. Raw Verifier Integration Can Still Be Replayed/Misused By Application Contracts Severity: Integration risk. +Status: Acknowledged / integration guidance. The raw verifier is stateless +by design and cannot bind proof meaning itself; the NatSpec on `verifyProof` +and the wrapper guidance in the testing strategy place replay/domain binding +(nullifiers, chain/contract domain, program ID) on the application contract. +Any deployment review must check the wrapper, not just this verifier. +Triaged 2026-08-12. The verifier correctly says application contracts must bind the meaning of public instances separately. That warning is important. This raw verifier diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index 0986048bf..2c6ea31b6 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1,5 +1,12 @@ # Solidity Verifier Codegen Audit +> **Path-migration note (2026-08-12).** These findings were written against +> the pre-rename source tree; `src/codegen/` has since been refactored into +> `src/lowering/`. Historical `**File:**` citations (including line numbers) +> are preserved as the audit record; translate with the migration map at the +> top of `AUDIT.md` when re-verifying. The release-facing status table below +> has been updated to cite current code and test names. + **Repository:** `halo2-solidity-verifier-exp` **Scope:** halo2 → midnight-proofs port of the on-chain KZG/BLS12-381 verifier codegen and emitted Yul. @@ -47,7 +54,7 @@ the release-facing status snapshot as of 2026-05-11. | 2026-05-11 #1 lookup quotient identity count | Fixed | `lookup_chunks.iter().map(|chunks| chunks + 2).sum()` is used in planning and validation; `lookup_identity_source_handles_variable_chunk_counts` covers variable chunk counts. | | 2026-05-11 #2 fixed eval count | Fixed | `proof_evaluation_counts().fixed` counts `EvalRead::Fixed` entries from the protocol plan instead of fixed columns. | | 2026-05-11 #3 challenge phase remapping | Fixed | `ProtocolPlan::from_constraint_system` sizes phases by the max of advice and challenge phases; `plan_allows_challenge_phase_beyond_advice_phases` covers this case. | -| 2026-05-11 #4 packed32 operand widths | Fixed | `validate_packed_quotient_operand` enforces logical `u8` and `u16` bounds; `packed32_validator_rejects_logical_operand_width_corruption` covers corrupted packed operands. | +| 2026-05-11 #4 packed32 operand widths | Fixed | Operand decoding and width bounds are enforced by `validate_quotient_program` / `validate_quotient_const_slots` / `validate_quotient_mem_ptrs` in `src/lowering/quotient_numerator/vm/mod.rs`; `quotient_vm_safety_validator_rejects_malformed_programs` covers stack underflow, unknown memory tokens, and truncated operands, and `quotient_vm_lengths_are_derived_from_opcode_spec` pins operand widths to the opcode spec. (The names previously cited here — `validate_packed_quotient_operand` and `packed32_validator_rejects_logical_operand_width_corruption` — never landed under those identifiers; corrected 2026-08-12.) | | 2026-05-11 #5 reserved memory writes | Fixed | Trace and helper templates avoid Solidity-reserved memory writes; `templates_do_not_write_solidity_reserved_memory_slots` checks `mstore(0,`, `mstore(0x00,`, and related reserved forms. | | 2026-05-11 #6 external quotient return overlap | Fixed | External quotient output uses `QUOTIENT_RETURN_MPTR`; template validation checks output length and disjointness from the copied quotient frame. | | 2026-05-11 #7 structured selector-run trace | Fixed | Selector-run grouping is disabled when trace is enabled, preserving per-identity trace events through direct quotient blocks. | diff --git a/proofs/solidity-verifier/docs/audit/CODEGEN_ASSURANCE_DOSSIER.md b/proofs/solidity-verifier/docs/audit/CODEGEN_ASSURANCE_DOSSIER.md index 5669216d2..cecd4f2ab 100644 --- a/proofs/solidity-verifier/docs/audit/CODEGEN_ASSURANCE_DOSSIER.md +++ b/proofs/solidity-verifier/docs/audit/CODEGEN_ASSURANCE_DOSSIER.md @@ -37,7 +37,9 @@ manifest: | Rust toolchain | `rust-toolchain.toml` | | Cargo features | Exact feature list used to generate the verifier | | Solidity compiler | `solc 0.8.30+commit.73712a01` | -| Solc flags | `--bin --optimize --via-ir --evm-version cancun --no-cbor-metadata` | +| Solc flags | `--bin --optimize --optimize-runs --via-ir --evm-version cancun --no-cbor-metadata` — `` is bytecode- and deployability-affecting (0.8.30 at `runs=100000` exceeds EIP-170) and MUST be recorded per artifact; default `200` (`SOLC_OPTIMIZE_RUNS`), IVC bench uses `1` | +| Solc binary | SHA-256-pinned by `scripts/install_pinned_solc.sh`; hashes recorded in `docs/reference/REPRODUCIBLE_BUILDS.md` | +| SRS provenance | SHA-256 of the SRS asset(s) plus ceremony reference; produced by `scripts/record_srs_provenance.sh`, recorded in `docs/reference/REPRODUCIBLE_BUILDS.md` | | Generated sources | Hashes of verifier, VK, and optional quotient evaluator sources | | Runtime bytecode | Runtime length and `keccak256` for each deployed artifact | | VK binding | VK digest plus external VK runtime length/codehash when split | @@ -56,12 +58,12 @@ line-for-line translation. | Checkpoint | Rust source of truth | Solidity/codegen owner | Evidence expected | | --- | --- | --- | --- | -| Parser and proof reads | `plonk/verifier.rs::{parse_trace,verify_algebraic_constraints}` | `src/codegen/protocol.rs`, `src/codegen/proof_layout.rs`, `templates/contracts/Halo2Verifier.sol` | Exact proof length, ABI head checks, per-section offsets, canonical scalar and G1 checks | -| Transcript challenges | `transcript/mod.rs`, `transcript/implementors.rs` | `src/transcript.rs`, `templates/contracts/Halo2Verifier.sol` | Rust/Solidity trace equality for VK, instances, commitments, and all challenges | -| Quotient identities | `plonk/mod.rs::partially_evaluate_identities` | `src/codegen/evaluator.rs`, `src/codegen/quotient/mod.rs`, `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul` | Identity order manifest, quotient trace ids, VM validator, selector-fold trace coverage | -| Linearization | `plonk/linearization/verifier.rs::compute_linearization_commitment` | `src/codegen/generator.rs`, `src/codegen/pcs.rs` | Same `-nu_y(x)` scalar, selector buckets, quotient limb scalars, and commitment expansion | -| KZG multi-open | `poly/kzg/mod.rs::multi_prepare` | `src/codegen/pcs.rs` | Same dummy queries, point-set sort, `x1..x4`, `f_com`, `q_evals`, `pi`, final MSM | -| Final pairing | `poly/kzg/msm.rs::DualMSM::check` | `templates/contracts/Halo2Verifier.sol`, `src/codegen/pcs.rs` | Pairing precompile success, return size, and semantic result word checked | +| Parser and proof reads | `plonk/verifier.rs::{parse_trace,verify_algebraic_constraints}` | `src/lowering/protocol/mod.rs`, `src/lowering/abi/proof.rs`, `templates/contracts/Halo2Verifier.sol` | Exact proof length, ABI head checks, per-section offsets, canonical scalar and G1 checks | +| Transcript challenges | `transcript/mod.rs`, `transcript/implementors.rs` | `templates/partials/verifier/TranscriptProofParser.yul`, `src/lowering/abi/` (offsets), `templates/contracts/Halo2Verifier.sol` | Rust/Solidity trace equality for VK, instances, commitments, and all challenges | +| Quotient identities | `plonk/mod.rs::partially_evaluate_identities` | `src/lowering/quotient_numerator/` (planning, Yul emitter, VM), `src/lowering/quotient.rs`, `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul` | Identity order manifest, quotient trace ids, VM validator, selector-fold trace coverage | +| Linearization | `plonk/linearization/verifier.rs::compute_linearization_commitment` | `src/lowering/quotient.rs`, `src/lowering/kzg/mod.rs` | Same `-nu_y(x)` scalar, selector buckets, quotient limb scalars, and commitment expansion | +| KZG multi-open | `poly/kzg/mod.rs::multi_prepare` | `src/lowering/kzg/mod.rs` | Same dummy queries, point-set sort, `x1..x4`, `f_com`, `q_evals`, `pi`, final MSM | +| Final pairing | `poly/kzg/msm.rs::DualMSM::check` | `templates/contracts/Halo2Verifier.sol`, `src/lowering/kzg/mod.rs` | Pairing precompile success, return size, and semantic result word checked | | Optional accumulator | Wrapper logic outside `plonk/verifier.rs` | `AccumulatorEncoding`, VK header, `templates/contracts/Halo2Verifier.sol` | Public-input schema validation and batched accumulator/KZG pairing equation | The bridge between Solidity calldata and Rust verifier objects is: diff --git a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md index 577c670dd..7198bfe45 100644 --- a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md +++ b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md @@ -2,6 +2,110 @@ Companion to `HALO2_VERIFIER_REVIEW.md`. This file records exactly what was changed, what was verified, and — importantly — **what the review found that these changes do not fix.** +## 2026-08-12 follow-up: generator-side closures + +A second pass (with the workspace compilable) closed most of what the first +pass could only specify. Newly applied and validated: + +- **P1 / M-2 — exact precompile gas bounds.** Gas model in + `src/lowering/layout/mod.rs::gas` (EIP-2537 discount table + pairing + formula, EIP-2565 modexp), threaded through `GasTemplateConstants` and + emitted as `G1ADD_GAS` / `G1MSM_GAS_1PAIR` / `G1MSM_GAS_SMOKE` / + `PAIRING_GAS_2PAIR` / `MODEXP_GAS` / `ACC_RHS_MSM_GAS` constants. Every + precompile call site — templates, PCS emitter, and constructor probes — + now forwards the exact scheduled cost instead of `gas()`; the two + `quotientEvaluator` calls keep `gas()` deliberately (regular-call refund + semantics, codehash-pinned callee) with a comment. Decision on cap style: + exact schedule, no margin, per EIP-2537's DDoS-protection guarantee; + liveness caveat (upward repricing ⇒ regenerate + redeploy) documented at + the constants and in the spec §15. This deliberately reverses commit + `2b2bf49` ("Forward gas to EIP-2537 precompiles", old finding M-04): those + were hand-tuned literals, these are generated spec formulas, and the + constructor probes now fail-fast on repriced chains, which is what M-04 + actually needed. Verified: `eip2537_gas_schedule_matches_spec_vectors`, + `eip2537_calls_forward_exact_schedule_gas`, and the revm test + `malformed_proof_point_rejects_with_bounded_gas` — a malformed point now + costs no more than an honest verification (was 29.5M of a 30M limit). +- **P11 / H-1 (code half) — applied and repaired.** The patch as shipped + could not compile: it shadowed the `omega: U256` binding with an `Fq` and + referenced an undefined `srs_tau_is_consistent`. Landed in + `src/lowering/vk.rs` with the helper implemented as a Pippenger-MSM + Lagrange commitment of f(X)=X plus the pairing check + `e([τ]G1, G2) == e(G1, s_g2)`. Verified: + `srs_tau_binding_accepts_honest_params_and_rejects_foreign_s_g2` (honest + SRS passes; s=1, s'=2s, and wrong-domain omega all fail). +- **H-1 (non-code half) — SRS provenance recorded.** Ceremony citation + (github.com/midnightntwrk/midnight-trusted-setup), asset SHA-256s hashed + by the new `scripts/record_srs_provenance.sh` and verified byte-identical + against the ceremony's official `MIDNIGHT_SRS_CATALOG.md`; the gated test + `midnight_srs_assets_bind_s_g2_to_lagrange_tau` pairing-checks the real + 2p19/2p20 assets. All recorded in `REPRODUCIBLE_BUILDS.md` §"SRS + Provenance". +- **P7 / L-2 — q_eval_set comments.** Emitter now reports + "{m} evaluation term(s), {n} commitment term(s)" (identity commitments + excluded from n), so the comment matches the MSM pair count below it. The + structural asserts (`pair_idx == non_identity_terms` / + `== final_msm_terms`) plus a new whole-pairs assert guard the counts. +- **P13 / M-5 — solc hashes filled and script fixed.** Official sha256 for + linux-amd64 and macosx-amd64 recorded (see `REPRODUCIBLE_BUILDS.md`); + found and fixed a latent portability bug (`declare -A` fails on stock + macOS bash 3.2); end-to-end verified by a real download+hash+version run. + Rosetta mapping for Darwin-arm64 now documented in the script. +- **M-5 (remainder) — manifest + flags + provenance stamps.** New + `scripts/generate_artifact_manifest.sh` produces the §4 manifest rows per + fixture dump; `--optimize-runs` added to every recorded flag list + (REVIEW_PACKET, dossier, REPRODUCIBLE_BUILDS) with the + `runs=100000`-undeployable warning; the three provenance stamps were not + contradictory but unlabeled — each is now labeled, with the canonical + table in `REPRODUCIBLE_BUILDS.md` §"Provenance Identities". Still open + from the original M-5 list: removing the `SOLC_OPTIMIZE_RUNS` env + override from the reproducible path (kept, as the bench profiles rely on + it; the manifest records the effective value instead). +- **I-4 — stale `src/codegen/*` anchors.** All 58 references across 13 + files fixed or covered: living reviewer docs (dossier §2 semantic map, + plans, benchmarks, template comment) rewritten to the current + `src/lowering/*` tree; the historical audit records (`AUDIT.md`, + `AUDIT_FINDINGS.md`) carry a path-migration map at the top instead of + rewritten history. `AUDIT_FINDINGS.md` 2026-05-11 #4's evidence cell now + cites validators/tests that actually exist + (`validate_quotient_program` / `quotient_vm_safety_validator_rejects_malformed_programs`); + the previously cited names never landed. One review-side correction: I-4 + overreached on `QuotientNumeratorBlock.yul`, which does exist. +- **TA-1…TA-8 triaged.** Every TA item in `AUDIT.md` now carries a + `Status:` line (TA-1 Fixed — the quoted scalar-0 skip no longer exists; + TA-4 resolved/diagnostic-only; TA-5/TA-6 fixed by `460a666`; TA-2/TA-3 + open, cross-referenced to the deferred M-4 digest decision; TA-7 + fail-closed semantics now specified in the spec §12.7; TA-8 integration + guidance). +- **I-2 (partial).** The generated opcode-summary comment is now rendered + from the same `program.op_usage` predicates that gate the interpreter's + case arms, so each artifact documents exactly its own opcodes; the + `G1_IDENTITY_MPTR` comment no longer references nonexistent `mload`s. + +**New finding discovered and fixed during this pass — feature-unification +challenge-truncation mismatch.** The `midnight-aggregation` dependency in +`Cargo.toml` unconditionally enabled `truncated-challenges`, which Cargo +feature unification forced onto `midnight-proofs` in EVERY build of this +crate. Consequence: the prover always truncated challenges, but a verifier +generated with `--features evm` (without this crate's own +`truncated-challenges` feature) did not mirror it — exactly the "wrong +setting on either side silently produces invalid pairings" hazard the +feature's own doc comment warns about. Every `evm`-only fixture test +(`rsa_signature`, `sha_preimage`, `hybrid_mt`) had been failing with valid +proofs reverting mid-PCS; bisect showed the breakage entered with the +workspace merge that introduced the aggregation dependency, long before the +2026-08 review. Fixed by removing the dependency-level feature so truncation +flows only through this crate's `truncated-challenges` feature; both +`--features evm` and `--features evm,truncated-challenges` now agree +end-to-end and all fixture tests pass in both modes. The committed +`target/*-dump` artifacts are canonically rendered with +`evm,truncated-challenges` (they contain the truncation code paths). + +Deliberately not addressed, by explicit decision: **M-4** (`vk_digest` +coverage — protocol change affecting the prover) and anything outside +`proofs/solidity-verifier/`. Remaining open from the tables below: P4, P8, +P9, P10, P12, P14, L-4, L-9, L-10, I-6, I-7. + ## Short answer: no, this does not address all the findings Of the 23 findings, **4 are closed or substantially closed by the changes below.** The rest fall into three groups: diff --git a/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md index b15de510e..0ea5cfca8 100644 --- a/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md +++ b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md @@ -505,7 +505,15 @@ Three mutually unreconcilable provenance stamps exist for this artefact: | --- | --- | | `fixtures/moonlight-wrap/README.md:17` | solidity-verifier commit `3fb6d84` | | `REVIEW_PACKET.md:67` | repository commit `a096e71746e401404f250817ca4e857bac1eef56` | -| `CODEGEN_ASSURANCE_DOSSIER.md:37` | Midfall revision `53dc872f495104046d96bdac0a690f903dc0c537` | +| `CODEGEN_ASSURANCE_DOSSIER.md:36` | Midfall revision `53dc872f495104046d96bdac0a690f903dc0c537` | + +> Correction (2026-08-12): the three stamps are not actually contradictory — +> they index different things (fixture-render commit of this repo, packet-time +> commit of this repo, and the Midfall *dependency* revision). They were +> merely unlabeled. Each source now says which identity it records; the +> canonical table is "Provenance Identities" in +> `docs/reference/REPRODUCIBLE_BUILDS.md`. (This row's dossier citation was +> also off by one — `:37` → `:36`.) `REVIEW_PACKET.md` §4 "Artifact Manifest" — the table meant to pin *this* artefact — reads `fill per artifact` for all eleven hash rows. `docs/reference/REPRODUCIBLE_BUILDS.md`, cited from three places as where the hashes live, was not in scope. @@ -681,7 +689,10 @@ The upstream docstring itself warns that "128 bits may not be enough entropy dep **I-3 — Unreachable defensive branch.** `load_acc_point` lines 830–839 handle "x carried the identity flag but the whole-point sentinel did not match". Given the packing check makes the codec a bijection, `x_is_id` implies x's words are exactly the canonical identity words, and requiring `y` to decode to zero implies y's words are too — so `is_acc_encoded_identity` would already have returned true. Harmless defensive dead code; worth a comment saying so rather than leaving a reader to derive it. -**I-4 — The audit chain's evidence map points at a source tree that no longer exists.** `CODEGEN_ASSURANCE_DOSSIER.md:57-65` maps every checkpoint to `src/codegen/protocol.rs`, `src/codegen/evaluator.rs`, `src/codegen/pcs.rs`, `src/transcript.rs` and `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul`. **None exist.** The tree is `src/lowering/*` and the template is `QuotientHelpers.yul`. `AUDIT_FINDINGS.md`'s "Files reviewed (deep read)" list is entirely `src/codegen/*`; finding M1 anchors at `src/codegen/util.rs:443-448`. `ARCHITECTURE_REVIEW_2026-08.md` §11 concedes the drift and defers to a companion assessment that was not in scope. Consequence: the ~20 findings marked "Fixed with named tests" in the 2026-05-11 addendum could not be re-verified against the current tree. +**I-4 — The audit chain's evidence map points at a source tree that no longer exists.** `CODEGEN_ASSURANCE_DOSSIER.md:57-65` maps every checkpoint to `src/codegen/protocol.rs`, `src/codegen/evaluator.rs`, `src/codegen/pcs.rs`, `src/transcript.rs` and `templates/partials/quotient_numerator/QuotientNumeratorBlock.yul`. **None of the Rust paths exist.** The tree is `src/lowering/*`. (Correction +2026-08-12: this finding itself overreached on one item — +`templates/partials/quotient_numerator/QuotientNumeratorBlock.yul` DOES exist, +alongside `QuotientHelpers.yul`; the dossier row citing it was correct.) `AUDIT_FINDINGS.md`'s "Files reviewed (deep read)" list is entirely `src/codegen/*`; finding M1 anchors at `src/codegen/util.rs:443-448`. `ARCHITECTURE_REVIEW_2026-08.md` §11 concedes the drift and defers to a companion assessment that was not in scope. Consequence: the ~20 findings marked "Fixed with named tests" in the 2026-05-11 addendum could not be re-verified against the current tree. **I-5 — No transcript domain separation.** The Keccak transcript is a bare `keccak256` over concatenated raw bytes, matching Rust. This is weaker than the Blake2b transcript in the same file, which uses a personalisation string plus `COMMON`/`CHALLENGE` byte tags. Not exploitable here — every absorb is fixed-length and every count is pinned and re-checked, so no two distinct valid inputs produce the same byte stream, and `vk_digest` provides cross-circuit separation. A missing defence-in-depth layer, not a vulnerability. diff --git a/proofs/solidity-verifier/docs/audit/REVIEW_PACKET.md b/proofs/solidity-verifier/docs/audit/REVIEW_PACKET.md index fb9739587..c72805d98 100644 --- a/proofs/solidity-verifier/docs/audit/REVIEW_PACKET.md +++ b/proofs/solidity-verifier/docs/audit/REVIEW_PACKET.md @@ -64,11 +64,11 @@ Fill this table for the exact artifact under review. Use | Item | Value | | --- | --- | -| Repository commit | `a096e71746e401404f250817ca4e857bac1eef56` | +| Repository commit | `a096e71746e401404f250817ca4e857bac1eef56` (**this repository** at packet creation; the Midfall dependency revision is a separate stamp — see the provenance-identities table in `docs/reference/REPRODUCIBLE_BUILDS.md`) | | Working tree status at packet creation | clean before this packet was added | | Rust toolchain | `rust-toolchain.toml` | -| Solidity compiler | `solc 0.8.30+commit.73712a01` | -| Solidity flags | `--bin --optimize --via-ir --evm-version cancun --no-cbor-metadata` | +| Solidity compiler | `solc 0.8.30+commit.73712a01`, SHA-256-pinned by `scripts/install_pinned_solc.sh` | +| Solidity flags | `--bin --optimize --optimize-runs --via-ir --evm-version cancun --no-cbor-metadata` — record `` per artifact; it changes both bytecode and deployability (0.8.30 at `runs=100000` exceeds EIP-170) | | Cargo features | fill per artifact | | Generated verifier source hash | fill per artifact | | Generated VK source hash | fill per artifact, if split | @@ -80,7 +80,9 @@ Fill this table for the exact artifact under review. Use | Public input fixture hash | fill per artifact | | Calldata hash | fill per artifact | -The currently recorded IVC benchmark manifests live in +Generate the per-artifact rows with `scripts/generate_artifact_manifest.sh +`; it emits this table for each rendered fixture dump under +`target/`. The currently recorded IVC benchmark manifests live in `docs/reference/REPRODUCIBLE_BUILDS.md`. ## 5. Reading Order diff --git a/proofs/solidity-verifier/docs/benchmarks/BENCH.md b/proofs/solidity-verifier/docs/benchmarks/BENCH.md index d8fc67613..6ca7ca867 100644 --- a/proofs/solidity-verifier/docs/benchmarks/BENCH.md +++ b/proofs/solidity-verifier/docs/benchmarks/BENCH.md @@ -407,7 +407,7 @@ let prod_inv := scalar_inv(prod) Saves 13 modexp calls (~13 × 1.4 kg = ~18 kg) at the cost of ~28 muls (~280 gas). Net ~17 kg. -**Files:** `src/codegen/pcs.rs` (the emitter that lays out the +**Files:** `src/lowering/kzg/mod.rs` (the emitter that lays out the 14 `let _ := scalar_inv(_)` lines in the PCS block). Probably a dedicated `batch_scalar_inv` helper in the Yul prelude. @@ -419,12 +419,12 @@ the per-input zero check for defence in depth (revert if any is zero). ### C. Pre-fold `mulmod(_, 1)` / `addmod(_, 0)` in the evaluator codegen **Projection: 5–15 kg saved** -The gate evaluator (`src/codegen/evaluator.rs`) emits `mulmod(x, 1, r)` +The gate evaluator (`src/lowering/quotient_numerator/yul_emit.rs`) emits `mulmod(x, 1, r)` and `addmod(x, 0, r)` whenever a multiplicative or additive identity appears in the constraint. With `runs=1` solc cannot constant-fold these. Add a pass at codegen time that drops them. -**Files:** `src/codegen/evaluator.rs` (the `evaluate` recursion that +**Files:** `src/lowering/quotient_numerator/yul_emit.rs` (the recursion that emits per-expression Yul lines). **Risk:** must distinguish "literally constant `1`" (drop) from @@ -441,9 +441,9 @@ The gate evaluator currently re-mloads `Y_MPTR`, `THETA_MPTR`, 0.75 kg). Cheap to fix at codegen time — emit a `let y := mload(Y_MPTR)` at the top of the quotient block and reference `y` in each step. -**Files:** `src/codegen.rs` (the `make_block` closure that emits each -identity's Horner step), and `src/codegen/evaluator.rs` (the part that -substitutes `Y_MPTR` → local `y`). +**Files:** `src/lowering/quotient_numerator/` (`yul_emit.rs` emits each +identity's Horner step; `vm/mod.rs` is the VM path), including the part that +substitutes `Y_MPTR` → local `y`. **Risk:** none, mechanical. @@ -455,8 +455,8 @@ each repeat a 4-line `mstore(0x180, mload(...))` chain to copy 4-word points. Cancun ships MCOPY (`0x5e`); replace each chain with one `mcopy(dst, src, 0x80)`. -**Files:** `templates/contracts/Halo2Verifier.sol` and the `pcs_computations` -emitter in `src/codegen/pcs.rs`. +**Files:** `templates/contracts/Halo2Verifier.sol` and the `computations` +emitter in `src/lowering/kzg/mod.rs`. **Risk:** none. EVM target is already Cancun. @@ -559,7 +559,8 @@ and bumps the on-chain transcript's domain-separator epoch. Not as cheap as it looks — cross-stack coordination. **Files:** `midfall/proofs/src/transcript/mod.rs`, -`src/transcript.rs`, `templates/contracts/Halo2Verifier.sol`. Probably a +`templates/partials/verifier/TranscriptProofParser.yul` (with offsets from +`src/lowering/abi/`), `templates/contracts/Halo2Verifier.sol`. Probably a follow-up after A is shipped. ## Realistic projection after Step 6 @@ -621,6 +622,6 @@ the floor is dominated by EIP-2537 pricing and the cryptographic work. section (modulo the 750-gas overhead per checkpoint, which is subtracted by `dump_gas_checkpoints`). - For tighter attribution within the 631 kg PCS block, add additional - checkpoints inside `src/codegen/pcs.rs::computations()` at the + checkpoints inside `src/lowering/kzg/mod.rs::computations()` at the per-set boundaries. Currently every set's three sub-stages (point set group, batch invert, MSM) coalesce into the same 631 kg bucket. diff --git a/proofs/solidity-verifier/docs/benchmarks/OPTIMISATION.md b/proofs/solidity-verifier/docs/benchmarks/OPTIMISATION.md index 5f79c6c78..83c2c2eae 100644 --- a/proofs/solidity-verifier/docs/benchmarks/OPTIMISATION.md +++ b/proofs/solidity-verifier/docs/benchmarks/OPTIMISATION.md @@ -262,7 +262,9 @@ Files touched: - `vendor/.../midfall/proofs/src/transcript/implementors.rs` — `Hashable for G1Projective::to_input` returns 128 bytes instead of `::to_bytes` (compressed). -- `src/transcript.rs::common_g1` — absorbs the same 128 bytes; the +- `common_g1` (at the time in `src/transcript.rs`; the transcript helpers now + live in `templates/partials/verifier/TranscriptProofParser.yul` with offsets + in `src/lowering/abi/`) — absorbs the same 128 bytes; the `common_g1_then_squeeze_matches` round-trip test pins this to `CircuitTranscript`'s output. - `templates/contracts/Halo2Verifier.sol::common_uncompressed_g1` — replaced a diff --git a/proofs/solidity-verifier/docs/benchmarks/PCS_BLOCK5_FINAL_MSM_ANALYSIS.md b/proofs/solidity-verifier/docs/benchmarks/PCS_BLOCK5_FINAL_MSM_ANALYSIS.md index 8b1c23b75..8afd16ab2 100644 --- a/proofs/solidity-verifier/docs/benchmarks/PCS_BLOCK5_FINAL_MSM_ANALYSIS.md +++ b/proofs/solidity-verifier/docs/benchmarks/PCS_BLOCK5_FINAL_MSM_ANALYSIS.md @@ -74,7 +74,7 @@ let v = inner_product([q_evals..., f_eval], powers(x4)); The Solidity codegen for this is in: ```text -src/codegen/pcs.rs +src/lowering/kzg/mod.rs ``` around the generated `build final_com and v` block. diff --git a/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md b/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md index 3a0a542a4..d906283d7 100644 --- a/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md +++ b/proofs/solidity-verifier/docs/plans/REDESIGN_PROPOSALS_2026-08.md @@ -239,7 +239,8 @@ structurally duplicates Block 5's final-MSM term enumeration (:1673-1731). **F15 — Audit-chain docs rot** *(Confirmed)*. `CODEGEN_ASSURANCE_DOSSIER.md:59-64`, `AUDIT.md`, and `AUDIT_FINDINGS.md` -cite the vanished `src/codegen/` tree (REVIEW_PACKET.md is current — the +cite the vanished pre-rename `codegen` tree, since renamed to +`src/lowering/` (REVIEW_PACKET.md is current — the audit docs disagree with each other); README carries two stale, self-contradictory test counts (167+4 at line 49, 177 at line 389; actual at snapshot: 202 lib + 9 integration) and a broken `./TESTING_STRATEGY.md` link; @@ -341,7 +342,8 @@ gated on it. Cheap, generation-time only. **P0.4 One documentation-refresh pass with drift guards** *(F6, F15, L6)*. Correct the `REPRODUCIBLE_BUILDS.md` pinning claim and record the workspace commit alongside published hashes (the bench script can emit it into -`contract-sizes.txt`); update `src/codegen` paths in the dossier and audit +`contract-sizes.txt`); update stale pre-rename `codegen` paths (now +`src/lowering/`) in the dossier and audit docs; replace README test counts with the command that produces them; fix broken links; add status markers to ROADMAP; fix the 0x80 NatSpec ⚠; define a re-assessment trigger (any change under `src/lowering` or `templates/` bumps diff --git a/proofs/solidity-verifier/docs/plans/SPLIT_NWAY_NOTES.md b/proofs/solidity-verifier/docs/plans/SPLIT_NWAY_NOTES.md index 1754667bb..ff497eaed 100644 --- a/proofs/solidity-verifier/docs/plans/SPLIT_NWAY_NOTES.md +++ b/proofs/solidity-verifier/docs/plans/SPLIT_NWAY_NOTES.md @@ -103,7 +103,7 @@ within the noise budget of solc's optimizer rearrangements. ## Files touched -- `src/codegen.rs` +- `src/lowering/mod.rs` (at the time the top-level `codegen` module) - `render_with_quotient_helpers()` -> thin wrapper over `render_with_quotient_helpers_n(2)`. - `render_with_quotient_helpers_n(N)` -> new public API. @@ -112,7 +112,7 @@ within the noise budget of solc's optimizer rearrangements. - split quotient helper rendering with per-identity inline-asm spill (replaces `_vS`/`_vL` external calls). - `collect_named_refs()` helper. -- `src/codegen/template.rs` +- `src/lowering/render/models.rs` (at the time the template model module) - `Halo2Verifier.quotient_helpers_n: usize` field. - `src/evm.rs` - `Evm::create_with_address_and_address_array_arg(...)` to deploy diff --git a/proofs/solidity-verifier/docs/plans/TESTING_STRATEGY.md b/proofs/solidity-verifier/docs/plans/TESTING_STRATEGY.md index c5743ebd3..a1d6cddd3 100644 --- a/proofs/solidity-verifier/docs/plans/TESTING_STRATEGY.md +++ b/proofs/solidity-verifier/docs/plans/TESTING_STRATEGY.md @@ -500,7 +500,7 @@ checkpoint. | PCS/KZG/quotient | Mutate every quotient commitment, proof eval, opening proof, batching scalar source, quotient evaluator output, and external quotient return length. Assert the final pairing result is semantically checked, not just precompile call success. | | Accumulator-specific | Check accumulator schema consumes exactly the expected public input words. Test unused high limb bits, malformed identity encoding, x/y limb swaps, scalar mutation, zero/identity accumulator cases, and any future fixed-base tail. | | Precompile/fail behavior | Constructor smoke tests cover MCOPY, the largest generated G1MSM input, and the two-pair EIP-2537 pairing shape; add tests for short return data, false pairing result, reverted precompile call, and stale return memory using generated-template mutations or a helper harness. | -| Memory/layout | Fast generator tests should assert no overlap between VK, challenge, transcript, quotient, PCS, accumulator, and scratch regions. Keep these as compile-time/layout tests in `src/codegen/mod.rs` and `src/codegen/template.rs`. | +| Memory/layout | Fast generator tests should assert no overlap between VK, challenge, transcript, quotient, PCS, accumulator, and scratch regions. Keep these as compile-time/layout tests in `src/lowering/layout/memory.rs` (`VerifierMemoryLayout` overlap validation) and `src/lowering/tests.rs`. | | Production artifact checks | `verifyProof` production renders stay `external view`, no `LOG1`, no gas checkpoints, Solidity pragma `^0.8.24`, Cancun/Prague target, runtime size below EIP-170 with margin. | | Wrapper/application binding | Add small mock wrapper contracts that bind expected state root, program ID, chain/domain, caller/action hash, nullifier/nonce. Same proof with wrong wrapper context must reject. | diff --git a/proofs/solidity-verifier/docs/plans/spec-migration.md b/proofs/solidity-verifier/docs/plans/spec-migration.md index f046988df..c10ea6ab2 100644 --- a/proofs/solidity-verifier/docs/plans/spec-migration.md +++ b/proofs/solidity-verifier/docs/plans/spec-migration.md @@ -29,7 +29,7 @@ I'll deliver the migration in N self-contained steps, committing each so we can - Outcome: `cargo check` red until later steps; we get the type universe pinned. ### Step 2 - Transcript replacement -- Throw away the current `src/transcript.rs` (writes uncompressed EIP-2537 G1, single-keccak squeeze). +- Throw away the current transcript implementation (writes uncompressed EIP-2537 G1, single-keccak squeeze). (The transcript now lives in `templates/partials/verifier/TranscriptProofParser.yul`, with proof offsets computed in `src/lowering/abi/`; there is no standalone Rust transcript module.) - Implement a `Keccak256VerifierTranscript` matching `midnight_proofs::transcript::CircuitTranscript` byte-for-byte: - init: `Keccak256::new().update("Domain separator for transcript")` - common(input): hasher.update([1u8]); hasher.update(input) @@ -39,14 +39,14 @@ I'll deliver the migration in N self-contained steps, committing each so we can - Mirror this in Yul (see Step 5). ### Step 3 - ConstraintSystemMeta rewrite -- `src/codegen/util.rs::ConstraintSystemMeta::new` currently inspects halo2_proofs' lookups; replace its lookup section with midnight-proofs' `cs.lookups()` (BatchedArgument with chunks, helpers, multiplicities). +- `src/lowering/encoding/mod.rs::ConstraintSystemMeta::new` currently inspects halo2_proofs' lookups; replace its lookup section with midnight-proofs' `cs.lookups()` (BatchedArgument with chunks, helpers, multiplicities). - Add a trashcan section: `cs.trashcans()` (Argument with selector + constraint expressions). - Track `num_committed_instances` (keep at 0 for poseidon); track `cs.num_simple_selectors()` (midnight-proofs filters fixed evals on this). - New per-row counts: `lookup_chunks_per_arg[]`, `trashcan_count`, `permutation_chunks` (=cols.div_ceil(degree-2)). - `proof_len` calculation now needs: advices, multiplicities, perm prod commitments, lookup helpers + accumulators, trashcans, quotient limbs, evals (committed-inst evals + advice + fixed-non-simple + perm-common + perm-set + lookup-evals + trash), f_com, q_evals (one per point set), pi. ### Step 4 - Evaluator rewrite (partial-eval) -- `src/codegen/evaluator.rs` currently emits Yul for halo2 lookup constraints. Replace `lookup_computations` with a logup emitter that writes: +- `src/lowering/quotient_numerator/yul_emit.rs` currently emits Yul for halo2 lookup constraints. Replace `lookup_computations` with a logup emitter that writes: - For each lookup (per proof): boundary `(l_0 + l_last)*Z` - Per chunk: `h(x) * prod_j(f_j(x)+beta) - sum_j prod_{k!=j}(f_k(x)+beta)` where each `f_j` is theta-compressed - Accumulator: `(Z_next - Z - selector*sum_h)*(t+beta) + m` times `(1 - l_last - l_blind)` @@ -54,7 +54,7 @@ I'll deliver the migration in N self-contained steps, committing each so we can - Gate emitter unchanged shape, but now reads through midnight-proofs `Expression`. ### Step 5 - PCS emitter rewrite -- Replace `src/codegen/pcs.rs` with a `multi_prepare` emitter: +- Replace `src/lowering/kzg/mod.rs` with a `multi_prepare` emitter: - `construct_intermediate_sets`: bucket queries by point sets (in order: advice rotations, perm cur/next/last, lookup x/x_next, trashcan x, fixed rotations, perm common at x, lin com at x). - `q_coms`: per set, MSM-fold commitments by `x1` powers - `q_eval_sets`: per set, eval_set inner product with `x1` powers diff --git a/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md b/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md index 13ab2052e..c32299bf9 100644 --- a/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md +++ b/proofs/solidity-verifier/docs/reference/ASKAMA_TEMPLATE_RUST_MAPPING.md @@ -398,7 +398,7 @@ comparison against the instrumented Rust verifier. | Fewer point sets / dummy queries | `pcs.rs::compute_dummy_queries` | Can reduce KZG point-set work for selected profiles | Proof layout and transcript must include matching dummy evals | | Truncated PCS challenges | `truncated-challenges` feature | Mirrors Midfall KZG challenge truncation where enabled | Only the specified challenges/powers are truncated | | Accumulator pairing batch | `Halo2Verifier.sol` accumulator section | Combines public accumulator pairing with final KZG pairing | Batch randomizer is derived after all four G1 inputs are fixed | -| EIP-2537 gas forwarding and return-size checks | `TemplateConstants`, `layout::precompile` addresses | Forwards `gas()` to avoid chain-specific gas caps while checking call success and exact return sizes | Deployment smoke tests must pass on the target fork/chain | +| EIP-2537 exact gas bounds and return-size checks | `layout::gas`, `GasTemplateConstants`, `layout::precompile` addresses | Forwards the exact EIP-2537/EIP-2565 scheduled cost so a rejecting precompile burns at most one call's scheduled gas (M-2) while checking call success and exact return sizes | Bounds are the spec schedule, not hand-tuned caps; an upward repricing fork requires regenerating; deployment smoke probes forward the same bounds and fail fast on repriced chains | | Gas checkpoints | `RenderDiagnostics { gas_checkpoints: true, .. }` | Gives stable section-level gas deltas | Not a `view` verifier; profiling only | ## Trace Coverage diff --git a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md index 14d1ef4a8..698b10fd9 100644 --- a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +++ b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md @@ -65,11 +65,14 @@ proofs using: Supported execution target: an Ethereum-compatible Cancun-or-newer EVM with `MCOPY` and Prague/EIP-2537 BLS12-381 precompiles at exactly the addresses -above, implementing the EIP-2537 input encodings, subgroup checks, return sizes, -and enough gas capacity for the generated full-size calls. The repository -CI/dev runner exercises this target through Prague-spec `revm`; deployers on -L2s, forks, or alt-EVMs must run the same precompile conformance tests against -their target chain before treating the verifier as production-safe. +above, implementing the EIP-2537 input encodings, subgroup checks, return +sizes, and the EIP-2537/EIP-2565 gas schedule (the generated call sites +forward exactly the scheduled cost — see section 15). The repository CI/dev +runner exercises this target through Prague-spec `revm`; deployers on L2s, +forks, or alt-EVMs must run the same precompile conformance tests against +their target chain before treating the verifier as production-safe. A chain +that charges MORE than the EIP-2537 schedule fails the constructor smoke +probes at deployment. The generated verifier is not a generic reusable verifier. It is circuit-specialized. Circuit metadata, proof read order, quotient identity @@ -1200,6 +1203,17 @@ eval_s = proof_q_eval[s] * den_inv All inversions are in `Fr`. The implementation batch-inverts the `dx_j` and `lbasis_j` values for each non-singleton set. +**Zero-denominator semantics (intended, not incidental).** Every inversion +path in the generated verifier — `scalar_inv`, `batch_invert`, and the +Lagrange denominators — fails closed on a denominator congruent to zero +mod `r`: the call either reverts or forces `success := 0`, which the next +section boundary turns into a revert. In particular, a transcript challenge +`x` landing on a domain root of unity (probability ~`n/r`, negligible) or +`x3` colliding with a rotation point makes the proof REJECT with a revert +rather than being accepted, retried, or specified around. This mirrors the +native verifier, which would fail the same proofs, and is the specified +behavior (audit item TA-7). + Fold with `x2`: ```text @@ -1567,11 +1581,22 @@ Every EIP-2537 call checks: - Exact return-data size. - For pairing, returned word is 1. -EIP-2537 calls forward `gas()` rather than rendering chain-specific gas caps. +EIP-2537 and modexp calls forward the exact EIP-2537/EIP-2565 scheduled cost +(generated constants `G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, +`MODEXP_GAS`; model in `src/lowering/layout/mod.rs::gas`), NOT `gas()`. A +rejecting precompile consumes everything forwarded to it, so exact bounds cap +what a malformed proof point can burn at the scheduled cost of the single +failing call instead of 63/64 of the transaction budget (M-2). The bounds are +the spec-guaranteed worst case per EIP-2537's DDoS-protection rationale, so +they are sufficient on any conformant chain; a future fork that reprices +these precompiles upward requires regenerating and redeploying the verifier. + The constructor also smoke-tests the largest generated G1MSM input length and -the runtime two-pair KZG pairing input size with identity data, so deployment -fails early when the target chain/fork cannot execute the verifier's -worst-case precompile shapes under the supplied deployment gas. +the runtime two-pair KZG pairing input size with identity data — forwarding +the same exact gas bounds — so deployment fails early when the target +chain/fork cannot execute the verifier's worst-case precompile shapes at the +generated schedule, including chains whose precompile gas schedule was +repriced upward. ## 16. Codegen Configuration diff --git a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md index 2134df9a2..18525c288 100644 --- a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md +++ b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md @@ -6,12 +6,72 @@ bytecode: - Rust toolchain: `rust-toolchain.toml` - Midfall dependency revision: `53dc872f495104046d96bdac0a690f903dc0c537` -- Solidity compiler: `solc 0.8.30+commit.73712a01` -- Solidity compile flags: `--bin --optimize --via-ir --evm-version cancun --no-cbor-metadata` +- Solidity compiler: `solc 0.8.30+commit.73712a01`, installed and + SHA-256-verified by `scripts/install_pinned_solc.sh`. Official binary + hashes from `binaries.soliditylang.org//list.json`: + - `linux-amd64`: + `f3e987dc6ecebd4bd350c48edcbc320b46cf9e3109bd3fc3d88f1acaf4c428f7` + - `macosx-amd64` (also used on Apple Silicon via Rosetta 2): + `738dcdc6afddeb505ee4e4ef24f1c1fdba2b8c924e614cbbf5801a5b062dd683` +- Solidity compile flags: `--bin --optimize --optimize-runs --via-ir + --evm-version cancun --no-cbor-metadata`, where `` defaults to `200` + (`DEFAULT_OPTIMIZE_RUNS` in `src/evm.rs`, override with + `SOLC_OPTIMIZE_RUNS`); the IVC bench profiles below use `runs: 1`. + + **`--optimize-runs` is bytecode-affecting and must be recorded with every + artifact hash.** It is also deployability-affecting: solc 0.8.30 at + `runs=100000` emits a verifier over the EIP-170 24,576-byte runtime limit, + i.e. an undeployable contract that compiles without complaint. Repository-local `.cargo/config.toml` path overrides are intentionally not used. All Midfall crates are resolved from the pinned git revision in `Cargo.toml`. +## Provenance Identities + +Three different commit stamps appear across the audit and fixture documents. +They index different things; every recorded stamp should say which of these +it is: + +| Stamp | Identifies | +| --- | --- | +| `53dc872f495104046d96bdac0a690f903dc0c537` | The **Midfall dependency** revision pinned in `Cargo.toml` (also the source of the comment corpus). | +| `a096e71746e401404f250817ca4e857bac1eef56` | **This repository** at the time the review packet (`docs/audit/REVIEW_PACKET.md`) was assembled. | +| `3fb6d84` | **This repository** at the time the moonlight-wrap replay fixture (`fixtures/moonlight-wrap/`) was rendered. | + +## SRS Provenance + +`NEG_S_G2_BASE` — the element every soundness guarantee of a deployed +verifier rests on — is derived from the SRS at build time. Build-time code +(`src/lowering/vk.rs`) proves the SRS is internally consistent (G1/G2 bases +canonical, `s_g2` pairing-bound to the tau underlying `g_lagrange`), and the +gated test `midnight_srs_assets_bind_s_g2_to_lagrange_tau` runs the same +check directly against the asset files. What internal consistency cannot +prove is *which ceremony* an asset came from; that link is this record. + +Ceremony reference: the Midnight trusted-setup ceremony, published at +. Its +`MIDNIGHT_SRS_CATALOG.md` is the authoritative checksum table and also +documents a cargo tool for verifying an asset against the ceremony's +powers-of-tau transcript. *(Citation added 2026-08-12 from the reference in +`zk_stdlib/src/utils/plonk_api.rs`; deployment owners should confirm this is +the ceremony they intend to trust.)* + +Recorded asset hashes (`scripts/record_srs_provenance.sh`, 2026-08-12; +Midnight rows verified byte-identical against the official catalog above): + +| Asset | Bytes | SHA-256 | Matches official catalog | +| --- | ---: | --- | --- | +| `midnight-srs-2p19` | 100,663,684 | `8e8dc15c4362f05c912f1e770559a3945db3e58a374def416ed5d3e65ad5b10e` | yes (2026-08-12) | +| `midnight-srs-2p20` | 201,326,980 | `1cc62978558fdc1e445cd70cfd9a86ec3c2e2151b6d74811232d37faf9133ff1` | yes (2026-08-12) | +| `bls_filecoin_2p19` | 100,663,684 | `0574a536c128142e89c0f28198d048145e2bb2bf645c8b81c8697cba445a1fb1` | n/a (Filecoin SRS, test fixtures only) | + +Re-run the script before any deployment build and compare against this +table; then run the tau-binding test: + +```bash +HALO2_SOLIDITY_RUN_EVM_TESTS=1 cargo test --release --features evm midnight_srs_assets_bind_s_g2_to_lagrange_tau +``` + ## Canonical IVC Bench Command The current default IVC Solidity bench uses the multi-limb outer decider proof diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 614c9cebe..1cd8d1227 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -14,7 +14,7 @@ the replay deploys the verifier with the verifying key alone. | Field | Value | | --- | --- | -| Source commit | `3fb6d84` | +| Source commit | `3fb6d84` (**this repository**, solidity-verifier, at fixture-render time; not the Midfall dependency revision — see the provenance-identities table in `docs/reference/REPRODUCIBLE_BUILDS.md`) | | Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | | Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | | Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | diff --git a/proofs/solidity-verifier/scripts/generate_artifact_manifest.sh b/proofs/solidity-verifier/scripts/generate_artifact_manifest.sh new file mode 100755 index 000000000..6092ed7a9 --- /dev/null +++ b/proofs/solidity-verifier/scripts/generate_artifact_manifest.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Emit the REVIEW_PACKET.md section-4 artifact-manifest table for one rendered +# fixture dump (a directory under target/, e.g. target/poseidon-fixture-dump). +# +# Hashes generated sources and fixture binaries with SHA-256, and — when the +# pinned solc is available — compiles each contract with the recorded flag set +# to report the runtime bytecode length and keccak256. The point of the script +# is that manifest rows are produced by a maintained tool instead of being +# hand-filled (M-5 / I-3, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). +# +# Usage: +# scripts/generate_artifact_manifest.sh [--runs ] +# +# Environment: +# SOLC path to solc (default: resolved like the test harness: +# $SOLC, then .solc/solc, then solc on PATH) +# SOLC_OPTIMIZE_RUNS overrides --runs / the default of 200 +set -euo pipefail + +dump_dir="${1:?usage: $0 [--runs ]}" +shift || true +runs="${SOLC_OPTIMIZE_RUNS:-200}" +while [[ $# -gt 0 ]]; do + case "$1" in + --runs) runs="${2:?--runs needs a value}"; shift 2 ;; + *) echo "unknown argument: $1" >&2; exit 1 ;; + esac +done + +[[ -d "$dump_dir" ]] || { echo "not a directory: $dump_dir" >&2; exit 1; } + +sha256() { + shasum -a 256 "$1" 2>/dev/null | cut -d' ' -f1 || sha256sum "$1" | cut -d' ' -f1 +} + +solc_bin="${SOLC:-}" +if [[ -z "$solc_bin" ]]; then + if [[ -x ".solc/solc" ]]; then solc_bin=".solc/solc"; else solc_bin="$(command -v solc || true)"; fi +fi + +# Compile one contract with the recorded flag set and print +# " " for its largest emitted runtime +# (the file's main contract). Requires solc and python3. +runtime_info() { + local src="$1" + [[ -n "$solc_bin" ]] || { echo "n/a (no solc)"; return; } + local hex + hex="$("$solc_bin" --bin-runtime --optimize --optimize-runs "$runs" --via-ir \ + --evm-version cancun --no-cbor-metadata "$src" 2>/dev/null \ + | awk '/^[0-9a-f]+$/ { if (length($0) > length(best)) best = $0 } END { print best }')" + [[ -n "$hex" ]] || { echo "n/a (compile failed)"; return; } + python3 - "$hex" <<'PY' +import sys + +data = bytes.fromhex(sys.argv[1]) +# keccak256 (pre-NIST padding), matching EVM EXTCODEHASH and the recorded +# runtime hashes in REPRODUCIBLE_BUILDS.md. CPython's hashlib sha3_256 is +# NIST SHA-3, NOT keccak, so require pycryptodome and say so if missing. +try: + from Crypto.Hash import keccak +except ImportError: + sys.stdout.write(f"{len(data)} bytes, keccak256 unavailable (pip install pycryptodome)") + sys.exit(0) +digest = keccak.new(digest_bits=256, data=data).hexdigest() +sys.stdout.write(f"{len(data)} bytes, 0x{digest}") +PY +} + +row() { printf '| %s | %s |\n' "$1" "$2"; } + +commit="$(git rev-parse HEAD 2>/dev/null || echo unknown)" +dirty="clean" +[[ -n "$(git status --porcelain 2>/dev/null)" ]] && dirty="dirty" + +echo "### Artifact manifest: $dump_dir" +echo +echo "| Item | Value |" +echo "| --- | --- |" +row "Repository commit" "\`$commit\` (this repository; working tree $dirty)" +row "Rust toolchain" "\`rust-toolchain.toml\`" +row "Solidity compiler" "\`$("$solc_bin" --version 2>/dev/null | grep -o 'Version: .*' || echo 'n/a')\`" +row "Solidity flags" "\`--bin --optimize --optimize-runs $runs --via-ir --evm-version cancun --no-cbor-metadata\`" +row "Cargo features" "fill from the render invocation (not recoverable from the dump)" + +for name in Halo2Verifier Halo2VerifyingKey Halo2QuotientEvaluator; do + src="$dump_dir/$name.sol" + if [[ -f "$src" ]]; then + row "Generated $name source hash" "\`$(sha256 "$src")\`" + if [[ "$name" == "Halo2VerifyingKey" ]]; then + # The VK's deployed runtime (INVALID || payload) is constructed by its + # constructor, so the static --bin-runtime output is a stub and hashing + # it would be misleading. The authoritative pin is the generated + # EXPECTED_VK_CODEHASH constant checked on-chain. + row "$name runtime length/hash" "deploy-time constructed; pinned by EXPECTED_VK_LENGTH / EXPECTED_VK_CODEHASH in the verifier" + else + row "$name runtime length/hash" "$(runtime_info "$src")" + fi + else + row "Generated $name source hash" "not rendered (single-contract or embedded profile)" + fi +done + +for f in proof.bin calldata.bin instances.be instance.le; do + if [[ -f "$dump_dir/$f" ]]; then + row "Fixture \`$f\` hash" "\`$(sha256 "$dump_dir/$f")\`" + fi +done diff --git a/proofs/solidity-verifier/scripts/install_pinned_solc.sh b/proofs/solidity-verifier/scripts/install_pinned_solc.sh index 25fab697b..abd493fb8 100644 --- a/proofs/solidity-verifier/scripts/install_pinned_solc.sh +++ b/proofs/solidity-verifier/scripts/install_pinned_solc.sh @@ -14,6 +14,9 @@ case "$(uname -s)-$(uname -m)" in binary="solc-macosx-amd64-v${PINNED_SOLC_VERSION}" ;; Darwin-arm64) + # Upstream publishes no macosx-arm64 binary for this solc version; Apple + # Silicon deliberately runs the x86_64 binary under Rosetta 2. Same + # binary, same hash, same emitted bytecode. platform="macosx-amd64" binary="solc-macosx-amd64-v${PINNED_SOLC_VERSION}" ;; @@ -28,23 +31,27 @@ solc_path="$INSTALL_DIR/solc" # Content hash, not version string. `--version` output is trivially forged by a # substituted binary, and this project's entire reproducibility claim rests on -# the compiler being exactly this one. Per-platform hashes are published in -# https://binaries.soliditylang.org/${platform}/list.json -- fill these in and -# record them in the artifact manifest alongside the flag set. -declare -A PINNED_SOLC_SHA256=( - ["linux-amd64"]="TODO-fill-from-list.json" - ["macosx-amd64"]="TODO-fill-from-list.json" -) +# the compiler being exactly this one. These are the official sha256 values +# from https://binaries.soliditylang.org//list.json for +# v0.8.30+commit.73712a01 (recorded 2026-08-12); they are also recorded in +# docs/reference/REPRODUCIBLE_BUILDS.md and the review-packet manifest. +# (A plain case statement, not `declare -A`: stock macOS bash is 3.2, which +# has no associative arrays.) +case "$platform" in + linux-amd64) pinned_solc_sha256="f3e987dc6ecebd4bd350c48edcbc320b46cf9e3109bd3fc3d88f1acaf4c428f7" ;; + macosx-amd64) pinned_solc_sha256="738dcdc6afddeb505ee4e4ef24f1c1fdba2b8c924e614cbbf5801a5b062dd683" ;; + *) pinned_solc_sha256="" ;; +esac if [[ ! -x "$solc_path" ]] || ! "$solc_path" --version | grep -q "Version: ${PINNED_SOLC_VERSION}"; then url="https://binaries.soliditylang.org/${platform}/${binary}" echo "[install-solc] downloading $url" curl -fsSL "$url" -o "$solc_path" - expected="${PINNED_SOLC_SHA256[$platform]:-}" + expected="$pinned_solc_sha256" if [[ -z "$expected" || "$expected" == TODO-* ]]; then echo "[install-solc] no pinned SHA-256 recorded for platform '$platform'." >&2 echo "[install-solc] Fetch it from https://binaries.soliditylang.org/${platform}/list.json" >&2 - echo "[install-solc] and set PINNED_SOLC_SHA256 in this script." >&2 + echo "[install-solc] and set pinned_solc_sha256 in this script." >&2 rm -f "$solc_path" exit 1 fi diff --git a/proofs/solidity-verifier/scripts/record_srs_provenance.sh b/proofs/solidity-verifier/scripts/record_srs_provenance.sh new file mode 100755 index 000000000..b50643dc0 --- /dev/null +++ b/proofs/solidity-verifier/scripts/record_srs_provenance.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Record the SRS assets a verifier build trusts (H-1, +# docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). +# +# NEG_S_G2_BASE — the element every soundness guarantee of the deployed +# verifier rests on — is derived from the SRS at build time. Build-time code +# (src/lowering/vk.rs) now proves the SRS is internally consistent (s_g2 +# matches the tau underlying g_lagrange), but internal consistency cannot +# prove WHICH ceremony the asset came from. That link is this record: the +# SHA-256 of the exact asset bytes, checked against the table below and +# recorded in docs/reference/REPRODUCIBLE_BUILDS.md next to the ceremony +# reference. +# +# Usage: +# scripts/record_srs_provenance.sh [srs-dir] +# +# srs-dir defaults to $SRS_DIR, then ./.srs, then +# ../../zk_stdlib/examples/assets relative to this script. +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +default_assets="$script_dir/../../../zk_stdlib/examples/assets" + +srs_dir="${1:-${SRS_DIR:-}}" +if [[ -z "$srs_dir" ]]; then + if [[ -d "./.srs" ]]; then srs_dir="./.srs"; else srs_dir="$default_assets"; fi +fi +[[ -d "$srs_dir" ]] || { echo "SRS directory not found: $srs_dir" >&2; exit 1; } + +sha256() { + shasum -a 256 "$1" 2>/dev/null | cut -d' ' -f1 || sha256sum "$1" | cut -d' ' -f1 +} + +echo "### SRS provenance ($(date -u +%Y-%m-%dT%H:%M:%SZ), dir: $srs_dir)" +echo +echo "| Asset | Bytes | SHA-256 |" +echo "| --- | ---: | --- |" + +found=0 +for asset in midnight-srs-2p19 midnight-srs-2p20 midnight-srs-2p22 \ + bls_filecoin_2p19 bls_filecoin_2p13 bls_filecoin_2p12 bls_filecoin_2p6; do + path="$srs_dir/$asset" + [[ -f "$path" ]] || continue + found=1 + size="$(wc -c < "$path" | tr -d ' ')" + echo "| \`$asset\` | $size | \`$(sha256 "$path")\` |" +done + +if [[ "$found" == 0 ]]; then + echo >&2 + echo "no known SRS assets found in $srs_dir" >&2 + echo "download Midnight assets with: scripts/run_ivc_bench.sh (or curl from https://srs.midnight.network/)" >&2 + exit 1 +fi + +cat <<'EOF' + +Record these rows in docs/reference/REPRODUCIBLE_BUILDS.md ("SRS Provenance") +and compare against the hashes already recorded there before any deployment +build. The tau-binding of each asset's s_g2 (the NEG_S_G2_BASE source) is +checked by the gated test: + + HALO2_SOLIDITY_RUN_EVM_TESTS=1 cargo test --release --features evm \ + midnight_srs_assets_bind_s_g2_to_lagrange_tau +EOF From ca636ca86ccfe53160d43df2e8f4b7d03539b385 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 08:39:57 +0100 Subject: [PATCH 093/108] chore(solidity-verifier): regenerate fixture dumps on the current templates All tracked dumps under target/ lagged commit 460a666 (still pragma ^0.8.24, no P2 memory guard) and predated the exact gas bounds. Regenerated poseidon, rsa-signature, sha-preimage, and hybrid-mt via their fixture tests and ivc-keccak via scripts/run_ivc_bench.sh, all on the canonical evm,truncated-challenges profile. Every regenerated verifier was deployed and accepted a real proof under Prague revm as part of regeneration; the IVC final Keccak proof verified in 1,306,084 gas (checkpoint profile), and the recorded runtime hashes in REPRODUCIBLE_BUILDS.md were refreshed from that run. Not regenerated: moonlight-wrap-solidity-dump (rendered by an external Moonlight checkout; see fixtures/moonlight-wrap/README.md) and the committed fixtures/ replay sources, which intentionally pin the render-time artifacts they replay. Co-Authored-By: Claude Fable 5 --- .../docs/reference/REPRODUCIBLE_BUILDS.md | 24 +- .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 251 +++++++++++++---- .../Halo2VerifyingKey.sol | 5 +- .../Halo2QuotientEvaluator.sol | 32 ++- .../Halo2Verifier.sol | 258 +++++++++++++++--- .../Halo2VerifyingKey.sol | 5 +- .../poseidon-fixture-dump/Halo2Verifier.sol | 221 ++++++++++++--- .../Halo2VerifyingKey.sol | 5 +- .../Halo2Verifier.sol | 238 ++++++++++++---- .../Halo2VerifyingKey.sol | 5 +- .../Halo2Verifier.sol | 251 +++++++++++++---- .../Halo2VerifyingKey.sol | 5 +- 12 files changed, 1057 insertions(+), 243 deletions(-) diff --git a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md index 18525c288..6efb0953e 100644 --- a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md +++ b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md @@ -143,8 +143,10 @@ The proof repacked from `4,912` compressed bytes to `7,392` padded bytes, with ## Recorded Legacy Multi-Limb Runtime Hashes -The concrete hashes below are the latest recorded default multi-limb profile in -this repository. They were generated with the fixed default quotient codegen shape: +The concrete hashes below are the latest recorded default multi-limb profile +in this repository (recorded 2026-08-13, after the exact-precompile-gas-bound +change; the tracked `target/ivc-keccak-solidity-dump/` sources match this +run). They were generated with the fixed default quotient codegen shape: ```bash scripts/run_ivc_bench.sh \ @@ -163,15 +165,19 @@ Published deployed-runtime hashes: | Artifact | Runtime bytes | Runtime `keccak256` | | --- | ---: | --- | -| `Halo2Verifier` | 12,061 | `0xf0d2433a3142294afb4d9a9434d623b8f00bbea212380777b5aee197e79b1454` | -| `Halo2VerifyingKey` | 14,016 | `0x0f858e789c9d52f7e11beb96dd39fa30712c42f629c3505be9cceef3225119a0` | -| `Halo2QuotientEvaluator` | 23,221 | `0x1f8acc8aa363e10d031e9e56dd4180a70c714330fa466d3423f9ce1d4e1f00b2` | +| `Halo2Verifier` | 12,454 | `0xa74814afafa69cfcb69224aa3a68f0f461348439beec8f18450f334782159e10` | +| `Halo2VerifyingKey` | 17,025 | `0x67bac137fa7e479c25b63324812752e4b6e13d9841d5bf83c322170bf91c0f88` | +| `Halo2QuotientEvaluator` | 9,552 | `0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c` | -Total deployed runtime bytes: `49,298`. +Total deployed runtime bytes: `39,031`. -The same run accepted the final IVC Keccak proof on-chain in `1,399,268` gas. -The proof repacked from `5,056` compressed bytes to `7,776` padded bytes, with -`8,356` bytes of calldata. +The same run accepted the final IVC Keccak proof on-chain in `1,306,084` gas +(gas-checkpoint diagnostic profile). The proof repacked from `5,056` +compressed bytes to `7,776` padded bytes, with `8,356` bytes of calldata. + +Previous recording, for comparison (2026-07-era artifact set): verifier +12,061 / VK 14,016 / evaluator 23,221 bytes (49,298 total), accepted in +`1,399,268` gas. Compared with this multi-limb profile, outer single-H removes three quotient G1 commitments: proof size drops by `144` compressed bytes and `384` padded bytes, diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index 40e7e6568..42ca24aa3 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -137,10 +148,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x6840; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x6940; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -153,6 +167,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0x7e60; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x7e60; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0x8060; uint256 internal constant TRACE_U256_MPTR = 0xa980; // ---------------------------------------------------------------------- @@ -178,6 +196,29 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x7be0; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x7c60; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 454608; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -195,8 +236,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -216,7 +266,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -237,7 +287,41 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -250,6 +334,56 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -265,7 +399,7 @@ contract Halo2Verifier { } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x2940, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x2940, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -275,7 +409,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -309,12 +443,14 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -339,10 +475,20 @@ contract Halo2Verifier { // INVALID-prefixed payload into VK_MPTR. address vk = AUTHORIZED_VK; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== @@ -371,7 +517,7 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } inv := mload(p) } @@ -516,7 +662,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -566,7 +712,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -615,7 +761,7 @@ contract Halo2Verifier { mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 @@ -1283,8 +1429,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x0160) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1294,11 +1442,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1309,9 +1457,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0140) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0140) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1334,8 +1482,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0140)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0140)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -1628,18 +1776,24 @@ contract Halo2Verifier { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x09 push_const_u8 + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x13 add_mul_const_u8_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity + // 0x1c lin7 + // 0x21 modarith7 // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -2825,7 +2979,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 35 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 35 evaluation term(s), 34 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x8040, 0x6aa0) mstore(0x8060, 0x7240) @@ -2877,7 +3031,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 3 commitment(s) + // q_eval_set[1]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x7200) let q_eval_set_1 := mload(0x7220) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x7280), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -2891,7 +3045,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 8 commitment(s) (rolled, m>=4) + // q_eval_set[2]: 8 evaluation term(s), 8 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x8040, 0x6ac0) mstore(0x8060, 0x6b60) @@ -2938,7 +3092,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[3]: 2 commitment(s) + // q_eval_set[3]: 2 evaluation term(s), 2 commitment term(s) let q_eval_set_0 := mload(0x7140) let q_eval_set_1 := mload(0x7160) let q_eval_set_2 := mload(0x7180) @@ -3250,7 +3404,8 @@ contract Halo2Verifier { mcopy(0xa8e0, F_COM_MPTR, 0x80) mstore(0xa960, x4_pow_4) if success { - success := staticcall(gas(), 0x0c, 0x8040, 0x2940, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 66 pair(s) + success := staticcall(454608, 0x0c, 0x8040, 0x2940, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -3265,22 +3420,22 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol index fcfb39dad..a4b803555 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol index c2bc6699d..3a076aef5 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol @@ -1,5 +1,8 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Split Halo2 quotient numerator evaluator. /// @notice Reconstructs the scalar side of the linearization query for a generated verifier. @@ -416,18 +419,21 @@ contract Halo2QuotientEvaluator { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity + // 0x21 modarith7 // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol index 48f05f35a..f4856ff11 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -145,10 +156,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x9320; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -190,6 +204,33 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 525096; + // Worst-case accumulator RHS MSM: carried RHS point plus every generated + // fixed-base tail scalar nonzero. Zero tail scalars are omitted at + // runtime, which only lowers the actual cost below this bound. + uint256 internal constant ACC_RHS_MSM_GAS = 12000; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -207,8 +248,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -228,7 +278,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -249,7 +299,7 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -262,6 +312,90 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -277,7 +411,7 @@ contract Halo2Verifier { } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -287,7 +421,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -333,19 +467,21 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. function verifyProof( bytes calldata proof, uint256[] calldata instances - ) external view returns (bool) { + ) external returns (bool) { // Cheap ABI-shape guard before any generated memory work: // - proof head must point at the bytes payload; // - instances head must point at the generated instance array. @@ -366,10 +502,20 @@ contract Halo2Verifier { // reconstruction to a separately deployed generated evaluator. address quotientEvaluator = AUTHORIZED_QUOTIENT; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== @@ -398,7 +544,7 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } inv := mload(p) } @@ -543,7 +689,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -593,7 +739,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -642,7 +788,7 @@ contract Halo2Verifier { mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 @@ -936,7 +1082,7 @@ contract Halo2Verifier { // Single-pair MSM output overwrites ACC_LHS_MPTR with // lhs_scalar * decoded_lhs. If lhs_scalar is one, this // is also a curve/subgroup validation round-trip. - out := staticcall(gas(), 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) + out := staticcall(G1MSM_GAS_1PAIR, 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) out := and(out, eq(returndatasize(), 0x80)) } } @@ -982,8 +1128,11 @@ contract Halo2Verifier { // // The precompile also validates every nonzero fixed // base embedded by codegen and the carried RHS point. + // ACC_RHS_MSM_GAS is the compile-time worst case + // (every tail scalar nonzero); acc_msm_len can only + // select a same-size-or-smaller MSM at runtime. out := staticcall( - gas(), + ACC_RHS_MSM_GAS, 0x0c, acc_scratch, acc_msm_len, @@ -998,11 +1147,20 @@ contract Halo2Verifier { } + // Section-boundary gas-attribution checkpoint. Emits a + // single LOG1 (no data) with topic = (id << 248) | gas(). + // Cost: 375 (LOG base) + 375 (1 topic) = 750 gas/call. + // Host-side parses the topic into (id, gas_left) and prints + // pairwise deltas (see `dump_gas_checkpoints`). + function gas_checkpoint(id) { + log1(0, 0, or(shl(248, id), gas())) + } let r := FR_MODULUS let success := true + gas_checkpoint(1) // entry: before VK loading // =============================================================== // VK loading: either bake in the embedded VK bytes or fetch @@ -1091,6 +1249,7 @@ contract Halo2Verifier { // where the verifier converts failure to a revert. success := validate_public_accumulator(success, r) if iszero(success) { revert(0, 0) } + gas_checkpoint(2) // after VK loading + accumulator public-input precheck // =============================================================== // Transcript: VK digest + instances + proof. @@ -1161,6 +1320,7 @@ contract Halo2Verifier { } if iszero(success) { revert(0, 0) } } + gas_checkpoint(3) // after VK digest + committed_pi + instance absorbs // =============================================================== // Per-user-phase reads + challenge squeezes. @@ -1198,6 +1358,7 @@ contract Halo2Verifier { advice_walk := add(advice_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(4) // after user-phase advice reads + user challenge squeezes // ---- theta ---- // From this point onward the transcript alternates between @@ -1217,6 +1378,7 @@ contract Halo2Verifier { lookup_m_walk := add(lookup_m_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(5) // after theta squeeze + lookup multiplicities // ---- beta, gamma ---- // beta and gamma are the permutation/lookup randomizers. They are @@ -1236,6 +1398,7 @@ contract Halo2Verifier { perm_z_walk := add(perm_z_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(6) // after beta/gamma + permutation Z products // ---- lookup helpers + accumulators (per-lookup) ---- // Each lookup contributes zero or more helper commitments followed // by its lookup accumulator Z commitment. The generated layout keeps @@ -1276,6 +1439,7 @@ contract Halo2Verifier { calldatacopy(lookup_z_walk, proof_cptr, 0x80) lookup_z_walk := add(lookup_z_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) + gas_checkpoint(7) // after lookup helpers + Z accumulators // ---- trash_challenge ---- // Midnight squeezes this challenge unconditionally, even when the @@ -1295,6 +1459,7 @@ contract Halo2Verifier { trashcan_walk := add(trashcan_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(8) // after trash_challenge + trashcans // ---- y ---- // y batches all quotient identities. Quotient commitments are read @@ -1318,6 +1483,7 @@ contract Halo2Verifier { quotient_walk := add(quotient_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(9) // after y squeeze + quotient-limb reads // ---- x ---- // x is the main evaluation point. Values read after this point are @@ -1426,6 +1592,7 @@ contract Halo2Verifier { // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. if iszero(success) { revert(0, 0) } + gas_checkpoint(10) // after evaluations + x1/x2 + f_com + x3 + q_evals + x4 + pi (transcript done) // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1507,6 +1674,7 @@ contract Halo2Verifier { mstore(L_0_MPTR, l_0) mstore(INSTANCE_EVAL_MPTR, instance_eval) } + gas_checkpoint(11) // after Lagrange + instance evaluation block if iszero(success) { revert(0, 0) } @@ -1531,6 +1699,11 @@ contract Halo2Verifier { eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) )) { revert(0, 0) } + // gas() forwarding is deliberate here, unlike the precompile + // call sites: this is a regular contract call, so a reverting + // or failing callee refunds its unused gas -- only precompile + // ERRORS burn everything forwarded (EIP-2537). The callee is + // also pinned by codehash above, not attacker-supplied. if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x0180)) { revert(0, 0) } if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { revert(0, 0) } @@ -1545,6 +1718,7 @@ contract Halo2Verifier { mstore(add(SELECTOR_ACC_MPTR, shl(5, q_i)), mload(add(q_out, add(0x40, shl(5, q_i))))) } } + gas_checkpoint(12) // after batched identity numerator reconstruction // =============================================================== // Prepare linearization scalars for the final PCS MSM. @@ -1586,6 +1760,7 @@ contract Halo2Verifier { mstore(QUOTIENT_MPTR, x_split) mstore(add(QUOTIENT_MPTR, 0x20), one_minus_x_n) } + gas_checkpoint(13) // after linearization scalar prep // =============================================================== // PCS computation (multi-prepare emitter from Step 5). @@ -1624,6 +1799,7 @@ contract Halo2Verifier { x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) mstore(add(ROT_POINTS_MPTR, 0x0), x_pow_of_omega) } + gas_checkpoint(17) // after PCS sub-block 1 // Generated PCS sub-block 2. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -1639,11 +1815,12 @@ contract Halo2Verifier { mstore(p, and(acc, 0xffffffffffffffffffffffffffffffff)) } } + gas_checkpoint(18) // after PCS sub-block 2 // Generated PCS sub-block 3. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 43 evaluation term(s), 42 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9980) mstore(0xb2a0, 0x9480) @@ -1699,11 +1876,12 @@ contract Halo2Verifier { } mstore(add(Q_EVAL_SET_MPTR, 0x0), q_eval_set_0) } + gas_checkpoint(19) // after PCS sub-block 3 // Generated PCS sub-block 4. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 3 commitment(s) + // q_eval_set[1]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9660) let q_eval_set_1 := mload(0x9920) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -1713,11 +1891,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) } + gas_checkpoint(20) // after PCS sub-block 4 // Generated PCS sub-block 5. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 3 commitment(s) + // q_eval_set[2]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9fe0) let q_eval_set_1 := mload(0xa000) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -1727,11 +1906,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) } + gas_checkpoint(21) // after PCS sub-block 5 // Generated PCS sub-block 6. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) + // q_eval_set[3]: 11 evaluation term(s), 11 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x94a0) mstore(0xb2a0, 0x9540) @@ -1783,11 +1963,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_2) } + gas_checkpoint(22) // after PCS sub-block 6 // Generated PCS sub-block 7. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) + // q_eval_set[4]: 5 evaluation term(s), 5 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9e00) mstore(0xb2a0, 0x9e20) @@ -1821,6 +2002,7 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x120), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0x140), q_eval_set_2) } + gas_checkpoint(23) // after PCS sub-block 7 // Generated PCS sub-block 8. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -1989,6 +2171,7 @@ contract Halo2Verifier { } mstore(F_EVAL_MPTR, f_eval) } + gas_checkpoint(24) // after PCS sub-block 8 // Generated PCS sub-block 9. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -2178,11 +2361,13 @@ contract Halo2Verifier { mcopy(0xe2a0, F_COM_MPTR, 0x80) mstore(0xe320, x4_pow_5) if success { - success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 78 pair(s) + success := staticcall(525096, 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) } + gas_checkpoint(25) // after PCS sub-block 9 // Generated PCS sub-block 10. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -2193,27 +2378,28 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } + gas_checkpoint(14) // after PCS computation block (= sub-block 6) // Batch the prevalidated public IVC accumulator pairing equation // into the final KZG pairing. @@ -2249,12 +2435,12 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_RHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_RHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } @@ -2263,15 +2449,16 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_LHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_LHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } } + gas_checkpoint(15) // after public accumulator pairing batch prep (omitted for no-accumulator VKs) // The Yul `ec_pairing` helper checks // e(arg0, G2_BASE) * e(arg1, NEG_S_G2_BASE) == 1 @@ -2288,6 +2475,7 @@ contract Halo2Verifier { // pairing argument order. Pass them swapped to ec_pairing. if iszero(success) { revert(0, 0) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) + gas_checkpoint(16) // after final ec_pairing diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol index f8c08652b..c51a80c36 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index 3b9d726c2..fb2e21309 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -137,10 +148,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x5400; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x5500; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -182,6 +196,29 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x6360; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x63e0; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 337836; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -199,8 +236,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -220,7 +266,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -241,7 +287,41 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -254,6 +334,56 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -269,7 +399,7 @@ contract Halo2Verifier { } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x1d60, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x1d60, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -279,7 +409,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -313,12 +443,14 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -343,10 +475,20 @@ contract Halo2Verifier { // INVALID-prefixed payload into VK_MPTR. address vk = AUTHORIZED_VK; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== @@ -375,7 +517,7 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } inv := mload(p) } @@ -520,7 +662,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -570,7 +712,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -619,7 +761,7 @@ contract Halo2Verifier { mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 @@ -1618,18 +1760,20 @@ contract Halo2Verifier { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -2375,7 +2519,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 33 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 33 evaluation term(s), 32 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x6660, 0x56e0) mstore(0x6680, 0x5700) @@ -2425,7 +2569,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 5 commitment(s) (rolled, m>=4) + // q_eval_set[1]: 5 evaluation term(s), 5 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x6660, 0x5680) mstore(0x6680, 0x5720) @@ -2455,7 +2599,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 2 commitment(s) + // q_eval_set[2]: 2 evaluation term(s), 2 commitment term(s) let q_eval_set_0 := mload(0x5ac0) let q_eval_set_1 := mload(0x5ae0) let q_eval_set_2 := mload(0x5b00) @@ -2681,7 +2825,8 @@ contract Halo2Verifier { mcopy(0x8320, F_COM_MPTR, 0x80) mstore(0x83a0, x4_pow_3) if success { - success := staticcall(gas(), 0x0c, 0x6660, 0x1d60, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 47 pair(s) + success := staticcall(337836, 0x0c, 0x6660, 0x1d60, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2696,22 +2841,22 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol index 1ee722abf..e13e56042 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index 7679a069d..7530e2cdc 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -137,10 +148,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x5000; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x5100; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -153,6 +167,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0x5f40; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x5f40; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0x63a0; uint256 internal constant TRACE_U256_MPTR = 0x7940; // ---------------------------------------------------------------------- @@ -178,6 +196,29 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x5d40; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x5d40; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 299628; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -195,8 +236,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -216,7 +266,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -237,7 +287,41 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -250,6 +334,56 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -265,7 +399,7 @@ contract Halo2Verifier { } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x19a0, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x19a0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -275,7 +409,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -309,12 +443,14 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -339,10 +475,20 @@ contract Halo2Verifier { // INVALID-prefixed payload into VK_MPTR. address vk = AUTHORIZED_VK; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== @@ -371,7 +517,7 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } inv := mload(p) } @@ -516,7 +662,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -566,7 +712,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -615,7 +761,7 @@ contract Halo2Verifier { mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 @@ -1255,8 +1401,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x03c0) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1266,11 +1414,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1281,9 +1429,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0100) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0100) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1306,8 +1454,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0100)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0100)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -1584,18 +1732,13 @@ contract Halo2Verifier { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -1989,7 +2132,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 28 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 28 evaluation term(s), 27 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x5fa0, 0x52e0) mstore(0x5fc0, 0x5300) @@ -2034,7 +2177,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 5 commitment(s) (rolled, m>=4) + // q_eval_set[1]: 5 evaluation term(s), 5 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x5fa0, 0x5280) mstore(0x5fc0, 0x5320) @@ -2064,7 +2207,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 2 commitment(s) + // q_eval_set[2]: 2 evaluation term(s), 2 commitment term(s) let q_eval_set_0 := mload(0x5640) let q_eval_set_1 := mload(0x5660) let q_eval_set_2 := mload(0x5680) @@ -2278,7 +2421,8 @@ contract Halo2Verifier { mcopy(0x78a0, F_COM_MPTR, 0x80) mstore(0x7920, x4_pow_3) if success { - success := staticcall(gas(), 0x0c, 0x5fa0, 0x19a0, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 41 pair(s) + success := staticcall(299628, 0x0c, 0x5fa0, 0x19a0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -2293,22 +2437,22 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2VerifyingKey.sol index cd266f402..056663339 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 36d30c3e4..8b60fba1c 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -137,10 +148,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x6520; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x6620; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -153,6 +167,10 @@ contract Halo2Verifier { uint256 internal constant SELECTOR_ACC_MPTR = 0x7a80; uint256 internal constant QUOTIENT_RETURN_MPTR = 0x1000; uint256 internal constant BATCH_INV_SCRATCH_MPTR = 0x7a80; + // Lagrange batch-inversion input run: denominators, in-place inverses, + // then Lagrange values, consumed and distilled into the named theta + // slots by the Lagrange block. Planner-registered phase scratch. + uint256 internal constant LAGRANGE_DENOMS_MPTR = 0x8040; uint256 internal constant TRACE_U256_MPTR = 0xa3a0; // ---------------------------------------------------------------------- @@ -178,6 +196,29 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0x7880; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0x7880; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 436212; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -195,8 +236,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -216,7 +266,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -237,7 +287,41 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -250,6 +334,56 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -265,7 +399,7 @@ contract Halo2Verifier { } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x2760, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x2760, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -275,7 +409,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -309,12 +443,14 @@ contract Halo2Verifier { /// precompiles, or mismatched pinned dependency code revert. Trace and gas /// renders keep the same failure policy. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -339,10 +475,20 @@ contract Halo2Verifier { // INVALID-prefixed payload into VK_MPTR. address vk = AUTHORIZED_VK; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== @@ -371,7 +517,7 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } inv := mload(p) } @@ -516,7 +662,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -566,7 +712,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -615,7 +761,7 @@ contract Halo2Verifier { mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 @@ -1271,8 +1417,10 @@ contract Halo2Verifier { // First pass writes denominators (x - omega_i) for every // Lagrange value needed below, then appends x^n - 1. The // batch inversion pass turns all of them into inverses in one - // modexp call. - let mptr := X_N_MPTR + // modexp call. The run lives in the dedicated planner-registered + // LAGRANGE_DENOMS_MPTR scratch region; only the distilled + // results below are persisted into the named theta slots. + let mptr := LAGRANGE_DENOMS_MPTR let mptr_end := add(mptr, 0x0520) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1282,11 +1430,11 @@ contract Halo2Verifier { } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). - mptr := X_N_MPTR + mptr := LAGRANGE_DENOMS_MPTR let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) for { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } lt(mptr, mptr_end) @@ -1297,9 +1445,9 @@ contract Halo2Verifier { // l_blind is the sum of the negative-rotation Lagrange terms // used by the midnight-proofs blinding identity. - let l_blind := mload(add(X_N_MPTR, 0x20)) - let l_i_cptr := add(X_N_MPTR, 0x40) - for { let l_i_cptr_end := add(X_N_MPTR, 0x0120) } + let l_blind := mload(add(LAGRANGE_DENOMS_MPTR, 0x20)) + let l_i_cptr := add(LAGRANGE_DENOMS_MPTR, 0x40) + for { let l_i_cptr_end := add(LAGRANGE_DENOMS_MPTR, 0x0120) } lt(l_i_cptr, l_i_cptr_end) { l_i_cptr := add(l_i_cptr, 0x20) } { l_blind := addmod(l_blind, mload(l_i_cptr), r) @@ -1322,8 +1470,8 @@ contract Halo2Verifier { // Persist the derived values into named memory slots consumed // by quotient reconstruction and PCS preparation. let x_n_minus_1_inv := mload(mptr_end) - let l_last := mload(X_N_MPTR) - let l_0 := mload(add(X_N_MPTR, 0x0120)) + let l_last := mload(LAGRANGE_DENOMS_MPTR) + let l_0 := mload(add(LAGRANGE_DENOMS_MPTR, 0x0120)) mstore(X_N_MPTR, x_n) mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) @@ -1600,18 +1748,24 @@ contract Halo2Verifier { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x09 push_const_u8 + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x13 add_mul_const_u8_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity + // 0x1c lin7 + // 0x21 modarith7 // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -2597,7 +2751,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 33 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 33 evaluation term(s), 32 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x7c40, 0x6780) mstore(0x7c60, 0x6f00) @@ -2647,7 +2801,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 3 commitment(s) + // q_eval_set[1]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x6ec0) let q_eval_set_1 := mload(0x6ee0) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x6f40), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -2661,7 +2815,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 8 commitment(s) (rolled, m>=4) + // q_eval_set[2]: 8 evaluation term(s), 8 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0x7c40, 0x67a0) mstore(0x7c60, 0x6840) @@ -2708,7 +2862,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[3]: 2 commitment(s) + // q_eval_set[3]: 2 evaluation term(s), 2 commitment term(s) let q_eval_set_0 := mload(0x6e00) let q_eval_set_1 := mload(0x6e20) let q_eval_set_2 := mload(0x6e40) @@ -3014,7 +3168,8 @@ contract Halo2Verifier { mcopy(0xa300, F_COM_MPTR, 0x80) mstore(0xa380, x4_pow_4) if success { - success := staticcall(gas(), 0x0c, 0x7c40, 0x2760, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 63 pair(s) + success := staticcall(436212, 0x0c, 0x7c40, 0x2760, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -3029,22 +3184,22 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol index dc1527a1e..2091b9f1c 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. From 7cc22e0d1bd2a851d33ace0e78a2768fa11e80f3 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 09:27:05 +0100 Subject: [PATCH 094/108] fix(solidity-verifier): planner and codegen assertions for the silent-drift findings Converts four "happens to be correct" invariants from the 2026-08 review into asserted properties (P8, P9, L-2 assert half, I-6), plus the I-2/I-3 comment corrections: - P9 (L-7): batch_invert scratch sits immediately below lagrange_denoms with zero slack, and an overflow corrupts denominator[0] silently (the modexp still succeeds). The planner now mirrors the template's run-length expression and refuses to plan a layout where the two formulas disagree or the scratch cannot hold n-2 prefix products plus the modexp frame. Region-shape test across instance/rotation shapes. - P8 (L-5): CHALLENGE_MPTR == THETA_MPTR is legal only for the empty window. The planner now asserts the challenge window covers the phase sum of user challenges the transcript parser actually squeezes and ends at or before theta; an undersized window refuses to plan. Positive and should-panic tests. - L-2: the MSM emitters omit identity-pinned commitments while keeping their evals; that is sound only because the identity pointer is reserved for the committed-instance column. queries() now asserts every identity-pinned query is a CommittedInstance source. - I-6: (1) the upstream verifier orders permutation z queries as (Cur, Next) pairs then reversed Last openings, while the generator interleaves per set -- the identical point-set structure is now re-derived under the upstream ordering and asserted, not assumed; (2) the fixed-eval proof section is column-sized upstream and query-sized here -- the two counts are now asserted equal at plan time so a rotated or repeated fixed query fails loudly instead of silently desynchronizing the proof stream. - I-2: the constructor MSM smoke comment no longer claims the probe pre-expands the runtime memory range (creation-frame memory is discarded; only input-size coverage carries over); the unused-looking `r` parameter of validate_public_accumulator is documented as render-shape dependent. - I-3: the impossible identity-flag/sentinel-mismatch branch in load_acc_point is now labeled unreachable-by-construction. Co-Authored-By: Claude Fable 5 --- .../solidity-verifier/src/lowering/kzg/mod.rs | 126 ++++++++++++- .../src/lowering/layout/memory.rs | 175 ++++++++++++++++++ .../src/lowering/protocol/mod.rs | 25 +++ .../partials/verifier/AccumulatorHelpers.yul | 12 ++ .../partials/verifier/PrecompileSmoke.sol | 8 +- 5 files changed, 342 insertions(+), 4 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 3f2c7f98d..bcd518c96 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -94,12 +94,134 @@ impl Query { /// simple multiplicative selector queries are skipped because the custom /// linearization query carries their commitments and selector accumulators. pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec { - meta.protocol + let queries: Vec = meta + .protocol .pcs_queries .iter() .copied() .map(|source| query_from_plan(source, meta, data)) - .collect() + .collect(); + // L-2 (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): downstream MSM + // emission silently omits commitments pinned to `G1_IDENTITY_MPTR` while + // keeping their evaluation terms. That omission is sound ONLY because + // the identity pointer is reserved for the committed-instance column + // (`SUPPORTED_COMMITTED_INSTANCE_COMMITMENT` is the identity, absorbed + // as 128 zero bytes). Pin that justification here, where each query + // still knows its provenance: any other query source acquiring the + // identity pointer would make the emitters drop a real MSM term. + let g1_identity = EcPoint::new(Ptr::memory("G1_IDENTITY_MPTR")); + for (source, query) in meta.protocol.pcs_queries.iter().zip(&queries) { + assert!( + query.comm != g1_identity + || matches!(source, PcsQuerySource::CommittedInstance(_)), + "query {source:?} resolves to the G1 identity commitment; only \ + committed-instance queries may be identity-pinned, since the MSM \ + emitters omit identity commitments while keeping their evals" + ); + } + assert_permutation_query_order_is_upstream_equivalent(meta, data, &queries); + queries +} + +/// I-6 (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the midnight-proofs +/// verifier emits permutation z queries as all `(Cur, Next)` pairs in +/// forward set order followed by the `Last` openings in REVERSE set order, +/// while this generator interleaves `Cur/Next/Last` per set. For every +/// supported shape the two orderings happen to produce identical +/// intermediate point-set structure -- but that is a property of the +/// concrete plan (no new rotation or commitment introduced between the +/// placements), not an order-insensitive transformation. Re-derive the +/// intermediate sets under the upstream ordering and refuse to plan a +/// circuit where the structures diverge, since every x1-power index and MSM +/// slot downstream depends on it. +fn assert_permutation_query_order_is_upstream_equivalent( + meta: &ConstraintSystemMeta, + data: &Data, + generator_order: &[Query], +) { + let sources = &meta.protocol.pcs_queries; + let z_positions: Vec = sources + .iter() + .enumerate() + .filter(|(_, s)| matches!(s, PcsQuerySource::PermutationZ { .. })) + .map(|(i, _)| i) + .collect(); + if z_positions.is_empty() { + return; + } + assert!( + z_positions.windows(2).all(|w| w[1] == w[0] + 1), + "permutation z queries are expected to form one contiguous block" + ); + + // Rebuild the z block in the upstream order: (Cur, Next) per set in + // forward order, then Last per set in reverse order. + let z_sources: Vec = + z_positions.iter().map(|&i| sources[i]).collect(); + let mut upstream_block: Vec = z_sources + .iter() + .copied() + .filter(|s| { + matches!( + s, + PcsQuerySource::PermutationZ { + kind: PermutationZEval::Cur | PermutationZEval::Next, + .. + } + ) + }) + .collect(); + let mut last_queries: Vec = z_sources + .iter() + .copied() + .filter(|s| { + matches!( + s, + PcsQuerySource::PermutationZ { + kind: PermutationZEval::Last, + .. + } + ) + }) + .collect(); + last_queries.reverse(); + upstream_block.extend(last_queries); + + let mut upstream_sources = sources.clone(); + for (slot, source) in z_positions.iter().zip(upstream_block) { + upstream_sources[*slot] = source; + } + let upstream_queries: Vec = upstream_sources + .iter() + .copied() + .map(|source| query_from_plan(source, meta, data)) + .collect(); + + let generator_sets = construct_intermediate_sets_impl(generator_order); + let upstream_sets = construct_intermediate_sets_impl(&upstream_queries); + assert_eq!( + generator_sets.point_sets, upstream_sets.point_sets, + "permutation z query interleaving changes the KZG point-set structure \ + relative to the upstream (Cur/Next then reversed Last) ordering; the \ + generated x1-power indices would not match the native verifier" + ); + assert_eq!( + generator_sets.commitments.len(), + upstream_sets.commitments.len(), + "permutation z query interleaving changes the deduplicated commitment \ + count relative to the upstream ordering" + ); + for (g, u) in generator_sets.commitments.iter().zip(&upstream_sets.commitments) { + assert!( + g.set_index == u.set_index && g.comm == u.comm && g.evals == u.evals, + "permutation z query interleaving reorders commitment {:?} relative \ + to the upstream ordering (set {} vs {}); MSM slots and x1 powers \ + would diverge from the native verifier", + g.comm, + g.set_index, + u.set_index, + ); + } } /// Resolve a typed protocol query source to concrete commitment/eval handles. diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 50039236d..3d0e3abab 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -643,6 +643,44 @@ impl VerifierMemoryLayout { .expect("constructor G1MSM smoke bounds are non-empty"); let batch_invert_len = batch_invert_scratch_bytes(meta, config.num_instances); let lagrange_denoms_len = batch_invert_input_words(meta, config.num_instances) * WORD_BYTES; + // P9 (L-7, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the + // generated Lagrange block computes its batch-inversion run length + // INDEPENDENTLY of the planner, in the template (`Lagrange.yul`: + // one denominator per public instance -- or one fallback slot when + // there are none -- plus `abs(rotation_last)` negative-row + // denominators, plus x_n - 1). `batch_invert_scratch` sits + // immediately below `lagrange_denoms`, sized with ZERO slack, so if + // the two formulas ever drift the forward pass's modexp frame lands + // on denominator[0] and corrupts it SILENTLY: the modexp still + // succeeds, `ret` stays 1, and the backward pass returns wrong + // inverses without reverting. Mirror the template's expression here + // and refuse to plan a layout where they disagree or where the + // scratch cannot hold the run. + { + let n = batch_invert_input_words(meta, config.num_instances); + let neg_lagranges = meta.rotation_last.unsigned_abs() as usize; + let template_run_words = if config.num_instances == 0 { + // fallback denominator slot + negative-row denominators + (x_n - 1) + 1 + neg_lagranges + 1 + } else { + config.num_instances + neg_lagranges + 1 + }; + assert_eq!( + n, template_run_words, + "planner batch-inversion input count ({n} words) does not match the \ + run the generated Lagrange block writes ({template_run_words} words); \ + the scratch/denominator regions would be mis-sized" + ); + let required = n.saturating_sub(2) * WORD_BYTES + MODEXP_FRAME_BYTES; + assert!( + batch_invert_len >= required, + "batch_invert scratch is {batch_invert_len} bytes but n={n} inputs need \ + {required} (n-2 prefix products plus one modexp frame); an overflow \ + lands in lagrange_denoms and silently corrupts denominator[0] -- the \ + modexp still succeeds and the backward pass returns wrong inverses \ + WITHOUT reverting" + ); + } let quotient_return_len = (2 + meta.num_simple_selectors) * WORD_BYTES; let mut arena = MemoryArena::default(); @@ -721,6 +759,35 @@ impl VerifierMemoryLayout { let at_theta = |words: usize| theta_start + words * WORD_BYTES; let ptr_at_theta = |slot: ThetaSlot| Ptr::memory(at_theta(slot.word())); let theta_mptr = ptr_at_theta(ThetaSlot::Theta); + // P8 (L-5, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): with zero + // user-phase challenges CHALLENGE_MPTR and THETA_MPTR legitimately + // coincide (the challenge window is empty). The hazard is a circuit + // WITH user challenges whose window is under-sized: the transcript + // parser squeezes user challenge j to CHALLENGE_MPTR + 32*j, and the + // very next squeeze unconditionally targets THETA_MPTR -- an overlap + // silently replaces a user challenge with theta while the transcript + // still matches the prover (permanent liveness break, potential + // soundness break). The window is sized by `challenge_indices` while + // the runtime write count is the phase sum of `num_user_challenges`; + // tie the two and pin theta past the window. + { + let user_challenges_total: usize = meta.num_user_challenges.iter().sum(); + assert_eq!( + meta.challenge_indices.len(), + user_challenges_total, + "user-phase challenge window is sized for {} challenge slot(s) but the \ + transcript parser squeezes {user_challenges_total}; the excess would \ + collide with the theta slots", + meta.challenge_indices.len(), + ); + assert!( + challenge_start + user_challenges_total * WORD_BYTES <= theta_start, + "user-phase challenge window [{challenge_start:#x}, {:#x}) overlaps the \ + named challenge slots at THETA_MPTR = {theta_start:#x}; theta's squeeze \ + would silently overwrite a user challenge", + challenge_start + user_challenges_total * WORD_BYTES, + ); + } let total_advices: usize = meta.num_user_advices.iter().sum(); let lookup_helper_chunks_total: usize = meta.lookup_chunks.iter().sum(); @@ -1432,6 +1499,114 @@ mod tests { ); } + /// P8 (L-5): a circuit with user-phase challenges must get a challenge + /// window that ends at or before THETA_MPTR, or theta's unconditional + /// squeeze silently overwrites user challenge 0. + #[test] + fn user_phase_challenge_window_precedes_theta() { + let meta = ConstraintSystemMeta { + num_user_advices: vec![1, 1], + num_user_challenges: vec![1, 2], + challenge_indices: vec![0, 1, 2], + ..ConstraintSystemMeta::default() + }; + let vk = synthetic_vk(); + let layout = VerifierMemoryLayout::new( + &meta, + &vk, + Ptr::memory(0x2000), + VerifierMemoryLayoutConfig::default(), + ); + let challenge = layout.challenge_mptr.value().as_usize(); + let theta = layout.theta_mptr.value().as_usize(); + assert!( + challenge + 3 * WORD_BYTES <= theta, + "user challenge window [{challenge:#x}, {:#x}) must end before \ + THETA_MPTR = {theta:#x}", + challenge + 3 * WORD_BYTES + ); + // With zero user challenges the two legitimately coincide. + let empty_layout = VerifierMemoryLayout::new( + &ConstraintSystemMeta::default(), + &vk, + Ptr::memory(0x2000), + VerifierMemoryLayoutConfig::default(), + ); + assert_eq!( + empty_layout.challenge_mptr.value().as_usize(), + empty_layout.theta_mptr.value().as_usize(), + ); + } + + /// P8 (L-5): a window sized for fewer slots than the transcript parser + /// squeezes must refuse to plan. + #[test] + #[should_panic(expected = "user-phase challenge window is sized for")] + fn undersized_user_challenge_window_is_rejected() { + let meta = ConstraintSystemMeta { + num_user_advices: vec![1], + num_user_challenges: vec![2], + challenge_indices: vec![0], + ..ConstraintSystemMeta::default() + }; + let vk = synthetic_vk(); + let _ = VerifierMemoryLayout::new( + &meta, + &vk, + Ptr::memory(0x2000), + VerifierMemoryLayoutConfig::default(), + ); + } + + /// P9 (L-7): across instance-count and rotation shapes, the + /// batch-inversion scratch must hold exactly the run the Lagrange block + /// writes, and the denominator region must match the input count -- the + /// two regions are adjacent with zero slack, and an overflow corrupts + /// denominator[0] without reverting. + #[test] + fn batch_invert_scratch_capacity_matches_lagrange_run() { + let vk = synthetic_vk(); + for (num_instances, rotation_last) in + [(0usize, -1i32), (1, -1), (2, -3), (19, -6), (200, -6)] + { + let meta = ConstraintSystemMeta { + rotation_last, + ..ConstraintSystemMeta::default() + }; + let layout = VerifierMemoryLayout::new( + &meta, + &vk, + Ptr::memory(0x2000), + VerifierMemoryLayoutConfig { + num_instances, + ..VerifierMemoryLayoutConfig::default() + }, + ); + let n = batch_invert_input_words(&meta, num_instances); + let scratch = layout + .map + .region("batch_invert_scratch") + .expect("batch_invert_scratch region is registered"); + let denoms = layout + .map + .region("lagrange_denoms") + .expect("lagrange_denoms region is registered"); + assert_eq!(denoms.len, n * WORD_BYTES); + assert_eq!( + scratch.len, + n.saturating_sub(2) * WORD_BYTES + MODEXP_FRAME_BYTES, + "scratch must hold n-2 prefix products plus one modexp frame \ + for n = {n} (num_instances = {num_instances})" + ); + assert_eq!( + scratch.start + scratch.len, + denoms.start, + "regions are adjacent by construction; the capacity assert is \ + what keeps the adjacency safe" + ); + } + } + #[test] fn fixed_low_memory_regions_are_planner_registered() { let meta = ConstraintSystemMeta { diff --git a/proofs/solidity-verifier/src/lowering/protocol/mod.rs b/proofs/solidity-verifier/src/lowering/protocol/mod.rs index 42cd838c6..c3a00a592 100644 --- a/proofs/solidity-verifier/src/lowering/protocol/mod.rs +++ b/proofs/solidity-verifier/src/lowering/protocol/mod.rs @@ -465,6 +465,31 @@ impl ProtocolPlan { // Read (num_fixed_columns - num_simple_selectors) fixed evaluations. // Simple selector columns are intentionally absent from the proof // scalar stream and are filled by the quotient/linearization path. + // + // I-6 (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the + // midnight-proofs verifier sizes this proof section COLUMN-based + // (`num_fixed_columns - num_simple_selectors`) while this generator + // sizes it QUERY-based (non-simple fixed queries). The two agree + // only when every non-simple fixed column is queried exactly once: + // a rotated or repeated fixed query would make the native verifier + // under-read and the generated verifier over-read the same proof + // bytes, silently desynchronizing every later transcript offset. + // Reject the divergence at plan time instead of inheriting it. + let non_simple_fixed_queries = fixed_queries + .iter() + .filter(|q| !simple_selector_cols.contains(&q.column)) + .count(); + assert_eq!( + non_simple_fixed_queries, + num_fixeds - simple_selector_cols.len(), + "fixed-eval section mismatch: {non_simple_fixed_queries} non-simple fixed \ + quer{} vs {} fixed columns minus {} simple selectors; the native verifier \ + reads the column-based count while this generator reads the query-based \ + count, so the proof scalar stream would desynchronize", + if non_simple_fixed_queries == 1 { "y" } else { "ies" }, + num_fixeds, + simple_selector_cols.len(), + ); proof.evals.extend( fixed_queries .iter() diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul index 1bdc89eb5..a261ea2fd 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul @@ -199,6 +199,14 @@ // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -236,6 +244,10 @@ // 3. folds the RHS carried point and fixed-base scalar tail into // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for // randomized batching in FinalPairing.yul. + // `r` is consumed only by the canonicality guards in the + // carried-scalar and fixed-base-tail arms; renders whose + // accumulator layout has neither (e.g. point_pair with no tail) + // legally leave it unused. function validate_public_accumulator(success, r) -> out { out := success let bits := {{ self.expected_num_acc_limb_bits }} diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index fae7c3de8..4eb731e4e 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -155,8 +155,12 @@ // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := {{ memory.constructor_g1msm_smoke_scratch_mptr|hex() }} for { let off := 0 } lt(off, {{ constructor_g1msm_smoke_input_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { mstore(add(msm_scratch, off), 0) From 86b262e02e4595ae0f9df174458f38b80416e8ed Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 09:48:15 +0100 Subject: [PATCH 095/108] =?UTF-8?q?feat(solidity-verifier):=20runtime=20ha?= =?UTF-8?q?rdening=20=E2=80=94=20VM=20operand=20clamps,=20typed=20errors,?= =?UTF-8?q?=20alpha=20vk-binding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three runtime-template findings from the 2026-08 review: P12 (L-6) — the compact quotient VM's operands were raw memory pointers whose safety rested entirely on the VK codehash pin plus build-time validation. The interpreter now clamps every decoded memory-pointer operand (simple, fused, run-loop, and 7-limb forms, including vector bases and the modarith7 condition pointer) against the coarse [operand_lo, operand_hi] union of the plan's quotient read windows — computed by the same quotient_read_windows() the build-time validator uses, so the two layers cannot drift. Single-comparison wrap-around form, ~6 gas per operand. FOLD_SELECTOR's bucket index and y-power gap are clamped against their codegen-known table sizes, and ADD/MUL pops revert at the stack floor, which the terminal eq(q_sp, base) check cannot do for balanced underflows. Wide (u16) constant-table indexes get the same clamp; u8 forms stay build-time-validated with the rationale documented. P4 (L-3) — verifyProof could only ever revert with empty returndata, so malformed calldata, a swapped VK, a non-canonical scalar, a failed precompile, and a rejected proof were indistinguishable. The verify path now reverts with one of seven declared custom errors (BadCalldataShape, VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, ProofRejected, QuotientProgramInvalid) via a fail(sel) helper writing the selector to legal 0x00 scratch; the quotient VM uses its own q_program_fail() since it renders into both contracts. Constructor smoke probes intentionally keep bare reverts (user-scoped decision). NatSpec now states the never-returns-false semantics and documents the exact calldatasize pin — ERC-2771 forwarders and calldata-appending relayers cannot call the verifier directly (L-4, keep-and-document decision). Selectors are pinned against keccak256 of the declared signatures by p4_error_selectors_match_declared_errors, and typed_errors_identify_rejection_classes decodes three classes end-to-end under revm. I-7 — the accumulator/KZG batching randomizer alpha hashed only the domain tag and four G1 points, binding the VK transitively. vk_digest now joins the preimage (verifier-local randomness, no prover interaction); the batch frame grew one word and its layout constants shifted accordingly. All fixture artifacts re-render, compile under pinned solc, and verify real proofs in revm; the bounded-gas invariant still holds. Co-Authored-By: Claude Fable 5 --- .../src/lowering/layout/mod.rs | 28 +++-- proofs/solidity-verifier/src/lowering/plan.rs | 114 +++++++++++++----- .../src/lowering/quotient.rs | 5 + .../src/lowering/render/models.rs | 20 +++ .../solidity-verifier/src/lowering/tests.rs | 77 ++++++++++-- proofs/solidity-verifier/src/test.rs | 62 ++++++++++ .../templates/contracts/Halo2Verifier.sol | 49 +++++++- .../quotient_numerator/QuotientHelpers.yul | 10 ++ .../QuotientNumeratorBlock.yul | 84 +++++++++++-- .../partials/verifier/AssemblyHelpers.yul | 28 +++-- .../templates/partials/verifier/Constants.sol | 15 +++ .../partials/verifier/FinalPairing.yul | 7 +- .../templates/partials/verifier/Lagrange.yul | 2 +- .../verifier/QuotientAndLinearization.yul | 10 +- .../partials/verifier/TraceReturn.yul | 2 +- .../verifier/TranscriptProofParser.yul | 10 +- .../templates/partials/verifier/VkLoading.yul | 8 +- 17 files changed, 443 insertions(+), 88 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 709fc99e6..6e8378d32 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -112,8 +112,9 @@ pub(crate) const PAIRING_STATIC_WORKING_WORDS: usize = PAIRING_TWO_PAIR_BYTES / /// /// Placed past the end of the accumulator pairing-batch hash frame, which /// occupies `[PAIRING_BATCH_PTR, PAIRING_BATCH_PTR + PAIRING_BATCH_HASH_BYTES)` -/// = `[0x1000, 0x1220)`. Starting lower would put the last word of the hashed -/// ACC_LHS copy inside this scratch. +/// = `[0x1000, 0x1240)` (tag + vk_digest + four G1 points since audit I-7). +/// Starting lower would put the last word of the hashed ACC_LHS copy inside +/// this scratch. /// The two regions carry different `MemoryPhase`s, and `MemoryLifetime:: /// intersects` treats distinct phases as never co-live, so the planner cannot /// catch that overlap -- it has to be avoided by construction here. @@ -275,16 +276,23 @@ pub(crate) mod accumulator { /// deployed verifier on accept/reject. pub(crate) const PAIRING_BATCH_DOMAIN_TAG_HEX: &str = "0x70616972696e672d62617463682d6163632d6b7a670000000000000000"; + /// VK digest offset inside the batch hash frame (I-7, + /// docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): alpha was previously a + /// function of the four G1 points alone, binding the verifying key only + /// transitively. Absorbing `vk_digest` makes the binding local at zero + /// marginal cost -- alpha is verifier-local batching randomness, so no + /// prover interaction changes. + pub(crate) const PAIRING_BATCH_VK_DIGEST_OFFSET: usize = WORD_BYTES; /// KZG pairing RHS point offset inside the batch hash frame. - pub(crate) const PAIRING_BATCH_RHS_OFFSET: usize = WORD_BYTES; + pub(crate) const PAIRING_BATCH_RHS_OFFSET: usize = 2 * WORD_BYTES; /// KZG pairing LHS point offset inside the batch hash frame. - pub(crate) const PAIRING_BATCH_LHS_OFFSET: usize = WORD_BYTES + G1_BYTES; + pub(crate) const PAIRING_BATCH_LHS_OFFSET: usize = 2 * WORD_BYTES + G1_BYTES; /// Accumulator RHS point offset inside the batch hash frame. - pub(crate) const PAIRING_BATCH_ACC_RHS_OFFSET: usize = WORD_BYTES + 2 * G1_BYTES; + pub(crate) const PAIRING_BATCH_ACC_RHS_OFFSET: usize = 2 * WORD_BYTES + 2 * G1_BYTES; /// Accumulator LHS point offset inside the batch hash frame. - pub(crate) const PAIRING_BATCH_ACC_LHS_OFFSET: usize = WORD_BYTES + 3 * G1_BYTES; + pub(crate) const PAIRING_BATCH_ACC_LHS_OFFSET: usize = 2 * WORD_BYTES + 3 * G1_BYTES; /// Number of frame bytes absorbed into the accumulator/KZG batch challenge. - pub(crate) const PAIRING_BATCH_HASH_BYTES: usize = WORD_BYTES + 4 * G1_BYTES; + pub(crate) const PAIRING_BATCH_HASH_BYTES: usize = 2 * WORD_BYTES + 4 * G1_BYTES; } pub(crate) mod quotient_limb { @@ -847,10 +855,12 @@ mod tests { accumulator::PAIRING_BATCH_PTR, super::LOW_MEMORY_SCRATCH_START ); - assert_eq!(accumulator::PAIRING_BATCH_HASH_BYTES, 0x220); + // One word longer since the vk_digest joined the alpha preimage + // (audit I-7): tag + vk_digest + four G1 points. + assert_eq!(accumulator::PAIRING_BATCH_HASH_BYTES, 0x240); assert_eq!( super::FINAL_PAIRING_SCRATCH_START, - super::LOW_MEMORY_SCRATCH_START + 0x220 + super::LOW_MEMORY_SCRATCH_START + 0x240 ); assert_eq!(quotient_limb::LIMBS, 7); assert_eq!(quotient_limb::PAIRWISE_TERMS, 49); diff --git a/proofs/solidity-verifier/src/lowering/plan.rs b/proofs/solidity-verifier/src/lowering/plan.rs index ed1046335..6c09c98b1 100644 --- a/proofs/solidity-verifier/src/lowering/plan.rs +++ b/proofs/solidity-verifier/src/lowering/plan.rs @@ -144,6 +144,8 @@ impl LoweringPlan { vk_mptr, &memory, "ient_plan.selector_fold, + quotient_operand_bounds(&meta, &data, &vk, vk_mptr, &memory), + meta.num_simple_selectors, ); let plan = Self { @@ -361,36 +363,14 @@ impl LoweringPlan { /// contain -- a read outside them is either uninitialized memory in the /// split path or live verifier state in the inline path. pub(crate) fn quotient_read_model(&self) -> vm::QuotientReadModel { - let theta = self.data.theta_mptr.value().as_usize(); - let instance_eval = self.memory.instance_eval_mptr.value().as_usize(); vm::QuotientReadModel { - windows: vec![ - vm::QuotientReadWindow { - name: "vk_payload", - start: self.vk_mptr.value().as_usize(), - len: self.vk.len(), - }, - vm::QuotientReadWindow { - name: "user_challenges", - start: self.data.challenge_mptr.value().as_usize(), - len: self.meta.num_user_challenges.iter().sum::() - * layout::memory::WORD_BYTES, - }, - vm::QuotientReadWindow { - name: "challenge_and_common_slots", - // Ends one word past `instance_eval`, matching the frame - // window in `Halo2QuotientEvaluator::validate_layout`. - // `quotient_eval` sits immediately above and is a write - // target, not a VM input. - start: theta, - len: (instance_eval + layout::memory::WORD_BYTES).saturating_sub(theta), - }, - vm::QuotientReadWindow { - name: "decoded_proof_evals", - start: self.memory.reversed_evals_mptr.value().as_usize(), - len: self.meta.num_evals * layout::memory::WORD_BYTES, - }, - ], + windows: quotient_read_windows( + &self.meta, + &self.data, + &self.vk, + self.vk_mptr, + &self.memory, + ), token_bases: vec![ (vm::Q_MEM_L0, self.memory.l_0_mptr.value().as_usize()), (vm::Q_MEM_L_LAST, self.memory.l_last_mptr.value().as_usize()), @@ -406,7 +386,10 @@ impl LoweringPlan { vm::Q_MEM_TRASH_CHALLENGE, self.memory.trash_challenge_mptr.value().as_usize(), ), - (vm::Q_MEM_INSTANCE_EVAL, instance_eval), + ( + vm::Q_MEM_INSTANCE_EVAL, + self.memory.instance_eval_mptr.value().as_usize(), + ), ], } } @@ -424,3 +407,74 @@ impl LoweringPlan { .unwrap_or(0) } } + +/// The memory windows the compact quotient VM is allowed to load from, +/// shared by the build-time pointer validator +/// ([`LoweringPlan::quotient_read_model`]) and the runtime operand clamps +/// rendered into the interpreter (P12/L-6, +/// docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). One source of truth so the +/// two layers cannot drift. +pub(crate) fn quotient_read_windows( + meta: &ConstraintSystemMeta, + data: &Data, + vk: &Halo2VerifyingKey, + vk_mptr: Ptr, + memory: &VerifierMemoryLayout, +) -> Vec { + let theta = data.theta_mptr.value().as_usize(); + let instance_eval = memory.instance_eval_mptr.value().as_usize(); + vec![ + vm::QuotientReadWindow { + name: "vk_payload", + start: vk_mptr.value().as_usize(), + len: vk.len(), + }, + vm::QuotientReadWindow { + name: "user_challenges", + start: data.challenge_mptr.value().as_usize(), + len: meta.num_user_challenges.iter().sum::() * layout::memory::WORD_BYTES, + }, + vm::QuotientReadWindow { + name: "challenge_and_common_slots", + // Ends one word past `instance_eval`, matching the frame + // window in `Halo2QuotientEvaluator::validate_layout`. + // `quotient_eval` sits immediately above and is a write + // target, not a VM input. + start: theta, + len: (instance_eval + layout::memory::WORD_BYTES).saturating_sub(theta), + }, + vm::QuotientReadWindow { + name: "decoded_proof_evals", + start: memory.reversed_evals_mptr.value().as_usize(), + len: meta.num_evals * layout::memory::WORD_BYTES, + }, + ] +} + +/// The coarse `[lo, hi]` bound over every non-empty read window, rendered +/// into the interpreter's operand clamps. `hi` is the last legally loadable +/// word address (inclusive). Build-time validation still enforces exact +/// per-window membership; the runtime clamp is defence in depth for a VM +/// whose program bytes are trusted only through the VK codehash pin. +pub(crate) fn quotient_operand_bounds( + meta: &ConstraintSystemMeta, + data: &Data, + vk: &Halo2VerifyingKey, + vk_mptr: Ptr, + memory: &VerifierMemoryLayout, +) -> (usize, usize) { + let windows = quotient_read_windows(meta, data, vk, vk_mptr, memory); + let lo = windows + .iter() + .filter(|w| w.len > 0) + .map(|w| w.start) + .min() + .expect("at least one non-empty quotient read window"); + let hi = windows + .iter() + .filter(|w| w.len > 0) + .map(|w| w.start + w.len - layout::memory::WORD_BYTES) + .max() + .expect("at least one non-empty quotient read window"); + (lo, hi) +} diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index e0d295d68..04d8fea07 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -149,6 +149,8 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { vk_mptr: Ptr, memory: &VerifierMemoryLayout, selector_fold: &SelectorFoldPlan, + operand_bounds: (usize, usize), + num_selector_buckets: usize, ) -> (QuotientProgram, usize, QuotientStateSlots) { let quotient_program_chunks = PackedProgramCodec::encode_words(&build.bytes); let quotient_const_words = vk.quotient_const_words; @@ -185,6 +187,9 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { selector_tail_updates: Self::selector_tail_updates(selector_fold), stack_mptr: quotient_stack_mptr, program_mptr, + operand_lo: operand_bounds.0, + operand_hi: operand_bounds.1, + num_selector_buckets, }; (program, quotient_stack_mptr, state_slots) diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index e6fabab76..1e3c1def9 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -105,6 +105,7 @@ pub(crate) struct ModexpTemplateConstants { pub(crate) struct AccumulatorTemplateConstants { pub(crate) limbs_per_word: usize, pub(crate) pairing_batch_domain_tag_hex: &'static str, + pub(crate) pairing_batch_vk_digest_offset: usize, pub(crate) pairing_batch_rhs_offset: usize, pub(crate) pairing_batch_lhs_offset: usize, pub(crate) pairing_batch_acc_rhs_offset: usize, @@ -220,6 +221,7 @@ impl Default for TemplateConstants { accumulator: AccumulatorTemplateConstants { limbs_per_word: layout::accumulator::LIMBS_PER_WORD, pairing_batch_domain_tag_hex: layout::accumulator::PAIRING_BATCH_DOMAIN_TAG_HEX, + pairing_batch_vk_digest_offset: layout::accumulator::PAIRING_BATCH_VK_DIGEST_OFFSET, pairing_batch_rhs_offset: layout::accumulator::PAIRING_BATCH_RHS_OFFSET, pairing_batch_lhs_offset: layout::accumulator::PAIRING_BATCH_LHS_OFFSET, pairing_batch_acc_rhs_offset: layout::accumulator::PAIRING_BATCH_ACC_RHS_OFFSET, @@ -702,6 +704,19 @@ pub(crate) struct QuotientProgram { pub(crate) stack_mptr: usize, /// Memory pointer to the first encoded program word. pub(crate) program_mptr: usize, + /// Lowest word address a VM memory operand may load from (P12/L-6). + /// + /// Coarse `[operand_lo, operand_hi]` clamp over the union of the plan's + /// quotient read windows, rendered into the interpreter's operand-decode + /// arms. Build-time `validate_quotient_mem_ptrs` still enforces exact + /// per-window membership; the runtime clamp is defence in depth for a + /// program trusted only through the VK codehash pin. + pub(crate) operand_lo: usize, + /// Highest word address a VM memory operand may load from (inclusive). + pub(crate) operand_hi: usize, + /// Number of simple-selector accumulator buckets addressable by + /// FOLD_SELECTOR's index operand (P12/L-6). + pub(crate) num_selector_buckets: usize, } #[derive(Clone, Copy, Debug)] @@ -1199,6 +1214,11 @@ mod tests { selector_tail_updates: vec![], stack_mptr: 0, program_mptr: 0, + // Synthetic model: a permissive clamp window keeps the + // rendered guards inert for layout-shape tests. + operand_lo: 0, + operand_hi: usize::MAX, + num_selector_buckets: 0, }), pcs_computations: vec![], simple_selector_cols: vec![], diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index ceb8d02c8..9626e1dc3 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1474,22 +1474,22 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { let pcs_codegen = include_str!("kzg/mod.rs"); assert!( - verifier_template.contains("if iszero(success) { revert(0, 0) }\n }\n\n {%- if self.expected_has_accumulator %}\n // Fail malformed accumulator public inputs before transcript"), + verifier_template.contains("if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) }\n }\n\n {%- if self.expected_has_accumulator %}\n // Fail malformed accumulator public inputs before transcript"), "ABI/proof length/instance shape checks should fail before accumulator or transcript parsing" ); assert!( - verifier_template.contains("success := validate_public_accumulator(success, r)\n if iszero(success) { revert(0, 0) }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), + verifier_template.contains("success := validate_public_accumulator(success, r)\n if iszero(success) { fail(ERR_BAD_POINT_ENCODING) }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), "accumulator precheck should fail before transcript parsing" ); assert!( verifier_template.contains( - "success := and(success, lt(inst_be, r))\n // Instances are passed BE in calldata, matching the\n // Keccak Fq transcript input.\n buf_len := common_word(buf_len, inst_be)\n }\n if iszero(success) { revert(0, 0) }" + "success := and(success, lt(inst_be, r))\n // Instances are passed BE in calldata, matching the\n // Keccak Fq transcript input.\n buf_len := common_word(buf_len, inst_be)\n }\n if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) }" ), "non-canonical public instances should fail before proof transcript parsing" ); assert!( verifier_template.contains( - "if iszero(success) { revert(0, 0) }\n\n {%- match quotient_external %}" + "if iszero(success) { fail(ERR_PRECOMPILE_FAILED) }\n\n {%- match quotient_external %}" ), "failed Lagrange/common-polynomial setup should fail before quotient reconstruction" ); @@ -1505,7 +1505,7 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { } assert!( verifier_template.contains( - "if iszero(success) { revert(0, 0) }\n success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR)" + "if iszero(success) { fail(ERR_PRECOMPILE_FAILED) }\n success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR)" ), "final pairing block should revert before staging/calling the pairing precompile when success is already false" ); @@ -2126,8 +2126,8 @@ fn quotient_vm_runtime_asserts_exact_program_termination() { let verifier_template = verifier_template_corpus(); assert!( - verifier_template.contains("if iszero(eq(q_pc, q_end)) { revert(0, 0) }") - && verifier_template.contains("if q_has_top { revert(0, 0) }"), + verifier_template.contains("if iszero(eq(q_pc, q_end)) { q_program_fail() }") + && verifier_template.contains("if q_has_top { q_program_fail() }"), "quotient VM must fail closed when bytecode over-runs q_end or leaves a live stack value" ); } @@ -2302,7 +2302,7 @@ fn production_verifier_documents_revert_or_true_policy() { && verifier_template .contains("ret := success\n if iszero(ret) { leave }") && verifier_template.contains( - "ret := and(ret, eq(mload(scratch), 1))\n if iszero(ret) { revert(0, 0) }\n ret := 1", + "ret := and(ret, eq(mload(scratch), 1))\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }\n ret := 1", ), "final pairing helper must revert on pairing failure and normalize success to one" ); @@ -2321,6 +2321,60 @@ fn production_verifier_documents_revert_or_true_policy() { ); } +/// P4 (L-3): the Yul revert sites carry hardcoded 4-byte selectors while the +/// Solidity ABI carries the `error` declarations; pin the two against each +/// other so neither can drift silently. +#[test] +fn p4_error_selectors_match_declared_errors() { + use sha3::{Digest, Keccak256}; + + let verifier_template = include_str!("../../templates/contracts/Halo2Verifier.sol"); + let constants_template = include_str!("../../templates/partials/verifier/Constants.sol"); + let helpers_template = + include_str!("../../templates/partials/quotient_numerator/QuotientHelpers.yul"); + + for (signature, constant_name) in [ + ("BadCalldataShape()", "ERR_BAD_CALLDATA_SHAPE"), + ("VkMismatch()", "ERR_VK_MISMATCH"), + ("NonCanonicalScalar()", "ERR_NON_CANONICAL_SCALAR"), + ("BadPointEncoding()", "ERR_BAD_POINT_ENCODING"), + ("PrecompileFailed()", "ERR_PRECOMPILE_FAILED"), + ("ProofRejected()", "ERR_PROOF_REJECTED"), + ("QuotientProgramInvalid()", "ERR_QUOTIENT_PROGRAM_INVALID"), + ] { + let digest = Keccak256::digest(signature.as_bytes()); + let selector = format!( + "0x{:02x}{:02x}{:02x}{:02x}", + digest[0], digest[1], digest[2], digest[3] + ); + let error_name = signature.trim_end_matches("()"); + assert!( + verifier_template.contains(&format!("error {error_name}();")), + "Halo2Verifier.sol must declare `error {error_name}();` so the ABI carries it" + ); + assert!( + constants_template.contains(&selector), + "Constants.sol selector for {signature} must be {selector}" + ); + assert!( + constants_template.contains(constant_name), + "Constants.sol must define {constant_name}" + ); + } + // The quotient VM's dedicated helper hardcodes the QuotientProgramInvalid + // selector because it renders in both the verifier and the standalone + // evaluator assembly. + let digest = Keccak256::digest(b"QuotientProgramInvalid()"); + let selector = format!( + "0x{:02x}{:02x}{:02x}{:02x}", + digest[0], digest[1], digest[2], digest[3] + ); + assert!( + helpers_template.contains(&format!("shl(224, {selector})")), + "q_program_fail must hardcode the QuotientProgramInvalid selector {selector}" + ); +} + #[test] fn templates_do_not_write_solidity_reserved_memory_slots() { let verifier_template = verifier_template_corpus(); @@ -2336,6 +2390,13 @@ fn templates_do_not_write_solidity_reserved_memory_slots() { ("QuotientHelpers.yul", quotient_helpers), ("Halo2VerifyingKey.sol", vk_template), ] { + // The one sanctioned use of Solidity's 0x00 scratch word: the typed + // custom-error revert idiom (P4/L-3) writes a 4-byte selector there + // immediately before reverting. It is terminal and 0x00..0x3f is + // legal scratch, so exempt exactly that pattern and keep every other + // low-memory write forbidden. + let source = source.replace("mstore(0x00, shl(224, ", ""); + let source = source.as_str(); for needle in [ "mstore(0,", "mstore(0x00,", diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 0e64ad5f7..62b7d9a63 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -3047,6 +3047,68 @@ fn malformed_proof_point_rejects_with_bounded_gas() { } } +/// P4 (L-3, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): rejections revert +/// with a typed 4-byte custom-error selector so integrators can distinguish +/// failure classes. Decode three representative classes end-to-end. +#[test] +fn typed_errors_identify_rejection_classes() { + use sha3::{Digest, Keccak256}; + + if !poseidon_inputs_available_for_evm() { + return; + } + let selector = |sig: &str| { + let d = Keccak256::digest(sig.as_bytes()); + vec![d[0], d[1], d[2], d[3]] + }; + + let fixture = create_property_poseidon_fixture(); + let mut deployed = deployed_separate_verifier(&fixture); + if !deployed_call_accepts(&mut deployed, &fixture, &fixture.proof, "valid proof") { + return; + } + + // (a) Trailing calldata byte -> BadCalldataShape (exact calldatasize pin; + // documented ERC-2771 incompatibility). + let mut trailing = encode_calldata(&fixture.proof, &fixture.instances); + trailing.push(0); + // (b) Non-canonical public instance (r) -> NonCanonicalScalar. + let mut bad_instance = encode_calldata(&fixture.proof, &fixture.instances); + let len = bad_instance.len(); + bad_instance[len - 32..].copy_from_slice( + &hex::decode("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001") + .expect("BLS12-381 r"), + ); + // (c) Off-curve proof point -> BadPointEncoding is checked only for pad / + // range violations; a canonical-but-off-curve point fails at the MSM, so + // expect PrecompileFailed or ProofRejected there instead. Use a pad-byte + // violation for the deterministic BadPointEncoding class. + let layout = proof_g1_layout(&fixture); + let mut bad_pad = fixture.proof.clone(); + bad_pad[layout.repacked_offsets[0]] = 1; + let bad_pad = encode_calldata(&bad_pad, &fixture.instances); + + for (name, calldata, expected_sig) in [ + ("trailing calldata byte", trailing, "BadCalldataShape()"), + ("non-canonical instance", bad_instance, "NonCanonicalScalar()"), + ("pad-byte violation", bad_pad, "BadPointEncoding()"), + ] { + match deployed + .evm + .try_call_with_gas(deployed.verifier_address, calldata, 30_000_000) + { + CallOutcome::Revert { output, .. } => { + assert_eq!( + output, + selector(expected_sig), + "{name} must revert with {expected_sig}" + ); + } + outcome => panic!("{name} did not revert: {outcome:?}"), + } + } +} + /// H-1 provenance (docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the /// production Midnight SRS assets must bind their `s_g2` — the element the /// deployed verifier's `NEG_S_G2_BASE` is derived from — to the same tau diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol index b0dfc4967..c40c68e41 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + {% include "partials/verifier/Constants.sol" %} {% include "partials/verifier/PrecompileSmoke.sol" %} @@ -58,9 +86,19 @@ contract Halo2Verifier { /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -86,7 +124,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload({{ abi_selector_bytes|hex() }}), {{ abi_proof_head_offset|hex() }}), eq(calldataload({{ abi_instances_head_cptr|hex() }}), sub(NUM_INSTANCE_CPTR, {{ abi_selector_bytes|hex() }})))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientHelpers.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientHelpers.yul index a9ec4d9e7..41c625e58 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientHelpers.yul @@ -1,3 +1,13 @@ + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul index a0b255e2c..0d1b1862b 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul @@ -1,3 +1,28 @@ +{#- + P12 (L-6, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md) runtime operand + clamps. The VM program is trusted only through the VK codehash pin; + build-time validate_quotient_mem_ptrs proves exact window membership, but + the deployed interpreter re-checks every decoded memory-pointer operand + against the coarse [operand_lo, operand_hi] union of the planned read + windows so a substituted or corrupted VK payload cannot read arbitrary + verifier state. Single-comparison form: unsigned wrap makes + sub(ptr, lo) > (hi - lo) cover both bounds (~6 gas per operand). + u8 constant-table indexes stay unguarded: their drift is bounded to + 0x1FE0 bytes inside the VK-reserved region and covered by build-time + validate_quotient_const_slots. +-#} +{%- macro q_ptr_guard(ptr) %} + if gt(sub({{ ptr }}, {{ program.operand_lo|hex() }}), {{ (program.operand_hi - program.operand_lo)|hex() }}) { q_program_fail() } +{%- endmacro %} +{#- 7-word limb-vector bases must leave room for the whole vector. -#} +{%- macro q_vec7_guard(ptr) %} + if gt(sub({{ ptr }}, {{ program.operand_lo|hex() }}), {{ (program.operand_hi - program.operand_lo - 0xc0)|hex() }}) { q_program_fail() } +{%- endmacro %} +{#- Pops revert at the stack floor; the terminal eq(q_sp, base) check + cannot catch a BALANCED underflow, this can. -#} +{%- macro q_pop_guard() %} + if eq(q_sp, {{ program.stack_mptr|hex() }}) { q_program_fail() } +{%- endmacro %} // =============================================================== // Batched identity numerator / linearization target. // @@ -467,6 +492,7 @@ // the smaller u16 form or token map. let q_ptr := shr(224, mload(q_pc)) q_pc := add(q_pc, {{ template_constants.quotient_vm.byte_u32_bytes|hex() }}) + {%- call q_ptr_guard("q_ptr") %} // Load one canonical Fr word from generated memory and // push it through the cached-top stack discipline. if q_has_top { @@ -516,7 +542,7 @@ {%- endif %} // A token not advertised by the VM usage manifest is // impossible for valid generated bytecode. - default { revert(0, 0) } + default { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -566,7 +592,8 @@ {%- if program.mem_usage.instance_eval %} case {{ template_constants.quotient_vm.mem.instance_eval|hex() }} { q_ptr := add(INSTANCE_EVAL_MPTR, q_off) } {%- endif %} - default { revert(0, 0) } + default { q_program_fail() } + {%- call q_ptr_guard("q_ptr") %} if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -583,6 +610,7 @@ // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_ptr") %} if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -596,6 +624,7 @@ case {{ template_constants.quotient_vm.op.add|hex() }} { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + {%- call q_pop_guard() %} q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -605,6 +634,7 @@ case {{ template_constants.quotient_vm.op.mul|hex() }} { // Same stack contract as ADD, with multiplication // reduced directly modulo Fr. + {%- call q_pop_guard() %} q_sp := sub(q_sp, 0x20) q_top := mulmod(mload(q_sp), q_top, r) } @@ -667,7 +697,9 @@ // constant tables. let qconst := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) - q_top := addmod(q_top, mload(add(q_const_mptr, shl(5, qconst))), r) + let q_const_ptr := add(q_const_mptr, shl(5, qconst)) + {%- call q_ptr_guard("q_const_ptr") %} + q_top := addmod(q_top, mload(q_const_ptr), r) } {%- endif %} {%- if program.op_usage.mul_const %} @@ -676,7 +708,9 @@ // Two-byte constant-index multiply. let qconst := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) - q_top := mulmod(q_top, mload(add(q_const_mptr, shl(5, qconst))), r) + let q_const_ptr := add(q_const_mptr, shl(5, qconst)) + {%- call q_ptr_guard("q_const_ptr") %} + q_top := mulmod(q_top, mload(q_const_ptr), r) } {%- endif %} {%- if program.op_usage.add_mem_u16 %} @@ -686,6 +720,7 @@ // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_ptr") %} q_top := addmod(q_top, mload(q_ptr), r) } {%- endif %} @@ -695,6 +730,7 @@ // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_ptr") %} q_top := mulmod(q_top, mload(q_ptr), r) } {%- endif %} @@ -709,6 +745,8 @@ let q_rhs := and(shr(224, q_word), 0xffff) let qconst := byte(4, q_word) q_pc := add(q_pc, 5) + {%- call q_ptr_guard("q_lhs") %} + {%- call q_ptr_guard("q_rhs") %} q_top := addmod( q_top, mulmod( @@ -728,6 +766,7 @@ let q_ptr := shr(240, q_word) let qconst := byte(2, q_word) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_top := addmod( q_top, mulmod(mload(q_ptr), mload(add(q_const_mptr, shl(5, qconst))), r), @@ -744,6 +783,8 @@ let q_lhs := shr(240, q_word) let q_rhs := and(shr(224, q_word), 0xffff) q_pc := add(q_pc, {{ template_constants.quotient_vm.byte_u32_bytes|hex() }}) + {%- call q_ptr_guard("q_lhs") %} + {%- call q_ptr_guard("q_rhs") %} q_top := addmod(q_top, mulmod(mload(q_lhs), mload(q_rhs), r), r) } {%- endif %} @@ -762,6 +803,8 @@ let q_rhs := and(shr(224, q_word), 0xffff) let qconst := byte(4, q_word) q_pc := add(q_pc, 5) + {%- call q_ptr_guard("q_lhs") %} + {%- call q_ptr_guard("q_rhs") %} q_top := addmod( q_top, mulmod( @@ -787,6 +830,7 @@ let q_ptr := shr(240, q_word) let qconst := byte(2, q_word) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_top := addmod( q_top, mulmod(mload(q_ptr), mload(add(q_const_mptr, shl(5, qconst))), r), @@ -815,6 +859,7 @@ let q_ptr := shr(240, q_word) let qconst := byte(2, q_word) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_top := addmod( q_top, mulmod(mload(q_ptr), mload(add(q_const_mptr, shl(5, qconst))), r), @@ -829,6 +874,8 @@ let q_rhs := and(shr(224, q_word), 0xffff) let qconst := byte(4, q_word) q_pc := add(q_pc, 5) + {%- call q_ptr_guard("q_lhs") %} + {%- call q_ptr_guard("q_rhs") %} q_top := addmod( q_top, mulmod( @@ -882,6 +929,7 @@ let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -905,6 +953,7 @@ // loaded once and reused for all seven products. let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_lhs") %} let q_lhs_value := mload(q_lhs) if q_has_top { mstore(q_sp, q_top) @@ -916,6 +965,7 @@ let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_rhs") %} q_acc := addmod( q_acc, mulmod( @@ -948,6 +998,8 @@ let q_lhs_base := shr(240, q_word) let q_rhs_base := and(shr(224, q_word), 0xffff) q_pc := add(q_pc, {{ template_constants.quotient_vm.byte_u32_bytes|hex() }}) + {%- call q_vec7_guard("q_lhs_base") %} + {%- call q_vec7_guard("q_rhs_base") %} let q_coeff_pc := q_pc q_pc := add(q_pc, {{ template_constants.quotient_vm.limb_pairwise_coeffs }}) if q_has_top { @@ -1005,6 +1057,7 @@ // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_cond_ptr") %} } let q_acc := 0 @@ -1039,6 +1092,7 @@ let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1051,12 +1105,14 @@ for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_lhs") %} let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, {{ template_constants.quotient_vm.limb_count }}) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_rhs") %} q_acc := addmod( q_acc, mulmod( @@ -1076,6 +1132,8 @@ let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, {{ template_constants.quotient_vm.byte_u32_bytes|hex() }}) + {%- call q_vec7_guard("q_lhs_base") %} + {%- call q_vec7_guard("q_rhs_base") %} let q_coeff_pc := q_pc q_pc := add(q_pc, {{ template_constants.quotient_vm.limb_pairwise_coeffs }}) for { let q_i := 0 } lt(q_i, {{ template_constants.quotient_vm.limb_count }}) { q_i := add(q_i, 1) } { @@ -1101,6 +1159,7 @@ let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + {%- call q_ptr_guard("q_ptr") %} q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1115,6 +1174,8 @@ let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + {%- call q_ptr_guard("q_lhs") %} + {%- call q_ptr_guard("q_rhs") %} q_acc := addmod( q_acc, mulmod( @@ -1214,7 +1275,7 @@ {%- endfor %} } {%- endfor %} - default { revert(0, 0) } + default { q_program_fail() } } {%- endif %} {%- if program.op_usage.fold_main %} @@ -1246,6 +1307,11 @@ q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, {{ program.num_selector_buckets }})) { q_program_fail() } + if gt(q_sel_gap, {{ program.selector_max_power|hex() }}) { q_program_fail() } let q_eval := q_top q_has_top := 0 {%- if self.trace %} @@ -1273,21 +1339,21 @@ {%- endif %} // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, {{ program.stack_mptr|hex() }})) { revert(0, 0) } + if iszero(eq(q_sp, {{ program.stack_mptr|hex() }})) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index aac0dbc37..3a844a297 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -1,3 +1,11 @@ + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of @@ -11,8 +19,8 @@ // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := {{ memory.scalar_inv_scratch_mptr|hex() }} // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -22,8 +30,8 @@ mstore(add(p, {{ template_constants.modexp.base_offset|hex() }}), x) mstore(add(p, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2)) mstore(add(p, {{ template_constants.modexp.mod_offset|hex() }}), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, p, {{ template_constants.modexp.frame_bytes|hex() }}, p, {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } - if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, p, {{ template_constants.modexp.frame_bytes|hex() }}, p, {{ template_constants.modexp.output_bytes|hex() }})) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -83,16 +91,16 @@ let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -254,7 +262,7 @@ // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to @@ -273,6 +281,6 @@ // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index bddf29aef..d8a7f403b 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -197,6 +197,21 @@ uint256 internal constant ACC_RHS_MSM_GAS = {{ acc_rhs_msm_gas }}; {%- endif %} + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; diff --git a/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul b/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul index 758fc0d3a..3d2a12a7c 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/FinalPairing.yul @@ -15,8 +15,11 @@ { let batch_ptr := {{ memory.accumulator_pairing_batch_mptr|hex() }} - // Domain || KZG rhs/lhs || accumulator rhs/lhs. + // Domain || vk_digest || KZG rhs/lhs || accumulator rhs/lhs. + // vk_digest makes alpha's binding to the verifying key local + // instead of transitive-through-the-points (audit I-7). mstore(batch_ptr, {{ template_constants.accumulator.pairing_batch_domain_tag_hex }}) + mstore(add(batch_ptr, {{ template_constants.accumulator.pairing_batch_vk_digest_offset|hex() }}), mload(VK_DIGEST_MPTR)) mcopy(add(batch_ptr, {{ template_constants.accumulator.pairing_batch_rhs_offset|hex() }}), PAIRING_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) mcopy(add(batch_ptr, {{ template_constants.accumulator.pairing_batch_lhs_offset|hex() }}), PAIRING_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) mcopy(add(batch_ptr, {{ template_constants.accumulator.pairing_batch_acc_rhs_offset|hex() }}), ACC_RHS_MPTR, {{ template_constants.g1_bytes|hex() }}) @@ -75,7 +78,7 @@ // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) {%- if self.gas_checkpoints %} diff --git a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul index 0f6d5a85e..6c630586f 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul @@ -88,4 +88,4 @@ gas_checkpoint(11) // after Lagrange + instance evaluation block {%- endif %} - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } diff --git a/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul b/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul index f1242859c..062f59c61 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/QuotientAndLinearization.yul @@ -21,21 +21,21 @@ if iszero(and( eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } {%- when None %} {%- endmatch %} {%- if self.trace %} - if iszero(call(gas(), quotientEvaluator, 0, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { revert(0, 0) } + if iszero(call(gas(), quotientEvaluator, 0, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } {%- else %} // gas() forwarding is deliberate here, unlike the precompile // call sites: this is a regular contract call, so a reverting // or failing callee refunds its unused gas -- only precompile // ERRORS burn everything forwarded (EIP-2537). The callee is // also pinned by codehash above, not attacker-supplied. - if iszero(staticcall(gas(), quotientEvaluator, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { revert(0, 0) } + if iszero(staticcall(gas(), quotientEvaluator, {{ qext.frame_base|hex() }}, {{ qext.frame_len|hex() }}, q_out, {{ qext.output_len|hex() }})) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } {%- endif %} - if iszero(eq(returndatasize(), {{ qext.output_len|hex() }})) { revert(0, 0) } - if iszero(eq(mload(q_out), {{ qext.magic|hex_padded(64) }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ qext.output_len|hex() }})) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } + if iszero(eq(mload(q_out), {{ qext.magic|hex_padded(64) }})) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } // Word 1 is the negated y-batched identity numerator, stored // in the same memory slot used by the monolithic path. mstore(QUOTIENT_EVAL_MPTR, mload(add(q_out, 0x20))) diff --git a/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul b/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul index 7d3f27f40..aa27b06c6 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/TraceReturn.yul @@ -59,6 +59,6 @@ // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) diff --git a/proofs/solidity-verifier/templates/partials/verifier/TranscriptProofParser.yul b/proofs/solidity-verifier/templates/partials/verifier/TranscriptProofParser.yul index 80e97e1cc..0561aaf53 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/TranscriptProofParser.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/TranscriptProofParser.yul @@ -65,7 +65,7 @@ // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } {%- if self.gas_checkpoints %} @@ -316,7 +316,7 @@ // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, {{ template_constants.word_bytes|hex() }}) @@ -379,7 +379,7 @@ {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) {%- if self.trace %} trace_u256(proof_eval_trace_id, eval) @@ -413,11 +413,11 @@ // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } {%- if self.gas_checkpoints %} gas_checkpoint(10) // after evaluations + x1/x2 + f_com + x3 + q_evals + x4 + pi (transcript done) diff --git a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul index 35aca7478..f8939530f 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul @@ -67,7 +67,7 @@ if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -85,7 +85,7 @@ success := and(success, eq(mload(ACC_OFFSET_MPTR), {{ expected_acc_offset }})) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), {{ expected_num_acc_limbs }})) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), {{ expected_num_acc_limb_bits }})) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -109,7 +109,7 @@ ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } {%- if self.expected_has_accumulator %} @@ -127,7 +127,7 @@ // success-plumbing style as other helper calls; this boundary is // where the verifier converts failure to a revert. success := validate_public_accumulator(success, r) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } {%- endif %} {%- if self.gas_checkpoints %} From ed9f455cf809f106cf83168eb768fe39e908b636 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 09:55:09 +0100 Subject: [PATCH 096/108] feat(solidity-verifier): on-chain BUILD_ID provenance and a template-tree digest gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P10 (L-8) — nothing in a deployed artifact identified the generator build: no commit, no feature profile, no SRS identity, and CBOR metadata is stripped. Every rendered verifier now carries `bytes32 public constant BUILD_ID`, a keccak over the build's identity components: the crate's enabled feature profile (exported by the new build.rs), the vk_digest, the expected VK runtime codehash (zero when embedded), an SRS fingerprint keccak(n || G2 || s_g2 || [tau]G1) — the tau commitment reuses the H-1 Pippenger helper, and n + tau IS the SRS identity — plus an optional 32-byte deployment provenance tag supplied via the new `RenderOptions::provenance` (Copy-friendly `[u8; 32]`, typically keccak of the generator commit + build context). Provenance is None by default so repository fixtures stay byte-stable across commits; deployment builds set it and publish the preimage components in the deployment record. Tested: renders are deterministic, and the provenance tag changes BUILD_ID and nothing else. P14 (L-1) — the replay tests compile committed pre-rendered sources, so a template edit without fixture regeneration kept every test green while deployable artifacts drifted (the review demonstrated a malicious Yul edit surviving the full default test suite). New feature-ungated tests/template_digest.rs pins a keccak of the sorted templates/ tree; any template edit now fails default CI until the fixtures are regenerated, the README stamps updated, and the digest re-pinned. The deeper L-1 legs (expression front-end certification, native-kernel differential) remain tracked future work. Co-Authored-By: Claude Fable 5 --- proofs/solidity-verifier/build.rs | 23 +++++++ proofs/solidity-verifier/src/api.rs | 10 +++ .../solidity-verifier/src/builder/render.rs | 3 + .../src/lowering/artifacts.rs | 35 ++++++++++ .../solidity-verifier/src/lowering/kzg/mod.rs | 6 +- .../src/lowering/protocol/mod.rs | 6 +- .../src/lowering/render/models.rs | 5 ++ .../solidity-verifier/src/lowering/tests.rs | 53 ++++++++++++++- proofs/solidity-verifier/src/lowering/vk.rs | 41 ++++++++++- proofs/solidity-verifier/src/test.rs | 11 +-- .../templates/partials/verifier/Constants.sol | 12 ++++ .../tests/template_digest.rs | 68 +++++++++++++++++++ 12 files changed, 259 insertions(+), 14 deletions(-) create mode 100644 proofs/solidity-verifier/build.rs create mode 100644 proofs/solidity-verifier/tests/template_digest.rs diff --git a/proofs/solidity-verifier/build.rs b/proofs/solidity-verifier/build.rs new file mode 100644 index 000000000..9df918e7c --- /dev/null +++ b/proofs/solidity-verifier/build.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: CC0-1.0 +//! Exposes the crate's enabled feature profile to the generator (P10/L-8, +//! docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). +//! +//! The rendered verifier's proof schema depends on feature flags +//! (`truncated-challenges`, `fewer-point-sets`, ...), and nothing in the +//! deployed artifact previously recorded which profile produced it. The +//! generator folds this string into the emitted `BUILD_ID` constant. + +fn main() { + let mut features: Vec = std::env::vars() + .filter_map(|(key, _)| { + key.strip_prefix("CARGO_FEATURE_") + .map(|name| name.to_ascii_lowercase().replace('_', "-")) + }) + .collect(); + features.sort(); + println!( + "cargo:rustc-env=SOLIDITY_VERIFIER_FEATURES={}", + features.join(",") + ); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/proofs/solidity-verifier/src/api.rs b/proofs/solidity-verifier/src/api.rs index 0cf0be6e1..ef36609ba 100644 --- a/proofs/solidity-verifier/src/api.rs +++ b/proofs/solidity-verifier/src/api.rs @@ -352,6 +352,16 @@ pub struct RenderOptions { pub quotient: RenderQuotient, /// Trace/gas diagnostic knobs. pub diagnostics: RenderDiagnostics, + /// Optional 32-byte provenance tag folded into the emitted `BUILD_ID` + /// constant (P10/L-8) — typically a hash of the generator git commit and + /// build context, e.g. `keccak256("commit=,dirty=")`. + /// + /// `None` (the default) keeps `BUILD_ID` a pure function of the feature + /// profile, VK, and SRS, so repository fixtures stay byte-stable across + /// commits. Deployment builds SHOULD set it and publish the preimage in + /// the deployment record; see + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. + pub provenance: Option<[u8; 32]>, } /// Rendered Solidity artifacts. diff --git a/proofs/solidity-verifier/src/builder/render.rs b/proofs/solidity-verifier/src/builder/render.rs index 7d3eee235..c60a23563 100644 --- a/proofs/solidity-verifier/src/builder/render.rs +++ b/proofs/solidity-verifier/src/builder/render.rs @@ -15,6 +15,7 @@ struct VerifierRenderPlan { gas_checkpoints: bool, external_quotient: bool, expected_quotient: Option<(usize, U256)>, + provenance: Option<[u8; 32]>, } impl<'a> SolidityGenerator<'a> { @@ -39,6 +40,7 @@ impl<'a> SolidityGenerator<'a> { gas_checkpoints: options.diagnostics.gas_checkpoints, external_quotient, expected_quotient, + provenance: options.provenance, }; let verifier = self.render_verifier_source_with_plan(&inputs, &plan, render_plan)?; @@ -109,6 +111,7 @@ impl<'a> SolidityGenerator<'a> { render_plan.gas_checkpoints, render_plan.external_quotient, render_plan.expected_quotient, + render_plan.provenance, ) .render(&mut verifier_output) .map_err(|_| GeneratorError::Render { diff --git a/proofs/solidity-verifier/src/lowering/artifacts.rs b/proofs/solidity-verifier/src/lowering/artifacts.rs index 9c37d89cf..94a9bb402 100644 --- a/proofs/solidity-verifier/src/lowering/artifacts.rs +++ b/proofs/solidity-verifier/src/lowering/artifacts.rs @@ -77,6 +77,7 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { gas_checkpoints: bool, external_quotient: bool, expected_quotient: Option<(usize, U256)>, + provenance: Option<[u8; 32]>, ) -> Halo2Verifier { assert!( expected_quotient.is_none() || external_quotient, @@ -101,6 +102,39 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { U256::from_be_bytes(digest) }); let vk_len = plan.vk.len(); + // BUILD_ID (P10/L-8): one on-chain constant that identifies the build. + // Preimage: domain tag, length-prefixed feature profile (from + // build.rs), vk_digest, expected VK codehash (zero when embedded), + // SRS fingerprint, and the optional deployment provenance tag. + // Deployment records must publish these components so third parties + // can recompute the id; see + // docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + let build_id = { + let vk_digest = plan + .vk + .constants + .iter() + .find(|(name, _)| *name == "vk_digest") + .expect("VK header always carries vk_digest") + .1; + let features = env!("SOLIDITY_VERIFIER_FEATURES"); + let mut hasher = Keccak256::new(); + hasher.update(b"halo2-solidity-verifier-build-v1"); + hasher.update((features.len() as u64).to_be_bytes()); + hasher.update(features.as_bytes()); + hasher.update(vk_digest.to_be_bytes::<32>()); + hasher.update(expected_vk_codehash.unwrap_or_default().to_be_bytes::<32>()); + hasher.update(self.srs_fingerprint()); + match provenance { + Some(tag) => { + hasher.update([1u8]); + hasher.update(tag); + } + None => hasher.update([0u8]), + } + let digest: [u8; 32] = hasher.finalize().into(); + U256::from_be_bytes(digest) + }; let (expected_quotient_len, expected_quotient_codehash) = expected_quotient .map(|(len, codehash)| (Some(len), Some(codehash))) .unwrap_or((None, None)); @@ -251,6 +285,7 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { fr_delta: fr_delta_literal(), embedded_vk: (!separate).then(|| plan.vk.clone()), expected_vk_codehash, + build_id, vk_len, num_instances: self.num_instances, k: self.vk.get_domain().k() as usize, diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index bcd518c96..8b94597be 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -112,8 +112,7 @@ pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec { let g1_identity = EcPoint::new(Ptr::memory("G1_IDENTITY_MPTR")); for (source, query) in meta.protocol.pcs_queries.iter().zip(&queries) { assert!( - query.comm != g1_identity - || matches!(source, PcsQuerySource::CommittedInstance(_)), + query.comm != g1_identity || matches!(source, PcsQuerySource::CommittedInstance(_)), "query {source:?} resolves to the G1 identity commitment; only \ committed-instance queries may be identity-pinned, since the MSM \ emitters omit identity commitments while keeping their evals" @@ -156,8 +155,7 @@ fn assert_permutation_query_order_is_upstream_equivalent( // Rebuild the z block in the upstream order: (Cur, Next) per set in // forward order, then Last per set in reverse order. - let z_sources: Vec = - z_positions.iter().map(|&i| sources[i]).collect(); + let z_sources: Vec = z_positions.iter().map(|&i| sources[i]).collect(); let mut upstream_block: Vec = z_sources .iter() .copied() diff --git a/proofs/solidity-verifier/src/lowering/protocol/mod.rs b/proofs/solidity-verifier/src/lowering/protocol/mod.rs index c3a00a592..02ed0efdb 100644 --- a/proofs/solidity-verifier/src/lowering/protocol/mod.rs +++ b/proofs/solidity-verifier/src/lowering/protocol/mod.rs @@ -486,7 +486,11 @@ impl ProtocolPlan { quer{} vs {} fixed columns minus {} simple selectors; the native verifier \ reads the column-based count while this generator reads the query-based \ count, so the proof scalar stream would desynchronize", - if non_simple_fixed_queries == 1 { "y" } else { "ies" }, + if non_simple_fixed_queries == 1 { + "y" + } else { + "ies" + }, num_fixeds, simple_selector_cols.len(), ); diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index 1e3c1def9..dd9f78b49 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -499,6 +499,10 @@ pub(crate) struct Halo2Verifier { pub(crate) fr_delta: String, pub(crate) embedded_vk: Option, pub(crate) expected_vk_codehash: Option, + /// keccak over the build's identity components (P10/L-8): feature + /// profile, vk_digest, VK codehash-or-zero, SRS fingerprint, optional + /// deployment provenance tag. Emitted as the public BUILD_ID constant. + pub(crate) build_id: U256, pub(crate) vk_len: usize, /// Generated public-instance count for this pinned VK/proof layout. pub(crate) num_instances: usize, @@ -1162,6 +1166,7 @@ mod tests { fr_delta: crate::lowering::quotient_numerator::vm::fr_delta_literal(), embedded_vk: None, expected_vk_codehash: Some(U256::from(1u64)), + build_id: U256::ZERO, vk_len: 0, num_instances: 1, k: 8, diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 9626e1dc3..1a151ab9c 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -38,7 +38,7 @@ use super::{ use crate::{ api::{ AccumulatorEncoding, CommittedInstanceCommitmentKind, GeneratorConfig, GeneratorError, - QuotientIdentityManifestTarget, QuotientIdentitySource, + QuotientIdentityManifestTarget, QuotientIdentitySource, RenderOptions, }, SolidityGenerator, }; @@ -824,7 +824,8 @@ fn lowering_plan_reuses_stable_layout_facts() { plan.meta.num_simple_selectors ); - let verifier = inputs.generate_verifier_from_plan(&plan, false, false, false, false, None); + let verifier = + inputs.generate_verifier_from_plan(&plan, false, false, false, false, None, None); assert_eq!(verifier.codegen_layout.proof, plan.proof_layout); assert_eq!(verifier.memory.vk_mptr, plan.vk_mptr); assert_eq!(verifier.proof_len, plan.proof_layout.proof_len); @@ -2321,6 +2322,54 @@ fn production_verifier_documents_revert_or_true_policy() { ); } +/// P10 (L-8): the emitted BUILD_ID must be a stable function of the build's +/// identity components, and the optional deployment provenance tag must be +/// the ONLY thing that changes when it is supplied. +#[test] +fn build_id_identifies_the_build_and_its_provenance() { + let (params, vk) = quotient_vm_test_vk(); + let generator = SolidityGenerator::new(¶ms, &vk, GeneratorConfig::new(1, 1)); + let extract = |source: &str| { + source + .lines() + .find(|line| line.contains("BUILD_ID = 0x")) + .expect("rendered verifier carries a BUILD_ID constant") + .trim() + .to_string() + }; + + let base = generator + .render(RenderOptions::default()) + .expect("default render succeeds") + .verifier; + let again = generator + .render(RenderOptions::default()) + .expect("repeat render succeeds") + .verifier; + assert_eq!( + base, again, + "renders with equal options must be byte-identical" + ); + + let tagged = generator + .render(RenderOptions { + provenance: Some([0x42; 32]), + ..RenderOptions::default() + }) + .expect("provenance render succeeds") + .verifier; + assert_ne!( + extract(&base), + extract(&tagged), + "the provenance tag must change BUILD_ID" + ); + assert_eq!( + base.replace(&extract(&base), ""), + tagged.replace(&extract(&tagged), ""), + "the provenance tag must change ONLY the BUILD_ID constant" + ); +} + /// P4 (L-3): the Yul revert sites carry hardcoded 4-byte selectors while the /// Solidity ABI carries the `error` declarations; pin the two against each /// other so neither can drift silently. diff --git a/proofs/solidity-verifier/src/lowering/vk.rs b/proofs/solidity-verifier/src/lowering/vk.rs index 1678e14a1..198065171 100644 --- a/proofs/solidity-verifier/src/lowering/vk.rs +++ b/proofs/solidity-verifier/src/lowering/vk.rs @@ -39,6 +39,15 @@ pub(crate) fn srs_tau_is_consistent( omega: Fq, s_g2: G2Affine, ) -> bool { + let tau_g1 = srs_tau_commitment(g_lagrange, omega); + Bls12::pairing(&tau_g1, &G2Affine::generator()) == Bls12::pairing(&G1Affine::generator(), &s_g2) +} + +/// Commit f(X) = X in the Lagrange basis: `[tau]G1 = sum_i omega^i * L_i`. +/// +/// Used by the tau-binding pairing check above and as the tau component of +/// the SRS fingerprint folded into `BUILD_ID` (P10/L-8). +pub(crate) fn srs_tau_commitment(g_lagrange: &[G1Projective], omega: Fq) -> G1Affine { // Pippenger MSM: production SRS sizes reach 2^20 Lagrange points, so a // naive per-point scalar multiplication here would stall every build. let mut omega_pow = Fq::ONE; @@ -49,11 +58,39 @@ pub(crate) fn srs_tau_is_consistent( current }) .collect(); - let tau_g1 = G1Projective::multi_exp(g_lagrange, &omega_powers).to_affine(); - Bls12::pairing(&tau_g1, &G2Affine::generator()) == Bls12::pairing(&G1Affine::generator(), &s_g2) + G1Projective::multi_exp(g_lagrange, &omega_powers).to_affine() } impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { + /// A 32-byte identity for the SRS this build trusts, for `BUILD_ID` + /// (P10/L-8, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md). + /// + /// An SRS over a fixed curve is fully determined by its size `n` and the + /// secret tau, so hash exactly the values that pin those: `n`, the G2 + /// base, `s_g2 = [tau]G2`, and `[tau]G1` recomputed from the Lagrange + /// basis actually used for commitments. Two params values agree on this + /// fingerprint iff they present the same trusted setup to the verifier. + pub(crate) fn srs_fingerprint(&self) -> [u8; 32] { + use sha3::{Digest, Keccak256}; + + let g_lagrange = self.params.g_lagrange(); + let omega = self.vk.get_domain().get_omega(); + let tau_g1 = srs_tau_commitment(g_lagrange, omega); + let mut hasher = Keccak256::new(); + hasher.update(b"halo2-solidity-verifier-srs-v1"); + hasher.update((g_lagrange.len() as u64).to_be_bytes()); + for word in g2_to_u256s(self.params.g2().to_affine()) { + hasher.update(word.to_be_bytes::<32>()); + } + for word in g2_to_u256s(self.params.s_g2().to_affine()) { + hasher.update(word.to_be_bytes::<32>()); + } + for word in g1_to_u256s(tau_g1) { + hasher.update(word.to_be_bytes::<32>()); + } + hasher.finalize().into() + } + /// Generate the VK payload before compact quotient constants/program data. fn generate_base_vk(&self) -> Halo2VerifyingKey { let constants: Vec<(&'static str, U256)>; diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 62b7d9a63..bf161201f 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -3090,13 +3090,14 @@ fn typed_errors_identify_rejection_classes() { for (name, calldata, expected_sig) in [ ("trailing calldata byte", trailing, "BadCalldataShape()"), - ("non-canonical instance", bad_instance, "NonCanonicalScalar()"), + ( + "non-canonical instance", + bad_instance, + "NonCanonicalScalar()", + ), ("pad-byte violation", bad_pad, "BadPointEncoding()"), ] { - match deployed - .evm - .try_call_with_gas(deployed.verifier_address, calldata, 30_000_000) - { + match deployed.evm.try_call_with_gas(deployed.verifier_address, calldata, 30_000_000) { CallOutcome::Revert { output, .. } => { assert_eq!( output, diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index d8a7f403b..1ecaa76cb 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -197,6 +197,18 @@ uint256 internal constant ACC_RHS_MSM_GAS = {{ acc_rhs_msm_gas }}; {%- endif %} + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = {{ build_id|hex_padded(64) }}; + // ---------------------------------------------------------------------- // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the // errors declared on the contract, as Yul-readable constants. The diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs new file mode 100644 index 000000000..67be759b8 --- /dev/null +++ b/proofs/solidity-verifier/tests/template_digest.rs @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: CC0-1.0 +//! P14 (L-1, docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md): the committed +//! replay fixtures compile PRE-RENDERED `.sol` sources, so a template edit +//! whose fixtures were not regenerated keeps every replay test green while +//! the deployable artifacts silently drift. This test pins a digest of the +//! whole `templates/` tree; editing any template forces an explicit +//! regeneration acknowledgement. Deliberately not feature-gated so it runs +//! in default CI with no SRS, no solc, and no EVM. + +use std::{fs, path::Path}; + +use sha3::{Digest, Keccak256}; + +/// keccak over the sorted (path, length, content) stream of `templates/`. +const EXPECTED_TEMPLATE_TREE_DIGEST: &str = + "0x87a5652da53283b444bf2c5c3bdbb2242c9cd7c0f183b9e5a3c0e60dd184f24b"; + +fn collect_files(dir: &Path, files: &mut Vec) { + for entry in fs::read_dir(dir).expect("template directory is readable") { + let path = entry.expect("template directory entry is readable").path(); + if path.is_dir() { + collect_files(&path, files); + } else { + files.push(path); + } + } +} + +#[test] +fn template_tree_digest_is_pinned() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("templates"); + let mut files = Vec::new(); + collect_files(&root, &mut files); + files.sort(); + assert!( + files.len() >= 15, + "template tree unexpectedly small ({} files); digest coverage would be vacuous", + files.len() + ); + + let mut hasher = Keccak256::new(); + for path in &files { + let rel = path + .strip_prefix(&root) + .expect("collected paths live under templates/") + .to_string_lossy() + .replace('\\', "/"); + let content = fs::read(path).expect("template file is readable"); + hasher.update((rel.len() as u64).to_be_bytes()); + hasher.update(rel.as_bytes()); + hasher.update((content.len() as u64).to_be_bytes()); + hasher.update(&content); + } + let actual = format!("0x{}", hex::encode(hasher.finalize())); + + assert_eq!( + actual, EXPECTED_TEMPLATE_TREE_DIGEST, + "\n\nThe templates/ tree changed (digest {actual}). Every committed \ + fixture and dump was rendered from the previous tree and is now \ + stale. Before updating EXPECTED_TEMPLATE_TREE_DIGEST in this test:\n\ + \x20 1. regenerate the fixture dumps (fixture tests + \ + scripts/run_ivc_bench.sh) and the committed fixtures/ where \ + applicable (see each fixtures/*/README.md);\n\ + \x20 2. update the source-commit stamps in those READMEs;\n\ + \x20 3. re-run the replay tests against the regenerated artifacts;\n\ + then pin the new digest.\n" + ); +} From faa8ef472262867a22d15d9d9100059618afcbab Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 09:57:22 +0100 Subject: [PATCH 097/108] docs(solidity-verifier): deployment/incident-response requirements and accepted-risk records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L-9 — new docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md states the immutability corollaries the review found undocumented, and turns the wrapper guidance into requirements: replaceable verifier address, wrapper-held pause, and chainid + wrapper-address + anti-replay binding in the proven statement (without which every accepted proof replays across all chains and deployments, forever). Includes the deployment record checklist and an incident/migration playbook keyed on BUILD_ID. verifyProof's NatSpec and AUDIT.md TA-8 now point at it. L-10 — the 128-bit truncated-challenge profile is recorded as an accepted risk: per-attempt PCS soundness ≈2^-107.6 (2^-108 with the x1.3585 sampling-bias factor), essentially tight, expected grinding work ≈2^108, with the truncate(x1^i)=0 edge case and the derivation's assumptions, against a stated 2^100 target security level and a deployment-owner sign-off line. I-5 — the Keccak transcript's missing domain separation is recorded as an accepted defence-in-depth gap in the spec and the risk register: tags cannot be added verifier-side without rejecting every midnight-proofs proof (same upstream-protocol class as M-4). FIXES_APPLIED gains the 2026-08-13 follow-up section closing the Low/Informational batch. Co-Authored-By: Claude Fable 5 --- proofs/solidity-verifier/docs/audit/AUDIT.md | 12 +- .../docs/audit/FIXES_APPLIED_2026-08.md | 52 +++++++ .../DEPLOYMENT_AND_INCIDENT_RESPONSE.md | 141 ++++++++++++++++++ .../reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md | 10 ++ .../templates/contracts/Halo2Verifier.sol | 4 + 5 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md diff --git a/proofs/solidity-verifier/docs/audit/AUDIT.md b/proofs/solidity-verifier/docs/audit/AUDIT.md index eaa3e77da..df8a5d3ee 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT.md @@ -2508,11 +2508,13 @@ Recommendation: Severity: Integration risk. Status: Acknowledged / integration guidance. The raw verifier is stateless -by design and cannot bind proof meaning itself; the NatSpec on `verifyProof` -and the wrapper guidance in the testing strategy place replay/domain binding -(nullifiers, chain/contract domain, program ID) on the application contract. -Any deployment review must check the wrapper, not just this verifier. -Triaged 2026-08-12. +by design and cannot bind proof meaning itself; the wrapper obligations are +now stated as REQUIREMENTS (replaceable verifier address, wrapper-held +pause, chainid + wrapper-address + anti-replay binding) in +`docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §2, together with the +incident-response and migration playbook. Any deployment review must check +the wrapper against that document, not just this verifier. Triaged +2026-08-12; requirements doc added 2026-08-13. The verifier correctly says application contracts must bind the meaning of public instances separately. That warning is important. This raw verifier diff --git a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md index 7198bfe45..db0cd1811 100644 --- a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md +++ b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md @@ -106,6 +106,58 @@ coverage — protocol change affecting the prover) and anything outside `proofs/solidity-verifier/`. Remaining open from the tables below: P4, P8, P9, P10, P12, P14, L-4, L-9, L-10, I-6, I-7. +## 2026-08-13 follow-up: Low/Informational batch closed + +The remaining P-series patches and L/I findings were applied in a third pass +(commits: planner asserts, runtime hardening, provenance/digest, docs): + +- **P9 (L-7)** — planner asserts tie the batch_invert scratch capacity and + the Lagrange run length to the template's own expression; overflow (which + corrupted silently) now refuses to plan. Region-shape tests included. +- **P8 (L-5)** — the user-challenge window is asserted to cover the phase + sum of squeezed challenges and to end at or before THETA_MPTR; an + undersized window refuses to plan (positive + should-panic tests). +- **L-2 (assert half)** — `queries()` asserts every identity-pinned + commitment originates from the committed-instance column, the exact + justification for the MSM omission. +- **I-6** — both latent divergences are now plan-time assertions: the + permutation z ordering is re-derived under the upstream (Cur/Next then + reversed Last) order and the intermediate-set structures compared; the + column-based vs query-based fixed-eval counts are asserted equal. +- **P12 (L-6)** — the runtime quotient VM clamps every decoded + memory-pointer operand against the coarse union of the planned read + windows (shared source of truth with the build-time validator), clamps + FOLD_SELECTOR's bucket index and y-power gap, and guards stack pops + against balanced underflow. +- **P4 (L-3)** — seven declared custom errors cover the verify path + (constructor probes keep bare reverts by scoped decision); selectors + pinned against keccak of the signatures and decoded end-to-end in revm. +- **L-4** — decision: keep the exact `calldatasize` pin; the ERC-2771 / + calldata-appending incompatibility is now documented in `verifyProof`'s + NatSpec (typed BadCalldataShape revert). +- **I-7** — `vk_digest` joined the accumulator batching randomizer's + preimage (verifier-local; no prover interaction). +- **P10 (L-8)** — every render carries `BUILD_ID` (feature profile, + vk_digest, VK codehash, SRS fingerprint keccak(n||G2||s_g2||[tau]G1), + optional deployment provenance tag via `RenderOptions::provenance`). +- **P14 (L-1)** — `tests/template_digest.rs` pins a keccak of the sorted + `templates/` tree in default CI, closing the committed-fixture drift gap. + The deeper L-1 legs (expression front-end certification, native-kernel + differential) remain future work. +- **L-9 / L-10 / I-5** — `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` + states the wrapper obligations as requirements, adds the incident/migration + playbook keyed on BUILD_ID, records the truncated-challenge ≈2^-107.6 + bound as an accepted risk with a 2^100 target level and a sign-off line, + and records the transcript domain-separation gap (I-5) as accepted — + it cannot be fixed verifier-side without breaking prover compatibility. +- **I-2 leftovers / I-3** — smoke-window comment corrected (creation-frame + memory cannot pre-expand the runtime frame), `validate_public_accumulator`'s + shape-dependent `r` parameter documented, the unreachable identity-flag + branch labeled unreachable-by-construction. + +Still open after this batch: the deeper L-1 certification legs, M-4 +(excluded by owner decision), and the outer single-H recorded-hash refresh. + ## Short answer: no, this does not address all the findings Of the 23 findings, **4 are closed or substantially closed by the changes below.** The rest fall into three groups: diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md new file mode 100644 index 000000000..b1da3266f --- /dev/null +++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md @@ -0,0 +1,141 @@ +# Deployment, Incident Response, and Accepted Risks + +Closes review items **L-9** (no incident-response or migration story) and +**L-10** (truncated-challenge soundness as a recorded accepted risk) from +`docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md`, and records the wrapper +obligations that `AUDIT.md` TA-8 places on integrators. + +## 1. What the deployed verifier is — and is not + +A generated `Halo2Verifier` is **stateless and immutable**: no owner, no +pause, no upgrade path, no `sstore`/`delegatecall`/`selfdestruct`. That is +deliberate — an on-chain admin lever on a verifier is itself an attack +surface. Two consequences follow, and both land on the application wrapper: + +1. **There is no on-chain mitigation for a post-deployment soundness bug.** + The only lever is the wrapper above the verifier. +2. **A valid proof is valid everywhere, forever.** The transcript starts at + `vk_digest`; nothing binds `block.chainid`, the verifier address, or the + deployment. `verifyProof == true` is a statement about the proof and the + circuit, not about *this chain* or *this application*. + +## 2. Wrapper obligations (REQUIRED, not advisory) + +Every production integration MUST satisfy all three; a wrapper that +hardcodes the verifier as `immutable`/`constant` and treats +`verifyProof == true` as authorization has **no recovery path and +unconditional cross-chain replay**: + +- **W-1 — Replaceable verifier address.** The wrapper holds the verifier + behind an updatable (governed/timelocked) address so a re-rendered + verifier can be swapped in. +- **W-2 — Wrapper-held pause.** The wrapper can stop accepting proofs while + an incident is investigated. The verifier itself cannot. +- **W-3 — Domain binding + replay protection.** The statement the circuit + proves (or the wrapper's own checks over the public instances) MUST bind: + `block.chainid`, the wrapper (or verifier) address, and an + application-level anti-replay value (nullifier, nonce, or consumed-state + root). Without this, any accepted proof can be replayed on every chain + and against every deployment of the same bytecode. + +`verifyProof`'s NatSpec states the same split: the raw verifier checks the +proof against the pinned VK and nothing else. + +## 3. Deployment record + +For every production deployment, record and publish: + +| Item | Source | +| --- | --- | +| `BUILD_ID` and each preimage component | the deployed contract's `BUILD_ID` constant; components below | +| Feature profile string | `build.rs` export baked into the generator (`SOLIDITY_VERIFIER_FEATURES`) | +| `vk_digest`, VK runtime length/codehash | generated constants | +| SRS fingerprint + asset SHA-256 + ceremony reference | `REPRODUCIBLE_BUILDS.md` ("SRS Provenance") | +| Provenance tag preimage | the `RenderOptions::provenance` input, e.g. `keccak256("commit=,dirty=")` — deployment builds MUST set it | +| Compiler identity + flags | `REPRODUCIBLE_BUILDS.md` (pinned solc SHA-256, `--optimize-runs`) | +| Artifact manifest | `scripts/generate_artifact_manifest.sh` output | +| Target security level and accepted risks | §5 below | + +`BUILD_ID` exists precisely so "which of our deployed verifiers has the +affected codegen?" is answerable from chain state during an incident. + +## 4. Incident response and migration playbook + +**On a suspected soundness/liveness bug in a deployed verifier:** + +1. **Pause** intake at the wrapper (W-2). Verifier-level mitigation does not + exist by design. +2. **Scope** the blast radius: enumerate deployments and read each + `BUILD_ID`; match against the deployment records to find which builds + carry the affected generator code, feature profile, or SRS. +3. **Assess replay exposure**: anything accepted by an affected verifier + must be treated per W-3 — if the statement was not domain-bound, assume + cross-chain/cross-deployment replay of every historical proof. +4. **Fix and re-render**: land the generator fix, re-run the full gated + suite and the IVC bench, regenerate artifacts, record new hashes and a + new `BUILD_ID` (with a fresh provenance tag). +5. **Migrate**: deploy VK first, then verifier (the constructor fails closed + on a wrong VK), verify on-chain `BUILD_ID` matches the record, switch the + wrapper pointer (W-1), unpause. +6. **Retire** the old verifier in the deployment record (it cannot be + destroyed on-chain); wrappers must never point back at it. + +**Upstream repricing note:** the verifier forwards exact EIP-2537/EIP-2565 +scheduled gas. A fork that reprices those precompiles upward bricks +`verifyProof` (liveness, not soundness) and deployment of new artifacts +fails fast in the constructor probes. The migration path is the same +re-render + wrapper switch. + +## 5. Accepted risks (deployment owner sign-off) + +### 5.1 Truncated challenges cap PCS soundness at ≈ 2⁻¹⁰⁸ per attempt (L-10) + +The `truncated-challenges` profile — which the canonical artifacts use, and +which mirrors the midnight-proofs prover — truncates `x3` to its low 128 +bits after squeezing and truncates each `x1`/`x4` power to 128 bits at use. +Consequences (full derivation: review §L-10): + +- Per-attempt false-acceptance probability of the isolated `x3` step is + `(n + 9) / 2¹²⁸ ≈ 2⁻¹⁰⁷·⁹⁹` at `n = 2²⁰`, and ≈ **2⁻¹⁰⁷·⁶** after the + ×1.3585 `mod r` sampling-bias factor. Untruncated sampling would give + ≈ 2⁻²³⁴; the mask costs ~127 bits. +- The bound is essentially tight: an adversary can place all roots of the + lying polynomial inside `[0, 2¹²⁸)`, so the attack is grinding `f_com` + with expected work ≈ **2¹⁰⁸**. +- Edge case: `truncate(x1^i) = 0` (probability 2⁻¹²⁸ per power) silently + drops query `i` from both the commitment and evaluation sides — a clean, + symmetric failure. +- Assumptions: KZG binding fixes `f'` from `f_com`; `x3` avoids the poles of + the batched rational function (fails with probability `11/2¹²⁸`). + +**Decision (2026-08-13): ACCEPTED.** Rationale: the profile faithfully +mirrors the prover (a verifier-side change alone is impossible), and 2¹⁰⁸ +expected grinding work per forgery attempt exceeds the target security +level below. Disabling the feature is a prover-side protocol change tracked +separately, not a verifier patch. + +- **Target security level:** ≥ 2¹⁰⁰ expected work per false acceptance. +- **Sign-off:** deployment owner: ______________________ date: __________ + *(recorded per deployment; this repository documents the analysis and the + default acceptance).* + +### 5.2 Keccak transcript has no domain separation (I-5) + +The Keccak transcript absorbs raw concatenated bytes with no +personalisation string or `COMMON`/`CHALLENGE` tags (the Blake2b transcript +upstream has both). Not exploitable in this protocol: every absorb is +fixed-length with pinned counts, so no two distinct valid inputs produce +the same byte stream, and `vk_digest` provides cross-circuit separation. +It cannot be fixed verifier-side — adding tags would break every proof from +the midnight-proofs prover; this is the same class of upstream protocol +change as M-4 (`vk_digest` coverage), and is **accepted as a documented +defence-in-depth gap** until the transcript changes upstream. + +### 5.3 `vk_digest` coverage (M-4) — deferred upstream decision + +`vk_digest` does not cover the SRS points, quotient VM program, accumulator +schema, or feature profile. Compensating controls: build-time SRS tau +binding, VK codehash pin, generated-constant cross-checks, and `BUILD_ID` +(which does cover all of the above, off-transcript). Widening the digest is +a prover-affecting protocol change, explicitly out of scope by owner +decision (2026-08-13). diff --git a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md index 698b10fd9..8ae374903 100644 --- a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +++ b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md @@ -535,6 +535,16 @@ The VK codehash pins: The generated verifier implements the Midfall Keccak transcript. +**No domain separation, by protocol (audit I-5, accepted gap).** The Keccak +transcript hashes raw concatenated bytes with no personalisation string and +no absorb/squeeze tags, exactly matching the midnight-proofs prover. This is +safe here because every absorb is fixed-length with generated, re-checked +counts (no two distinct valid inputs share a byte stream) and `vk_digest` +separates circuits — but it is a missing defence-in-depth layer. It cannot +be added verifier-side without rejecting every real proof; like M-4, it is +an upstream transcript decision. Recorded in +`docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §5.2. + ### 7.1 Transcript State The transcript state is a byte buffer. diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol index c40c68e41..c1db4f284 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol @@ -85,6 +85,10 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return /// `true`; this function NEVER returns `false`. Every rejection reverts /// with one of the typed errors declared above (BadCalldataShape, From f894f75a7849e60984ddf47c5b652978e1d47f17 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 10:16:03 +0100 Subject: [PATCH 098/108] chore(solidity-verifier): regenerate dumps on the hardened templates, re-measure, pin digest Regenerates the five regenerable fixture dumps on the canonical evm,truncated-challenges profile after the L/I-batch template changes (exact gas bounds were already in; this adds the P12 operand clamps, P4 typed errors, I-7 alpha vk-binding, and BUILD_ID). Every regenerated verifier deployed and accepted a real proof under Prague revm; the full gated trace suite passes 212/212 including the native/Solidity trace differential, and both --features evm and evm,truncated-challenges modes stay green. Measured (IVC bench, checkpoint profile): 1,365,883 gas total; the P12 runtime operand clamps cost +59,951 gas, all inside the quotient-VM section (314,530 -> 374,481, +19.1% of that section, ~+4.6% of the transaction); every other section including PCS block 5 is unchanged. Runtime sizes: verifier 12,637 B (+183), evaluator 9,790 B (+238), VK unchanged. REPRODUCIBLE_BUILDS.md records the new hashes, the gas delta, and keeps the previous recordings for comparison. Also: the template-tree digest (P14) is pinned at the final template state; RenderOptions initializers in the test suites carry the new provenance field (None keeps dumps byte-stable); the moonlight-wrap fixture README now states its staleness relative to the hardened templates (regenerable only from the external Moonlight checkout). Co-Authored-By: Claude Fable 5 --- .../docs/reference/REPRODUCIBLE_BUILDS.md | 28 ++- .../fixtures/moonlight-wrap/README.md | 1 + proofs/solidity-verifier/src/test.rs | 4 +- .../hybrid-mt-fixture-dump/Halo2Verifier.sol | 195 ++++++++++++++---- .../Halo2QuotientEvaluator.sol | 43 +++- .../Halo2Verifier.sol | 183 ++++++++++++---- .../poseidon-fixture-dump/Halo2Verifier.sol | 184 +++++++++++++---- .../Halo2Verifier.sol | 175 ++++++++++++---- .../Halo2Verifier.sol | 195 ++++++++++++++---- .../tests/ivc_keccak_solidity.rs | 3 + .../tests/template_digest.rs | 2 +- 11 files changed, 808 insertions(+), 205 deletions(-) diff --git a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md index 6efb0953e..8576f2dea 100644 --- a/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md +++ b/proofs/solidity-verifier/docs/reference/REPRODUCIBLE_BUILDS.md @@ -144,9 +144,11 @@ The proof repacked from `4,912` compressed bytes to `7,392` padded bytes, with ## Recorded Legacy Multi-Limb Runtime Hashes The concrete hashes below are the latest recorded default multi-limb profile -in this repository (recorded 2026-08-13, after the exact-precompile-gas-bound -change; the tracked `target/ivc-keccak-solidity-dump/` sources match this -run). They were generated with the fixed default quotient codegen shape: +in this repository (recorded 2026-08-13, after the exact precompile gas +bounds, quotient-VM operand clamps (P12), typed errors (P4), BUILD_ID (P10), +and the alpha vk-binding (I-7); the tracked +`target/ivc-keccak-solidity-dump/` sources match this run). They were +generated with the fixed default quotient codegen shape: ```bash scripts/run_ivc_bench.sh \ @@ -165,19 +167,25 @@ Published deployed-runtime hashes: | Artifact | Runtime bytes | Runtime `keccak256` | | --- | ---: | --- | -| `Halo2Verifier` | 12,454 | `0xa74814afafa69cfcb69224aa3a68f0f461348439beec8f18450f334782159e10` | +| `Halo2Verifier` | 12,637 | `0x6df65ec939553efef2dadffdab078bfb424d10307a32dddd84866cf94d29b215` | | `Halo2VerifyingKey` | 17,025 | `0x67bac137fa7e479c25b63324812752e4b6e13d9841d5bf83c322170bf91c0f88` | -| `Halo2QuotientEvaluator` | 9,552 | `0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c` | +| `Halo2QuotientEvaluator` | 9,790 | `0x7e72c7c5d6fe845370d9431aaa590ab2cd62ca703c3d5b2a862bdb9937195814` | -Total deployed runtime bytes: `39,031`. +Total deployed runtime bytes: `39,452`. -The same run accepted the final IVC Keccak proof on-chain in `1,306,084` gas +The same run accepted the final IVC Keccak proof on-chain in `1,365,883` gas (gas-checkpoint diagnostic profile). The proof repacked from `5,056` compressed bytes to `7,776` padded bytes, with `8,356` bytes of calldata. -Previous recording, for comparison (2026-07-era artifact set): verifier -12,061 / VK 14,016 / evaluator 23,221 bytes (49,298 total), accepted in -`1,399,268` gas. +Measured cost of the P12 runtime operand clamps: the quotient-VM section +("batched identity numerator reconstruction") went from `314,530` to +`374,481` gas (+59,951, +19.1% of that section, ~+4.6% of the transaction); +every other section is unchanged (PCS block 5 stays at `533,488`). + +Previous recordings, for comparison: 2026-08-13 pre-hardening — verifier +12,454 / VK 17,025 / evaluator 9,552 bytes (39,031 total), accepted in +`1,306,084` gas; 2026-07-era artifact set — verifier 12,061 / VK 14,016 / +evaluator 23,221 bytes (49,298 total), accepted in `1,399,268` gas. Compared with this multi-limb profile, outer single-H removes three quotient G1 commitments: proof size drops by `144` compressed bytes and `384` padded bytes, diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 1cd8d1227..dd8f06664 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -15,6 +15,7 @@ the replay deploys the verifier with the verifying key alone. | Field | Value | | --- | --- | | Source commit | `3fb6d84` (**this repository**, solidity-verifier, at fixture-render time; not the Midfall dependency revision — see the provenance-identities table in `docs/reference/REPRODUCIBLE_BUILDS.md`) | +| Staleness | **Stale relative to the current templates** (exact gas bounds, typed errors, VM operand clamps, BUILD_ID, alpha vk-binding all postdate `3fb6d84`). The replay test intentionally pins this rendered state; regenerating needs the external Moonlight checkout described below. | | Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | | Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | | Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index bf161201f..01b07e8b3 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -2544,6 +2544,7 @@ fn load_property_poseidon_fixture() -> PropertyPoseidonFixture { trace: true, ..RenderDiagnostics::default() }, + provenance: None, }) .expect("trace pinned render with quotient evaluator"); let trace_quotient_verifier_solidity = trace_quotient_artifacts.verifier; @@ -3967,7 +3968,8 @@ fn assert_rendered_reader_matches_proof_layout( "generated proof reader proof_cptr increments drifted from ProofCalldataLayout" ); assert!( - solidity.contains("if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) }"), + solidity + .contains("if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) }"), "generated proof reader must fail closed if proof_cptr drifts" ); } diff --git a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol index 42ca24aa3..aa0e9cc7d 100644 --- a/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/hybrid-mt-fixture-dump/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -219,6 +247,33 @@ contract Halo2Verifier { // Exact cost of the deployment-time worst-case G1MSM smoke probe. uint256 internal constant G1MSM_GAS_SMOKE = 454608; + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x360d2263de36925682a544990692d3d7e5c2f7beba81756f9a349f8544ea4123; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -391,8 +446,12 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0x7e60 for { let off := 0 } lt(off, 0x2940) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) @@ -438,10 +497,24 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -467,7 +540,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -493,7 +569,15 @@ contract Halo2Verifier { // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -506,8 +590,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x2c60 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -517,8 +601,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -578,16 +662,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -749,14 +833,14 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -768,7 +852,7 @@ contract Halo2Verifier { // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -973,6 +1057,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -1033,7 +1125,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1050,7 +1142,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 0)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1074,7 +1166,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // =============================================================== @@ -1144,7 +1236,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } // =============================================================== @@ -1327,7 +1419,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1380,7 +1472,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1406,11 +1498,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1493,9 +1585,19 @@ contract Halo2Verifier { mstore(INSTANCE_EVAL_MPTR, instance_eval) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } - // Optional quotient helper functions. Each one is rendered only + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding @@ -1515,7 +1617,8 @@ contract Halo2Verifier { let q_r := FR_MODULUS let x2 := mulmod(x, x, q_r) z := mulmod(x, mulmod(x2, x2, q_r), q_r) - } // =============================================================== + } + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -1817,6 +1920,7 @@ contract Halo2Verifier { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -1828,6 +1932,7 @@ contract Halo2Verifier { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0x85c0) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -1864,6 +1969,7 @@ contract Halo2Verifier { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -1871,6 +1977,7 @@ contract Halo2Verifier { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // VM 0x13 ADD_MUL_CONST_U8_MEM_U16: fused q_top += mem * const. @@ -1880,6 +1987,7 @@ contract Halo2Verifier { let q_ptr := shr(240, q_word) let qconst := byte(2, q_word) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_top := addmod( q_top, mulmod(mload(q_ptr), mload(add(q_const_mptr, shl(5, qconst))), r), @@ -1924,6 +2032,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1961,6 +2070,7 @@ contract Halo2Verifier { // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_cond_ptr, 0x2d60), 0x45e0) { q_program_fail() } } let q_acc := 0 @@ -1995,6 +2105,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -2007,12 +2118,14 @@ contract Halo2Verifier { for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_lhs, 0x2d60), 0x45e0) { q_program_fail() } let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_rhs, 0x2d60), 0x45e0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -2032,6 +2145,8 @@ contract Halo2Verifier { let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, 0x04) + if gt(sub(q_lhs_base, 0x2d60), 0x4520) { q_program_fail() } + if gt(sub(q_rhs_base, 0x2d60), 0x4520) { q_program_fail() } let q_coeff_pc := q_pc q_pc := add(q_pc, 13) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { @@ -2057,6 +2172,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2d60), 0x45e0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -2071,6 +2187,8 @@ contract Halo2Verifier { let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + if gt(sub(q_lhs, 0x2d60), 0x45e0) { q_program_fail() } + if gt(sub(q_rhs, 0x2d60), 0x45e0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -2556,7 +2674,7 @@ contract Halo2Verifier { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x85c0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -2568,6 +2686,11 @@ contract Halo2Verifier { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 15)) { q_program_fail() } + if gt(q_sel_gap, 0x29) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -2590,21 +2713,21 @@ contract Halo2Verifier { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x85c0)) { revert(0, 0) } + if iszero(eq(q_sp, 0x85c0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -3469,7 +3592,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) @@ -3481,7 +3604,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol index 3a076aef5..30464e1e4 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2QuotientEvaluator.sol @@ -138,7 +138,17 @@ contract Halo2QuotientEvaluator { // block mirrors that rule by accumulating those identities into // SELECTOR_ACC_MPTR buckets for later multiplication by fixed // selector commitments, while fully evaluated identities contribute - // to the negated expected scalar. // Optional quotient helper functions. Each one is rendered only + // to the negated expected scalar. // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding @@ -158,7 +168,8 @@ contract Halo2QuotientEvaluator { let q_r := FR_MODULUS let x2 := mulmod(x, x, q_r) z := mulmod(x, mulmod(x2, x2, q_r), q_r) - } // =============================================================== + } + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -457,6 +468,7 @@ contract Halo2QuotientEvaluator { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -468,6 +480,7 @@ contract Halo2QuotientEvaluator { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0xb8e0) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -491,6 +504,7 @@ contract Halo2QuotientEvaluator { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -498,6 +512,7 @@ contract Halo2QuotientEvaluator { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // Limb-aware opcodes are opt-in compact forms for @@ -544,6 +559,7 @@ contract Halo2QuotientEvaluator { // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_cond_ptr, 0x3680), 0x6aa0) { q_program_fail() } } let q_acc := 0 @@ -578,6 +594,7 @@ contract Halo2QuotientEvaluator { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -590,12 +607,14 @@ contract Halo2QuotientEvaluator { for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -615,6 +634,8 @@ contract Halo2QuotientEvaluator { let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, 0x04) + if gt(sub(q_lhs_base, 0x3680), 0x69e0) { q_program_fail() } + if gt(sub(q_rhs_base, 0x3680), 0x69e0) { q_program_fail() } let q_coeff_pc := q_pc q_pc := add(q_pc, 13) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { @@ -640,6 +661,7 @@ contract Halo2QuotientEvaluator { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -654,6 +676,8 @@ contract Halo2QuotientEvaluator { let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -1277,7 +1301,7 @@ contract Halo2QuotientEvaluator { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -1289,6 +1313,11 @@ contract Halo2QuotientEvaluator { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 10)) { q_program_fail() } + if gt(q_sel_gap, 0x30) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -1311,21 +1340,21 @@ contract Halo2QuotientEvaluator { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } + if iszero(eq(q_sp, 0xb8e0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled diff --git a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol index f4856ff11..ece93ee6b 100644 --- a/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/ivc-keccak-solidity-dump/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -61,8 +89,8 @@ contract Halo2Verifier { address public immutable AUTHORIZED_QUOTIENT; // Expected split evaluator runtime metadata. It is checked at deployment // and again immediately before each external quotient reconstruction. - uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9552; - uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c; + uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9790; + uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x7e72c7c5d6fe845370d9431aaa590ab2cd62ca703c3d5b2a862bdb9937195814; bytes32 internal constant EXPECTED_QUOTIENT_CODEHASH = bytes32(EXPECTED_QUOTIENT_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -231,6 +259,33 @@ contract Halo2Verifier { // runtime, which only lowers the actual cost below this bound. uint256 internal constant ACC_RHS_MSM_GAS = 12000; + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x5c2e8be9a8dc4e220b823ce41569f6a757baefeed4df0a04ef5e67db74b36d27; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -403,8 +458,12 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0xb140 for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) @@ -462,10 +521,24 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -491,7 +564,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -520,7 +596,15 @@ contract Halo2Verifier { // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -533,8 +617,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x3580 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -544,8 +628,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -605,16 +689,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -776,14 +860,14 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -795,7 +879,7 @@ contract Halo2Verifier { // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -1000,6 +1084,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -1035,6 +1127,10 @@ contract Halo2Verifier { // 3. folds the RHS carried point and fixed-base scalar tail into // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for // randomized batching in FinalPairing.yul. + // `r` is consumed only by the canonicality guards in the + // carried-scalar and fixed-base-tail arms; renders whose + // accumulator layout has neither (e.g. point_pair with no tail) + // legally leave it unused. function validate_public_accumulator(success, r) -> out { out := success let bits := 56 @@ -1191,7 +1287,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1208,7 +1304,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 4)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 7)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 56)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1232,7 +1328,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // Fail malformed accumulator public inputs before transcript, // quotient, PCS, and final pairing work. The late accumulator block @@ -1248,7 +1344,7 @@ contract Halo2Verifier { // success-plumbing style as other helper calls; this boundary is // where the verifier converts failure to a revert. success := validate_public_accumulator(success, r) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } gas_checkpoint(2) // after VK loading + accumulator public-input precheck // =============================================================== @@ -1318,7 +1414,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } gas_checkpoint(3) // after VK digest + committed_pi + instance absorbs @@ -1508,7 +1604,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1561,7 +1657,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1587,11 +1683,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } gas_checkpoint(10) // after evaluations + x1/x2 + f_com + x3 + q_evals + x4 + pi (transcript done) // =============================================================== @@ -1676,7 +1772,7 @@ contract Halo2Verifier { } gas_checkpoint(11) // after Lagrange + instance evaluation block - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } // =============================================================== @@ -1698,15 +1794,15 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // gas() forwarding is deliberate here, unlike the precompile // call sites: this is a regular contract call, so a reverting // or failing callee refunds its unused gas -- only precompile // ERRORS burn everything forwarded (EIP-2537). The callee is // also pinned by codehash above, not attacker-supplied. - if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x0180)) { revert(0, 0) } - if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { revert(0, 0) } + if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } + if iszero(eq(returndatasize(), 0x0180)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } + if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } // Word 1 is the negated y-batched identity numerator, stored // in the same memory slot used by the monolithic path. mstore(QUOTIENT_EVAL_MPTR, mload(add(q_out, 0x20))) @@ -2417,16 +2513,19 @@ contract Halo2Verifier { { let batch_ptr := 0x1000 - // Domain || KZG rhs/lhs || accumulator rhs/lhs. + // Domain || vk_digest || KZG rhs/lhs || accumulator rhs/lhs. + // vk_digest makes alpha's binding to the verifying key local + // instead of transitive-through-the-points (audit I-7). mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) - mcopy(add(batch_ptr, 0x20), PAIRING_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0xa0), PAIRING_LHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x0120), ACC_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x01a0), ACC_LHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x20), mload(VK_DIGEST_MPTR)) + mcopy(add(batch_ptr, 0x40), PAIRING_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0xc0), PAIRING_LHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x0140), ACC_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x01c0), ACC_LHS_MPTR, 0x80) // alpha is Fiat-Shamir over the fully materialized pairing // inputs. Replace the negligible zero draw with one so the // accumulator equation cannot be accidentally dropped. - let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0220), r) + let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0240), r) if iszero(acc_pair_alpha) { acc_pair_alpha := 1 } // PAIRING_RHS_MPTR += alpha * ACC_RHS_MPTR. @@ -2473,7 +2572,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) gas_checkpoint(16) // after final ec_pairing @@ -2486,7 +2585,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol index fb2e21309..c44946f7f 100644 --- a/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/poseidon-fixture-dump/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -219,6 +247,33 @@ contract Halo2Verifier { // Exact cost of the deployment-time worst-case G1MSM smoke probe. uint256 internal constant G1MSM_GAS_SMOKE = 337836; + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x521a3bd7a16dfa041e1716ee7a4905275d964b4a8a2f9a3d6ee839ea10414812; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -391,8 +446,12 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0x65e0 for { let off := 0 } lt(off, 0x1d60) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) @@ -438,10 +497,24 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -467,7 +540,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -493,7 +569,15 @@ contract Halo2Verifier { // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -506,8 +590,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x2800 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -517,8 +601,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -578,16 +662,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -749,14 +833,14 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -768,7 +852,7 @@ contract Halo2Verifier { // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -973,6 +1057,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -1033,7 +1125,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1050,7 +1142,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 0)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1074,7 +1166,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // =============================================================== @@ -1144,7 +1236,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } // =============================================================== @@ -1311,7 +1403,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1364,7 +1456,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1390,11 +1482,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1477,9 +1569,19 @@ contract Halo2Verifier { mstore(INSTANCE_EVAL_MPTR, instance_eval) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } - // Optional quotient helper functions. Each one is rendered only + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding @@ -1499,7 +1601,8 @@ contract Halo2Verifier { let q_r := FR_MODULUS let x2 := mulmod(x, x, q_r) z := mulmod(x, mulmod(x2, x2, q_r), q_r) - } // =============================================================== + } + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -1797,6 +1900,7 @@ contract Halo2Verifier { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2900), 0x3340) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -1808,6 +1912,7 @@ contract Halo2Verifier { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0x6960) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -1831,6 +1936,7 @@ contract Halo2Verifier { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2900), 0x3340) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -1838,6 +1944,7 @@ contract Halo2Verifier { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2900), 0x3340) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // Native permutation callback. It evaluates the @@ -2142,7 +2249,7 @@ contract Halo2Verifier { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x6960), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -2154,6 +2261,11 @@ contract Halo2Verifier { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 4)) { q_program_fail() } + if gt(q_sel_gap, 0x15) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -2176,21 +2288,21 @@ contract Halo2Verifier { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x6960)) { revert(0, 0) } + if iszero(eq(q_sp, 0x6960)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2890,7 +3002,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) @@ -2902,7 +3014,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol index 7530e2cdc..88b985fac 100644 --- a/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/rsa-signature-fixture-dump/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -219,6 +247,33 @@ contract Halo2Verifier { // Exact cost of the deployment-time worst-case G1MSM smoke probe. uint256 internal constant G1MSM_GAS_SMOKE = 299628; + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0xc8ebd03a9db607769309801d4400ca32e5c4da41621ca090e5ec163f5855d744; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -391,8 +446,12 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0x5f40 for { let off := 0 } lt(off, 0x19a0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) @@ -438,10 +497,24 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -467,7 +540,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -493,7 +569,15 @@ contract Halo2Verifier { // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -506,8 +590,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x2560 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -517,8 +601,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -578,16 +662,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -749,14 +833,14 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -768,7 +852,7 @@ contract Halo2Verifier { // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -973,6 +1057,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -1033,7 +1125,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1050,7 +1142,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 0)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1074,7 +1166,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // =============================================================== @@ -1144,7 +1236,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } // =============================================================== @@ -1299,7 +1391,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1352,7 +1444,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1378,11 +1470,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1465,13 +1557,24 @@ contract Halo2Verifier { mstore(INSTANCE_EVAL_MPTR, instance_eval) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } - // Optional quotient helper functions. Each one is rendered only + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding - // numerator block. // =============================================================== + // numerator block. + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -1983,25 +2086,25 @@ contract Halo2Verifier { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x61c0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x61c0)) { revert(0, 0) } + if iszero(eq(q_sp, 0x61c0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -2486,7 +2589,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) @@ -2498,7 +2601,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol index 8b60fba1c..b418c826b 100644 --- a/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol +++ b/proofs/solidity-verifier/target/sha-preimage-fixture-dump/Halo2Verifier.sol @@ -45,6 +45,34 @@ pragma solidity 0.8.30; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -219,6 +247,33 @@ contract Halo2Verifier { // Exact cost of the deployment-time worst-case G1MSM smoke probe. uint256 internal constant G1MSM_GAS_SMOKE = 436212; + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x1c7b7ee0fa4c51d53a25031f26abb34b3e31f13dc83e83927465e52cb369a210; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -391,8 +446,12 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0x7a80 for { let off := 0 } lt(off, 0x2760) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) @@ -438,10 +497,24 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead /// of Solidity's free-memory pointer. Generated scratch starts at /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's @@ -467,7 +540,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -493,7 +569,15 @@ contract Halo2Verifier { // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -506,8 +590,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x2ba0 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -517,8 +601,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -578,16 +662,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -749,14 +833,14 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) @@ -768,7 +852,7 @@ contract Halo2Verifier { // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -973,6 +1057,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -1033,7 +1125,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1050,7 +1142,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 0)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 0)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1074,7 +1166,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // =============================================================== @@ -1144,7 +1236,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } // =============================================================== @@ -1315,7 +1407,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1368,7 +1460,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1394,11 +1486,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1481,13 +1573,24 @@ contract Halo2Verifier { mstore(INSTANCE_EVAL_MPTR, instance_eval) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } - // Optional quotient helper functions. Each one is rendered only + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding - // numerator block. // =============================================================== + // numerator block. + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -1789,6 +1892,7 @@ contract Halo2Verifier { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -1800,6 +1904,7 @@ contract Halo2Verifier { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0x80e0) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -1836,6 +1941,7 @@ contract Halo2Verifier { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -1843,6 +1949,7 @@ contract Halo2Verifier { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // VM 0x13 ADD_MUL_CONST_U8_MEM_U16: fused q_top += mem * const. @@ -1852,6 +1959,7 @@ contract Halo2Verifier { let q_ptr := shr(240, q_word) let qconst := byte(2, q_word) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_top := addmod( q_top, mulmod(mload(q_ptr), mload(add(q_const_mptr, shl(5, qconst))), r), @@ -1896,6 +2004,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1933,6 +2042,7 @@ contract Halo2Verifier { // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_cond_ptr, 0x2ca0), 0x4340) { q_program_fail() } } let q_acc := 0 @@ -1967,6 +2077,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1979,12 +2090,14 @@ contract Halo2Verifier { for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_lhs, 0x2ca0), 0x4340) { q_program_fail() } let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_rhs, 0x2ca0), 0x4340) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -2004,6 +2117,8 @@ contract Halo2Verifier { let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, 0x04) + if gt(sub(q_lhs_base, 0x2ca0), 0x4280) { q_program_fail() } + if gt(sub(q_rhs_base, 0x2ca0), 0x4280) { q_program_fail() } let q_coeff_pc := q_pc q_pc := add(q_pc, 13) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { @@ -2029,6 +2144,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x2ca0), 0x4340) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -2043,6 +2159,8 @@ contract Halo2Verifier { let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + if gt(sub(q_lhs, 0x2ca0), 0x4340) { q_program_fail() } + if gt(sub(q_rhs, 0x2ca0), 0x4340) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -2526,7 +2644,7 @@ contract Halo2Verifier { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0x80e0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -2538,6 +2656,11 @@ contract Halo2Verifier { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 14)) { q_program_fail() } + if gt(q_sel_gap, 0x22) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -2560,21 +2683,21 @@ contract Halo2Verifier { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0x80e0)) { revert(0, 0) } + if iszero(eq(q_sp, 0x80e0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -3233,7 +3356,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) @@ -3245,7 +3368,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/tests/ivc_keccak_solidity.rs b/proofs/solidity-verifier/tests/ivc_keccak_solidity.rs index e28144fc0..b7a30f01f 100644 --- a/proofs/solidity-verifier/tests/ivc_keccak_solidity.rs +++ b/proofs/solidity-verifier/tests/ivc_keccak_solidity.rs @@ -1144,6 +1144,9 @@ fn ivc_final_keccak_solidity_e2e() { trace: quotient_trace_enabled, gas_checkpoints: gas_checkpoints_enabled, }, + // Repository dumps stay provenance-free so they are byte-stable + // across commits; deployment builds set this (P10/L-8). + provenance: None, }) .expect("pinned quotient render should succeed"); let verifier_solidity = artifacts.verifier; diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs index 67be759b8..4bc1b7324 100644 --- a/proofs/solidity-verifier/tests/template_digest.rs +++ b/proofs/solidity-verifier/tests/template_digest.rs @@ -13,7 +13,7 @@ use sha3::{Digest, Keccak256}; /// keccak over the sorted (path, length, content) stream of `templates/`. const EXPECTED_TEMPLATE_TREE_DIGEST: &str = - "0x87a5652da53283b444bf2c5c3bdbb2242c9cd7c0f183b9e5a3c0e60dd184f24b"; + "0x0809729cd0ee884736704458fbc53a2afc62c0de675b3a749b3c22c9ac797671"; fn collect_files(dir: &Path, files: &mut Vec) { for entry in fs::read_dir(dir).expect("template directory is readable") { From 85b7fa3d2acf4eda94d12d2056b1137d94af5099 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 11:21:45 +0100 Subject: [PATCH 099/108] chore(solidity-verifier): regenerate both replay fixtures on the hardened codegen The committed replay fixtures were pinned pre-hardening snapshots, so the replay tests had stopped exercising current output (the exact situation L-1/P14 flagged). Both are now re-rendered at f894f75: - fixtures/moonlight-wrap: re-rendered via the external Moonlight checkout (origin/codex/wrap-bench-cherry-picks @ 1940ea9, scratch worktree with the documented local-path Cargo unification; the user's Moonlight clone was left untouched). The real wrap decider proof verifies on-chain in 1,338,272 gas, and the trace render matched all 244 native Rust/Solidity trace points against the hardened templates. - fixtures/ivc: refreshed from the canonical target/ivc-keccak-solidity-dump render (1,365,883 gas, checkpoint profile). Both fixture verifiers now carry the exact precompile gas bounds, typed errors, VM operand clamps, BUILD_ID, and the alpha vk-binding; the accumulator-mutation replay matrices pass against the regenerated artifacts, and the provenance stamps are updated. Co-Authored-By: Claude Fable 5 --- .../fixtures/ivc/Halo2QuotientEvaluator.sol | 75 ++- .../fixtures/ivc/Halo2Verifier.sol | 439 ++++++++++++++--- .../fixtures/ivc/Halo2VerifyingKey.sol | 5 +- .../solidity-verifier/fixtures/ivc/README.md | 4 +- .../fixtures/ivc/calldata.bin | Bin 8356 -> 8356 bytes .../fixtures/moonlight-wrap/Halo2Verifier.sol | 457 ++++++++++++++---- .../moonlight-wrap/Halo2VerifyingKey.sol | 5 +- .../fixtures/moonlight-wrap/README.md | 7 +- .../fixtures/moonlight-wrap/calldata.bin | Bin 8516 -> 8516 bytes 9 files changed, 800 insertions(+), 192 deletions(-) diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol index c2bc6699d..30464e1e4 100644 --- a/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2QuotientEvaluator.sol @@ -1,5 +1,8 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Split Halo2 quotient numerator evaluator. /// @notice Reconstructs the scalar side of the linearization query for a generated verifier. @@ -135,7 +138,17 @@ contract Halo2QuotientEvaluator { // block mirrors that rule by accumulating those identities into // SELECTOR_ACC_MPTR buckets for later multiplication by fixed // selector commitments, while fully evaluated identities contribute - // to the negated expected scalar. // Optional quotient helper functions. Each one is rendered only + // to the negated expected scalar. // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } + + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding @@ -155,7 +168,8 @@ contract Halo2QuotientEvaluator { let q_r := FR_MODULUS let x2 := mulmod(x, x, q_r) z := mulmod(x, mulmod(x2, x2, q_r), q_r) - } // =============================================================== + } + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -416,18 +430,21 @@ contract Halo2QuotientEvaluator { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity + // 0x21 modarith7 // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -451,6 +468,7 @@ contract Halo2QuotientEvaluator { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -462,6 +480,7 @@ contract Halo2QuotientEvaluator { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0xb8e0) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -485,6 +504,7 @@ contract Halo2QuotientEvaluator { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -492,6 +512,7 @@ contract Halo2QuotientEvaluator { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // Limb-aware opcodes are opt-in compact forms for @@ -538,6 +559,7 @@ contract Halo2QuotientEvaluator { // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_cond_ptr, 0x3680), 0x6aa0) { q_program_fail() } } let q_acc := 0 @@ -572,6 +594,7 @@ contract Halo2QuotientEvaluator { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -584,12 +607,14 @@ contract Halo2QuotientEvaluator { for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -609,6 +634,8 @@ contract Halo2QuotientEvaluator { let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, 0x04) + if gt(sub(q_lhs_base, 0x3680), 0x69e0) { q_program_fail() } + if gt(sub(q_rhs_base, 0x3680), 0x69e0) { q_program_fail() } let q_coeff_pc := q_pc q_pc := add(q_pc, 13) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { @@ -634,6 +661,7 @@ contract Halo2QuotientEvaluator { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -648,6 +676,8 @@ contract Halo2QuotientEvaluator { let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -1271,7 +1301,7 @@ contract Halo2QuotientEvaluator { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -1283,6 +1313,11 @@ contract Halo2QuotientEvaluator { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 10)) { q_program_fail() } + if gt(q_sel_gap, 0x30) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -1305,21 +1340,21 @@ contract Halo2QuotientEvaluator { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } + if iszero(eq(q_sp, 0xb8e0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol index 48f05f35a..ece93ee6b 100644 --- a/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -34,6 +45,34 @@ pragma solidity ^0.8.24; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -50,8 +89,8 @@ contract Halo2Verifier { address public immutable AUTHORIZED_QUOTIENT; // Expected split evaluator runtime metadata. It is checked at deployment // and again immediately before each external quotient reconstruction. - uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9552; - uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x6a7ec82a9b0683783c459f4b43e924f8ceba256731bf2b9782ab5747e801ea2c; + uint256 internal constant EXPECTED_QUOTIENT_LENGTH = 9790; + uint256 internal constant EXPECTED_QUOTIENT_CODEHASH_WORD = 0x7e72c7c5d6fe845370d9431aaa590ab2cd62ca703c3d5b2a862bdb9937195814; bytes32 internal constant EXPECTED_QUOTIENT_CODEHASH = bytes32(EXPECTED_QUOTIENT_CODEHASH_WORD); // Solidity ABI calldata cursors. The generated verifier accepts exactly @@ -145,10 +184,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x9320; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -190,6 +232,60 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 525096; + // Worst-case accumulator RHS MSM: carried RHS point plus every generated + // fixed-base tail scalar nonzero. Zero tail scalars are omitted at + // runtime, which only lowers the actual cost below this bound. + uint256 internal constant ACC_RHS_MSM_GAS = 12000; + + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x5c2e8be9a8dc4e220b823ce41569f6a757baefeed4df0a04ef5e67db74b36d27; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -207,8 +303,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -228,7 +333,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -249,7 +354,7 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -262,6 +367,90 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -269,15 +458,19 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0xb140 for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -287,7 +480,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -328,24 +521,40 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. function verifyProof( bytes calldata proof, uint256[] calldata instances - ) external view returns (bool) { + ) external returns (bool) { // Cheap ABI-shape guard before any generated memory work: // - proof head must point at the bytes payload; // - instances head must point at the generated instance array. @@ -355,7 +564,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -366,15 +578,33 @@ contract Halo2Verifier { // reconstruction to a separately deployed generated evaluator. address quotientEvaluator = AUTHORIZED_QUOTIENT; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -387,8 +617,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x3580 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -398,8 +628,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -459,16 +689,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -543,7 +773,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -593,7 +823,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -630,26 +860,26 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -854,6 +1084,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -889,6 +1127,10 @@ contract Halo2Verifier { // 3. folds the RHS carried point and fixed-base scalar tail into // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for // randomized batching in FinalPairing.yul. + // `r` is consumed only by the canonicality guards in the + // carried-scalar and fixed-base-tail arms; renders whose + // accumulator layout has neither (e.g. point_pair with no tail) + // legally leave it unused. function validate_public_accumulator(success, r) -> out { out := success let bits := 56 @@ -936,7 +1178,7 @@ contract Halo2Verifier { // Single-pair MSM output overwrites ACC_LHS_MPTR with // lhs_scalar * decoded_lhs. If lhs_scalar is one, this // is also a curve/subgroup validation round-trip. - out := staticcall(gas(), 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) + out := staticcall(G1MSM_GAS_1PAIR, 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) out := and(out, eq(returndatasize(), 0x80)) } } @@ -982,8 +1224,11 @@ contract Halo2Verifier { // // The precompile also validates every nonzero fixed // base embedded by codegen and the carried RHS point. + // ACC_RHS_MSM_GAS is the compile-time worst case + // (every tail scalar nonzero); acc_msm_len can only + // select a same-size-or-smaller MSM at runtime. out := staticcall( - gas(), + ACC_RHS_MSM_GAS, 0x0c, acc_scratch, acc_msm_len, @@ -998,11 +1243,20 @@ contract Halo2Verifier { } + // Section-boundary gas-attribution checkpoint. Emits a + // single LOG1 (no data) with topic = (id << 248) | gas(). + // Cost: 375 (LOG base) + 375 (1 topic) = 750 gas/call. + // Host-side parses the topic into (id, gas_left) and prints + // pairwise deltas (see `dump_gas_checkpoints`). + function gas_checkpoint(id) { + log1(0, 0, or(shl(248, id), gas())) + } let r := FR_MODULUS let success := true + gas_checkpoint(1) // entry: before VK loading // =============================================================== // VK loading: either bake in the embedded VK bytes or fetch @@ -1033,7 +1287,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1050,7 +1304,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 4)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 7)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 56)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1074,7 +1328,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // Fail malformed accumulator public inputs before transcript, // quotient, PCS, and final pairing work. The late accumulator block @@ -1090,7 +1344,8 @@ contract Halo2Verifier { // success-plumbing style as other helper calls; this boundary is // where the verifier converts failure to a revert. success := validate_public_accumulator(success, r) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } + gas_checkpoint(2) // after VK loading + accumulator public-input precheck // =============================================================== // Transcript: VK digest + instances + proof. @@ -1159,8 +1414,9 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } + gas_checkpoint(3) // after VK digest + committed_pi + instance absorbs // =============================================================== // Per-user-phase reads + challenge squeezes. @@ -1198,6 +1454,7 @@ contract Halo2Verifier { advice_walk := add(advice_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(4) // after user-phase advice reads + user challenge squeezes // ---- theta ---- // From this point onward the transcript alternates between @@ -1217,6 +1474,7 @@ contract Halo2Verifier { lookup_m_walk := add(lookup_m_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(5) // after theta squeeze + lookup multiplicities // ---- beta, gamma ---- // beta and gamma are the permutation/lookup randomizers. They are @@ -1236,6 +1494,7 @@ contract Halo2Verifier { perm_z_walk := add(perm_z_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(6) // after beta/gamma + permutation Z products // ---- lookup helpers + accumulators (per-lookup) ---- // Each lookup contributes zero or more helper commitments followed // by its lookup accumulator Z commitment. The generated layout keeps @@ -1276,6 +1535,7 @@ contract Halo2Verifier { calldatacopy(lookup_z_walk, proof_cptr, 0x80) lookup_z_walk := add(lookup_z_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) + gas_checkpoint(7) // after lookup helpers + Z accumulators // ---- trash_challenge ---- // Midnight squeezes this challenge unconditionally, even when the @@ -1295,6 +1555,7 @@ contract Halo2Verifier { trashcan_walk := add(trashcan_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(8) // after trash_challenge + trashcans // ---- y ---- // y batches all quotient identities. Quotient commitments are read @@ -1318,6 +1579,7 @@ contract Halo2Verifier { quotient_walk := add(quotient_walk, 0x80) proof_cptr := add(proof_cptr, 0x80) } + gas_checkpoint(9) // after y squeeze + quotient-limb reads // ---- x ---- // x is the main evaluation point. Values read after this point are @@ -1342,7 +1604,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1395,7 +1657,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1421,11 +1683,12 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } + gas_checkpoint(10) // after evaluations + x1/x2 + f_com + x3 + q_evals + x4 + pi (transcript done) // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1507,8 +1770,9 @@ contract Halo2Verifier { mstore(L_0_MPTR, l_0) mstore(INSTANCE_EVAL_MPTR, instance_eval) } + gas_checkpoint(11) // after Lagrange + instance evaluation block - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } // =============================================================== @@ -1530,10 +1794,15 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(quotientEvaluator), EXPECTED_QUOTIENT_LENGTH), eq(extcodehash(quotientEvaluator), EXPECTED_QUOTIENT_CODEHASH_WORD) - )) { revert(0, 0) } - if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x0180)) { revert(0, 0) } - if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } + // gas() forwarding is deliberate here, unlike the precompile + // call sites: this is a regular contract call, so a reverting + // or failing callee refunds its unused gas -- only precompile + // ERRORS burn everything forwarded (EIP-2537). The callee is + // also pinned by codehash above, not attacker-supplied. + if iszero(staticcall(gas(), quotientEvaluator, 0x3680, 0x6ac0, q_out, 0x0180)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } + if iszero(eq(returndatasize(), 0x0180)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } + if iszero(eq(mload(q_out), 0x00000000000000000000000000000000000000000000000051554556414c0001)) { fail(ERR_QUOTIENT_PROGRAM_INVALID) } // Word 1 is the negated y-batched identity numerator, stored // in the same memory slot used by the monolithic path. mstore(QUOTIENT_EVAL_MPTR, mload(add(q_out, 0x20))) @@ -1545,6 +1814,7 @@ contract Halo2Verifier { mstore(add(SELECTOR_ACC_MPTR, shl(5, q_i)), mload(add(q_out, add(0x40, shl(5, q_i))))) } } + gas_checkpoint(12) // after batched identity numerator reconstruction // =============================================================== // Prepare linearization scalars for the final PCS MSM. @@ -1586,6 +1856,7 @@ contract Halo2Verifier { mstore(QUOTIENT_MPTR, x_split) mstore(add(QUOTIENT_MPTR, 0x20), one_minus_x_n) } + gas_checkpoint(13) // after linearization scalar prep // =============================================================== // PCS computation (multi-prepare emitter from Step 5). @@ -1624,6 +1895,7 @@ contract Halo2Verifier { x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) mstore(add(ROT_POINTS_MPTR, 0x0), x_pow_of_omega) } + gas_checkpoint(17) // after PCS sub-block 1 // Generated PCS sub-block 2. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -1639,11 +1911,12 @@ contract Halo2Verifier { mstore(p, and(acc, 0xffffffffffffffffffffffffffffffff)) } } + gas_checkpoint(18) // after PCS sub-block 2 // Generated PCS sub-block 3. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 43 evaluation term(s), 42 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9980) mstore(0xb2a0, 0x9480) @@ -1699,11 +1972,12 @@ contract Halo2Verifier { } mstore(add(Q_EVAL_SET_MPTR, 0x0), q_eval_set_0) } + gas_checkpoint(19) // after PCS sub-block 3 // Generated PCS sub-block 4. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 3 commitment(s) + // q_eval_set[1]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9660) let q_eval_set_1 := mload(0x9920) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -1713,11 +1987,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x20), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x40), q_eval_set_1) } + gas_checkpoint(20) // after PCS sub-block 4 // Generated PCS sub-block 5. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 3 commitment(s) + // q_eval_set[2]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9fe0) let q_eval_set_1 := mload(0xa000) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -1727,11 +2002,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x60), q_eval_set_0) mstore(add(Q_EVAL_SET_MPTR, 0x80), q_eval_set_1) } + gas_checkpoint(21) // after PCS sub-block 5 // Generated PCS sub-block 6. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) + // q_eval_set[3]: 11 evaluation term(s), 11 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x94a0) mstore(0xb2a0, 0x9540) @@ -1783,11 +2059,12 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0xc0), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0xe0), q_eval_set_2) } + gas_checkpoint(22) // after PCS sub-block 6 // Generated PCS sub-block 7. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) + // q_eval_set[4]: 5 evaluation term(s), 5 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9e00) mstore(0xb2a0, 0x9e20) @@ -1821,6 +2098,7 @@ contract Halo2Verifier { mstore(add(Q_EVAL_SET_MPTR, 0x120), q_eval_set_1) mstore(add(Q_EVAL_SET_MPTR, 0x140), q_eval_set_2) } + gas_checkpoint(23) // after PCS sub-block 7 // Generated PCS sub-block 8. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -1989,6 +2267,7 @@ contract Halo2Verifier { } mstore(F_EVAL_MPTR, f_eval) } + gas_checkpoint(24) // after PCS sub-block 8 // Generated PCS sub-block 9. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -2178,11 +2457,13 @@ contract Halo2Verifier { mcopy(0xe2a0, F_COM_MPTR, 0x80) mstore(0xe320, x4_pow_5) if success { - success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 78 pair(s) + success := staticcall(525096, 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) } + gas_checkpoint(25) // after PCS sub-block 9 // Generated PCS sub-block 10. These lines are // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. @@ -2193,27 +2474,28 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) } } + gas_checkpoint(14) // after PCS computation block (= sub-block 6) // Batch the prevalidated public IVC accumulator pairing equation // into the final KZG pairing. @@ -2231,16 +2513,19 @@ contract Halo2Verifier { { let batch_ptr := 0x1000 - // Domain || KZG rhs/lhs || accumulator rhs/lhs. + // Domain || vk_digest || KZG rhs/lhs || accumulator rhs/lhs. + // vk_digest makes alpha's binding to the verifying key local + // instead of transitive-through-the-points (audit I-7). mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) - mcopy(add(batch_ptr, 0x20), PAIRING_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0xa0), PAIRING_LHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x0120), ACC_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x01a0), ACC_LHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x20), mload(VK_DIGEST_MPTR)) + mcopy(add(batch_ptr, 0x40), PAIRING_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0xc0), PAIRING_LHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x0140), ACC_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x01c0), ACC_LHS_MPTR, 0x80) // alpha is Fiat-Shamir over the fully materialized pairing // inputs. Replace the negligible zero draw with one so the // accumulator equation cannot be accidentally dropped. - let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0220), r) + let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0240), r) if iszero(acc_pair_alpha) { acc_pair_alpha := 1 } // PAIRING_RHS_MPTR += alpha * ACC_RHS_MPTR. @@ -2249,12 +2534,12 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_RHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_RHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } @@ -2263,15 +2548,16 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_LHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_LHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } } + gas_checkpoint(15) // after public accumulator pairing batch prep (omitted for no-accumulator VKs) // The Yul `ec_pairing` helper checks // e(arg0, G2_BASE) * e(arg1, NEG_S_G2_BASE) == 1 @@ -2286,8 +2572,9 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) + gas_checkpoint(16) // after final ec_pairing @@ -2298,7 +2585,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol b/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol index f8c08652b..c51a80c36 100644 --- a/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/fixtures/ivc/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md index 2f44e95c7..81951bb38 100644 --- a/proofs/solidity-verifier/fixtures/ivc/README.md +++ b/proofs/solidity-verifier/fixtures/ivc/README.md @@ -14,11 +14,11 @@ is what makes a vk.bin-based replay unusable in CI. | Field | Value | | --- | --- | -| Source commit | `6753679` | +| Source commit | `f894f75` | | Rendered by | `tests/ivc_keccak_solidity.rs` (`ivc_final_keccak_solidity_e2e`) | | Circuit | IVC k=19 leaves, k=20 decider | | Accumulator | `AccumulatorEncoding::new(offset=4, num_limbs=7, num_limb_bits=56)` | -| Verified on-chain | yes, 1,286,780 gas under revm Prague | +| Verified on-chain | yes, 1,365,883 gas under revm Prague (2026-08-13 render: exact precompile gas bounds, typed errors, VM operand clamps, BUILD_ID, alpha vk-binding; gas-checkpoint bench profile) | ## Regenerating diff --git a/proofs/solidity-verifier/fixtures/ivc/calldata.bin b/proofs/solidity-verifier/fixtures/ivc/calldata.bin index 66e2fad5af082449ef70a1d61af4083c79a60a0f..0e7e61f5be728e64fb23cfef2892e08c533d8ca7 100644 GIT binary patch literal 8356 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 Q?gU+u`rqsS!#&i00g*Nz5dZ)H literal 8356 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 S*JegLc)ZB}%>OTA`2PaT_%IUy diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol index c80ed093b..713a6b431 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2Verifier.sol @@ -1,5 +1,16 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned, not floating. Two properties of this artifact are compiler- and +// optimiser-dependent, and neither is visible in the source: +// 1. The generated layout writes absolute addresses from TRANSCRIPT_MPTR +// upward. That is only safe while solc's stack-spill reservation stays +// below it -- measured 0x8c0 on 0.8.24 and 0x8e0 on 0.8.26+, so it is not +// a constant this file controls. verifyProof now asserts the separation. +// 2. Runtime size depends on --optimize-runs. Measured: 0.8.24 at runs=1 +// emits 29,567 bytes and 0.8.30 at runs=100000 emits 29,836 -- both over +// the EIP-170 24,576-byte limit, so neither can be deployed. Only the +// pinned (version, runs) pair is known to produce a deployable contract. +// A floating `^0.8.24` advertises compatibility this contract does not have. +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 KZG verifier. /// @notice Circuit-specialized verifier for Midfall/midnight-proofs Halo2 @@ -34,6 +45,34 @@ pragma solidity ^0.8.24; /// precompiles using identity inputs. Compile with Solidity >=0.8.24 and /// deploy only on chains/forks that support MCOPY and EIP-2537. contract Halo2Verifier { + // ---------------------------------------------------------------------- + // Typed failure taxonomy (P4/L-3, docs/audit/HALO2_VERIFIER_REVIEW). + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. + // Constructor smoke probes intentionally keep bare reverts. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). + error BadCalldataShape(); + /// @notice The pinned verifying-key (or VK header cross-check) does not + /// match the generated constants. + error VkMismatch(); + /// @notice A public instance or proof scalar is >= the BLS12-381 scalar + /// modulus. + error NonCanonicalScalar(); + /// @notice A proof point violates the EIP-2537 padded encoding or its + /// coordinates are >= the base-field modulus. + error BadPointEncoding(); + /// @notice A precompile call failed or returned an unexpected size. + error PrecompileFailed(); + /// @notice The final pairing (or its staging) rejected the proof. + error ProofRejected(); + /// @notice The pinned quotient program or evaluator violated a structural + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); + /// @notice Verifying-key contract address authorized for this verifier. /// @dev The runtime length and codehash are pinned by generated constants and checked at construction time. @@ -137,10 +176,13 @@ contract Halo2Verifier { uint256 internal constant Q_EVAL_CPTR_MPTR = 0x9220; // Reserved 4-word slot for the G1 identity (point at infinity) in - // EIP-2537 padded form. EVM memory is zero-initialised, and we - // never write to this region, so the four `mload`s below produce - // 0,0,0,0 which is exactly the identity encoding the EIP-2537 - // ec_add / ec_mul precompiles accept. + // EIP-2537 padded form. EVM memory is zero-initialised, and the verifier + // never writes to this region, so any read of this slot (the PCS + // emitters `mcopy` from it when staging identity commitments) yields + // 0,0,0,0 -- exactly the identity encoding the EIP-2537 precompiles + // accept. Artifacts whose PCS plan never stages an identity commitment + // still emit the constant; it costs no runtime bytes beyond the + // declaration and keeps the emitters' pointer model uniform. uint256 internal constant G1_IDENTITY_MPTR = 0x9320; // Decoded polynomial-eval buffer (Optimisation H3). The off-chain @@ -182,6 +224,60 @@ contract Halo2Verifier { uint256 internal constant TRASHCAN_COMMS_MPTR_BASE = 0xaec0; uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = 0xaf40; + // ---------------------------------------------------------------------- + // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled + // cost instead of gas(). A malformed proof point then burns at most the + // scheduled cost of the single failing call instead of 63/64 of the + // transaction budget. The schedule is the spec-guaranteed worst case + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // + // Liveness caveat: if a future fork reprices these precompiles UPWARD, + // this verifier must be regenerated and redeployed. The constructor + // smoke probes forward the same bounds, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = 375; + uint256 internal constant G1MSM_GAS_1PAIR = 12000; + uint256 internal constant PAIRING_GAS_2PAIR = 102900; + uint256 internal constant MODEXP_GAS = 1360; + // Exact cost of the deployment-time worst-case G1MSM smoke probe. + uint256 internal constant G1MSM_GAS_SMOKE = 525096; + // Worst-case accumulator RHS MSM: carried RHS point plus every generated + // fixed-base tail scalar nonzero. Zero tail scalars are omitted at + // runtime, which only lowers the actual cost below this bound. + uint256 internal constant ACC_RHS_MSM_GAS = 12000; + + /// @notice Build identity for this generated artifact (P10/L-8). + /// @dev keccak256 over: the domain tag "halo2-solidity-verifier-build-v1", + /// the u64-length-prefixed generator feature profile, the vk_digest, + /// the expected VK runtime codehash (zero when the VK is embedded), + /// the SRS fingerprint keccak("halo2-solidity-verifier-srs-v1" || n + /// || G2 || s_g2 || [tau]G1), and an optional 32-byte deployment + /// provenance tag (0x00 marker when absent, 0x01 || tag when set). + /// The deployment record must publish these preimage components so + /// third parties can recompute the id; see + /// docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md. + bytes32 public constant BUILD_ID = 0x76eca8e8f19f0bb8c7d8d0b7757bf44687a635676d3a55e5ca8efb47b4481999; + + // ---------------------------------------------------------------------- + // Typed-error selectors (P4/L-3): bytes4(keccak256("Name()")) of the + // errors declared on the contract, as Yul-readable constants. The + // `fail(sel)` helper in AssemblyHelpers.yul writes the selector to + // scratch 0x00 and reverts with 4 bytes. Pinned by + // `p4_error_selectors_match_declared_errors` in src/lowering/tests.rs. + // ---------------------------------------------------------------------- + uint256 internal constant ERR_BAD_CALLDATA_SHAPE = 0x1b99e37c; + uint256 internal constant ERR_VK_MISMATCH = 0xa447d73e; + uint256 internal constant ERR_NON_CANONICAL_SCALAR = 0x77530042; + uint256 internal constant ERR_BAD_POINT_ENCODING = 0xf27905ec; + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. uint256 internal constant FR_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001; @@ -199,8 +295,17 @@ contract Halo2Verifier { /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact EIP-2537 gas bounds the runtime + /// uses (see the gas-bound constants block), so a chain whose + /// precompile schedule was repriced upward fails here, at deployment, + /// instead of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). + if gt(mload(0x40), 0x1000) { revert(0, 0) } + // Scratch is reused for every runtime-prerequisite probe. let scratch := 0x1000 @@ -220,7 +325,7 @@ contract Halo2Verifier { // G1ADD(identity, identity) -> identity, 128-byte return. // This catches chains where the precompile is missing or returns a // non-standard success shape. - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -241,7 +346,41 @@ contract Halo2Verifier { mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) mcopy(add(scratch, 0x80), scratch, 0x80) - if iszero(staticcall(gas(), 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1ADD_GAS, 0x0b, scratch, 0x0100, scratch, 0x80)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } + if iszero(and( + and( + eq(mload(add(scratch, 0x00)), 0x000000000000000000000000000000000572cbea904d67468808c8eb50a9450c), + eq(mload(add(scratch, 0x20)), 0x9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e) + ), + and( + eq(mload(add(scratch, 0x40)), 0x00000000000000000000000000000000166a9d8cabc673a322fda673779d8e38), + eq(mload(add(scratch, 0x60)), 0x22ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) + ) + )) { revert(0, 0) } + + + // ---------------------------------------------------------------- + // Known-answer probes for the two precompiles that actually decide + // acceptance. + // + // Every probe above this point uses the point at infinity or a + // G1ADD vector. That leaves the two precompiles the verifier's + // security actually rests on untested for *rejection* behaviour: + // - 0x0c G1MSM is the curve/subgroup validator for every absorbed + // proof commitment (common_uncompressed_g1 runs no curve check); + // - 0x0f PAIRING_CHECK is the sole accept gate, so a chain whose + // 0x0f always returns 1 accepts every proof. + // These four probes cost deployment gas only. + // ---------------------------------------------------------------- + + // (a) G1MSM known answer: [2]*G == 2G. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x20), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x40), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x60), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x80), 2) + if iszero(staticcall(G1MSM_GAS_1PAIR, 0x0c, scratch, 0xa0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if iszero(and( and( @@ -254,6 +393,56 @@ contract Halo2Verifier { ) )) { revert(0, 0) } + // (b) G1MSM negative probe. (4, y) satisfies y^2 = x^3 + 4 over Fp + // but is NOT in the r-order subgroup (checked off-chain: r*P != O). + // EIP-2537 requires G1MSM to reject it. This is the one property + // the verifier's deferred-validation strategy depends on and the + // one property no other probe exercises. + // + // Gas is bounded on purpose: a precompile that rejects its input + // consumes everything forwarded to it, so an unbounded `gas()` here + // would burn 63/64 of the deployment gas before the probes below. + mstore(add(scratch, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000000) + mstore(add(scratch, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) + mstore(add(scratch, 0x40), 0x000000000000000000000000000000000a989badd40d6212b33cffc3f3763e9b) + mstore(add(scratch, 0x60), 0xc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) + mstore(add(scratch, 0x80), 1) + if staticcall(200000, 0x0c, scratch, 0xa0, scratch, 0x80) { revert(0, 0) } + + // (c)+(d) Pairing known answers. Lay out [G1 | G2 | G1' | G2] once: + // with G1' = -G the product is 1, with G1' = +G it is not. G2 is + // written literally because the VK payload is not loaded during + // construction. + mstore(add(scratch, 0x000), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x020), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x040), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x060), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + mstore(add(scratch, 0x080), 0x00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051) + mstore(add(scratch, 0x0a0), 0xc6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8) + mstore(add(scratch, 0x0c0), 0x0000000000000000000000000000000013e02b6052719f607dacd3a088274f65) + mstore(add(scratch, 0x0e0), 0x596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e) + mstore(add(scratch, 0x100), 0x000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351a) + mstore(add(scratch, 0x120), 0xadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) + mstore(add(scratch, 0x140), 0x000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99) + mstore(add(scratch, 0x160), 0xcb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be) + mstore(add(scratch, 0x180), 0x0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0f) + mstore(add(scratch, 0x1a0), 0xc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb) + mstore(add(scratch, 0x1c0), 0x00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f2) + mstore(add(scratch, 0x1e0), 0x67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) + mcopy(add(scratch, 0x200), add(scratch, 0x80), 0x100) + + // (c) e(G, G2) * e(-G, G2) == 1. + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(eq(mload(add(scratch, 0x300)), 1)) { revert(0, 0) } + + // (d) e(G, G2) * e(G, G2) != 1. Flip the second G1 back to +G. + mstore(add(scratch, 0x1c0), 0x0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4) + mstore(add(scratch, 0x1e0), 0xfcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, add(scratch, 0x300), 0x20)) { revert(0, 0) } + if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(iszero(mload(add(scratch, 0x300)))) { revert(0, 0) } + // Restore the identity encoding for the probes below. for { let off := 0 } lt(off, 0x0300) { off := add(off, 0x20) } { mstore(add(scratch, off), 0) @@ -261,15 +450,19 @@ contract Halo2Verifier { // Worst-case generated G1MSM with all identity/zero terms -> // identity, 128-byte return. This exercises the largest MSM input - // length rendered by this verifier instead of only a one-pair - // smoke call. + // LENGTH rendered by this verifier instead of only a one-pair + // smoke call, proving the target chain's precompile accepts the + // full-size input. It runs in the creation frame at its own + // scratch base, so it does not (and cannot) pre-expand the + // runtime call frame's memory -- constructor memory is discarded; + // only the input size coverage carries over. let msm_scratch := 0xb140 for { let off := 0 } lt(off, 0x30c0) { off := add(off, 0x20) } { mstore(add(msm_scratch, off), 0) } // The production verifier uses G1MSM both for commitments and as // the subgroup validator for absorbed proof points. - if iszero(staticcall(gas(), 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } + if iszero(staticcall(G1MSM_GAS_SMOKE, 0x0c, msm_scratch, 0x30c0, scratch, 0x80)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x80)) { revert(0, 0) } if or(or(mload(scratch), mload(add(scratch, 0x20))), or(mload(add(scratch, 0x40)), mload(add(scratch, 0x60)))) { revert(0, 0) @@ -279,7 +472,7 @@ contract Halo2Verifier { // -> true, 32-byte return. This matches the runtime two-pair KZG // pairing input size and catches absent pairing precompiles, // short return data, and obviously incompatible semantics. - if iszero(staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } + if iszero(staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20)) { revert(0, 0) } if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } if iszero(eq(mload(scratch), 1)) { revert(0, 0) } } @@ -308,17 +501,33 @@ contract Halo2Verifier { /// bind the meaning of those instances separately: state roots, program /// identifiers, expected IVC outputs, chain/domain separation, and any /// protocol-specific authorization are outside this raw verifier ABI. + /// Wrapper obligations (replaceable verifier address, wrapper-held pause, + /// chainid/address/anti-replay binding) and the incident-response + /// playbook are REQUIREMENTS documented in + /// `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md`. /// @dev Production renders are success-or-revert: accepted proofs return - /// `true`, while malformed calldata, invalid proof material, failed - /// precompiles, or mismatched pinned dependency code revert. Trace and gas - /// renders keep the same failure policy. + /// `true`; this function NEVER returns `false`. Every rejection reverts + /// with one of the typed errors declared above (BadCalldataShape, + /// VkMismatch, NonCanonicalScalar, BadPointEncoding, PrecompileFailed, + /// ProofRejected, QuotientProgramInvalid), so callers using + /// `if (!verifier.verifyProof(...))` never take the false branch — wrap + /// the call or decode the revert data instead. Trace and gas renders keep + /// the same failure policy. + /// @dev Calldata must be EXACTLY the ABI selector, proof bytes, and + /// generated instance words — `calldatasize` is pinned and any trailing + /// bytes revert with BadCalldataShape. In particular, ERC-2771 forwarders + /// and other calldata-appending relayers (multicall wrappers, paymaster + /// contexts) CANNOT call this contract directly; route such traffic + /// through an application wrapper that reassembles exact calldata. /// @dev The generated verifier uses absolute Yul memory addresses instead - /// of Solidity's free-memory pointer, but generated scratch starts at - /// `0x80` so Solidity's reserved memory prefix is preserved. The main + /// of Solidity's free-memory pointer. Generated scratch starts at + /// `TRANSCRIPT_MPTR`, which leaves Solidity's reserved prefix *and* solc's + /// stack-spill reservation below it untouched; the assembly block asserts + /// that separation on entry rather than assuming it. The main /// assembly block remains terminal: accepted proofs return from assembly /// and all rejected inputs revert. Do not inline this body into Solidity /// code that continues executing after verification without reviewing the - /// memory strategy; see `docs/MEMORY_LAYOUT.md`. + /// memory strategy; see `docs/architecture/MEMORY_LAYOUT.md`. /// @param proof Solidity-facing proof bytes, with G1 elements repacked into EIP-2537 padded uncompressed form. /// @param instances Public instance scalars encoded as canonical BLS12-381 scalar-field words. /// @return Always `true` for accepted proofs; invalid proofs revert instead of returning `false`. @@ -335,7 +544,10 @@ contract Halo2Verifier { // valid Midfall proof stream. assembly ("memory-safe") { if iszero(and(eq(calldataload(0x04), 0x40), eq(calldataload(0x24), sub(NUM_INSTANCE_CPTR, 0x04)))) { - revert(0, 0) + // BadCalldataShape() -- fail() is not in scope in this early + // guard block, so write the selector inline. + mstore(0x00, shl(224, ERR_BAD_CALLDATA_SHAPE)) + revert(0x00, 0x04) } } // Non-embedded renders pin the VK by address and codehash. The Yul @@ -343,15 +555,33 @@ contract Halo2Verifier { // INVALID-prefixed payload into VK_MPTR. address vk = AUTHORIZED_VK; assembly ("memory-safe") { + // The `memory-safe` annotation above is what enables solc's + // stack-to-memory mover, which reserves spill slots upward from + // 0x80. The generated layout below writes absolute addresses from + // TRANSCRIPT_MPTR upward and never consults the free-memory + // pointer, so the two regions must not meet. The size of that + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // This block owns the call-frame memory and remains terminal. - // Generated scratch starts at TRANSCRIPT_MPTR (0x80), preserving + // Generated scratch starts at TRANSCRIPT_MPTR, preserving // Solidity's reserved scratch, free-memory-pointer, and zero-slot - // words. See docs/MEMORY_LAYOUT.md. + // words. See docs/architecture/MEMORY_LAYOUT.md. // =============================================================== // Helpers: modexp, transcript, EIP-2537 calls // =============================================================== - // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier + // Revert with a 4-byte custom-error selector (P4/L-3). Writing at + // 0x00 is Solidity's legal scratch space and never touches the + // generated layout, which starts at TRANSCRIPT_MPTR. + function fail(sel) { + mstore(0x00, shl(224, sel)) + revert(0x00, 0x04) + } + + // Inverse of a Fr scalar via modexp(x, r-2, r). The verifier // calls this only after transcript absorption is complete, so it // reuses the dead transcript buffer just below VK_MPTR instead of // a fixed post-VK address that can collide with live PCS scratch @@ -364,8 +594,8 @@ contract Halo2Verifier { // downstream mulmod chains would silently absorb. Every // current call site feeds addmod/mulmod output, so this only // guards against a future emitter passing a raw scalar. - if iszero(lt(x, FR_MODULUS)) { revert(0, 0) } - if iszero(x) { revert(0, 0) } + if iszero(lt(x, FR_MODULUS)) { fail(ERR_NON_CANONICAL_SCALAR) } + if iszero(x) { fail(ERR_NON_CANONICAL_SCALAR) } let p := 0x3580 // EIP-198 modexp frame: // [base_len, exp_len, mod_len, base, exponent, modulus] @@ -375,8 +605,8 @@ contract Halo2Verifier { mstore(add(p, 0x60), x) mstore(add(p, 0x80), sub(FR_MODULUS, 2)) mstore(add(p, 0xa0), FR_MODULUS) - if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) { revert(0, 0) } - if iszero(eq(returndatasize(), 0x20)) { revert(0, 0) } + if iszero(staticcall(MODEXP_GAS, 0x05, p, 0xc0, p, 0x20)) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(eq(returndatasize(), 0x20)) { fail(ERR_PRECOMPILE_FAILED) } inv := mload(p) } @@ -436,16 +666,16 @@ contract Halo2Verifier { let x_lo := calldataload(add(cptr, 0x20)) let y_hi_word := calldataload(add(cptr, 0x40)) let y_lo := calldataload(add(cptr, 0x60)) - if shr(128, x_hi_word) { revert(0, 0) } - if shr(128, y_hi_word) { revert(0, 0) } + if shr(128, x_hi_word) { fail(ERR_BAD_POINT_ENCODING) } + if shr(128, y_hi_word) { fail(ERR_BAD_POINT_ENCODING) } let x_hi := and(x_hi_word, 0xffffffffffffffffffffffffffffffff) let y_hi := and(y_hi_word, 0xffffffffffffffffffffffffffffffff) if iszero(or(lt(x_hi, BLS_P_HI), and(eq(x_hi, BLS_P_HI), iszero(gt(x_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } if iszero(or(lt(y_hi, BLS_P_HI), and(eq(y_hi, BLS_P_HI), iszero(gt(y_lo, BLS_P_MINUS_ONE_LO))))) { - revert(0, 0) + fail(ERR_BAD_POINT_ENCODING) } // Memcpy the 4 calldata words (128 bytes) verbatim @@ -520,7 +750,7 @@ contract Halo2Verifier { mstore(add(single_scratch, 0x60), x) mstore(add(single_scratch, 0x80), sub(r, 2)) mstore(add(single_scratch, 0xa0), r) - ret := staticcall(gas(), 0x05, single_scratch, 0xc0, single_scratch, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, single_scratch, 0xc0, single_scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) if ret { mstore(mptr_start, mload(single_scratch)) } leave @@ -570,7 +800,7 @@ contract Halo2Verifier { mstore(add(gp_mptr, 0x60), gp) mstore(add(gp_mptr, 0x80), sub(r, 2)) mstore(add(gp_mptr, 0xa0), r) - ret := staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) + ret := staticcall(MODEXP_GAS, 0x05, gp_mptr, 0xc0, gp_mptr, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read @@ -607,26 +837,26 @@ contract Halo2Verifier { // returns true without consulting `success`. Revert here too, // so this helper has no path that hands control back to a // caller that would report success for an unverified proof. - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } // Lay out two (G1, G2) pairs at scratch..scratch+0x300: // [lhs_g1 (0x80) | G2_BASE (0x100) | rhs_g1 (0x80) | NEG_S_G2_BASE (0x100)] // Cancun MCOPY (3 + 3·words gas) replaces what used to // be a 4-step mstore chain for each G1 (~60 gas) and an // 8-iter mstore loop for each G2 (~240 gas). Net saving // here is ~500 gas per ec_pairing call. - let scratch := 0x1220 + let scratch := 0x1240 mcopy(scratch, lhs_mptr, 0x80) mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) - ret := staticcall(gas(), 0x0f, scratch, 0x0300, scratch, 0x20) + ret := staticcall(PAIRING_GAS_2PAIR, 0x0f, scratch, 0x0300, scratch, 0x20) ret := and(ret, eq(returndatasize(), 0x20)) // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. ret := and(ret, eq(mload(scratch), 1)) - if iszero(ret) { revert(0, 0) } + if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } @@ -831,6 +1061,14 @@ contract Halo2Verifier { // If x carried the identity flag, both decoded // coordinates must be zero after shifting. Any other y // value would be a malformed infinity encoding. + // + // Unreachable by construction (audit I-2/I-3): the + // whole-point sentinel check above already accepted + // every encoding in which x carries the identity flag + // -- the packed codec is a bijection, so an x flagged + // as identity with a sentinel mismatch cannot decode + // here. Kept as defence in depth for future codec + // changes rather than as a live branch. ok := and(ok, iszero(or(or(x_hi, x_lo), or(y_hi, y_lo)))) mstore(dst, 0) mstore(add(dst, 0x20), 0) @@ -866,6 +1104,10 @@ contract Halo2Verifier { // 3. folds the RHS carried point and fixed-base scalar tail into // ACC_RHS_MPTR, leaving ACC_LHS_MPTR / ACC_RHS_MPTR ready for // randomized batching in FinalPairing.yul. + // `r` is consumed only by the canonicality guards in the + // carried-scalar and fixed-base-tail arms; renders whose + // accumulator layout has neither (e.g. point_pair with no tail) + // legally leave it unused. function validate_public_accumulator(success, r) -> out { out := success let bits := 56 @@ -908,7 +1150,7 @@ contract Halo2Verifier { // Single-pair MSM output overwrites ACC_LHS_MPTR with // lhs_scalar * decoded_lhs. If lhs_scalar is one, this // is also a curve/subgroup validation round-trip. - out := staticcall(gas(), 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) + out := staticcall(G1MSM_GAS_1PAIR, 0x0c, acc_scratch, 0xa0, ACC_LHS_MPTR, 0x80) out := and(out, eq(returndatasize(), 0x80)) } } @@ -953,8 +1195,11 @@ contract Halo2Verifier { // // The precompile also validates every nonzero fixed // base embedded by codegen and the carried RHS point. + // ACC_RHS_MSM_GAS is the compile-time worst case + // (every tail scalar nonzero); acc_msm_len can only + // select a same-size-or-smaller MSM at runtime. out := staticcall( - gas(), + ACC_RHS_MSM_GAS, 0x0c, acc_scratch, acc_msm_len, @@ -1004,7 +1249,7 @@ contract Halo2Verifier { if iszero(and( eq(extcodesize(vk), EXPECTED_VK_LENGTH), eq(extcodehash(vk), EXPECTED_VK_CODEHASH_WORD) - )) { revert(0, 0) } + )) { fail(ERR_VK_MISMATCH) } // Runtime byte 0 is INVALID so direct calls cannot execute the // payload. Copy from byte 1 into VK_MPTR to reconstruct the // exact payload layout used by the embedded branch. @@ -1021,7 +1266,7 @@ contract Halo2Verifier { success := and(success, eq(mload(ACC_OFFSET_MPTR), 11)) success := and(success, eq(mload(NUM_ACC_LIMBS_MPTR), 7)) success := and(success, eq(mload(NUM_ACC_LIMB_BITS_MPTR), 56)) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_VK_MISMATCH) } // // The checks below validate the dynamic ABI envelope before the // transcript parser starts walking raw calldata: @@ -1045,7 +1290,7 @@ contract Halo2Verifier { ) // Stop before any transcript absorption if the ABI/proof shape // is not exactly the generated one. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_CALLDATA_SHAPE) } } // Fail malformed accumulator public inputs before transcript, // quotient, PCS, and final pairing work. The late accumulator block @@ -1061,7 +1306,7 @@ contract Halo2Verifier { // success-plumbing style as other helper calls; this boundary is // where the verifier converts failure to a revert. success := validate_public_accumulator(success, r) - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } // =============================================================== // Transcript: VK digest + instances + proof. @@ -1130,7 +1375,7 @@ contract Halo2Verifier { // Keccak Fq transcript input. buf_len := common_word(buf_len, inst_be) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } } // =============================================================== @@ -1313,7 +1558,7 @@ contract Halo2Verifier { // Proof evaluation scalars must be canonical Fr elements // before they are absorbed or made available to quotient // reconstruction. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } // Spill for quotient numerator and PCS codegen. mstore(eval_buf, eval) eval_buf := add(eval_buf, 0x20) @@ -1366,7 +1611,7 @@ contract Halo2Verifier { {} { let eval := calldataload(proof_cptr) // Canonical Fr check before transcript absorption. - if iszero(lt(eval, r)) { revert(0, 0) } + if iszero(lt(eval, r)) { fail(ERR_NON_CANONICAL_SCALAR) } buf_len := common_word(buf_len, eval) proof_cptr := add(proof_cptr, 0x20) } @@ -1392,11 +1637,11 @@ contract Halo2Verifier { // NUM_INSTANCE_CPTR is the calldata word immediately after the // dynamic proof bytes payload. If proof_cptr lands anywhere else, // some section was under-read or over-read. - if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { revert(0, 0) } + if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) } // `success` carries deferred canonicality failures from public // instance reads. G1/proof scalar helpers revert immediately. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_NON_CANONICAL_SCALAR) } // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). @@ -1479,9 +1724,19 @@ contract Halo2Verifier { mstore(INSTANCE_EVAL_MPTR, instance_eval) } - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } + + // Revert with the QuotientProgramInvalid() selector + // (bytes4(keccak256) = 0x3cc81b89; pinned by + // p4_error_selectors_match_declared_errors). Defined here rather + // than in AssemblyHelpers.yul because the quotient VM renders in + // BOTH the main verifier and the standalone evaluator assembly. + function q_program_fail() { + mstore(0x00, shl(224, 0x3cc81b89)) + revert(0x00, 0x04) + } - // Optional quotient helper functions. Each one is rendered only + // Optional quotient helper functions. Each one is rendered only // when the Rust lowering pass recognized the corresponding // expression shape in this generated verifier. They are pure Fr // helpers and share the same FR_MODULUS as the surrounding @@ -1501,7 +1756,8 @@ contract Halo2Verifier { let q_r := FR_MODULUS let x2 := mulmod(x, x, q_r) z := mulmod(x, mulmod(x2, x2, q_r), q_r) - } // =============================================================== + } + // =============================================================== // Batched identity numerator / linearization target. // // This block does not evaluate the quotient polynomial h(x), and @@ -1762,18 +2018,21 @@ contract Halo2Verifier { // q_has_top = 0 means the VM stack is empty. let q_has_top := 0 - // q_program opcode summary: - // 0x01/0x09 push const 0x02/0x05 push memory - // 0x03/0x04 push token ptr 0x06 add, 0x07 mul, 0x08 neg - // 0x0a fold main identity 0x0b fold selector identity - // 0x0c..0x11 add/mul const or memory into top - // 0x12..0x16 fused add-mul runs - // 0x17/0x18 reserved - // 0x19 native permutation 0x1b native heavy identity - // 0x1c LIN7 0x1d BILIN7_ROW - // 0x1e BILIN7_PAIRWISE 0x1f native lookup - // 0x20 POW5 0x21 MODARITH7 - // 0x22 AFFINE_SUM + // q_program opcode summary. Rendered from the same + // program.op_usage predicates that gate the interpreter's + // case arms below, so this artifact documents exactly the + // opcodes its program can contain -- no more, no fewer. + // 0x05 push_mem_u16 + // 0x06 add + // 0x08 neg + // 0x0b fold_selector + // 0x0d mul_const_u8 + // 0x10 add_mem_u16 + // 0x11 mul_mem_u16 + // 0x19 native_permutation + // 0x1f native_lookup + // 0x1b native_identity + // 0x21 modarith7 // // The default IVC verifier uses one physical encoding for the // logical VM: compact byte-oriented opcodes with variable-width @@ -1797,6 +2056,7 @@ contract Halo2Verifier { // 64 KiB when this compact form is emitted. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } if q_has_top { mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) @@ -1808,6 +2068,7 @@ contract Halo2Verifier { case 0x06 { // The safety validator guarantees a spilled operand // exists before ADD. q_top is the right operand. + if eq(q_sp, 0xb8e0) { q_program_fail() } q_sp := sub(q_sp, 0x20) q_top := addmod(mload(q_sp), q_top, r) } @@ -1831,6 +2092,7 @@ contract Halo2Verifier { // already range-checked Fr scalar in verifier memory. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := addmod(q_top, mload(q_ptr), r) } // VM 0x11 MUL_MEM_U16: multiply q_top by a short memory load. @@ -1838,6 +2100,7 @@ contract Halo2Verifier { // In-place multiply by a planned memory word. let q_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_top := mulmod(q_top, mload(q_ptr), r) } // Limb-aware opcodes are opt-in compact forms for @@ -1884,6 +2147,7 @@ contract Halo2Verifier { // whole identity is gated by mload(q_cond_ptr). q_cond_ptr := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_cond_ptr, 0x3680), 0x6aa0) { q_program_fail() } } let q_acc := 0 @@ -1918,6 +2182,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1930,12 +2195,14 @@ contract Halo2Verifier { for { let q_row_block := 0 } lt(q_row_block, q_row_count) { q_row_block := add(q_row_block, 1) } { let q_lhs := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } let q_lhs_value := mload(q_lhs) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { let q_word := mload(q_pc) let qconst := byte(0, q_word) let q_rhs := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -1955,6 +2222,8 @@ contract Halo2Verifier { let q_lhs_base := shr(240, q_pair_word) let q_rhs_base := and(shr(224, q_pair_word), 0xffff) q_pc := add(q_pc, 0x04) + if gt(sub(q_lhs_base, 0x3680), 0x69e0) { q_program_fail() } + if gt(sub(q_rhs_base, 0x3680), 0x69e0) { q_program_fail() } let q_coeff_pc := q_pc q_pc := add(q_pc, 13) for { let q_i := 0 } lt(q_i, 7) { q_i := add(q_i, 1) } { @@ -1980,6 +2249,7 @@ contract Halo2Verifier { let qconst := byte(0, q_word) let q_ptr := and(shr(232, q_word), 0xffff) q_pc := add(q_pc, 3) + if gt(sub(q_ptr, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod(mload(add(q_const_mptr, shl(5, qconst))), mload(q_ptr), r), @@ -1994,6 +2264,8 @@ contract Halo2Verifier { let q_lhs := and(shr(232, q_word), 0xffff) let q_rhs := and(shr(216, q_word), 0xffff) q_pc := add(q_pc, 5) + if gt(sub(q_lhs, 0x3680), 0x6aa0) { q_program_fail() } + if gt(sub(q_rhs, 0x3680), 0x6aa0) { q_program_fail() } q_acc := addmod( q_acc, mulmod( @@ -2617,7 +2889,7 @@ contract Halo2Verifier { mstore(q_selector_ptr, addmod(q_selector_acc, mload(0xb8e0), r)) } } - default { revert(0, 0) } + default { q_program_fail() } } // VM 0x0b FOLD_SELECTOR: consume q_top into one simple-selector bucket. case 0x0b { @@ -2629,6 +2901,11 @@ contract Halo2Verifier { q_pc := add(q_pc, 3) let q_sel_idx := shr(16, q_selector_payload) let q_sel_gap := and(q_selector_payload, 0xffff) + // P12: the bucket index addresses the SELECTOR_ACC + // region and the gap indexes the y-power table; both + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, 10)) { q_program_fail() } + if gt(q_sel_gap, 0x30) { q_program_fail() } let q_eval := q_top q_has_top := 0 // Simple-selector identity: keep the same y-batch @@ -2651,21 +2928,21 @@ contract Halo2Verifier { } // Invalid generated bytecode should fail closed. 0x1a intentionally lands here. default { - revert(0, 0) + q_program_fail() } } // The VK-pinned bytecode must end exactly at q_end and every // identity must have been consumed by a fold/native callback. // This catches malformed generator output whose final opcode // over-reads operands or leaves a partial expression live. - if iszero(eq(q_pc, q_end)) { revert(0, 0) } - if q_has_top { revert(0, 0) } + if iszero(eq(q_pc, q_end)) { q_program_fail() } + if q_has_top { q_program_fail() } // The spilled stack must also be balanced. A FOLD executed // with more than one operand live consumes only the cached // top, leaving abandoned words below q_sp with q_has_top // clear -- so both checks above pass while an operand of the // identity has been silently dropped from nu_y(x). - if iszero(eq(q_sp, 0xb8e0)) { revert(0, 0) } + if iszero(eq(q_sp, 0xb8e0)) { q_program_fail() } // Structured post-VM suffix. The current default uses this for // regular trash constraints: it is smaller than fully unrolled @@ -3020,7 +3297,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[0]: 43 commitment(s) (rolled, m>=4) + // q_eval_set[0]: 43 evaluation term(s), 42 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9980) mstore(0xb2a0, 0x9480) @@ -3080,7 +3357,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[1]: 3 commitment(s) + // q_eval_set[1]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9660) let q_eval_set_1 := mload(0x9920) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0x9680), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -3094,7 +3371,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[2]: 3 commitment(s) + // q_eval_set[2]: 3 evaluation term(s), 3 commitment term(s) let q_eval_set_0 := mload(0x9fe0) let q_eval_set_1 := mload(0xa000) q_eval_set_0 := addmod(q_eval_set_0, mulmod(mload(0xa060), mload(add(X1_POWERS_MPTR, 0x20)), r), r) @@ -3108,7 +3385,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[3]: 11 commitment(s) (rolled, m>=4) + // q_eval_set[3]: 11 evaluation term(s), 11 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x94a0) mstore(0xb2a0, 0x9540) @@ -3164,7 +3441,7 @@ contract Halo2Verifier { // emitted by the multi-prepare lowering pass and are kept // grouped so gas checkpoints can attribute their cost. { - // q_eval_set[4]: 5 commitment(s) (rolled, m>=4) + // q_eval_set[4]: 5 evaluation term(s), 5 commitment term(s) (rolled, m>=4) // stage per-(commit, rotation) eval source addresses mstore(0xb280, 0x9e00) mstore(0xb2a0, 0x9e20) @@ -3555,7 +3832,8 @@ contract Halo2Verifier { mcopy(0xe2a0, F_COM_MPTR, 0x80) mstore(0xe320, x4_pow_5) if success { - success := staticcall(gas(), 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) + // exact EIP-2537 G1MSM cost for 78 pair(s) + success := staticcall(525096, 0x0c, 0xb280, 0x30c0, FINAL_COM_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mstore(V_MPTR, v) @@ -3570,22 +3848,22 @@ contract Halo2Verifier { mcopy(0x1000, G1_BASE_MPTR, 0x80) mstore(0x1080, addmod(0, sub(r, mload(V_MPTR)), r)) if success { - success := staticcall(gas(), 0x0c, 0x1000, 0xa0, 0x1000, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1000, 0xa0, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, FINAL_COM_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(0x1080, PI_MPTR, 0x80) mstore(0x1100, mload(X3_MPTR)) if success { - success := staticcall(gas(), 0x0c, 0x1080, 0xa0, 0x1080, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, 0x1080, 0xa0, 0x1080, 0x80) success := and(success, eq(returndatasize(), 0x80)) } if success { - success := staticcall(gas(), 0x0b, 0x1000, 0x100, 0x1000, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, 0x1000, 0x100, 0x1000, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(PAIRING_RHS_MPTR, 0x1000, 0x80) @@ -3608,16 +3886,19 @@ contract Halo2Verifier { { let batch_ptr := 0x1000 - // Domain || KZG rhs/lhs || accumulator rhs/lhs. + // Domain || vk_digest || KZG rhs/lhs || accumulator rhs/lhs. + // vk_digest makes alpha's binding to the verifying key local + // instead of transitive-through-the-points (audit I-7). mstore(batch_ptr, 0x70616972696e672d62617463682d6163632d6b7a670000000000000000) - mcopy(add(batch_ptr, 0x20), PAIRING_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0xa0), PAIRING_LHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x0120), ACC_RHS_MPTR, 0x80) - mcopy(add(batch_ptr, 0x01a0), ACC_LHS_MPTR, 0x80) + mstore(add(batch_ptr, 0x20), mload(VK_DIGEST_MPTR)) + mcopy(add(batch_ptr, 0x40), PAIRING_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0xc0), PAIRING_LHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x0140), ACC_RHS_MPTR, 0x80) + mcopy(add(batch_ptr, 0x01c0), ACC_LHS_MPTR, 0x80) // alpha is Fiat-Shamir over the fully materialized pairing // inputs. Replace the negligible zero draw with one so the // accumulator equation cannot be accidentally dropped. - let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0220), r) + let acc_pair_alpha := mod(keccak256(batch_ptr, 0x0240), r) if iszero(acc_pair_alpha) { acc_pair_alpha := 1 } // PAIRING_RHS_MPTR += alpha * ACC_RHS_MPTR. @@ -3626,12 +3907,12 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_RHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_RHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_RHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } @@ -3640,12 +3921,12 @@ contract Halo2Verifier { mcopy(batch_ptr, ACC_LHS_MPTR, 0x80) mstore(add(batch_ptr, 0x80), acc_pair_alpha) if success { - success := staticcall(gas(), 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) + success := staticcall(G1MSM_GAS_1PAIR, 0x0c, batch_ptr, 0xa0, batch_ptr, 0x80) success := and(success, eq(returndatasize(), 0x80)) } mcopy(add(batch_ptr, 0x80), PAIRING_LHS_MPTR, 0x80) if success { - success := staticcall(gas(), 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) + success := staticcall(G1ADD_GAS, 0x0b, batch_ptr, 0x0100, PAIRING_LHS_MPTR, 0x80) success := and(success, eq(returndatasize(), 0x80)) } } @@ -3663,7 +3944,7 @@ contract Halo2Verifier { // -- the historical "LHS"/"RHS" naming follows the dual MSM // accumulator (left = pi, right = combined) and *not* the // pairing argument order. Pass them swapped to ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } success := ec_pairing(success, PAIRING_RHS_MPTR, PAIRING_LHS_MPTR) @@ -3675,7 +3956,7 @@ contract Halo2Verifier { // rather than clearing `success` -- but it keeps acceptance a local // property of this file instead of an invariant split across // FinalPairing.yul and ec_pairing. - if iszero(success) { revert(0, 0) } + if iszero(success) { fail(ERR_PROOF_REJECTED) } mstore(RETURN_MPTR, 1) return(RETURN_MPTR, 0x20) } diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol index 8f0b378f8..3d0114fa2 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/Halo2VerifyingKey.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.24; +// Pinned to match the verifier, so both halves of a deployment are provably +// built by one toolchain. (This contract's runtime is pure returned data, so +// its codehash is compiler-independent -- the pin is for the pair, not for it.) +pragma solidity 0.8.30; /// @title Halo2 BLS12-381 verifying-key payload. /// @notice Contract whose deployed runtime is `INVALID || generated verifier-key payload`. diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index dd8f06664..3f02dc487 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -14,13 +14,12 @@ the replay deploys the verifier with the verifying key alone. | Field | Value | | --- | --- | -| Source commit | `3fb6d84` (**this repository**, solidity-verifier, at fixture-render time; not the Midfall dependency revision — see the provenance-identities table in `docs/reference/REPRODUCIBLE_BUILDS.md`) | -| Staleness | **Stale relative to the current templates** (exact gas bounds, typed errors, VM operand clamps, BUILD_ID, alpha vk-binding all postdate `3fb6d84`). The replay test intentionally pins this rendered state; regenerating needs the external Moonlight checkout described below. | +| Source commit | `f894f75` (**this repository**, solidity-verifier, at fixture-render time; not the Midfall dependency revision — see the provenance-identities table in `docs/reference/REPRODUCIBLE_BUILDS.md`) | | Rendered by | Moonlight `wrap_circuit_composes_two_fold_children_from_four_dummy_fold_proofs` | -| Moonlight revision | `origin/codex/wrap-bench-cherry-picks` | +| Moonlight revision | `origin/codex/wrap-bench-cherry-picks` (`1940ea9`), rendered from a scratch worktree with the local-path Cargo unification below | | Accumulator | `AccumulatorEncoding::point_pair(offset=11, num_limbs=7, num_limb_bits=56)` | | Public inputs | 19 (accumulator occupies the trailing 8 words) | -| Verified on-chain | yes, 1,279,482 gas under revm Prague | +| Verified on-chain | yes, 1,338,272 gas under revm Prague (2026-08-13 render: exact precompile gas bounds, typed errors, VM operand clamps, BUILD_ID, alpha vk-binding) | | Native/Solidity trace | 244 trace points matched | ## Regenerating diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin b/proofs/solidity-verifier/fixtures/moonlight-wrap/calldata.bin index 55dbae62e6963dfa4e7abf45201a8c5dd2cdf2fd..08caa3a0e74e5eebe40f990c3da74e3cfa681a1c 100644 GIT binary patch literal 8516 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 literal 8516 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 Date: Thu, 13 Aug 2026 14:31:28 +0100 Subject: [PATCH 100/108] fix(ci): restore exec bit on install_pinned_solc.sh, clear clippy and fmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three Solidity verifier jobs all failed at the "Install pinned solc" step with `install_pinned_solc.sh: Permission denied` — the script landed with mode 100644 while every other script in that directory is 100755. With the step failing, `SOLC` was exported empty, so the codegen tests died on `Command '' not found` and the two EVM jobs on "pinned solc unavailable". Also silence `clippy::too_many_arguments` on the two builders that gained an eighth argument in the hardening work (BUILD_ID provenance on `generate_verifier_from_plan`, operand bounds on `quotient_template_program`), matching the existing convention in this crate and across the workspace, and take the rustfmt wrap in test.rs. Verified locally against the pinned solc 0.8.30+commit.73712a01: `cargo +nightly fmt --all -- --check`, both clippy invocations, the non-EVM test job (212 lib tests + fixtures), the 8 `pbt_` real-EVM tests, the Poseidon fixture, and the native/Solidity trace equivalence test. Co-Authored-By: Claude Opus 5 --- proofs/solidity-verifier/scripts/install_pinned_solc.sh | 0 proofs/solidity-verifier/src/lowering/artifacts.rs | 1 + proofs/solidity-verifier/src/lowering/quotient.rs | 1 + proofs/solidity-verifier/src/test.rs | 5 +++-- 4 files changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 proofs/solidity-verifier/scripts/install_pinned_solc.sh diff --git a/proofs/solidity-verifier/scripts/install_pinned_solc.sh b/proofs/solidity-verifier/scripts/install_pinned_solc.sh old mode 100644 new mode 100755 diff --git a/proofs/solidity-verifier/src/lowering/artifacts.rs b/proofs/solidity-verifier/src/lowering/artifacts.rs index 94a9bb402..9baad6fae 100644 --- a/proofs/solidity-verifier/src/lowering/artifacts.rs +++ b/proofs/solidity-verifier/src/lowering/artifacts.rs @@ -69,6 +69,7 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { /// Build the Askama model for the main Solidity verifier contract from an /// already-converged lowering plan. + #[allow(clippy::too_many_arguments)] pub(crate) fn generate_verifier_from_plan( &self, plan: &LoweringPlan, diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index 04d8fea07..bdfb7599c 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -142,6 +142,7 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { /// VK payload reservation, and the generated Yul interpreter. Keeping the /// bounds checks here prevents the standalone evaluator and in-verifier VM /// paths from drifting. + #[allow(clippy::too_many_arguments)] pub(super) fn quotient_template_program( &self, build: QuotientProgramBuild, diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 01b07e8b3..eccaa4369 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -3968,8 +3968,9 @@ fn assert_rendered_reader_matches_proof_layout( "generated proof reader proof_cptr increments drifted from ProofCalldataLayout" ); assert!( - solidity - .contains("if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) }"), + solidity.contains( + "if iszero(eq(proof_cptr, NUM_INSTANCE_CPTR)) { fail(ERR_BAD_CALLDATA_SHAPE) }" + ), "generated proof reader must fail closed if proof_cptr drifts" ); } From 8e65c9622907ef07b78e8305bc5c23909f80c040 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 14:52:03 +0000 Subject: [PATCH 101/108] fix(solidity-verifier): price modexp for EIP-7883 and probe it at deploy (MF-1) `modexp_gas_word_frame()` returned the EIP-2565 price (1360) and its doc comment claimed EIP-7883 "only reprices operands wider than 32 bytes". That reading was wrong. EIP-7883 changes two independent things, and only one of them is width-specific: the `2 * words^2` multiplication-complexity branch applies to `max_length > 32`, but the removal of the `/ 3` divisor from `multiplication_complexity * iteration_count` applies to every operand size. The verifier's only frame (32/32/32, exponent FR_MODULUS - 2) is therefore priced at 4064 on Osaka/Fusaka chains, not 1360. The failure mode is not graceful. `staticcall` forwards a fixed amount, so on a repriced chain the precompile runs out of gas inside the MANDATORY Lagrange batch inversion and every `verifyProof` call reverts `PrecompileFailed` -- total, deterministic liveness loss on a contract that deployed cleanly. And it would have deployed cleanly: `require_eip2537_precompiles()` probed MCOPY, G1ADD, G1MSM (including the negative subgroup vector) and PAIRING, but never 0x05 -- the one precompile the runtime cannot do without. The documented "deployment onto an already-repriced chain fails fast" property simply did not hold for modexp. * layout::gas::modexp_gas_word_frame now returns the MAXIMUM over both live schedules (EIP-2565 1360, EIP-7883 4080 at the generic 255-iteration bound for a 32-byte exponent). Over-forwarding is free on success -- unused gas is returned -- and only widens the burn of one failing call by the difference; under-forwarding bricks the verifier. * PrecompileSmoke.sol gains a modexp known-answer probe forwarding the same MODEXP_GAS the runtime uses. The vector is the runtime's own operation, Fermat inversion in Fr: 2^(FR_MODULUS - 2) checked as mulmod(result, 2, FR_MODULUS) == 1, which needs no new rendered constant and still rejects a precompile that returns zeros or echoes its input. * modexp_gas_bound_covers_every_live_schedule derives both prices from their EIP texts rather than asserting a magic number, so the next repricing forces a conscious edit; constructor_probes_modexp_at_the_pinned_runtime_bound pins the probe's shape and asserts every precompile the runtime calls is now probed at its pinned bound. Not done here, and deliberately not papered over: * The replay harness cannot exercise this. Pinned revm 19 exposes SpecId::OSAKA, but that variant is Prague+EOF in this version and its 0x05 handler is `berlin_run` (EIP-2565 pricing, `/ 3` intact), so switching the spec would produce green tests that prove nothing. Real coverage needs a revm bump to a version whose Osaka handler implements EIP-7883; evm.rs now records that gap at the SpecId pin instead of leaving it implicit. * The committed fixtures still carry the old bound and no modexp probe: regenerating them needs the pinned solc, which was not available where this fix was applied. Both fixture READMEs are marked STALE with what remains to be done. They stay valid inputs for the replay tests, which exercise verification logic rather than the modexp bound. * Consequently the Sepolia moonlight-wrap deployment predates this fix and, Sepolia having activated Fusaka, is expected to be bricked (fail-closed) today. Worth one eth_call to confirm and record. Verified: cargo test -p halo2_solidity_verifier --lib (171 passed, +2 new), --test template_digest (digest re-pinned for the template edits), cargo fmt, and clippy clean for this crate. EVM/fixture tests could not run without solc. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../solidity-verifier/fixtures/ivc/README.md | 10 ++ .../fixtures/moonlight-wrap/README.md | 10 ++ proofs/solidity-verifier/src/evm.rs | 13 +++ .../src/lowering/layout/mod.rs | 84 +++++++++++--- .../solidity-verifier/src/lowering/tests.rs | 105 +++++++++++++++++- .../templates/partials/verifier/Constants.sol | 17 ++- .../partials/verifier/PrecompileSmoke.sol | 46 ++++++-- .../tests/template_digest.rs | 2 +- 8 files changed, 254 insertions(+), 33 deletions(-) diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md index 81951bb38..fd699c43e 100644 --- a/proofs/solidity-verifier/fixtures/ivc/README.md +++ b/proofs/solidity-verifier/fixtures/ivc/README.md @@ -1,5 +1,15 @@ # IVC Public-Accumulator Replay Fixture +> **STALE — regeneration required before any deployment.** These artifacts were +> rendered before the MF-1 fix (`MODEXP_GAS` raised to the EIP-7883 bound and a +> constructor modexp known-answer probe added), so the committed `.sol` files +> here still carry the old 1360 bound and no modexp probe. They remain valid +> inputs for the *replay* tests, which exercise verification logic rather than +> the modexp bound, but they must be regenerated (and their provenance rows +> below updated) on a host with the pinned solc before they are used as a +> deployment source. Regeneration needs solc, which the environment that +> applied the MF-1 fix did not have. + Pre-rendered artifacts for `tests/ivc_accumulator_replay.rs`, which replays a real IVC final proof and then mutates the accumulator public inputs to check the decoder in `templates/partials/verifier/AccumulatorHelpers.yul` rejects them. diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 3f02dc487..77a313a1e 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -1,5 +1,15 @@ # Moonlight Wrap point_pair Replay Fixture +> **STALE — regeneration required before any deployment.** These artifacts were +> rendered before the MF-1 fix (`MODEXP_GAS` raised to the EIP-7883 bound and a +> constructor modexp known-answer probe added), so the committed `.sol` files +> here still carry the old 1360 bound and no modexp probe. They remain valid +> inputs for the *replay* tests, which exercise verification logic rather than +> the modexp bound, but they must be regenerated (and their provenance rows +> below updated) on a host with the pinned solc before they are used as a +> deployment source. Regeneration needs solc, which the environment that +> applied the MF-1 fix did not have. + Pre-rendered artifacts for the `point_pair` accumulator arm of `tests/ivc_accumulator_replay.rs`. The IVC fixture next door covers `AccumulatorEncoding::new` (explicit lhs/rhs scalars); this one covers diff --git a/proofs/solidity-verifier/src/evm.rs b/proofs/solidity-verifier/src/evm.rs index 7f929275e..09689eb2d 100644 --- a/proofs/solidity-verifier/src/evm.rs +++ b/proofs/solidity-verifier/src/evm.rs @@ -346,6 +346,19 @@ pub(crate) mod test { /// are routed to revm's bundled implementations. The runner keeps an /// `InMemoryDB` across calls so tests can deploy once and call many /// times. + /// + /// MF-1 coverage gap, deliberately not papered over: this harness cannot + /// exercise a chain whose modexp is priced by EIP-7883. The pinned + /// revm 19 exposes `SpecId::OSAKA`, but that variant is Prague+EOF in this + /// version -- its `0x05` handler is `berlin_run`, i.e. EIP-2565 pricing + /// with the `/ 3` divisor -- so switching the spec here would produce + /// green tests that prove nothing about the repricing that bricked the + /// pre-fix bound. Raising real coverage needs a revm bump to a version + /// whose Osaka handler implements EIP-7883; until then, MF-1 is guarded + /// by `modexp_gas_bound_covers_every_live_schedule` (the bound is derived + /// from both EIP texts) and by the constructor's modexp known-answer + /// probe, which forwards the rendered bound and so fails at deployment on + /// any chain that prices modexp above it. #[derive(Default)] pub struct Evm { db: InMemoryDB, diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs index 6e8378d32..e574366a1 100644 --- a/proofs/solidity-verifier/src/lowering/layout/mod.rs +++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs @@ -139,7 +139,7 @@ pub(crate) mod precompile { pub(crate) mod gas { //! Exact gas schedule for the precompiles the generated verifier calls, - //! from EIP-2537 (BLS12-381) and EIP-2565 (modexp). + //! from EIP-2537 (BLS12-381) and EIP-2565/EIP-7883 (modexp). //! //! A failing EIP-2537 or modexp call consumes ALL gas supplied to the //! `STATICCALL`, so every generated call site forwards the exact scheduled @@ -153,11 +153,19 @@ pub(crate) mod gas { //! amount succeeds by construction on any conformant implementation of //! the current schedule. //! - //! Liveness caveat: if a future fork reprices these precompiles UPWARD, - //! deployed verifiers start reverting on valid proofs and must be - //! regenerated and redeployed. The constructor smoke probes forward the - //! same bounds, so deployment onto an already-repriced chain fails fast - //! instead of bricking at proof time. + //! Multi-schedule bounds: where more than one schedule is live across the + //! chains this verifier targets, the bound is the MAXIMUM over those + //! schedules rather than the one for a single fork (see + //! [`modexp_gas_word_frame`]). Over-forwarding costs nothing on success -- + //! unused gas is returned -- and only widens the burn of one *failing* + //! call by the difference, whereas under-forwarding bricks the verifier. + //! + //! Liveness caveat: if a future fork reprices these precompiles above the + //! bounds rendered here, deployed verifiers start reverting on valid + //! proofs and must be regenerated and redeployed. The constructor smoke + //! probes forward the same bounds for every precompile the runtime + //! depends on -- EIP-2537 *and* modexp (MF-1) -- so deployment onto an + //! already-repriced chain fails fast instead of bricking at proof time. /// EIP-2537 G1ADD flat cost. pub(crate) const G1ADD_GAS: u64 = 375; @@ -196,23 +204,65 @@ pub(crate) mod gas { 32_600 * pairs + 37_700 } - /// EIP-2565 modexp cost for the only frame shape the verifier emits: - /// 32-byte base, 32-byte exponent, 32-byte modulus. + /// Modexp bound for the only frame shape the verifier emits: 32-byte + /// base, 32-byte exponent, 32-byte modulus. + /// + /// Two schedules are live across the chains this verifier targets, so the + /// rendered bound is the maximum of both: + /// + /// * **EIP-2565** (Berlin): `max(200, multiplication_complexity * + /// iteration_count / 3)`. With `words = ceil(32/8) = 4` and + /// `multiplication_complexity = words^2 = 16`, that is + /// `max(200, 16 * 255 / 3) = 1360`. + /// * **EIP-7883** (Osaka/Fusaka): the `/ 3` divisor is **removed** and the + /// floor is raised to 500, giving `max(500, 16 * 255) = 4080`. /// - /// `words = ceil(32/8) = 4`, `multiplication_complexity = words^2 = 16`, - /// `iteration_count <= 255` (32-byte exponent), so - /// `max(200, 16 * 255 / 3) = 1360`. EIP-7883 (scheduled for Osaka) keeps - /// the same result for these operand sizes: it raises the floor to 500 - /// (< 1360) and only reprices operands wider than 32 bytes. + /// MF-1: this function previously returned only the EIP-2565 value and + /// asserted that EIP-7883 "only reprices operands wider than 32 bytes". + /// That reading was wrong. EIP-7883 changes two independent things: the + /// `multiplication_complexity` branch for `max_length > 32` (`2 * words^2`, + /// which indeed does not apply here), *and* the removal of the `/ 3` + /// divisor from the final `multiplication_complexity * iteration_count` + /// product, which applies to every operand size. A verifier rendered with + /// the 1360 bound deploys fine on a repriced chain and then reverts + /// `PrecompileFailed` on every proof, because `staticcall` forwards a + /// fixed amount and the precompile runs out of gas inside the mandatory + /// Lagrange batch inversion. + /// + /// `iteration_count` is the generic upper bound for any 32-byte exponent + /// (`exponent.bit_length() - 1 <= 255`). Both exponents the verifier + /// actually emits are `FR_MODULUS - 2`, whose 255-bit length gives 254 + /// iterations and an exact EIP-7883 price of 4064; the extra 16 gas keeps + /// the bound valid for any 32-byte exponent a future emitter might use. pub(crate) const fn modexp_gas_word_frame() -> u64 { const WORDS: u64 = 4; const MULTIPLICATION_COMPLEXITY: u64 = WORDS * WORDS; + // Upper bound over every 32-byte exponent: `bit_length() - 1 <= 255`. const MAX_ITERATION_COUNT: u64 = 255; - let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT / 3; - if cost < 200 { - 200 + + // EIP-2565: divisor 3, floor 200. + let eip2565 = { + let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT / 3; + if cost < 200 { + 200 + } else { + cost + } + }; + // EIP-7883: no divisor, floor 500. + let eip7883 = { + let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT; + if cost < 500 { + 500 + } else { + cost + } + }; + + if eip2565 > eip7883 { + eip2565 } else { - cost + eip7883 } } } diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 1a151ab9c..422e790be 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1459,14 +1459,107 @@ fn eip2537_gas_schedule_matches_spec_vectors() { assert_eq!(gas::g1msm_gas(200), 200 * 12_000 * 519 / 1_000); // 32600*k + 37700 for the verifier's two-pair check. assert_eq!(gas::pairing_gas(2), 102_900); - // EIP-2565, 32-byte base/exp/mod: max(200, 16 * 255 / 3). - assert_eq!(gas::modexp_gas_word_frame(), 1_360); // The rendered template constants come from the same module. let constants = crate::lowering::render::TemplateConstants::default().gas; assert_eq!(constants.g1add, 375); assert_eq!(constants.g1msm_one_pair, 12_000); assert_eq!(constants.pairing_two_pair, 102_900); - assert_eq!(constants.modexp, 1_360); + assert_eq!(constants.modexp, gas::modexp_gas_word_frame()); +} + +/// MF-1: the modexp bound must cover EVERY live schedule, not just the one +/// that happened to be current when the generator was written. Derive both +/// prices here from their EIP texts instead of asserting one magic number, so +/// the next repricing forces a conscious edit rather than a silent brick: +/// `staticcall` forwards a fixed amount, so a bound below the chain's price +/// makes the precompile OOG and every proof revert. +#[test] +fn modexp_gas_bound_covers_every_live_schedule() { + use crate::lowering::layout::gas; + + // Shared inputs for the only frame the verifier emits (32-byte base, + // exponent, and modulus). + const WORDS: u64 = 32_u64.div_ceil(8); + const MULTIPLICATION_COMPLEXITY: u64 = WORDS * WORDS; + // `exponent.bit_length() - 1` for a 32-byte exponent, upper-bounded. + const ITERATION_COUNT: u64 = 255; + + // EIP-2565: `max(200, multiplication_complexity * iteration_count / 3)`. + let eip2565 = std::cmp::max(200, MULTIPLICATION_COMPLEXITY * ITERATION_COUNT / 3); + assert_eq!(eip2565, 1_360, "EIP-2565 price for the 32-byte frame"); + + // EIP-7883: the `/ 3` divisor is removed for EVERY operand size (only the + // `2 * words^2` complexity branch is width-specific) and the floor rises + // to 500: `max(500, multiplication_complexity * iteration_count)`. + let eip7883 = std::cmp::max(500, MULTIPLICATION_COMPLEXITY * ITERATION_COUNT); + assert_eq!(eip7883, 4_080, "EIP-7883 price for the 32-byte frame"); + + assert_eq!( + gas::modexp_gas_word_frame(), + std::cmp::max(eip2565, eip7883), + "modexp bound must be the maximum over live schedules" + ); + assert!( + gas::modexp_gas_word_frame() >= eip7883, + "a bound below the EIP-7883 price bricks every proof on Osaka/Fusaka \ + chains: the fixed-gas staticcall OOGs inside the mandatory Lagrange \ + batch inversion and verifyProof reverts PrecompileFailed" + ); + + // The exponent the verifier actually emits is FR_MODULUS - 2 (255 bits, + // so 254 iterations); the generic bound must cover its exact price too. + assert!(gas::modexp_gas_word_frame() >= MULTIPLICATION_COMPLEXITY * 254); +} + +/// MF-1: modexp is the one precompile the runtime cannot do without -- the +/// Lagrange batch inversion calls it on every proof -- and it was the one +/// precompile the constructor never probed, so a stale bound deployed +/// silently. Pin the probe's shape: right precompile, the pinned runtime +/// bound (not `gas()`), a return-size check, and a known answer a stub +/// cannot satisfy. +#[test] +fn constructor_probes_modexp_at_the_pinned_runtime_bound() { + let smoke = include_str!("../../templates/partials/verifier/PrecompileSmoke.sol"); + + assert!( + smoke.contains("staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}"), + "constructor must probe modexp at the same bound the runtime forwards" + ); + assert!( + smoke.contains( + "if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) }" + ), + "modexp probe must check the returned size" + ); + // 2^(r-2) == 2^-1, verified as mulmod(result, 2, r) == 1: a precompile + // that returns zeros, or echoes its input, fails this. + assert!( + smoke.contains("mstore(add(scratch, {{ template_constants.modexp.base_offset|hex() }}), 2)") + && smoke.contains( + "mstore(add(scratch, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2))" + ) + && smoke.contains("if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) }"), + "modexp probe must run the runtime's own Fermat inversion as a known-answer test" + ); + + // Every precompile the runtime calls is now probed at its pinned bound. + for (probe, gas_constant) in [ + ("modexp.address", "MODEXP_GAS"), + ("eip2537.g1add_address", "G1ADD_GAS"), + ("eip2537.g1msm_address", "G1MSM_GAS_1PAIR"), + ("eip2537.pairing_address", "PAIRING_GAS_2PAIR"), + ] { + assert!( + smoke.contains(&format!( + "staticcall({gas_constant}, {{{{ template_constants.{probe}|hex() }}}}" + )), + "constructor smoke probe missing for {probe} at {gas_constant}" + ); + } + assert!( + !smoke.contains("staticcall(gas()"), + "smoke probes must forward pinned bounds, not gas()" + ); } #[test] @@ -1560,10 +1653,14 @@ fn verifier_constructor_smoke_tests_runtime_prerequisites() { "generated verifier should include a deployment-time runtime prerequisite smoke test" ); for required in [ - "Smoke-check the Cancun/EIP-2537 runtime features", + "Smoke-check the Cancun/EIP-2537/modexp runtime features", "mcopy(add(scratch, {{ template_constants.word_bytes|hex() }}), scratch, {{ template_constants.word_bytes|hex() }})", "eq(mload(add(scratch, {{ template_constants.word_bytes|hex() }})), 0x1234)", "non-Cancun fork fails during deployment", + // MF-1: modexp is a runtime prerequisite like any other precompile. + "modexp (0x05) known-answer probe at the pinned runtime bound", + "staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}", + "if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) }", "G1ADD(identity, identity) -> identity", "Known-answer probe: G1ADD(G, G) == 2G", "template_constants.eip2537.g1_generator", diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index 1ecaa76cb..35aa53241 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -169,7 +169,8 @@ uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = {{ memory.quotient_limb_comms_mptr_base }}; // ---------------------------------------------------------------------- - // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. + // Precompile gas bounds: the scheduled EIP-2537 costs, and for modexp the + // maximum over the EIP-2565 and EIP-7883 schedules. // // A failing EIP-2537 or modexp call consumes ALL gas supplied to the // STATICCALL, so every generated call site forwards the exact scheduled @@ -179,9 +180,17 @@ // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient // by construction on any conformant chain. // - // Liveness caveat: if a future fork reprices these precompiles UPWARD, - // this verifier must be regenerated and redeployed. The constructor - // smoke probes forward the same bounds, so deployment onto an + // MODEXP_GAS covers both live modexp schedules: EIP-2565 prices this + // frame at 1360, EIP-7883 (Osaka/Fusaka) removes the /3 divisor and + // prices it at 4080, so the larger bound is rendered. Forwarding the + // EIP-7883 bound on a pre-Osaka chain is free on success -- unused gas is + // returned -- while forwarding the EIP-2565 bound on a repriced chain + // reverts every proof. + // + // Liveness caveat: if a future fork reprices these precompiles above the + // bounds below, this verifier must be regenerated and redeployed. The + // constructor smoke probes forward the same bounds for EVERY precompile + // the runtime calls, modexp included, so deployment onto an // already-repriced chain fails fast instead of bricking at proof time. // ---------------------------------------------------------------------- uint256 internal constant G1ADD_GAS = {{ template_constants.gas.g1add }}; diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index 4eb731e4e..398bd6c49 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -1,9 +1,10 @@ - /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. - /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. - /// The probes forward the same exact EIP-2537 gas bounds the runtime - /// uses (see the gas-bound constants block), so a chain whose - /// precompile schedule was repriced upward fails here, at deployment, - /// instead of bricking verifyProof later. + /// @notice Smoke-check the Cancun/EIP-2537/modexp runtime features required by the verifier. + /// @dev Exercises MCOPY, modexp, and EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. + /// The probes forward the same exact gas bounds the runtime uses, for + /// every precompile it calls -- 0x05 modexp included (see the + /// gas-bound constants block) -- so a chain whose precompile schedule + /// was repriced above those bounds fails here, at deployment, instead + /// of bricking verifyProof later. function require_eip2537_precompiles() private view { assembly ("memory-safe") { // Same free-memory-pointer guard as verifyProof. This body runs in @@ -21,8 +22,39 @@ mcopy(add(scratch, {{ template_constants.word_bytes|hex() }}), scratch, {{ template_constants.word_bytes|hex() }}) if iszero(eq(mload(add(scratch, {{ template_constants.word_bytes|hex() }})), 0x1234)) { revert(0, 0) } + // ---------------------------------------------------------------- + // modexp (0x05) known-answer probe at the pinned runtime bound. + // + // MF-1: every other precompile the runtime calls was probed here, + // but modexp -- which the MANDATORY Lagrange batch inversion and + // every scalar_inv call depend on -- was not. Two live schedules + // price this frame differently (EIP-2565: 1360, EIP-7883: 4080), + // and a bound below the chain's price does not degrade: the + // staticcall forwards a fixed amount, the precompile OOGs, and + // EVERY proof reverts PrecompileFailed. Without this probe that + // failure is invisible until the first verifyProof call, on a + // contract that deployed cleanly. + // + // The vector is the runtime's own operation -- Fermat inversion + // in Fr -- so it exercises the exact frame shape, exponent width, + // and gas bound used at proof time: 2^(FR_MODULUS - 2) == 2^-1. + // Checking mulmod(result, 2, FR_MODULUS) == 1 rather than a + // rendered constant keeps the probe self-contained while still + // rejecting a stub: a precompile returning zeros (or its input) + // fails, since 0 * 2 != 1 mod r. + // ---------------------------------------------------------------- + mstore(add(scratch, {{ template_constants.modexp.base_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // base len + mstore(add(scratch, {{ template_constants.modexp.exp_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // exp len + mstore(add(scratch, {{ template_constants.modexp.mod_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // mod len + mstore(add(scratch, {{ template_constants.modexp.base_offset|hex() }}), 2) + mstore(add(scratch, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2)) + mstore(add(scratch, {{ template_constants.modexp.mod_offset|hex() }}), FR_MODULUS) + if iszero(staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, scratch, {{ template_constants.modexp.frame_bytes|hex() }}, scratch, {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } + if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) } + // Start the EIP-2537 probes with the identity encoding for G1/G2: - // all-zero padded words. + // all-zero padded words. This also clears the modexp frame above. for { let off := 0 } lt(off, {{ template_constants.eip2537.smoke_scratch_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { mstore(add(scratch, off), 0) } diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs index 4bc1b7324..1467fc128 100644 --- a/proofs/solidity-verifier/tests/template_digest.rs +++ b/proofs/solidity-verifier/tests/template_digest.rs @@ -13,7 +13,7 @@ use sha3::{Digest, Keccak256}; /// keccak over the sorted (path, length, content) stream of `templates/`. const EXPECTED_TEMPLATE_TREE_DIGEST: &str = - "0x0809729cd0ee884736704458fbc53a2afc62c0de675b3a749b3c22c9ac797671"; + "0xfe89267c0778787678b938eb6f56f5e79f4bc11578786da45f2aad82384349d9"; fn collect_files(dir: &Path, files: &mut Vec) { for entry in fs::read_dir(dir).expect("template directory is readable") { From 580a912d1ce6e349316dd2524c132cc308229f82 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 15:08:12 +0000 Subject: [PATCH 102/108] fix(solidity-verifier): type the layout guard, harden the quotient VM, split precompile faults from rejections (MF-2/3/4) Three independent hardening findings from the same review pass. None changes which proofs verify; all three change what happens when something is wrong. MF-2 -- the memory-layout guard reverted bare. `if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }` is the ONLY on-chain check that solc's stack-spill reservation has not grown into the generated absolute layout, and the failure it catches is permanent: a fork that recompiles at a different (version, optimiser-runs) pair can still fit EIP-170, deploy cleanly, and then revert on every proof with empty returndata -- indistinguishable from every other empty revert. It now reverts MemoryLayoutViolated(), declared alongside the other typed errors, and the constructor's twin guard is typed too, so the same build fault fails at DEPLOYMENT rather than on first use. The smoke probes keep bare reverts: they report a chain-capability failure, which the deployment transaction already identifies. MF-3 -- the quotient VM interpreter had three holes its terminal checks cannot see. The program is VK-codehash-pinned so none is reachable on-chain with a well-formed artifact; these are containment for a future generator bug, mirroring on the deployed side what the reference VM already enforces at build time (`stack.len() == 1` per identity, `const_at` bounds, `identity_segment` rejecting a native marker mid-expression): * FOLD_MAIN/FOLD_SELECTOR consumed `q_top` without checking `q_has_top`. With the cached top dead, a fold silently re-folds a STALE value and both terminal checks (`q_has_top == 0`, `q_sp == base`) still pass. * Native callbacks RESET `q_sp` to the stack base. Operands spilled by a preceding partial expression were discarded with no trace: an identity could drop out of nu_y(x) while the program still ended balanced. They now assert the stack is already empty instead of making it so. * `q_sp` walked upward with no ceiling; every spill site now clamps it to the planner-registered region, exposed as `quotient_stack_hi`. Constant-table indexes: the u8 forms keep their documented exemption (drift bounded to 0x1FE0 bytes, inside the VK-reserved region, covered by validate_quotient_const_slots). The u16 forms do NOT share that argument -- an out-of-range u16 index reaches 0x1FFFE0 bytes past the table, well outside anything pinned -- so those three sites are clamped against the rendered table length. MF-4 -- three paths conflated "the chain could not run this" with "this input is bad". Both fail closed, but they are different incidents, and the typed taxonomy exists precisely so a responder knows which one to investigate: * ec_pairing reported ProofRejected even when the pairing staticcall itself failed or returned the wrong size. A failed call is now PrecompileFailed; only a pairing that RAN and returned != 1 rejects the proof. * batch_invert returned a bare boolean, so a zero Lagrange denominator -- reachable only if the squeezed x lands on a domain point, i.e. a transcript event with probability ~n/r -- surfaced as PrecompileFailed, pointing responders at the node when the proof was the cause. It now returns its failure cause and the Lagrange boundary branches on it. * validate_public_accumulator did the same in reverse: a G1MSM staticcall that could not run surfaced as BadPointEncoding. Also split. A G1MSM *subgroup rejection* deliberately keeps surfacing as PrecompileFailed: the precompile is the validator, and renaming that path would cost a pre-check this verifier intentionally does not perform. New pinning tests: memory_layout_guard_reverts_with_a_typed_selector, quotient_vm_interpreter_fails_closed_on_malformed_programs (counts every guard site, so a regenerated template that drops one fails), precompile_faults_and_input_rejections_use_distinct_selectors. p4's selector table gains MemoryLayoutViolated(). Verified: cargo test -p halo2_solidity_verifier --lib (174 passed, +3 new) and --test template_digest (re-pinned), cargo fmt, clippy clean for this crate. As in the MF-1 commit, EVM/fixture tests could not run without solc, and the committed fixtures stay STALE pending regeneration. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../src/lowering/layout/memory.rs | 9 + .../src/lowering/quotient.rs | 2 + .../src/lowering/render/models.rs | 13 ++ .../solidity-verifier/src/lowering/tests.rs | 190 +++++++++++++++++- .../templates/contracts/Halo2Verifier.sol | 24 ++- .../QuotientNumeratorBlock.yul | 55 ++++- .../partials/verifier/AccumulatorHelpers.yul | 10 +- .../partials/verifier/AssemblyHelpers.yul | 22 +- .../templates/partials/verifier/Constants.sol | 1 + .../templates/partials/verifier/Lagrange.yul | 14 +- .../partials/verifier/PrecompileSmoke.sol | 11 +- .../templates/partials/verifier/VkLoading.yul | 10 +- .../tests/template_digest.rs | 2 +- 13 files changed, 343 insertions(+), 20 deletions(-) diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs index 3d0e3abab..022381f94 100644 --- a/proofs/solidity-verifier/src/lowering/layout/memory.rs +++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs @@ -528,6 +528,14 @@ pub(crate) struct VerifierMemoryLayout { /// selector accumulators are accounted for. pub(crate) quotient_tmp_mptr: usize, pub(crate) quotient_stack_mptr: usize, + /// First address past the quotient VM stack / callback scratch region. + /// + /// MF-3: the interpreter's spill pointer walks upward from + /// `quotient_stack_mptr` with no ceiling of its own, so the rendered VM + /// clamps `q_sp` against this bound. The region is sized for the larger + /// of the interpreted stack depth and the structured native-callback + /// scratch, which is exactly the ceiling both uses must respect. + pub(crate) quotient_stack_hi: usize, pub(crate) pcs_q_eval_source_table_mptr: usize, pub(crate) pcs_q_com_trace_scratch_mptr: usize, pub(crate) pcs_final_msm_scratch_mptr: usize, @@ -1099,6 +1107,7 @@ impl VerifierMemoryLayout { lagrange_denoms_mptr, quotient_tmp_mptr, quotient_stack_mptr, + quotient_stack_hi: quotient_stack_mptr + quotient_stack_len.max(MODEXP_FRAME_BYTES), pcs_q_eval_source_table_mptr, pcs_q_com_trace_scratch_mptr, pcs_final_msm_scratch_mptr, diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs index bdfb7599c..9a09a1f8c 100644 --- a/proofs/solidity-verifier/src/lowering/quotient.rs +++ b/proofs/solidity-verifier/src/lowering/quotient.rs @@ -187,6 +187,8 @@ impl<'params, 'meta> VerifierBuildInputs<'params, 'meta> { selector_max_power: selector_fold.max_power, selector_tail_updates: Self::selector_tail_updates(selector_fold), stack_mptr: quotient_stack_mptr, + stack_hi: memory.quotient_stack_hi, + num_consts: build.consts.len(), program_mptr, operand_lo: operand_bounds.0, operand_hi: operand_bounds.1, diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs index dd9f78b49..f5dbdafa4 100644 --- a/proofs/solidity-verifier/src/lowering/render/models.rs +++ b/proofs/solidity-verifier/src/lowering/render/models.rs @@ -706,6 +706,17 @@ pub(crate) struct QuotientProgram { pub(crate) selector_tail_updates: Vec, /// Operand stack / callback scratch base. pub(crate) stack_mptr: usize, + /// First address past the operand stack / callback scratch region. + /// + /// MF-3: spill sites clamp `q_sp` against this so a malformed program + /// cannot walk the stack pointer out of its registered region. + pub(crate) stack_hi: usize, + /// Number of Fr words in the generated quotient constant table. + /// + /// MF-3: constant-table indexes decoded from program bytes are clamped + /// against this so an out-of-range index cannot read program bytes (or + /// commitment words) as field constants. + pub(crate) num_consts: usize, /// Memory pointer to the first encoded program word. pub(crate) program_mptr: usize, /// Lowest word address a VM memory operand may load from (P12/L-6). @@ -1218,6 +1229,8 @@ mod tests { selector_max_power: 0, selector_tail_updates: vec![], stack_mptr: 0, + stack_hi: usize::MAX, + num_consts: usize::MAX, program_mptr: 0, // Synthetic model: a permissive clamp window keeps the // rendered guards inert for layout-shape tests. diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs index 422e790be..60b6998d3 100644 --- a/proofs/solidity-verifier/src/lowering/tests.rs +++ b/proofs/solidity-verifier/src/lowering/tests.rs @@ -1511,6 +1511,176 @@ fn modexp_gas_bound_covers_every_live_schedule() { assert!(gas::modexp_gas_word_frame() >= MULTIPLICATION_COMPLEXITY * 254); } +/// MF-4: the typed taxonomy exists so an incident responder can tell a chain +/// fault from a rejected proof. Three paths used to conflate them -- a failed +/// precompile inside the accumulator precheck or the final pairing surfaced as +/// an input rejection, and a zero Lagrange denominator (a transcript event) +/// surfaced as `PrecompileFailed`. Pin the split so it cannot regress. +#[test] +fn precompile_faults_and_input_rejections_use_distinct_selectors() { + let corpus = verifier_template_corpus(); + + // (a) The pairing helper: staticcall/returndatasize failure is a chain + // fault; a pairing that ran and returned != 1 rejects the proof. + assert!( + corpus.contains( + "if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) }\n // Compare against 1 rather than truncating to the low bit:" + ), + "ec_pairing must report a failed pairing staticcall as PrecompileFailed" + ); + assert!( + corpus.contains("ret := eq(mload(scratch), 1)\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }"), + "ec_pairing must report a pairing result of 0 as ProofRejected" + ); + + // (b) batch_invert and the accumulator validator both carry a cause flag + // rather than a bare boolean. + assert!( + corpus.contains( + "function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret, precompile_failed" + ), + "batch_invert must report whether its modexp call failed" + ); + assert!( + corpus + .contains("function validate_public_accumulator(success, r) -> out, precompile_failed"), + "the accumulator validator must report whether its G1MSM call failed" + ); + + // (c) Both boundaries must branch on that flag. + for (guarded, fallback, what) in [ + ( + "if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }", + "fail(ERR_PROOF_REJECTED)", + "Lagrange", + ), + ( + "if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }", + "fail(ERR_BAD_POINT_ENCODING)", + "accumulator", + ), + ] { + assert!( + corpus.contains(guarded) && corpus.contains(fallback), + "{what} boundary must split precompile faults from rejected input" + ); + } + + // A zero denominator means the squeezed x hit a domain point: an input + // rejection, not a broken chain. + assert!( + !corpus.contains( + "success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r)" + ), + "the Lagrange batch inversion must thread its failure cause" + ); +} + +/// MF-3: the quotient VM's terminal checks (`q_pc == q_end`, `q_has_top == 0`, +/// `q_sp == base`) cannot see three failure shapes, so the interpreter grew +/// guards for each. The program is VK-codehash-pinned, so none of these are +/// reachable on-chain with a well-formed artifact -- they are containment for +/// a future generator bug, mirroring on the deployed side what the reference +/// VM already enforces at build time (`stack.len() == 1` per identity, +/// `const_at` bounds, and `identity_segment` rejecting a native marker inside +/// an expression). +#[test] +fn quotient_vm_interpreter_fails_closed_on_malformed_programs() { + let vm = include_str!("../../templates/partials/quotient_numerator/QuotientNumeratorBlock.yul"); + + // (a) A fold with no live cached top would re-fold a STALE q_top, and + // both terminal checks would still pass. + assert_eq!( + vm.matches("{%- call q_top_guard() %}").count(), + 2, + "both FOLD_MAIN and FOLD_SELECTOR must require a live cached top" + ); + assert!( + vm.contains("if iszero(q_has_top) { q_program_fail() }"), + "q_top_guard must fail closed when the cached top is not live" + ); + + // (b) Native callbacks used to RESET q_sp, which silently discarded + // operands spilled by a preceding partial expression -- an identity would + // drop out of nu_y(x) with the program still ending balanced. Assert + // instead of reset. + // The only assignment of the stack base to q_sp may be its declaration. + assert_eq!( + vm.matches("q_sp := {{ program.stack_mptr|hex() }}").count(), + 1, + "native callbacks must not reset q_sp; a reset hides dropped operands" + ); + assert!( + vm.contains("let q_sp := {{ program.stack_mptr|hex() }}"), + "the surviving q_sp assignment must be its initial declaration" + ); + assert_eq!( + vm.matches("{%- call q_stack_empty_guard() %}").count(), + 3, + "each native callback boundary must assert an already-empty stack" + ); + + // (c) The spill pointer has no ceiling of its own. + assert_eq!( + vm.matches("if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() }") + .count(), + 10, + "every cached-top spill site must clamp q_sp to its registered region" + ); + + // (d) u16 constant-table indexes reach far outside the pinned payload, so + // unlike the u8 forms they cannot rely on bounded drift. + assert_eq!( + vm.matches("{%- call q_const_guard(\"qconst\") %}").count(), + 3, + "u16 constant-table indexes must be clamped to the rendered table length" + ); + assert!( + vm.contains("if iszero(lt({{ idx }}, {{ program.num_consts }})) { q_program_fail() }"), + "q_const_guard must clamp against the generated constant-table length" + ); +} + +/// MF-2: the free-memory-pointer guard is the only on-chain check that solc's +/// stack-spill reservation has not grown into the generated absolute layout. +/// A fork that recompiles at a different (version, optimiser-runs) pair can +/// still fit EIP-170, deploy, and then revert on every proof -- so the guard +/// must say *why* rather than reverting bare, which is indistinguishable from +/// every other empty revert. +#[test] +fn memory_layout_guard_reverts_with_a_typed_selector() { + let verifier_template = include_str!("../../templates/contracts/Halo2Verifier.sol"); + let smoke_template = include_str!("../../templates/partials/verifier/PrecompileSmoke.sol"); + + for (source, name) in [ + (verifier_template, "verifyProof"), + (smoke_template, "constructor"), + ] { + assert!( + source.contains("mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED))") + && source.contains("revert(0x00, 0x04)"), + "{name} memory-layout guard must revert with MemoryLayoutViolated()" + ); + } + // The guard must still be the first thing each assembly block does: it + // protects the writes that follow, so a bare `revert(0, 0)` left behind + // on either path means the typed rewrite missed a site. + assert!( + verifier_template.contains("if gt(mload(0x40), TRANSCRIPT_MPTR) {"), + "runtime guard must still compare the FMP against TRANSCRIPT_MPTR" + ); + assert!( + !verifier_template.contains("if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }"), + "runtime memory-layout guard still reverts bare" + ); + assert!( + !smoke_template.contains( + "if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) }" + ), + "constructor memory-layout guard still reverts bare" + ); +} + /// MF-1: modexp is the one precompile the runtime cannot do without -- the /// Lagrange batch inversion calls it on every proof -- and it was the one /// precompile the constructor never probed, so a stale bound deployed @@ -1572,7 +1742,7 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { "ABI/proof length/instance shape checks should fail before accumulator or transcript parsing" ); assert!( - verifier_template.contains("success := validate_public_accumulator(success, r)\n if iszero(success) { fail(ERR_BAD_POINT_ENCODING) }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), + verifier_template.contains("success, acc_precompile_failed := validate_public_accumulator(success, r)\n if iszero(success) {\n // MF-4: a G1MSM that could not run at all is a chain fault,\n // not a malformed accumulator point.\n if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }\n fail(ERR_BAD_POINT_ENCODING)\n }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), "accumulator precheck should fail before transcript parsing" ); assert!( @@ -1583,7 +1753,7 @@ fn failed_success_paths_do_not_enter_ec_precompiles() { ); assert!( verifier_template.contains( - "if iszero(success) { fail(ERR_PRECOMPILE_FAILED) }\n\n {%- match quotient_external %}" + "if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }\n fail(ERR_PROOF_REJECTED)\n }\n\n {%- match quotient_external %}" ), "failed Lagrange/common-polynomial setup should fail before quotient reconstruction" ); @@ -1843,9 +2013,9 @@ fn accumulator_points_are_prevalidated_before_transcript_work() { let verifier_template = verifier_template_corpus(); for required in [ - "function validate_public_accumulator(success, r) -> out", + "function validate_public_accumulator(success, r) -> out, precompile_failed", "Fail malformed accumulator public inputs before transcript", - "success := validate_public_accumulator(success, r)", + "success, acc_precompile_failed := validate_public_accumulator(success, r)", "gas_checkpoint(2) // after VK loading + accumulator public-input precheck", "Batch the prevalidated public IVC accumulator pairing equation", ] { @@ -2399,8 +2569,14 @@ fn production_verifier_documents_revert_or_true_policy() { verifier_template.contains("function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret") && verifier_template .contains("ret := success\n if iszero(ret) { leave }") + // MF-4: a failed/short-returning pairing staticcall is a chain + // fault (PrecompileFailed); only a pairing that RAN and + // returned != 1 rejects the proof. + && verifier_template.contains( + "ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }}))\n if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) }", + ) && verifier_template.contains( - "ret := and(ret, eq(mload(scratch), 1))\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }\n ret := 1", + "ret := eq(mload(scratch), 1)\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }\n ret := 1", ), "final pairing helper must revert on pairing failure and normalize success to one" ); @@ -2487,6 +2663,10 @@ fn p4_error_selectors_match_declared_errors() { ("PrecompileFailed()", "ERR_PRECOMPILE_FAILED"), ("ProofRejected()", "ERR_PROOF_REJECTED"), ("QuotientProgramInvalid()", "ERR_QUOTIENT_PROGRAM_INVALID"), + // MF-2: the memory-layout guard reports a build fault (a recompile + // whose spill region reaches the generated layout), so it must be + // decodable rather than an anonymous empty revert. + ("MemoryLayoutViolated()", "ERR_MEMORY_LAYOUT_VIOLATED"), ] { let digest = Keccak256::digest(signature.as_bytes()); let selector = format!( diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol index c1db4f284..72b41fff4 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol @@ -50,7 +50,10 @@ contract Halo2Verifier { // verifyProof is success-or-revert; these errors let integrators and // incident responders distinguish malformed calldata from a swapped VK, // a non-canonical scalar, a failed precompile, or a rejected proof. - // Constructor smoke probes intentionally keep bare reverts. + // Constructor smoke probes intentionally keep bare reverts -- they report + // a chain-capability failure, and the deployment transaction identifies + // itself. The one constructor exception is the memory-layout guard + // (MF-2), which reports a BUILD fault and is typed on both paths. // ---------------------------------------------------------------------- /// @notice Calldata does not match the generated ABI shape (heads, /// lengths, instance count, or exact calldatasize). @@ -72,6 +75,12 @@ contract Halo2Verifier { /// invariant (bad opcode, operand out of window, stack misuse, /// or evaluator frame mismatch). error QuotientProgramInvalid(); + /// @notice solc's stack-spill reservation overlaps the generated absolute + /// memory layout. This is a BUILD fault, not a proof fault: the + /// artifact was compiled with a (version, optimiser) pair whose + /// free-memory pointer starts at or above TRANSCRIPT_MPTR, so no + /// input can ever verify. Redeploy from the pinned toolchain. + error MemoryLayoutViolated(); {% include "partials/verifier/Constants.sol" %} @@ -159,7 +168,18 @@ contract Halo2Verifier { // reservation is compiler-version and optimiser dependent, so // assert the invariant in the deployed bytecode instead of relying // on a generator-side test the integrator never runs. ~6 gas. - if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } + // + // MF-2: this is the only on-chain guard against a recompile that + // silently moves the spill region, and the failure it catches is + // permanent (no input can verify). `fail()` is not in scope this + // early, so write the MemoryLayoutViolated() selector inline + // rather than reverting bare -- an empty revert here is + // indistinguishable from every other empty revert, which is + // exactly the wrong signal for a build fault. + if gt(mload(0x40), TRANSCRIPT_MPTR) { + mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED)) + revert(0x00, 0x04) + } // This block owns the call-frame memory and remains terminal. // Generated scratch starts at TRANSCRIPT_MPTR, preserving diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul index 0d1b1862b..005228fb0 100644 --- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul @@ -9,7 +9,10 @@ sub(ptr, lo) > (hi - lo) cover both bounds (~6 gas per operand). u8 constant-table indexes stay unguarded: their drift is bounded to 0x1FE0 bytes inside the VK-reserved region and covered by build-time - validate_quotient_const_slots. + validate_quotient_const_slots. MF-3: the u16 forms do NOT share that + argument -- an out-of-range u16 index reaches 0x1FFFE0 bytes past the + table, well outside the pinned payload -- so those three sites are + clamped against the rendered table length. -#} {%- macro q_ptr_guard(ptr) %} if gt(sub({{ ptr }}, {{ program.operand_lo|hex() }}), {{ (program.operand_hi - program.operand_lo)|hex() }}) { q_program_fail() } @@ -22,6 +25,35 @@ cannot catch a BALANCED underflow, this can. -#} {%- macro q_pop_guard() %} if eq(q_sp, {{ program.stack_mptr|hex() }}) { q_program_fail() } +{%- endmacro %} +{#- + MF-3 interpreter fail-closed guards. The program is trusted through the VK + codehash pin, so none of these are reachable on-chain with a well-formed + artifact; they are containment for a future GENERATOR bug, in the same + spirit as the P12 operand clamps above. Each closes a hole the terminal + end-of-program checks provably cannot see: + + - q_top_guard: FOLD_MAIN/FOLD_SELECTOR consume the cached top. With + q_has_top clear, the fold silently re-folds a STALE q_top and both + terminal checks (q_has_top == 0, q_sp == base) still pass. + - q_stack_empty_guard: native callbacks used to RESET q_sp to the base + rather than assert it, so operands spilled by a preceding partial + expression were discarded with no trace -- an identity would drop out + of nu_y(x) while the program still ended balanced. + - q_const_guard: constant-table indexes are decoded from program bytes + and were unclamped, so an out-of-range index reads whatever follows the + table (program bytes, commitments) as an Fr constant. + - the inlined spill-ceiling check at every push site: q_sp walks + upward with no ceiling of its own. +-#} +{%- macro q_top_guard() %} + if iszero(q_has_top) { q_program_fail() } +{%- endmacro %} +{%- macro q_stack_empty_guard() %} + if iszero(eq(q_sp, {{ program.stack_mptr|hex() }})) { q_program_fail() } +{%- endmacro %} +{%- macro q_const_guard(idx) %} + if iszero(lt({{ idx }}, {{ program.num_consts }})) { q_program_fail() } {%- endmacro %} // =============================================================== // Batched identity numerator / linearization target. @@ -473,9 +505,11 @@ // Fr words, so shl(5, const_idx) converts an index to // a byte offset. let qconst := shr(240, mload(q_pc)) +{%- call q_const_guard("qconst") %} // Push semantics: spill the old cached top, if any, // then install the loaded constant as the new q_top. if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -496,6 +530,7 @@ // Load one canonical Fr word from generated memory and // push it through the cached-top stack discipline. if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -544,6 +579,7 @@ // impossible for valid generated bytecode. default { q_program_fail() } if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -595,6 +631,7 @@ default { q_program_fail() } {%- call q_ptr_guard("q_ptr") %} if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -612,6 +649,7 @@ q_pc := add(q_pc, 2) {%- call q_ptr_guard("q_ptr") %} if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -662,6 +700,7 @@ // constant table has fewer than 256 referenced slots. let qconst := byte(0, mload(q_pc)) if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -697,6 +736,7 @@ // constant tables. let qconst := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) +{%- call q_const_guard("qconst") %} let q_const_ptr := add(q_const_mptr, shl(5, qconst)) {%- call q_ptr_guard("q_const_ptr") %} q_top := addmod(q_top, mload(q_const_ptr), r) @@ -708,6 +748,7 @@ // Two-byte constant-index multiply. let qconst := shr(240, mload(q_pc)) q_pc := add(q_pc, 2) +{%- call q_const_guard("qconst") %} let q_const_ptr := add(q_const_mptr, shl(5, qconst)) {%- call q_ptr_guard("q_const_ptr") %} q_top := mulmod(q_top, mload(q_const_ptr), r) @@ -918,6 +959,7 @@ // u16 ptr} pairs. The result is pushed as a fresh // stack value. if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -956,6 +998,7 @@ {%- call q_ptr_guard("q_lhs") %} let q_lhs_value := mload(q_lhs) if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -1003,6 +1046,7 @@ let q_coeff_pc := q_pc q_pc := add(q_pc, {{ template_constants.quotient_vm.limb_pairwise_coeffs }}) if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -1081,6 +1125,7 @@ q_pc := add(q_pc, 5) if q_has_top { + if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } mstore(q_sp, q_top) q_sp := add(q_sp, 0x20) } @@ -1214,7 +1259,7 @@ // stack. The Rust memory planner must reserve enough // words for structured_permutation_scratch_words(meta) // whenever this opcode can appear. - q_sp := {{ program.stack_mptr|hex() }} +{%- call q_stack_empty_guard() %} // The generated lines below call the same fold snippets // used by interpreted expressions, so trace IDs and // y-batch positions remain contiguous. @@ -1240,7 +1285,7 @@ // f+beta/prefix/suffix scratch rather than as a // conventional VM stack. The Rust memory planner must // reserve structured_lookup_scratch_words(meta). - q_sp := {{ program.stack_mptr|hex() }} +{%- call q_stack_empty_guard() %} // Generated LogUp code follows the same y-batch order // as the Rust identity stream. {%- for line in quotient_native_lookup_computation %} @@ -1265,7 +1310,7 @@ // interpreter stack before dispatching. q_top := 0 q_has_top := 0 - q_sp := {{ program.stack_mptr|hex() }} +{%- call q_stack_empty_guard() %} // Native identity sub-cases are generated from selected heavy gate identities. switch q_native_idx {%- for code_block in quotient_native_identity_computations %} @@ -1283,6 +1328,7 @@ case {{ template_constants.quotient_vm.op.fold_main|hex() }} { // q_top is the complete value of one fully evaluated // identity at x. It leaves the expression stack here. +{%- call q_top_guard() %} let q_eval := q_top q_has_top := 0 {%- if self.trace %} @@ -1312,6 +1358,7 @@ // are codegen-known sizes, so clamp before the writes. if iszero(lt(q_sel_idx, {{ program.num_selector_buckets }})) { q_program_fail() } if gt(q_sel_gap, {{ program.selector_max_power|hex() }}) { q_program_fail() } +{%- call q_top_guard() %} let q_eval := q_top q_has_top := 0 {%- if self.trace %} diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul index a261ea2fd..41e2b46a0 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul @@ -248,7 +248,13 @@ // carried-scalar and fixed-base-tail arms; renders whose // accumulator layout has neither (e.g. point_pair with no tail) // legally leave it unused. - function validate_public_accumulator(success, r) -> out { + // MF-4: `precompile_failed` separates a G1MSM staticcall that + // could not run (chain/gas fault) from a public-input point this + // verifier decoded and rejected (bad packing, out-of-field + // coordinate, non-canonical identity encoding, or a point the + // precompile found off-curve/out-of-subgroup). Both fail closed at + // the call site; only the second is a BadPointEncoding. + function validate_public_accumulator(success, r) -> out, precompile_failed { out := success let bits := {{ self.expected_num_acc_limb_bits }} let n := {{ self.expected_num_acc_limbs }} @@ -303,6 +309,7 @@ // is also a curve/subgroup validation round-trip. out := staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, acc_scratch, {{ template_constants.g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) out := and(out, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) + precompile_failed := iszero(out) } } @@ -418,6 +425,7 @@ {{ template_constants.g1_bytes|hex() }} ) out := and(out, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) + precompile_failed := iszero(out) } } // The caller checks `out` and reverts before transcript work if diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul index 3a844a297..604d642d5 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul @@ -138,7 +138,16 @@ // The function returns a boolean instead of reverting so callers // can combine it with other `success` plumbing until a section // boundary decides whether to fail closed. - function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret { + // + // MF-4: the second return value separates a FAILED PRECOMPILE + // (staticcall reverted / OOG'd / returned the wrong size -- a + // chain or gas-schedule fault) from a REJECTED INPUT (a zero or + // non-canonical denominator, which for the Lagrange batch means + // the squeezed x landed on a domain point). Both fail closed at + // the section boundary, but they are different incidents and used + // to surface under the same PrecompileFailed selector, pointing + // responders at the node when the transcript was the cause. + function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret, precompile_failed { ret := success if iszero(ret) { leave } // Memory ranges must be forward and word-aligned by @@ -177,6 +186,7 @@ mstore(add(single_scratch, {{ template_constants.modexp.mod_offset|hex() }}), r) ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, single_scratch, {{ template_constants.modexp.frame_bytes|hex() }}, single_scratch, {{ template_constants.modexp.output_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) + precompile_failed := iszero(ret) if ret { mstore(mptr_start, mload(single_scratch)) } leave } @@ -227,6 +237,7 @@ mstore(add(gp_mptr, {{ template_constants.modexp.mod_offset|hex() }}), r) ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, gp_mptr, {{ template_constants.modexp.frame_bytes|hex() }}, gp_mptr, {{ template_constants.modexp.output_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) + precompile_failed := iszero(ret) // Leave before the backward pass on a failed modexp. A failed // staticcall writes no output, so `mload(gp_mptr)` would read // back the stale frame header and the pass below would @@ -274,13 +285,20 @@ mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) mcopy(add(scratch, 0x180), rhs_mptr, 0x80) mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) + // MF-4: separate "the chain could not run the pairing" from + // "the pairing ran and rejected this proof". Both fail closed, + // but they are different incidents: the first points at the + // node/fork (a missing, repriced, or short-returning + // precompile), the second at the proof. Collapsing them into + // ProofRejected sent every responder looking at the wrong one. ret := staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }}) ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) + if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) } // Compare against 1 rather than truncating to the low bit: // `and(ret, word)` would accept any odd result word. EIP-2537 // only ever returns 0 or 1, so this matches the strict form // the constructor smoke test already uses. - ret := and(ret, eq(mload(scratch), 1)) + ret := eq(mload(scratch), 1) if iszero(ret) { fail(ERR_PROOF_REJECTED) } ret := 1 } diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol index 35aa53241..04a7d36cf 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol @@ -232,6 +232,7 @@ uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; + uint256 internal constant ERR_MEMORY_LAYOUT_VIOLATED = 0xc9888d23; // BLS12-381 scalar-field modulus, used for transcript challenges and all // Halo2 verifier arithmetic. diff --git a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul index 6c630586f..1a0b06fb2 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul @@ -1,6 +1,10 @@ // =============================================================== // Lagrange & instance-evaluation block (pure Fr arithmetic). // =============================================================== + // MF-4: hoisted so the section boundary below can tell a failed + // modexp (chain fault) from a rejected denominator (x landed on a + // domain point) instead of reporting both as PrecompileFailed. + let lagrange_precompile_failed := 0 { let k := {{ k }} let x := mload(X_MPTR) @@ -33,7 +37,7 @@ } let x_n_minus_1 := addmod(x_n, sub(r, 1), r) mstore(mptr_end, x_n_minus_1) - success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + success, lagrange_precompile_failed := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) // Convert inverted denominators into Lagrange evaluations: // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). @@ -88,4 +92,10 @@ gas_checkpoint(11) // after Lagrange + instance evaluation block {%- endif %} - if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } + if iszero(success) { + // A zero or non-canonical denominator is a rejected input, + // not a broken chain: the only way to reach it is a squeezed + // x that coincides with a domain point (probability ~n/r). + if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) } + fail(ERR_PROOF_REJECTED) + } diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol index 398bd6c49..1545e1b0e 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol @@ -10,7 +10,16 @@ // Same free-memory-pointer guard as verifyProof. This body runs in // the *creation* frame, which the generator's memoryguard test does // not inspect (it parses the runtime prologue only). - if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) } + // + // MF-2: typed like the runtime guard, and for a stronger reason. + // The runtime guard turns a bad recompile into a revert on every + // proof; this one turns it into a failed DEPLOYMENT, which is + // where a build fault belongs. The probes below keep bare reverts + // (a chain-capability failure, not a build fault). + if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { + mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED)) + revert(0x00, 0x04) + } // Scratch is reused for every runtime-prerequisite probe. let scratch := {{ memory.constructor_smoke_scratch_mptr|hex() }} diff --git a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul index f8939530f..bd522d101 100644 --- a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul +++ b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul @@ -126,8 +126,14 @@ // validate_public_accumulator returns a boolean to share the same // success-plumbing style as other helper calls; this boundary is // where the verifier converts failure to a revert. - success := validate_public_accumulator(success, r) - if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } + let acc_precompile_failed := 0 + success, acc_precompile_failed := validate_public_accumulator(success, r) + if iszero(success) { + // MF-4: a G1MSM that could not run at all is a chain fault, + // not a malformed accumulator point. + if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) } + fail(ERR_BAD_POINT_ENCODING) + } {%- endif %} {%- if self.gas_checkpoints %} diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs index 1467fc128..e0e15a79a 100644 --- a/proofs/solidity-verifier/tests/template_digest.rs +++ b/proofs/solidity-verifier/tests/template_digest.rs @@ -13,7 +13,7 @@ use sha3::{Digest, Keccak256}; /// keccak over the sorted (path, length, content) stream of `templates/`. const EXPECTED_TEMPLATE_TREE_DIGEST: &str = - "0xfe89267c0778787678b938eb6f56f5e79f4bc11578786da45f2aad82384349d9"; + "0x063bb003b3f8eafacd300e1a20cb645db55832efa476689ddb83f6d781efb7dc"; fn collect_files(dir: &Path, files: &mut Vec) { for entry in fs::read_dir(dir).expect("template directory is readable") { From fefbd61b98b9740c55a28b251e65a2414008ca94 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 15:14:15 +0000 Subject: [PATCH 103/108] docs(solidity-verifier): record the MF review, its two withdrawals, and the operational gaps it exposed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the documentation half of the MF series. Two of the items I proposed turned out to be wrong on inspection, and both are recorded as withdrawn -- a false-positive finding is worth writing down precisely so the next reviewer does not "fix" it: * MF-10 (native selector folds hardcode a y^1 gap) is a FALSE POSITIVE. All three emission sites already use `selector_fold.gap_for(identity)`; the fixed `Some(1)` lives only in `native_identity_estimate_block`, a size/gas proxy for gate selection that is never emitted, and whose doc comment already says "Do not 'fix' this to call gap_for here: the plan is intentionally unavailable at this point" (it is derived from the selection outcome). The literal `0x20` visible in a rendered artifact is the real computed gap for that identity, not an assumption. * The proposed vk_digest CI job would assert `x == x`. The payload word is written directly from `self.vk.transcript_repr()` in `lowering/vk.rs` -- one expression over one in-memory VK, not two independent paths. The residual it was meant to close (that vk_digest binds the SEMANTIC constraint system) is not reachable that way; it stays covered by the trace-replay tests and, off-transcript, by BUILD_ID, per the standing M-4 decision in §5.3. Documentation added: * DEPLOYMENT_AND_INCIDENT_RESPONSE.md gains two wrapper obligations and a revert-triage section. W-4 (MF-5): a low-level staticcall to an address with NO CODE returns success with empty returndata, so a wrapper pointed at the wrong address or chain reads a missing verifier as a valid proof -- call through the typed interface or check returndatasize, and treat every try/catch branch as a rejection (custom errors do not match `catch Error(string)`). W-5 (MF-9): the canonical identity accumulator (O, O) is well-formed and passes the pairing layer by construction, so "this accumulator continues the expected fold" is a circuit/wrapper rule, never a verifier one. * §4 gains the post-fork triage entry for MF-1: exact-gas forwarding means an upward repricing bricks the verifier outright, so the symptom is a sudden TOTAL PrecompileFailed rate right after a fork activation, on proofs that still verify natively. The pre-fix Sepolia deployment is the worked example and should be assumed bricked pending one eth_call. * §6 is a new selector-to-cause table (Caller / Deployment / Proof / Chain / Build), which is what MF-4's split was for: the first incident question is "chain, build, or proof?", and it should be answerable from four bytes. * The spec's precompile section now lists the modexp probe and every known-answer/negative probe the constructor actually runs, and explains why MODEXP_GAS is the maximum over live schedules rather than one fork's price. * AUDIT_FINDINGS.md gains the dated MF-series table with dispositions, including what these commits do NOT close: stale fixtures, the stale Sepolia deployment, and the revm-19 harness gap. Generator comments: MF-8 explains why set 0 carries one more eval term than commitment terms (the omitted commitment is the identity, and that omission is what forces the committed-instance eval to zero -- indirectly, via batching, not by an equality check); MF-12 records the three properties that together make the `memory-safe` annotation honest, so none is removed individually. Verified: cargo test --lib (174) and --test template_digest (re-pinned for the two commented templates), fmt, clippy clean. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../docs/audit/AUDIT_FINDINGS.md | 47 ++++++++++++ .../DEPLOYMENT_AND_INCIDENT_RESPONSE.md | 71 +++++++++++++++++-- .../reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md | 21 ++++-- .../solidity-verifier/src/lowering/kzg/mod.rs | 11 +++ .../templates/contracts/Halo2Verifier.sol | 10 +++ .../tests/template_digest.rs | 2 +- 6 files changed, 151 insertions(+), 11 deletions(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index 2c6ea31b6..243d51b73 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1423,4 +1423,51 @@ These should be fixed before treating the document as a conformance spec. The rest are mostly edge-case, interoperability, or validation issues, but several could still become soundness bugs in a generated verifier. + +## 2026-08-13 — independent external review (MF series) + +An independent review of the rendered `moonlight-wrap` artifacts (verifier +sha256 `555ed976…6798`, VK `7ca78ec2…b7ec`; byte-identical to +`fixtures/moonlight-wrap/`) run as three separate passes — cryptographic +implementation, ZK/protocol soundness, and EVM/software security — plus a +line-by-line equivalence pass against `midfall/proofs` and machine +recomputation of every recomputable constant. + +**No soundness-relevant defect was found.** The transcript schedule is +byte-exact against the Rust verifier, every absorbed proof point provably +reaches a subgroup-enforcing precompile, the linearization/PCS algebra is +exact, and the memory plan has no live overlaps. Findings are one liveness +bug and a set of hardening/diagnostic items. + +| ID | Sev | Finding | Disposition | +| --- | --- | --- | --- | +| MF-1 | High | `MODEXP_GAS = 1360` is the EIP-2565 price; EIP-7883 (Osaka/Fusaka) prices the same frame at 4064, so every proof reverts `PrecompileFailed` on a repriced chain — and the constructor never probed modexp, so deployment succeeded silently | **Fixed** (`modexp_gas_word_frame` takes the max over live schedules; constructor modexp known-answer probe added) | +| MF-2 | Low | The memory-layout guard — the only on-chain check for a bad recompile — reverted bare | **Fixed** (`MemoryLayoutViolated()`, typed on the runtime and constructor paths) | +| MF-3 | Low | Quotient VM: fold-on-empty re-folds a stale top; native callbacks reset `q_sp` instead of asserting it, hiding dropped operands; u16 const indexes unclamped; `q_sp` unbounded | **Fixed** (four guards; u8 indexes keep their documented exemption, u16 do not) | +| MF-4 | Low | `PrecompileFailed` / `BadPointEncoding` / `ProofRejected` conflated chain faults with rejected input on three paths | **Fixed** (cause flags threaded through `batch_invert` and `validate_public_accumulator`; `ec_pairing` split; triage table in `DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §6) | +| MF-5 | Info | A low-level `staticcall` to an address with no code returns success — a mis-wired wrapper reads it as a valid proof | **Documented** (wrapper obligation W-4) | +| MF-6 | Info | Single-reduction `mod r` sampling bias (max point mass ≈1.36× uniform) | **Accepted**, parity with the Rust reference; already covered by §5.1's ×1.3585 factor. Regenerate in lockstep if the reference moves to 512-bit reduction | +| MF-7 | Info | 128-bit truncated challenges cap batching soundness | **Accepted**, already recorded and signed off as §5.1 (L-10) | +| MF-8 | Info | Set-0 has 43 eval terms but 42 commitment terms (the committed-instance column's commitment is the identity), so its eval is forced ≈0 only indirectly via x1-batching | **Documented** in the PCS emitter | +| MF-9 | Info | The canonical identity accumulator `(O, O)` is well-formed and passes the pairing layer | **Documented** (wrapper obligation W-5) | +| MF-10 | Info | Native-identity selector folds appeared to hardcode a `y¹` gap | **WITHDRAWN — false positive.** All three emission sites already use `selector_fold.gap_for(identity)`; the fixed `Some(1)` is confined to `native_identity_estimate_block`, a size/gas proxy for gate-selection that is never emitted, and whose doc comment explicitly warns against "fixing" it to call `gap_for` (the fold plan is derived from the selection outcome, so it does not exist yet at that point). Recorded so the warning is not overridden by a future reviewer making the same mistake. | +| MF-11 | Info | The transcript stream is positionally framed (a point and four scalars are byte-identical) | **Accepted**; identical to §5.2 (I-5). Any future variable-length section would need explicit length tags | +| MF-12 | Info | `assembly ("memory-safe")` is unsound by the letter of the annotation | **Accepted**; safe here via the terminal block + FMP guard + pinned pragma, now noted at the annotation site | + +Also proposed by the review and **withdrawn on inspection**: a CI job +recomputing `vk_digest` from the rendered VK payload. The payload word is +written directly from `self.vk.transcript_repr()` in `lowering/vk.rs` — a +single expression over a single in-memory VK, not two independent paths — so +such a test would assert `x == x`. The residual it was meant to close (that +`vk_digest` binds the *semantic* constraint system) is not reachable this way; +it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. +See §5.3 for the standing M-4 decision. + +**Not closed by these commits:** the committed fixtures and the Sepolia +deployment predate the MF-1 fix and are marked STALE; regeneration needs the +pinned solc. The replay harness also cannot exercise EIP-7883 — the pinned +revm 19 has an Osaka spec, but its modexp handler is still `berlin_run` — so +real coverage awaits a revm bump; `src/evm.rs` records that gap at the +`SpecId` pin. + [1]: https://eips.ethereum.org/EIPS/eip-2537 "EIP-2537: Precompile for BLS12-381 curve operations" diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md index b1da3266f..6bc1dafaf 100644 --- a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md @@ -38,6 +38,24 @@ unconditional cross-chain replay**: root). Without this, any accepted proof can be replayed on every chain and against every deployment of the same bytecode. +- **W-4 — Call it so a wrong address cannot read as success (MF-5).** A + low-level `verifier.staticcall(...)` returns `ok = true` with empty + returndata when the target has **no code** — a wrong address, a wrong + chain, or a wrapper configured before deployment reads as a valid proof. + Call through the typed interface (Solidity ≥0.8 inserts the `extcodesize` + check), or, on any low-level path, require `returndatasize() >= 32` AND a + decoded `true`. If the wrapper uses `try/catch`, every catch branch is a + rejection: the verifier's failures are custom errors, so `catch Error(string)` + and `catch Panic(uint)` will not match them — use `catch (bytes memory)` or a + bare `catch`. +- **W-5 — Bind the accumulator's meaning, not just its validity (MF-9).** For + IVC renders, the verifier checks that the carried accumulator points decode + canonically, are in the subgroup, and satisfy the batched pairing equation. + It does NOT check that they are non-trivial or that they continue *your* + chain: the canonical identity encoding `(O, O)` is a well-formed accumulator + and passes by construction. Any "this accumulator continues the expected + fold" rule belongs to the circuit or the wrapper. + `verifyProof`'s NatSpec states the same split: the raw verifier checks the proof against the pinned VK and nothing else. @@ -80,11 +98,27 @@ affected codegen?" is answerable from chain state during an incident. 6. **Retire** the old verifier in the deployment record (it cannot be destroyed on-chain); wrappers must never point back at it. -**Upstream repricing note:** the verifier forwards exact EIP-2537/EIP-2565 -scheduled gas. A fork that reprices those precompiles upward bricks -`verifyProof` (liveness, not soundness) and deployment of new artifacts -fails fast in the constructor probes. The migration path is the same -re-render + wrapper switch. +**On a fork of the chain you are deployed to — check this first (MF-1).** +The verifier forwards exact scheduled gas to every precompile, so an upward +repricing does not degrade: it bricks `verifyProof` outright (liveness, never +soundness). The canonical symptom is a **sudden, total `PrecompileFailed` +rate immediately after a fork activation**, on proofs that verified the day +before and still verify against the native Rust verifier. Triage: + +1. Compare the fork's precompile schedule against the deployed constants + (`G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, `MODEXP_GAS`). +2. If any scheduled cost now exceeds the deployed bound, that is the cause; + re-render (the generator takes the maximum over live schedules) and + migrate per the steps above. There is no wrapper-side mitigation. + +Worked example: EIP-7883 (Fusaka) removed the `/ 3` divisor from modexp +pricing, taking the verifier's frame from 1360 to 4064 gas. Artifacts +rendered before that fix carry `MODEXP_GAS = 1360` and revert every proof on +any post-Fusaka chain — including the pre-fix `deployments/sepolia/` +moonlight-wrap deployment, which should be assumed bricked and confirmed with +a single `eth_call` before it is retired in the deployment record. Deployment +of NEW artifacts now fails fast in the constructor probes for every +precompile the runtime calls, modexp included. ## 5. Accepted risks (deployment owner sign-off) @@ -139,3 +173,30 @@ binding, VK codehash pin, generated-constant cross-checks, and `BUILD_ID` (which does cover all of the above, off-transcript). Widening the digest is a prover-affecting protocol change, explicitly out of scope by owner decision (2026-08-13). + +## 6. Reading a revert (MF-4) + +`verifyProof` is success-or-revert: it returns `true` or reverts with one of +the typed errors below. The taxonomy exists so the first question during an +incident — *is this the chain, the build, or the proof?* — is answerable from +the 4-byte selector alone, without a trace. + +| Error | Selector | Class | First thing to check | +| --- | --- | --- | --- | +| `BadCalldataShape()` | `0x1b99e37c` | Caller | Heads, lengths, and EXACT `calldatasize`. A calldata-appending relayer (ERC-2771, multicall, paymaster) cannot call this contract directly. | +| `VkMismatch()` | `0xa447d73e` | Deployment | The pinned VK address no longer has the expected runtime length/codehash, or a VK header word disagrees with the generated constants. | +| `NonCanonicalScalar()` | `0x77530042` | Proof | A public instance or proof scalar is `>= r`. Usually an off-chain repacking bug, not an attack. | +| `BadPointEncoding()` | `0xf27905ec` | Proof | A proof point violates the EIP-2537 padding/field bounds, or an accumulator public input failed canonical decoding. | +| `PrecompileFailed()` | `0x84e81692` | **Chain** | A precompile could not run: missing, repriced above the forwarded bound (see §4), or short-returning. Also raised when G1MSM *rejects* a proof point as off-curve/out-of-subgroup — the precompile is the validator, so that rejection surfaces here by design. | +| `ProofRejected()` | `0xc3b0d8cd` | Proof | The pairing ran and returned != 1, or a Lagrange denominator was zero (the squeezed `x` hit a domain point, probability ~n/r). | +| `QuotientProgramInvalid()` | `0x3cc81b89` | **Build** | The VK-pinned quotient program violated a structural invariant. Not reachable with a well-formed artifact; treat as a generator bug. | +| `MemoryLayoutViolated()` | `0xc9888d23` | **Build** | solc's stack-spill reservation overlaps the generated layout. The artifact was compiled off the pinned toolchain and can never verify anything; redeploy from the pinned `(version, --optimize-runs)` pair. | + +Two rules of thumb: + +- **Chain/Build classes are total, not probabilistic.** They fail every call, + including calls that verified yesterday. A sudden all-or-nothing failure + rate points here; a per-proof failure rate points at the Proof class. +- **A revert is never an accept.** Every path above fails closed. There is no + configuration in which `verifyProof` returns `false` — see W-4 for why a + wrapper must not treat a bare `staticcall` success as verification. diff --git a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md index 8ae374903..d8df0a6fe 100644 --- a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +++ b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md @@ -1574,9 +1574,14 @@ rules. The generated verifier constructor runs smoke tests: - `MCOPY` one-word round trip in constructor scratch. -- `G1ADD(identity, identity) -> identity`. +- `modexp(2, r-2, r) == 2^-1`, checked as `mulmod(result, 2, r) == 1`, at the + pinned `MODEXP_GAS` bound (MF-1). +- `G1ADD(identity, identity) -> identity`, and the known answer `G1ADD(G, G) == 2G`. +- `G1MSM([2]*G) == 2G`, and a **negative** probe: a point on the curve but + outside the r-order subgroup must be rejected. - Largest generated `G1MSM` input with identity/zero terms -> identity. -- `PAIRING_CHECK` over two identity `(G1, G2)` pairs -> true. +- `PAIRING_CHECK` over two identity `(G1, G2)` pairs -> true, plus the known + answers `e(G,G2)e(-G,G2) == 1` and `e(G,G2)e(G,G2) != 1`. Deploy only on forks/chains where EIP-2537 and `MCOPY` are available with the exact addresses, encodings, subgroup checks, return-size behavior, and enough @@ -1591,9 +1596,15 @@ Every EIP-2537 call checks: - Exact return-data size. - For pairing, returned word is 1. -EIP-2537 and modexp calls forward the exact EIP-2537/EIP-2565 scheduled cost -(generated constants `G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, -`MODEXP_GAS`; model in `src/lowering/layout/mod.rs::gas`), NOT `gas()`. A +EIP-2537 and modexp calls forward exact scheduled costs (generated constants +`G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, `MODEXP_GAS`; model in +`src/lowering/layout/mod.rs::gas`), NOT `gas()`. For modexp the rendered bound +is the MAXIMUM over the live schedules -- EIP-2565 prices the verifier's +32/32/32 frame at 1360, EIP-7883 (Osaka/Fusaka) removes the `/ 3` divisor and +prices it at 4080 -- because a bound below the chain's price does not degrade +gracefully: the fixed-gas `staticcall` runs the precompile out of gas and every +proof reverts `PrecompileFailed` (MF-1). Over-forwarding on a pre-Osaka chain +costs nothing on success; unused gas is returned. A rejecting precompile consumes everything forwarded to it, so exact bounds cap what a malformed proof point can burn at the scheduled cost of the single failing call instead of 63/64 of the transaction budget (M-2). The bounds are diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs index 8b94597be..c97cdfa71 100644 --- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs +++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs @@ -109,6 +109,17 @@ pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec { // as 128 zero bytes). Pin that justification here, where each query // still knows its provenance: any other query source acquiring the // identity pointer would make the emitters drop a real MSM term. + // + // MF-8: the visible consequence downstream is a set whose eval-term count + // exceeds its commitment-term count by one (e.g. `q_eval_set[0]: 43 + // evaluation term(s), 42 commitment term(s)` in the IVC render). That is + // not an off-by-one. The omitted commitment is the identity, so the + // multi-open equation still holds exactly -- and the omission is what + // FORCES the committed-instance eval to zero: the eval stays in the + // batched claim with coefficient trunc(x1^i) while contributing nothing + // to the commitment side, so any nonzero value breaks the opening. The + // enforcement is therefore indirect (via batching, per-term error + // 2^-128), not an equality check anywhere in the verifier. let g1_identity = EcPoint::new(Ptr::memory("G1_IDENTITY_MPTR")); for (source, query) in meta.protocol.pcs_queries.iter().zip(&queries) { assert!( diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol index 72b41fff4..a8ee8778f 100644 --- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol @@ -169,6 +169,16 @@ contract Halo2Verifier { // assert the invariant in the deployed bytecode instead of relying // on a generator-side test the integrator never runs. ~6 gas. // + // MF-12: by the letter of Solidity's memory-safety contract this + // annotation is a lie -- the block writes memory it never + // allocated through the free-memory pointer. Three properties + // make it safe HERE, and all three must hold together: this + // block is terminal (no Solidity executes after it), the pragma + // is pinned so codegen cannot shift underneath it, and the guard + // below fails closed if the spill reservation ever reaches the + // generated layout. Lifting this body into a non-terminal + // context, or unpinning the pragma, invalidates the annotation. + // // MF-2: this is the only on-chain guard against a recompile that // silently moves the spill region, and the failure it catches is // permanent (no input can verify). `fail()` is not in scope this diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs index e0e15a79a..68d11d554 100644 --- a/proofs/solidity-verifier/tests/template_digest.rs +++ b/proofs/solidity-verifier/tests/template_digest.rs @@ -13,7 +13,7 @@ use sha3::{Digest, Keccak256}; /// keccak over the sorted (path, length, content) stream of `templates/`. const EXPECTED_TEMPLATE_TREE_DIGEST: &str = - "0x063bb003b3f8eafacd300e1a20cb645db55832efa476689ddb83f6d781efb7dc"; + "0x07b952304f2e76417023f215b63e13226ec63c14928e4cfee3312ee8fc3913f7"; fn collect_files(dir: &Path, files: &mut Vec) { for entry in fs::read_dir(dir).expect("template directory is readable") { From 03f1f7e365d20cf92173e199a065ab32e74b6829 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 16:22:47 +0000 Subject: [PATCH 104/108] test(solidity-verifier): run the EVM suite against the MF fixes, and fix what it caught The MF-1/2/3/4 commits were landed with only the pure-Rust tests: the pinned solc binary is not downloadable from the environment they were applied in (binaries.soliditylang.org unreachable), so every test that compiles Solidity self-skipped. The same compiler COMMIT is published to npm as a WASM build, so the suite can in fact be run behind a thin shim exposing the native CLI surface `src/evm.rs` drives (`--bin`/`--bin-runtime`, `--via-ir`, `--no-cbor-metadata`, stdin); it reports `0.8.30+commit.73712a01`, the pinned identity. Running it immediately caught a real regression in MF-4, which the pure-Rust tests structurally could not see: `BatchInvertHarness` is a hand-written Yul contract built from a STRING at runtime and compiled by solc, not by rustc. MF-4 gave `batch_invert` a second return value, and the harness still destructured one -- so the extracted helper no longer compiled. `cargo test --lib` stayed green throughout because nothing in that path type-checks the harness. Fixed by destructuring both values and discarding the cause, which is all this harness asserts on. Also strengthened one assertion. `verifier_rejects_when_x_is_forced_to_domain_root` used `assert_solidity_rejects`, which only checks THAT the call reverted. That is the single live path reaching the zero-Lagrange-denominator branch, so without a selector check MF-4's re-route was pinned in template text and never observed executing. It now asserts the revert payload is exactly `ProofRejected()` -- the transcript event it is -- rather than the `PrecompileFailed()` it used to report, which sends an incident responder to inspect the node when the proof was the cause. Result: 217 passed / 0 failed under `--features evm,rust-verifier-trace`, including native-Rust-vs-Solidity trace equivalence, the transcript differential fuzzer, the constructor precompile-rejection tests, `typed_errors_identify_rejection_classes`, and `compiled_verifier_runtime_fits_the_eip170_limit` -- so the added modexp probe and VM guards do not breach the code-size limit, which was the main open risk from the earlier commits. Two honest caveats, now recorded in AUDIT_FINDINGS.md rather than left implicit: * The WASM build is the same compiler commit, but this repository's reproducibility claim pins the NATIVE binary's sha256. Nothing compiled this way may be deployed or used to pin a hash, and the code-size result should be re-confirmed with the pinned binary before release. * The Poseidon-gated tests need an SRS asset whose host is also unreachable here, so they ran against a locally generated k=6 substitute (fresh, known tau). Those tests regenerate the VK and proofs in-process from whatever SRS they load, so they are self-consistent -- but this is why the committed fixtures still cannot be regenerated, and their STALE notes are corrected to say so: the blocker is the SRS and a Moonlight checkout, not solc. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../docs/audit/AUDIT_FINDINGS.md | 28 +++++++++++--- .../solidity-verifier/fixtures/ivc/README.md | 5 ++- .../fixtures/moonlight-wrap/README.md | 5 ++- proofs/solidity-verifier/src/test.rs | 37 +++++++++++++++++-- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index 243d51b73..dde6d37f3 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1463,11 +1463,29 @@ such a test would assert `x == x`. The residual it was meant to close (that it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. See §5.3 for the standing M-4 decision. +**Verification.** The full EVM-gated suite runs green against these changes: +217 passed / 0 failed under `--features evm,rust-verifier-trace`, including +native-Rust-vs-Solidity trace equivalence, the constructor precompile-rejection +tests, `typed_errors_identify_rejection_classes`, and +`compiled_verifier_runtime_fits_the_eip170_limit` — so the added probe and +guards do not breach the code-size limit. The MF-4 Lagrange re-route is +observed executing rather than merely pinned in template text: the +forced-domain-root verifier reverts with `ProofRejected()`. + +Caveat on the compiler: the pinned NATIVE solc binary was not reachable from +the environment that applied these fixes, so the suite ran against the same +compiler commit built to WASM (npm `solc` 0.8.30, reporting +`0.8.30+commit.73712a01`) behind a shim exposing the native CLI surface. That +is sound for exercising behaviour, but this repository's reproducibility claim +pins the native binary's sha256 — so nothing produced that way may be deployed +or used to pin a hash, and the code-size result should be re-confirmed with the +pinned binary before release. + **Not closed by these commits:** the committed fixtures and the Sepolia -deployment predate the MF-1 fix and are marked STALE; regeneration needs the -pinned solc. The replay harness also cannot exercise EIP-7883 — the pinned -revm 19 has an Osaka spec, but its modexp handler is still `berlin_run` — so -real coverage awaits a revm bump; `src/evm.rs` records that gap at the -`SpecId` pin. +deployment predate the MF-1 fix and are marked STALE; regenerating them needs +the SRS asset (unreachable here) and, for moonlight-wrap, a Moonlight checkout. +The replay harness also cannot exercise EIP-7883 — the pinned revm 19 has an +Osaka spec, but its modexp handler is still `berlin_run` — so real coverage +awaits a revm bump; `src/evm.rs` records that gap at the `SpecId` pin. [1]: https://eips.ethereum.org/EIPS/eip-2537 "EIP-2537: Precompile for BLS12-381 curve operations" diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md index fd699c43e..8ff87be09 100644 --- a/proofs/solidity-verifier/fixtures/ivc/README.md +++ b/proofs/solidity-verifier/fixtures/ivc/README.md @@ -7,8 +7,9 @@ > inputs for the *replay* tests, which exercise verification logic rather than > the modexp bound, but they must be regenerated (and their provenance rows > below updated) on a host with the pinned solc before they are used as a -> deployment source. Regeneration needs solc, which the environment that -> applied the MF-1 fix did not have. +> deployment source. Regeneration needs the SRS asset +> (`zk_stdlib/examples/assets/bls_filecoin_2p19`) and a full proving run, which +> the environment that applied the MF-1 fix could not reach. Pre-rendered artifacts for `tests/ivc_accumulator_replay.rs`, which replays a real IVC final proof and then mutates the accumulator public inputs to check the diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md index 77a313a1e..83be67ef5 100644 --- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md @@ -7,8 +7,9 @@ > inputs for the *replay* tests, which exercise verification logic rather than > the modexp bound, but they must be regenerated (and their provenance rows > below updated) on a host with the pinned solc before they are used as a -> deployment source. Regeneration needs solc, which the environment that -> applied the MF-1 fix did not have. +> deployment source. Regeneration needs a Moonlight checkout on the branch named +> below plus the SRS asset, neither of which the environment that applied the +> MF-1 fix could reach. Pre-rendered artifacts for the `point_pair` accumulator arm of `tests/ivc_accumulator_replay.rs`. The IVC fixture next door covers diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index eccaa4369..1ff5d3987 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1554,8 +1554,9 @@ fn batch_invert_harness_source(verifier_solidity: &str) -> String { pragma solidity ^0.8.24; contract BatchInvertHarness {{ - // The extracted helper forwards the exact EIP-2565 modexp cost; mirror - // the generated constant it references. + // The extracted helper forwards the pinned modexp bound (the maximum over + // the EIP-2565 and EIP-7883 schedules, MF-1); mirror the generated + // constant it references. uint256 internal constant MODEXP_GAS = {modexp_gas}; fallback() external {{ @@ -1566,8 +1567,14 @@ contract BatchInvertHarness {{ let r := calldataload(0x20) let base := 0x1000 calldatacopy(base, 0x40, mul(n, 0x20)) - let ok := batch_invert(1, base, add(base, mul(n, 0x20)), 0x8000, r) + // MF-4: batch_invert now also reports WHY it failed (a failed + // modexp staticcall vs a rejected denominator). This harness only + // asserts fail-closed behaviour, so it keeps the boolean and + // discards the cause -- but it must still destructure both values + // or the extracted helper does not compile. + let ok, precompile_failed := batch_invert(1, base, add(base, mul(n, 0x20)), 0x8000, r) mstore(0x80, ok) + pop(precompile_failed) mcopy(0xa0, base, mul(n, 0x20)) return(0x80, add(0x20, mul(n, 0x20))) }} @@ -2868,6 +2875,30 @@ fn verifier_rejects_when_x_is_forced_to_domain_root() { call_deployed_verifier(&mut evm, &fixture.proof, &fixture.instances), "verifier with x forced to domain root should hit zero Lagrange denominator", ); + + // MF-4: pin WHICH rejection this is, not just that it rejects. A zero + // Lagrange denominator means the squeezed x coincided with a domain point + // -- a transcript event, so ProofRejected. It used to surface as + // PrecompileFailed, which sends an incident responder to inspect the node + // when the proof was the cause. This is the only live path that reaches + // that branch, so without this assertion the split is pinned in template + // text but never observed executing. + let selector = { + use sha3::{Digest, Keccak256}; + let d = Keccak256::digest(b"ProofRejected()"); + vec![d[0], d[1], d[2], d[3]] + }; + match evm.evm.try_call_with_gas( + evm.verifier_address, + encode_calldata(&fixture.proof, &fixture.instances), + 30_000_000, + ) { + CallOutcome::Revert { output, .. } => assert_eq!( + output, selector, + "a zero Lagrange denominator must report ProofRejected, not a precompile fault" + ), + outcome => panic!("forced-domain-root verifier did not revert: {outcome:?}"), + } } #[test] From 564865ee05cfba038b9ad6ae221779b391204a81 Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 16:59:42 +0000 Subject: [PATCH 105/108] test(solidity-verifier): prove the modexp probe rejects an under-priced bound (MF-1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MF-1 commit added a constructor modexp probe and a test pinning its SHAPE in the rendered template text. That is not the property that matters. What matters is that the probe REJECTS: an artifact whose MODEXP_GAS sits below the chain's price must fail to deploy, because the alternative -- what the original bug did -- is deploying cleanly and reverting every proof forever. `constructor_rejects_a_modexp_bound_below_the_chain_price` renders the verifier, lowers MODEXP_GAS to one gas under what this harness's revm charges for the 32/32/32 frame, and requires construction to fail. It carries a positive control: the same fixture, compiler, and EVM, unmutated, must construct successfully. Without that control a rejection caused by anything else in the pipeline would read as the probe working. The mutation moves the BOUND rather than the schedule because the schedule cannot be moved here: pinned revm 19 exposes SpecId::OSAKA, but that variant is Prague+EOF and its 0x05 handler is still `berlin_run`, so no spec setting in this dependency reproduces EIP-7883. Lowering the bound produces the identical runtime condition -- forwarded gas below the precompile's price -- which is what the shipped 1360 did against EIP-7883's 4064. This closes the last acceptance criterion from the remediation plan that was previously recorded as unreachable. Full EVM-gated suite: 218 passed / 0 failed under `--features evm,rust-verifier-trace`. The pre-rendered fixture replays (`tests/ivc_accumulator_replay.rs`, both accumulator arms) also pass, so the committed STALE artifacts still exercise their decoder paths. Not reachable from here, and left as the standing action in DEPLOYMENT_AND_INCIDENT_RESPONSE.md §4: confirming the pre-fix Sepolia deployment is bricked. Public Sepolia RPC endpoints are unreachable from this environment, so the eth_call remains for someone with network access. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../docs/audit/AUDIT_FINDINGS.md | 11 +++- proofs/solidity-verifier/src/test.rs | 62 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index dde6d37f3..7e088f318 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1464,7 +1464,7 @@ it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. See §5.3 for the standing M-4 decision. **Verification.** The full EVM-gated suite runs green against these changes: -217 passed / 0 failed under `--features evm,rust-verifier-trace`, including +218 passed / 0 failed under `--features evm,rust-verifier-trace`, including native-Rust-vs-Solidity trace equivalence, the constructor precompile-rejection tests, `typed_errors_identify_rejection_classes`, and `compiled_verifier_runtime_fits_the_eip170_limit` — so the added probe and @@ -1472,6 +1472,15 @@ guards do not breach the code-size limit. The MF-4 Lagrange re-route is observed executing rather than merely pinned in template text: the forced-domain-root verifier reverts with `ProofRejected()`. +MF-1's probe is likewise demonstrated rather than asserted. +`constructor_rejects_a_modexp_bound_below_the_chain_price` renders the verifier, +lowers `MODEXP_GAS` to one gas below what this harness's revm charges for the +frame, and requires DEPLOYMENT to fail -- with a positive control deploying the +same fixture unmutated, so the rejection cannot pass vacuously. That is the +exact shape of the original bug (the shipped 1360 sat below EIP-7883's 4064), +reproduced by moving the bound rather than the schedule, because the pinned +revm 19 exposes `SpecId::OSAKA` but still prices modexp with `berlin_run`. + Caveat on the compiler: the pinned NATIVE solc binary was not reachable from the environment that applied these fixes, so the suite ran against the same compiler commit built to WASM (npm `solc` 0.8.30, reporting diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs index 1ff5d3987..387b77c21 100644 --- a/proofs/solidity-verifier/src/test.rs +++ b/proofs/solidity-verifier/src/test.rs @@ -1727,6 +1727,68 @@ fn verifier_constructor_rejects_missing_or_mismatched_eip2537_precompiles() { } } +/// MF-1: the constructor's modexp probe must actually REJECT a bound below the +/// chain's price, not merely be present in the rendered source. +/// +/// This is the property the whole MF-1 fix rests on. A `staticcall` forwards a +/// fixed amount, so an under-priced `MODEXP_GAS` does not degrade -- the +/// precompile runs out of gas and every proof reverts. Before the fix there was +/// no modexp probe at all, so such an artifact DEPLOYED CLEANLY and only failed +/// on first use; the probe exists to turn that into a failed deployment. +/// +/// The mutation lowers the bound to one gas below the EIP-2565 price this +/// harness's revm charges (1354), which is exactly the shape of the real bug: +/// the shipped 1360 sat below the EIP-7883 price of 4064. It cannot be tested +/// by repricing revm instead -- the pinned revm 19 exposes `SpecId::OSAKA` but +/// still prices modexp with `berlin_run` -- so the bound is moved rather than +/// the schedule. Positive control: every other EVM test in this file deploys +/// the same fixture unmutated. +#[test] +fn constructor_rejects_a_modexp_bound_below_the_chain_price() { + if !poseidon_inputs_available_for_evm() { + return; + } + + let rendered_bound = crate::lowering::layout::gas::modexp_gas_word_frame(); + let needle = format!("MODEXP_GAS = {rendered_bound};"); + // One gas below what revm's Berlin/EIP-2565 modexp charges for the + // verifier's 32/32/32 frame with a 255-bit exponent: max(200, 16*254/3). + let underpriced = (16 * 254 / 3) - 1; + + let fixture = create_property_poseidon_fixture(); + let verifier_solidity = { + assert!( + fixture.quotient_verifier_solidity.contains(&needle), + "rendered verifier should pin the generated modexp bound ({needle})" + ); + fixture.quotient_verifier_solidity.replacen( + &needle, + &format!("MODEXP_GAS = {underpriced};"), + 1, + ) + }; + + assert_pinned_quotient_constructor_rejects( + &verifier_solidity, + &fixture.vk_solidity, + &fixture.quotient_evaluator_solidity, + "modexp bound below the chain's price", + ); + + // Positive control, so the assertion above cannot pass vacuously: the same + // fixture, same compiler, same EVM, differing ONLY in that constant must + // construct successfully. Without this, a rejection caused by anything + // else in the pipeline would read as the probe working. + let mut evm = Evm::default(); + let vk_address = evm.create(compile_solidity(&fixture.vk_solidity)); + let quotient_address = evm.create(compile_solidity(&fixture.quotient_evaluator_solidity)); + evm.create_with_two_address_args( + compile_solidity(&fixture.quotient_verifier_solidity), + vk_address, + quotient_address, + ); +} + #[test] fn production_renders_do_not_emit_gas_checkpoints() { // The fixture's base variants follow `RenderDiagnostics::default()`, so a From d7b246a35668e04c1e4c72f8efc9e972fbae49ee Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 17:07:16 +0000 Subject: [PATCH 106/108] docs(solidity-verifier): correct the "Sepolia is bricked" claim, and measure the WASM/native compiler gap Two corrections, one of them to a claim I made in the MF-1 commit message and propagated into the incident-response playbook. **The Sepolia deployment is not bricked.** I asserted it should be assumed so post-Fusaka, reasoning from the deployed artifact carrying `MODEXP_GAS = 1360`. It carries no such constant. That deployment predates the exact-gas hardening entirely: all 17 of its staticcalls forward `gas()`, the three modexp sites included, so an upward repricing is absorbed from the caller's remaining gas rather than being fatal. The recorded source is genuinely what is deployed -- recompiling it reproduces `deployment.json`'s `runtimeCodeHash` byte-for-byte apart from the two immutable AUTHORIZED_VK slots -- so this is settled by reading it, and the `eth_call` the playbook asked for is unnecessary. Worth stating plainly because it is easy to get backwards, and I did: EXACT-GAS FORWARDING IS WHAT CREATES REPRICING FRAGILITY. The older `gas()`-forwarding renders survive any repricing but carry the DoS that exact bounds were introduced to close (M-2); the current renders bound the DoS and inherit fragility to repricing, which is precisely why MF-1's constructor probe matters. Neither property is free. The exposed population is artifacts with exact bounds rendered before MF-1 -- not the Sepolia deployment. **The WASM/native compiler gap is now measured, not assumed.** The previous commit noted that the suite ran against solc-js and that the pinned claim is on the native binary's sha256. Comparing them directly on a real 21,161-byte via-IR verifier: exactly 40 bytes differ, and they are the two 20-byte immutable slots a fresh compile leaves zeroed. All 21,121 other bytes match. So the EIP-170 code-size result carries native weight; re-confirming on a pinned-binary host is release hygiene rather than an open risk. Not done, and not doable from this environment: regenerating the committed fixtures still needs the SRS asset (host unreachable) and, for moonlight-wrap, a Moonlight checkout on the branch its README names. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../docs/audit/AUDIT_FINDINGS.md | 32 +++++++++++++++---- .../DEPLOYMENT_AND_INCIDENT_RESPONSE.md | 31 +++++++++++++----- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index 7e088f318..d8c0733c2 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1487,12 +1487,32 @@ compiler commit built to WASM (npm `solc` 0.8.30, reporting `0.8.30+commit.73712a01`) behind a shim exposing the native CLI surface. That is sound for exercising behaviour, but this repository's reproducibility claim pins the native binary's sha256 — so nothing produced that way may be deployed -or used to pin a hash, and the code-size result should be re-confirmed with the -pinned binary before release. - -**Not closed by these commits:** the committed fixtures and the Sepolia -deployment predate the MF-1 fix and are marked STALE; regenerating them needs -the SRS asset (unreachable here) and, for moonlight-wrap, a Moonlight checkout. +or used to pin a hash. + +The two builds were then compared directly, which upgrades that caveat from an +assumption to a measurement: recompiling `deployments/sepolia/moonlight-wrap/ +Halo2Verifier.sol` (a 21,161-byte via-IR runtime, at the `deployment.json` +settings) through the WASM build reproduces the committed native-compiled +runtime with exactly 40 differing bytes — the two 20-byte immutable +`AUTHORIZED_VK` slots, which a fresh compile leaves zeroed. All 21,121 other +bytes match. So the code-size result carries native weight; re-confirming it on +a pinned-binary host remains good release hygiene rather than an open risk. + +**Correction to an earlier claim in this section's history.** The MF-1 commit +message and an earlier revision of `DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §4 +stated that the `deployments/sepolia/moonlight-wrap` deployment should be +assumed bricked post-Fusaka. That is wrong, and the assumption behind it was +wrong: that deployment predates the exact-gas hardening, so all 17 of its +`staticcall`s — the three modexp sites included — forward `gas()`, and an +upward repricing is absorbed rather than fatal. Only artifacts carrying exact +bounds are exposed, which is the population MF-1 addresses. Verified by +reading the recorded source (its recompiled runtime reproduces +`deployment.json`'s `runtimeCodeHash` byte-for-byte apart from the two +immutable `AUTHORIZED_VK` slots), so no `eth_call` is needed to settle it. + +**Not closed by these commits:** the committed fixtures predate the MF-1 fix +and are marked STALE; regenerating them needs the SRS asset (unreachable here) +and, for moonlight-wrap, a Moonlight checkout. The replay harness also cannot exercise EIP-7883 — the pinned revm 19 has an Osaka spec, but its modexp handler is still `berlin_run` — so real coverage awaits a revm bump; `src/evm.rs` records that gap at the `SpecId` pin. diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md index 6bc1dafaf..55f9dccdf 100644 --- a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md @@ -111,14 +111,29 @@ before and still verify against the native Rust verifier. Triage: re-render (the generator takes the maximum over live schedules) and migrate per the steps above. There is no wrapper-side mitigation. -Worked example: EIP-7883 (Fusaka) removed the `/ 3` divisor from modexp -pricing, taking the verifier's frame from 1360 to 4064 gas. Artifacts -rendered before that fix carry `MODEXP_GAS = 1360` and revert every proof on -any post-Fusaka chain — including the pre-fix `deployments/sepolia/` -moonlight-wrap deployment, which should be assumed bricked and confirmed with -a single `eth_call` before it is retired in the deployment record. Deployment -of NEW artifacts now fails fast in the constructor probes for every -precompile the runtime calls, modexp included. +Worked example: EIP-7883 (Fusaka, mainnet 2025-12-03, testnets earlier) +removed the `/ 3` divisor from modexp pricing, taking the verifier's frame +from 1360 to 4064 gas. An artifact rendered with exact bounds but before the +MF-1 fix carries `MODEXP_GAS = 1360` and reverts every proof on any +post-Fusaka chain. Deployment of NEW artifacts now fails fast in the +constructor probes for every precompile the runtime calls, modexp included. + +**The exposure is exactly the artifacts that carry exact bounds.** Note what +that implies for `deployments/sepolia/moonlight-wrap`: it is NOT affected. It +predates the exact-gas hardening entirely — all 17 of its `staticcall`s +forward `gas()`, including its three modexp sites — so a repricing is simply +absorbed from the caller's remaining gas. (Verified by reading the recorded +source, whose recompiled runtime matches `runtimeCodeHash` in +`deployment.json` byte-for-byte apart from the two immutable `AUTHORIZED_VK` +slots, so the recorded source is genuinely what is deployed.) + +That is the trade-off worth stating plainly, because it is easy to get +backwards: **exact-gas forwarding is what creates repricing fragility.** The +older `gas()`-forwarding renders survive any upward repricing but are exposed +to the DoS that exact bounds were introduced to close (M-2) — a malformed +proof point burns 63/64 of the transaction budget instead of one scheduled +call. Neither property is free; the constructor probes exist so the fragility +the current design accepts is caught at deployment rather than in production. ## 5. Accepted risks (deployment owner sign-off) From fbfdeae5b88e7643bd97704cdd2f30372bf00acb Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Thu, 13 Aug 2026 18:29:15 +0100 Subject: [PATCH 107/108] clean --- _to_delete/gitlock.HEAD.lock.27728 | 0 _to_delete/gitlock.HEAD.lock.28476 | 0 _to_delete/gitlock.HEAD.lock.31577 | 0 _to_delete/gitlock.HEAD.lock.9194 | 0 _to_delete/gitlock.ORIG_HEAD.lock.19008 | 0 _to_delete/gitlock.index.lock.11897 | 0 _to_delete/gitlock.index.lock.20480 | 0 _to_delete/gitlock.maintenance.lock.15666 | 0 _to_delete/gitlock.maintenance.lock.31732 | 0 _to_delete/gitlock.maintenance.lock.32411 | 0 _to_delete/midfall-src.tar.gz | Bin 0 -> 2562192 bytes _to_delete/pr1.git.patch | 412 ++++++++++++ _to_delete/pr2.git.patch | 739 ++++++++++++++++++++++ _to_delete/pr3.git.patch | 239 +++++++ _to_delete/pr4.git.patch | 130 ++++ _to_delete/pr5.git.patch | 100 +++ _to_delete/pr6.git.patch | 82 +++ 17 files changed, 1702 insertions(+) create mode 100644 _to_delete/gitlock.HEAD.lock.27728 create mode 100644 _to_delete/gitlock.HEAD.lock.28476 create mode 100644 _to_delete/gitlock.HEAD.lock.31577 create mode 100644 _to_delete/gitlock.HEAD.lock.9194 create mode 100644 _to_delete/gitlock.ORIG_HEAD.lock.19008 create mode 100644 _to_delete/gitlock.index.lock.11897 create mode 100644 _to_delete/gitlock.index.lock.20480 create mode 100644 _to_delete/gitlock.maintenance.lock.15666 create mode 100644 _to_delete/gitlock.maintenance.lock.31732 create mode 100644 _to_delete/gitlock.maintenance.lock.32411 create mode 100644 _to_delete/midfall-src.tar.gz create mode 100644 _to_delete/pr1.git.patch create mode 100644 _to_delete/pr2.git.patch create mode 100644 _to_delete/pr3.git.patch create mode 100644 _to_delete/pr4.git.patch create mode 100644 _to_delete/pr5.git.patch create mode 100644 _to_delete/pr6.git.patch diff --git a/_to_delete/gitlock.HEAD.lock.27728 b/_to_delete/gitlock.HEAD.lock.27728 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.HEAD.lock.28476 b/_to_delete/gitlock.HEAD.lock.28476 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.HEAD.lock.31577 b/_to_delete/gitlock.HEAD.lock.31577 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.HEAD.lock.9194 b/_to_delete/gitlock.HEAD.lock.9194 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.ORIG_HEAD.lock.19008 b/_to_delete/gitlock.ORIG_HEAD.lock.19008 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.index.lock.11897 b/_to_delete/gitlock.index.lock.11897 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.index.lock.20480 b/_to_delete/gitlock.index.lock.20480 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.maintenance.lock.15666 b/_to_delete/gitlock.maintenance.lock.15666 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.maintenance.lock.31732 b/_to_delete/gitlock.maintenance.lock.31732 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/gitlock.maintenance.lock.32411 b/_to_delete/gitlock.maintenance.lock.32411 new file mode 100644 index 000000000..e69de29bb diff --git a/_to_delete/midfall-src.tar.gz b/_to_delete/midfall-src.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..fdd81047bed5d1e7da91db70295f03188c44a847 GIT binary patch literal 2562192 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 fW7Vv=}wlR`tta93M}|^thp)Vt%cDaOiYnoWNA! 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 `ZX_{ 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�kwnJ4qpd@v-&kq^AVSKc-!vOh1H{8^eq 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≪>j2%h|w65e!=S8tS7xUZW8Cq0CcMZZU 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

61f+k;{CF{@TQ^_$25X7qBVszdcMn+X8z(~^); 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∓eXw`BZJ zT;Da9V(R-hzUw=Fmen)&WLosT&pwDaQ?TMsE2O%vGW1;$UH(XV;r`{jiLFa0RX3Zz zkPi#fy~e^vdxx>aX_Pr5BaigNQ|lW1Hom4d67i--(~rnEymri3p-?1tVj}hM;d?K| z1J)~deM1I#bAB1D>IxI|d*lRhM0+~;^n8WKWhsSvpLp&oNlNZ&?l)v_0gMt1s(7F= zUs0uCdzGx5j&MBd({Ba1BRW^Bd#>DHbWx~FL~-kFrPFfRqJt9rFLto%C@1R^^_g!d#*UG5 z>Ydt>pGd?Rj$FO@0%-fa{($8N@d~AL&o?{Vd7LvW{p#2_Rf=GJO^&fuO?=ne*RNmn z6m^E!rSpz(%)KZ2azFR5=9!Se)Yx|!BJ=`0GgqzhDI?m=B493|FE?L1;+9SN=!c4s zU8-BD2yKyIp#KxClc<8P(qU0oi;`xVQ@?(H$Jm*RYjTJZaAxNSS_x|%x|dil%)yGT znu)c!`u2W-qDvWSJmiP<9c^Armmz=|&2Z#}jGFwfrjFT)MG}bhm5dNvAjp>LP&k{9?^(swRgHv2H|+3QJ7SQ^-XSv9$d3npp#&(~86yY8ep}tTLj1 z=X`#+mWnbz=-VLHOKsyhEh!Sr^H@tF7kSI^<(e<6mZ!`k*H zOjoGtA{C?a>~9`bi~DLk{1nplt&}_4g-w$&yjq1(e_!HbeqA9H=0$0$m}U{xsi>nnP?wTv6GJ~Eqq(Ic?_m^$`v z65jO#_ZGW{{pt3+R}Iu3C|seXp%(q*sDv-;7Ob3cT_?@$KalTwmB;Dm@uf6RiPb*t z32@Pxi}4CZ`NtsX)_L+n8`Q(f%XY42Y@aJxYG*8I|F!DH@cvM<y*HL=YK@W2P#fOqMW^y?Q}KM`2iP&UYOrfxtA5G_ENaM$zL2TvOh86Zwq4 zh@BxQ9kk;!1jc&mZgHF${^?0t68}CZD$p=OPm$*_6uRoW!SL+Ljoej}VUj^+XG{^p z49iRSTv?X~Dio4Gt={$fQ@2Q}Y|9(hp!sMTnHU2os;oo!VLO}1-lnMmI7l@a~+PuPj?inm_F-8?DgyX3AZ)VI4WGF^PGzR7hCI1!`@ zi(?A=v~qJWN1OX8>|a`}W38A;r5UO}b3c&u$w2&ASF0dk^9S4rr+! zmOMnJdq;NunUDONUtT1se~?p$+I)r9KTRfLr30ozV-1R!3o@P)hpBTxjSo%`1H$LX zix%KfBfa89xM*IYLZNKKna8(nIt*g4(^{-i`!O;OpV5HbCkVI@|C%>t(rtkEW@E#hc;Y z9yDLM?mj|%&w9(7bcY<}GsBdG?F1Vsg*+2IXr;cBEqCksgj#NfgUYYkMMLhwzz!;a z(#$~5?z2f>!q~KYks|A_r-RfJv`|x+W@(KrC@6D1P8LoU@qJLLq z-v(HuSX`79Ay?GY)H^TGzV@zXKOSaUs`Pt=?A1{@XlksT^a_6wGOOKRuEabTP|e=K zAe&%`*YPb+`WuW&s!^?cqK=Dvpm6h9(9}-9v_0o5l^4q22Oi5S441CAOB6x?zK;s| zb*p@+Z~oO2SGwu)tb>BTHsdGd)<;nGIid1dEQ@F328HX{{ReC2MnF z`hFQ4Ex&0-3eDx#y$|?K&1nQX;kYAJDa}MiP@9|h{O|;tjiI_qTaZc_>Ct*Vq0NS5|)Ady-oHt3_he zx|18_lO^6?hl&^Ch1a(eg_ptrH)x_x5or_@jSCz-%e2`&j>`sfuqh`6?;AL$H;3Fm z68v8-q`8gL&TdjN+(J7UiaU)yzO>iOHif6MMIr#5##gyEAXXgL85ruMKZdpN>ZxV~IeRX@MDySM z&%hHQQ8tg*->Fh%pF&P3m=%i#Zhig1Tod5y@ z+p-aAfRx|p{xzigd$a)uQsL)y+{gbpYp&`FGkaTu&CW<*oh)^%_mKH`IIAeB;RVHu zE0{O^K@7t`=@9p9vp}vtk`m^(-6z?hud{}U0oxjA^Tc8rJ=hdPD>-FKzG&$7)aQ_F(2hwggDR0>RJPFAs zD69OUx4ZZ10W3J@GK6k4_dijc2aH$Mk5&8)lF9e|`oX>#jK9nsf$J{g`qyFey1akP zeZrSR9#K7cc}ov`v8>p2y=YUcM#MNh` z%`V42T49&jwwFXp>D?Y)Ak{Z@qd5KD>q9H|%-p-Kv~Fg>z`J*wZEF+L81JjER5irQ zfBa@mJL8lqSwr(H^Zoa6)`UUPJEa19-c+3oa<|FpyrY92jP4Wn(mZ846(i%nm4uc$ zs@TB&R{ztA+Hg6}tMu`?nq${fudx=}N}2_#0wHU^?z4vvDBjw>iaQE>lFn(592orr}+NfMEw~(Yx~86*lWK3A@uWRcM$mB3&9W65nSgQ0|px$O7}+T z%>pi~s9wEHe+9bZYpkGF6+$9=$(FQUvKGmREdJqd#bxg5t8=Q?Fk9Le?whSYo;6GyPyJV8k?D&}E&nT4 z!ynuKP}@afpAq;!w5tKf+phqxQ%D}v9UF<81QanTioqvJC0KBmAk{e-UYxuoY$n}# zHfQv2Bqi~!*=^Pyc*#rQS$5~!a@zUtW~BC>zgqG7-`0@r$fWn|NFHw73miIv$*ECv zm?>)KcYUa2d8+`u5EggML)EcMeCi7AJ;oNl!#{FN?|(dUfG18k(LouX^#5b|GyTN{ z?HL-L9T70VbZBEKnR}(tWwPN3hm4!UHO4BD3atg_;J!<|_brCrf1zD$%ya*9Y)scw z=9{{C9%jKQ%Luw!znLVS2I2MJRkgrM7{%evI z(8RvOOB4U%);|ft?Qu;(-zjjdbJw7bdB}}Qie?wvvN!5Mw7P!g=G07aJ0(i4;@oSw zypJw1PfVh{6{{?r!tbK({7&J{U~e7AwkZ0^U)f8tp?;+RTE@H+))T45bn`6$XX=8@;z&I5~+o0D)xH=nPkU>D0IJ_Tk#mMmV z;F7xhI2P|ns4JrO-BgS6I40XKC?9F=n1B7B~CEW2SIX%;+>64@-K-rC_Xf9-p_ zuwcQKEm~J(jH9e9g>%x*{#-Por>mJ`5TFN@fbpGM~ zMN6k~y}JJSKImd(W&x#+vh`tfM3?!a4^~ei{^S8@Oq>1w$6KtQpKDB5RCw5G*W~|T z|NiCqdsg!5z-9|8VUbB&Ryd4hD~lC7BLyQQ9A#7nO)p1PL#6aW`V-Vh?z6 zR7mC}rCyNxEjKPqNt{T^{RrORF$vElixAp3Oxhg{vV%a)F(~oy1u&izbi-mP=vjK< z>QyhLpUZi%=S?*WG~kJb-*uvKd6Ib=dy}h`tDUGrcTo&FcJ0&Nh4_sGj?|T_5#L}}-3xz?`@90O{R`6T!H7ju(BxBqb&1ZEcr$?#63U_8qbSL+-Qr^5DC_OL4Lt7cO5~)T2I}=8nO7D)JieJ(H zJ7Rk8kC=S?Y7I{%vGw}sJ$r9ckF)Ww`+H;V%0&xFSyWV5j zImwXn(@rFor_0{D{qJ6u12}frVY7Ws)R~?+CPfUzn;Gzmt&*?p@AA}lnEbb2i7{m< z>ffRs%O|}|9iop#uNWPsjBF|=0_(mQ%*GE$f3n`X@8Q~5_MwxBDx)=~1j zTAY&(+#nHo?q~b1EnP78*$5v^5(6KU^9LPXFOlKe>iNotTx3_SZAP*a%}ZYepIcvs z{b|jbgv!3XTzSiIgY_hpKItU|{~;VA@x3}-cHo|R0^hycNj&r7L5^|x^c{cd+C=5Y zSE-)*<G=bfUNtVdAGue=BSn!r>vFlO}+kCvNG{dmNayld!I^@+ivBu@0oeN*7WvrsAt z!)sQ^#P{Qpqbd13FES*3WgYEn=akO*lfH#c^qgHQy0YaN`}z0HanfyGU}h6uI}z_B z<`+ls< z9#?;S!%JSjtwi5*LhU=8Q=ZN6SgNFVlGbKO^8rs(%;oHQ$HUkl%A*fdMslseTTIqD zfVL%p492i3lV{E1H`pQ^%id00yY`fw68Pv%s)u0Ee#G^u(Bhk>j=Gp+sQV51nAHZJ z{?t$3wWw~i73q4F%V-PenU|UJ2yx05P8BBmLYTv$UCiESCzUIv&u@28-x<)rtqOPeWlA(PxR`EE^6T9;dKo7g7EPpr}+cnPkR--)~S(y#B`azKj({0pp4b1@ylxp9(s`Z>nK1I891+`+|&Z6-- z%l`iXJV3+0^h1e|h##_!{2e;gyx(Dn-?WL3D3u{n)*einkb{!rLt*mJLPZJsp_vZbm!uP z9s#Q2wM2zCPXzX3L0;_woCH{3FXJ-;GcM|8HXk2;uVDv$b#X{1^Y`pj^M0>k z`J{5fA&Nr4s6*0)-(^vOjak5(JC#!T9flJx z2n6_!AWYZ-%n_{!Eb=h~!wta!B%X*_xRAET;eQuk;_wfF!Dr+7B683SkyW?>>+)iF zXD&7(!1<2IL<8Z0l|~FWJb1A;^9Az)GTb;!BUhXwHDeX>1eSyF`8G@w_855y2*GEd zizygC_&kbRFi0pq@s{oKf$F#P1FiV;l!q=>Qcve7&t zZyU>n!T4G^8&5W#4L+?kac^cJxaAPUH|$Vk1Rs@?GCo($@+K{rc0`QMv{YNB95dw)v%5@K01$srQJ5OEE6vd3s^zMT4(yq0P zva`GYkXvyFiuHgBkD7(b4Ij@uA3Uc#B2CZcp`gQLEB+u#?=}%%t~t|gR&CUWcQDN{ z`}f34U~clM?4mcWR2@Ku?9=a8CbpI2Kwt=#%GzG!rd|RHDO`{HaB@}@T!azpd-DbN z{o}Pa54`0naip7_*-uApi?*BK~uJ8Nso) z-uMDZ!YG!EH3q;fT_Xwrl@|f=+Ts4Pq@lk(zW=&BUWapJXYE5*+bn1i?UUzbM@Ei{ z_$ViJ#BM(^1H|;Nt`awo94{z_`U%z}a3E_q1Vf1{Kr;;k?i*4j9=M<4*^sjZxrtfk z98nj-K(IRs)mzZyPh$Jy$3Kp6C)y@47`rRjuOBb`xKjQ3XSqP)BvsN@L}H0sndzyU zMh}3O_H}LH^9S(U8M8}ou>f5QT(FD>sV`yVEj?V(#Z9$QXUAYIIN?LNRA-5RV}w

ZkIbMa`;(iP0tm{>Z0NRiCp$oneX<7eB!CSJi9?h@pp^ zDlQId!`aPw0v?}75k^yBnk8;AE@CGc+mlnt0%x-}6SJQzX*LLtQG#=ZnbQ%&tmTMp z>EDRfixOc=K2m8FrF4_zA@+|L{sO%q-2=Y?Argj#i-qFit~iKYu%vc=-dRNvJUNIg z;4k#C8%~3gP|@F60q#y(lhHzi??UR(&c48kW#pi(fc0u-IMVVdz-R`p8|{oI?uuOe zHSokB@S}7=a85sywqI31gntM(@gBtac@j>&V3Q_y9~9?UfPLXvK>}pUGF?{g^zlxz znbpucf-2DrJT3>!fE?+R;pEVD+{J&SLVOi>6l7972<&H*Gb$H3_m(0C*MNXT`Cn^= zvlOij16_jHMh}Kj09!bE$XKz1gN2O}5y(xk4jIYe*ha^}td~bG)v=^wL%TkPwFiJda3Nd{MaynJ`BU5?AHc{%Lm&O>a!Z7N)BXP<)yoV)$ z9I*^)?ZNOj1}7!{n+h{rlZbnxARM}q&eAW61-HLy5Of{Cybm( zAmaIeyADoQL=hgCFA}K@1P#dTYEE9@(%z$DZbHNtG3Zl_x|MqI3M|e?>jb%7?e!@3 z0z7);8(h!rrz6dbgC7qZKz(80!EmOPiPNI7Kwu93h+!OrSWeJ`fbFUizmn{?&_)F8KYA_`y0mm>_M0$hYsHfu?tm0Dr3~;7UWlM2-tkcyO%TdJ-vrD7t2~o|;0WL$ zN~b^tmFx(190_(_kP=RBh*NhI^FuOfGa)_D)&umi?u9+mh%vxnOY1=`v8Ndt1|Ny^ zkdiD2&tbNO3oXc%VxkN{Z&}Q&GtuC9cM^DGq=vkrh6V&H$V`fE@US|EIeHZ``!wSI zvkixU#Ul?B?81yAz(y1ZCIfJZ0C$>TS>w?Q=HcU!tO5WCiXpl^H^80g7a)+pp`^S! z*7jM+J(Oa1K?DdzxL6wWY{|Df=4Qf+DsV8KCM$r^UlrP?BreMu4Ktaw38u=Mc5zgf zLrLY-<^m>o!8GM?G;ZA3M1FvqiyBD6m zt#aT-w0LWgaP&tK_UUZj9^q;8F-7Em{xeIiR+wh6&acBxdqT5Kd!3uB$+fKU2vr~s z0|YY=(gP!lMKNss)*G}g6{TF7$|EFTLPa+fn!}U;#7~>`@`pDtun8+~A#4vWJJ+r8 z_4Jp)=o0A5PuSXszs_67U&Q8f{F)X>wHh-%!|%o^qQ>#(jp_GO&nmN% z+1c5wCgkjt3)HGPXNQRuLE)fqTHmn*sj(PFIfDrxt&A~&->dhT6o3Oj*?>-}`-B&8 zOu=L@;o?Yd;NSjk!bMzEczDC3Sh?&w8hxj^Ne4=Z<9jcQU!7>p3 zn$Ey$I2sH-;(1To!^wzFtX_ZZ#MMjE8oK7IbT?o6)9%f9(zP)_jZm3v`HVa-HJRpL1OxPjc!NjJ5 z=v)ES99z9t1C}c&mtQqZ^|B?(NWTrN-}U)w57&GnjUj_uKBS~EdSb9H6zm9MfbWNo zVxB25?X(G&w|(s-mG3t-h7xNn5+RE_ixeQj?I+Dd`&<~U%mi{GA47zQJgD3zf+=%dB0X|K*9{(+H_N!;AUuyg4T&weDUX?()%kEWYJb630 zZHr@@{51FM`n4lGe-rr)$Z%_uyKf>N^gCBAn_T23m!!M1i(JN-QBDTao=slOK@I_E z+G@AI^uP34lflR)e?3O47tl`!A3u&e_PLAv=Z^HfZvVnQck%kU+oaQr?qrAjP3L}9 znO?NU9h?452Y*%Fr(fjUyqnI|bUb}VUn|$OGd;|peckFIGP3CEi>l>>+r}%&vU!P( zWf@I{YY5uhF0N{JTH7?o3+ydywB~FZQT&t3923tKZ+DeqHM! z?gHj}@$la4>wdGT-{$Jz^{Y+&Hctn{6`MN0qf^w?jJlB@bZF|DP5rjx2I{&^UAGM8 z0s}GKh3(unAgn-RkzHcX$`};#a{w;$0+2fB+cM;ju$1aZ37Yky=4nQcP;GMsOFH8 zD7rUa#?#7foNZL!Vt2i1uVn+AM)eJL*PCASx;K|L^&9Q3H!a)L`RvZ5DxKSwg%BDw zZFqP(V#(bt3m}_2mt_-mmAfiD6-#)vOWku4@0zk0+6v%u%|z81^`)pjW?>`iBj%Mv zi9QctPUNz6W~cxeOgEPmLAsW=?F{Q}s=R`=9juTe3k)kutR+5hpP>I!9yR*>WiaV> zZYIw*B)=~)EG%m9B~pHM=a~OsKR%P>tsWK7w?$sh?@~W@Z(!zKk5sSzH&!xibw}Ns zt33x&=l=s%yWXVnOe(D}eQILZ;H_(9WmGY#9#!V%pe3>>m(v@L29xP<(7l=LNRZdo zAvz8RzjQ`6@mV#qw$HfXSonv`7CTm?Bg8I}G>Sm?{VgP&c!P^~wlW8$LUMoH*UK|^ zLUAbVbSY0ilR zclGW0A5(H9rd;5M?!9c~Q|0*&>`};DF;CqGt8xUQ0CIfscD)u!w9UI0mbli6PVE(q z^uZ_uV&+1zt}2G7YC~#nn|80FvWs$a$4Zsd5^Jf>O;Gd|*6u)R zw()tOR!-F$yaRYiI%As&_DJF)Wt~VJ{s&y48{$=d5E|8#)zz8UhP$<*xo~~ezDTEm z>Zjtc+Pxp-b(?HO5I)$gM~9nB1tI(GUP2`6PONmId1fo%rI7tV*!vZPYtRh`?L>D~ z6b7=5Rf>3Blif4e`{Gcyz_ZG>x|LjcYfurTLiSB%Ed5?~&wbI69^ZC)ce*x?<-0q! zq~f1+m3TKOWYZg)dvL^{4N|788f~hJF`OT}QTF7!SwQ=~q9i|aK&t);h=ogiQRpmL85JO9e4Z)$n**oYs;cT(@R2E(G zCq=#1)u@G)1Tf-3-#XaS{E6jc)PnTj3yjIg`Pu0=tLP75$u3yL62s1n5DLb#{Rp+& z_Gh(_YCi6MqoC<{vwP2u4LdMoQ`LXwo_4$v_V2~}^|2q|e6jD1Sv_{r;6G4|%aGJk z_QRWu$%@?AktHvE&;=Zu%Lr!?`goZ`_s6Eu#uW2pT91>1;MC$)@B(#{B%5{Vc_X?& znBtb+6|Hh!>+-gXcU6PF(h#aRW^n91D`$gygTbdS!)gD}@b|3#Z%GJ_cgp7vo|}bE zK<=GUfBO5M&9g^J??9S21)qDLZsKQBTz7iF^aYOZ88}5lZa;YS^*NV=B4u2p0MnK5 zf!EYsrNMnXC0R3WRJ?1qZeHj1;*yLPq?+|>OQO;##K8C)*x>89^nk{Y&#mQkEC)4- z*qr1qE*;P-Vsn~<&7Uh1u{q0|avxMFV#D*XIjBj*WcE6fKi4JV;x@mX1J4?$5T(q* zG?>TdsyKuVImVUiyrbEGn6?u0)TeS#oIG=JEo#F;h;E3(NVUz%HZ2u>W7g{RXkKhR z^*w5nwh{Aq(wcPJZ5TzV2;%jf4j$wcd$KPYpLmKb!Htk6#(=Cg@`8B_fN)z@=ce8A zMz~>?Mgf(h)<|qgwz~y7wN$tHdif-uHDj}O+^nmy2A&|0<+9gkmd=+Vk>OEKfXN)O z-U!!OrjS2?2EnutFk)uP~>nQ2x>M;O3X<*5BHERY#?ok1FqEssDBKyl*0j?^o%ggCiYYe`mcG7s= zr(IS0<318hD_Fmy2QG4edtK{8!m1`LSI=@+F#Chc&aXoyX{BbR10C7uYZ=;pQ$1OO zgVrF$w~zca=$);1+#h^Gms@Yto8?pEaLjvh2cI)q&jcd#;tSlyqcIje zm-r+G`c=6Bg@X%?qZpToeUHH|H+bi&ihst_CH?)kgr|SMsuX2$iwD`GWVNcy9x^@I zWkrwp1k_xOyI#QWFVKZoS{t9mbjN|e5|2~iC|Sx9iFKqB0_-Rx-Ee?^A%8`^qVX#8 zb>13#h0x=L0bNR(s)N}wFT(E!kWU}ubD`2f;?uvf4)y_`&DkZQ=OIj$;`p*N>L?vmTP zo!QxTA;2ZMBnN5al28KKo1LA#Te7#i*>brHf}j*BB3%U$k)lFCK$?hvC{m;eqEz__ z0!o#lh$#Hu_xs+P`et_ak|6SDKYrx0JMTNMeBZa1MSZi$I2vk6ZemVR63_=TktT?n zQlQ37Ivpkd%EfX?BMzO3vPM=*$;o&kpN6Q+e2P3{XsWEl)|TjkNg@#%eOxn&22HtP zIU?=dba85%dEwf2pG(MnTl?`5yBBebc}_LH@620f&=Jf~!?k!oY!bq2DRfJ9pZ=>4Y;{^T{hvdejKD zuK5dkiB2%TZ+35HMi2S_>9%#HR3jymTNn-wMAa_nJpkjDo%^Fh1+A2x3j@bgR|vqF z3wj{hkH)DZsnDS#St@M{#c(C4I1@fPs0ju6s4X+vic>FQ1Sdby&#iH4Z`t9pZLghh{fX7)Vx;)I$^s@as9kEP7Q5+_CQQ%|u%xGm!&Pvl&Wq%$jVKb+XI*{h&oq*AbrJG$JuJN?qpt<>|&c> zCoM&iE$7Ct&I@<`+u*^5Pt=J-3X`8mGxIv2ypJ;lwOpN0V_^aGMIh;63ac9+#E6l7 z1JzGzBh1Q{J;c$RU{0|-*f5Z+wL9yK74p(xy^T6KqoXSC-V}|Jy8r;q>T`KLV-SO=o)#k zGoS>qyMPfIZa8Swp{55s$1eVA7U|FlS6t^h8%@CEUS>)2Zha|2NeeZRQ8dprFxS+k zS=!JVF_@LR5!No`(M7NmN=$8cJ_9itSU}JA7?yN&{@Z=Rg&N2sZN_qT&|V1b<_p7| zJH#Kk<2aBwp{64a`=GTex@IcfZg50UjG(;4+=S>;b8Zd{J_>QAoX;bkNJmS>dK>u{ zE&EIHmHi0IW4}Njr=wlB+P2${jUYo{8=Sl6T|FA++V}!H%%!$N;Jo#<=?SG7&7E#A zv}h5=UDjAp2e4FB4HoQVQdS5pE7WQ%QJX@miIEYAcMhlpOGBec`ko8V(4hwIIvtGN zZKkmicQfn2rzp9RjxSPC5t8_#9Gx*w^>1qr4We9aBmbiq%U(|g`(kiA6c-R9xQYla z{3!t=-E<#5_PI5|hy$UBSA^(6E9l+M8r=*_W_Cz3+odT}BxR->0o*`(k!<2Eb8K+ss%5M(3RcmAitK~+;4Uo!?G<=L6EL0e)(oiNVD36vS z!Z(=gr)Y4Ou?-%1fEu_px=Z}M5~kZzdoSz;R^c&RnUMXSin;`eF>!o^+MsBF978}T zG0@0@2@*sD!uD%oPUE@=VQUm8^U%F98I#k=Tr#aHiF7;>OX+G}OKW;G-yY&stO&6l zOQc|68f5u&G_J|25z}IMIZ1?lJ)TPF@wky9N=G^g?TU%&5z~kcujR6eq9?N1Fs};R zaVM3H<<*o--VcpZiTaT?Vo@WPROMVsGu&)g_$pS~H?Qa8Ml>DI#dBn?`9w6D%gQM| ztLRZELQUt}7bT%K&t46!$t%8ZPyeVqP zO_8B*cP^!CSv`>?w@^{?IgR|4Op+;*dN!3vMh!I~=aaE4x$9)7 z;?N0JQ}uWvm(HnrPEKTVayF}_$axUjl1{2n{z0%Qj&FqGs+(G_5p%c=o|oTS=BGNA zp|yPD$an~gZeTh<&VXW69%_ye&*0T+T}VJbCKV9;f|9GdEH{IvcX7x@x&3=y7IT%nECOo>Xi3XAZg=QWCKqZgu^GEerBqa!-qZ7S%XMym;XhOYMA za06`9+S$3$+P3tXbW2N=BPPxiiNc?XBmYC zA+H5hjnK*xCX;OA<5o%MfvFX;!tWX|NU73lSF*?ve zS=#HX1W z&K#W`G+u-ihUyj?HDJk9T}S(Z$40=TVUabX6@z`W64C!NQYwJynjzJ5zVKGxR6dOiL8>y5t@}t#f`L*Qd2QiO~lkhHf0c&Ysfi+ zFkeFDV@52lLZ7~9LJ!SVWe-=iu~P+C6^e_7piX-Gq_$kUG@sSVv`cTbPHDC_h6N~> z%#&qs*E1pM;|OzQPW@#qVHXQoJznRaU#RwnPT|2}D^)o-E`fEPR(283SKjgnL> z)S;pq(J<`3AFGl*FPi{=lj}yEF`}ExBc#J!n~zQ!jedmUXxIjVYeF84euM&P=q7-Q zN`PmTd^D9O)InAfWMo`PDmgtaN8{n%#oAZt2}4b4Idar0bT(A7DglvAknfCGPEIDV zzGX~FXygr9Lc((@`6HpHbXk$Jxoj%byTUftiy34B30R7pCR?1$X*$8nXey;7RcK@u z=3T6PUOY_%qG&EkC>>djtYzaw9wP!$PEY3JQ8gWlsd`=}i--}SH5X4BaZOL=qH%J( zs*+6_Vcr$CL0(h`TB;c({3?XF%37#*@fLWwe2#DfBKks$S}mE# zsY+TS7gkP0bF!kRm6%4L>oIa}1Q*kWoF?=;MKC0r0>L`eyTabD1mOuPbS5OULnZH2 z$ayJ%M7om7rqiL`#aR=%L`o`Yq~c^vgd`|LwMZ-E*piBoPHS0UchQ`ZjO&Ij=LqT0 zhys#~=kw8cKAFyjJFl?Kh}Qr;}CiQe85szonxi}$vL^+EkR3nj(rLtO-XfMe)Su1&E4tnRN zV`*K{-8e6f5P(;S#0z@$M6!Tnpz~5`mnM=wBkb=fQzSWrJK2*{f}5Im`W#{)y0|74 zV}w9ieZ9X$5JK%SMpbz^ly;YM?HT)XH`p?1MzK&~apO9amzW7nV<0-MOoX2>B1l-& zTobICqvo1r)t?AVVgK>RmN2NYz`$(}2$Tud?LJP?Fb7*1Tvj#}H5;ISkExVwja?Y! zL*)128m~TSgXAANLro5*mQQP&K|{z|9V;>kwR2Xq+|yFb^wZm-vM}6N0~;^_}YOPNW6*-ZAwYa`V(q)0|GbN3k(@h%s7Hg?{L~!+Kt5uQa1;S4P-_8!HWZq zlog&xLLRyXwFY?0KC^2_85Y!XlkVSl+C%@;UO(U&`*j^MuKx?9sjc6udNlwoFVNs1MVvTm|5728jOL|A$|Y_qD@h3?|}}j!?yk{i)@@R zOkf4GpEdc>%+~K)JPj=CkTcZ5(t}uG0jq5?&y*iCVewVauDkhyZk`t_R7lX7K*i#E zv^1o)!XiOEQ~RvlKe!5g?y7{m7Yl)cyUrXO%&;CxGzqiO>$vf^q!*v;g7E|2kW9cwPY)dy%zGAmPQE))PXBYOtO zMX4DBoh+uy42$F`7LFTpu15I$KHv!!tv>}JJGAZfDokRhKYkQs0{8Xoc(V$i{&lzfZI>2FS9q(jWDHA&3 zVamMr9ZyT@J)~#a!r6!7aO{xCviUpg9c(*ny(#UzkqXPzG15eG zUK1hqP@iC(A$AFjVChsgfNmF>mB3^`#G`Tpk~b&Qg6=#slGa{^f7*!=Z8&T4B?zG) z7a!=ChKK^)>tIl0m`a*7jbm7|5o*^Ps>U$pK7m;XYHa%vSJsu44R+wDhHGP;99i}) zy#$@o^fJqkgkty<-7q~9D~9sTv>|DZMSlQJ7D^4oAIJ#A{1~iVNs)wO9ZR4guPYcU zm|@5S$7@rwFqg@+J2UNqTh)gOQ0I%#m##UzbLK5LG&8&B(0Pj%x)>9c%P9rn^Nr*+ zo$7Ely2AYFyzp+#YJ!bxb=UTEG^)0$72DovNjURejZJx#VBV)(tJ!M>i%Un?vik5H z>{NSbyes9H)YjoV{>c)TTTOI8@@6yNQBc@5n=w^E9i`830VC3?Rn4aN*rKVJ<;$d&jFvz(c5?l5k!l&U zzpTB5lw?BxX0ZBtj@Tyxj26_k%K7ESO4=|KdZ-SfpvU?ru{x`?J$r%o2&d?$+2K)i zaq1$pOsut>kQw04*id76o4x2Yl%G=D%?Kp#uL}HHYh>Fztqy7Qg^yth3X^!6AcHLy z3l+8V5Esx8^m4_ZmSeDxYgJb!AcMvb4(KfkWmw0^S;mMG$WG5_W*`N}6B#;GY*Q4q z!>0mJyEjUbn@mPooRaEiQ9aszfJ8ox@Y-aih*l|>rOUEoR>N6a%UH^62)DMw!ayMG zUqV$&yG?*yL0f1&gI8fz6gwbRFvlv@W=0$Vd1XEOYzW3CII@iB(t=jAEg&H;T4H-< zKtkI-)AdmHFF^hwa%+0vlRJgJZ>br%!HyUDn!)?uWXJoGA+MvR9PG=R-mhSlQvP7Vrs8hai(Mo z@kBROohmR6{#G0lM6to!t$Gm=s_Gjx{stm(&_aTA@4&~@DIJplwWnzb2-iu3@M+S* z7qnl;ic-x~$s(-xG!vh(Dwh{^7Wfog>ZB-kF2q-+|M1r?7xQqtnN%i{AGbnvi@W5rJDibkFLmc4}0%s0#dowC7UZAp%#b`jtMyrZo})I7vdVobGM zt49cn=j@XzV;UG}i$$Pth-BCj5X$#6jPP7mTb)zRrfFLb!rO+?B;|9?bbB*|K(~$3 ziXNpAv50mU1T#Pnr&3u$69}_KjF`EW4R`~;1orq$=7-Mkiq2-+y{-9e(Cm9Wos z6s97Pn>)9sQ z*n_8o+syYWTNsRhcZ6_lw0U;fW{7-NtBXWb&c_fO^YOWt<|D1J5(WUAV?+nO3ipuQ zQ-5jI`M5w%t@98%^U0Xf?27gv&n5_B8G&cY%+gpWxoyxM#BrOXr8d>FB2vc~bTvrP z>)^>a8_f(Apxo|grdWpmj~tS5(-LH_FOj)rwko_e^}i zUd|v<84y&YboJQc3Q~!P?S@$}3*Dh+TrQlA8%*24Fg3V#Q8-;tsNC9+F0&w4xe67_ z2imO~?DhiyM@qR-GsP~j>(P#G%J2FQIVee+F821^ovE(=S3 z=E131Bh*&MG-1}Q&WrH5YPnJq5@a?Pma7!ofac2(xoP4s08SaLHUaa?JN__Tj4k@Fp)#h(X2B1^wfS(zbDZ2HtwbJ3{ z1av40`(w2Z^0753}_=yCA zMir~+A&(hsZ^>FiM91L*dY0fsrp{I3s%iCs$bTpl1Tq&vCD!_PrtFbzXciTK8-s{H zl)p;0ARHnAmRHo6d);zIc|9SHI6N9hS2HbCUZoJ@H>6@2nya~if#`vyiNL`HR(xAi zovL-EI>mk>uv=r~+F%2eD3D|cR?et03TAfO#%Nq=4ta90JZw}2i^{Ur72MBVhkgu# zN{wSmvrvSx%`^bqa}rQFN~`kXp{O8G_fQ!*o}?Fv;GXj#qB>i67W;D%=_6>4f+2&zC zJke`sKnqpSA*lnAchV(Fa~Xm=2$SiSw2^Yb3{vJUd>#ewf`|S|BwOU>FpreYn~Ky+ zICTiVv!>0RI^q*Uk>7GW1nn%F7R_}qi`6?FqG(Y;KI`L3?2`)0dqdWz^n<{00r_65fy}F(6)aLuVvL&#D-5G!qfc~Aw7J&6u|lV z(Y5woUqql7YtK8klR@Dyd$|P1Xs0)`^|8uoj8#`-te+>d=|I!9SrvOUn*u-=r@*oS zAI@ZgT$^5q;O7+XY|uMEA0>Zc46mPe(+_o#L)ryuld;kyV#i$CMYat1gk}^#bQyDm zkc4hqkQ^#rZaEAs)ifQpsq0fe6K@Q?PSP7!e;}S(g zbK{G^x)?T;7GET+%5gN8n>t*A3y%#DmEYj+b8%zeyY}DYQtZ4CzwjJJeJK|s1`HcI z$WWi>T-zK(scfhPkDIW?BgDr#nkj<3)?}}p`;0@@I?{PJ*L<(&%Jxv9%c(d*iZ(`c zl9xiu`I18pg~o&;Pyh&{!-z_5S9+o7K%wTYvf|tya;|GtDX`Rfv6}2_*KuJ;fJ`DD z5Fm(%2LwnT;sGdfi0*~>@n(XCc$A-X5k|7GfdP@C$$eWLIf9(>Y*evqg`G{y2Jm7U0WY^E)Ak}E*J5P`E6#xpRWVzw0sIY6&JTT}ahse5QbaI{h#8nra=v0+3%B$7dZ z1Mh?d^JGaM9``MS1NIqeETS1V_S;F6yCov4L^~Q!M9>DcY8GlrnUW6MJ}Vm#4u#yo zpc~x8J^@6N>|(|dsK&QVcweX553ZX>2r#1*r7M`l#-$3r_6yJM~CY$ ze0j0`_=FIGhdT`AWK=LC=aNrIMjm3@#5hSNlA&#>eV1k1W%24b99EIi7m$SrVmNGv z?D%3%&-ZBu4p_5j=1-V`x`{1}j0Q0<9|BQUibFL7I)GPZplbcoTW;TU4A4Zk$xwJ4 z!j7q>ofQx_FRNKVh9?yG7+eiK!=`1KTluWW{;|KtZ(Hr+U7)BvnFuL$K1qAA5mrUS zY*i?N!!xkRJ|WF)ThP03(So_myMy=$0b{ge2K5kjjx~gYid)PfjoVC$XX$#Fn9a@J zojh5HwmL1Bz5P6Zfw5qH7MjDdEYQw~2_cYX%<4vzi)JNNVO|BZjNvfO<|T znGaH<#3FWcq9#l5@o)`Wu=BimGcpT$55N*kA{8HaJgcA&$%t(;Wm+8;Pz7aHrY?4N zvOgwaJyE|nd_br{S!$!T{hYX>*G2S7-Z?ZP6ih`Fh= zMKyV!m$0E5-!wTnA(;2y{So{5{kuL&{HWO_b;6R}tvP&w(F)!sIa;lW(elzx40BA+ zXJTF{e7w~G*R(i34T>8=5FSegk{uaYgvOO1(aVbC1gSS$s0(lFfH?__P~x&S>kbFi zAIiBLOY6c%I!*p2l%XMWk0$i;Tq_9YldS|Nd)deuxNYm+cwGhzJqNb>uC&lC<`8Q| z&<4;iE)XyU`zt7!xJD@`d!-yCA+TlHq7I&pLat5J9zV86$KY<8=#0jJcR{q3_A9Tay^^7doFrd3zt7YhHS?G2* zkPOZz+`z=IInID8rU~e5U-B-=!$-`$;8lusxT-i@dO6bk7&h)LE~tUIlJLes{mOL zt*?kT1EvbG$+e+EzRqIx3#@FL9jDxGPZTvxlEn%^V79AyLRS186w5^@LV}8**pAR} zII|>UmPPSlQRL8W{=_U&+0o^ZfD?Ywkfu&Tur-3P zgkDt2&<+_A*jAL=y`m6@#{>W<^N2MKsrW)eM+!^#w+`Ug~dTkpv;R@ha8~AQyZzGLHz+H1ITCyFjLGx(x z+$FkTK(X69*m9w;JRx}kdoKr#)Sg+;03Hta-P#HvVvHf1oQ!NL&rK6>GCxqJhy)j~ zi`w3SQo0$LFZ<#j8ufz+SDz1jnZEbL@N>5<~MUgqp>WLWGaIq zy@q0gR8a;%g_2Q(>p~<0H`bVQj`T80qtHY%Z^ur@|GmiHvaXb30E zb8%(4kZ=5wTbk^Snbm2P-n1#VTyPQSC{U{fwyIKWh!ixYA$W8;PiF|SG6o6RGhx*Z zKpw@hk7?OPjoV5rwGMP=P)7@;Jmme4QPL0Y2Rz-Hr$Mn7SHR+JMxa7l8lzaq8nhTY zGk$QZ&F;2&0QlWKyHw|?iP&_9PYP_$yr2Nc+*Wx~o4)7b1AC`uqM3vH z7S77_P0!4j-80jtQMU-HDf99s<~}bFs2T9_c~eUZvrRz_nnHAZ%Sw!AS)Om3Q3n>K z+$f<@9=RdoYIeQaVFF`S?cgT4p@B@zv~`CC4R45-D47pyV_Z5Xy5d~D9G-A{v>e>6NJEcWh7mM8KQIQ`Yl!26P5T8#I6DgzL9n3HaY2sv% zFF79Sc@OI*mH|dNWR|s*g(OG{zCkVngv9edJ4o%bp8KX6&AKrUCNWYcnc# z-a^)xP+9*O5uloD59k%lV>Kr9CxGDf*EJFHPI>$dI3;=DFJ+U~?8O}ydo@iSVm8Jeg^Uj~h+Z6ZPqqkyRS9MyeaPc0V3 znnLS~O`$cdrqH5a!kh~Du;6aQrsjFb^f8ue6!vMgrKb}% z*Sa=Y^4fzKC|0kwFg$GJ3e;##i}H^KyD=@{2{1wReReI_li1AXp|np8JWQ;2X^EZE z7$x_tA)}*7lM7l2>q3fjR^O$KW`Hi)W57l;=4}({nsPHG)Av5+cNZ1!qy80rq_HJL4V6f1MO}qA3K3tTLm;`8s@Gw_h z5HK1bWGflW${&yVhqDHOi$v_M7V5P|dr7vy`ukFCqC{Q*um*!?N3M$bYSvxHT=6h# z=L=#Nty2K63xWm_VV%-}70oTj_ij{Z`}7}#S8uGvHznvGzc+>SvN#!k zvl^Wk6v*-m$y4BJ5rOGixranZqW-4%U!;WAAK3nxz%X%3|zHOit@S!(-D4yS=l~CIm(kuny7Y?iw_DBSMh1 za$wF(EF!Wo&`c&u3xdTWyto535J)4uqHKqhD}$?80?$x~gZvH~bq&k4i@>=|?aa=F z1eisr(x3sBhbe>s)C>sQ@6|@m*P6&-Qn*#?F z!MWiEO8~J-?4x_rl_0)Wn>q?@YYU8s&ilOC63}^H0v)@_*}B(yTWVOiWG4Ahh}@jY zRBzgU6kSI|u7m=Dv=K;AoH&j?JR%zmF=#|HBlE#r>Sah%Alf2=m2Wkc7M~jw&kPgp zY0m>{C!n#>TBANxt`?wrG;al{qlS_zcq&sfP$sqF?S0AkLBK0=1KH+fng5X!ps?l3 zdJmb8iHU^lWoGxzow;xptD462gQ9^nm-h%pG-Nba1kQ8!`II{yZ<;o5dhe{B{#luW z=Pj7dD5!AZkO0LO4NWv?9ZD3ds5U}LBKAlQuzdOY*No+D#%LX_iI6)xvW#$4@0R$O zF|5Jxe(zw%Dg`bsN1iB2_I zx;S5!_YnePC;w&=bltDDCu_*nerF9!-Nay8!_T=f+Cfa6y-PruGqOWrRFXG5oR_7(iP!d3v$9 z69EdMW6>*Zg^9>Ms?H7qPPv#vOD)UK$E->) zeE_8+LJ|sKv>h=JIuSfp(!GY2RZ9*>k5M9^bb~hqw7UQCKI%e$IIa2yCOVXuXvsr6 zWv0yqARnr{jCR*%ao1&6nE*aRYF)>e5!*r4%M`s@B5cu7Ij%-KoC&S8vIF5knQ7Q# zqoqqMyMWn=rY}6qlVSLQ_HiD9%+okvL*UBsrsN&=`ydQt;3yukqc~+{)}EEjh;jb7 z2o#IB2iv@fqx2&B7V{Tul2Fp(JLe~c@vYD8fzdhsJS?T4|**zfR(L zzTdPlAjLT0CR5C{pOUq?!nE07f(>1OruEF8J-ugPPo{rX&-`9D-4=(xtYMSPLUUWX zsZjvC#!NDi1bR&hDo**>QIIrnYYOj4!h4~x?xC!v#~j*^(YGJG?YuyW$u){bCnju_ zQLCvM1{hngIu#TfbsGx2YPH?tY#YBZL!-vUlc2qxn)6vXb`HJqAd{2_Wizaav6F{S~yoAK4U3~-=nGz1A3=je(c+w}%ac_` z!_$mb)VY(H?|6h!jkPakhfaG%VrzpsYcWM%Gnu!v5yPvY(%Q7+GVg6nYo`i(SDE3m z_KwC@QzzQnI0wCQ%$7T7WW+bGRnrd`i*0R)J?)UaHr~wizL~xKto7Cq5mRcml~F(3 z)Lyes6&kVH1lh4R8!oRN59M46nlwPo=mWeNtgWV$8wk6nGnPBADs-?8MbOx!>4h@0 zL``vKnK34D`;~?s-!US2dAiTq*bu#-!*Cr65Y}A7y0*@_*tT2PLYXQL&W&zw_iJ}d z=T5j(rUEfiGvyw1%XD{}VP5T~_sVkv&A}0qArL9k(9jQy&M~;ut|q-6d|U+9XlCs3 z?;LDz1l&gMi)S(|w(#u`t;lr5Ve8%+pd*BM+WO8~&A-r{C@_4F0EjZ&>$&q5;3nMMjCl)sXI&l;HIrochs`2M2X)Xbm}RMbP~+|n%)4F& zVFB*W(hMBsEk?0OKooS=5tX)BLqCmYjJwBpa9MC$FGD|fy!dH9SG@RXKR3LM7_`<| zQFy|BsAKA?RQNE{Wdl?NT3Bmx0EvY&wgi}|y*|i5)gAW!6*gB8k1Mupd z@&Qp=ylgi0H9}Qb@2i^;S=lFhfp1AhXJwKdI*MnAtk5Y_N+3O;~^uK7Musc7$XT#Vsw_RQgQ)i`600giZj^1*r9fA~cyCFSW>A z7^WS>tWo6#Cw56V_ZO=wT026>E44j)qy~_mb0Y=9ORuy9oW^2-7LAk;rfoH(!C$>?f(2w8iJWB%x4#SRZB|2L zZ_OF&n617G)pEV8my39xUD<4=vNt))Z zg5)&3P~$k^E(4WfxwNdyG_+Q010HHmSD0nCGw{eYDok%PMiFDY+OrM6*z_~?vaMzP ztlot^)Ep(;R94Ccs@XyALL1{rV40=wZx`H1+@0UM zU{2<+)xYSekN-uttvt*%cWo3d+74k&U2)fWBdW1G#=UWq?4f&vzkrS##8^;iXE4y$ zRLC}fV^h0#RT?g1C=0p{ol+?%tX}PnAQi0}fe`Hh=!e&no#V<-1+z3ucYG!0JBwM(_&^TvoTD=ASa#rtba+d-x zk`2a6_we8=2;Km?`O$8oWY8J3)!GSW$gpYdhi8e-)+F80mIeC%f!pmpoECVw>qu=3 z-2rbcUHKj%);mv(JC{5vHBI_v5~rE1$HuWpI4nmdYK^c44nlMY;fSo~D%iH&pUAel z+t$^Q*TB`0KfOAxm(jRsY%Hk7ffP9m9O4pZ4plN7ZjSc71DN;%9i zgyf(O?1JPQp}{Kt@EBv90TG)A8{$@32NEHJst{1Jg3iGCMtX{vRc)Cwyjt{dg-GGq z0-8@X9r85zRBEgiKq+Uo+N876%f-fUs}_X?kb5(2R?lq66X^}mI`ADj1RRTYeIfhR zqg|9MblJ4rhrKxt?6y$Pa~mMXcqK7Y;mC4L%{tX=fq4~%z48*Dx{0N@>S;Z5S6AKm zAE2p@wTB_6p3Q<~yP&L9tHPKN!NyEW8U(ePm|$t8ozg-4OE(UBI-7T~PKwl!fK>=s z1fa_bu%KbjSB6d@E#0m|*?khObGdiAAP)HIQFdGq4W`i`=Fx){&P+jewP+5Af73@cg1R3}@yva*{_^Zt;6}b5=+dP#20pq4)3&M~g&z`};T~O9485$Md#8Do6 zkBRVB>^JpQbV`dcXp4DGnWfzHWQcejVPAvb*DM#uO66e)S+xh0YtU8>5)}yv8X=GQ zo79?6qCXljCF23}y49oR`(-Rog*19)*uPAB`&!DU`yMU^Q5awZQDq{r6o z!kmVMw9~MGt*XHriV1h<)e6`G>cj>UufUe(kf|2W>0h&>2hCY0w^{c=vW>6|jGb#Wn#}f6dV}FeeY^xf z$>3%Wiei}I!=iXO7Ion6iVwh!X@E4=7;%4aHb)k}Z$%;zN@VpmbofQ6H^>i=Cs}EH zk$?URY{t?=i)Z?C&I5Zy0;k>KDL@6D zbVcP}v>9NgqAfDW)B;efwPFBk+K3mW55jk2bSHg3O(+c&Mo!me((9sD7-kvDg|Rvk7s%d3J27^8?Q67&a&$lv7apyOO@wCO9fEyau~7cGVOq91+DpgYfZ`mW5W>Hfk?HCRG%RLjo0T@RUl~J zT~);mXaGkJuw(=qY7N-(oq1{^>nJaDk^)IB< z$Tg0Mu-G742+X$xiut9fP?#f+k7eYa{F*&Lvtz(pc_55JAzM=4DnqXkb=W;&s)b{&*Ew ztCd*<1=eYKqZ(!Yw2p|E<+7}66eT(d!QiE3XlgAFR;z+>zivMQzZJKVJtyK&YdEim z*8-9Dwki+VgcDi=rmX@@7sjBf44}`4^P1E`cy1Fun-qNp9w#X6?$nIlVJ`MC_4m%?#G!uvVj`O5oOj z{h-9cFGq=@h9ENqT9qA(!HOW6C`I*=l3`$#NpR}1^hTbS2geYh!79S6bZQJLl*pTE zsDQ%kpt1{f%ux8PZ2n9sEt;TYSOSxqB&U|MzO33xxG}EqA7hqyau8E zT2-8)KD%e;f*uHEnBF^g9`maa(on^D)9B2}R&mr^0p)TrC_;#cOwThhH5yWmwcl(a z1DL~eEFVHpD3~ApFyp_X>G=+@XR!~PAX@fM<5-`vHSh4V7ADbD#D z(&@YS4E!?QhixLouqDg--XEr;&_~H2yhXGb5fovw&AZ({b=$K%dK>LucS!6%!iy=| zYjTZQ=Rlb)$h_ffc5=HAoNY<4Qyq3lfu-*78fEZ;)UDig5pr~x`%B-zs$@)sN|bn@ z{nHlU-}K?CPo>v#iE=~y4>nP=Q4&OElSbG~vceLQvonRZ(RMjw5gd-i)fhN$Y?l9jO0%s!*B;lW-fb_EWuYE z!>6!&wrolR9qvW@j-H*F-NUN>b+9D|JUexE-`wfu!$>3po{pMN`WG%UZ#&xZ>GKYx z4Kx=An>FSy=$$ri&iuaFy_p$3xpS>OU{#nwJqj@zoC|V{=(u2-2Ji^o4Flg$$g|n>qKda0eErSBp z*h@J=GD?OOMI~wM%|6YTmuFb}nhc(jsM{Mu45(*FTUINI+F{#Ff$&1DUu+0e!f57W zn8yP3t&MQkbnT?xGgzG20tss~7d=O4Cb3`yoE5eP#sZ*OgC*?k;;EYC@fw?#~Q*(S%FM~O6^@xST$0s7W^g0qf`!VW^%@@td$#8opnVO#0u~f5ezMW3Y=XP_9pX> zj6PJTK%_x;jl9|m0-Wa=TzX~@(p9+LJxS4OH!|eAay8N4R&LX@p)ufr(WxXiPr`u+g%4>GQ+yFenBPd{O z-W~P@NC{<)thxiVP(WToO2z$88V_zGM^&!Y^#%<;8C@Fp*z0LAPBX38TyND=ZNN@4 z$aFyokL)Y0^fApY&jj_T<4=t$c6FLC$qpFkr6(($kMX}0h##Xv1Oq*3a%5kxbVW5tqxIFVaj|$?9lulX)sU}6(#5nmSgrBf};4aM3%QlMj9u>ZnA2_bvbO?u_ zGq#95^zQ-=Gzvwtr)J3*tuw4J_edCZ3w995HE|>$)xgCa0mC}j$sW8UQy`LPjZlvI z(gOM7piH4dsuUaO*7NxCu;_Ax3qp3lRyje|zlr*)SsI)sn3!O9XoO;+X6-lIXVk*O zGo(m4A0bHS(@)S=CW*!W2-25oJVc=eGzfeWqC>{vT{`s{QI~@qHL2am@Z@Q+iLe;E zZpP7yV;O$AGq&<3v{HS|S@A?P8Q>@#_L?ajEFrdoWn}twCx|$Slf8~qcQ;#H#_>qT z+9>h1pr-}vN7h)KNZa(YV>C<-8(BgxUU2n@;JES427_RV01bIGl839o2L-K07E8?2 zsJt=m$h3%dfvdqB1@TNm5o)vRrPUsu+YHO4GPz(w1sx}0HVgB+wXEe>AMc^dV+%Ft z^Md{Qxc<{?iuJUaskkhtJusX|AP!*)?(ED&_LoTg6);!$ zh~f}oGTgj^0V_Fs0u{v%5iFNN$Jtw0Ru(aP0b09Z_3UKf9Fws+Eo)_pxr8E04Ikbl z(9vhoMm1R(?mBI8%NlKf$Qc%W%8feW4>*?VM#=1ri5Me96*FnkJQt9ZjRLRc$vB6H zbGxg`vlUuaRTod{K!X^O^|?$S-0l9}*}c=CVIA~$gUKw3c6JguCqqe?WjkoMX6g1p zvza&rMYask)U4Y{ftm!cX;WSTF_ImN0AyrYcoWRV26jHxT*{lsin8(+pVWn4sJWUK zTX{t^(i)B4nrOXBJQ2wj>Qe9GIh;1}&?~aUVc@9{T|Edo7gYHNi9*yno`FM=$TVWm zfMH-qESH9tu{X1sFpSXfVHq5=BNVgI8roqo9wOZsqtKkToX^(`_zAgDLr{uAw2=eU z{s=Z)lkA~dxk96SgX{>4Wnde@CM%jM+Z#&JH8|!X+1fa6t)t31-B@~Tw9BUNHnQWO zQ!6od18dbR4KM?CXJ;o^p9duI#TsC`8Gj7Z8flwgD^>`Ro|hco-A?r1n>r- zd?VcW<(Yc9GGGPCp@sq-#F&$iY&_pja{l_VPU&EbN)gIkC*?g z2Ief9JwWz%#NePXS)P@Q#xOx2_QsAMnS>dDPiIRJf-W}90rYVVISbYo4MXtYG7@Ty zr4u{tmK3_b&>K?oT0igrN+ua9@mWlk24>8gJv}q0r*AHxCi^F+(*xY6A(T4{G~U*% zGmSQyVmV8$6jNx)O{^7YNImPZ0S+42Nq-Ds6-eNM)AR#uw@8G>`d9?9%&{BLqpBg6 z^G!Z*Xro9^gW#&=97ItL%Os%sXyo(IrZ&v6I1AO8iPX%>2c)OO>(nqy74S(S zVd*RMdSGvDpgo`r@L{+kxw4MsYbe8m{Sh#HiBjxbnHs2YO{SDV!)x&Yh_SVd!G7K5 z;KS|U$Ptme^ZGSMHij{=2QLQXm(U1fL3Zd`4{Br)iS}Oe5zg9%J@S>{WEl`l*9MzY zt!|m8Y;}Ll#2Qp#Id+PJAxbO?n_!=5AnG8qfo@+GMF%auM3dz;lYxogS-hGbr%hr& zVtk+#e{5OAM4*s4k~P&?;{*nnHIHX}8~rod$e3N@8`gwziZn?kYuI*#S7PPYot8lx z)IxW4oo1J}P19@y+F*ikpEJ6tjn>)?F7=3@fo#fIOT^jgk4r1u8Dwq_Xc8b*h~QCO z9iTEb*b&l8MF)1FSy_StQ>8`FZ2BZry0*2whg0q1A|!9eJ{d|{`8J0&L)oGF0oL25 zMLf$zK_whE23i6&)dYET4;4y)aEiUuW0uQUSV@Pyb9n}(#tcSTp}>Yx!HlY)DLIuj zgj2Wta4tZY!fV|WI0PYpY3AE#z8798ttM>k#SWw7n!omaQO=bzy zMI!F`-RBPS2S&#Ls)^t^T9087Uwodu23oS~ep7br9-VYjJZYkXqGren4B3mVVvcSD z*`2^pByNgqrj=U{c2H#&ddf1pGBX@Y19OS+G9aX7oJtQ?%Z-ZgRehyGox1g;9`I&! zj!T4Mx+1*x9F8BVnBLq}6#69#0s+XY`kfjlJzJa^4?Z?MMh^W|1S{JhXULm9QELzg zLRf{@3>z19p=INjgEpOk$1_ClV$DWOos2@KjZc_b=7nO#!nuH1G5O9PXe@{kh3EzE z5G)4dc|Ir_2)sp^8Xg)h89do8t)8tUup9-v*kgL=aLrKMXin5LUYf?dgv(0h6-=0P z*8;q5KI_of;MFelt~aVs zA(_VOp=CgPbQJ427|2)gds#m;4~m*^iV}2@JIynqRt+kKYt#z{-M)Pbue3Q7AZf6n z0ZoN4Eog*>w~ri$*SKllIku}AIIj#lFDX|oS6C5k_`cR|isSfiKVZ}t%>CBXEkL=e z`5N3JO2H?w%j{b|#Z^aBibTNBP_RfOVl(V04a~tv96w;7YEmOv74q^+SQopDeWmgR z5Iry-L?Z(85L%Ypu5tdc(biNHn+*CLHK&4wDY6*{#E#r<3(&GeaTmYKPSY56WeSL2 zoS>QCc1Ws1DVgIzO2%wY1!NzwdG}BinVO5nmbMilWDMCUxEIuhLu3o_eBtA`2h31p ze%ArMA)g{g=C)x)PI?K&XcJQ=7W^k*qoe$gAfPGUVc(nfcH2M0hN+6<*rwAu4}}sM zyofZOFN`81bb82;yIR6?4RkFbE2RwI0MVW^d?HU$&dNi{Z1#Xsp;9r>3oL@Rcup77 zZtS89t#&#lm5E$b8M7dAONhYg1|M-0$cR>rQfbUf_2Bn>CT2<5(b0rqh)OKugR0}f zoZo|*J=BvtsOdfrlBvlyG$b$RfWbl(WX~(MI9@XI4us)5AfJgl*B14ivh19)-`dFQ zVvZ@tVaon9AkV9|DZ>hI&ar?wC!BK@1xC|3D~<=Vev2coi#z6=fH^Bcb51zttm2&G z0dr0|=Pb&GpmTO2Th?!J+TsrBrf4tfzo^hN!JRR z-&fg%{BoSGz#skL*R=CJ?A%g8iH?M2$948#I*f|r(sdol7WB(@CUpp^$oLoS`Iwo>>V(>1A_r`kPcoi&yT-@EL$j||c!oU_R-+fs z9|v0@>~?w)H4|(J1aVG{o$cB%9C0vcLgA^l>N6oVa6&GkL1mFZYM&6@H!)ZBUbn=@ z{~Y(A;h*qKW!JJG&-tkl11) z@$xg`;ux^LicbH@4b-OdP!vsO8wcsy@PYrbN?2ty;P zMx(}a*RonoxRLDCFc2Mc6!b<>t9IB*kUN^c3L~HxC{{2EHXM?J8dc2gVDq6-!)CZf zC$0nSw|<^+oduC|-wO?X=kX?mp!)L6JB&Bo=_MAw%b-<6w31|u>SSwS)#zNb<1~vI z1lNz>8*Rl8oUf%#Q{sX&ZH6GiwdNtckRCV&`T5br3T3B2S;X)Gi3@7WBFJYDIU?yR;0a-62?Wn!fTt7QQR90>=MGUq5CG=~oDatr_#gv|IpAR_jp1Pp zI{qx+L14DZy~AQWXLwhxWEwSX5bg4`$`^|x8szzQw);FmNVFizP0}C|k5x0Pv5Y3T zK9H1YM!VJQwJJrRc+epD_xKuVOS4iPk^>?U2$zALwNUO^${QQdX7RRvE3?WmQ zhMe$yECC4W`)dlS=lK4brmvu}B8`;qb6IpoWP)6@_#D(7E;a=xM`6m%7ADIGtl3jB z3d{D|rbE(<6lVOIRofrV^M`3-mhW>}{v3B``#y=G(@DRd74(o}0GH?)KmL|8@>-)< zm--e@vvN?7Utk&Pp|Kjq_#?e#ITe0bTr3abvy10+o2e#1J|pES#A6{tqj-)n#6$!w z06U1RDCFux;%h;p;X2GhrPW4>g}FhtV?H#2vIMp#7zNl_j)Gnj?yce{) zPy~bJoWB`Fj`2`_VJOTyThTixn`p=Hd_xcx+T*_{?*twWi{M#XIqHG8GAjIFf!s-U zo=8ImZ+0{QkU&r2;&VlBZy$gpG@3UjI%o4}a89mx2--sp%b`!Efi9FtvfyezV928( zDvwb~AcK56adU&BD=5bhtwcD8%L9x#>*%Q$K3OAJiY432-pk7-PBtCs?fgakvodpf z=VTVi308ijy_+WQLL7lDM2-b~G7*wXT|)S{bqGGtEkBQK6s;%REfE5S)u)OLvs1Vw z-HA$T+FeO& z8!$|8HOq*TrF2^IG+dA>HvVOR{4tuKhOyi{IkW+^hFcr~D6%$30P~ocIl?rQRN5KB z`NrKeInb0ew|8bYR81~wy1`zAj2+1Lj4G?X=-2m)A7U!_5G`9;6)G9PWTjz^$Dr}7 z4g3eDTMNq&+u-r=H>>&urnZ>5jO2X<8Wuw<2nWS8Id|4F_tASi-hE9|ZZd7&-2R1` zMJX3MK@Q7O2|W3V!8@I9!bdQ16w1JWT*I0c)me=SRQU-QTKwHlE?|&cIl|Dt8Z{PL z5KD8CSfzt8t)QU;*q3y z5!VW8hCT%PFh>z?tVXIG7GcIohls9CxEvR1yOA@yq*qoZAQZDE;98bq?NTfI2Wyas zM!LX*Wf{26!mMTsBgtNHfwhhPq)DM}{^UR#D(;OJHDtW|CTa+;z8g`3u|p2Vj=oZa zN*U&>@FlJ!II(e*fBx5xQFQxP?-*nBhTF)vb*6cwq4edGroawM6Dh$BKFHWOt~qQ{ zBSoQS3OS!#3i!}7L=s@vTy+1_5T81Q(PWg9v@6X=dC?^HU%Ty1#23J!V2Q}?=;dhE z3d;!w@3jQ;Pm7p5+cE<>Y@nNVgTE9vAjcZc+)App~=q*|-mzMFyqQOPa{NXt&d*aS_v2*BZ)C)xfeN?S6oPp%_ zS_kw$%d9BW47fEpUyKQa3we#hv{>j-;3}ngAhnKMxj|&tjO{Bw_Bx5ao$rmL{7#o<_svaqGoJ+1=14}M{;lhFvx56TGlF@Y9?a|L%K$$M zbUjN7M-V280SNFXZc9+c6xguFDrlC#Ygn!p1`DNbKHV-XE8A6qc~-@!!l1w-kQk?# zrP`e!2(gC(iLjj!#O@$qWI?nL!f4l6*Gh_PL2GD59H37QgHp;ji*4}#=VKyC) z7q*Gfzy=Hb(3-s|jzxD2KfTVe%<(yP;M3AYp#vOQ46ES-3^+R=n&8(iTi&w<7Q>Zt z1{9gj(x_KTLA=GGU7%=a9Ba!%tGf(Q^{OyxeK33XvGm{RxBHirTPMX3^JQ?Vz0n&LUpa_j!%LR<1 zcgL>nn%{QVk&+T|#|XM4+v6eh;kBYAyv;$) zHDmaE1PVBOf|YRi1Ruw^q!S45cI$(-TS_!7azE{NmFQYwuPTss?^QLw?XXjSdi0JF zbf;~Phc;cotUp>glDu(EV6!>>3@z7fqYC89;JJT7sZ^Do<$sAvRoBe9(m8x2R4UZ7 zw&!i=W?dAr>=ptBnRP4+LDm7$e2;X@_egWTM_TheGW2}SIr|t-I8CLe(P8Zec}aVinZsvX%*Pzq z0vl+N3E9R77!i{Iy(e~LsCX&Qi`F=gf=@U;1)nv~{F*)$e9_0t)p{Y~4N1 zvb2*F7uD9trQl{ofdps&rNeE3G*8tz+AOePANsMqD8e`xgJmECXvn zAzjPYw{^1`HE@hq16{M6J%qCOU!gMN^!fHwxFf&JorPGh#c}}`HH=qok_gJcL5E=Q zD`5v;TSGNouB6L^+sxjAk%5xBxLa;2xFS- zUnr^*;!+%O!hS&PqitpKX^6Y^8w9Lk^@#$juHy%9@f@>_Ne7JysE+X92@I>X;*_Df zJ?$Un2h7%+1Y4{*%5`y8DJ~6VO$RH<%c$7arQ{WW-nOvg4W0JmM|0bTCjnG zJIe~8vA`dy3t}%mmeM`K+b)uwYO+UgsTOi1c2(}c^Psp6EhEZ}!N8bj+H(ur^_Vr= z>_v_;Y}zPh)Y^uPx)vCN1~oqnTG0-=1@o?uB}uDPh@usAe1TQWY_D*g4N>4&9WF#_ zpJo_A0D01|{YKlmCerd=RY*eYn_lznoWp>*TZcm3KWy_26}<|Bjk3F~x&7mRb3p>k z8O6HB_9zikb5Tu;Dzc{KQ)*1tvaz_D*Rt7YG@;}Z@u;H4l6pdmrgid-9!v&0|XT`rXlH%Dj+u9xWsro#?^E@m(w7G{7x)F>^>6pd2o5p+E`jxI)3Qt@ai z6;slBES)wqHJ;Q`x+dph(R?Z$PZ~*8Pv+xFI;AR_98adRYThv7@oX%eQqqe5OKtsj zY{*2b<6Cu56FEH^VEOaE3l6=KLC*kCmkrkS8)!RJ$?%SGPSqUHM57cWl*7`60*rPkphfu$O zH~T{|EGT_*`xo}ioz|P_UEDL9cKaL;L^ ztxop>9~h20dL|6ps)C`}F}mb-=sT&C8noxZ+c>+Yf1zt9P1iJgw}r1Ix{YS>I`-}V z;_iBAqq8Y0{mMxL-E^-dTF10jzcX~wyujED8&I%!`9P(&lYwPUP;=73#o=1Hb=Ky9Le zjqbPeO^lzKz!U4O&6!D#JC!D+%^KTzyLUd38L1LKU2CC%XZ<}{JRJ@fu6R`?Hm(=Q z{OVL4{RHm@dmapq>@4|C`S8k**Y%p$Op~1>jdr1vzdMnArP50YMs4~-NIeu@dY#mZ zGxZ2{RTEk*8bok^MwX z&5Q-7au45%DwUSnVSnz!7wR>M=e`Y}jf#B$!m$paIbD&7)53V7@pxeI9~IX+r|t~J z5D(cw?77E%_O7z?rtUg#al7`=zvrz3nNe3+9Xc;I_I+V)@;9n&zwql_c-o!h@8QWM z{Ekr;iKShAnaO-H8OdLVIW=1*`Dz*!qCADzJG3bh7%<1AKJv#-i=a9J`o<4NR!*YX zOz2*c+J2-OBO_6&^|3dmnWHz6tv`m+(uSzpQT_J%!xIm+P%kihm(6xaoC4#0Ib5eX zBTnN5ZZq3g+`ZX#Dyn^HRpP3*A#kJC zbFyv#ZoLmN8q?i%)J+#orpq{O8hFSE_Dzf*6<-Kr6?tGCw6h5fx1u7A^p5Hf=enjO zQq?r!D_z6484-zeK`hAat>$hF?zjrQ8qsO6;}7}qx(edSxVmzNvQ}}*S5=-ZI5&n` zCjWE6-87L<8q5&9!=5bT!DaCPM~b{lLSU2X zH(UTVsB@rtD2Ee$8_;w>7uD3aD|}`*#{$7098miGk>jAHWweQubSNZAahQtqg|K#q z59B#cWjmi|^%Cl^3Ga)4-%;sQ{TFYT>C)7!Q5P@28;Gi%f+M z4l>!N7@ti0UECCLoo@Xn=N^Jb!4e~vwP7hfoq9iP#JYdvx3O0YHr8NpI7lco&OA|C zps+9t0!f#huW~|SFlTT4r1I+*>`I1!LX~zY5(3_R;1sG}uLU7GL@)0x z!{MO7->gcr@c_KQ&(ozM#P6zo=u(&#DN)f>3DG;b%bbo{2T*=&I;_pOQQ9zR<0hnF z%C=*;?dc@5%#;bR3SzdG5YkGM4&w&$t7oB4kh-JC@86{u6Fm>Sc+iufX4u)^Tq;GH zg4#`^F|FOA=l*no42$Jt>gU;okeF}@TmNa-B(_ZliZ~A(t0Mf{=*^j^!ZM=EbZx8; zbS$U04jHVtdZ0CB6^Klazal|&(bGs`E`udZiV8IJgVH_@CTj_!ed-P)=y|vG%PVfl zmvTxwfXZt9A$FmbZejLdyYOtqqdLyDUv3*OGWsAeICNghCPEDLlVfc=-J+i407v9~ z&MbXC$k(x%vwZ4!h{yIz{}j(ff_$kT)A|vlj3AO9ecyg4Urv!rTLdEB-&!m|XI{iaxy5;{H=JN`DMN-Rq!QWR9YT*vEp@8#TpGqj5d^@~?C*Ip>$rooGN(u}+&gy$8x^xk zTNULZVl5sbcmCw&hqlhhDQWjP4Tji%7vrSh3uyHl%NK9Gl8b0@6+*`*B-2Kxww5ld&9~wgNQa&F)U>Wj=r+UDk|e z5x=wFH5*CSyR6k4wJ;obx6K(r;CRE)4ti1yxSD}zU{+erm?ER(wd~K6bsXJS4H!BL zK`kS05+g2jtcZ>@nC-@rVe2?RTRy zDS03XY`g0roHjT^5^31)1WFk{gfA;_@g<>&#uYJ^R{l^99tK4fR>SS$`1UQ#@2jy+ zM$U+uU0&vF@Y;bop)zu<=9xROeM5yPjlXh9xbPj?2-}sogfrl-eL#=T!0~Pk#6jm> zr+-mGL$vON&x;dBLo7D=-X)eq-n`?RK?k zuRPN=h&&Mk?KNNHCYoa1Cg`wIjOOZ~X&1ZY_u$){4?0apX-Fj4$Ea44h^-bRf)>r! z7F2fUB6LZSO0Q(uzr+0{zXCOxWyRCR$sD@VKz+whPd-46&HGMZBM0G;pp`MFMbRmo zZMm^$eKOm;frquCs(g_arjcuRX+MdN?E=aWzLtfHv0zzo>g}hi=7?P_&|0tZ{@KOJ zmO7~VHOWTnhZ6{QNve;D45W6Z4MelQSF}>%*X3W6k`^u2sn1D2F|us<46 z952>2msWRFQVyBeDe0vt7k}o0VF;*Tbg3L`Oqn^zY|R03RWTgT{7Y?p?N%B>NAfe; zWn>g-6YYE!@UCLG4mkSu^oFFZ(}z5%P~9ZbNQp2W?QH6%l!h7ZPo9kTIqbfRja(Ap?QQ)wrRWpx^lU4z8XMl)}hqECyX z2`xV@&sB@gMrGgO7LzZY_ZA?G8XYy|%ZWW{H;;!YIIgrFNOV?CF!9ohJ4l2BH-C9k z+ueV)8kQOZWqh?}^ghih)lp~W zk=_sBwiS-WnHL8+L;MD#aA$UYP1>-rSdB#zvm5W1mO5#iw7M~dtC7ilfttT$Kmn(3 zac@deeBZG7R`tlwEV1~ticN8{1nh5|Z`#l9S61t{U%FGDYii_Ena-c`J? z!Q==S&|z1-_M_~anFAc$o?QP%pu9z;!#b{e(jRsj^{X=-yL{=oYeMEb3!Xg-O8#I*Ko>XkxMyPp-Q@{P^ z?DCINBt4x_*{98{xL4&{6X^T&6~r=Kd5E_np)Ls%hBaM`bsK_>el5gN{GO*zRMnZ6 z%a7)F$(cEZzCSP{DmB-AFn=_bwHMwQrF&W7JBrOhm9ACg5Wfx56^npOZNqH#aoxWV z--y_Y26aR}PdXX}{cVGTbiJ%v(gn(J%!A+B+XJ^vFfKlkVGpcZ)R@Dh>O?jYYM#Ps zCn3fxu;^aR`laabjl);i#CSMADC%?8esxn=#t!a7+$tZ(%7j0&FUyZ4=6!@`3>?!L1$Hn*;gCbo@95*vaz=8)S(20N?q?>PLXN8S z|FBoD%Z*2G)o1@S`{3@#u?^M{cc1+kCehe_4@F5Igb}9=Q6BBaJljMhh>up1t4Y$b zkzD%C{5Nec)W>NgHjK+(67ToHcku|B07);lq91zIKOr`|{*I!sE&MLR`&AV+gWJpe zn7fWgx`%=vcIHjY1!W1hJ)aQti!Mn^V&r~ANYFDGZInpOd25tybTLVj1V$&dTa{ep zZfe4~ZOEAt8?+g0)+$NPbqUWNNT6CJY{|FsMH~9dqb40HPcFq;B?ibFE%{XFI;*m8 z2Cra<0P1Sow32lkVK&UKqmSPq&&#xVJ7QmxIm zQ|#X<5LY<|^S=gs6FHU1D--G{ z{_g8G>6Tr+Kzss{EA3QgR(svX*wMok5pKE7XX#%in^B3q7RY95ztMTk#$tFEYE!uU zyz~wFUIKXvS01&EB9x45NNT0tw2GXI_Wa4;qRpAWtN4R>sc6K<>dy!^{`F}zp;dp+D+kurwf6J%}rtFy3@x#A?)2Rto4c znw=RrXnc&%e9%al1RmP0vz1pV{65N~aQwNF6vo!NQ4+i52{Kg9nF&9Wvr(fcjO$EkQ)IoX z*7EhxzIhD5j&H*0TEUm`xD$QTDo<1>nF}r7zt^OtJxnU6A6FV=PVUTHxcB6#ww6+3 zPyCs`ew>^Tji=3%Z+YE{xtIu7v(MRhy?GJi7{U&ds{|jxJULo=9!*7*k}zztBJU= zw_`Z*0GQdwkc9Dq^5y$lMywFP`-c>B98HeK=m>fxzA<-_LRm^oZJuX^kOC)W|Hhj( zMe)8fb-pk{moH`FaKE%%%tc9W%16XS#AgWK+~36l@*j!dDIaSMOhNluWZXWbTbmP{YFYeff|lGM>GuV-X`|SB(v-AV0-NiFesELUy!WDQ%9;od8M4T#s61VRn&X_t<_KO+r0QSg_I$`7*-=5P9q#|C7Uqn*h*NsP~RPQ)v2GVfa`(s0{o{#Iut*7 zuOFrj&8I-9iRE)f-qaa4VdX?_XEo#YN=s=Di&AmY;^Way+oJl}^vuMDO#Eqz+cH&w zDvH}7oz=p>^ z>OwAj^(K3g7tU!8EaXuKFCAg>J9$}eM_39frFA>#jrKfCnK&A84Cgz6;heQ1TweY> z23=TcAHI|XpYs6KemD|n4i2TuH6$EQT6)@CWySYru8ako8HFtcHlP}iPFsd8{y@DECY6E)sHJ^;+q!>c$HV;WUuF;=kPx@R6 zSLN};@c8VpgYe2?>RC&5sWLAH8XFdh-06z?lHr};x^S^Ll%BgkzeH^qD8iA9-6GJ1 z7ttxqN8sWSF`S7aqSM1E=OQfe3!s&8+g3wM4$#C?bqy)1C{#1ThgOnh8JmeKlKMRo zEK<8r=&wr|Zz{(s$3(Y@#dA%9q3KxUV(_j-mF3FX@u`#Rf!>)W2wwfohl$h2*=CuO@IAum{0| zw9Y)Klz}!sGow(Nf=e0qfU308qWW?%#rMIP>^C%h?yBqwQ`R)#l-2<_b`0U{@Q%-R zRN3+yjFS^75!oAag_+uhVnlrklr_S!vNPGXG*hU(z3nWZZVDypSdh>}>X2=Zhsqz?+Cqd_rz-3Su zd8bn6c}+?d?^+9_P8^TgW+I3AW=lfQIJ6ibZrPbw+M7zYw)zDoUW*d9C^*_HG~(sR z(v&2$i6?34jYE8um)Mo`fjb>NY-nqgzq1sf==;S{anMkfoIv$G5oOZMPmY4oJ`dIe zOS1jxzga#xc%1ZJgX2Uq@3zJ}$G;mwW&|3?$`o?+ut_aCSsk&R)Tb3qBv}}Q1Dn~rmUHX($8?qYL-O_xUWx)Ux{%P ziQcHfBUO(f@skmPij<6$T7~PbmkiRCD%D0PC63W?FlUg4c=8WKpLQGnT%Suts z1^=epDTB=aA;o>(gNXI2P?D*0pgSQb72*9e{u$^=6RIgaDhB58-!cGW za*XpNqCLq`h9%U9z(5#^;3d|w@EVJ;y!k`D&{EyM_p%fOORSr3-X+Shr&6;#7?L6? z(V?iiQ~Ud#$*_mV$TeT{&_|}8aW4Ho_O67FB)>P>Y@T?wj7!L zc{s(v1}F9sitwMgRPELrxifQZ^h$}aHDtoZ3&aIJ*;g&tO0PfUq+a_x62@Km2JU4$ zV9hg))p_C#OH_=7kv-?*{Yw&?h!z!opdTs$A#)hGxdOCx=69+U?eG# z>^1F6A|`E+dMOG|-&GbaK(~cT*tlOXyHKA@e@3P%yGw%KWvf03ifZY%X+|voZ@CX~{wTim1K5UZbyU z%A)Vjyh-yyD=h_DsYMN|6bui3(&Dxk2A`-=7MXGdZf+OdKs>Yp!&6Oa@MV6 z{4VpUSUAq+W{MO|eXlxK20D(!eoh{vRa5sMTqlClV2X_W}%RLXC7 z30=mU^+@=gz?XK^F(IO)jS3^oMZ=1;vuZwzxxd?FZW`H1CY?#5S1}$~nY(PvPu(4K zYsKgZ-Cw6v&JfY@9_z?Yd{gTv9J zuM5yXwwdEiwl`Af#%R*JvuCewP6hIrWx?*}qvc7i^?ui7jP{7eMXWd!bFl>!CZd?i zE^r0oR_)cmhI;vKS!5~F>hcv^dZbj-73M^i0vr?)QmZ|aGEvg)KyT@`G7?GP$&lei zuyPQKCObUAVUs3p4ks+PQnD=vfr<)^7TFoGgsbKxGdhLbzfxp4>Z(#_X$9nB8l0uV zXHU{{a$f|N`V-0=YuLH6b}8U-_;<=2+8Ud5h4>1*Y04eZ07@9##obV0O?;4*k`^nh z5XBowp7KJad~gM1!r5G1cB0&PJt53=(k1+k{Z3gZY3{|C^-m9p=LL1v;kF1M>JTki zN0;EwTb$9}43lG)sW@uTTX(UGh$6H-U}Ads*h_8hh*y?>qJ&qi9ihgCr;**!jA>OSF6^#@kTbRhuXaY9flq*q47T+8bsgLdnvl zf<{xdYUTrrBe~`B#oBswi)1OzPL-;Jp+(Qyy;R2nmx^%AKAPH_#MZJ@m_NQ!BwPA> z6WruBwXK6IF%ujOeUNqqKFYoRDeS zT9!5;iICt24uzyF@clxrQ>F|*_ziW^1bvSs&0PiShGsry%2b;v0dw)gyj8~Omm)ng z=-(h5a-QDTM(7wHuR>XSyl3b;=W4SKBh|)l-08w_)daaQ>cL}}CJDZU&?yL4MZ(#M z5mf=DhLY4N6!q0YBe_&Ig&n`{y>Cp!Dv%QVL>hiI9jxTMMEwLJF}Et}?=<&bY6inMK&3-Or~@50svicOvCF3I7lv6+93BH4Rh({| zn^}cu+D8aPguGO@95mZpb%k7}F6uN({+4VM@B#-JTi^I=1i31#7f`}W*#Ha#Fi-)Banl{kih9G_SWC#$IeZr74MOz*hB2 zdpBDhBgE($1(EX2i7Y@U->GFowbq`Y`_9MI9V| zv@0d-oEu>?N~?;MjzHf9*Om!EoNh5+{B2DXs=y}nT$Z)IibTjygK%ERDvqjGIF)A*U=-x8(so#gdawy6UB434sv-KyY6){?|ya!47TC#>g z{r>!7QNj;DPEzy(C$mH(GD+d{Q({S~$XyW3b<8!YZsV1Ly-r@=p^$xFee zGiRi}8vgqUAZ1Fox)9t>Xags%kJ4TQg#W&2w`3DzY`p5%&Q7-=Mf#`HCmpc2W+pDC znG_~S4bzx5VjiNuXMQBp%kI{&2Y$iVAEBJA;3}IWVqQk@#f{{ zg7vUwcTT{lDD-3ag9l~}BGZWbS~Ah9r{di98R-%WwYF z^@5h_jB4v95QKkuM&$$gEbPY8^zMaMfqyQ{to46;WBJm)%}U2l;|fe!*Jzr$v9;zw zt&x7iDfiul)&9qOgx0QaBNI;WYD&UUWuH}sb5Ai#*8a66gCA?pt3cxi8v13tak(C| zxq*ybqo!#XTjwRZ&@Al(bh)-_v~^KT-x0G|qq{GTmR6y3BUHnt_Y4ClUr5oVI)a~w zP;R?WsyIS$v_6n3g;D^|Q`IDnqi&$TkjJMnA`P98{iv|+z-2I)MN-yM;Oh^u2bot_ z{;>zObhHC+wq8QJ9s6Jjm9tso@ww%~$+%ztRtn{GRjx`udtw>CuW1-P?Ye7N#9<2l(>war_}o2&O%TqprNKT%_}Nq5_g_uBwq#C%az*{w z7{OdopH(dF?lbLaW{>KrFFKeg-jI-1(nPe1(E{oqLw8Om>M#qh@pe&jO*^j8ZInEX zRa*WA4xCD*SwOn${OR(ob<!r&;G?z8O&4fMM$;8Vn4O&jtH-qzApc`l*xH(P^yWX0$1P(|X;YG!M>`-EhHs=J2d&y62KzCfMdWQgL} za`*Qrp$70VaOCaZsojSNo%FHegrukOWxovPWGKj)^}5G z;UyCG`ot{yJ6shnEJ1oP|AX|3FSJP)AQ#lSBT=|T75_|XTcJxKGo&7xIHpr2obJg# zV`JBm9!5P`kYX!_j2OZ0#pO^U8;le&8{|#6Fh!8{ySJ#y-+G^$ue-Xjdr~+FZfq)$;ekGJwbEC3}}>b34J1>JYAt zaF#Z90!|Oja3h;=BNuQ___hsAG4QTWO*C>#C7x7&TB(o;wpNFr+Hs`go6P9YDYosQ z_)WKTu;+ibl;Kzoa!U^>?VJcTE3q6>-*kqQ^^&O_j-+$fAIt7eC6sg5kJ_g7bK!y! zP#l@nXDFiurwkKea&#IxMGBbiy)gV@&W{z78oJ~jy5)2+Igjjmvn+jd7G62P882N7 zPqlD_&u0Z-dVUA%$mlbMz>V9yoFj%_-r>!_j#Rx1aJtft(}r*GmDZYzE#_Gkq6>fb zyp;flXMbz*AhgJmtz;2PF-#WMAVnDBsIS-;!x?e{&;1#ZH?=T#mmMW(_;bsXS8)x0 z2AR#`#*``Y^zt26=coquvxXG@hI_%rl7mQTG|?ZqeX}p6{GwADT`pa zyzdoNae9S)>PlK(GqrtylKT7QSSHx*_f-$^N^pvjZ}DgJ z7`h~G-Sy4Kzqad>s}D>rXSz->n5dc$ajLvhZ>s!F!AbqTr&mi5S0BUehStls)0$mN zE!m_whA+WEgpAe4g*AIf#Z`6xc9I$dLb0_6$A}pJMq)i%{BkQ00@nWSBwmzdJx|p&5mANG?3h;;$eoY$;{z5~ z&su#oG^IlvG88equ0_G)COWp1Gu#=$F4c>^gerfB8q@X^>iY;>=FxE zZ^iU36lEbB`m#iD-d3~&GFs(69B0xjae_z1+P7)-kl^(EV8622y<+cA>F!li9sXH) z;y03a8Ol!aof!-Nne?u7Qd$9C+o;Yit&h!e@lckYD))d~j0$?>eqS~F>{-beNwqcU z;3lqn)u_3K8lsa%l50$z>ro3wM}>3vcxF)=dr8O!NVQ>{HmtRZ#$BhW)<%xKqslq_ zH1lAI{Y-m)vbq9)r@Q_(8pmj?| zkzM8!Q-aW;-nHVVCcLg84p_8YZaSH~s6gH6KDp~IcV2Ef$lTDN81S2%eJvjn?rHj8 zMY6HaCk%@*e^i5WGFahP6HyuPZFt3ncQUyBZ(U6XSsP25;jfv%M>PZ)l=)fnNA`bj z-6dKtUAXGD(&LjCHkHqQat(Nep($B&&YvS~{0-*mz4Q?1IEz#Mzp{NBuDZQ6-Tzl! zaA2=oPmcXuQr*EL`($YluKJC_Cka%=>VGrG(6iHP{Ev77Flft1@&TEqPx2i|e@FfG zLzdxNfOp}^x8e2j%``Vpxfr>{*G6l_rCPJF>im`r!xgBR1u^|R zqkWn-t8(UACv4-#ny=Zl>T*hPA0q?GyC*$Eey|>{+|Z9Ej&qZG4*t7U;XEB>gdPqT z(uwWjF{5Lc)tJC)pcveMUH_Z54|hq5G5IH?QC6jFF)I~7#CzC@ouJWYuc58g<@Mb1 z(`|xoaybCky=U&_WOBU6FW*I9wpOM80!tfK!$kjs;0phCF8v4#sl#C9=s$(tKPLLJ zU(|Pv9^uWF7Sq!J75s;t=}+mf9R}^~-nTcGZ71nzQzIIrXa2_(Qr)KD*yh-XeeAC? zp&Pa9)~L+fW!?X*@@q z_LSNctWwOV39ubh5%J{04sMiE;-siXkK{OsqSy@6!3p82%luL+lA>t$>M|^-3Ew|s zustP3=?8u~L90MzL663;Y5sk#o8iEG1?4&Mo5FzVy(UPPR_H4ly>UKPrv>^ ziPM~5N%%Vz;GZ9S1#DBBN3yZB*a*1zaC!HY!6ol}ssB$Z|9Gr()OMd4**1 z(#Ah%xhhF%Cx@nxo#Cx3sc@qFyDIU?_YLzLG>CyoMGa-&oGWc}^M^YNQ_WVlnj`6e z{blgIL8sgSB2c^iu%d~Re;(Msxm|5~{z@z%n7W1vtsVbv*Aa)>rHptd{hs!C z4TfiPYB{mv;H08=nm#O>@xUJC0R1G>u8SAhRI@UTg3>$D;X}yWWDm_RV=;Qo*1sJZ z&1(H)L}V5P^UFF&0mA5UBnW{f{sn4;POI(ZS?d$dl-B_;2QjxdU3~`S-|70rY zx-zwazdQ|Z5dVsQgW6r%uULCy#yQyZFdu@w_Z#T~TY2zR2T2ONys{_k*slwylem^&Lk*Gjm7Y<7%pqi3ta4*}P1b;m1y!wqJuy z?KDB743E*g7U|laZ=Ff0?!=;^@50F(b9mx@VsD8iwG?Z4PF8E!uYQN49)80k9Cu8J zxp<|@_~UKHf1+z8YA}WW5J9Q&HG9kzY2S0iflww9zM|qJNSVl~3)@l5eq(kcOc>7M zWr$WbP#|Bw0sP_9>%6BML{3;zP_ON13W-i8JGr3exvV*U@^c}fE7PB3YYwP9Nu9u@ zNVCAV5wFhqM^}tXXt*hG8&vb5FXag#egrWFv7~s3Vt`IFuh-gzUI&_HhYW=s_5+sz zBkI?-P=y0rHij`5D7(hWD$Bi7YCF`?N@gxdfD3vFFMC3KVZ@i|INJCsTf?do=al#$ zc`JdD{k>^ zb8)0+@bNjLv%Lw|KRo*G-F=J;7i(bJq|5#b&UU0aQ6M}bjftb|FOCEuM`Ny{ukUo~ za1;cEX5Mgz$Rt$Rl7NipV7wXDCIwmx8*#T_OCgAR>waulmn>+!&)x2P8EzZ2QHdgP zXZHNi7tZZPlU6qb;XJ2J?Pgg@399`zXHk9#XLTY{>v(-OHooz%&2A815{|@_^W|0P z3Y8&>NN6!@5rxkaMtrXFwJ9MZ=&Q4VMa%}oV@kiBah?)8OMh|HXa{)B2Xo8Sq}t?` zO$OxTPS2P{BMbcPzc!xvKg!#qoaUJ*0ohpH|K;1=8R}BCcM{mCd{Pi1>>8cTgS$OG z>+2lS)`$TK2RBSr^R!8cciC9d>oDw*_TR%A)$i?#lP_Uc&lu(G8FK(&5<&|iEYUyc zsCLWWd!AGh-zbMuG=E~oNbC<-6x4Y}`%;LBR2i}h1|L|fNxjIb8K6Xr4VsaOjH_D) zvD=ZCMI*+l&e4_kOZ2%+`h$ty-}b6?06r^IXm|?Aj7N$WFZX*n>Ycn@WF05PZ7}@r z2Vdbm_}`z12&%zP=d-V1|F=B(f6WHh3*}T>-hg)(#?|`)f;IEQ%eTQ2u)t|x-h_hh zX&AVBFW|Qh$8#@|I1=mB`}?d4k>GW`2~W$*_%$#G$lv4XWVOY40C+9&>+u@dHQ)ht zH8{jj^JZ7Q*}Y5<;H7Q3-Kl$g_*cNkIRIX=b*g22U*Bf49yjfl0Em;-d5(5%cOiCw zrt7Z`mwfL7K!frejp{eAt#gNuUU>LwfsfM1j^ea~^^be44hNt4eJYD)|MP`h9S42S z^|yKX_KQ2JYAv@*zYc3&au0JN*^`A zkGB$;9yR`pxFq>br-vg>8797-+4+`_{X+%DHjdd%k8Syo!^W=AmdyL7>L~N0Ew0@R zv`C$e*Fv`<1KqnFqRlp|9+7TllVSLhg__Na^!r$D%Q;@&oW<0q{xPT^30=T#!9eU1 z;C>FPI;K*C_pZz!t>adL;Q8+*ljrHshnIxItu32d^4ocjUgz4q2Kj}LXHxHF?#JCihX7zExGV1M z_Jv8|=}HF4O5)?{c$cTg;}{Fzw($DuF9=vKFD!uZdrDf%?KzNno~Lwp2Kj^EblhGY z&YRzM8khv!cL4@?f=^BGAO1sSFpB~n=Oq$*|Kb(^FShr~YD3@+o@1o6)U-TLAAlI| zU2;Q3Tv^i)XtDWzs=e-dC)7c}XUZ#V^I?;dNXCQcA&;Q>^${qLJ%jZ5MRWxtd z6kZ(7Y6!OIpH~=cxwQyR_}Ty=rh1Hmf|4I8*K7OV)Dj?QEihl0biG%VUKy40^qV$g z0pr~qW@%cB3zhsW-WQt-#Y}qbcfZ$U8hTKBoW^dd3|8)v3wzeuz%{YjG*v#MFaUp} zurR92r@U8rmWSv!pXqxd@IMHdT>d=^Iyn8fM3;>vI0S+HD?@r-Z@x-2&3-t+jo>IId&Rk!d?1=0s^SDp* zW2umQ$<%sITGccdwUN1>U0h1k%$`2|VG- z4iHRh%hmXrl2;?^UEO#-#Y&n4ZZ-Uf818J}g6_fgapQEWIrr$fI*W<*dc2qL@3!8T z=Y4ZN?pnfcImC)3EnfT~@s=pFjG4M3Q|} z>s=psP`cWJ=d&&&vR%dkg0O8{r8AsPSSe_|I%l|eLVOrpfiuVL&vg)id}@p9th_ONH|m?-W2jLyUF zeF@K%d^*Ep7Skned4KwvwFKXB@cb2VV?Em6l%vb0(1P&&y%{Kn-Ql$3mv!NOYS6NA z@6zGw;J(~Ftmm_4u;ziCxsb7WUe~5z*9^*zX^G_rNZbgLt-ZaKOg;#J)2s3%8CUq& z!4(>I+1?gOOcOb-(;eqsz>T6y_a!o{ZvT`08o7=de|fw}nv++Kq?&NSD)U-(gKo`=;SuQ%u@s%iw#5y~oHo6+w%%zWX|R zT57SBhy87#+!BA~ZSo;wmE5vR*!eu3z}r<|1J(Qf;Nhi~)1BMKe&1E!<-6Y~&mw~V zQxaZW)&{@p{81gJUc)U4Qcn9KnjlYw%c}+0d3y6Q$7N0Gb@9XL**)!I;rU@s>g6R5 zU^kbBB*=ez5Zj{Py42=y(J;9*wc>uE-b0XCfByl~RJ~2tVeD6=Qxxq?- z=O9=IciIrPf>tjK9@fDp_8U~2%YN(0FanR`1l^pkSql2?Ck{Y^y6b67d*3Zq2pP;N z-NWWf|JJwhO9Rg}!#&QHuJ%nqlLQ2dyG!OSaBr00>!wuN;g-N1)g`^I*QtKnnNyHO z=hMALO-9Gv{Ri6G!Ta`B3q6yA8>rzj4x7oIa7A(BA~8z8jB5JhYA5O9=w|Mxwdw%*SgDrUUTa$q%^N>GDx!d^^KD z6nI;&gSoi5RB;D9oj+c3onM(b=+-~&WjUn#zo)<`=(Gag{`o^BT>?&DWTTe%p|BPx-SV;opZ3@6 zH3d9w@rJvbW|tnNR5_lXhcY1%%jlL zeV%5}wHN-_{H#6=(bM|6d1^2C_Rr=K{PG%ed}v$y9s&e_r}Y|;md!T3rwLx(Sh5fa zlyE+C`O@@wx{PaF=&+rp3Fc7ewTU?$CD>sh3U>c_-@uq=^go~RAQITGe1O0N?=KF2 zxV=QxTr^xCjd~E;ciwC(?kB@ktIHT@x>?;MYIyfFgZ>H_WOOf1>#uEJ$oK<%4;SEl zJp5m8srcW1JKYIPe}FP8?AuR%|JL}pX+n^Q<=!sGtL8rmxiHc9Hhk#}EkC=GEciI{ zLSoElupTbU3F~s+^V;IF0q!m>HE&+0?jnBJngl(=_wZ0SbS{^5KHY5OJv;TMfBr6A zp9KA1X7nGsXPbIyfZ6PqOKn*tdOdsVJ+bFkDHLenwxddqeW;#nz_Co2J)W0koJ4t# z-$4qiI)PsM>8RT2`8tK+Vet9ZcJ;`0eat<6 zc)h_4+dJN;b^+R~f;w_XtJ?R=EtDnlURS`cqas=4_FT5kwm=_qTem&6@y)LLkfoY* zE7y&td7P~caQ4!a{^RhHntBe$ewv50zYkJ}Mt#$oP?1z@w7-&t@jXwZUOIR^yCrON&o=LqvDVlF%5ML>K*=Ch=PUsJQkG4}bhV#+ zf9{i*emP#F+G<=Ba=7rG7UPuVuY4JSa9EVrbyG0uZF}WwI_9Z($!&X~n*Pi|f11mi zs_WI$eqjcaT;C#~4<3!q@ac5E70Btpf4m9vnDVz84Bii$Qax}5aI&Az)^VI;Ju~^6 ztioei&1nE?UB@@_^uReV;O5~6AG_vqzttoMKY-}_gTa(;{pDLqn%!d!R&#g9Y0#s> zs#Dq){?*m~klb|cRn8=moW9>ojZBss9@YEd!y4w)=K&$P-gK4oVf9jQ{<8bi%g=cKN zdM0qlsOvnxy8m!UT0d}M^ndrD^1IC#-_o%#-=g%3%UNT;JAdy^?t1;5Rv&ZXMP+;a zj9`*BDYxE`<$f8bq3?IM(roN+OM*{5JkzsB%xLBo~JDj~PDN$M5alV1h z7dWApx*o$?YJ84Y=2$QN-}eU~OsFPtIzTBd0QZ4clQq3E-G|=68hX9DYhEUUn|sh3 z1>j`uHtp5^wW((+y3-FJ)%83vPQ(k6>2Rg@aqJtcd3zZS;pKRp*vjp8pGCpS_Vc&y z`YmYiob@rVvXZBlI#T27bu`2KK>O|##qZtyX{0B~+G;gj5!?FcL(<57_#3ep_6T^Z zHhJChd>&`=GrC9s@PO+&5L*v+`T(&Cgmqh3?eaWVALE!!Iq$d4Nj07CTUZRQ7fAk{ zTS%LF?jQ&aKeF4M?l}L;WCy+5zNL?Ox-P$7{y3Y%nj`RQA&kLt!)EB^eZ|)MY81?V zi5)=xt^`O~`N(=NnD>0IHf_h*=(>3gcslS%+XR1LU23R*Ts0FdSX{WQb`9I!f}k$n zwxEG&-91YpJx`O7hmUWde55JQ$KHqe>7Mto27jOHjt;3Y2=ENg<{Eh24)C}{Mzm`4 z`uJk7RZ}~qp@6;eQX%;CFgfku`lJG*d)==lA;9Z)=@z%)c~VUD(Rp5@aPGBC#tD#U zyLqU1{OAk%BnsPvVy*7j4auTA1UQb_2`-xfi4M0G1a*OqV1gc|cN5mivAzJAL82A3Lnqv^iUo zce_u3$n7xI-QoZEt5@*-JW2=e;i>~0pHI9x-@t$ z;7#UY9@n2c?g_V!(?1p{A9HlyXZNQ49xtyu@?N&9PSa$$Ew29-ZTR!u7j@H>Z2oM& zMghLRUv6c_uUbCn*CAk?we{~X*=A-pe{P1omP$C^Z5r%Yk=|aPrv1FqfN>w854|o( zn=ese=4XC;yITUR?d7k_O90n_nf{6c`P52_qRzp+BIFL zeF6zfCQ~$z3PHZBxN*S$0Lm2@12MsMVfT! z2m;c3F9D>t&^v_QL#PQPBzgJ$zwdp|*>m@vyK{HXnc3Ny*}3<5Iv|JIyhx4HsvNN& zA#MhAZRmoAQE~u0A+}Tb)0VQH^~4b+-7AE zT@tr_`iwI2M{hX9;(&)}V)HfYt!k3B?R{8|1iCGF+msJ@jvnLn)MKdIJ!ssw_XX9T z?~?@8CSoQ?HFA70U~JIA%j!spm*o6uq%n)h+WN_2)ax2-e1SgjZMg`!TMRw$ z{9tkBPO2c^72oPR$NiONsPEXidC*qa+#GhG5_=iI{8IHn4-!S*=K?e6`@nrZob2G%y{x>BIl2M7tn zX8Rp74BpS8C7{PH-o2N;q!f7_Z*EcRDohZE^kG+*kR$D68KLE_C273e=HEe3{p$Pt z`GwpQMv!TYC?(>ChYxJpeuZ~z+HqdFt7h930?wKtF>63+bNeiK0?{kBpi6XnE^_Mv zT4f%zo<6Y@u!ScR2#px#!iL9!QXev=jo3=d!pH zeaPqB(zDWDoot3|q-%bAS0K*<46ecK1@lRT>{~#d=jJLcmz@#=rJ5!k}cJ6N!Ofxw|#*m$6|7nNh|$M7Z+EIO)hSBl}_8ydRDeUe(+5o z@S6Md{J7b!&?5n&7vL6fnq#{Iyer=x;2P*Z^!CBrq0bAkXTY$Pj*Q#+_;bjtMuyBW z3bG8%OV^-o-^a)}xn%|3+3+lPtZs`L)tuKN)*GQ_V9*sJ5ZlpT&6_3Vj;5nL^#S8? z`=S^0LG%8TGUmxHIYE0YT+kG*!8gIE{&cDB1^cOpJx0)aMm2hGi8OY=H{@z@ODPv{ z>>61q30veg58$uVxCsF7o1unpv6=oTi#R&77H9%puz#T^2W-QFG|zF0eV+y*TJ1NB z7pXyqIt@la&X$rPF~s*($U)g)%O}%`&GcQDxhTftGo}P=?;P6##Q~^qsbb!Di~nne zpj>p|byXo#&JCs@5KE65y_Tf+nuzGf170qSC!w%tcuBLA-_Gb^FXjEHFKKJHmc=58 zJ?e#=xMv66rSU8i0gm%-PIXZg&9_Y8o6i&9jl0~p1Ztx>-n1PRKfKk49tXpyBms?6 z^9Y#R*x03c%dV>@_GY>d0pV)?zfyj=3?7nxqVRY3WJAkMdI?xRa zcej-f;}`~E?`r;6NH?A=n%yyno3PfowpTkeu5te!P8X=n)MKqQbgE2mq1Uj^jhv%I zzDkqZqkBB}g$&(RbZ;0O;CT$i>U3Pi<(ax4!Cd_?t4l|}_d&qANYK51+$;bSb3abO z;C{EAr6};)e&7OA&1Gdh1ZdYAXqtW%aRS^dXN{jJ)?Bzco6Y> z3Itjg-;I%Ux~sR^rkh>eZg!oDIHr-goWrglHdXKLwrxT#$1{BQ#e&W~rHt`H+?1HMI<-R=26 zZV-J|drsMJ4||~~^V>mJ#^tSPbnaWLlW7*0;2X3jMG-6;_(DuKK?<8?j`{~;TD`A? z`%XQ7dY&hyyPO6H*tPC>LU+y9R7ndplv0TQ^pMYC6co^3lD?|r8k9G9Vcr_sa)ffu6W^M;Vn}zrhdQ`EC1pfU zeLKO;k_p%u>reEJs5+6lYPn|5*-FH&<}oZ|16CRbp@EAwYwbZU3(nYpW0$OTvGaji z{1RsrN-1yYph``sbUd9kZxQ+H60v?#oaZWZk+;JD9&B3on~2B)h#+d$rgM@bo(rjW zZgmD1clq3wR-4}pnYJH_<;<^OP65e#Ar{HLpXki5=Wbi^efKmL%O^`obDIXowatuR zzwlxAYXDj3r2iE0bUk7%VB7gLn>CfMbFanvqHJ5e4gC}9(+P}0rMcW0eR1n7U62Ny zHHcA?P>rlDFm!I^?wj9@{;8*ux;u+Fg!(RezJpHhs~<`^t*HSU5CEXR4{D-51v zMB1xwVqw+mbFY^77Zx~pg4;by zRGQoGm>SXQZP0AQ6R}R&+X9oo+sHsZ8Tb)t8lSk^^d=ue2XA@_6#jqL+3>>C+n@ht;ZYtBdoHmOumsD|yh`dg>@{0>&3_7f76jAAPIdm~- z3-H+qKVnZ7O-SepnwHM+2N~|iOLo1*j-gKtf`;ivNo1h$2uO$@LL1XL8agPAIBPWy zg7=OvBD!wE0ALjIlp^Ye3~a!12MkHB`jeG+P$7}ZMoe! zRc<8YJ-|#wvKZ$G1UWCnnM>FtgpOA6Bij?!_P(a#AVOSoXh4#GxNn0RDm{AXGU9+; z%51gZ1u^9OVq6y3G~}N%A5*prA}S`t2XSuxRx`&C<93c#az!LmA~-SdYpc^WxPI8~ z^@MuvrRvHx(tnzabZi9h)^_z{X{eyb(;VpirEFhH@01t&L`7(bFibh z7wxt@$o)Px^CgRu>V4kUkY%-2bFk!bini!M!1nr@5}!0egRZOP^l~{n5`p%FAj@+* z%Dt}2gv|W+n&*_@ew=mAry1>{Er)!a#%7&8wM_I_FoL%;8{j#gtt4r7DitA*NN6YtU2hquSgYiAkzf?4#) zN>@c}eSZ!p+he(G#9PJ;adQ8s65DQj;-!B#bj=tN_~mxpvl(;CYXt_d0)sJT`|F57 z?n@9?b>QY2uoJnqHgVJn<50>*PS_82`JYx~fv&ESAuIm9ipG16{U{r=xlR}bR@H0? zzFyeu+y5jdyj&G_KNrzg71*^ z6UdpFK``iWbtTt-Hv<`#Zho~GiD(YCx<`CTcfG}=fu;P1SlScJL~HB)_Vg!Ouw64? znUh%<(I@P2BUY5 zY>|4E^@rN1?Dl+ja2dIyE8y(Ibxo<5i5Ixam9ZhH_eZ)7+IUtCyXsp@@}Zx|uZ2(n!Ya=Ch_1 ztY^|xr{UoOo@tJh*Cj0b>_lx~mlO=#fX*xg7GDi9*kXK~kZb8DK_d~Mwfi=UpmI4| zOkRL^BCfDwOH$3l*h*i&l?$5YlbgHmR3>M~?U<`g3k??m_w!Mq``v;4o`Hxw$X57e zS=@;V>1qyoIt0RaB!Q^yy5~=>x?JA{2VMSwbcUQ`@YVz8rb%;K+)J>7>#eebUX`SG zv57;PtYlhS0?QxX&FWrkd@3%pOSMt7=1&sOWB$P1C;5INBSY%L$k+}#w?UZoe1ec| zJI7Bqrr>JbKBm3w+D?l?{|?m2q3k*l{wKf{dkn((T2^{aNTX12S73GUMDCX*gJ9bq zCRgf5KS+}bniO5iBi408$i+xcuX}trp0Yx{fKA| z`pSMfLN7I|%=mj1lLz8mDOF!pg@1X4Bls3j_9$%LG*cQGMk>?g4z@5nBfV{;!=vbI z+0vR^Pht9~uNr0SJ^~wvB<;#=haQmL=9c_JB1|YeG34^!!FS2N<}|3_j^il#Q`g|j z^OM`)G41`;sBCDnJ1mwJq|EW7s&4CLhO(htvad<&KQDesGz)S7s=S&QQzt}LTk@Pm zOx$|sd+CUTIu~&q5N$mO`o4>K|Xp6XigeA?&JwPDX1L>=4gNU1MzrvsOorCw)nMjqvZ!B7k&Bb&mT|(BK-S7YP_m zttK|J15TFr>-`~l#+vTq9iFiTZRpS$bw*?Em?zfyK?39G3xpXe*NJ+!yV0`iS8+rE zoP&Z67}EHU?-C@Om(3mU{9@+Bc`cCg#N0TGrj0k~zUC@6)a@afKBs8B#A*^Z>`(KS z5B}EY3s@qz4(X17!=;ymZ1tdyl(A^9)=ov$4>{9361RFOeuOZ+S?!C9aFKmeK}ns6 zoYp-FTabn`sw<;aY{|NL^`hDPt*0IGAx8-2U*?)fVH2=NG7gYqdOQC^!8IHZ@FJhi z?HedPXQ!9&ChePaapJs@)+sOwzJt zpuepZSLf$39m-c|aMHck4M7giKP2LuwUq zG5Zf4fU(2crMjZNn_P>z!5D1I6#b83I6Zn_hN?5juIFo) zf~p#a3bd_UXaQ&x_yKbru0`0vvA*UmzG7^ClyPEcd5PhMHV?T>{=Es2R%y9KV_Q|^&G54*o3~F@TxXk`j&j#@ntMK@jX64b%Jy4*cQACMu$6y58gdCvj2Gxj9{K!J1chiLKF% z>Jm9tR5kml*%Lz}NmehGe|LO1QSJMxRrBfdfMbs|o2K=PsW3)*8a;O30*371vmag_ zU%ItuRjZ3U1X@e>Gt>&7PYzL!)&BClOgC{Jr%MsG}5DW&u_t6o7JI0 zHBG<1TT+i(U2OUR{sCV($k)?dN${spygV_!E~)P5wF52zXD@@#+BS$=82x30!Ozn@ zp;2E;*HjD~;Zo5{urY)y6Vvxv6fP#vs?u`Yk=<8N7$Y5Wc+L@%wp&5>?t`gGC1B-l zAQS+7rM^0;@sxoarg<&jy(ebQtnKdZ4ZUOfrOKTh?ftPL+SdH*!!#MkR}M#~^Dmm5 z1Lo5_p|)>fw3waAwIY_fr%qP_aEqWufwArK?3fr%Z4D4KA+ z>HEg!kcPW`Y#1u{%;<7FLcrz8hhDL@UUFJxf4SA*UyLQ zb`#_*9eRT=!ksP+oZfsQ8RDcpgsgia695;4V$E6*t?ETm^|u;y<>Kz|%EdSTWV2uW z61u(1$|5LC(+d{OM}RlNlL>bB*G{#Tiv!?0Yx@aQ2^U$^(qA+p$yHXHI(&CW*W^hV z@i<~0&ETrxO{nr8o%DS+A_seCzZ6_8kC7}DIi0M{p>~9?AfGCc-#pb7EByJ_QAg!n z%0oZtN!1BRc{MlAc#V97#SSyvLCd~2ja%m?Mf~mj_(R3>JANvX6F^GY#Aja(d`1@G zKRu^!o%y$93FiNF-}72LIrOjLn6~+!Jc4;{VXe5#!yt}MGIKSr6j(tJWyausGL+uf zrcB7&IaTTAu#!_^LvPN1C!z~7fQ`~%OiNnq6x+V8&33aZ*{LY~l59Q&N2f*9uFxHl zta)~WY_1niq^-l&{5AUL>RioKfasti_@s*IGT>xg;67h}5Vvf0)hd;CT#dEpm0d7N z*5v2wblo`K4BgPOpV8ZTykB@+9B@$*D@HwSHWAJ`&>9J&(g0UhyhPhHmY|a%{{o(oq}I<{PTpR=#+|r zzAEdKp$**i6NSVT9N&wztIlt>JP$jBmC;_+)B&|-mzzVTc5*(1F`?=dcUG4I5~%P` z>rO+SRDRI$#k4CJN;U`BAK2SiKcNaEoc~-sKVoA$;}nUc$R=VFRGp~HF@a-NV!J#`LOe@>{?aISDRS&8-?&C)xHYRU`HxeAI_wM7!*8Km2c$k(HeoZ3uvl|> zZ}pTJXWjts1j8h_Ut}3pVdmMaA0*`;8o9=7e#*zfWpxGh zu6b;LiCTa3&!hHr}Cz1)ryP1>`i&5`=}Vd}MyZ{sAW ze2zV_kDWLm)@YhSN#pqenfsf4cG1Q5cdUhzU$x3)7wn#ullv1)ik-$?vnoeXa_N2z zrq&oFX5KD<_5GRs`K-+ImLNG>s7$wlFrs1~ao`D5%zez3Mtzn(tgGoFC+WwiDEavD zS9C($ph@e2P0yb$ajoqqq@4%M!yr2`dq{+yhJ&uKieYKiL{GjPF@c}8SN=zSN&4QW zA(X9VmVcS>OZGBs8Sc?ij(_VoXv$@zJg`e~V6n-|{lj!f8NR0ZF5aldD&s|>zJ*_P zubt8N%^HHvRs!wdR0V-JXZ?MTv0G_q%DA-F&uSFQdO7?kR?-Y+<&`hXi+dIWaw+DrjNcGxk;t4&rB9T| zr|9&=7$)MpA9f>w9`AR%_sL1!sO*}Ex}wvE_P^NI2{jr%bJnwCedet7;cb*C7wa`s z)ShOvcJN6x|LA$5MvSY-D*)q_L)Z^!qz$~~&urq0Qo=YQ5}yJA0XClkfZC_UXm*j| z&l~}>U%r`AH?Rwx^fHg8_wot@pNJOV3D%J93cjf!+!dr*{O*ylh`TFjt@+I(<4sDw z2|FGeXS)5j=P9GY^7tdxM){9->!>;9THkOXsYwN6@uh00Df~9_U+mVYYX0yrwBb}} zeM6X1U?PfB#F@_X{Zqwl;0*KIM$r$EZ+rF zMib@4M|Nv8<2}UbQwmMu@kg|H2Z?q$)2%{1QerIg>30R+irY=SXV?2<**VqDXspaB z|Lp}2q;&nFw8G@)6Pi!0q5GOTE<4^oM~2w~B3aD{X#_ordn5(@37GC#qCK29tX_t( z*#>-&EqJUa=h0gH^6kYNk69Z_O=GEFcHkHMT9t|^B8GoMhHQ_#Hl&`b{w?$bSky&J z02CB+a&3y$HAJ;bN@`{g?J1A0z7To`5Gdv3PH2{t@XsEW+8kYZmCtDZxmWM6deL|X z{FpnmC-M%EP|3-)y!Wk_0OS;^Yt-JCAO1TtQ>m_DeSb2zFDv97P<=<`bPDtXd{jV)yibY-}A%uMjRR+E0Z}2=ZCFIy)WK6s^?}HaZs5*@~lnS z8NsB2;FqOTU-!J%e?$vUvK)AP@OVmEyU|!34 zQAnKpb_BIqhu-9$-F|$MZ*zmpwf4`XCEbJ z!2HG5;=U#WxBV+3C;H4A`b?1|B09i3nEeNO(GpIrq>P_;CpVN&>eV(x)1Q6FqRd08 z(u9puKe50`xaD@0j(q%&6|Md-$ejFk*~^1}`ESq13zWT4K^l770oOghDMuqapRsRo zuVk)NMoO0T^O@1Rw8iNbF*NM)-?PxB;Rh6YhkmaXh;kHJ$W-gCAJVdfR^?PY zeEmyf^py^WiJxX+K3fl5;R#jh&aXeV%ldpoi^b)Ko>Bl2I)&**p116(t_U&~N#8f)RnNP=cMwmxC_%TG-luwzU+i zCwPHBIhCH`{C^sk(o?*^#Q$uS^hEchBh))LDIVb-XIvhA%!AS+0+FG?Lu6s} zD9%B868K9cB9D_2dQY0g1bTs?+B}bN0nO-pO-osPeelUnlpKlB?$iD5*n5*jF+CwQ zKa0{E5Bhw1!nbd~($@~T|MYnCWrNwH@718(NbS$CupzP-`bbWt$2gHcSt!LxwBnzV zko?c3m_CO3ZR~$8;T~_cHlF_HLN-$SE0kr3ERtS{YtWJ;{*@BF2Yn&E3iaCvdiNps zSdTZG8`K_sFO?{E4Mt=s{;wt{@}DNMYcL@DpEl?|QX3n#{oic{xduI+#IxLE;brI3 zkBYwyr9U5XPtuZ=Vow}jj$LaS-uQC`TnwB)D=u^LOnQ;@ZF*kR;0M#@wX)X7Okw4i z>ZsU4DkkxB^=;~srFQ#K<_2r#zZ6On%F}pJR*Y)g*1Tdjlu9x^J>1NhWUvFV9|d2( zN)bho+EnSIgZKlqPK{96#pB9GL2)1=CV(xh5gq^yo?qV2ZbX!lDQq4LM0$*zCh!!|3-(U1eq3TT}WOB$v3z*9SE{zt0%?vH8^kMJ}JF7S7mm zFJ8X>_u1&43VuO$l=vMp}v_t6@@gX@Q#Zoi!C!FQouE`9pnTlo#}M9L42C*|lq ziSw_22F$;i6w4nJE%UJ8*KYWGzy8Rcx=y4n2Nv%LSz(*y_Ou;t{Ao?2m zkbP}@?EG`msrnr5A!9L8o}^9b>nHxfLOdk<4Ei@~@Jtk^_$%6A?F%y!q)i>~dxW3@ zlgf1GEa^^S>;*pX|!skw{jcgVNtd)La6`LdlJp{epum> zrx@C)j7VfR9LQUP+Qjr_>T$G_>tc&_;CM{$$`sG-kCtkeH}ij+LCXi(uyH(j^! z@n=VjfMm5ed_BcV}fb1J*t5a}z#>NyYpzK|W zNt5)5s#{hVquQ+Z;{!=WsvKmgv3vdW4BhdI0L!&kU2NpYzB#1K^WQk^%H{a>k@BSO z;Tz9b2AC(ZD7ihyQyB|@QR+ar*Sequq0d@R7jSX1EhCI2xwRzLx z%;=s{tKTK+c7R*qn2tk;_t6_~^259`KH>KYn~X3@b_(g_GKQN>-}lrI`v_{=ZYA$W zNjrqB!|9_*=7b93{y0BbUu0EeGyjhD40K_(`XX5?R`dz=%8ft!haS06N(!zN_i&lR zQy!ns0Vau7nwB&IW;#w^TQ$gvjnXE$I1JPJm51+4Bs}5T39cw|l+Op{Pe!l>Mu-#k zFZXaFra;@WzqW%Rt?A=qX4R6r-}BpJsyL|+N7=ePbmJ8XBOJV}DkI&@C#;lKFrjsxF--%gJXRYM4PF3DIvi)zSuPiuMYIq`%Au zAL>78TE>Ro)bNfd91JOc{LKICS(L!~@NxSUls7n>a3-Nn~BH_DeU@Xi{jQa9}0 z5_FcW5l}zH1_m=FA#cmYCP6%Hz+(xtlj>h?>>|{Hizl;uiQ)z6 zlffr#1Mxgu0)3%*F}y0R2he9kE@Expo-NqjqBdBcmE!!|Sbve&5w)uz%(pdl!6M7O z7rXZ;;_sfvF!qfnXXEdq{olWn)j^)JC-}sw83rlp=3;;07`c%?xeQ-JpAAt%8gEkV zV!GXvFC$(!lA00Sz$o6)=T*;M3!%Y{xqe0&EmZ&S_J;|Dp<#*HvfeFlrC}G{>1SyW z1NZ&&NK!K)d!3D5E4KRp{h`j?LhKsarwd-#=8t!$A)2QWtF=&)o4rubjd|4l`m=C7 z`=a@QisQ#N{IZU}GMXzoKUQ8j2njlcvMMAgU1pmr_fTrrZa#g$s6$!NN48O6;g-HF zpskgXfKFg~^-%tgZiXa{K$NB2AA_Wg>;{#vRxOKYi#MZwV-AI~>@VL_hV@5$2%Y`* z)Z$m+qP^UszUOik8wsp>gT7?t0OL0=3G}5h%fj`fHhn&3e5RvclCH7r%yRjpAn@;v zjx4v)n%pjt@K=M&Rm00qtZMm=kC>~T_1(GXF!kZP{Rm-y2b`0Aqg)f~Ca?x}vUx%L zXq;~C71K-dkF7O$LMF0*%PQW>KR%NS4nHg+tq=O8_BvgV6JM^&l!@@c#}|so@aYc^ z(8k|sc}+R)5Q;_eW6^`3Sw+K-M);|T-vtr)v@knF9>&_Rl0AI%*~L|(xtW9Z7@p># zRb3+gc+=cgJTO+ClX~)r9HdTtf|l#Ikbq=!JwW&!V11HIbNhX%Y`)OwWct{clKH#0 zKjD1O6f{yjtT*RY0pXX^8D&Nq=FFM{*K#owa#hd1+>LayKl@r>Bh~!mBXbP<2k!XI zJ08kw#c1|!vg@0lcmuQ|=;y2ixRtnU;X<0pBhY9vXVw>_lNqA{vuh2HRzcKpeSHS= z-Q*P8!a8qgWw*c?eH%FSwBZ!;6xCrAxbD=;{5r%D)C7w?{gMQ|0F&&A)u)sv-ahcR zhhs9KGq|Ca>H^8{DG43wzDMc3fEjvokTdkYVIT07WKn142hEc|i*Bnhm2a>p4wj_W zs}m7v>=s}4+w*SBHS5Knn&Y>!T+{x1K&-9JGJwM;f~Fl-?2b1Pn|eHzVm6$j5y~~y zwaht0YkLvtu2PC496A})CC_V^)nd#HVtIv3H5RQLGFc>jXSAMlTgg)&Tm0jQAm&iY z+|lzg2>5-?vRYVM+q$2=?I!J(hr(;B;Co!x_XcY-X~!nJ5W*0{Q{hUs)p-TX?af2! z?X4mn6&sq}RldwNz4ARoj z!}^!%D%Y}VL46UO%s1?kjlbwN^i6f0>u)n1%4o+#uJ=A3H)}~G|L)91zUG0mJGfTV zE!>RF2W0hIR+Uu=uT<_0lm!@D6%{=kkhczN>?&Q}s{b|qxe8gF`7y7wv<+!&%oA4L zIpqRh3Z8#rtZn6;I%g>+GOJ_wnyYA@mb_97MeAh4)R^^^p+;oJA*;3PcUSR~sv=rP zZ);slLNFTp0Gp8a=^ts0?i(li+(G+0ko_3~^v1xoHp3}Z28GSr8q9eTvSO>oA#4`B zAICFi<-4Zeb=`NlEXM2Nf129(dSL=*WiRD!5}w`}xX@#NAK8km^SiX&=h;|g8Z#0U zEe3urf&zM*fEn(GETrh~lT^i2&M_b{>(c>cTq;W9VxZi#+Z|I5@{DjW&gx>JySz;PUY^7yqMN?e8KK5x&(jSL3-`+V#aem*t=sOi8@j&GG>eIPh$&?@#79 zxifCF#{v_#)cJXt+WO<(>-J)*U*maK83E=k{@dJ`ZW0f@fso%*`c0UvPy>evtL;G% zkY74xY<7zV-W0qrJs4lj6nQpWKS+xVrs?ySUJj*M>nRQP zJLG(g_&&?*XF74DpTr1wt0O%~TJmx-VG&sdCOh&iHIX_`2o6$MT$a;!4jpbFIUE1H zyniH2x^N!4;nVTvo~WO%HGrRrv=rd$3&O?yXa@;Q))j9)P*nkb_WO#4e_vHqL_HKSGo*n&C|;T^Fx*M>w6XR}O*$OW4N#EGNxA?P7qGlXdDtcD{&p(S zjB-Q1_2ME0WU5u*k*n3cl`rC6siMWTsLtjSBYGrshR_5UQOrn%WyQWOUY2R0fN@8&4-K|(0=z%6GR2C8D|dash%^2f zraNRWmVL=6)KBVf6^bF_DV2Ij@hUG~Y(r(r;3<6~oTYiNl(7A8Q~o^peFFGviXTb7 z4=k*bw*Mh{%YyliJ4X@t;~qE4cf11iF`{4n&XkUxa~S)V^(fRnBfoI-=H4t# z+mJANyH#iOl+DOwiQxQQmRrtzQ#*ZRK*@VjEb<630k|F?E)miH@yI9~UiP&s5tlhL zlF;V2dd#s)B5&1zf;1=IP;%t8fqL8I38eQMnQ+7WkcxNrCzUTwnm-l<{M;UJUg3yv z(L8N?DPsn*^J+(h&7VyKJIXjM>CA~0kN&kilPV;V0bUl5LMHDc;bo3byG~^nzGqea z+%SqH+P4Yb?3$JFh0R|A+i#$kkKXZY_SUqu)7eI3grlL8W-M=anh?!I|cV zhL4e((+Hn0bIT-V;Ac;I0bT-2EXoaW~#a0lZrk^f^45 z0;2NDuYe)@zA<2ljMZbhkA;m8C6;G?thf=qOK95s zFiJqzLJ|J-W|1;dF|#m!?eq)tjPwgboLBWAvrcu`^)sGT5{ly0n}H_KRRtY^mynAK z=R$?0h%r5H0hv_8*^_4SVsb&Jh!vWNDL%j}wYN8BTI7e*$4`bStU~RGH`{xn9Cd;~ zZ(f<=zy}{Ka#ShxGc#{eQa$*%p~#=f$~6D**|Pm4HBqRWL~!^xpPV&uc>81iY3ib2 z$ysH4`KR9R2tW>zG2b;s5_?OGe)bkGbADH8{78^aAED8`?RJcRFZKz$w;!*1KZ>XJ z>Di;7Jboxmf2#NpDo){I*PHypCBHZMi=Jzxa*YMSyW|s^2R&=X%t^EvTgS}H&#kGx z?LNm}efrqxp&3hm@?$?T;mj!U)C>hHo2f)Y)(nN0^}mMRunWax1kL^bN6P<{Po+Y) zWq9ZPn-V87HI#W)ZZ*F-J}$*+la`Rb9QnfX{5JF1R1n&B;3|V9SaI6+9r8`0v`R5} z`fAob;7AzY-Bu}~rjfJvTYW~GClt}oQE%j@{X9u1y5DDQiQBc-u z)%+~&UlFYtZch3%@wx7vm0Oe#gk-}>B5+#*T-!t6!)71H^8U$!wa>p8brIenhSRM@WGJLxkdcN+mkzd*roAqUbXJIj>Ek2hVMg zebuaJ$5L!;${knd5hCH6)pNOk$7;CGkTI1`z>-%Lw8Xp<@`~N|=NvdCu65e1`WjdL=`Qq z^TAoCq8x6(p+nyrT9%-plB;z!AM!*zHa<3!3Ez0SZS(nHWdb1#RQ+UdV7@TL!@&N3 z>p!9W0gHih{Z(QsFN*LDYQA;GjPQK!UyK7NTE*hi8W$*9sh$KlJhu{tyUap_e6y!5 zdDA;!u={kAx^?KpxR3@`x?ZTAi*xF+d46F?J-gbq5}Q!{0(?<#X=nGJVC}6AY}mVN z;-+)%mpC`@ENki5W-!{~a9kg5G`;Hr)|fulsaJjdW%S!ymAHQ|+a||?mIg(?i0N$U z`GLM`&rqt(%~0}w%t=X!aJEP^ZvJk^Mel;P6GxRhChY9M8@vkf+qC8mr| zby$V$wl66mA=BHtW?@$ij@}rzy-)Ig#F7^Wo%fc4l09t1n!gi%(i}$m;oIQrOw+{* znm_PW>5qupmHvCDlVux(@A6F{b%D7iNLJX~YDP3`jk2w9m%Z6#cuA%wy}-jnP=c4n zIsFfPI?+-(e5s@KeYJ1bqv0oDqR%h42^l<1YQES6@^>-swfuAdeXcQmN(5`>wBIbi z{roDqow%&#>1sgelCwhwZn9>pTL=A6@XsQm*9(92L4RD*?89EGinZ&0$guFK&d&na zWDx2aIPseFY&B7*5{3@I6_l*O8@q1sgidEBTh)Jrb0hg?LZN3X&B>cblc zpIN8vBm`b2kALSF_sW7k0hNC3Uwq~jX)Qo*`GfR*Pmv4PUsZg1?KfP6l)R4?tpY!p zFKzi%OiZ;$a{j z@1s{A*;~LkJBWf@VlI9e9rf-g!0JTN8?l_)kie(J=5&mFXnoxs@$7gg1(B=D_S91L2CXcKb1K4lnsm4G!RSVBJW@+ae zK1bHt8}S_%D*q>wyjc%22CFvf!~&P_D+pkbDDd#YG;l;eg6=g++YdDC2R(b&j9agH zs9NK303`nA%Fnyr0-UXWo^pw1ABt6?ZipJKKWIvhI00t^j}ssH2jqJH{m zQ>w|3^!XOPLpV0rX}cNg@U3vGan38(FDRo$PR}PSGqjb~PY#FA7^l22Qi}L%I2HSS zGJRiqE8S!}m(gp9GSs~E+$aOa%MA!}^9^6|r)yJ- z1t8oQI-8P@nh$T1K6)#WG&ZcRob-%zXT|yca6ZMSh2lJd!d>R^V!Mo+4lb106Ams^ z*sK2&XE4^wU2_%oyaOl8zurQhEylyV3rAout**1&ewjdZD5c-Bgc0oLWJz+jU$bY_ z%MmN@TWO6xZy+!Dqhrm*K))%Fq-z!0TR6!}j&Lz{`=b|__h^KteJ=0|C2Q`Z6U$zR zTb{nuZ7b=Wl$*DZj z&o$v~P~Fzy-{g?dcK?RTX*GYZ!R7XKmb_uMk=UcAs?Vna&IuJRxcqtM_2ig{=8m!b zeI9;N*EtT6zh{iRM}(9<4^yB& z&Tx6?N|-^}%!?VnN?tfJYtiD~QuK4Zo;|~jPt;Xlo@0k*p{D+&3ihPSd#S(!Igam0l5Xe!#$hro z1Hc$3Q#bf*+IQ{EV9OIdmy6x#MmZiM6IaNdJNDuCp@wmncH{t+zre<1cuE+dDsKE} zTBTIn+C@a-9a+nvxza}T`yvhj6{9$UzrdP+qEU^NCWzneR#;~VV;x16=u^O1Sx@w% zci=ubVijQ5rKI*UT&4^2w>9C{-<=ur=3B? zp`8YZBiq8zj`3Ob5R?rBl(Wu^l zFID?46|^!r!wa1phzJuL3_(fRhbct{CgVU(jgi|O^ZN*&Tc`CH>-m^*DH1b=LN2PV z3IV`*Ipd`dE&KG|G+{@KDBvC@u>(Gcxfqs|u^04O8ceHo+Pxa_YBa~I_-NYDXs(xv ze+fwm7HAeSLtXa>WWyE%g1N<=tVZjPOF~xn2VSe)V?D${9Hh;IU%7vZ!dtVPE>);k zY@^{*TF-)TvRxh<=3%9_1`cHtkI9-P9U1~xu?q^$Sj7Gn1bBgw8HC4x{O~p)9oU5Z zr4AUDWeIDHMT0H}^KC!~L6884cb>rwQETP!)bE@s%2xfNf!RbE(;R(wMU=pCZ~GnN z-Dl%Kkp12czo+}<2)`%SC8j3&9QY;e=u*sr1~svzbCQ!dWK~Kx zMmW8mb%JWc$a4P=0JA_$ztvanEqgJm=DoD9do`^6=N#k~6gIJLv11!OOWt4faBpWZ=Z96p?V=V7^{HX_80I1G&dOC z-|b06?rsIVNzNTc^LM);k$Y$XFPC#iPP|;sJ-L9F%ek*~;^lJg`wMuvoclE=UM^S2 zt$>%y6$*0V<#L69Pp?g%Mto9koZt5uV$#O2wYN|q;Pbk7Q9bSDo}v5t531BCeNy(c#P(X(Be zG-y5e%UY&sHP#C?*v_?%c=wq>y5DYr3IU%!RR$dmztD5s#i`Xx{P4Q|JyZzzOkuuR z8+l{)qws?(hPnm$v^1~_8!r9nNTtl9_txzC{Aw5~415-O{;~)2!|QY3`2F?^RXwsD zDhzyP)I4{#_VK;#4;D%;J#X%s_?yJN@<3tu5j-BrVMF}ipIjOCSL^m1a0D9d|LaC? zvM~$txK==;JS!EEr`rd~y|On7D!9?BTs?(;uqXKcJ~Tpq+34>3o|402{oi`kJanbD zzj1R?nUgUQB}yXCm0_{<70>A@FUr=g)~4J@b@=SUN0I0Lu-IDFD}GAP{chH%cB!=| zr^bKP5P4n;i>)`Vea)3ew!|FVnQ^Lf`__#+ATKv)+u@+!$*^I!y3^|q)K6?3mX5rF z!eZ+V{PkkHMeZZ7FIrZq#imKmS|YD}+?@U6?1Y+!DhXRZz4FzpmxlfQzeZm9xH)?$ zkFMO2SMp!6-2L|9T5sPxtqm-Dt;FWC9_sb|_=6QbfcAzRj_xVOKhmdm39nhU-b%Lj z_|O|;h8R=b*{+LTf4emjd4u-kM}f^+Ms(MUEsIdvv@l$4@o}B98L>~Be>6}0>FDGm z9gue}?VT+U;3983zhNIj!N?o<^{yqnzF%kN_RYU1Uwb%`JNe2aRhgBZGN1v3weW;yWOeeQNG-OH`7W6 zw^=&!)adBILgR~ieA`BuRcSz-cJ-GaZ?N*fvMDvbtsXn09`mbcI=*krd7q+>OPy&H z5$)5c@AOGw^N}~msd@TWcNb4NdT-w3SmTIe6~6p*53xhCX*6u-<(A`@I{G56G$c=pi-z+KvyrKjFgW zM-vBp8QbrBa#G5}USn>CZ}U0OB>?$=oC>)YAIkn>`S^5g;mhAIwK{psqt&_onIG5h zbEc!Q*`_J$kPiwQd>V%W_#gQshmC`OD~@Y6x7m$DJKH|kcf0P5*6F*0BX4Pc8s~WY zfqe40{Mpy0UaR+q)ck(`sCl$`?Ie)B4+z6!RNBi}^VFE2@E&gi3^CSCPgnD|+Kher zY|_ws^XYZKO;)k@kRnAQO^BO7&zOB^AD*wd=lZQlaGZ;MQzlcRe z!MDTi`IK1NdG+pTQ)6Boel?=zaa1(FB+f1N9zgs#Yq;mi*iF?&ecgT!DwNS9n=f~qJ$G++r8v)<^u^C^ z&divX@Jd9!`EtkED*I-^K0b%+4%8D=yIoF2Q6gVr+dEM zg?#gCL4RJ&~_|sT3*Q*xP-)_detc3JQ8t zywmJ2x*9|K8G@HzIbFRb@&yI;KI-ci^sqtK*7Jxv-`*(WlY)FfL7m(3LkCw}R_gAe z+TFZr-<*(uii3i}pQm-3 zpHF(H|?!8nZLK`0ctz%Yvr|SC1aQIS%=OGRYn{mHFj%_Flbf z@XbX(?Q6Zf^^Px=E-7EJI_lH8Uzo3g{D5CR;^~EE4^oV4+0Bi{XdX97Zf=R4r5<>` z{;1dT$_-lfMt-17azwM>3Ox;Vnt%SfZ<(rNTHipYzaJkJv2JR)4V|Ah*>)fKfih!n zr~me7_syj!U`4yYLkrm%pAD?LYQVPBYwLY-C9C_`zQ_;cROp;ggd+C7E>^SeeBqDG z`26ngwMkk_Ti8p$f*V){i`Wsl>=n z{R*!MM1CNrfEMRw6^$&V-#XzfTzfoVbXlV5%)>|P9Npcdlhm%?FCy{>IeC=dvwXwn z13Z8IZv28$KOW~Ebe(xQ?M&i>!h5?OIJ9b1H{=g;3Mf?j`Qu09o^1a5a`(&qZ;YDr z;*Hs(+KjDFzT1pSPFWs={6lj_^qx4P-(6fLtffuOO_uiS{Pjr)tQ zQbS+#p?}^n2bBQ9kJIKZ`F+H*lI@Pxda*Gv|AtqguWt96Yp!&ri?7eJKl8+gc#QYTN+id-vQoEB+^ZlOHAS0V?LnVQq8Yy0TI`4>^dFg1! zD$BlWkPeOW2hU}!xz@tlSC<yaPzPqBVN=Pb-BY&ouc~dQzKrzcxCO>qZ2CS7N(T5nNg{ruwmtLX0B3D2b$p@ z6gI^C{^W;k?3v9nO8te6J#219M0um<*6>j+wlvze z`t50RQ1HczsC52BxoP&c)N8({ihefyWJ#vdt*66L>HLXuchPC$lAlo<|H!jjo}De1 zJQtPDuj?)S>V$t4yK>wJ{rDhhSp4*1sC52Bx$6sdiqfy<%--o+#;)~^@B2L}onP16 zEcgD1IsYPBJa_2GsI@Nx5>aW$o9fHDzpY~Kn-2yUW?Wi2GBOU8z7{sDSWaz~aRYNL z(z{l$`qQlYKWtoh*u0^6rERE8P}mUSeIqd5-_NaW#)h43dTh_=N2SN?8rvV0fgm`w zeo1}D?N*~BerzWbJysU)jmjiLhlOu_ar4_PWtJ~(wD{VO`_@DpKxM!gCna2o|D{*a zE}bi%i2eP_>7Cb585rd4!|4Mr-km<`5&L*L7<9(=XF0ubqa4}ZaZl2vfSh1A_^YrgL{FSwPNx9#Tg}(mz zPSlF0Ne7!1tv~Wd01!U`kf@8w0l!tAl&JOXknTz+;c}ZP`?hp6R)6x-i3-O?e|}?5 z*XZZNBT+dp&)Cv2ZJ$N%?@+7c_|d0!@})*4FY~_j@JK9o`$)^pQEQK(aya#WIo-?B zV<~^>R8h+e?*V=*Kb}+Jr=GvmulC2xcK2WPy@ASsoTLrkeG^Cy+1@VlVSPtFK3?=YDXKz^A$6|%zG}I(al`&I zwxMz$C+YVIeVL7hu&EUA;Xs48H=o_9LOo^)~pHpPItRM z@0K=;zSU9P_er_1*84oxcI-9y%cQkWKSAX{PDN*|57ZaZ&#K4!ZQgkF`svi2rS3Mb zx^Gjz#v2b93Y7X?+A!SSL95(usrpe0cA08}AKQcb*hvMYJwq1W$ zAEELfi_m35%P!K|H;6yIe!%L0K)Uufj$jg7NXzmGwF-_I<4 z-EFGxxS!2mdCYx+DuA2{hkvvlKM#x1*0vCCYYl+^Pz4ZEs@21i>9|l4>UX#dz4|ZC zwD*WAV6yGKo zRY|v2PBR3i8BryWQVzM~yyg%|MN|o-WJ#)|XI0j%foXKuc0JJ*&EIt&wJ^3D+_! zTTFo#b2Up+bsbd#DP`5rtu@mOwXj?QEv9M~b9GBn4Lz%-ZmpGOsGWu?fs~AO(o9$= z6%B=g-0Qj-3_gZj_JAsbH93qTj~QVb(KA7?s4~b2OVLwZvW(E#PEF7>>Ex;YfsR4Wf`X);fsMBKREao&LXGuyk@Nh6v78D3_0^+nKQ#Ubi zFtcz-65s$m!!T$#pg@q5k%3Pp77k_s4oM;$GC4gI#9o(`W^ANeb!$W2 znr3JW2V;{oLzZcq0byNl9WDL+vt#os1J*f>`Gx}Mq{<qP3N7 zXssLD=q6MJfif_kO1-4LW3 ztLmnnx;b2jF@czRVTBnj)*#(bRX6t3P2sw^m!8zyp(|trbF#5u8)Ek8ESW(TYgOIQ zQ#Xd|re4TsGpF8qQXj0asupWc-4L!Dd+Da$y19>@)E5E*GGaNIY})FEwH1c7)g2Dj z9#~QRu%b{9$f*+6R(Gte9#~ubuv_-WnhM04>ZhY1kQ1n@KUUWOtgh-%MZHhucASSFWd)zUkWg615JkqS5>4u`|nZ?qxeABH4 z6a-?jn9^|QPs1@DF2W(R7#y;E;Q&eAjDkQ+X<5KrniW~h=}E=lkm(DDEXrcezVI+z1XyzHoq8l9T~aDk;NkuvpVFJ%G7uVH46aJ#}MRCepLgO^x7Smf(;? z=~)>@8V;x`NXf*&Co|Hm={T~anSfQQhpqhZp?vWvQRY;(mNcJZYl`J7*REZC0QVjNl&uln3AX(wxwJ+ z#$w9Dr9Y|$wv=HC$N)zv21b;gRXpA5mtpYFFa~6pTEXcg-*i+B#FSY)JYrf< z$S}6bFtyGAk1C#?>6f16pKcAvK-IvOT4fkpXPDZ+C97Y0rhj@?K)SV6hM{$au}y}l zZ3e0iwgm3ypPm_zp4BSd+B(C~Cd1e^!_+PV95Nt1vsHQ)st#gmoo;QDVQ8CSY?onb zpJC3On~eSzR2{^GQxb$_f7|%6%I!|4g1&tWplnnffq7>uykfesQo5;fx;Ze1uB*V1 zlEWr|?F40*-mBbLQ8!i6&6RaPP@rv89m01(5Y3_OiV$?GgN$-QG@HtEK{W7y>R?LM zvC0dCXz6gyR2kK9!%;8~L`yg4fM{7YPz{^I*&$kbQb7>SXhAhFYRbW^!Om#a_u8(K zj%t7{S;2*ZGK^I-Og-%?&#aQ31-=!OVW^s6?3saTU<@9PRbC}M6Fe^{-C8xn&@;mr zo?+^R)oo1AL^Z&cg3`09rdxYv7{W7*y)sO_L9d3O^vtU1Sv}LO;TZ;01LV{z!`M5+ z)CcRlYI)SP6BXF)X)E*^}-Es&Ao;gAJ%EY@Kb6Z8%TBhZ9KASY`i-S1b~m4`!SwR z)J^yt$bAGHtcf~^a||4eBXmevs3yoM5k6VR=#aO@!oirRXX;sF;9wmKwrd!tqgohU z+Om?j9q)~|;k|eAnqV|xzb5sk*Ci5_hHBvWB(v6dK(-hr2RZp4*IXx-T zVx6QLCZk#yT^gt8rm4Dlnw~Trb2iChova(C=*FqKX_{`Hj%wLZ_zcYOWQ%o*ZkVbY zr|G8Yx_O44G!u(piUrle=yIxVn5G-2>!umHd8VE;3$7WbTCCG_!*ty^Lr1l7qMNCk zXX#0^9eB@X9~0nUg?hkZNJ6!PaAjaICc`0f4z`)Osn%3$64;C(84kudsa8}w6f1Zh zwxjuAJ%%~hnC4+)O2Njo0IbJ|YJ;3ourV#f#94Ks+*VTNz3)jC3@CURNDqGm!%n&=hB$HEBlY3 zCyRN+6ejV1-daS86s1C>pt7{!r*9NSvjaXe9u%iAzOaj9n8jPE9~{ zu|0u(0zZ;{E1=R&P;WGZ+aC3s6Y|lq^ZSe`*KR2YxMpJ+^phHv_%L(_IGhWy|%f{a% z95d^IoRTJEfIbBS^r;x2Ps5D+VQfAHWAmw~9*$2C=%!&gOviEvzyN(37RGcej2RFP z>xJUNwl$W>3=Gg`Vqvt!!kC4H(H;u})dM-%Bx2Lob`XZ!dtun86^5dEHXLr3hn_i}iaAurrO^*~M-bJ!(f>oDgJz-WCz1Ry66#}ZtsEX9&oh9$8aOJW6< zgb^fx>SH-A!{S(uC9wiaA`?rZDwf0wEQw51Kgc!#U|5N5BOFU&C6>fTSQ5RlBvt_o zsc(~0-*>j*R=!HUrM;*=3XAa=l!%xC-;Mhv!R>NJK3K9ufAi$47EM1{S++E)zcMVQMAKO{##(#bsnK%||MT{7w@`hM!@NfG z+MJ55=DVeyX{=cX>bI`MwSFlBRGtL`W`C@iM%*5WIVU#fKK zqqV|DpQqQipkUzh`Wt5R*z+;FeU3Bi# z+ONhnJ7t}Uf`QMHDF=7XFY@sE2D)CkZm&N59yI_yuQe_+PuU*)QNxn2#f+F4tA>6tW6Bq(0r0u_V&$Swrg;~C9rJps zapUf}bB+Cr1jI#ctFz_!%mo4GH=qWoCop%H2Td~O#Wmc0D^ z;$I`a4$;d6tS-|z`p*1KtyjhL?Ob@eU%)CD81PwsY`=y4kChi)D&3vhMSFHf4S>&k zgI4_(x$d(~TO&WInRf2ZomUr*?s$9sNz*p_j()yeT(k={z4SB3M_&K&KCs6AvdA>eriNMov510fk_@ zmG=gAm^(Bp$<%N|mmBrQqY&Wp+QJH6JJ)ai?S8Yb%!y}07t|<{uz6Cg-akA#GIal? zM{Qf85a6?n`P$h_Z6`eR>R9QEL(TMqC(PZ9(VtZY+&OmZm%`7@JBn=Y z;kn|-`HMsMb(n)ffX{$)-a{KEj0%nzr4BqWVNEMU0H2?|XxySj=Q=;8k6XC1{o5*m z8=n!C`c5EbZXLMr`{!*>eTxX-)8oRa?<-xJx6bqA*H@mM*-j$@`24!J-tN#GZjTr} zHgj(9@te2a9$D&9r|FEhm(C^@s(6M#1n^mG(Z2X@H7hG?%UDYeUDmuFB7o1`?XE5D z%}4g>U9H{bnFmjlOenM_cJ9(%-)`7wUK{xNq1%W6K8t;|^I7D9>z6Bi`t^_g!HpIp z0{A?$;Y9ecV^J@bmMdTDY0LR#$Ys)!d99+xO`0)#-d9h}{Sg6tddH2K^GW?}LN~VE ztFoVbJ{OU|=lO{4Wxh3!XnC_j58~GaMd#mDpKh+u^-1-^Qx4tgwf{&{L;{~~-fQ_W zzf)^&?ETI|t@*SDB7skOW$SIze~deQ;zEkwx3jmboJJ4!8rZ>%{C83Peip}vArkm3 zJYwAS&P6T{TfOkC(Pw$cK12eahdSLme~Y}+_fgaK3pbY=eBklflpF3tHjHh4vy1xu z>6qJy1U~(rHffz)qiCm)1#$hGughqJNZ@m0Dc^6N)IT&)+Spo%j)>Cs)U9rc`gQ%) zZQXA_nRy~*HX<>f{S^N~#ZP1zQ)_oCJnkWnDByGH(j_~}^>7bu(IVM@Mb|+=Q|fNs zy}U%qSEWy-C3@7KTpUrDPpy90U+Q~|TzTOM^?J#GmWTpASM6GqTzJ~KKzY>_a{_KSw!6xQe6K55OaRG!hj`}qgMAB@XD6!7_a#!vC? zPro~K?8Nvf#Dj#X5BF|t@6#ZzclCBlnq{4I+lMINv;4VL^*i3|jat90n7OH3r$9sl zpOfTG2QMs73+@+CF7c^P%GIv1tL9~V({SF3uv=aJ95`b+qJdBM3B5{^_u91=`utdp z*g0u9qJhsv)8d!(3iYQrVWS&K6`BVVXU_Kgci_p=7L2>eWSR3#J-ZvivGB^Scwb5&LIO44Sf2w z4d>pDJ+r>i?FCn+U!8CU(ZFY$UdQ+BJdm-V#BYlyoj+0|ar-IvVwYF?H7y$YRj(~y zx1NURYhi;Bc8*k``mYW=blaOKTSD*12HfZxqax9 zZgVznxm)>*jK+VIP&WV8qQVegW7Rh2ntpaK@Fyc;K;%WIkD0!_^%tqJ!#@f-?3H#7 zu^@6^dX5&{If>sD-}rfxiS><@G7t+Q_xp2m?3l!?9ZUUv z>u%rW!y*<$UbnuvtIzcQ;_gPfez+bqjOZTWKC@bQ%;9^%RgdoOc>OEH0-wIVMaNAk zU9HZzNiE5@--ZPv7WmxJX=CKRIfF*CZmWk>e8x=}v*v7-Z);TR`2G4vRUURoAC6ey zvn0U!R&vRmoe!V+=*^%OT@VX={6m_N=C+>e%`O^xz6Roe&sAs36ykoF zR%h5izIlzxh6ah}&Yki3D)sZ%KEqcuyZ^}~!~vhBDy42qsL(_izU^|KPn!EKM?5aM z8~y6O;r7i3;fdPC2@SvNTWX6)rn+@cs?(%$Mo(R>gm@e(rjD5Z{iyRE7Tol_y*YYx`<68QF8>dRKE_u7&? zGAgovAH)Nn8;V4g_k7XikU~_iA$UAnIX31%^VwfcYkzs!xe~3)m2Ql9;ImxX`X|yc zW9|Bbi{E+jEUq2mfzM9&A5NmYcCDIRx1w+2^c~){ehVEI-t^U1*GoL{-}G?iRm9^I z7fLUl)_4A)HX}V=-tf@&AOZLsd-lNixk2+@cHS{3X~B?|zug(o=E$Xx>7`r6PBe5F zd!;K9fX^av^N+pkJEq^u-#WD4K6~=7NB};!`;~n@`+Bdfd(J2S)GhLL{SHlMK6%-H zCBwY7?C6m7WIqysPxo~*+&iVPH-GjsSNzO7d}=GGb(v z@2}1O=yCD2zfNEExKU_E-v$X^k#DOb0r+%lS>L>U>0tLdSN2^TS*@87iNNPjt=0wK zgVN;20rfAIopSBT^9@_}>nFW-whT7S-FNf~gGAu7qM)gtO)B0jV4&r@@+WRoi7VOrM!i4QOpU5rHFlglh0-tU#we`KHGL5JFQ3~4N{a{D9AzxUaGpZ-*_>sKB~1U^d? zU-x$Ng=?(;vct37B5o{44S~ni_tV{3Z?Ba6q=Zk(p*L?E27g_z;&8KC z0yP9aeWw*Zu!gL+KCplI=9JFOen1U@&m#@%G#LEmi}R^B&P~ed`iqb0i&I>OcE8{M zea__MY9l6eLk)q?5})5$wos0};FfUu!h#wpD^Nq=vs)HXduiO@Z^|~?c+7aPsr%UV zGe7F}=dyJ}2HmP#d0s#t)DZYAU1`{bujJ|0+7NeY4QdE{F1p#_MYkrEm)xir zJfrsQ>T_q0d>yv@#t#fvXFD~q&F+qFV?d~@d?LE>_&|+)E@uU_~m6h_SU)D zt9a*7^)zY(eBRh<4367+dR&b%oBi+KOKV17zUa5@MyF??JB5D38-KqZHNvG+tt$(s z^`2gI&7Cb<<{qxq05t+W8~dp*PFXL!_+m@3xgqHB)nCkw&%8Kr?|R4CyXHRisWKZi z0zQ4h6CaP5P$q-u|J$gw-(4Aj8Uvr}eq~I>M-S|u6x96JtKBwsSQa}ztpBt1?miJq zIrpN8!%<^gI(1o|cti?$Rcl$#`BSVn@1VxO=j5JGY7Tiax$gZRpBHhPyXO2!sb2dt zrSAFvzPZecPM7B1Lyd7>$@*c#N8>ha@9<(-%G>e6$h+Oy4|7Tr#p+Ej33YgH3mMt#?0bA@oTi|Ov^6{*YcibLXCmX8K%>}{5YcL z_yo(-CZ>-c@4k@P<-k5IB)ZOu17p4&@be+m_*z(WdQ4pD4WIt}MTB|Qx3@?1M@@ju ztUo%P-8UmGDs#fpHX~vxElIi8u4DhN3spG$&8NNmemOV*H32pYsmV!iihTWXP`ul5 z=Jbn=s0pxHc>Cf;H%qra)1)l_y3CN#4Pzsexv#2UnY?y;lQ?AXr%)3dZr3!Usx*3f zy2$g6TJb;K=AkCQ=9-vW(-$PnJTvOX!%dymHSQZ&s8-u6J|+3-e!e|C+B80knqXwM z|ANu0S^BcG5o^CUG`T+>H32pUu^rp}8k-ezqVQSjtI8(>H&lH3dhPM8V}&X0X4G2P z7k&xq^bD02+&&UpHngh8?N-$u9z;!n&(}Q{emiq(@oPF#HY6^U2G~Q8Es(EUs_xaBotebCMwA6n? zxl_A6vpkn4d>(jv#B|gYn{B^kX9h3)DRI(}ISU)Ui5ZQW0-yIc46d>@WM4|qP=0FX zrAHsl>fE`()h~}M|9E>s{IOEi8ltAaX8?D9_n57|XlaFA+wWhxI|MZaKKpVZ8;0G8 z@4o59{mn_}z=h6hIu%K8RAayC?bFVmCbw^anqmZ6jQR9MI(mBb#1+%4*OpVL8SrUY zyRXfsvpu@pDjas>linvfeI9i-X6=vD$5;4%?WIBW>z+l;FaqrxvbNd6kG8p0t8uFP zt4?qd_`JLBw-@u8^m=fn@VUb^&2dL2RDA0HV8_{ChgLs$yZ^-Xy-_pZ)AQmwQ^;s( zT)inb9;AI)Q4r-P>yvz&!x_`Y;{r0qgy1rD(+TS z_R{%)I>-ckme_qO_=VyfeIj7sur?Pqk3uHk^Q5SBTV3hNpv;h8XKh&>8qs}oKwZr{ zaqRIb?LF@d9UX&AxI$dG!L9PHE`vt*VtfZ4FFq2PfX}F*AuS}2##HyNLdlh@%ZwY+ z_QdDczbWe9t|pp~iNRK_! zT5DSZK1t_id$z5WqW&4tc;KZ@%`cQB-Fx&$p}?mX<*{b|g{Zz)e_TFk+L#`5P$=-3 zw5|5`!LjGpElXV?H7VR=@x2G%9yIMMHR=1K>1Y2OyZ1X3iedaScmG34o~w?{UKlt1 zWzknC6!`3U!P34?_s+-KEF0N*&W2Gfeea5&oLav3*H2#UIkcz#o7pH7hoRd23yM-mS z?|yI89M9m;$7&Cl7<)Wu;?>DV7M>l6nggF<~}1>VQldU z2eMwKAFuqRmOE;WE8(fHr+c5kcU6W7+RN^Cy)^ygiuIdJ-M@y(rf)mU4? zXHCy;8-_LtFZVDbS{dZC_w~y9t7equHlgO%!puqbmpbK}B>YdG{{YwX5itDC^B*Xh z;CVLB`~P^J|G)RY{;&Lngc!SbZP`1xV}z_m$E(5Z6g4`*rvHY<7A=TivH?+~2sG+y zf7fe5j4=u&$U}??LsX-~QtBJyV~kQv!Vu#S6gg6jH^yj2l>H*iDCo|J;#4D;*+?Ws zCgRSd5fPCIMk&!46Rkp*F_H2R6cOFPSi8rNh_PU6&r5pj4N z_&^PuKwL(YU?XQFb1-Bhh!SH)V5LMx#*B*3Wo*WX=-3gUaRt7Q zgh6R>F;TW3o1-EW4H$bD(Bk9}5OVaekf<1?L0o*phB;%E*)}%ZF{mXvUXF{1O|W+} za##aA_CXQR2{C4)1dNP~0OJ@DuVUGJfQ(~=K+CQmTYnwxtked>qp4sUx1(a>l=%8a zDPnLiSZ4%^u45PT5ETJe#`wq>;1B!EdnONkI}Sv zHM;{OfgNMz;@{hv*hG&V6u#Ix4DaAjOSU86mXh75?9ChsZUDsJzvb6%bNF($nb~@a zjZ?LV(T#Fz40oQ}07gb2yRg;K3D{V`MiOg}99ADjGpJM79%1#3#At%7ZyY&nQ1(v- zfoauwr?hB@1ezMBM$2GXDw2oTdc%UVsVKV_V?AR;4ow(sf;YmzjSX?nO2l9_KEYVP zU+vbz>*uhGL2+tqoI@Bby4T6o8;N_19uYOj@jBf2T$d?)d00V2-Vuw88B95PS7M?d z5*qOv)pL`fZDfGR$iM7|41w4dZEPKv`EFNap^TfPV%*8D#f?f>?EE$%vD~XouKykjdSn=+G|iH8LVf z%B5YB$a{H^1lcH86S6@Al7Uuj$U)6RySFN6OpGHUv})Him||%j{6tYyCD%|$wm}1m z!W~h6*^%H(M-<%v5*l>WxmBA%-3JxaopT-0q^+ZR#%_bUhW6>$CA6je*A0!svtJ5p z4DW=qIhHsCqE4C0BZ48kv!kAEjBo6pzz!0+oBnYx_^ zwQkqD749p$;RpX38e`SCs1eyV`B&s@J#~)3FFCh;41O2FaLzE>?I{O_u^|^bbb`Q? zP(UtqghHdy+^ToiRxNt8YB>nvSBow!TeS`C-qvgbS13Bs9&{5%sc0DPR8c{OI5R*B zwSx(xEk0iJ($qKz(Qt$u5|4S6F)$k(hoW$&@nHYZB?J-7ME0<< zhYxw;T^{I>GrGsAIJ!qI80Sz@sDg-#6IHe{^S_wC_6V7D8ZaEf#e+>F?dKq zuswUjcjyUg+$f=84wM2zij0XFHX_z24;c|X3@8BO@wSW*KLk)yHsSb$xDhhoQMJA; zEtzo~h>wVhjZ_E4tC66c7ytrT<}tQz^Fum2!YcC4R`S2XeryqJnmKV~%WPdcG>{i{ zV&InW7bx1{cMab6>Hu6eFU9OYP#qN)VMBn??*OFD^z2~FF6j5X*!{!Cq(k)}3p-B7 zBLVZYV}kcsw*d0CTx+w{cLTBMWQ3++K!h<%JhpT*F>MP>8WoJc1d zWJ{_8XDffv69iKLgV57^*}jKnb`Wh7{d*$;3(C`1-mcBr63133M~+a`T!8HzSTj4y z3S(?c1di08Of0*+-HlP>VjLMWS6PCqF^EDKElG~}p}voSol!#fSXFM2tG`Id&knUDjaR$tIwEDTBNp1N zIuHEL(^>eiuJ+;CA-Fv%Mnpq=SB=pq3YWprw!~p{#58+pZFAndovEX-plkp(TY7Q0 zaK&*gK4wImtTrfs-P%|v@4!0<1^(*TJ}?SHlM+EIvcMrmQ8WUn8mUpN!1A2JDVm^? zk{~dMM~G)RMpF@`Xz&XL5t_i&!9#k7ke#ATWmEolf2xggZZz!-b>_dIPBJ#?!p*U70L`Bq8S>;tir9}Z6Fp`a` z4U9WQ71^nBGA%L;g?)%1M2hDGBoj2PAx`56foBPhVh|}wB(F#^L2;@k@-ofxG@=Ae z7UcI-o#t1zQ>G9h%MwBaN75Q0(i$a6oGS7HE3){E1m_ij6?hdPky0d4WjTV81cj40 z;Frx!*;bl3MPB_+jM}c`Jk^Xd^hx4Bp>H?q_hpe&r2iX#=HL1A`})Zl>i>y9(?UM# z_VUb`5pd3pfaEn&p%G7$BCqfwLvbR@(SpoqNCfZDY$F&<4jMgZNQ6^#vprmJSicW6*!q?Re{!^0U{x`YZ8qhs31k6D4CO__jDs;oT7`Il(-<# z8Y7S}7;r}jXN0KIgsSiisR&4A9CQ<%; zDUh>FILR`V?bR};GCWeiQW%1k2ufn0M~Q=TDy@(_Pe?etQXB$;lB8-110Ohuqa;O2 ziX`MB?Ht#XlU_~IkUb<0GfIk}3|>JpSUDjG6whcJn}amzEZ5mC&5E3)5DFoR6b{=+ zVim+e(okexV+ls2X-3vaU=eZ+SOc%JNahuS1-oDxwihzy?gjfool%4Bnb?~70LI2FV>1^*-DF_sj$cem$;2$I@tjua8 zXjlXs`Xb=XNI-HSt z0`Qz5&?IP4V(0<};G_hc^>>lfSOBIhcsR@QGQ?DtVn|A%HHDH@E%yNaf!EX7UN3?y zWN>p%R%t=fXo%hngj1*&D3Smu4G@LJo)1xmlX+4GaS5u1poWkjV6apH18`CT&iX#m z1fa*z4CYx8WRcKRL1k%*V(?h=4Zvv|$c_LIr5?#OmoRq+S3Edsj1A}a{NY0RFvZDa20y%KSIIl;`}qj|H{|7i<#^1$ zCI3(To+#?Kpu4 zj46_U2q~K3q4?rB7XFbSaR{!GcM9)QJYaiCVrg1XWK}>s)S@CoLA@a|07Ny~RkXu7 zmG3Euhbo)m5GnIW`7GbN{(Y zKDXch1A_kzdBIU+$sDJGj76T-Xps}3l43cEgBT|vl4e-}R6?pWk2ryXvY(*f9KMOA z$Ou8j;VOB@T{$2My=x4^fme$hA&Uwpaty;WG(jjDxR^viz=c|j&^U%dOuYqA9M2Ol zdT_WN?tW+>1b26LcbDMq?(P=c-Gj^F4uJrHKyXQL2^Q?#@BhB<)vM~NyPe(Xo#|V_Roh(R>I6tqXIIW^M>QGa12DeW9 za3K{=POKx9S6P);J8X0zedif=?iPedJFj(vF-WhKn}M8#D;KK8skI}Ur%q^`;j0Yu zzN4v5Yik@@`UQS+#ytV>Cs~Uj6^l{NW94sz!yqCbFsHcqbKLHAKXRHSB;`n5Et~$N{5z1w$x3 zU!p1HM))o=B?EluZ%ug^!U##7sTqt5u|e1|EMnkwq9%-97(J{FXH!dD`3>9$Mz9hJ z?v7C0;SicHeiyxDt~uwD)r9-<1Aqo8Q-ZUul{!AeqS+n>#HDT-mB~eBVlN*qeK711X4Jwv4C;rA7gkgtRH0c@Au7Dd^^7@QQzTqr@5oS**&2~7~ z?go=!h7s&Qx_B$;f#D~nupQ1!QPpphQAb*U`#!ia^vB+?I}9bOL~pL&agFn*hi~q9 zr?K-3r-xKI&vkVN1w}u~ggq9uZsvCbLJYvh=3}3j#8WQ0qS{zGTMzxStc>P-eh&^k zHR=nyAspYL%z@&l#S1>DqeMtatC8`VWWj}58zw$YG7jp1r7EQ+0}{drqOjV*yR@jd zjL5hnZjHzO2eWEC$%Odl%IqYU;rRF z`HZ1!LSzXb(rht|ayp>Ey|qpY!)^K!52lnxR5kCLCCoK=h$=0*M1#9{hH^@4COiMe zUnxZ^DF8Oa2tNDM}(&<{j!St6vJrbEmGVu7K8T->?XNjaC>}qS>q}xwKR} zITueiDQIg|B3|Z^s0X4K)K#s%`IID8ijLI*=F9nX!W$1Z0|Sa{r)BXNv_QV)*QBVb zgbR(WeRFJvUjwGP15}n&zqJTT+@Jxq5P1h@kwdyUQTUr1#$8hTG=di51m~z=1ca(? zP;y9$o$#))d0{ZSOgwV?+@Fl`b+Zutze|c!LD03dc8hO94Z{i2P#fJZAx~%u5@^Ms zI+$S{IHd^cFfFPn+g4dQ!mG9rPrm8~Eos;hi(_=W+WW6S!J+FRt(*71 z!iB0=b~;n^xxssc8G1QBJgO3S3VsnHd9j8x3Q9RtR|qT8m=jpTH?Db z7Goi73Nk~wHm>{*7>hB#ZdfOOZJkf){0=4l);x9vgYDR3XDoH|@B}Jc1V{rF)3u)n_@HpjDuoQZkUk2~}QyM5`(I^G7Kp_^$ zf<=@tB<@U8>eMu1o*!b%Cq*kxYY*$7x|1p%njRN%IJjsz{AXh34EVPhB zaHa0zT?nmULmQK2))hpB$Ir=Elz0q{3&$RM08ulFL36}!ySQWqbZobA=5Q#;F{6cH zYw3@<^QZ=+?6_wjt>Ces$W~Yqn-|C;kpfeb5j_~vI_z9@j_)*O2C9&%e-Yu$Cem^N zno*)s*oSskt^_lD>Z^B|G%QSW%17f>*K0Z9ECEGvr&>vQ=MR)d0W+#Y3fr#uQML=V z<@M8H!)Zvh`jEa-(P|&-Y-&kuFjt>b(Js6!63Qjhl2+SmA)TJ|n71t_Gn{s_l_ru6 zHTnx98aJYHDVPX0Q4;nUcO;d0IiP-29n@`<=x5)tEg_4?r7YH7nM!S(JG{uOZW|ko zB+(q=BAbVUi+v@8tWL$NBnCY@izzlcW5mS>+=PX3L3Jd0u1uXZhR1@7Evum`>4rN- z6QyB?!N3R>#hAQ^K}5v@xiq!Az3+L=5BXv_i@AZ3hAH z$SWSkSvF0L{3Ij3Q-O;LKTvnTH&MWh0yiZ3;~S5hc+$QkQA&eoTvxFTZCtr513M!Y zvY<~HbviDl7G*+$81o;dZ>z1Zg>crmVxkeFQ()klQ3i}8%q0j;HM&@lN4 zj_8;ovW10i+#T&B&~YyHQV-jl1gwb#R}08Hwq!VvBFqdUsB|Glwo@6s?RlJMS`!BH zVse7pVvc-QS88aLyj)ZOL5pzctnXP|F8o9x%<=EpT9lNNdDXkJv+A5ka=_&h*kM|> z8+@&4tDB^M1I7M)XTAP>OaNo$1HII2Mq8wR&A%)pTSZ3(eTq^Q4jdI6-pS9unfipF zSxUjzjVN?MKH&M+C~*iDYI;LGyE~yd(GXQyyk0uv+D1Dx^r4hcP6o;tnbvr=A`hot zL0W~~u zH$Vos`%4laZglk4box9Pl}9R8ORQp1jr_H7kAIDttoP3~4iSTDjr^pGvfA~WKU^b1 zfH^P9lvbpeSZR2V_`u}1o5@#a_4LrF0xcNoiFyVO+?Z^Rf#r^W94oxPDru&@IA3h{p70kHAQe8YB1}H=rb&7}<*?$NL8`}~gb>_RFIT@% z4>t;7S-lEmd{$#11o5sBPyvq$p}2hSWC?Wp&tR$S*o#Z-`~?sAV}AWOC-M7`F^i5b zcNLsHC2;tlDi!t=+F64Q?^#qm*$SE5@r|ojuVv_(6*^xI7^wcnETg((^?1>Z^gEuw zF7fc%Pdqk@Xlu+)D$VQTwnkhj078J2cFbGt2zMp0kzQJifCyslwSQ{YIQ2>?$JU)w zH4S;%$16pvNUMij)zZ08&-5z(=Pblv=4h8N>JPUW(<{ zJ8ZbmHkV7<;|^=+gUmRwSQWK!rPX<>f0yiy)jjO?!Ev#IqEYhA3|IT>PVdghpIDu# z(*KH#J{<)6q2|7@-fz1%rrQ|y1Q$`<^vb_&?*<5e>8ZbPJ76w0q=MaM=9?e7TpvJ;m?&UTDE3Nu?!f>OdS} zm^;+Q9#%Z*vjL*-^`nose76f^B?$NlbsP`;(?sh-ipVEgQ0OTWRc&8Jl^LSH+5G&^bf7DOvC3x z7BNBD5u%5M;P4Tjd_+i%I5}~YT&j6}02>QYO)+6o>d^A3jiF{rK30p~i*@aIuG|!C z1Sc2$s;Z{+%!<64u?4;0#q{Vx!|-=WwxNPMeRvheIk$?GY#l|#h6F+k;HvC>!W-+%j(@%R!@3ZR zswE;KDX?RYrE?bB#?)a;+=evxhT`Ih12i$u!YN!pG1uW9c*O<&=)zt$Tj{7COK9B}k*G*IBi6OCm1L=}O zzK*K0kL)Znx#wV)a+XuVmpMxAN92aOW>v-Zqb-Bv{H7leOv=g1t&-ATb=xF zG}_LXdF`|+E_@?H8+IZEF}f7pN0HPzWSz;xTM?h8i(tzA{*7RjoehmJx+P9o6Zl|y z%8O4B(yje3AeHN3_-dl-j~=qV#P=-f zSwl!eqmUoP169}Qgt}L1dYZlwfEV|A23h91E|LtVCj=PR*}eta0ykV)ixgpw)fSAzT|=;HZ@v`W>-&@0npQf1~HZ`fs6B#~J> z^8p6YzG#M~Z*Y<_iRN(l&B7Vmjr@fc??S+Wee^7!&lEt6v2b|mn0t`A7zVS#63G9$ zmT~eqB?87N-Lwif5iUUu8gU5SJSDVapDNQ)3oqUfS5%Iw1@=M!XvFM;B(2cPm263e zd%tNWq{3JO1L4&RXEp_1jKRF}rCO?t#@#?;_@pRXq(|zq6wsRN3#XkJ+&%;~PEUN- zDsvY}E?it<(Xc=95vnFe++wh=!}vZ~60zpsgdklWj9?meym&AC0{NO|rd!4YAcgKA z!|zrFPND!C6Cd`Wk%}z^u5hekg?K)3<+|u@7>zAZ*CO=wVcrST6#2&wC*J#Q9G@`` zkB@tCiSQZWI(F_pKR{IL+UMzA@DY+XuUMTlts94Qmp+NP96%qFU4?Z?9gG z$wN}mIbn+Z=g{OvOv;T1SDqZuv`kF9BTpxpT(m=TxdXNjJ^ByCE2poGO8F?E*;q$e zFh|BPTrSeNbYm+V9Zux;O z+{j{|H$PtbB?YqsWJrr04+u&4R;82LQun1cq{&ke)lG9?F;pL^79Mk-alzQVbv+mG zd=H1mcb@9Q{Pb4QO~?1J>O<_|VPi+NjhK*YhgZP?W&5=sV$0C4cQJtlrOkC|X-d+q zO44yk(o9*Yr$Cp{P}soNrpZH3ttC%nUa#Yg$tiBPxWxRpDK!se6B`HlT?hG=8bGJE z>*qMHK)~{|s3aSP$wUMp3Dtb%=OJm?ap3TQ!@NujhR)czAw|eO@-vixbJcJpR75!c zyJICl(fZZG;hgtB61+)Kx}7a%vr#F|9|hoEUU@3Uv|#OhqEbxyiavi&D7=ZGkNQpx z;`90=A@#xB#M`Hvh2{I&55|nwS+3Ma(JYTZz+@`Ad(}E74L}CFgRhcBwp$o5fk7^l zVL_&rl-9}@{k=O}S&VJu4ub*^KM{3)3y2g=#AvGX?G``(4cRDvr6i*TT{f;`q>&qgW8 z-w5eAHqbZ2W{9G!eUL+>FnCq+EP<$ORAgU*`_c9>x7Q4Bf#dncM}VB4e1YBU@LGcZ zvD2@4cih$<^Ub{=G#2P6XdhrezSwB{m`p?yl8!|?c4aY4XlM4o4-~*iXqvwKGX7 zfVVFL!Z1W!%T4;O-x@hgw>x%KKWbkeH}BEvUSrn_k+!R>L+KF;d@D#wxB3V?j4;G; zGp}XBQl<49>S25SuhB?U^d>7aI(HI(^r;RaL6g2z#}QP8zkEA-+R%^rf>MCwf>9rpsK@@Q_8fZXwvB7WVKZ zku(KTwpv88Wi#KCe*Wh#I%y95b2oVy!OvH~gNQ}A&L4gtht5^VvwVopT7-T`4zjE3 zBqfiT0W#=wOGP6)WyA5k3gmz@-97C20uo3oS`Q!d6~MO8#=bDqcgkLT{1oK9Gk|Zq z5|*GSi%Rt&Li8h&yGnClL8u)j>CFqBF2zAuq-IFY`p*a!76(^?%TqMLHK4M~Hd)t# ze<^Z_5|W*7@Q2&J*^x8Omr-cnc}*!m+hj497^B|S3B*m47;6`Rvs1L$f5q%r|EJuy zhXz`P#g*p!#EvzO=BdHbdrjzM0>~i@!LZA@UML_;Mi3)H zRwF_-Bl;@T>i3^ql*}3d_JYn}sj2=TUh_*!8ERaV@c?^XoSQg4eU8i!j1%;aW~Zi- z6W^4*pd80yEfzBbX$YtFwxDh)zs{7wIY}clr6-4SAOjFvHA^d~fOq*!On zu3a;*j$S)?JWg9i`jC9! z-m@P>IoB}8<{acqmvm+03bQmp3Ifu3dg)l(1cK5$UPFSf3(hrGh*t*oz9u5<;heBI zegSc*Vmm5}6SmF%1)(&;lq3$p0qGAb`*SkJA=?3z;6Yzf8j+S81Ry3o97eO%NOHVO z3yasnZw^JYK4BN5-~7NfuNV|D^c>2nDKJCZ5SYLNRBkrz{|^ot zg422iXn@YXBb;Mbk;`0;z4K5}t*6wNGfIC0dj>*9#TYvMY3^O349NyI*SpGqo@jfOa4em%5)?MxYf-Ce6O3X1{;Y6F1 zk&%t*{TqJZvE+8Q#5P+AI06O7+^w`Rzxo6H$#jLm!0sZ~&cst_wCNjzG11;*WpyLR zr`IqZC7uyeJsXM~7L{52;C~&yY*PKjr39J>MTROHf7bZ`$(FRL!dWekYOSqpY;M5W zX{3#3Iy`!w8+gBajH^J+QJ1DaYJF+VtrlRB{S)kfgyux7pt|vDhh1sp=)zyX@lFhN zxsS;dV;>X+6Z6vOP@OviD=f<&l3k-=ghD5iLr9@Xh6&M?E+3HG(u-0pe}t3JeEL&S z8L{4fk^hgzPYmN`1xSIvb4TVB*2iI!kJt9HH<}Mb? z2c5tKabg;lL9*04sOD-Ea}}(e+Ly5vK44oC7etSeo((xZG)r;?PLRN$ylcz+#V4zp z2vMqbwqjoB0*wk{W-IWvi=4#WAy1~n5Y}{)SkjaFh@}b8j8Gi>XN^)059y}R(nbNY zil4A?5;hfWFiic7!)MTDonXZR@+Ww*Rvvc^MA!ohU|y|p{Nz@lkYPd#JI(Kz6+7YA(|0y?T{nxfZYZWh*w|wKvh{`3bNk+9EQ7xE{e!*-kdu2 z-l;Q^!`HkdzhSjjW)sb=k4c^BD5VUUWojt8GO6zBI2{(1XyoNc z7E5PZMFKVZYgi(Yv5zj#-lHmZ)WYu$0IzABW{urJ6Pu8&47FOEYYhRJ7nn7>4sQDs zURq9)H~|Ao)~rDgdr%ErTk+{c8rjbd}{b+-UdfX3Rtf8}B{?t^zh=m>f7 zpP-9O^`ZGNZM)rWrAt?lXcydegsCcHYf7Pf0gOMqlhEs^08+~sis>(VWk6^pGQ^t> zJ-(k~h(tj?^JkLMdr)8G6)}m!Lk0FhPy4n1zh|N!Ay98#_8`O5MTGGK0ei=Sw7 zmgQGghvs-A_`_=WG6&{9)*CRyb}37 z{5@zM5cKXm_)@kal6g7!_S(5U2>pG%pVY_ed9Y zg}96{av4xC?|e%TlqmA{`T0`heV_IHb_N^sJM{30=W#^G%qIJ~0C($;4R;xU?wa=U zhR+48?V}iH4ZWKUY%C-f9~w9LFb9K7_RP+)X((ImMzcrUB))x%^O{#AICP@wj9LIvpDBJelo~YYRv|1?m<(kDNH&LcNV;3Z7 zIUM9!k&k&-4VnYKo{x2pa(1f8Ie|xUxFfhr@v+bL7*Bhkjy}nN6fN-H_ zkMyV&Om=FctoG{QQMqsZ#lU4(Z}FHP$-7#SItX7V!F$lPdbzb!Kvu3Rr1CSgy6c1a z50x909JX#8Ize)iwLZ!Kfg3KXxSNQv`8XKRl4J9A+aXDg zfZT|k1V&HA_^6Ie)qKCMm~gx4y#h{=k1pxOc-9$kGEjP?fb4^1)#E@Dc0uBIC72)a^67RJ;V@2E~Suugi~4US+#74C+in z810F!$$m_$`{CZzF9?W&4rGHo^dyi*R1<@*Pv(;!WgNvlAD0lO2~a4WQ!ekX=xewC z!{q>D(Lt|EJW!s(2=g~^DhieU1K01hc_HX21Y0fiW@);=ZC-@NtWCpgg6BtiuDV%q z2CNP~6Md{^TemxN(S6p@50oDe#(G0 zFhYzn{Hmi;$_-Ltt)ER5WykT5XRU+M7$%4{b0 zUj0)-8jJ*3(}1y1Ow}1Wi3LP&7)U-IA}!!MBJ4fpt{JBs`d@a z)S9%_Au&{Mpb0&mmO^x=O;O}R6RL@cl<;L|rF}Jg$_9Uxr0#9@9@>PTvac@QKv^~- z=ZUs~GFgviRm7`~sj<%Q)lGBvFX!JTi1c}H@hpYC)_%2EGrY%L-uA(~d>$tFPefCb zdy}x*$%KPW;NzQiOkpjw6lxIL zhBj47audx@K0!PqDTck7GLKzUe8e8L`;BxoB6%>X>Qwi$4k`#Vo`^+sYmfBKqX;6L zWrPP9S%+sBNJp>v+vg!Db-;xJpAG@ml z{wyWX#R*U;UNY8lZXrA5q$SzZKDDW?vfAZnbC$!nV#aOaYj@oBsN*IzDbaPPnRc<~ z>xNjFUh$y15L7pZ;)F=Lp5u^bMJzbfZ8=Q|8Fb$xbTB1o#I_E-ZFn5|ugpWGM3|#D z8#0w#!B6N%>p#$4135|L_i*05Vsw6_gCpa^|6Oc@YR4<^XmC*=kSj<-(N7m}Jrm)~ zH7_F;E$Q%>)i-pkIljKuhH}M?EmZgGG3@GmQl~80?VMMViFYPj07i3eH9(WZw1w-E z-+}DK<5YQLxCA4F0!}T{v`~WO8h+P6O8D!wR8;6?$tQlkfuXNgW`tFN5C8Olqfo*b zH^A`}H4*KiDi&LMnC&}nm_A&Ssmoo%e-Ji}HHC9UL}X6lA-4Y1=~<^-bbBS9@>Hiz zD%~Jng#I|0h?%sDB}|W+I8j3}fLwW;K6&JqG%{<0Em^Ds9_=htZ8fnial3v~|RY zQwPiI-vOT7)>as$3l~EE7JhEiPnBHoyDpl2HC83<-%r8&paqgmV~lwK$G&tC+jSUR zkXGSHwbhF|kumv0=I2j-yk9f(uiM6Edq`xsrPK0Sr%--Q|X5Dml98qWunljw5rlN(lh(`NUMiB!T&^N-RA^ zu+X-d^eeUxUqjdtIasq;pq7a991hh~6(ml;Cm2kNSp;&;KcEGi%)jQt z5`kLdBfqsSd9=e8fhxuDGUVJSg6ck&$m1;y^fe#97T$bnQ^2ruR%gVg!_>LZj4o)T zbSn@@cf^w=?69mJ0w>d5pJyp|+U}x?zc2)ikCwtUnp3_6672l0U3F~VnHbXeF)m7* zjO?~uIh&gpB9f#^2PoD#BcHX3#K!Y(3H z|7r-@$WQ8)$j9q{hB9e31V%O?RcrtUgiKgwIt{Zlm2U*?g)YsklgSawn(|VF3=?5L z%P`IuscUjZcA)HSSq0eoj0Ajj@VwGSu{lPwTC=*4g#Cd-Fzf6BPzta;;dCviv7cz6@8Q* zGi5B~pg0*@j{aA>8O>JbwWIRpA9Q$k5Y6_dX!?IN*ukUAqHTWF$n_C}9b|$rKVw3` z_82-M^4;;vY)GZUQM&8NUH&=sp~*&c_Dp5DWpQdb1l?&j`ig7|W)c>Ws2Nq~yCpDv zQvGvtM4Cpwi|A6baYQgkSrBrE8`Cl~(A?21&t>Qd;DFyKX8If*jV3|Wfdk)F2xMzh z!Qymktre)ME{}kZn#x7}q1{o-Ns!A$7|G<@48iNfm!{4)vp4$6@2@Aq@jubQA6?Tz zo5d9mQ(CQ`P+x0?&;0wY;qBO)N-E=3_=@-1VO-BU{VW9$CcGIzxspnOA90p8rnd1L zqeAB9D`VRU-gb}E$oO%#XARSf&J1sBo%d@+PcIeg*itf|Q;?X6o$>7^>-amRmzIn= znQ(Wgy}bdAtPBE?9TH!ROSAg4{s)M&2(~+*v^+!Kv^ku%?jJL9&O*2@&nXZ_Kw;vQ zfR5T{piBExxVo>QaR;k6@GgLQw2?`!viZfs&OLDe24sGx1py6ZAW~vEn_bdbSp*`L z!4n}+)>II~EGq@-!B=@(i~k){rwUp{^m@^;P*4VXewju0iPoB&*iGb<81Om}*LJM5 z7ZsPc{aSS-qexiranrYs<|oLv`Rkm&@>jjp0smE+rX&A&X z1$`LfvxD&g;SOQi{K}0Uq#>5}TiF2+r4+Tska&SgP5C8;<5hA=imjc+-b?lnBIYbT) zl&xWVC+c~vndgoOi)+@|pU(M{=Y=&J{Hlzlz6uMZpMJApc9D@DUC*1A}{?zp>NObIuX41`@s#+5DrYVJEkXJ($nBiZCy**o$ zci%IgoUL>~GnYBP9dn~L^Ab^&Tiy(JU6htFnB+&w5+qe+xv(N$KAViK@6k+PFIiR8 zh8z(K^zBXUtvBy2gof?cNz1QbLI=ur28ZumHxc z7LA6CY)}a@7Y+_)lkz8PRis=>eC>@vMGWi4{ia)q*Qm%@IRdAu1;f)bjafqtzV%81 zQMKItiqp9Td|2)+`La28p%|hwT6koqLgDc}!-!9Yay0*P8+hAj=x^egvKp{6813iTWnyhS|kBKOnr4qNoQ4x4K%o}N;m@pIJ2nq^4tiRat z7k($eU!1>p=_-SjFA-75dBPN1MngTD+0?^7dML^ZXvErk9Y|^`HKu7H8y!pKyKqvF z`ZRKIazn%^i-^~J&DG)gsHo1mAIcMfRuOWAEf6xkRNi=?1_CXKaE`X`8VZAiCbgq! z%q&g;*=Rj{<4?n+1L7YY2*$#=U+NhRZ?RlD)$v%uP{Y#!@zbJ&pt3niwa<^57dHP~ zy^bVjp@Zq#L;bB~zX7~v8s^GNNtpv5kanY(G1zwqeUlazvo^#QFtZ#wWQ9w=0)~*m zy}*qYl|NmW$19?T`1l-SMIovbjnIz`ZiasnfFfH(%(DFi^u#qGjAcWd(n9>0Z{K?3 z#^m2Y$%o%J4vT8TneXyP+WI@PFE7 zw~CmDjiXf}Ff&LSrxDKdD^ncLqHi;i4f?7&@?6Bc4pCk{o)l7(kO$gqr$q1WPtR33 zRGwtv#hk3Y*P^2^3wpKiw(b8hn&S64O4?Hl63#Kt2>9b@wtlxdq#fSEA)5bCebmcX z+SzoE_mPQM^zWecVBt?3K5=9e6OS8%CD*B1ubCDv`DgXn)B+^Hd}Yp;%Gpa%U9gX@ zwc;RdN+F&76J{~2#Vdaumg_%c#QF@On?2QAqOCYcv8$DLwKR{N<8dmHN+ua#!urjL z6u`KK4XZLD%TL15a`<^SGXcng5M|h9MExeaHzOSHxiWdM7w9{FS4V`0bI)P!@#^@6 zE^U&hFzic%4RVY{3>@!f_y!o%U6L4MB;$_;bWJ`9faB?E})a_*ijRFGQjTT}C|!F+H}(;SB8S35lp zVqQ});cNI;hk#=;R(Hw8Hd^lACt74DXjI#iu>q_P6yy}sBiHvuw7k=If9_Q=E>6Cm z2fh!s4eH^_x<>Ot{`p}E`uG19Y38SCM!jOZ*?e{5=#Aus8ptX}HMHhfhW&Povv#<3 zEIF%Y;%V)ywxa|W!3a82KMNhV!!3B#G+#$>dKPayqJTJEeTffR4Zag{xIieuhiKaG z=l8OebFSyOv0V!eV3(O1&syA{NfqlEI--NR{61Ri0M0zCR6BqV0uML-kU?LNBltUa z4XahU)hfODQUwgf7l3dgq^9h&lAxo>Dsy7o=yI)8Z|qN>G=n)ptrU*=4F69x6kl8S ztmvqnKUIoWS)tb%gxCq`EJ{MihBi=i?%aCTSkzI(_R$7t+)^i;p+%M>U1tAkwSB$7 zZQM`HIyMBe+5N^HWlY23T%6Nz7f0$UqB0OTI#h?1uy=JS1DNhGC)!;K_?F;(CD1~jJOzNGU%*ToM$FP~Fm{Q!PcGm;n%O~V=BY1F z<#m+RN+}6j71EDJk;&`I|2Tlh=IyXwzZYmevlDx}n6aqjF#g$#gHf`4$lh9^CbCu< zzS1L5vZ}64G*@kdw)^F$?2$vOvVvWx{g4#Uwj5WB#aJH;gjP(9GlyTe-cr&w{j^>w zeMO@IuFOvTFd!4!k_)4qC};Xv<*|4;*5S&jzmc6XWwtbh@Q*_=aYg^q3J@8H@Ed6U5&ty7KgXh4CJ4 z#9ZA#vIv#iV1nz|CjO&~ca`!7han^|tR)<9AU-9vH<}grYGSwyWiv;&yL9{kf{$$F zyWL}nlLv@n-)eXc{hfd`)r}riy9`{PlY6Y)idp^94JPd^ifl&cUMn2j^sSqDRvclH z;?Z}Maei4!f>w_#u$-T!$P9$))=aHMf;x474P#i0MNOz*H4HEjFp+7vSKaBZd@F4YdEx^aFMa6R}Liu?sLA+unMSX%F9fITI^9xZ*QSs{s9$a3^p&Kj% z2h(0_<0HD&i!^w*?T0vC4sZ3u5lV6s|B~~c<{U|(i8|O)^qlM;Oqvt>gqqT zaC$jOMk1}|Up6ILF45V%mP>tGMK-CIZ>u2gpOoV4<&4j26@oIgVSHQ5U$@W=%W32- zkRm;-(+EKnZh8f?Bu3I}$++hbDhyimKcBpn4_-4CXB((-*{xH0YT^~~h*=!O3P_hz3t6dw%|uwfpEs zaR_r^uswV$aAH{nk0M4{ydIEI<|d# zqhT^LdNF@;RvK5~^lwph^nf~jUhV9m84EfpKPzRgHOrp=u^Hf_MQhei^8;xRVBjXE zpz!d;@q_sVL!J>HD&i--k2AiUE(n4I=t;aG<9}1e06)GoDtVjcyXJgjw8Ycx!)}vO zWHnf`lQ}%AcPcqa-NUL^YnC7oe4F(g{&j|02OG~F>Rn$Vh*Hzj{1V&M*`+QV8j zEs{2h#Jj&N!3&R_R4|451m<4Ie!-Nt1VZ8$jkLAYToZB{j|InM$EHw&rvUd6oAQTl zFI1S9my~CS>`4&nDe=>iip_{BsO|SCl)!!L^ljYTam0Sb+8m!)wU|}gSR5^9aY*IA z&3VkqUhC%5(i@1qwQDG{@z+4`8@n2QJtx-wY!JGQr**5WKyQOptqr=u#Y((N1T5*P zwPa-7v4{@JI7t>Jzax-~e;ZHGmb8>~gZF0c&@Un;wU7#t%qNY+TVeB3+9jd$Uf*ja ztGSO!nnfXFijXE$5WV7#j5dQ<5zivHDAO_oSuuR~>b5r=`5;e>%L`Z`n$_to)ZgK2 zS)}ws-shZoR(8Fy-8k!UB`VGSa8ZZKHqx2|~HI6rBzGfbrR!IPqUq z>BQP>$(ii2U>$`%Z!ugeE0SUCvyvb0N-0w;ytef^0|6N#?V5$kh~6B2?zdWdPn_BF zMe1BUu>+54UeT}Xi0O=x@luwVH+f&gzwkAZAs1ZN!;+MxV_2WKwP*IsF!2+>scs`Y zYJuFn%%m^Ws?8fDvm(`V#O>$5M0K;4m9b_mq#RTG zg!aI7?B=tg4>W%!FK4-7dl*Ns>nQQI^uLt$aMiCW5igQ^>GQ(|o;S342f8Po$)3!j zfZ2`2wZ^YKxEtG*O^IsvrInJukh{xhAM4S(UU`_R$Q^O_O;{2Esx{+wYJ=tez~KbM=Ooz325mv*7qAXV_XH?8UwkCJ;&-^iSE(4IC^^< zF&{%k!Y@loB=)x?R}xT@67@K(N{9ZvfjACB0Y`z`%Np;hQ!KS#RiYLbohidw1`hRS z$M~u-SC4|S0*4RdabLIL!=cyTiZlTyefbs!0p@0MN>8G>wzMEiuB?0-$m43@f{piP zZ8hOqbrW6;zPKeo7rUVjzA_n-AF9r!2QQ)zkhnu~!kFzNIQa><>7IN2P8LSzq_4}S zPku5=M@(%@-VGyOsEC542=3?3up2SF6{uxOXVSJl=tgFHIJ-fLS(&CXCLogNT*@z- zM5U`a&2l?&ZP%^2e>_n=LcdifBIjvno#aRWX^>zhMyPe<>5^Jt7k{m_`0%4gVt2Gb zKYq)*P(u%GI6Xb8D`&_vzkD29c{YHcrF$>dvIZ{{N3rZky5^nRlH0_7| zcpEl~xp$}-^LBTa0>qd!|mTsmZ=+@gKbLG(Kbw9|Ktx_OdJ{(@(| zd^X+CE^)=Sk_SV3O0zzW{Bqh`7ZF}0K%hQiv6K&g1NIbc6l=|PbL(TC%6%6! z>H7t%K?F0V*G0Z9`{w4JDlW2W7Fmd2PAd2aHX?EYmLM`(b0`cj%&j&S&@rKO%8}$$ zR=e_ql+HW^wy0<7PsC!-dzn_XMt9e;W6m^QhuI@BfmJ9%4WOD-m3|3pTNO-Zy=`X_ z(QL%q5&xp?U~U6Fm8;r(?%|~^@|6-Z`GE)Vsk=S;bRjzW!R_$^Gx%-pa^U$K#)~^i zgyN!+LS^Rk@<94x2FQFl1KB1I3V1Ko+WY5oi?em3c9Fc#@DSa*k1i4*`V?A_OYZ`Vh=k79+^On-s{gBG@f@BY3I z4*K36o&WHD=AlQw zJ5MCo_rc)hVs0EWk&0nV#Pjb3#k-{tW?`Ja1bntE9?5`HS;zI9n4{5E@a^$+#Iqpj z)@G-Qj=ahH-|JVEqUm0ZC&IafOX00Ul?RHq^vma>p!fH`h~p1cm%-23b=zcLHuDco zdNC+^1s9z$wu9;#{~FwV__wz|muR~9Yg3pMVK!$KQQ^%4HGFVv+Lw3wkBdN|L&r`L zPyrZ><#*A$|8>)3F~GNGLqPZNIzp#sa|(U%vTm&1`2gv3Kx7AnBDu<!!^W&cpG1d>iDezZ4p8}pAT^>Dx10a<0k+j0*ix53#;dc+hhfWF%k+-WaA}@b7 zCo^*DGg} zUH?ZuG=RoSK!4bu-XR^zGZqd3Uh2NTF2VkRe$NN2!odsh3CV%{xSJQRBkB8mQ%2n; zXw7qv?}fc*)-BqN~=A(Jk6lFb|#G;HyGW-`{4|27SqIM?wdmyk7-5#RP@P z6yK(!yL@WCe^1hjb)YrJDK6zUd6J2lHK zSP|6k9ujna{LxtiuX2&hqaytHr0*TyLLQWOTIBL>!Xoj+y4CnsAQ3zjd^uQJIEdx| z+{2Fk_1#$^1iWg90QP?9TQ9AZE!KvY`awl<`EpHy<*Vs7$uyUc?Q7AiCS_@9O*$Bp zzmbwkk%6@#uO{P{?hB7e96ZA+2a}*ZJ`>N&+I7HH zTtGayzXgrZv9hJ5NbgToplwrU2bEE^ZZ)RJ&?lYo;BjL#i*y+-CxkZnuezVL5|V>A zYjRZgFkvN{HOuxRo%Y6xQ)cfRD7=*8$?GUNqsR|v2ZF!eWeGU<$Hs5Y-BQJ5K2l5K zNOF0O!ijfaQe*C&!z>4(T&U&gQ(Eb^+I%7iYI#t{2Lg=IF#A>>lsZh?9*O?)!8WRFY~`}nKlA@ zo};g=<)Oh{e*ZcKej+GXRy9bN{A9MpYDhn>G>}e;dqkqw`a~{5j50L2Eu^$5=+;+E zxJRHy010(4!@;GU2h4GO@yjennocCZ!=C_cZ)Ch45APRX z8zp5*PI7xg@BST*Co`>>1Rvsnl?`b2w@V7xn)EO+d204)|Oy)s2|JHo`2>@e_Sf8`H5P2L6!w zOXGHrdq7{Jo56)r#vG<(QZ8pbyk z2ExbvY}8x)pLxm3#H3;$0Dt6DsfwQ)xw?VrNtFKp!{1fYM?ehuNK0@j8XefXr5%IE zx5E&lDKJg5o(Ly#l*pXODP)1Y*{Xq!ziQI#5murE?+r{k3I^i+f^ndKBg)NlWXkz) zr4^LiO_GN=-D3C)^n!E`{04+bcq~}01Q&N>gV;Gu>f*0Qv&e%d2ay^4g+6v~(?f9} z=oeamTX1VqT8OZhaUD8Z7nm`R9JCZLU&#!g)O-psa=>+?o!POwAs2rSJTVCT!d(#T z)32oMcNGxff0!G4&+PsCIIz6kK8Y6}1m}o>ec@g~=Ag@Btt$(;z4LTr@#un}O6Y*c zwE;6AN7`lBIdmP1=+A_)Z)`z9Cc%xsJJx(e;UbsbnnmCm5ReG}tIg0!(AqH2#fWX> z!|)Wq78^ZeB-p{m!a}hSS{ETqco2EGBY=k}odOjU zvLo0jaubhTLxbWyb1syD1zvAZh%L_uRtJ%kCO5pS=%Qe z_k@ex2N56?;biHdvnf9wnVSkPqQGI;NxT6V{Y{{KO5)P2Q8D9L8#6>%P%kRVG9sy* zSX{sa7fh2sj>e4(8}lFF;$p~0wtPS-nzYU>R#q{)HXr8q<7xkoUe|j3C^y&WNtFXP zBE{RX*hYWEVV}(Q^(Q=OKC1ZokAI}e)dtfHqxajS*O}93)}S}Ko8R*q4-|Eb6Dqo@(7a5EK)hM5)<3*~!x826TPQo@Ztvcl-CLi> z(=IT;1^~x)E4AjzZnAo_?N+bxH=|eUtxC0dUBzNNtJIe5R=u*kcJS<|R;|LY&Z=E; z%d1w4k51V@t(tLk7+4VGUKH+vd4D=jY*U3lR`h7^Lvp8_0D7lX880Y)%8@%f?xB5e z$G`)8K-wl5omA{Q2RLgK>keWseQn5)OW2WyHR|47|;8?(fr&r_-wT~ zoY@I4MQFyE!fA!2U^@01lQI~c0ichWe~>vC!<3kP6`T9rbb?s$b)4P1^Xo7i@grmF-mBWuxla&2kNY9jsHeTaBu-#B;M|1>Xx= z&#cX7GF;N>%YsT@j^%ZkXCQ)8c-KwB2#ZrEwQQB%+5o=ypl0HX=>kU2sq8#h737ls z?e7W-MR}3y?d>oUaAZMGFC;h40koO0Whtn#$#;bIrhoRLU&F1E)(@W_p%*{07B}!ITc6jTBsuJoK_er=9 zA|^|8yxPK#1!N`l(yppZV%nQOOhW1)@79rdW)ETppA53TB=n3Cpn5C+8b{ z2Icar7AHQsL@DWyNm-Baj9A01z30Y|rV_sQj4(KcuSl>0xP9LbzOZGgz_ilJS3M3T z01&uF)z3zz?0kgnUm>&@nGC)aIprjy&5N0*-? z;oUcpk3fb;ot(Xid_3&knHqUBvo#6QHFTyzVAps=nrr7eQ&eb<)1M!aziHp^D%OoT>*@4w+W5Qb zDSa#B;*END*33GmZ#SefeVIY$-W(uS(&zv%X->GKyb?bWDj73gA{OBq0{BUJ{=FnM zupAp&`wbqNC}#$ajgnt}>U;X)gZ*HEhL3X3PIib#EbZY0#;qZw1b(@2@3z+ZX=4G}x`T1R^ z&hDqh=Qo}Dt$y~micbADHw)BNo%(HF7N~0)wf(m32I{&_UDXWc1_Lpj^B$d~A*?`S z;oXC0B{~ZE8333107xAVbs4fa>Z8x3uampl6inAmwuw&}Uk*=U`;VP`X5q-4-fNDu z>AXQUq@EsA>!JFOYEmuz__ ziC$H}at@yUAPWpDYpjz$+de`6uUXVc<=`g^vdr#F6bp?SdW->AR)Bfo0#DTEZzrgC)o2<^HlKL{F2Aw^26ogtv6_M&u z)p-e8!VAtBz2S5`wh!}&U~XeE=Mz^jh0!q`1#m~5 zDk`s)^$6GA+b)_PCb~WzoF*|I7GqZ)=ET?m3vm$}DDlMRlhU3yxbRQMD%Wx{;;z$) zq{Qjk(i0s~E5Ygr?=GaIJ-{meQR7*Nbxh&d{1b zP!XX*`YC+G{a)I`ans`-Uw3*7SsTal-NIN?@sGPoJoje2q0?A;u*IMaT&A=dt*VO= z?4Pj^2PH6pXkqw4ur~;-^2P*yj7iPhqMrw!X2ynLxKR#t8GJ#A!t5>K5ty6mUd$oV z(N1H2CUxTO#<&l{9Sc=5?Vw6BqgGtoXcsuWT&YybFQ`;6OiCRLpp9ipKc>A$2uQsy z`5P@Twd)z9+N?L|b+AZ;KwptNl`JWOf=id{#;=gynDfp(q4rs4O8>qvyq;nZo-C%# zWz^7xhV~w;2{m{}JxJL4QUsfJnP@~~sfN)}h+;_l4bP)Y$(HeQF|{c9z8{*2@le}Xr=A%F&Zj1% z2M_Q}O3rHaA6C(yz?5CEh&6^ChY$+Jv(pH5+|sJGM@v5LX%npK=G6NtuM|5lWL4Ea zb5BQJ342qc)B4z7V1Kcv)6n`yxxs&+7?&ccHNWejGA1o@W49qc^g$PJr4A#CtH8&@ z96B~tO=PN=$J2To90aHK&78LrCrP{!oi3r#0fL1~y2xwgJhS`Q$Fr*OP-qBM98);< zvr$eT9*oByA12oDrN@6Z>i-c3;CL;2`RuuA=mg~6n+~l%zBkSZDSZQJo&`SlDcMJ7 zQr!0j!1MygpAB$|id?^q_wAg^iz205xB%9M`M}F^H_7fPvPjmH8x`+5=IC{97pIh- zabwN;wJA~Q6k=fX18nehT>65>pl7f%xqRb$nnY|`*^}HC^orPIsXl&RnTSosV#;?^ zir8e#++WlrV!~c$@_k(*E~_8tz|-bHL@7>??3U4cQ5?eF8|BJn-qE;*n6_cd#HVsl z6rZ^`lUfWBqATJc6fNPr1yMxb$S?;38W-EDeUGjH=!khXH|PCM2cDu-1o8S&pAGVg zJl^wF{X@q5EtrF94FqsNdOQo!Is=-vAdlh5X~t06b7q0!i4H;RMJ*{K2`cmt@V zZUoL{ZpOR4)n@5U-$GT=o)^9hv@U7m6wEiq+*c)&KH~F3QAocOS6pzXfu(({Sq?n% zgbHBCLZ#9U$^Z9OfV+y>?OJ!{417tg`D#NU5)5ZUB(N%2zoW}U8Nj`)^&w$Z5|*pk zPw|H1Ztu5=khD^3r0GD9H?eDmc6woitf7e3z{S_M{59yE&UZE(e?*siUA->18*2E^ zDRWypmYLqqu#Wd$VAdsl!F>n41>nS6NpAFu?}~JbEe7q8wRXsmv1U^;{=hqD+E2KF z22>%yBB;Wq@|ORXjpuIol@;uf3Aw+36-#KAWHopvlfPB~mHo99Q3pVLT~ZAYW2ar4 zH;D&WR~1fF8?t7i@=kbeQYl{zimm)fhvt*Kaz*!odFWXNTePm&UK{V|USRR;Ed@mf zhb}%>-ktPg)5Wkxy~x{~i~PL|Ac(rmYOKI9p*sTYSkdJXDvLc?;-b_!J9eQ>S+!2* z=#n6nxnkbMgqI4p4#QL>e}UURdP8n0cUvhW4Sy*SY*jBuLR{BL!zBk!J+RRxb^hKKo2M`Y1UovVRb?2pWL}6b(crHdz)Rpf zV&GMOUKsp<7x9jX=<<^)+gx>flfn4+A)+jE)V2Df4pqvmX>T?ek7m8nR@j7W4i&As z$|7za`U9ZjeW=%Nm9-q!wp&ZL&Z^b2)2h~7RGsy~5BKy zyUfBzSY{B51(>+71c zwDB#}s};L;@K?<8k9;NBrD@*o<>ZX5w@c^}PC?vi@I3%&;L%m)l3s&THLs1g-thit zfFVa$@-Yepd;Bsb<3B1O5)wozp$XzR*g_yYd-}Dtg1J}|>%M;%)5mlFWGsbT1qfga$Hew{nw(#5%(vgZ_mzb%y;&!{Sg*1Q#a+BBfld?=4|qHI9v+|Zgq*JGQ<1`3C%otp z9p8w$099Wq44f3e()t*G85^JKF*|zsK@Q&wK^H;ns7MqkKH}#^yb5EBA_5&tpTcof zmQ#hGFLq?8@&kW+m8d`9@nzw7nkRY3rQ(Es?H@19ial8+J6`b-TW2wEkMp;*N=+^g z5_->Qu+JX*B3^NTA6tMsBlnIsBNXwKTJQ4OBf?wEaEVtTV@2_xJo?5W*Afw?CgA_E z_a$(06jkFWC;}pgBBBTla_o|s-RYj5YXit8*(6Ig2iYWC%4|<}&+d@fnaLcR-Eb)$ zc%h)8pa>`^iXeyrg35<@9~_FH;*B5*g5rIk{_DM}>aOmt?&;Yii2Rw~_epl9>vbLP zy?XZ>pmm2zb!!fbI`L=-0Um7l;U9L)*lRO^!+8`)aFw-{fgtW381sMi;&57YkbgapZ6FafqNMZW7- zP7l->9A^SAMq)S;0W~PFcY|V!CxrG-!O+1!P^N(k&O_Wo8+a2XH*Q-qW(Yo^Ko7ka zJ1t*?4Pti%LstB7(9A_`F?f!H{M9Vp?u zE@+klS|bLt+E&scpFG?Oc0x<*{oZFFXa&nm3XfswP4D0S6RxyC9_h0;v4ajm=yzTi z=iDJ6%OBW+%n3Cec^nKaR5Q3t8}frAf?^WoCFVCpC!=?BVDPDkEA?_2@kBXYskZyb zU#RP+DZa8FVR`Hq4Hn>|YGJoM8$pJ^Hh6b0xO%iy_VEQKoTc_dCV~64;~J*fyaRqP zv_csMqPAEC7qC<`Z5I9Ia8`)5tF&6IDg)0AmLelCZwt5u%gdt`IRXUF(4htXOB1aB zeU9}NceCWdrxc+`&lmZW3`s&!j?S3Z_2}!54Wi!cBmYM+mc5<~4#nVps3amsa2*j` z`coE0`uRS5#JP3Bh!s$=FG=*E&6KuF_7KC8WeH_jzjEY}inh#;0Dd4N$To4bVwCDL zHsxc84E``XeqmI+3Ah3@q(O{Afrv3)ZjMGwO@cSS32_EUuTVq6s-qtOJSR{qEkL1; z!UpkfhKQXQp2U$763;QDugv3A8XYX~;s*#1QIVazvkld)2!@f_waOK`=4t9BaZ4n% zXi;Tk%eBA+=~C-8wlBdo<2377=F!8qTAk8lv)*a=0aDqK#?#S*g>r&T8r$VYDbm_w z_y*_tsoLC!F2ExXP>a7ocZt7O!P*+s-V3{dCAVx}YUp^N_B26atP(LpZBR5~kRc${ z6X}$|1PP)6x%OM~o5n{7aU0@6yQ{R3ORI&Pl`H64wvfrD^QK-l3Wk{~_s4h@D;900 zp_iUshFbciLMmgZx}7%CWi>~HeKV8KnwgB9CrU>lXQO<6zf}Kv;R!&!~ykYyVVd<+_vFEZ`&e*9!#>!Y^uH|ehWtG&t zS<=juUP{}Rl}ejtPS*`Bp9jz>(=fEOR?x|E?VPQ~xbgG88$Ta<<3H6|JOe?P+TjN%Biw$_Xpl8nMlu@ zqQ~46HJddGR^Bv9W;REtP}88rNiLnsk#FsEzQ;|;ve#-_$w=E~DW8SLFsQQ-dDPyKm?=%AnfubYoW+DmkbpeHT20#Vp7GuR;TZyf&eQ76r5t&i6>aRd}Q$oCkm!s zwb`jE5Q!aPNAb-N;ThG<#$3yhs8qMo3O{;YkW3i84&9VxvX>kk(V;G=pkNgO?LRPd zt7*dzu+Qjc=SB-zQ!*J+PSRd;_%fL&{ERsAKO~MwUxo6B7E1>4#O&Z!m>$8yct#F+ zMh9*^vDkf1~nTeZS zbfAN>4jWPvgex(S%cyJ<{n<*gi<@RFK=jq*oY?F^tXw2O6W;{4bG<#qg)hbCZkcZ4 z(=r2Rj?NAmFTyHi4M~j}uw<&PqkSP@BjDk|cr~LHgL`Lah%oC6fn`hiJ0~!ncLI&d zet?_novMYwyq*|b|2@v?;k8|#5Jt{z!&|l6r-xg0E8i6Bs*8K88ijnJM8@hVE32tm zDV;XUWiwq)=dx+L5bFYGx2l=Trpg5(E))t{wxne(!n3S=#x7`iJ)hR~Y+BEj@;140 zZPl{LP5qh#k&Su^&nss?UV;X2iDRk3c-7~IM1U(jduD{EL`Tv2*!4Jc#A z99Ek>X_>0fcs{}$4#R)G2D6+4Qat(s;F%+pLt(?l233pJnEE$>6a++mk)Kn(kyI4;~Gi&QP!y-qmr_v>8`AtBSvgA8E zZK=6jikw<1tz`}Jh7w`nmQMbWHS?ybsU@qFkM*v&O&8NPnLrknq87*&=Pbh{c$v!Q zwVYngW@5dIcU3G9fhc9A2&W^< z*3z|tK?qjOrYu!63tHMB(9JYCH-d`=TP+a&ohKMl%7b7X>s@i_D@*PK-AHLR;T<}8 zr$)|810*uFe5p`~^)7xj5hBv^IcUvFt~H~q5!Irgkz>ngcA;RD;JQm$S}tSSrfL~b zm$s0~Wy) zS&Q{9n|Hs?t64H%qO)aEIkS+>W-_IMl_6}8C}-)cZfDEse91@=?Io8XYbCF=OeJ$r z(u@&kTd()`2tukorl~5g#?tOA-=4959tc~eEUi`=ENvm72Xc!^u%+02vW&;%PF}IYhaS)?? zi2Od?;^jC6Na3L~)a2l3`Lx&@bboENu|$1N{RXKfMr@h2g#i*cg(~7bM`_ zz$`t$*92xD@v=U&11&Y{AJ!5L2;68dF=Rk>=OlKx#A#!#I~FTQ-5e}7kag$)FAg|T zHU}aJdFUGC=<)uXPK%yCtS^lr01yOeC+*orh-Jk|6~nG8@KPuA5TZSVL{*`1lT~S% zXy*ucM(QbnvER4W zbs-@j=!v65fUQK!*e1d)@rmgX0Tmaohc0m;Lh5%bR$P}SX_T7^JWHk9_DqDAc+UQ# z@p$?API99Eij%4v09c&V$Q;6ddriL|EEX*85bEW5j~<3M&4L5PP~P_DI1kMh(P<+p0`~UIVbn!Pcq1B!tDZL>Pud zyD1GUCYpBo1vu<=Ey{s-FKg3@%y#U^zyaBfM)1mMOD((=IyFxV?QJ$}REAlz7-pe% zul@Fx<0nurz(*-VnZiMfR54dny^#%J+ZP=KQbfw}jMHVs0x*D!&?-9sTS zoP~}0nwHY&^d@<+;S*laXi8Jb2U%w>8Y0Oi4QeMBiv(jV-d+Bn1-1mQ|4=-o0eIB_ zdks-JgMFt0y!_BZgAg$9-8Yl+AQVatgAk8-}M(BQBw04YG#^L8wY1xH;TTY){D} z&v_5qB<*1mG~S;x!>@xS9yGH%$aOk-D%v?L!kGoi=IOC5X$gk=QF* zAkwnZcc7D=D)w80nyvj4tXy#0*hqOOZk9ssni^56?|Xm9|&LwJLQRd=bj zfjfzkKR1&MK#OpbY7~>0;z`dLssnq#;r+$?JvZuvPx$$j(@>b_^Nk!oym;N%2{;`4 z2(vO639-+6Lg?T;C~!unwJxnq2}^WJ^@99Ap}0(p@d7AXfThn|ZiSipY}tr6etZ~E zMr*XZi`l_rA6dINspWF26Y|k?F%Oj`3{c@SNdnm;36r-F0)?&Xn}#~_xc!VR0P8d6 zrVS{~>aqpGVC`9`K)rZ)6$Ja>2&53F^(3!4ypV8E$X+CrHwCMNa%sZpkRK;8JH`+g zID0n_dSR)tcFWh4S<>zW~y1CAUpuhe{4OH8%pRi+1& zWzLI)d`+mVVz?L1gs;Qg1W%G;LCwNDoXYdG>XLFeIj_SZXxBWS?j_J52;l?&G7wRq$14o#Orr|V%Ii%V z0;Bf5p=nQ}@Co)*sMa6GTv_jOHrRus2Cj|uJ7#I?ln4ftC3Tis3~e=dRW56e)*j}Y zDIlrE!lnQxE42>d52Vtf;DuFiDUxukW0_~CW>a`~n$A(W>y?&kVVxl@G~JV2 zT5~mH8j7PdCsD>@P1snm=8{bfgKenhX16Kk86rH2DPA>%)|z&g6SHc9H=f$w)F)QX zhmvi2zZ10={8fWrTb)v0pkFGDSPC)bf|Sz-Z=F0B0>3I#un{G(8bgHLE`uSBeO_RKypCg?$Do(k-(wuAi5_+oBdxl)p9^*tE8=MlEf@+nb1)6tbcGFQ9yar3% z6#=m#Q*L=fCrS@ED{K5IAQ+qA%toS2OM0<0sN??5+H|oNIT!4EfQLj`D5`P6{!St^ zuOWb%WnInGZSC%oyU#K!&U};KKlO*mOepByV_GX}F%>8wK)91# zGf;vPL>d7Qm2BE|E@n-GH;zk7Og3uK_7l8Zcg8w|RxvNUc%SPVErsO-q=2xC4Qt&>j;703;yZKsYgcuP=EGyYoN7nXb+>!tbIK&_ayaXb436P zBYH*GKqf+j!0(?JD2aGLlI@Yn{ElBqQq+f9i?D(LAif_QmBf^B+g7@ZqJcFXxpf~u zI98W(h*d042$lE}LZv#g{{aTDwKI`jmum&x*-&)q&NK<3)u(;6KAlpZ1Ilr%rB{&V zu!d&EqqPBZue$iq;MNFc@IYNm8gb!gOq|t)qLeS%hD*avnb7b!0^gMn56|O%_b*_S zHj4p1U?@wQycY9J#bAfuH=9tJNsatZzt^MVhlJ=r1s@voLfezLH5@U}pdqrls@>+{ zB|*mMq#Rqorvx~xRnsXQr>-;a^6fIU0CQBBj8Jd2lSE?ScPdpY4KOuVtH9w9$*@f- zv@~HD5g=Bf)G?PjXsaV~w@ssQE##c(_7(|)?wh4WeQGmui4%)pLtndET|r|Gv#QKE z4Ss;RFKsS#ta-r4k!#DqF$E2a0C~&;MDw16!j!Z(0ofGtt^w)@4j?>(g-zsL-4eS1 zQFj!c35HP7R0>*vGBw1@vB;p!!o535G)?F@P*+kg6@^gpED>+ujy2}`-Puv4F2%@9 z22SW)MYauK@d8Mg0o5YcD>fyhVK268Qclx*Q}U8sdTKSI2(hhz^b%1IDzRwU zoraK?22on>%dq%7f!lSoCL0Y4i8EN24F;@{~WE@LX=t;86ac2`#=nS z7ceLSJA^13w?_ePZidK67($<7|6tKD4k`tT6-VP?bc{`pPzi4(xJgCNMz@>LtvjHM zBmV$$T;Y`F7cL-L$h#$s@WGO)SHTOcif#Ua@(Gn2Px1>617sMG0=b4)3-N%|(pzaW zk;4zno^G_~2$wU6P(q7R^r11fU!h(D>VstE!&{p=w!OtJ9^S{_6}aSS*?BBs%r-}1 zO#@I2wpnRVwnP?r5L}~EjGv9gri2Da1YosVy25Vb4tNhA! zH@*l3OZxEIW$Tk)y(6$^k^^Hx9q-B6O}K*(e-A-J-?Lq?aTrerx0&x%sWO=aKM%RJ z(Rw>5%n4w+U8NT&XZ}a z8;K6%olOwLHD@nVnc=ij^IOvch~qb|D}B0a6s0ac=<|`M$-(j71y7#1@OFHrP+;6Ukb{Z0!;|L`D2LM#T`zlm-M>MMni&jxK$ z4v}xIDX`}p;V`*ySxv4@7*^&&Er2}w~}U*AElAk~Q2 zZaX#e(6Q@;=EK?e!Sqc`Q~U8Cg)<1f3fv7DbZYX|o6xjiqTg-9ARYj?gzC_lhKXHZ zrlegi$$`+fpST#Jk6cs&J*R7u;PiTJ=;gb)}s{oM?<;)&F@m? z`X~I5s(_}@K-KLYQ#B?*Q|UB76ed4bW|+ybGFejqbX{8Yw+!yt7U8xgRtjJpJc9^t zHS3L*lp(XZz&t>Y=!Q&Aqym}s5U=0>WkQAG^vw3e3e@9w0UJ}9(#-@Rr3o)BGGh(` zcB`WYA+T_orHuh)6}085R<=-&AH)OkKE!BNhO>sBP!R~ADFihzJ@g}eCBmvjha91U#MP1H6_e+$Dqwp@J`{qW5Mz-FkYIM05Nks5}c@-yriY1G?iEd zjBFC(Xm~xYKt{b>(!%@Tu$BbvsI;gQu1PFHdPEwaT z@@%;vM-3sgHy_BkgiahWi4Y7c1?FOS^j++$DCXXtW~1GVxRyavg9{8VbGUjvt}z@O zGKO4s{>S0kh9O)smyVnZeVaI34?2o6!d%h5sSG|cQ1p+SNbo-!9v_K^be9uNr!Vr*tf_*yr zL!7DbiQ2@#fGBN|&U!9n)`9QcS2JFy~5CY&;jX}gmy%QT(gd8=~xdPLfk{mLuqY2A!EkCk(jiWM-TibF} zZo2YfQ1cF%&@>_&d8ThF1rCHrlnczhyFMtGY(^GCKMo?npi#wb1k0lz`+Kt15YchE zf}SNfkwvStjP6){pfnoP3Imyopb~3`zDy0sHZ+kEz|BGIBFbMiA*P5(fc4ES=3aN5 zQ9)0LC!&x>1hyOtRZuC!a1^ClhyIFwU?6&6buw^pffZlqtJQQ#YC!HM0=qTF;7xWw zi2_NMVCB*#<6xCq664cpT(Po}JULmPwwsbgm00&0?&pS_l#P;Nt?B@y3>HqwGGeg< z4s*^(>ZfW06m**@AVhj_3Pj=3(JnPo9H=C z)@6}$g(zOjxB`P0asQJC`!Q+TAS4tN6zGjx$4FSjaUK=U8y&%o0=Szbm)4}vInlr0 zLJ-eFaM9R!=oSS_8wg;;q=B(dL<6I#08$4I5m?+kad#?A>R@{j^sT@L7am9U0IqM6 zlO|jnRbt%Tl6)fJCeada$wMRhVE0%AG~;Pb+;WubN|=Xuc(T_ng|^b5L$Yi?)?J(^ z&2;bm|aG=uVqEb>t_8BERc+ zh}u~;Et<9A^sDeXMA4#x_pH~)8V1bodS%O`N<9nkO|gtEu#vRu^@Mc47(5WA&{V8|KOEI?!=#Hsv18t^m-*DY0z8hhH*LuFW7stY#tG*{FAb zK1%+HA<1Fh%`nu(8&VXgor{&$5%A2VUuMgIPwa~Vm@c~PV1J#NKLl8)Y&U_0hD+>`+~sb|OjwF_{b;O`RBIb8re;C>BkE zp;lmp%TfwWqz*0|n8{=VxkgtmLZ6Ly1$mhBWFv|@&r1}M&5bVtOXCPAEhi)_%yT-I zn-V_3g~tZSD)8|4`EKJ-TKjL_QtZ4CzwjJpLpc{?1`Hb#WN659zHN@;R03+j;|^^3 z2>G$j7ONnyb=hn0KI4$>j&#Azb>1r@*IoIu~6u4@=TulzO>-aDvLMD+9h!8~N10tjk`2Z9-WON~a zyqlmQ9~CBD#E~onFd$NNp|`D(BgiR_p^7Ecc6TfraL3a~|1zeNGi_mjkO2Kc2F_g= z&%l79`EDTO1SNmArv3>>_b{a3Xt7E(Y8l{T!-#&!i-Q0M-V6`s$&x+-?pp>2>@(C@ zL=%Wa>LkkDNiwTMKN?SD&?b#$3ChYjk`CKGH?I*6h0tIW1$VJe0MjJ9So8#{@okgR z>mu>shIoVkGfGjuf=PKS3xv=%R)ZoND}%;~o$qqX5Hgqf!sVg}HZFIr40mg#57WY= zo(skuABOXyutO-b3x&8sg77kK)Q=Pn_~z5gfgMM}cNn2}v3Pt^2+_kmhH^40`Xc9& zPt1!v#Np%$lr|KQiwJT!Y==aAai$mgvl$GjK3xQ4`$xJleKZ6}N9LE4nbXy3$2O#X2TH09;0f$(fQaC)JAjIHm zn?*J)*WAiyMfQ*VYyP&?LEZ?C+LMWp(&m#C%cih;C{DLh862L0MfM4KX5ZS8b?euz zV%{CZM+g|B#XqQraA2+@WmMc^4hiW_dOu6o!xVFF_8#ELLbTg)y&i1o0~Z(z)@PwP zEXxAzjF=DtS<|cnM!o73Qn?gclL`82fvS)SkuxB6Kh=la|&d8=HTw0$+1}L8diz$aut=Ag@2#tWy zbP8iYSp}Dw5l9DQfDq>hTAh(e;Q$C}5(pM?MSh!lyVPrXP_U=P*Bz6S7lK3o{*T}abdMk~yFG0Zc)kckDQ@c9-9-PYpxVyJHlL3k_~ zNcCi75gu2AL@zgv6Qtf!r7fk_31<=*p~Piv)*up!S=23yrFG#W1J3;>m7yVXk0$i; zTq_9YQ{4n7v2rXeB^Zp?Wx&vLAe4BfwXQLTn3dndnm$32knFFdYU(!SpzM`ul!U;R zB}5%SnK-i59U|JGnnBCnC25shEP4gU7(4P{Vz|{pKjc!viO4^&_SX?ku=`OHnEwPK z1TrU(CRiaCH-69$lUHVPVZ(r-A){5Kvt^;%LqtlSvB}MDSe4nNc5)`GR4db^mL!?7 zkA}G?$swRD!z$W9kIoJOHfP4*5s|m$V1{nn@Uf{Bp#`;;P0~3j`9s)h( zZV>=$MATqa4B(o9Il3#Cgg|gV9-KxoMebVshpHTL1Tcjb`C?#TfZE~di51DUgE4_2 zu+$-?X3w_i!wH}oe`cmUeu1I`3a^!R8;tBUcY!wuv@uzpl>ltplQy=_mBgzfKKi2H z1eqAx&{ZZCEtADydZ>0`(>NNuoc-{qRe&srR*FQ*fT==ka%-wmZnIeZ3M)V-;*{U* zIp`_b!3sfOwySeOZu}k8%SI?thKiurj?i#8r?_N^MgU4n_lAi5ur)=(X^J?JBCg9O z{IF>z5DOBDlOpNGfdtdk4Ga9ns22b(SL^cBr63UUQP_D;P| zmRlsXRJawV>}ok_Ba4KkU>z&F4V~ZQ&HX<^QezLF{@cjz6GE`u& zv^YPTWDFB)~|hz<#Co9q2SQHaB10ss`O#OjPxe4(ME zkimhPUWo@yRoY>hA2N3qA&!N0Mk7 zc$&UlAk%i-29q?*Fbo__3b6vxNoEQ3x~ymvd|cs3e(X`sE*F`ADCu85#?phQ3!+Q0 zUI%5<6^iF@m2pABsZGZ!71pgmGU-stgPsM`MgzjHC`8$Hl5f%j1f z4TZHia$^NgVvdGzvOE`GmJ9hNEV-r2?l@VUZV^#Ix#fb3L`Q*IEwELMYDcD^F%2Q0 z(*>Htkd-k=cs-M=+5;${IF2$c+ir1NiL2Iu?hNW^rB;T#|2fL~!To@z+Y0n358?_~ zyqyTt3RVHElx$YKj~YL?)#e~!9svHJz%I3UY9jXC;*$c~GcPCrGPhf3RnQmxpd6hO zD>J$wO;}y5S|P%Uo40B-d1@#YscMHN`x86_1%sV@k#9VRi}5f~?jH;L0Y3f;o$#t4 z;;tE9ykcZYF;zTnblvje=#t{nvEgO?LBoC+R7d8ea&71fBx(kHLf+KV!h|X4QBz3G zZ&}&-EGzJBH}1fqlsh#v%HwUwZZ%P__L#s}RXd<0KQxf3nYQk+pdp1gIrc7YGcH`g zI^tk~l+u?Yi6lXTu;L~XyIHo7Yb_|+uqgDkc@%A*KnK)O-zXuD`o^G5k;`S7J@`U6~`%v`-rG25Ux(pRCOQ$rghb*&hBoNUw@0#Oj^ZC%}K_N zu|ZT~cP0@;`3M2t|2hXs4`M0I8xEz2=fPAT59BB{h|b;_-&F~K^CP0CFhIqA#M;Tu zS5y-fWS1yl9Dk^YKyLObt2J1oHe<}W3Kxng+kgwEzA*tS2{+-m=-{+546J0E3C~Mt z=~!SjK^b~LnIN;QZzi)r3kJIC(VYZ5Vm2V^m24AQ)JUX7S{IAZ^sLMe5X(SHH;B)t zi;0x+?*uc9LYg=k6w1!$bw$X0RdB%W6kRP$A`-#0!xPg7vH44h?&WO2IYOMQaU(Z7U z4xm#6IkZiW^gI*{-&SP-Tt`|LbGsAjg8gc70MsdCSfezZ-!REAz`98pIq#Imb^YR;Pn$UvI^R?>13>FSVlh*M*!6VQmNaa%}A&t zmEdF?A@|%bL;z%Ue1q@c1lIOgwge3o5~4dL5Sf!9C3Sdy_p{hO{)L`wC@!+-6wh(t zFym2D*63n(IPk=lpE`gUjo1NDkI$6iCNzN<%?-W*d92!XEUXzmfOMsGq#C#q%YKH&i+p1DPh_Y2OO(%cALnILm<fdtWsX_EdMIUn~p>op8H>xBaxf7A0E|*f0G$rAX+IFT4aso#7aBN!5csw)` z`_cRsP^qO*OM)tYldk;HP-nv*6HZwr5J_2W6;8qblX9#x7zyu9!|(ZBx;(MTsH9W< zTudw<-B2a_w3&Im*}a-=0MCo*slU`EJb7%83uD5Vh=&#PJA;wxNkdyyFoLrv%iCz9ShxlJ zRji>ycm}bx4P3oKiA^vxF)x$Yu+`dCkY+-AP)#GuH~jQwn;j7e;ciXmharbUZBO`M z1F!bScw-O22;)1#Aa=A|w$H6-Txo=~cJQa+7YJC2L~Sy}4KmrfykXowhNRCbPt#($ z+%QIW&ELseA}wb6xAf<_xQ-;#Oe8d~^-ZNKp!nt3XMN8e83W}esHyjCwMa-+%ikiU zG((1@82B$Y4_;mDr2Uwog{eembP3?&5Rj1RLJfW&Y}~l4GP+Eap4b?b|x3xkA4XFnXy`PgQbMl#Y zv2rp3&FvaqH`9-Mrp~-@ZyKrZro0<11>zw&RLEakY=yA#msK2Y5q9^YP}V->x?&ly z#@x9sv_6`N?1bGczaMH>_`)fxEBw(Ow!mQ=$)1;ii z!HRa4Y2lId#c<6uKb3{Hw(%&xQke913bqI20d2`fKds$;O5P}`$Y2;Szl|mI#U6AF zVdC>pvk1fQ!ZQ1uhN``h`loc|D$~^f(yRq0u zk}{glnX@EA@k`87V4C?yY~^fo5a*xu`ohwsNMHQUqb&Zj(IMz}2?25k!>B9kD4xoj z^*lfc=>%%QGo8xVEL}y_0ViAZzZRTqVT=wU@3qg(i{F~C5_oT2@+YkKm5I#l=#z3L z?|x?RTSKV_t#(zZ+;Sa24hED!?)bT1DI?&m9d3>4Z^J;V0Zn@rd{DDP!Y9(Rvp z96sE0v>GMhmK>$+&AFY9I~HqQdG#KJ zftcF58T@pxsHZp|#kx{s8m<(AZq=fIDw7jM$+5%CH`}$7LYv2n{hMI$qT{SARU=Q` z2LW%*H)_&~eRm|>7k3e)I=_R67<%oh6zWOGpA^7_2dfY?*C2L=z8~o{nG-pt`1Nvr zrF3u3N|+9#`{6yhR0T|K%f(HY{OYl63-_5uX=ZNcsIzf}EUAzG+_}?2vKmuZwl*zz;y-9*mrG z?q2NrL$ll;UT5kk{{2$f=iT%S+S3X4#_>cDRB5;@G^|uaEspi+(8%pjEPobsfGJQ3 zyIqsame|iC$dyv{urQ@8gzt&aO2Bgvg>RV8cSp)S-x_ZQgX^q9u&xC^5K6vBQS`+UVhU%)`$I-CFhyvI16*)=fXk{ys0l;MB z%ng?Dk^4457pe`aY~=?MqpuQ072~;~=&hi5>%Ne+LvRcAr|1{!$ArFQeT~cb?($nx z>XzHwcLkmF?5wTeww66Awyp>|(=Az3e^an-CI*eDN5*_eu){uAy(n$f8fOr>_snG? zN~)g}O1krghB)X#<^_w}M-(uKlt_dqQ*SWEuUSeHmq_+?14{4H&8dIP~ z&I5pkg6a!ONfmTg*97mF^ZC-ZRd}F z$fYzADD~k;fL)4Jg{EJodZfhw_}=Ao-il2+V2NmFWn$Y#i}1az{WqGgIhPStlj79_ zW!45`reg~_|5tzla)%=q*{31Wpb*WrT+Tr(<~^Rtu?z$wC>2s$FD%47v=ia;7rreF zY)o{`)Q`M6!B*6AwVfmyi%s=h5d_?x37(SWR_o&ltoacN5aH{t`Ts^hA z3IHn1ExYWo8n4*|WbdrjswO0$UU>{*nU|t%2Fl7h~fUlJW=MZM0WWgbe8aUG% zF11Q9-Vnh0V-CIhX;Mg0geN+43?J0*hWg1L;uNbbK1#L=Enxc9=drg;M|x|&G@MJG zZ?h}RtaEEdM*M13=EEQH>}{;?NH5%z851T*^_x>`Ui?|&Nw0hphh^2n^ zj~KV()mS{e;Iu@yr=GCyAUYlqF7{ z$&(h@`jN*Brg%TVS2Hulp4UAkrOa8UiNnOef8i)Jt;E&(1f4!@HoH7zmaGF~DHNP6 zV`w;H>!!_^5BGy8Flk#_4kv)M<1PD~G*0@9#NZiM`dV`hoLE|ah9e6O@N>6j*xpsW z1fp*j$?TiaH_?D{&^Mj8D7kOLjp#Q_$zs&Rq&jayjxlNoC#$6&g=?B%Mh=-K+tPM} zoy+Y%1P=qy}2FQ1jSkFI$M=Ixl8xh^o)-XvFbMGf6V}S>7%k zT;)jc9M-&1h84@oNVV+CsP43s9gQ6pGXUXn4OurT2YpHFFr`8@YMTdznN~YJMy}#{Qks3|RVMAt9$@Euds5JiyxhaxUGI83}x1dO% z5nl1UC=qC{o)U_-5q{%S4nd!`v&f`q6naIYt1vH{9;MbHw`(=WRH((->VoCmecu>%=!Vr4IJl2%?xZSvLhK=b|p?K~(wxW$?L z!Ema)w}$Bw+F%689#G|-=Dtz|IL|aA&@if%DFhp{_1od_g-?GetFdo?eX`p6JfkH7 ze33#M!|WF&r{_pWPGT(eXr>s13QJHJC~xuDYj=A_M>8Eckx7tf*yn|OP`DT_eW}xL zJFHn@i>iz^SmcEU!QQK=jCm=l>XO-P`MgD#1Yi7PM$T;jp@Wtdc9;z98WZEGRx5?< zoQVtl!oefp=%#yYTAKNx!TK#oJ}JcbAW|xg1(K{e>TsI`_Fv`C{-t8C@;RP5Dr_aI zL@=UIml?S6hZ_}kd{}tHmos)?64Ce%8|`b3BVA6u4L|+M+rmzfpMclw4YFlT zWaiCMazqrX)2bocxRt)S*|3?+)Ah1?i{m2q4ni9$Eq~UCwd7^GCS+_e<*8Z=4 z1o;*(8m8;Z(QDJ5XU&?hdp0JkhKwGEv9Ne^LTL6{jG6nqszA3}a*I$`UAT@BZ}(g< z!U_S64^`+g$vv{J9n;-H6phnvQT=OI4wvc!3leGznCCD!f(-xj3=~QX2OZlLD8%V( zoojmiqR>s@I+-?|APZv>rQd`K?qV+dI&$*nHnY6B0GXJ+;_N(yD25|VBH#8 zAYF4|UE70(Wdb6+UJMJY)@kZQ$&iorHF5%b16(Vmmzb^+>9VJ1Bo#+#afdW?G11*D z{_GmEZmW5)3u}s~91bCrSu+Z-vnTJh+tO3S4kQ7s4ik zaRkAKMOn*v`V4ES5`aZ+Bqxuwpo0f~cY(U&<=lhBX^AGkz@&{|luTtZf}pY5RoK0; z6yp>W!+`T)TCV=|Z7YU&2Gy$a3+iMlezM&obSB2~0f5 zw!2%09>_~1=Q9U2%>4ddQxo0Dc|`2NbmUsxi-9+#fE5#INNzn=20c}i3{%!2OzVO;Q$uoheYt|g3_8^<`lcln8v5|u6iqMp$Wod}D^H+Ip zmAQUaff?6P7qKYG2u_Xch=$b$s?;XDZX-^8+HqA9D&PCbv3ZEiXYTLaTZ$+63iFFvnAs#xUA~oKsS}TamvyEO4m3b<wP$K0-oeyo?a0S{T4rumG1pX z=3>u;deHGNcyYt}h;}3U0uQztNXU(o%&u0@t(G;IWXo?&XpF5aw|Ce^(eb#j2t z_(lq?b<(Lb+pAaYiM*JvoMqOgZz}LNs}9(Dj9L1mT8HF8sj`sVAir8HNVe1fx7INf zk3j5w9%{om7;W=h$IW2aT5JCyl0f9~Q>R7k$T`UDHSdYVMWs^*xL$7OfXi^2in`7` zMRzFxKyS|D21(gABA+g)_}Z)y$H$IUb*aSN2zn#{!18MvZJuU9suaa8lVsCMV)Kd!FJzc*yZmkpzNtLh2(1Aoo48j{HzvEe z9W|;%+G8hDmH%R#y|F}D1A}D*ihr^b8S`_i2}owUVdD{jhc=;N<>XlZsdb3}?;Lntn&*KdOy>WDI&0ViNwVAYX*@b9#07LJgN<7%zru%3{~Cd#a1L0@Q2Dh zA8o*e8##qjcF?|YkpP&Z#cgRu5qZ>QN}dyU86{R%%G=6Ws3_t2$Lf`H7lU5LAJMVF z6hWEDtkLVX4Mc+owlrTi?fkA>ifPMi$pI^Mm)S~vOIi-wxAf;{mwNk1LAno4u8jcC zQf$;h5O1@`<0clUCd^Q09)BO6#uLxi+al^ON$s@ozF=18-Wc^M1ontD1Iq-0X&|hh z{SGmS7A8l#k{>exkQC`CDh#ss8D7|@2T^k4Le7=?%p>J~G-WA97Fb=X?ldYrH_c;H z-BpZ0LMOjru%J_O!u~}1s!++nDd{(CUU~3wf8l_~u}5JZR5<$=U#?MqrqKf~OO~c6 zI@?Uf{Q4*BOO|h)^qMcF4X;cWW)PF(x}cowrCD*8vuT+Ma79|FT6pM!9@Y0TOB_Zz z?8$q7uvk^3&hlL37IDH08|c(``BfZBk6g^t-sN~P6I^vO{5ODTEQKse>=_CLo!{hO zAyBdiS8EFEIi(+?G>EFm^WJBrM&cg13fYc|1r860W0Pd#smO}htJlDXPSyjrz7j)q z8H@UjGnQ6FsyTWAIXnSHPNZW$T#B|rX?EiUEnH5sA@hho(;R?e?>)# zgR>HeUb5chx^T2*L7u40S6azf_TJsK3v1YVqsUc%4>$t^xCxCb6AmTn9o*iQ{K>-b zkL@|nHGXhY%Cs5(nXVOxu3ZYc@O7zAk*r(Hh+cjz$nEfRxj3c!+cF}+2yL9i+vnX1u>+SaT#Fc161 zNhCu`b?(j4l-P^0BaJqUhRh4%`iFm{Amd)Tazon}YH$JR9wHJ64hfM@oRc70Xy{ry61OsRydo*#j$0^{u`F z;-3V&{w?QyJU)qT5B{so;=m{Mda4lcIQ90hHw-=W8sBD z`hz+hUdOz4WLG_>^X z7s=)Wq=@8#YmaT;y^-+6&XSfh!@y-DJj2e=KsN)@#Zdv6`6<6z`+?^0mC*LqY1EFC z1d;-i`evu*t;#^hyL%c}5)AD5jQt754a5GlFa_`n4KPzaD@Ip_?jFPwpVm=tIZ~Fs zWNJ=F=+(zr5Lr+UMh7slog&v_k*C)ZCCbE|#jkVQEZ48AMXJm1Q%fPoYK8CoGM3ih zuEEKtUEcuEDcx1?<3|Ek<7$l!L|tpTCkd&h6>@OR9Bwfa%WYh$=V#T?vFc*x3LD_N3Yi^p{_Pz# zw|F`Q>wG7k(boQ&98EC1_dsd+lAr_N6}@Rke7=F-MYhlSHQJfTZYEu5y`M#Ufot*k zKtGS$E2lI)savSsUmR(JYV=?YS_{xFmS_6hy~Td|5%uk{{8?ebJ3!rYQS%#B{_m@H z^~NdW5LF2Yp#_@auyvUnIdJs}NW-dlTFEBaWrk&0XCLDZ4?(R{x5f(J%mg8WE@c-j zit^J&QN7B)0}ZxVX1@95s4CwA0WGV+eiAJ6p`?}V`ZQ)+FMbt;i34rBCMPbwoJw?T z?EG|t2Cs5|zO34C-086odykULg;ol4*gGppmwM~b^I|QiU)y=!dMQG~LQ!npvFi9# zV0-S?BsBr$5Vz1>4OeCzT56qT7go_nbI8J6^K?bjk36{XB5hiK*Tx5_B!m@8 zTX*Lo`qAn4rXc2QNQB%)K0S6hnM9sJ=EbTH;dg%+Z_>WF0 z6$f)eSmOpZiy)J;*BePCe=rH%L=6Fvsqjx|_*bEKv@XpdgHy+FOAR=z!JV?FQc6cH zS|J5TibVRpW3$L+eA|WTniEc30|G5#BJ4C9b;?=iv_SZVxs|ge0ECsEn9$KSVYAdu z>9EPg-I5@}D*#s-=O?4#gFUsXiXOuaBpTFP|rMM&zm;TB|;kE*P;x)RZv zpvf5tj3(RBBNA33_g-kv%_dd;1~wFTv@Eds%Vsh<4R}I616Q6OEiwKcBIV?Qm<^9^ zrpqrK5Q^i64YfMHSpod0$x~j-sCI%TXKL|=%)Mwk-+3#jn%~=zge-{}?}Z31)DS;b zWu}@$zQwsSB2ZDTb#CX92fS}&{fxgFiDD}>MY$YrDKbVK zDf4DFdqZ%ax(w68ltnEmA)z>h25Y(RqQb*n(897dIwdz|HJk?vovqoM;&@Cf0}dv0 zLBkx^Wp@;&$~K?ho{tu4NX2m&L`XYwh1g-i>@pA{%x*1-weB;Za?oxeO%Db^Or+7m zGqq46XwYv9p%^UrxM)O7-C31(uOOHbqr4Kt-f_MAg1I!)=Ps60NDReXErb~KuW^+X ztY{jP(T-pC3inViym%n^r-^^lOx^6IvR4iT@?(C*6C?ec4}by%|E$Nf`V6dQb3){0~d{_Z|ffLp8T zv?l-Tcc{)-Q^68+;=NM8k-FAxQE5VZbZU>fQo!WM2y`H{uohDky$Q4$n$tG7kOFU7 zu#GaY?s3bIn-(BypUG=@6STCV)NGcD@pv9KthqeaY=gnXVf|QH85r$1 zLT4MdHNE0S?m11rAy89bROG3=)8O&Ktbdviym^xKo3bPVFV8+m<6EBl(21ifmNs<-5q< zb4l22ZpB)YJ$j3YRJ?seqi9l!A4^?`7TXKzMy6@->9}ssE4!r{Of`38>zwz6OIO*& z73;*-*`4yyxsqLiwP{45(oet-vZx~&+u*hdVGLyLCpmCGeX}cet(Af5=8rVhi-+(o zaT4k_soD1u)EzkiHQlw28d@j%bRxhx)e3}?An2y`QPByY98?EYfkT!)xD>G!+e6X!E0S+$XoV? zyb<{#&S3GW@A7BfRj#T<7iykfzAl%H*2>Yf$H|ggpTk+) o<6lr1m!4;XxHZJ0? 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%0DDx?Me=)J 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°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%0Dpk9!%Ym zdPx?@u2I-tqhwLxY;8{MI{B$}!8+Fg9m^2wDQ0TJwwqn=cuGy{o`u=>VifPPb^b1X zyxSya-%=`ZDK~fLv_P3V0&3jP&u)2bex>)F$}wh7S{UyW7<$KZ$hpy?WJa@N&j7Og za6S&w8kOaBPcosw$|0$uX{DpJTgSQ5M$&ajRnwI9gZ4o=syFX+Z1WTgT{~9jG5o$l z?^#DE1=gII!F{BxYcsdXjCe&Q`dq~+o0{G@ql~nXh>Nzlvo>h2iy~4*>47qvWPRah zJZI#GNuS#-!y)HjOEaU%%w>qNz&bo~7`e?z_94QIactj6W*w(G>mQt3$&yt`nbthV zrcJ;KX%}{+ndxcj>YO*_T>7DH`$z&pE>RpXKXKf*9mh^Jet+J={SLuX3A?Wik(~w! z%ZG%eEm*T-Fmg^3(&{Os0_P{8EFfY{Q~shDC(YOZdj^WH}ht34`yZ@*|h*=L9)zwRJXYgk~wLmYx;iI|93h@)hQR4 z3)zB7ggfD%z-txRJt58dho($4?r1M=@9mMpYi3d*8lP0@#!8i0PpUlV*QTBF+(LEc z7@dDQx~@JwI?f=qj&74Zg-?&peLT9V?nhT(NsJCD2^kJLX%Ui%LU|TvP4;EW1A~AZ z$f*@N7Z}myqR4`2QI zKL7O1f9LPt>Hnn)zrX$Q+yCjmfBpVnKYn=oL;t$`{-M`*t$+Pp|BX+DlzKz75u9EB z65W$0${PqJm{1N=72d#b1%JHxhk6YJ{Ojir`Tals@#cN~^((b~|Ic5(`{%Fu+n@6< zLI3vcFF&PU-~aG`RPOBgzv)Z;1|Fa^nA(my1~mBABE{dP^+E?j{Mk2fWaB`3F4wYI ziuGKu>Y5HFC6B!4yf*X9`j+_}e_;(!oa;_`SDbBh#D-PH7voKXo*H0mbcmC|A;^T^ zH~MEf`SX-ok`1thvE)!Fwt&yEb({5|+*i73?_jbtNSoS2SK$0enG=eyQ2ng#oZB+# zK;eUxF;FAPSRjQ}+f0emLMs(Z00dpA&~;4K9O)aPt=7VUEX{!28M+kT6Ldc41Nf$p zBR&+s&~r|@60{IL%AoL6~f{U;~LU-p9feDd1DAg_Tyap9qlSqk^= zO{~y~$?alP<0E}awCp504X~6-Wk4x`?gNzzt7DH?YEsCQ-+2_1K|Hw?t*bBRK-gdSV_QmL|CqoYaS&f1XD zTOA1TeEvXwSrEfP+l=Y9e&u2H5OCzm*>9FxK`S2B*VqgF0V^!h?z> zsRTvA95l4GbNS~6%$Qz=bQLduA8IO7lx8pL@24wRv7dlkCvNp6fj&_ zOe^$b%y^1VE=M8DwbZIqt+*gE<8P?&mUD96j7 z?-b-yLPKcE81GXZkUV4u4o|LOf274fy~g>=zCw-D*Gr({x%SQ%*YEfC-i7-0k-hi_ z`(M7eetFUMy8!vZ`u$1!XY-AcL4)I3r{jFBi1jxQCWKx}tK#GOP*Et48wA}*Tc9+3 z1yEc~)Ai!+?he5rxI;)F!6mr6I|OI3pn)a0y9Rf63j}v}x5a(gpXdGRuj*Ufb7rRM z+MJr2neJBf`I=AM;TdF_Fa4Z3hgH)eA7q2ro@+J|xE6{@K*s>jYhg?S)bEC83z(v$ zhI4x;Sb+s-x8>>RIbB{=_*)-n{*EscGsjWCWpaZ%-3%ub^9|GwyoMVxaExUDDfYxH!LhK}VS- zt7KBLU6f}XNoNIL>Y)*H(1ol_Po>&b#`9&u(#NSab$6l@5% z+N<*<={&T9;E1wK8q*g#8=Y6HwO8Or4U2-k1wL5e%;Lqi>}hikHMqw$ESBYDGm z?7PHeK9r_ zy~1@dA;L%gv*5yRh!^~=T}qS%!#yvOr;%XymIxiVuml`4N&zmf$Y#{n_3MSTS2=^Z z@FJ>DN(aP5_0exirQK?o&I9T0RwBQ!TvtL{8;h%Nk@Z4!wjLY!-A-@md1O0N7;W}1 z_%SoC&y#pS&AJDp4_(4}#UUXAnBC}on2@g9bDePHB#Ci}M<`fi;}J*(8G19J>okKl zhoNQPSJ%e8pWxcu4bL|#Uaf$lZT$6N0DN<2aZFtnMln>>fsYQ1=&>v8 zlePAHSp&X-1Hy4HVy^pPo8m*wn%Z~6P+!eoE*(D`9O4jJb6QJV{T{4A#`h4yPnb*v zUlR$wn#28aTb_nl4!;aUuUT&I+4<)F+=MC8dn~P{WmDFk z?F(O=E;_en2HwY2Kq2<0P1q=bY@-m%&*2TVslNOY_{g}Ff_QBLTk|(BeVF)Qx5ZBz z!21V&r+dz|t9$UKbCJ`nM6uvU$6qR4A4zNY(5wW2cI3XC6r69J5C`;m!nzr#RLR#x z16w=c9QF;mjvL_W=K8r};q{xL3RNJ!&tG8Jgh~4TIOJ8khT#0DL^ui+W3uU2>)Esp(@)X_fDP8uIdR^e*K?L(fo8t3GkGn^O0AwF| zo9s}+dHL3`Vg4+DFP*Xw4?^~$EF32%8y0K@QPLXISU!!EN9I@^4RnHTdH3|Lxw*h? z5cEd&E*83h|KOVJ$H4XK>~_G5on{^EK=)+yU^jH>YnHYiAHZ7qQ|rbPU+tc=-M;Cj zs5lu}DR1*Y=7an^1~}Z+y_vYxWK(wFn;2JyrOxKbomFNa-Y-z1(t|6c@7;}2oJ~t^ z1?5tY)N@CC3~3*v&+^v;lW>O1zFguo?*lG`!{HuN0h#PizrCWIR*N0rz*TaKy|UKl znlJY}xgIN(Z22JwpykY<`%sG$_{Pd{m-QGugX?JF2h~$^WT5c9W=6u74Y(czmqLmu z2hkJSHx((D!6JM9MCkxbZSiLQteFEL1ZDJpo1c2qDV9h=>qsjP*!}a=M3&In^HZegqQX&X|#Pgb?e~mg1UFd zIJkNmktP(}WgD}Xh0cu&;k494=<*}^95!h_ya$Ozku$MTtk=Z9Wo1*OJsq8l4H8$% zF|qP2B_-XI>$r@z7^tgzG->6D4CjvaPVyhKLhcnAN4vH~cb^@abc3^n9iq#@9% zFtgL!Em@HX%kn!RV>+e`a};USO;A@W5^EP~9!BiEJpN7dnOeRyb++dDj6Wpc^z67} znDC~kf=TMt?7KQ}F3IP#hCCOmx!_o^3Y-AWL_;Oz9VRO@i)G`KKe{eEv=~1<4GD)d z(*&c~hd&wwOtqeVz6JoY!9$aQ(B@6E^6;dHaG*6&OoZw}tm(KwK>y^lOq5USM~(EG zkU!JH(#HvT4q4*;5+tt${yTiGq2SCo%4flFm<{GHdUCaA+Joo zA0H>Woc^k=ExKzN>FssTntjsLtH(ppzp4Qmf!1K_Fmmq`hqfq zW68F82xd|7hv`=DY`~yUMUvcez{I1WTom1G04@qMi6{M?=Jh1!*n+9$OZHzx_wjXu zE--J~!EhwUOJ;3VfA_Yvx!&{NtuOn{9~Nx}hk+!ThvvnAk;uBhpmktmxl2MI^uZS_#X3iSAvD7lXK*fkm5Hw5DF6Y#AT-b{*$qpg*!k8N7Y*k zNIcv104rev(xJ0TlKhT(i>Q>Fmjk}zTVH=L5Mlpe_cM?2F!*9&?omzC@W2zgA+B7KTEcg2w(0~q0+*=3{sBy2nl2d{u`2|DMcjxH!S97#XRXBb#yoQ?CHa?=s!@^6BB7u-~qT;HafukYVFZ zr+UCgZn4a?x_n#6q2CZTTBgbRwk-;Lxio50GIZ6w&s{6IeGhimBcw|{AcY@?h(SEU zTk^7vF|4iZaH2A1wh;4uhN%K07x2Ot!yP;wQ8AcLv%Y?2bUSvwwE z+WN%^cb~niYdWlXieGEqpfEVhPl!07sFoiHmZq9zbp1PO1Dw5bBwM72dwv>_0MvV& zzpxIfjI?iQH_F0%AUXUM6-ylDkcF_{#j=r&Iz>j3wcw|V{cRG@USi7LSf`JRsaa_- zGWpDpG*`>hf9@E&WF;NxtM5GFs{cBjDp9F(#^|39G`itx)NUK@PQN3+$2f7ar_aja z7~^M&iqV+Ft`*F3ofwL`eC~5o3E-F8_1#W5=-`4>n5qU0N^ROu7_!RD8<&enF6biktouSVrNRJpu?+e?B%4j0#UvlxntI=N%nNv6 ze0?82s|+r@HEaUMu67vIG@OtLsA`Tqv&L|}MJd#4S&bfv6`W!3?Nm7^B|bk1RyjKH@Lg>^3LBgw+~#B!y)Yb=f(+td zKH9KTP*Ry-!(*&DI(<7ej1J(QTF#Sl7t8RR&jmI5$go)i} z08r#5BtB00#Pfrf>b#JVxiyfKHRvZ*Pw~}G?9hA4D4{Geu~t$p*(>-;hU}?rucN$v zdY|z6+^y!O-Y&Pr)YTtNTc2lJ2oZ@JxYj^5d|5wiQxX+`cY)Wp*V?Upjw@o`VfNfi>@E;0x%MO|yUw^F8X`!K)tg_yb~eK}GAy@S`K$k%W8u;0 zOWM44TxZbo0_?ql0AeBb8`3V)P8W?03)i;C4DrSwcK^Mc(F{S+(+QSdgicL+t%RCKNJX$3N z>nU081$oX6;h3ROu(_lyVF7fTb}|9h`mgaKomColm>q30p5+c=I*r92?KuC+Ge_K9 zba(H{A6vW5+O{z;9h=WA7e;^ElwHwGloL*O_n9-A87y@AHfzafpy;@g;`B1{Z!dpD zXH{;6;@Hu3MQP=~*73>u{6dAD-&PT?84VPkn-DfrzKJB^GciAVy}7bJ+e^Xl&V+AeE}lo`(i%DXc;8k>hR zvk}FYYlltmG=1Jydsp40tN)OZZ@T4CiX7?x-DrP3h(UlMyx|t4 z@v?xiv+Ln$D3^rx?VD>D)r!=_siKeOVtq$rr-Xw92>Q~mSI_5kWF5&^CiBqfw(-sjoMrZYQS`-he5uSXzet?WxPvy7L;eb}ew)adnKjMc z-l_N_M)lW`7pQ{y=?br8S=AeBrJk-^67j&8&{T*xwF#Vb&bJpJM-p zmB26G8e5dg{ux*Z%Jf%l;vBUsirJEg8|AS2qH;s?=E1w-g??Ey>f#jlSobeJ_0oBozH6=8)!EMj=X|-b zhLBboIe^K|?QV;zfOm;T9_wlM!n1}}E387h|A5mTRx76pzF9WaC*6ve$0=1J|5d#s z3?=@_3M=kno$l*t;=;4CBg-72@%#qL#iz$)2GBaixvt_)AKS)~AHIJO&CizK;iA*{ ze~em+RT*oEnT3jr>QC5cM!J;$lWarX|C0c&-)}`J$tC|^s6Ly!aZ(pk|NLH0P?5&SA^DjgXtWje-;( zC-EZ4+|(fJ zTl9o=4}xPwHFsYtCZWB=ibx&6R^jiUr=;hs-vmi}wBmDoD{~M!CA0G1t#A@==CUAR zV~t~HRZ-I1VnuuT=y?_Wvvb6tgYB%@m8cO)@2PsI>`LVEZcJBE?Qw`V*K|LiMI7Ow zxmof|*bk+Rf1S8oH)0!08yBo6vEru_>h~PKT<`D8T>izA;bO@X&oi)qUdtzKkM(~& zWL(3R(rKD3BPvNueYI10GJgM$cmI1Jo04~@t#1=Q^phKOv_GQBTbhipvH6>rP+h&r zx&v!=Y(|tFPKDZdUjM2pkAG7hPseh%xJh4j=g#1`M*Gpnx#C?5NtYU7(!2H=?S1x{ z>AmvSZu;Cko**SuWN$50tuEZHA$|D#&Y3TXEk1P&ZEea;14jG51tLMD5+~LS3`o-xzjeUj5Srbjf#? zu{D-Wq(=O(8d)8fYRdQV%FokEF9RbAzTMgY?Ms~;yA6F|wIp&H$uh}rz_fJ6W|iCP zV6=YCz%JcfU2R$o%SV!bH|HFO`kvhazkn2%P3<5{{f_9|4oUOD;xv6)!QrXl#>8NY81#1QiXT-MVQ<>d9Q z?Jqa6I=NAQtBNW&p-qbskezUqwpEfL)j_9QtD!|9kn75T2onEzpJc_M$AHF=8LMaP^AgjJ3sSBx_^$_1KV6|+A!(y~**P{beFxa)E z%n_P$?p7tzKh*KiO?%jNT1)?9!>)mfF7I`)bo%uR1@wg2w;J3b%6-zldFm_s<~#mi zGvjB(IR4=Af68Izl}q87WS}rdO6l2Kc>$}5v$P#~^reo{2VOK4>z~h2?cJ6*+i9Lz z_*AX*(GrdO8Md$-G6h3uEbgc0mWoYqFXaBcp33f~w&KRO7RY(y`}*T#a{|jk?A9v$ zYPl9Da_4mTcK&h1=V%ghx88S;>Gp%wk?O=$L1vy(9p#YK!(Zk9io2ilh9f_L@P6{Y zxBQ*+U-kc$DVb2klz4}Rgrf6gg{0pb{13qQ$+Z4eEbBrf)tcZsar>xk^v}1^myzZ75F_!|ADEayKJnMqjLe561&Oj^--JL*ztkptzZN9kbgGWR zSU;#y_S5fkE2&Y=mK2IA9d11b)eXO}gXQmEzCOAn?sqnV`ByIV&iQ?*{LilDKbH?}+y@ zJ#>k4Nj!MYTi#rQyj!1CgT-tE&fFxf*O0C*+xe{33#YK&uV`kqqkVkl+i;3P8s*=g zIE%mLrM$yb_bIO?K%3J4nE|gR;Nc7##rMVixp&o>webBvm9g->9joFvD{~Q&9)(qT z4Dla)SiJ3x-M43aUwf!Y?^P}*>3e5SrFR-_NUw=dUu#w{a4G&;nV{k6|fqd`|nMeFDnU0lE&=i!FQnL+g{MA ztk{;IcI>NawErY)q--UE%irs!R|d98BwbFqgQtRc^+uV2^cYMQK~`;lVsK=xxkdh# zHNmXCpylnbz>JDrbQOyYVz!NM9!0_s(QJvt5$`{oEc2O#I0R-2qFcw_U*+%V z0*aCnzfUoYl7}Sle&VX`Fdc*adK6!YEkd;0BR8nfrPs+eguefX-bn8~K6TZ?Qa)0! zes&p)vtVJ!XgwoSW)`K&U{E*N^tJaArMD4X!>ZRONH`5Ub-4C>NwhP0_k-I-cSCI- zJ*fF)fr~=;fJN?{?{ccTZ?;uuMD)WtmX)m?jRJ&$Tv zaut>s#=wPW2*Fk4B0|L?Sv7kCr<$zjsWM2Dw&@fH6T2oWtQKk4N+T_xc#M1? znf%w*g64TQWATzD^2zU5BDG0(5IHGM z=1Wq>HyMHvx`TY~kx%H}U*(EPJ$R%fFTKVxKc#v#Q3~sjg0d;!qi<#hPEc3IGx57! z)-g_oR*hcTGfa|Lk|p*B%7q%&X9MsF*A?YT1GsXLv1md)okWQ_D)G>bwzYUJKt5(H z_&QQZ-r&5$?eP1gP-dCx?+n#Dt%LC6L-E3t-v`vTa$Nr&;noxT@Q${VO`#3DmDZ5N zwpxKsyF*TpsQTh^bxl-+K5JVZb7QGAr1E{i{1`Se-=RclRtD>)rq4`c^6k0T3K28~ zHLpwj)E0!qU(dEe=^$}EVPx{>Fmp+oF!>(*p7S7 ze6pscd07iBrtOV@B{EJL# z#as<+{4u76Zg!d``$eYA7M&tZZ>na%2Pf=X=uef9ur1W#XN5Lltm6odq}-Y5mzPdB zlHy8+L9`l_aYdt`>t(qnVHC#_Y;6^`bHZ<|bKQ)Tzu@^_7o_YWcavsxrlQ z*9xyHmb{$ob6su8$I4zfy_d9X38#0fuZ&mZ9ZcgGf2@YrbkW%4te8c4pf1S&R<4A1gCqr^nCbw_?J!rs`vaH9*Gn&RZ^wE_ucGlLpA425A{C1@u)q$)IZyV*;xeU7sH>!*Xl)9e@<#vdrMSHs4n zc}QdIsWFJztf?ql{2ALnap4ZgX%yn%-)?wMz228#5<(nY6$tyrO^?U}&=>8d*#y2Bp5(!{xRCu7> z`XbHJGs67!*lVQN{9m8vuwguJ8qpzaLLXY-CE_&3Sed1{ML4Rm7r@9WSw1<=QNv59 zsFx706eU%H0Pnn3)j6F@X5!jZ+`dRGR)S@W^jEfR4F#8b(jdq$;rDzajUWFumZ5BA zZN73EiBs;j!V2RSLFz-;;m+3m(a%UP{2Uz&C)g38#}H3E$-O*VxsdDvEOA`b{yJ%> zd*FtEXtjy?5H}q`vpu|u&KA2THIgM;o$fVkB@037zy~clx-3nqZqG#WtWI)s3y0rF zsUTJX?K!|l_}|~1U01jW^d~AZG)4F1!_>&Jn+QlB;b#G#;r|W3%H*YvmG`j0(mc(*${LlR3R=E3%Wj(bxW z6b}S{g=O;|3*1}3dyywl&O5rnPB#GOn`yS!J% ze&c_V*vhr{Ah@0|jn3ZJ;kxd-4&YkCD1Nbi3Cjw{Vijf7vT@Lv?zu6=P%)&X4~xj7 zLzJZ9Qk9L!ClUPjX{Gl?359nogl#t?l8;*FG0icR1Ut4VhjojSClECmRGM5={Sobn z0Zk842BDi}_ASt>|NA8=A=)A!n0OrDsp&Iv*5yL!=uQ`353Q6GDc&uGgTzz;@>nr! zA<{j|+QbFyuZ59tE6 z#5L?pLI)xm7UrK_$@=XeHoO$Lq(4zZ+f?%Vo%HVg*J%2v#l&V`L<_vewZBSTte$cQ z`{cpVyRb#NxIYF`YTOsJV7qqeAUGiX!WF808Z`y{_gJ3{yM@_`wy(MBa3K;K0g?Yx%tP2f4 zinQHgn366VSpnS8+C^exOc}_$f{vrfrbnl*;P!R@i2*gMu*Xq9xN-_ilDQ=jZIWk_ zaz^z(1CFnaaRghHas{Zpb3gy)D$3EjyR-pxS!1QmW zd^3$(`0W;QRjdE?^viUw6io&75&<^R6nyCSy#5|t0{KJ91nuE35yD&^nc{}PsG_!3 znt%4TwTz6utXp*~(?6}^s4Qj8u9*H(L>B`LdqpA`8~7`B`@ib+p;41Z;M^elNv^4E zN$Ot?Um@Xj2Yu^TtH~E!2cgcJAb$EG)+m#|aY+Hh1x~W7;qg9~;eZMD)Mf1QUnY|IsNnS*VYaVINnCA` zAHoofFu=!>@9sz9eG+z;F4Qq=(No`hib@;yqXGe;yZ1RrgxhVYw_4Js`U^cBfvchc zp-e8(GQlC-Wz2sW(aC8fZWXx=C@f^iibX$r_I|QZA970wYD{Y3^KpmhNR)A{XPWd; zaZzr7Jj$FvA-`A#Q_$fd?G_@ z1Moz#5O)`4SFLs=PHUPfC~;ETvxRN}0MS_iI4qTWW53*$DHoOW13TNaE2LcYRk=!Z z1Uw8_$(n;i^G}6+M{Zwv4vhF1D>xVl5A^qitx@pky!Z_H$Kd0bcqLgDNafLI?i7W% z{H&XmI#pQese~DQVG|~LOsF}jF9Sn|>v6fWMYOrtr=Wmsc5LzGT-2oRxa#NvNN)Y7 zn`4RxsjM@Yk%MQw&tJMhaN+QPKGTX^%9;8-yabj$F)F7Vq7`qP4q#Rqv&pOp3S#*0 zHkwO0;Xr(aPWTOEg<#_?7q%Y68@MuLdbQLwRX7wLBVFVv;}}C(v~=e+Xi$A`Cqq-A z0_r#h`}VLTKS`K=kh0t*g|kovuR>6uF8xy0%HK>M4HQOQ6qHbc6SS?!9PT^>yZ7z> zqa}IIy%9Rx4sR@hu(Tr@AwpUK^$AhkFvc_S1_Ti0l^q=;MZqiRi*y zBfIQuO23kpDS%T5tqVd0=ms1upCTn&43H`RPwu@r~-Xn;^Y+VS!C(_?P} zYJvvb9yb8=4JOp2Ykp`1PCvTF@G+V}W9I6)j96+Wi9B0i5#A0N@R?gg+WZ@gF?X(0 zAcZVJtpc;sA?7`vF*>ZwIBk$*FxO1{mO&3iA5jQ3CT;QVHdU!$!fCJsSC`Fm5moUg z%ceNgPnZL6%|nu`=7De^B}I{< zs$v{Ni;K3z?69IhTQ2W-7@?oMB;y4W3%z}sgrPsP%wS;p2dMD#hrTa`@hyl+f1f7* zCo!QUeNQG3;MU8P=8B$-PoHUlF~uE7Ch3pJBPo!3lDmc8OQIaEPrtDAfh}3uN~(qY z;V3ikL75plbFzmDL*X}3j>%`^&X4*4dG~AKAoZ}wk($pW$*LA88(JSl3xEFnO-PO< z$&HMrf}dc#_QBecG9foI_5}w}FFQ>2@}|i~>WBFXy1En&e8}VZZ53;3%=hgmvBdG) zb2&LJPYmV+S3lk_d^A=@$?sk&8}ugk4h?Kl2C+9-tErg!j5FkELBwb`EH)8Bl8v8; zxY~?$s;vN{ajhz2#+33?m#X+mlXV!{Lhi&hA_T)*L{sXT=i0EU9Dp_L*-HSadS#Ho zRwG*`NaMHnvb%CsCE0(w#X#HY-4Qh@fD$3~Y%g9gsNt{ad7z>5wEJ%A#JdB}@FEpD zQ2+s2befXBbU%8r`Oo-=M=yJ%IC?kGms(8#DU*mrmUoZ7LBs+~ud8wfhWqGuv7?H< zw$j~K<-g|TXY<0wuxS{C+HvN3fEV07o=YC|fktsVE3_Ipv$F(^S)?O&QA_jI=Aj0u z2FN4XK*S*rtr_yLVHml1kB!VJuQnMMmu78F)xXFVETGoGZI}Q;EgOcWS}*}AD?I#{ zJ9#l@Ral?NhU+dAYHw{CufUo2*JTJzh-U`CxN1lJG@(~u?~uh!V^XA>q`*Ju3)ZU{ zyD9icE$^N?7ViyA|5e2e>8QQ@OBtqJSIU|i_&!+Fg5AeBQ~x z>=rf8mFh(CQCHn^j|fq4?#LoAx&PqZlbsGUhJ`>5-)N2U{h;O5S9$`AQJNTzw(ny_ zMc8N`A*@|~OU9U5UI#A4G>l9V96h`b+zYOcF)2__69(}P{Z~kT9L4|v&jOV($xKF% zMH*vHcs$HEZESQw@eh*TkCrKC&8KDLsv#b}L3 z9W?wTF~-6D%lMPGHrog8gspl7z<>cE!W)&gJ^34sqqt-n`Vn$7CEBC_44EDx6>YiF z=Rh3gQd}J+oo~R3x9urqBv|#jXP!x2FK6z};h0Tbx@{CMfjQF|I!-`6e(0udQyXf)vX$70rVsF)W)$=-!~AD5)TK9`jCGh6rqe$9d_q(;gk-M4sql?VX&fJ zD(S=gc2?zjBIPpJWyG%E+5hCDp<&|1;_|Zb!I+obeCT6sAu%=s7rpgQyLS%Zj5GR* zDzog$VV+zgiaU!FIy&(sqzDP7cR5+hJRed8YbYRz>g9+LKcKsv8>mrc>@$e@p~-oxGl+ys zr&jj<1sAu8%KklT9{1RqXE=?tmR@(^aDno(mxc)poKphAvP@1MM`}!9<18Uy3F&Vx zQY66&fS^Vx0*hLX7G}Thh`^6C9dK;Y!s?n4H^|-SmTNT4mFi9oK ziQG@n!)zG>{t1qFtG>QPc8lZ(I|z6zcZ-0`!L2P#^VtcywUtJjAzoG_(%E1 z5K*Lmf>uzXr7Rn=A~eiETtFZnxz00!Vd5QA-dn}oL>)(;+9GX-0w)oI>w+W%9$8c% zF8xmh3__X7+gGMq^x-F_Gu|;)$|XA?SGeK#%#hRo^$}eQK32WhFLxiE3i|-M#`uK( zW1_8aW4-S4ns&zVwB9`O8pLC$=^qRJG@4(r!4Sd-8fc5k!szvn#}goJhh?iO)YEeD zRDbNj!pzkv3D*jpN@SWH{DhqSNkdFKUd;lAJvmHlMZDgCDJST)m&in(`2J2&=Rm3f zT|&!Igttc0aNEKHXUvZbSDHr{-FXPklZC7_9)Z5!4l;)Ub**G|bw(~KcLU$f zP9?-7+SzjKL*$X;Mu2EsKVP5+Ia{jF0{J<*E0xT}H<1 zy*oBh^=5|;guiQTNI>cB_IljI%h&Bm;<3{#2ikpm=UFbHDBt$1tUWW2wJTTMC0_A1 zG6JezSk=(koa(JXDpXaEmZYp0dZ}ZWqK2cnocLhr&#>~^pLQVy^!H?M9bn(0mO!&s`<;bBk!O3lKv9+M`o7kqV${>!pLKhVr~QOi zRDU56p{Mq4JxEP-`|5d$r!rWgy{im?Vy)`>d>mtFcJoWKvQof9JJs}x0d%KIfJ(l# zY?VFW_sQVFIZJ;3>iY9eKCrE|52?uUW?VQgQj2&ZL8EOwYb_&YeEdXXt*Ys?Twg0C zL*Q}a;Kcst!p2>Rfdf|u>Nsn&cNWKqV7fn4X@ZkG|E7Ku;&^vBelh=ivTy7EvzV#^ zh6;=P$Is!l%AR8z@b(Wk--PKAFAXKk1W)y+ITu^bjmiyEW=*HvdoC?v>G7){dQTCx zDSm`2t82LrmCzk{|0Vs(VrFPpc78tsT8#L8GTj1ewbS*v&+xKnbr?a%-IFajtH@8O z2F;gG3bfbzBO{aLIS;hqF0UQWC);Y30YgMe+#PR|oLJDl_CsI<5!q8SBw@mMXyS_7 z_#BV*Q%V*)RPQg-^F{Yn`!Nv`_ijoyGV2B8Ad-BpGba=J2&tEVUd}&k20ZLWOZY$R zKG+}mJ&s_#NF4pWV!A7eHS-;g^d3L%SaQ6F+Z5k+t)g)}g!;5ES8|ULrDmlFTwVJ$ z4qjIYXhEl}+$4T8Jvw$;vyMT|35wrN7>bXY54jJCG8URVnxBW0un(0ri8t>Y+O(~B zo&DRTr4JV~_^7BB1rCjjd%JX?p|$!lf2Hk3&;t_xg#7Wu__De5s^~ywdxF^gxDKYS zjT_=C$KBKm49;fzMrqR@3bOp7_#bWr(S1A zjKEJfkAT|9eFUwKPPvwxP1Ot9$*x_&l!T>ny5Nnfy!bz|QlH{b_8nQ@~UbgbxCUg7=VHR){i zIW0$>{%PG+W>xOA^Sr}rWZ#s@Ghs5Y%XN@qe@a^aG4@pinWFtCN=IiPWA~pY4=T5D z1L~_~p@1K%Crg)nisKB7tx6K!?HipZSU@feWzE!TpU&NS?&ESr=EvTP`vcp%XJ zHid-?{Y+5Svu((6dutJffdi*NHI19L(T~&i48>scyU3j4V|>i>^^>RO%`CYB^3b&I z5ZzAy#);|{a^kmn=2s*cAPEiL!%(1isL)zv^SJ>PvPGBul1=K9z*IL`hqsRB=^Dmy zDfjwn zS}PEG=|3)z1S;^^c)EvjwYAjG8*y)4Y~E*EIz8kWfSZ_HeA_l+vBCxGwFe*?Qu)n|Tj^+dg5wt@<=N*GcU$nSJDg6NK6Di#@pMe6WZvW3z;l{0 z5B+&3E>`KpffCoOk6hv0)!CP!l`)&iFHj>XGBseJ-+36n1T%s7eCKGuIeMR09hB7e ztA{^xwEU{ZPFNmUDO;*b>+Mh5Sf`nL^4?^iq7!^8ASVo#`wP#8t^8){g+i0dzTJHXcb8rjjE z5yP_}d`HhqF@NI{m1y-hmm0nB`HMJsWuJDjqf*Ly%y`i0%?!o<#W^Axw|H?i>VdPn zubwbA-Gp!TQ9zLp(@?O9a1YVzb797r7B8=WZ(81qV9tQGYZ}s%&;245^fCq94dI;Z z4!CLt4&{=aiO2L2Ao9^ph|sw<`D`ej6|ZJ)e6t?4mN1r{WK311%%|Zv9`Q~Y+8)a( z+Xiz3Q%={@)Rq1UPU)-mW-ES81RR%(DIqK^bwjZU#lob&j{&Q|$VzW^o{itG$On0f zzCR76Ru@nNKt=5!Ntl!$@j7wy0}Ljit4>DeKNeRxbCfE;6|U}je_xh;ZrmlDln*7Y zqOkytWm*U2_Z`-d#+pq@cRfN(Ed0ri=L7GjgD0@GCS;&CW3#+f*}PhCSfUTdQFe8u zgpI6utJ8g2e1dT0;mv3yDTDrdFOU|veEJARAUMwN8PVTT(9V@c__%%q1I z^B@%7qvAR{tW}D&wa9-xNbv)Rw5ifuttl2zO9j_Fnh;S@r~YfpAQ8rlNJn!Rw~1Yf z4XK=B*Hn5kjm)7DR#ywpQhk!NzuLhZw*wf3wT}T6>jMp&AO3F0DrZvq!?f~v17bUD z^`;H+&JPuWKKf;aY`|X)l*wlP1W~h)r%|-=m})O1rv`Y~hcRGiHS%)qT6B%%m8+Sky)d-h=tC-Qt3$P(BITIxhT^ee znq>aQ(>^($)oU;R1hRHah;d0E(aYke=sVoROI+=|Y>KhnApyA?Yh(ddc=;l}8o)lYp~o>8aNhcZ8Q*}z%ijs4HXd-V z6Q$cNNa79iA`1dKKR}&a@eO4v_q~1${Uq9#+F!sp*OW4bwQH_o)#UY7Ykd6VAD8B| zu-JaCPD{yEO|*DgUXJRB#PF)Zg%(z!#thaIt3_U z!7L(4WYqjSW(Eiaw7>K`i0r){G|jeoJtV|3R@0WP(JVZ?4oirV)ItSgw!F;3g`;~@ zIjcS46~zWTsL2*x+RuNXE##`XUHy&rd|=!OKiq`ugEqx|VT7-DsyCrmR7|rzKYkzz ziYd-6?L|uu8!03c*@_2WfMQ*sPxp7vKKhZKFRE~xzth%FwTEMsH5YxOpm|b($_Dm; z734=2moxkXK^UuLQJt*A_nA{&9r|^JX92#6rq*Fe$*j84i*impyu`XgwzyYD+yw`J z9cg&C4;ra<^KRk!iE?{_0sQX`G1P_}CFyRagS(UQS59@Nq1L?JWxb$zo?pgbvh2#P zfK3%s>B!%C%m)Dq#U{(2*7 zp{yEF!lMvmIG)U`*OJZzajI2fB2(P=V=qU0$Bsp9k3UfVVo%(YO60p_R#2Ovi%raD zO>U6;wF-k>vc>jyU>{mWJ=gmxh4X}r&d)cpZ>DbcN_Lsh+tv(?jN-6@G^;0okN>E; zPn1*HaOjBQ09|+XQH}~Z=OsR`XW5@|s;piU$(zYX9p~UTg9|_EhCJQ9eY8c z)~-lS&RtvF-}6ALsZS?BK_Ty`O=wR09cEMczdo@fA^X5gSGYalF0+ak`&R@7%$4?# zS0~@8gTNQYmgcbD=le;Z@BMoiY(vQF4bs#pL^cPUV{no|5MouH7p_*_VpG@pse9XP zYpvwap=y|T&a%5~L2NZSF#Nve?fcDnmD1z}4-PJM@H{3a=Ym!>*lh09Mz&$yP=8Ij zqCDE?4p-AZYRh9aOk!tfHnnj_oUo4+vpHC+cfHdahTBZ zA2!FZ+c;(kd%UvTAjgLO(9eDAkcgFjVwX&bH?s$AU;@}Hjrs^uJUX6DGY_;nbVLv? zh!@%ug8M&ohvP!2;*z>M-=v}UkB>JllLZp~QN-6U+){B)o_E-KlqK1|nee`T)WqWf zIztq(Z{xhE^N)=-L6ekm^Qs4rSB7KHvsYQ8w|MuU$rXgN+J~z*UZ%mxjx<=%LF?w+RW=XYoq&MYnyh{2;`4DwYV7Kn3UgUg> zO>k^=*IvTEXA1=Tm!8w+&DYZeU)QVPpjVrZUC-OmNXmGAEA!|3(Xj|ic}P_90k6-} zG32D}OC5=`v;T^n44f9BnpFG+K0MZYLCD)JrUfKIzS-NPkv>2V@>)YO zY$b)(YUH(~?)O*`ge@=nnszvO;Xnv9E}dmDDVBrSq~H6Fi~5yRK=X0u zu0`y}60h%N4H6bCSvn=6ui8H}M^bw%^?8rCXyw;8u-3CDFyLyu8G4;LxdOaOsOHpK zybF7wHDHuj&H?~0P5Ug|has^rE`}Gx1D91IQaCv*6Mv;dRSZvsf*95q?)8#DztOFYQ z)x$Id-$+nrQ2ISyR7<={jg+L&P3svMYI@1g{%)@RN@TR?BX-_(;oAW;MAYb7emTIJ z*n$WJ-E^I#2Hb8uf>U;{!Zo6*nG%CJ3<5u|8-_Tq8+ICcaPZ44HdP0v-(!Ht%$h~< z=7ng_dw%$P`>RULa1LR(s|~ClOdr?!4i5&_C}GxJQx0lFHkt6pUj$vLU?d(Fhf5QB z&V%4h^Qgk{Coi&vVXAyz{9Xhxw)fzv+mB+5?K6+sYkxgYBMGrX=H0)VbeoBp28&d@ z1RbmM~;MCiLDGIjfy#F6f*8m+^6ReX=Y}>Z&WP^?EY;0_7+qSjI z#@N`lZQFJ>d9(j}@0>ex?sWC7Q}tDKHRg6Te<&DBf_|(MKbuNP?n75h)h6DyUH6It zoxVeRRody^W@q!z6hZA2w0O7o$E_8Zh}V8yUU_xZbHWs%$#34>i@OA>-gH*RTj~)X zcX$!!yf>)cL&<5+j}uFsEah~jpE5omD~JY{-oP_S9NL4ZFnHYJh?d>rO?-gn!M>Y=8MZQM{Nn7$Is^FyBn^CaS?cYS@^zuuq`yWMXtXKh~I z^(`Nxh5^_l_es8~Ck=5fs+*(Ax$;f+$!C%`@3Z}%PjBsYUS!}zReNu+Po34(d#0CE zWhdO~Npg6vM=f=qCx-h!g`sNSSNSfa^v5Cj;Dvf9*U%d@*-MM*iHeQmRJR z|0C1KPL^Y&_D)-Ac4yV=vzRT`y_yU;s*~7p{sGbMEId-LooYNTIo<4cN1N|Kp7 z-}Xsgb-wj>uEnrcC;mH~CL*J}*!)hZKO4S-JD#E@fXY;DmV-}kJ-&>i*Jh~dk>3RD z3vYP6?jc+KuWz<&m`(aNu>}`3T1-?EBI4I2Tv7oC-WhRJgRG^#XhjD%vnqx=o8s>+ zE2#Z??HJ<#l|ZM=vXr73HSxt@G#WEKE7lUv z#hVanBh#O2&_$>+iHXazS8JUs6INVP*$#QC^LqJgijwK|B&r+>d+Fy4>H>}LKd;=M zaS=7dRZL-{&?L9!86#c~$fw_Xhf+ljFW6=AkZ@E54zN9hP(qh_8Y0?V&12oFt@?kl z%sS%n*MPCEa*bo(^>w2Jtv1uKOnapBn6xgR*<|Fl3M)V4?|7r#>ymRHX=X4^vbb#L z|2o_}O}3)L_0wEYnq}L1g_4`bYs@ZNoah^RKgTYGj!_#n3Qevrr(%oD@REyaE!wJR zfZK^u)QALSqCH=0It{2m_D#}Z@#&j!I%?F6kDTB-H^PY`G4KKN2BTQ(1 z8(xVt1N)4M#$(3C#)$*D*+j7%o^Kr^U});4YR4m zdoJ{lCyi9M&_SLn0s8rmRyB|E2IQ*Z@~7;uv|0*>fo7V_S%3>M=ZL`R?U_RaRy#5TTO2SaF)B%GRRkEv28_Y1)YHh(VS#;xR^UiD}0uGzE9&6BI@#ECFz+v zIzIaf(+}f&lgWDSu6>OohtOR6(B1qRkokx_x=%dX#tJH)T=sIn8Ft<*;3hUNR;8wA z!zT@g-T5UQVyUEKz4&X0^&2qzR2El%-_d!{QCcPenK@UU5X;-(*+G5ouA?T z>3!_hSNZI+4-qC8Q5w6x(E5q_sldk%yzJmOIs-@}gH=sToWON!&iF?LTi?{~v<&xt zKC^ffdCxNTc~Nca8>SMPC%CNUdQz7}QwC*L>DNTMbjWC4a>;24z@m%%gt@=(XP32Y#p9 zYx;1KOx85qM6A(Y_|vw<`cCRI<$7bG;%ByU2Kkzh$@VbMFF4!}{>kgdEhAnAx<`oL znP+NCS#@)LLjf|hsj!UNs)vOTWC)oaiwMt3(y=Jf#+LV9oy`{L3U&g2JI=J`Ge~r- zhXYk0==msd(%DxLVjjtU)yR@$8omk(0dan&@w+xN?kp}mCOqrZh33HG6591<%DJmz zSBFBB8c;66BF?FGfQ?PzAge;3%ra2>O4)zNo1~uEBf2uL7Eda8POBbzFmH@=hD4l)B#O7k=P=My>x&a4 z(-Ch%#xJuFH49Uj7`%4Xsy=+^U9(JsprOX4uCegvCRbx#WxuC{Bn*Ih=i%%|s#gxG zW*98ig0!;FH5UVsA!NHEQQ{Dr-ng06m;j~&V#5iHr@gP^DtXYrtWd#llORhKJk!kF zkmSK)?_Tyw>6A`C7~9Jh=bgs(nV8T>i$qtGz6N(%?pxP6+E0-Uv@&6{--0&Lmk*kG&-CkBadHgJp3sS2( ziM2?3y={G&_1&L~RlV2)XQeJ1-=v4tw8-4Bb+C{tY`Z;|Z;plHm(3j50Spw4TBM5% zj;@}KbN|70hRI?baPOMe8YP5GZv7hrTgx(uS!$$uHP{Lpo?lQGRyAK&W|oeXbN}&b zihkr{-<<8Mq^VFUr;t$f^C&MF&`HDYL7Tx9UM+qY2Y1`idkVaI8BZw3VF@Bl>C?YD z*>}-NBNf+r8^=SKDW&o5eq?{-KPYDrnVtGbQB;6T|Aw2UM4+X(%9KgySQuh_es+-8 zjdLk!G_P7->EZBrV?3PEgkIn=yH%I@>ywSOJl_Y9Kc@GVp0los#6>#765(QwJRr=e)oNOEw(^E~& zz3&y|`{!F(tV&Y#jE5LwbRs%u^m$p{*FSW<>Vnp&DAFhG@18QFi4NmyQOvX+S_{!t zoA+|VSBS%l*6*POxDQS6Py|oWz83eUa5Gh7?QAz9wMo-+Xol`-C8+nf!`YYok%{@4 z=>~>WwS-@hCObfsRS&6{KC8ChW<;Oz!9KkWhoO}#33ru=33WKV1aNB98xDp7!{ii_ zxkj)Ch$$2|FJgq_DY}_55VCOZeAc$SdVC6c8RO4)hZVpp_G?E$+y~ScDmiw0KcG!5 zONe8(vLiruzhDZJ%7!Fa@{EY}*!jEI)-X@6@!^{AyNUkPq5|sI{gdcg@zfA_<4kl- zR!ot~`GxazeRy|tUzpTnBmMr|E@Dl3t1<)M9&Qu=t3m2tb`gs|#+9@5e@8i$*Oh9r zo&>|IsSW)U4&Zl|hpeT;@UCQ~TWMos(A{@Fy8d<7i)a_T^zxT&$i%IY^iD3|gMTPQ&L~?7-(YcWhgwp}aE?yw!SBHImbV3% zVs=84KTt}MKzuKOpXD2m3>W3C73LR~BufRmY+CjT=&c>&rMAPQzs6-1Mjx7@O&j#s zUC1vVE;n%|ng3$GuUiOU2^|z}m;2m;Ug6|kh}S$>RnHPR0C=joGY@itHe+EgA5PJl z=>OLH!I4#(%_j3rW>UV0$X{R6wUs6fFPRZAg8M0?!M?*LQ>GL8f=*cm>Y_@lD{??k zuDkIua4po3W{l{?gWJ?o_bjH+i_NVq$>qAfEW+&URES{HeH&8t_ z!HVt@TUCGUgWk7>9S)x=^;a~1`BtVnb13f58OfERj)kMBRo> zgKvAZ`$-{1*T-2xxa)Nsq8(v9aH8}Nu6=y8Y*AHUFxmQ!dUOu|PQKM%`-vD&1q-EY~l0@7~e=O9dAK3_Y=1aHD-`L6AA1V|bbuI2L{%-v=St+ge_= zJh#0WNok-VHuS{zcRcbR$7&P5IeF4dBG><10nDY7^8<5a+OUo=la%@EfIU|7N_E>~ zsf25NZkguJ!n<9&yCe7`c`pZPV}tnViCq7-`>z*(`V)a!@DSMkywf(;`@n0NT&vaC z@J}hG_YhSJ9XZsFIIjB6DSG<6ippLlqQ8~yzSLtYBBJ9hUQ=s$jHPDy(`b|_jXK!s z=#IJFX~pOu-a^pk3@tHXTaPBxm~jXyY;RAH+-_NND1*3)%VWM5j*i4*Mm0kb$}))m zHtId;b@%Wjx~8(%V@HInew=I6=%$T{eM!+7F?tgCc*ga90UA^}+wa=cPy9X#m;^5D zLniCXg?sx_2RLHrMn7(!hHZHC&i+zLRRPwxzuw)l?(%M$onGs%8B1S@c9E|bsnT&S z4mj^e0EJ3X#UxBc_gwlE$d;A@OHd`tn6dA=N^vZ88+ zzcy{QY)#jp&ucdg_lLmvHk(SmNi9q!X2|#ycviio`r1IDmh0`ozlS(YA-=3Q+6)Dh za^n_@EyDI%F6;gqu2=Hu`Y<$MxC@Vu8xT4V^I+lZWBoJ~(@6)~f2o1m_z|UV$-uGR z%%JBz(ZhD+sF+Wy??c%)Pw3+b*nhrwv54(w^h{(L`Ph6@lFfwP;~K~>9*GKQ(n4SM z5}K?1H<9R)K<3xeWS0;HwxO#WJ8A3^E5}iKiWRfe?q>RSKON|NRSQ#4EMBH zqf(h>l)=jP=fK}o%GHR(&9Hd1NVE_iT01_ZFxN(-d4ty(g4L=MZ7j^)ZM`p8nm-t& z84~ff;j;4FzH*ymgUoLywFRPqS=`w#$B_-=M+H(Nw>sXRt3_ISu4Uv6?bRh$*7u^1 z#96L;`BNiv|F(1!_1FYjmO=BFWWlp{pwm=B9Lh*QE))M%4*12`g-I^x@%5R+auN2g z^ILe=pV>LK^sRZ;Mwo-17tU!^@9@tunxb*yo4vm3yBg&m-7FXQdhd@C&u?>-bfHd%x6dykZ|4r_0 z{;FUSfqOgFtCyBy}Il;L&wFp?e}c!O;~ZQ6=k85* z4B6=VK-*P15p~U2ny)E=vz9@T?x)-{-IomJG_<|jV0ETsSM()q)s4U zwvvNrNyTQ^ls{qVt$o}4?BEbGD`4a&!y$3@8H~Z+VbRPB!XgZ9$}*gndf3hO=?_f} z=I$DtFMq#3Zv`P`2`l|*5W5*?={w(k8aj2x(&5L5YsC{!LOU(tO>*2xiPmxpilvL?7{ARUNlQ} z>^S`txS&B|^k=)n`+sqPPB$y8<**UMt|*8$mLdxur+AtxlRr*I--V{G)C|LcWDG9LuE2^B)= z?H{<)q@>)`hH!$GNhW_Q26?)byvle51q41e^|Axk1NvU&urg$<#966$4mRfMgs=H` zEP|n|YF~T%xBADhIC^+F%Q``qp#JKWy8}7Lgxv>H)I3>ICkKH`XnLiqP6V-t_CDP$ zpnnKvGw(F{XG>!Uut@8i*#klBS?nF0(l)TFz|KGMpHqbNFSD=>R{NQLS+F{yW1;pC zh(F<`wsVIW=R5b#teK%|nz=#`X@P;xK#Tp6ALVa|24EThhlWBz&njrqZ6r_z%u?H) za_;SZc5-rlDr{BTYPfC;eU82QOBrkqBBkR@=xjj+2`8G$0ycdDPr<)``nFKdtF`OC z11jg)W(?S&k)~r zn>ftV(Klne;a$?eKa3?3Phc;9ZP3*@JuUbq3yv?OREv(U9s0(84j{@Kpc^BY-%F$X zmS4#W53P$Qz;m^inMPNfj>t0Cw7$fYHl)cRuQ|RJxNSbBs#B=L_-v`N?`T9%tZIze zC)^0GRo3}-)pAmz-dz`SG?V)y)|9uX>iAmAN3-O`IxSj77@C6(D!X*B!qKD;o9FhY z((Z6%#HYbNHN-pdZxEdtmiE4$>Q^3jY%Mb*LwXEK(S%_xUvET$?mz|!56X1MhwnCy z!Ci_H`TUdqXTGEOH>56G_IIiM-KLY86zw}FYdL7KpXP`NGv+KoA*w@XA)_9Us_)kt zuQWVNc15GW2o<&pT7Qf)^Pz|CC^cdmq>C;pCn&8k8s4XyxQb_1zd>w~ZkAsLZ$h$g zaPIcH6oq^z`W+noV8Wn!q$AWLJ?98#g++M8mKaJ@37Un6?ts`;X@r8L*^u+dBO|N} zd>;P9(wpQMlE-6^IBd-T8H|VQpfcWxb={bAodz*WHrw1_I3Qbmf7c!Fq)n>5IxDMs zTQx;M9bJ7!PVE@y#+<=maVPEPSy45T8V5qTm3nEpNOlMIr}I7h1vf~ys2=O64C7tm zx#W+po`e1i4@g)1mW21xb6Mzv?;{u_8ok*+1k2C(0epx%6|Ts*c_0V0BU(y=?R5I7 zHQWC*QjMDM0)#)9bYUFU7kV$1R|hEqNa8Dq&Bb3UsfmtmZJsfa7XeU}$X3Jy2bI)$ z|5Z~@o(8_ZJz)(*&ny#EAcyInPNGwAtsst^qRVPhgY;45YYojJMZ+)87?2l+aJiYQ zRO)xZu>Ln5kPAeLNIO%|bYqvqhjA&#K8LTNIQQ^kf5C+SIYj%r|76`@p4{qctp=XK z6;>>;sbp)a-U|=I1~Do=NH{DeIomF$iJb3tuyoNddvxk@r ziQ#?i;MO!+lZ+FmS0ssJU*iLz`KhxAf)BC9lz(jO+kIfo75Mv&`@#0zEuDS-XpQLv zo1H~K?h;c_d`cK4htQkW+8;mM=o^m#`5huIiTk1N)8|MOI z@YV0es`*hgvHJ7aw>9h%c02yLYi@giBj3)kSw<;CsX&P!;Q9%(VHjI5n4~^?4Bz^7Zw>;TmF#7$<#y?k&^=#v8(CNkf>*`KG%?~b%oTy ze~@WKO9PNccnqiFR>hBY$ND`WKXMpOfUb=YEDSU*^GG8B(e3sPADaqK-ziZ0&wm9mAS{9+!=W4_1huw6vR!U~*DxW}w(95? zRw0HBeBXs?`6|;L;Q9a+ShoWYudAj%r~Si-AC%xm(n93A@yyCJ)=)sz4cF*^?+xk`QULSSljDHmNJ$7w{0I+f zBvT)fg8`eoho?r|!9aSpHV2T6qK4j*7xeNnWwb@mQjX`J_^c3FM{UQB~P>-6xX7 zFwLI-$q4*S4nvy=jv*BoDUl5#nn+;gn2u$tm+HaqwS{RR2||Je)p|?wzuXJx;W09n z<5|cyJG75}uwKI4@GJP{VGxbBdKGlAY0P^KtG9#UKTTad#imkieKD(2_A3^QsJkvX z`57NCSn2y8r%r`O;>;qG;ofcNW_VD$O6Dq#p%x}n{8CE2ncecy>q^-61pJ*M@u+nZ zqS@x2z<7!WhOjFTA%^W9jjvzc{at9e)_(qBcQG4!)Z6~pQ*8NEVby7NGk1zz0ju}$ z76h|Yhj?6G&&HSO=ECPtP3BKi;h?NW{?XXP6G`k_P);0qG>xAP*M4dAKVu?C;*cIkbrpdqwlCr=?q7-7e`jP0lw~H zM*hMha0UMtHAw=Rv*;%3S*OQ4EFl|ogwaK{pfN}m;%PeS-H4u{*gI=RKmK)m23}l= ziQn+A88!_|AJP>XIXr7I04tHV2;>W~pbimxkrGmh5+dTCaCij&J|Bn1I5PMcRD5{% z@c56xZK(-Oaca`)H_e=5nnTpmR=m~5?4POIQj1p0{-j8g`?o&PFSkV|Az!`Q5_KO7f~|CRZq`)5-K)mQFX!~qyj;C{x(+pyHk#fV}M zzOvlO;Hr^f-s3l{!=(Vx9Ki z>jBj6fFL-NM0oiQg_9$Cowajz+`{aEin;kGnOxhbCYzGg=)m&MjTFTm6uT>WF!|@0 z3-1RKtO|NTJ=3K&-})!s!=pnKPOCH22wb~^(8m+>(-;5nI2quBiF9{H9yJz1=M?6& zPO{lG1uf=Rb)wF-F+ZxyfniwPqA~e%djl1`0g_tqr96~q%Etz^7|*Z#3W$Vs9r@g2 z2dv2vk3*WKB8=gyA&C6fnZaU%IVG}9@QE5c@dKV1S^tPm!SFC01ja`Ja)Wh!>5Xw* zopJ-(og^%|dX>nx$3MAcx}#y)g(v=q7kYBdc&MgzDXCe<<%0G11(^_$jfP)85xFVB zzvsEVGx0&N0`cMpH2(!d)?P##`5_R{QBD=l^$2dEWG&?taLf-_Q!pW^IC?^SM)Hf_ zsER&>Uq3j;Y2h;$+vT}RLhn*h-uQxEPu^DPCxH5%h(lqSn9nn}0EV0LwlU|kGH zxsj^Kck+o@19{r;@32Cag1l3b1WH(ki3@TG3wXe5_NhcB6$ziX zjF_|xpMpk{^#3nhmt$n{#6E>YPcqM<*pZ`tBI5r@xW!k48)KS36Ho_SKsX^FE{4Zf z^bGSiZ2~NWl?RyAQM$Rsy)AY4zEeWjOn6BmTuFtbz2@jdbN8u(|yN6@>5&T?pIGd~M&xkv2L z8%jzK^pX(k)&hVyfS z9TulXoZ8m8RqBLht3NW#d$z%niY@<@wWU|3G9K*{s|q5DGW?)JI>u4N=bpko+>cg5 zEYI93vpUKz&nPM{@jFM`*b6M!ZvXlIpxBmvo%1l~w#Z(d35<{eyHr#()8((b1~2bT zJ10W+HX?%CA|De{8jIQHJEdfAvqKlh-wZ1(3uHx8y=0=EUp$!atasx)P#%5xu6 zmYo%3sCSp8RC;RvN|e=#f0al}o$Ivjd4>VZRH`KSnUhhg-xQ_K%9D5h`~Ejs5zex5 zfwrDSR+3s-3#oAd!ibUt%gv z?Y>rzb#3h)>g$~c@bT{VaW~!dS?2TgNYwrJv&!e|vRVK06Hno*>0_O1_vc^r&zGma z&z~>bf8YK79x8CQJY3pM2u{BZUw;sNU4Fe0`Q3cID%@Yj>34tqoz_sVm_+n#!bO{f zWihMgWcSt9xnxP7)44gIM%dV{&FnV9@%wnb6Y~2!*8h4=li|mIPELIO(ET>`)PPGn zOM$JquWLZ-a_U1@#)pT=o?CTt+iKV@$lgD6%!AbJ+da@fI4(OeXMF16(%5VTkf*H1 zxctuM8LZ_w)Zbm*1@$Ppw6eJx2dOf2B?mh zaz!v))j`U2cXvk;LKeI??Q?rXOsQJy;)xBH7O9~8eCVY3lwoFR?3CW~?LC6nT?e&e z%ZeF%Q_4&;<54)@p&n8Oa080 zEC|l$wb5Po)K()16K2|@h0*(|BG|4o+Iv7R&XhvN8o2xG^Qp}-dIi6_ny)CflhJ!^ zx1jY;9cM!f3Xy@{52SRVcBO$`|L2C7Z7CgaO(TJwGvB6u_!&`Qkbzifdn4q)3 zl?|NA0H%_YNo3S&(qsko2peHF?Dp)jp&|T5Wg@+H>&@CX$$5c|ooKjmY;gXs-Ze!l z;r>yR$suV=z?;(W(}PY2srS`*@HOcjPOPKDXZN2sTN{K|@y4MeyLH_|=)pY93q9nn z!gUaInneQvUjEEfRz`y%0SCiVi*HgaMZ;iq2^Y~#i>B7n1F3^;Wi=jqyM;GD#JkL* zYgtD(aLQ57)jh#2cPS z(s`!`M7ATXP-t-x3GME--MrSIcKKqw^26zwYMBDeXSJG?nmWz!JDm*qvhe(VyfplV zSg)BeiaJ1*nb%&)<&14z>D{~5C8*ZYvC@+>%Sw{lnt9k7GEpR0c^Cr@Eti99^d-9R zMa_rD>)-;%Woa3>*-V$lcoV0u!n%Q0SnX?x^-*uYuez9INvC+gHuX91TQ9z?(6VivoODhfeLbk^39_s$U`atXg z*I6~DW3i%!&+J>p4EgZ675~r_|L1h#T@5KI^y{k>l{V8cgM;ZEJB_xjMobgj)>wHS zlMSgo#JaX78|!yt+Rjft{nmY0-O?{j<0Fy*s5MUGww4@@$?Gu@7BJIv6opx`b^VCWcJVo1uy0IfTR*bph12(zdznjv*;dPAl6d;FQcwkl*I)cFW!TfiELyz4>9+Lp z5O{MrGHkc3ZD(6ojg{!r(2}f3kkw?MbrtOpWv*kMIEwf@Z89{NcqUz4eOU=|3bETB z=^aXdsM369Z|H2QzPdu8O@^VK;P~V-57+m5^ivtOorgj(`ow6uycr|aRo&g0_&LOQ zYvomAr^uM8SQFA%!f5%T=_+Ci=qMpfehD`PZC{x;t0UEV3Oe6f;hltq;PU3XC<^u>qoe0g9V^_bnijF2T6k#Jc*lPoDxj7@<*oGVMdTF3Al%@lH=8AS zP4!dkI*qFx7`Nw5&Xt;_HpcvopCm>#Hc#K2c31cJ)_TcyWwOMdMP>P@pIEh0f*TOj zGtR7HPYQn<(vzsRd0qW`Dwwjs7Z>Q-Y3o^JtGonA0z(H}WzK#u*435aS zu0V;^rmP$^n^MGbY-Ac8X@vNebEIDVoqxVjPJFFs;?8b`^-0dAVV;le3-sbkvuTd! zxWtVuP!tR7tB(xo!P^F!>O$y}LHvE{pNzzA*w+#;M`u&(93~%ik-@Wo|stvD$vl(ThX}bKd zNb|0U2x9ycG88d~cI8VCvT=wb=0$LX9>LvJc?pidBEPA4;>m7}^z)6OC&0UMt7kwb zT45hrSe0fU-#zgdUFPE5n58k(p~3StswJrliwSp)C{76hWulnAQ@6KkGQ}vhK4y-u zlxumlv1NI88XDByKD9q8zcyD=3g(ktU4_F(CV%pumnIE9ZXUg{qT;R~ere9QY`ATL zTu$?MQ)GXdl={WBV{P5{TeR@72b5@8(-u&aWw5iXUgfdr0jkbQmzm~Bg1#_8X4@H1 zWJCvpAIQN~v#2qm!n=}q zSoIQ&Qd?@P>ULx8P^+Bvu8;*G{CS>0is_Bx50dF}CC-&V!AUy%NuBks<7H|n@#6FL zr|_GKg}qPNV5HS295)3csV6n9vAh;cFG;|iRs=#Jq`UkGYUpotFpzdth`6oDU%6Qb z;c6v96td@gd+Dnzxs+Zy4oK3Z z5A8WJa69!_Ig#;hXzqAyeq)Rw{1}4?f+W{r7Ro*hq(b-&C0cpo4lXL{j^Q;aSTc1K zgZzq%?eGAXh6nAc_kzqb7?9#B3}G*?E3#X6?pT(ei!dVQ=Lo`E<2_Qm_${y23Wtj2 zNoW5e#LO}V6Fb;*P0w{RyloI$5}hBsshONqJOh#O*&c-nh*~33f(lXT?GepAY``jk zEW$O&4gK+|%ho{d{a%bV(nv`&0Awuzqag zOUfB4X08rKFh80KGH^vY+VueoJZ9EDcHfpQ?!B}}q&Ia?vAZ&)h7l;_*nIkk&StMg z904rBW!lT3%RCL?gE=Z?(~_;_(o7nj9d2Pn(u7m+J{&}u&8;f&wceh{#tUev#GP35 zjV)=}S$p7Lp1Kyo5`>+^1Ix%8)BoABJn*|793GyH(LEdraa*A>4%A$0s1S zgFfrOPxHm^O7`_55IPgYd|JY>Fkc##!*h=S=MT!FQ81u|iCAEm^UwixcrT1lw}qIF zmTWMUWjk7uxm1JdG4Tbm^#?2-mTZ(gmliLP6z$gi*N-z&AT+EUl&zyf9n_&GG>FcF zD8Z-AyAlz)nD*2cV3^9~TbesjRwKo;$-gE_?IeDRGo&4c3oVS7z;82EB<;NN#nO0- zxMVLNN=xvmK}MF~QQ!Q*7uBx_J8_`k=0uic`1QLBg>p~>fP#|{lf~5t?Wu&^np_ZE zHdO7vufVSZXarPm9VD}XOyke)3*Ai9D~0wt7$858SO+9%SaS{Uh>MHGwHt`tBKr@` zO-PZ^5I51;%$RK+4uR<>i!p|jCb$e6i@S?QL-gd2u`i|P7)Fzs)jd<=q~?KZ`b(xY z^6X3mmNntYKmDQX)31m~R>9}CpOX&GS!-)3Tcmte01a9rfZ4&~NRUYz>vb~08nqe? z#@Ed9f26bd0z76;(lieH|5yV@HW0qDx`I*IvKvGBD5O-5h3i{uA^zZrHPyqBhvfuW z?m(rRe5Z1-3P=-F`+eoX7M|{|1U0*?Ne6QhR=@2zp14f8i<)B%gANe}M$9U2{=-Jd zhq${k;%3>3^e`DNOxiH9bCe08PP!vj1cP=?<~P_fokc1913#!ij4|&YE`3sOpfqxJMVPoe7$JP z{USv2Z^#h#%&Kf~PHy`J$Ui_Rl|7^c9b~d1O{3IkX^&`!Wk43==vbST#9?O-ZU1er z(HuMj55_I@rYax_lRxN)lp$0A0+ee(g~&oUx44f3BMj;coLjny78+D{PEG?GNYh=@ z-A97~2?M?Le{`MNdb+{!Nq|*2wZ6s>(7b>pVt?mrKT{m^%QDRcGd5^ zaq7JvjJ9jqxvHe^0^#-4MJprw&HBsMGW4Vw8FmFF-i`h2HW5}M_2-IjpFeOYp2;T}W1BqUvtp%DMLEwP~g{FL5~KhU(;+?`KYR5X}KxNp4( zcm%i68jUSp7k+waFWS`BH%>yO!s5IPC0{MH-I_(QH3z$i->?{g9yvqyRkefD7T_WN zPm@l5N@%SMGk5ucNlfAGnAXbvUj8@bRu2-xcfx1$JI-9C`V|mF0VpN-5soOt3t>^* z4LvGEC-4s#T8`CZ@L*=MI`?|>*p6KAZ$J&p3IhUnmWPDF5Ow8L+WU{l)M~=V34}1o z`WVKNf9PZ?{eW<`IWIEwmW0<|5__@cK;gSWvN0kBYz>v9u-n#9r{k0cp>5)~{nIfj z#)Bl^41Adr?7lHX0R&7V0}>E4`~&=eLx_Q_3p83gbeTrr2zfV+h;eTM>=GRcGkBwE z=Ys;bUnCTVYllTJPo*mZYVRMbB!;wKWWz0TQGt^1g8>)Eti4{I2&&MZpf6~53ep7d z7U2iGeT2r!Le``oifFIPf1kfzuKgbTKGyZWGy;phfNL9%&7aL5OkelQ+sj{he+j0+ z(gHPNvFm92Cy!Gy_i`m=gGZTm3%)*%Cp$3r;$`4t_hx=Wc;P9zx`N29d#%HIjBF17 z=9n-7^9Tq-TyGdAow-9HcuVg|LynnDVCIErLcFrFBHg6WQ&jD1-&SQebuqa%9mDI1e+mnK@`e23fREKkQ z`W>Q(QOSsyIl@VY4)zE!R2Dq>&VHFmnLUl0;G*^s`;!Kf;I_UwqFWU^;Jd@H_R|FK zTI^Yl#4|BT=`xMa#O2w!f`+46(%%KXCFH;e&c*4D$e{sRu*V*lHDW~t&R0?`r_n`Q zfD$E`!#UiJJ3TYEK{9wrHpnkye=+=NNd1a5P`j8NW#c}^%Dd&viZD8!CaKR%IYM)I zk7sc_DwiqzLQ%`*?}YTkRBwwN&-c~(T(t*br7ETu>3;h@^kjp(noRrv_9mA@avE-mB7^w2_=e^CG)^M~*>i%m| zAQEkW;I3HNPqs(#oeB`iu4&X*mj*SzPhB<#nSMEYo&%jg@%L0Z)>gU8G-)55PgxRw za-F^;_M!d-i*tuU)g@C%t1pUuied}vS%soxc!#bZ+v`y3BS8x~Rg^YMbdd@%lFq^z zV5N^QkelqMGz`?Se$?TDN^)3j4?JM9LUPI{Rq+0dfW>+AJ|%nYfZ{lfGJjN6EAV?h zPm@3j>|T=-{`eOBuI_H3Op9$^t-P984W_{9kMpEq_mMOH6_bB>y-N+)BJotU8Zfg< zf@L@#ajljD+#bNl~_usx16x$U&!3xN=g=N0=w_q}BzF&Jr;6 zNpb!$UI|lkaF@txyK%6vUcJU4G1nYm?f7GlTB*OOa=ByhC7((MCv*yWDg2b8Zfm$q zMf&XuzFUt`s?!vln(Y+)ZaW2-E#YJptX0>V!RiVN?DN!)(#=ulFI|bn-*~U4SP857(;g3xQ zS#3jtM~}vi%Sd6Jl`NPIj48KQq!Cg^9#j^+K9HS|RBD?!^L6yMEb-o06k10{5CIoK zfiJAlyjL$8nOlQ2tsANkWK^#Zfu~;M5NfgViXNGY=feKAElVqM5C={8+<%717s0(9X4=K@aOFt;X(i{M`XFao>J5y z#-*ht>3~1}o@zYIR87Ngr#D6{)o#l6`Fx%ZZ`;L_Y%*7|`QOK1h2l?% zl)p}<%{;vX59OA+$G9XLJAt?i<`BEXr zxjTLfX<(K?9!!2?5CYBv3$aF3my*`(jjC&woA0(PN*~iwvns zCcKM>1LqG|Nn_`R{2g$3UabVoWV2DR4zfzCbpv*TP)6g4F_tv!JImu$sl$y4qAQ>K zt&t1?Y195$-7u#x z-OxVTikBI4$hVnq?*>Uv3|ags%R*&f9PTYdVJqg`ybXswPv|dqJ(tqe@A?EDNIA;}KK?K!N|A z=g3=G`lfNIGWB5{l5K4H&3^p5#=JJK2&Mla=AI=}VR-FFdbzLCXe&BmF$T!ns0rIS zZYcLJxNYKrf_Pb`R2k=_z!Q_pb(G2G=PhF_u4evEcbYIWk26|_s;F?Ci@fnpwRMIG z6j^ih!(rvVDDA0Yx9?>;M{tN1P|@s%5){0?$co-W;K-E)hsY3QcA`bZzIJ-nRuKgs zRI;z+!gnU=`V~jnV}yMi$=_j>Vj=w5{2EHw-oY2cNs@oR`zlSfE+Ea9uxe+q$ePct z58Fdkh{J0UCK->DXCOXchAmR#bgELI)Lc!{`iVhYG(q4pe|D-55 zQUC?3YLovSmFFsEEgN~~PjR3=6nomBI2u#iMs)q&QJciHIDmWx~eL9<{CrTBCF zW;+h#xT7J72|*kg7a|@ui{0R7t-yUTSNztZJ=>HtEeGdcGXgLF?un*GOo zaW>vjb0puZrZkHkZloKr0H-*ySx?4f2{eY$^yxX4GUcnXYC}APO1Ui#KbgPJ^F&_f zAUtK42xz(ZMP>mp^j<*o;YKBS5jt57P_%FT{Ez7dqo(Lrh;SCE1|^VKDdTH z2rR=oi&`a!WYqk2J?i81J4b0~@% zERVb5c4%*A*QA>$JY*erseMtS#G!PUYg2{ZL2&3A9406s8L@RLLIYccUmsHU2cyj0 zYDc5Pdr?J8UA(!78WkD4P0kMZyVzb8aiJc1$D?WB#<4?}KbIuoa57Lw%Fv2aeH5++ zvA9beWVK||5LEsLK0v|0=y2Jss8xoGcL+xH0B1O%k5Z%Xo+YfWFg6JPs~D6 zBv4jSh3k+++y3wS-pix1Kx!5C%tUPLG80mp%J=ek_mQQU11Il5^wZi0U#E%hL!XL+ zRQ#KXKfd#+);Pec*7Yg`LPs?S1dceI_93>efs&}< zp8#u6m+)jFz^4MHc-?5_ul6+azMm0$`apgh2b6jZJj@neK|Gu_TA)OoR^zpN>JINl zY1WO8DezkQtU86AR*#&?1O;_gh1jN6Zyr_mr$<$MEz)eivESkc5CXIg8vD(|8UEF@ zqxzSZ0;jUcVK*X9LZ69e?!?}j#S6iDSNH9H?~DPT&D>|U@{)+Yp9^1vJO<8F3oo@I~osl(cy8S}?G`SXvj{!e|%l~ou7v#1gUo;!8pbxEIhWhz!)utxO)PsIwJ z^U5*^e9xUP;?h&dSCtFy1@(IcPzDq)&VhX2s#fuL?O?xY|Aq(kMzhiQsEH>gXw4{(|G)dj7xk z19CRJKKrTEcOBtJqSTuLy@{O1tkbEMYUS#?RmkT{&NPRx|E`t~%k}2TyLS};|F77M zJ;8_-*lB-QtCt#wHTLo6b0fNCInWPcn1yxR&`I356s?5ga?ky23;8Sv*`+(3anGwP z-KkH!CRtQYL8#Ohq41{y?^;dPQZa0m<+mDrSFSG%gZ~kHT^I0|U%{`jCL@g^ z^ksZ0K*e3IJb@rV7)iuh#o>`IQOT8pmGB8y2K&n^4ZL;b;qx3scZ%q&bLhnk4g#nG zUIU$z>!c(@jV#ZZd3+rtagp7BWX90wKM_pWTw)sF4E6Vdi)<;DKm-GcI|x>2MYv}` znRw)0g0x{g6yUyige)}<$P0ll*qAiT8g%P~uUheCj0OBbb9tUYmLRF-XD`*_k_=0k8Rvh}fg#mmqZKF7D{`s=nW3 z6}F%WAFJgiiv^Goc5(bp!I!K#Cp;1i*5ggthZWL*zI1_%cu>|F^dh6Z6PW(Io(_R!=ply+ONn)Wc2gd6=I}6d;Ta%Jozn<6k?}V-)~VJ4v{{;o z*?Vg>E42Q&f@6lhVUeL*R%C1XH##GG(t(h8B-1L$FqkHe)DW8_hF`!J#CxDOxP#6{ zFqz9()!ufY<25l-wrisR!r z7`gr`iN_}jb0k2%kXGQ}*=rfiYhz8`+jM3%bjiueBT*SBhpJ;7{hA2z zS&Wej;F*wDVdacUMNZwhh(I;KbVBK0Ylo8rr43FK9`M)yA1TWReiVm^gIbz_Q^`_qse}$DifJ7QkQ>(c^`@ycNXb&$&KMror073P+-lSJXHUuV34raBwaGLbDMDVV31N(_GR=|}i64uBpdr&aODVP=Y0siBkunAl`co=(1)vb6KDMK-)(PNEGVgQ#xcr((@o)Oz!7<7d>X zSEEau%0&Z%>KgSj`eIf4+4)v$BZyS|lZaR-OhoM&yXM+54$ zmi{FljV-J3)%h*?N(ut#zy-dLGh`lk8WHMYkSttQ5iEcQ5tW#x%uAf7K>4sb9&qjslrcX`)u-wtkUaFKWM z06!Xh_%Q6+bU(~bcZBcvE>CT`AHGd@8+3HqyUl>_MECRB=(IiT+VDFO{=B{gpY!mp zy62!XoRNTe&VW z`8k{|^8p8SaA~h0kD|_eu6q{vq-kxT?KsIY@hG=hzyxIPzO$EmaimT!hBopY)`rkG z8ED5|TA$A$3;-2C1vUYSPvggUMN`mNJ-3>>ztetH+yU1OC)Nk7k zPHVb@-1SGN{od7?4ZWk>^+#13I-lH`Fr|Cn?%Uv6@Q^xU&Yd;$A(A_mNfVW!UlgAA z%9ydIqObIKh0ai*tbkvxk;s&l$#rWo3){0UGPf+s^xTIz5zD$XK?X?Obd!Vflcg-8 zFw9e_;IgGjefWr-1fRxw_692UzZpZ7BuJ*xqg*O&QI76 zn=28!YE3;Fv>) z$QBEcQW0WtFbPB8eQymxCnn}G6)$5@s`p$DFZK3{M(6@5uS*_2kXIL@@L<6UumEz7 ziJTuKgBc$k!%=YVs7PbtTAhn<_=-Cyei-O_jKf;u1P)e!2xCl)g=?^jPoYbR?;i~J z?4ZJb$gnXGD{iWW6EBT>>kjR$6fU<)6Wbziiz{(X;UdS2= z)xPJzZbiw6SVBrdHeO;fgbPOTF&%g!#@5qA&Z>>z#5t>kPf^-zDQJRBz zNj55!%jLZ>C8-6+QfZnJhv}xdobQ|NJ*eaE8A+R^mJj!H>hxi^-|b+E1l?Q%&TDxb zWaBKnlrwz;__Tf7xgd{q*twy9?>ISqAnFAF?+(VK;M0clZ%f%;i?HMX(dVdFCS-z8 zVQs3QY`NZQ{m^)v%>uuvRNFP36O8V0mgbYvufj#r%y=N zrKWODkxS|lTdEl=sWPLFTwXER=F%+iFjG(E!ANI#O}0kHZ8$kBoJ!LL2s&k%KsMP> zA0%anM|h;;Ju6?+KD+N>A!2ZODY=_cN~yj5mQ~Zi{lVbl-Sz15wc+2g=HKH0bPMR% zM;9bG1-Ujj}VH_SM_iUfhxqbV^FTwI#}pftrv04Knz)<)ZE-&du zl%yv>Jts+2luC)bMyp3KP3@wM$4)qfO}4P5rDbqa7U0*q&RfRz1Guq+v%CJ?P?J_h zKVr%c_8ax1qv^r4dDv()jv(4TtRC?i{NCShOs4n;8D`*8?N4T6rar29z4p>JKdkiT zK#lteH8Ow~y7Is^_uK~oTS^TMwX8u5g^h6v(*hK~te(DS*?zU(e+TDwgV#}dRbsOLs~YxG-Z1$!9*&-R%8d7tNE96( zd?rUJtvGy4gnKR9+GNX1iCbyO2;F;Mc##QVz#`9NUyV6F^tc^U1Vy)CJo>SB3y#p) z=tIAKK4w&jkgb8l+0=HVG0v#+{#>#!BF*yABR!VucIP9wjMWTH{@T&(K6z%}e{LoG zU$T&!%$2D@q`q^Jv1M=m*+;A~K-3w=oHW5Xkwx$`8Hp%Mn#Y4@F+cm{qc z1%hgQBjK)aijftd7WTjubsv!{A6@apelsV6t(?mVFmmB*8IzYHpxxJd)(|BULzU#B z_}i#E*J|5`REQj(&gC&n%a2=dEFDJO{~#$bgCKu4I2Z(@VUxFk7*5nX1m ztcXpM5Yq)IN$ijjd!j?tzyIQWGo4q%E}nX$xtAT|1gkaOc(R7kEwJo=XMo%pkO$35 zLHt^fk?b~xJu@Lt8E6TI85gSX=~Uv%xPQLW;-)kEB#dV(*t{9}V}t<%mN1c2Z% zWKVB<_vf|t*;zqvuxPfrhb80mYZD^Mn^)ycH1ZY(RU9JKrOKX&)nuAa%PGp%(v7Gq zmMRd4Eqa+5QE^T=27t2p3Tzr*ZHQaS4iUyN4#u{HIR|w>CppRRQngmCX1+MAzQiD} zvYT8jhR&D;ms8|I5rhT!zvNamJpjMTz3|Ko-+0_4=6>-}3n4eP8h-4xy}=DX24Le$ z4t6M{U32F(Op%i?!08&Ms1TQf0$4`6@4&+JI_pSY5ypm4Rf~tzi+5=3$VmFd^wq$-6{gc|`!dPfGZZy@_^`MW@Iz z8D9dLnZi(gsuQJHRFr=%xY&Lmx zgCz3SSsxPII`FJrXE!#SWlch3!z9%IIt%WIVv`MPUxL;bo42oUbV7m7FV9@D_URIn zz7d%AKx5-Cdl2gl$G#&=6Xc(!VS;i{T@O7Vq=%Y8a)@m4TNQ z$I@cRCJYs~S-bLum{J%s5jHM)x5A|WbE+E|DQ}xZO0rsc zu1UKXTw`;;W6TotN~A-ggzo+$UfYcWC-BOwjTjvLnh$xmDx&z$V4Jw=F4Q<3yK9o$N8$*f|*qXkmO2!~zOakGF zw187hObC8)slKzO9GcS2WxPu1NLx4Ok-?|8MI8<1CJ#=E{T}${1!tQjU%Y!nP8>R3 z9>(yW5>Gc3C{>4v0qOP{bg)rf6aNNFTtbu-40&uKlnN`I%t{$x{|Qf7a*WQ@7*hon zM$^xtvC5Z$Ami&tvf{W*YlM|F1tXh3Lb0R(5n~5z!Fi3=vP7qWQ*1J;4ugJ?oUJlV znk;7lHQBj7_R6Vuj0DrQ>;TYvG1!QrqykVhT|W^NoHz;f;mFFTq==GW41|E=aXME# zsa^_$PPeYac)auViM*3L4VZxJp9Xig<>hp|Wfdi->Lr$D+>suWxdL63 zVc2<1HzP#pZD-ov7vBs-%_*C6ruyYtU8PiCn9d1(A)QBd|HR9c5i8q4b0|W#y(hko zl+4O_B1`d;th8!k+F_kUMc1Q2_eWy9ksP$I-NR-8L~9Z{6r863gJX0=!t{FcKTH;3LM;B>f4X#FvPAwP@_ zMm@V;1{e5_u{qt5VUZ&$c(q#-FOWK%x5f0A3BrF zsX>~f)DGy<1FY!LMtR6zMuAH6aFt|uuy|N{b~I(y5ZGwQeoo0-K3Toi+L3sLxhl3H zxn)L~ZK5|LrotKW-)shq|L~I!@=+BJnh3beLxLwKY87uAaK6>qVO=G_tHfe~YB#9_ z6i|b{Q9@@K8o~&4;S}nOvRfcrEH2PvVUv2KP;!;gI|lh&yW&@Y<)wq2!5IHWgD`qP zFISw}NUl8;>ce{m?CR0xE+HP-*Cyn=7J&<#r~vee0BbsvGzypoWOcezIXxs-++hYn z!ql%y%rW>ui|(3jzO7!f>6#Bxx<4GKaf!){Tn#<%4f>Le;nGd_Fa86%@gMjbeZN{# z?1ng8ye%>fuQ?x~vM(8fQTic(TiUzj>WvGj(z)a63=^-^nQ|Cj9h9~su8M**@pq|v zt%LH8l+!fnl9;5ykpXKP*2in zf=s5vPIeja(L{GbBOM+)dGTc=vt=Bm;}N*IJB3t^gp!O` z2wYJ_orWSD!okdccC(v1bo8xy#?vj^t+FF}pWe!VK$1&xl9+9oNtl-Eow>4O8Z~{( z%H&haI3QqBHT1T_v}*X@Yx(yzrCAI4gjpVX*$17Om1Hipp^|k@$5CZo5i=Bt_Eo{( zNm^M=_kL=;KCQ(LmzNJM!;-}Fd`x)&et;JFgj6ydRk^At4U_Icq&~F=oyG)M z@yQ~*s$Cy=UwQb)+WY_gU;l6K`rsrDX@O*l0VdiFX1)kcQ9IqO@m&OdL=}$^6rC9rorK|K34XR&tz#!cmbu_OP3ky!|0B7d|#gp2&<0s|D;bci;7o`_t$aj)^G zcdOkZv#S@ud8l;jFqw(kZ1Ryoi~KUoB#6q#65XR&TS)R%Vj4V3v!|@zTh6X|M>z;& z7&w{|4&io2*`TGG6kaTgQ`sjI={a3*Hw9uDuVE;_NSLGOwQOzFIj0W@yL59D+t@{^;?ADe zxucogJNey92JX3fMi?@+seve|C(EsNnnb8EwK10y6*8TuXARZ`97KD z^~ay3>t^sYyqK=pqamX@*0kn$pi|GfVCX3MbG|;gG;sWwY{ow3a;2}NRA*ae)#~TT zU5+C6)f4m=a-}i{HB?)j3JL?Oy;bB5QwtU_{vp@S!R zrZc&yZdb`lFUlFa2bhN#x<{Fx=a&lV|``jm5;MG=bQ;$5V1j<+F28gzJ(;0nSJ?v z&M>(gJ-{#n&_Kv2Qqvj*7EnNA%fVjO7R+23Z8j>6IVB!fRvUb#U#&?+LJO(H!hYjt zbQAW(L~z&WF+lp$(s*P94Q}-g{Rmbdz>}AWto2$RD)=eqF4MlYFl8@wl*>l)+opk` z>Ok>BQ%Wae#l&rrBXyWTHQDwtg*`pSpYHGygqkQ&<)e*ouxQzUH3DQ#uKW~Qo~|y! zjbl+0i9AucptqZ7dY-v4d!BzNCqorCVJ{VO`x1lt-E6PcA%ot^1p=hM>d8wdyAqp= z9o^e7Xs`gz8cfeo@4~@Q(Zp;JblrfRi!P(t4#0~2yoz3FM9YYCy@#*WAu035YdTIG z@fWX@IXLudYLxGhfMB18&4 zoAg)Y8{QiEGKqmkX=5qh2heTyF(e0pa;ia=-I z36Xm^-#$P=NpO;2DqqVWTx1_U@Iwo)qI)3Mr!0nJzS0tQC+>;ln=~gX3X7lk5qmU) zSn)I%V6{WbP|>T8F%NU|T*E#JVs-^(*A$fn7%sgld@cqdGxCDVRiv1sek8_3?GAYK z&PQwuPL4bm882YOy_{1==YnL~>cz#qW2Dk24+lkKx@+g9Td z6#gVYDHzGXw0nOk6zaVaH1!mxSFfM0m?!+mymkxJ+fUbZV~Y9IDpVlruLF>rcBzFF zk*I-8Y_4Iudt|9=?}gwC5oboQRYr9ECWj-S)p$#?!;nCrD`r&`0EK|aAqA9iQ{Ba2 zhA2+QXyGT31c1IzstzOyy<0)fz0svMqJZ7II~4GEcZUMT?(RU`+(mxw=4CwG-7AlA zmoRMu0&?pTivAE5jZ6cEA6qUAGTwoc9==wW9cHfbb|lvwrdyqel=XcIVNwZ&QqUAJ zsY*O?klbK3i+1x+N@t-@e!}gXjbqG|IPe4ToHajjX{s@JW|}bzkMf=~$+fT;$cP0Dtn=uXAgE5?tfUEJn9_wQu}7 ztnh%4Mq*gy&_0wuzQBm(W}e3%uHn=d=V0#_Rloqhz`FGC%_h~tDpa7_WxW9T85`4b zaNdww8|~Ep-~SIA!+`N0U|bPCZTUBHUv#_>5u!-!kMguq`F zFzOnXb7Dn`MS0-#M^!D-eeE#mqBlf2_a#rM0^cv4bMN|0)8BEhFOUl!L|`_4kCIn zlw6-y#@sj)pn!JjD`O29t4QKnAd}!x=}D~&Jmh+mGM}Qe{EQHfcP4Zcr8N<{@KJEG zix$~BrRg>16eBgWg_7&N^0g_m#lJ8~gJYX?5!`gBJC6b zv*dU(uEvQJl_f}`$J9Htp+f-IpG2ovjh5WfC=;?Iu0_d`c}k!F3Rn=wQPau5siKz; zrM(lcHx5Y-Et*OjZ0X@k+uh@&G?|g*PQQd>5)7+cNfwk~gde7L=(VI%OWZ*XhoT%c z2~jf!PBW&7j3u34E#6G)Lu7lK(skbKl8Df7F>i#NdUr*24}*&k)PHi%~I%&5LOn03X3v#mn#wx4Qxkk7F{BSY=Y4uIM)J;GFW7*8^S@F z=CR5O)khX3D$`$bc}2Oj3y`9hEF$>8sftSVQifVv3uKV2w{~ z3~@ONuPB8IRUF;~%mC;&DjDE<0TN&;95L|~#Yb(>w%Hdie=7;P=sxJ~ge}zH;$)`110r&=)>yH)PP41R_*#h12`uaRHf=rW&m@ zMDcjC0QNAZ+|6SU={1)9qy}7rJj(9GH9ymf?_$bx5x&WDSS-Pg_PkHhM;O;8B@!Ll z@0E9tP_@P!)LGSEbkEFfA(KlCRwj_hZ)Lf%0cEZvkLCUr#wso$xiH|Z3@D`vE`c zv+EJSIV0`0Fk=dxqA4_QwyfSwmX-Ooj61yKfSKKr zY?UMpMXH%MHp{poNf2JCiXjFx42qF^pk|94?Bi-qsZ^rO@H&Se-i#$Lc(5t&-V3+g$)BL8m^!8{1&SP?SZYw*n-s zqg*#M+d$#Iv+P8U z8W!IJUujPa(#$V{Yo(og^YEQw#RcXS0~WP9^zJXOvlOjd0r{DpyeHp9aaIK|z)_T; zm1Q5}oX+qSqagAt|2o0pM0f<`*0to@V1lajb*}Jc5|5*$4w$KcAlBIRB(fx5punex z(@^$MOL5+~DP!6Xx%ya;i>^UDd)>eE5`g;$s;AKb=uq$E?KyA%Oa^usCw zNcM%~09mp%lKg7(m11TaC}39SbzDilaUdZFo%J@el8>f5bNx4BHCY|{&^v)yuHM0H zPEc3EtYJwlimQyOXXeefwMEWd0B8EjWnr#ldSe8s`IH#ngn!q?alN5 z5#5p8w473@4e%$KHR3grYI$+8vMJ?dBcG53sH~Fh^(uF|==2_JHj-c*7cN;b%_j!E za5|r;fD~DQvTqyO%ZuJ9a`_gZiC!Y`ziiF;0J|{lyqn1pl>&6f1=5~E)d(~>-@z#g z)NCCE-hR%UA?a0VSJ2ey0>`E_rN7x!`3@7qO}9I$%{mLWbUn$URE*#shC;HM#mooj z9OWGBT#X)hLmr_#NKS%c`l1demUXrgqh7})pYvdS2{&J|+hcZDvf`aZcVP8N2FT3B zD5TLH(3l&}m>>V;@GyT=3EJFV;oSHbftaF(Ju+Ew5!Nw%r{-R0jm5MkJhGafi?Czl0(%6C{E#k zkKmjl=IK2F4X+eA8@U_`m5C=<#4DZnKDt=1Vh+eR?B`tMh=TFjgH8^-jM}D5niTn+ z(Zh1}t3bU{W$(qb?`Bej+z3N7cCmR#GhPllBsxr8i%Hrm^N{1A9vW>WXYPe|RiJzf zW!e~xS({-RrYx)0idUY(MT!kp&rQh^Oc!bDAel-(Y%FlW3$|NKTSc}74WY3JFT;ga zYL!cflvZGqoYRlnZPO#EC}MzYdz>L6N#x4!CN6-}XfxeKm|?;)0T@-_%#W!8G12AScHxoBY zqNeg-9&RRH3yVxu)D z%e*Rn#!Qqaq=Zgx+fQIml9@jzZJ!N1qSmKwiHF`bv-_Da&2&8~1KN^u_qgt?xl6km zBVRJTi>}7{w7Kq@e%U26cc^O`Dsf)I|8-9ji+66%X8upKn%rNP1s!qq zCDx%r+fy!85MGjiT22QgW(0MSrke$&8rM}maxZy1G|F+_??{p`%~;F2N@Reu_j

  • !aJ0+ z7Mo64&2@7ifk&QUVh<%(<|LcAmY8n$JU32RVNfYu;Qx|S$~B)1KfpZO7k(;86Qfy0 ziQ?{2Bvsr!@+1p>${z9yB@BMVlAd}0rpuMOqTnTq^2C)A3|+wzy+CqOU;+9$CLyRb z>&*l0i$>Z~5i~=Q;+v70LP9Mn^E18X6v5K@lMU6;@u02AuMk!s^>yhQkWZ+{(q+bD zIyR)9RVCN`=-(Wtpf6sex8lN}c10()Oq5i!;A7_1IR%ehV@ICb|27{x=ApyBd!M^2 zr#&mb6CJ(lJxA(sr@WEME$8OH09&tB9z8TkuCe%ssx0uX1dr=p{x539*m!S%k|a0JM_<&>YsRo`Snf3c~IzT z1+Qx4HdzOJsXb?S-N4NjmrpgzFrDnXmE&e>Rz#!&DPCwmy}M0}e(c}<`x|q(Lo-*R zJCBTV-caIGCa4m?iYK{JAW4UDr|?S%zOyc8oUWc8%T-GLEhctxr5vP>NfC7l(?UWhBAZPZ z%&uLDU+Du>JX>90Au&x&ly4sC>;;qA;q`8jV`orkQ9%;Mt|x(N9G8Zk{EjD`U13}r zGIR9;+3h)hru@tO%uhn~x&GDSlMPZ#1&cgdyMS00#MtX+B0tW3^G2P1NhRD=F)Hy zs^!>-7|xc4@j*H`?V4}^v|Qu^#<3W+tNQf;rI7&k7LmdnEVWml)3C`Wkv3yRtuX~L zw)S>QOvlc@Q{I~eov#Mgl>qh4p{Xgna4Aqr9OT$UH7k%xC#sCbZY#y9ma_-u2m%X)?NchG9j2%7csrSK$IzR$NmVKLsx!DXKI{P@NGaj8w_8bTqR8Pm@2a zzQA^+iKEbh`Btmg(K zyIQ=Ne>mfPC&j6^X{SIFnrY^wDc$wr^Ju-6jL2+FAVN)4-F)+3`VquC!%(3~c!mW$ zg<|q-&K#+m9EZAR^8j~%FLh1s6;^)X zmmIf=DRKE^FH+~VN7aubOQ$Q&N3A8RgQQn@GaY0jI>@F(2T87A*>P{8gKYA35E>Y0 zj25d3`%vNy;a-w_gWskNy&-+&6L=_5*o;uBf#_jzstM%kddTC-YO`^eio9|wXc#EQ zH>G0yJ5^{{iET}}$|#5YoCP3BX{VQ!0E_76WH^^-akru}BwEJZVQ&*>D6|1Du{NX( z8F_vQIq&Vs^w2>sn9sxMmdZ6xLJ#;}ESJ2x#19xor7~fxD5IV-NK}@_2>=ntn-X!X zqxx2osr+i2Jq7G`;q0HGXU9Z>N^i+{N29E4Rq9^ z!A73J9^B5h27p|4@o2S}<*ZjqtefTuEkbf17?mZ>B2vkbK(00^b1GIv%>$+lWm5Z6 z+ljZUQ@%@Uk4?0H3e4Pi+)~x@xl@&VX{wTL-wx^TnauKYh0!s5S=8$b*xHM6#K=`r zHiG{A1yyK_3ILS7c^TIf(oEBw4(*UVr9-bkgebn3Brubpq zx3CH6#f2?Qow>B39Gv2Y79%d1-5@_z@o%oDzmg09$eGv#aI(VkV_Y)|(-Y~cPj->K zb2wK{Zn#tuw4OXf((@+D&y0;9&on;br2V1afA*Peb}XybK&b=Ru#K%SAR`Up&POjh z{Q5gmSAq46l(BPy<*(FBqdGBE`YL^QaeY)vW$ zr@>L+o_?N|Ty{#V5pDx2y5$0wa>f@Um-%{VNn$4qJf`?e z{^M@7jW7t}^;1s%9{?12+d zv}Cx``}SqnARd@X7OASsO{osFQFPvIBD`Z%NmvP2)ehIxFvET%}%&fu7YOY}b7oD)yMc+3Xz=Ri_e&Q9GkqvV)exsE*vIeSX5+n%j9 z^f0N4cu&ddIEym%i3F79RvWCVaS_5iqSJ_;Nfh!X5}~9Rkn07;1^VcpFOD9(BDObv za`fz*SKms8a!FSNx;q)IA3uA2|HjIZK`)bOE)<_SYKRo*O{_(fte>{Kr zP&lY_;h20&EgDN9)~UiDIqC4#j#(o9RFv8}Hv$JlJ>0kGjUMIv?9$p_WzmLhAPt>U?SY0uz(2*XSnO;QCKQUR7m1>N>9L7rVXaf5j9fBh2xZSQm#(V zR^%lR;57l=RsrxukliOk;iF7c$_WAv0Vm^p_WjebdemlR9gc%Pbm+{bpuSVxo#xEa z?r`SDaB2Ad>Gx0Wzk2>s&*dht@bdBe(WB#|R~pQX;2?JB?cnj#uQhi19|~#w_2X9> z8YWjN;DG|E64S}OzA(}8le;eBN{@xt%itoKl4nG?yo3hpFwfIW02-GZK2pj`j&-o` zbYSjIMZ!6WmK#zCmQ{W+S&^$(oKm2<9djt>u|i6?|YWSrAk|T5|Fk;hNCUtpX-S>X63oVOgxM{@~V;7b4P-yv`0^Vb}8@SN?cVEu9=1xEu~amE&<3* zAzIECyAb7FLJApUjVjj3)ma#ET!0An9dq;pH)6$D5zQT-877c4umZPQM}bN#w|S;K z+VS3<1}EpFq03Ij+v^2|>~Z*z7~bf1bXVk&syvxZ9L865O9BD6WxK2rRrnGuXVPAr z!P6@G4qM%;oP8IU`N&4rSDFk)Z04hCz+Y$~5X0YWkEvoAB}Sm^qpH@ds&OmtijpDz zX*8Ro8=Lb!X6uT0L7D9q;UOhy6py$tMDr=VHexBMwCOKvDDy#VAzPoQlR+Yu!zdDk zQgb0)`Zfy*K2nF;m}E*q%PK)!rY$qdzn??&?@(<|xxR{kQJyr*nZaIw^C$`EfY+AG zJwq^Te|JI*n&bCSUYuPY*tt4lail5kF8Ch&Bsiss)?IQ!c(W4}QA8~4LM-=giN!indiL-{oJ9iXcP~QHryerG5^Lq?3BYBX2C&S!TrHb9~VlqPs zCf}qgOCKJ}^wA@L%5M{JcTIBr;Hr$%I*>-O!u0}6kZ%m`jL!x%@+URsQrrSBgr9yC zy2tpmQ9DSF{rbD{!^hto9ZN~|GaWRd3XS7deto3tkCR!t=7?J{US(A6MJx^w1>Ole zV4RRucMAAVl#DbGIj4_)w2vx?#A-QPWzu}0bY@sBEzZMhPg$e`eA|z&K}KGrK^aOW zAJ7Xt4iTm@ipgo+o{NEQ9C*c9>WmWdbepgdeQ=O@juURja|dN-yvDo;-}v__Y;QEu zsT~edp-#_F*0d+a0^}t*9ErMKoJRr)S#+tuFhx@I5(au=y6ZYUZ7M3kL_E zG`{>!mAU_FG}^ADHi=h*^OBj&1&a*U!{a;gW_l;t)jQ~PNaaRWoA_`OpKzQ+MpIJm zOn7oR5C+q_Z~!A0R)#=N+`=QHhjIh8nOc z-!H#(`k!NAL(bwS2}ds@taly~#y3*GE`6N>0MA&qXey-J%0!$wzCL>N{N)ixZ7bUb zStV>R&Nmtx6C?f`?YkYKaWpdHz~<3)JMCzek)JAuSUTE!($}sDTl@p{fJwQQ&%^aL z&kK-cOSo772+-w8llE5YFxLx6{I~RZDlYn%G|LUwcDK$8)pobe3)423L8?dEJuRg# zI(ImabhI%_ylhm8+yYYomub0Mz+x%bM=LO2ALYgfp*cgwe`h@Is$4>e`QG$%E;8UF zQ+j>=guMr{L4PT{I+?6L%t=|MJ!GfierFjWGF^LO>$k3Ug8QSYN@o<`xMQ z(43;BMtq%hA4#Z{2Ppr9y60VXG-UGoB`d0G;rf)iEYe@NY3yS7A9mM4MuS(}M5`8s zKcmECOhTA!jVTa|FFRGl$%yPQ`O&5IKULV91+LLH6o|2+N~^*unu+%t?3HjB`>B)uu&Qwo3eFA2sXDcLBr%!r7n4t)P|3(Dnye8=YC|g@k>Ry z5{v*d<=3Q)mVgTL>@ot$iC7bBS)4KDur0|v-Ea#z-NB6^4Gm32NjIUcO?ZlST;Q2XQhtSj7E@uOFkX^Ze;keut*wqUkA6vCQvd?H1{Kj%t|ReFAN{ zs_A$(ai_#}A%(2M8rh3E<`>-Q{fX*I(=Q)*1LTh@4 zZkJF1DR%vVQ?Ub$z-;K$;hZ(Vv!Xi1C=;oj43PI4Cb%_d2Qw&bWiJ{;f8@hPyXKBh zF}Y&RARTl3yx5u)rBPUm3BldVK4V#&mt2z+v0@-e;H1(=y!Vkj<^ZFi0`@86W3V7! z9%ONoaQiOI*1;5#v}i6dKbwT9SXz)Rbz)mu*cuMf6Hg@s)a#bmF`27Sr&$J~YPDbCmZaHEE{VW&~W|-O^y5td*Q*o)jqy0L^23p-J+|^XK1v|6=^K zko{HR15^_H_s0jU(`&81%K6Qpi<3lKP(JAyhJy!JqSN5w!hMn_LL<^dr_M^;rtiqH z&>>QitKd45Qo=mYOoEFH)kbo{MQ|D8I8>(@I$au6Zr|ms2+ZU$C z1IQP=;}!`Py0i-ndR&So9G)PWz7792`m+w2 zD3jtejRCD00q+<*h*w+Vh$0zSvHVj{gykj{n!uNp0Wn{pk3A9i4r!?KT>0g7|ElSe;xt$5XkoYm*e) z5|U1-G>G*iNsG&pDP=uW)Bw!@)aKJ2zm}z&V{#b2LSSBco`F3g?;@qyF7OG(h}CU0 ziO75!Oflw4O(kaUCGuE;KTx&dSxr}q-Nn8Zg_jsU_u$+6PcY`|sNmK?V@xrGz=ic! z@@wXHv0C%8Ij6sw3JS69yyvA2kk_hQkiKx}e6z`}P9k|#xX9{DYU-LwY1I$zKl{+@ z#vg#ET5GSuPBX~DWv8HgQmewXlfV++cJyM^l#tv?5550ZU#4jg-!Rhf$X%Wd36z#z zT>es4fR{Tn<-i;+C3~H&f5~}ruJgz2bWt71y+@g};OfloAA0N23a7IOWL@n4`}^mw z9v?k>#ZhjlbHJ%#zg=yXxN3Tnq_-P-PITBgFSyJZS?$F~GVdWVd1uX>d;RLFUjwQ5 zlFRiJwgku_x+r@FeTv4R1_l}=7`wnwaef$$@nsxX@_&yblW6XGF=uD|He(OwzUW^k zas`Clni(?6ZyYJhf7H{}U zoV``r#@FPfC9kGpDc3Iy&cXEv}cV3-nPnJ;;MCR+ZXtWC%3NH>s6yqJI`~ zB6CF7qMw5dzldU9=(p_=Az(G1H$eOX7Iff&3fPJ+00EqO%3*jlT<+;;e|?l3c!_sA zUSl#|sxPP#*x?*ACQ0o6^62%^%j2VmRm`- zS@;@CA++?WRe%D1#NMT|i?c1w(y3lQy(75}WKtOFcqV=)ra5g1SS@pIC58oH#z25b zl8zZ>`cz?c(`k{TUMahy$rd@=;hZy`c1281kokhh+F%EY!m|!@k2c!ZE)QDr@P2K- zy`jl8z(glHK@l7PwS#%k>|&U?Y2}hC*0>Dvlq(Npmm&DP;s)lt2_WB+G;4(g0u{~F z372kkn{dw$|~1bl~GAIWvddEHivdrKAP3@npA^`}v z1VnbsmnNL7KR8{?q9lxJVpsVy6dYvMwgH%*t@F>Y^C&iZ1Lg}OYND}+74Ts-%9b`=CRkvs5p(&HBUHLym2kb7Wzv|#u*-T*q z>Rg-BFfc+g_pDI^vR@%-uIRZL#g0IA6<0=@4WRZSh*iYwhQ%zW&E0HOz${Xe%+c`- zzS%88j+i0!it=QsjgW$g=4p4wUW&96V&lT^9A&2H4-dq=ZSR-=^zCaQ^i^?SqLZ)(eMM(IzK6~iN{|YTxLo7 zziDjp<>c`>UbK?aIIm6f>qQV<$bCXimDFZY<=tipva%NrhhTI`MJXqeZ{W4~xKa|0 z+X*KFf3(pRJY4jX#!5cRuAo~7AJ>R*BW?N)CSx%aW#u=VA7WCJQOrORv)D_(m={^rQWRWv57~T1S;NDrhR} z#G_@;%=GJEoroUCFyVPNQ4tz;C;vfKukTDQ^P%CUgbx29KfaNpd=_AWew7r3$nw*w zRWBZYGMx$y31@(T#%4u4UI>7F@l^^WbjVMqKuQBTp`IraXkd_*S-4Hb8Nyl0eE>xU zx}0Ggp^nSXc>FV%?P?ZWvl@aad^3>dJBpO1J`M5v;e>s;`I53yBa=5u%MQ~_#QVP+6Zi zE>=07@sv!I=dJKJ&F-Soc6hgwBw&W3!RcCRYa~&SZovkq{Q~PLWRfF%;{3oUoXM!( z%4T!N->&dCQAi#4A(`U?E-dI>{jfxJ7qq94PArIu0QqE{kMq)laei>5sH2g_#51o7 ztbx&trqlG^QzYl?s_vcR_R9AZREuBw`Ej%|3g~Qb@2bJSup03)lOqT}4m!a}z_~jO z60AIbdi2eGm+%wRJfd9X7(=Sc^UgxF1uVsJ@(M0p1acg4fo;mf?1H38itiT7Fr-|s z_#7vJi7KKFx1qsqCe8qIHta;0Zz-nBB+gDULV>Qzw;y?K<5ukI3!>2l4xhrV*2ELt zTYDi=>7V0gZiBCCWX5J+Xh&XGMU{jo;2t;zHs;)x$Io7mUp*f`;r+=s7xP$Z26<83 z7lv@XNVK|KS`*!zn?fg|I4-k_xdV-PALNH4XO_p5Ykpn#6s zCm%6q5Mz=>_G6tiqGo-D4D+Ki-RYBYRJ%F=epQphbl`pNEq`eE@EXY)l?myMMdT+3si-zC zV%pd-vs0&#$Euzte>QtJ{Z7$qoa$b;0Ob)?dYVb^k`x&UVuYc|H|hi_K<@M7-hQ1m zL$p)p3kE&TAL_Ib`RRGif=iu?6C^iUjBG=XPCvlu3v#SR0*zjD?;6f0WP?Oc8Mzrp z%P=4()Cn>{r;Wr)kD{zJSyhlo!HM+@kZQ?Ua=VtNXK}*%?NYYnEbXRLoY@SaW$XJC zr!)w=ATf+$o>eIyl|xD0ubfUe^AL+teEgr8siKm+g-)IGI(ZSc-=X!hFk4*<2-T2^ zs7fR(FkenF_aYmSaglkJbCu!N&3xWUjLxBbC^Nop3RBJ1o~YI1XWt*gGL%fOrx%yo z`^ospeMvo6m!%c7{rbt{XAgB_VuuB-o4RFw_AGs_$>PlIE#fRRbKdlN{#=}g6Cz3{ zmONw|Kbr4!WhF}gyvRgmX~%l<%1K;l@EU})dAg*MF_}y*nYRrcysZ+VFTI?Sz{Z1s zT>8_%lz{_JgPn@ks11fs0j!2>sOGX`Qi;2TBOm-7%^$w9f<%d_R+3m~4ql!I zQ_9XLcJn}2I*iX&o9$G}SzrCo&Da?^BcKj-)a%`3BB0etl zN83tSpI;_&p4rxQL%GBlnOhUIEO+B;7&i+GKKfO-#81}pw{?0GSP8D>x$MfFDf*aQ z7aB4##eISAhf}I8An#K~QR=)w)rQmB^*dGtHeo@poql4IJQ4v#n%5GM{omQ?C3Qj^8`VOUmL0%h6y;y za3sEDn)L6|MK!iC}3XRMy;-uh+sEF0eYK$ys zn=a!mn@rvBOxYODwp5ce`SKrTLPumG;s`Vnfws6FtHV7uGA^jp{Zb9dukoKe!qt>-FF{J2>yh)Vd zXSH0x0XxGg>@W#ki!ATdN=38BQhil5$FJ*L1yIF19VvfpDUs^VRA?pARw?i{tt1@t7#s6M!a!6@D)Z^K%YaUm+_(LC9lD7#xuu2MKNJK#=ED*jhG z4|-A1U^bOIg7~N0Z=Q@lm%m)MABS+okIPvKC!=oB^v*srV>*~VT(HO$FUcLO#9LKS z*3hK}6Ko`vK;;$sE+x#A0;v?<Xio9lvKc5E}SdL{!!zsN>i-%E1kfJ?c<{-M-Q+Z z9u|+o$-HSE9)g}TW)?P9yb5l=dY0+OHJOR6D9SSMqL!Ra2C5lgX{ld;*qB^55Hg7@ zItem}=Be28^ zl&R!J>7ZR!LOJ0pAj>O?#rP9^`7UcaD=7BEW8W~SK_rW@mtC?y>kyc!M zIB|j?qGu}(<>6;Gp9x&WPl0T3>Nifr|2W>R)+dQ?58Y6(Mwz_y0OA!sVgIM+hu%Nv zx!tLEt=3e57@y}!FIn$E*CN+ub0GByuz<5)=dE5iF|QAl;)MVb;KXY#W-ostM9$1Q zlMJ*jSbUJaj+R)I>E!;yhbMPVo__!21n_$qDo_-^D_LyGyD3M!$@Y_w&|bnkTP6rz zY?TdotZv9sF)EVG+rX_Uo7k2{Gbh3YBsb~v$*S>JbM1*;rQwO$Ip;7 z<)4aApD5F{Q}2w}O;D%4B@@kJHGv}~7g{)pam0SVlII`o@QBHL3X!A;c);05nrb?N z(zv~D5S3Zjz&bfQx1O)%z`u42-VLDDti^dV-?&g+hXU=(y^UlP=#_b6V9gM0mR3ij|WxkM&5&$0o9E#GFwe4qlQ#J1N=AyzQ-JUwqpAftx0Pc z>=j52&^0iz1?N?~!Ve~SznDlkCb4&wQsY0n3yMCVgMm))>=@|?Vf*CXTH+;+Gu1 z8)yOMf|tl@wVj5>K+O2N#BDOMh`B(KaD+8&C6~JZmXh=$w*l}OaFT2D#&;1o9kAGw ze-auPQOP0Iap%lTr$Ob?u@6jrTU%xuSZWiM`&l?*6K#SGrS-U=p>C>cJ=*2Ql(r&i zx)bE!O#-zF7d*bJBUHHtTfT~{I>>>RNa;wf(k^JmeG-%J^8G{Z#IL`*qf|&$g+uwIcKuxM~Gq z)@9%h#X{?oEK!~dQ1|lAa~=L5H;7CjP=RNaKcc*%)Lw?citp3BDO=d1Nq2mQ%PZeO z>1HT7Pt5#}6iB!uapy1;xhpU0*w>_CoiDRkwN~uPVmS6ro`Ldm;^bwDOH-9n=TMKA z(UxEJy!#${$%@2{u>z?MpHp!1NJUu)Lf}xJ>8z=8A%}j+^=m#U~{_27? z*})#FYBOvNLPdxYgKB?RS0zm8|0CX}$Jl%f_b#b_pzmZ1oog}3wJZxIadb)nOPr1E z9}=IZpB-H&KS`#2k<$mh7L8-tG+Ht~WT$TRvXa7>c^o)ndZ?#n=q`5Us!Z=akVnGv zjNR7hB~0%>Kb$LDuedMcay8J?V9oLgBQ$nvD#_xks~udf zA~IV9+VF6VzM0~QOyVWnG!kN$5u8#TBnc;R0euz~{49!dH|@vq^_b&O*{*i|L!?Tl zPj?$k+RBbuWEpU89aEhG1JvW^4R)-KMs&~DQJ2?0G=XfW3=Yx@-j-u>8`XUK$ZHDoF`S`~QR%L?xE4T`M^*FV&v2J``DfoS6^K8POoeDPzU zN$d#vyE;A{;Qj^&la_A-Nenof$`6( z&T4L_mxmmy94*Nn0?OJvx*|SlKcEovO?0amRdFY$WqA;y=BMNVs2j|9RS2(fU0g=% zbx4ndE@-cx-Vx>3lx&=z@7h~|*j!&H5YRv>g-L5SX|FqL92WP{nQG| z&#Rvze!t5r$R~gNb!d+x`!*;FS^|+h>`B966%9Cb6|!8e`O5>*Ivkl0a_*st+L5@1 zJ5+YKUbxq8K!BTRvXM6ATpZZVbX1xRwXTT+5tb8hlSS9fWO!xqwU5j&quK&Kc=ay(xAL3MU#YnoxDF-N~6yr*J|krop;MA-C_j&YN4RW{+F%cYoUQ zc;KJ#xK&heE33?z;|7~IFHjwBAl~y%odWbR51%?yXlLpB1M)^meh)Gd*(k9pJbL2r zFYK>BwglMDNFw+J?MBaN{g?T$Q>lKMp;6C4KTMv zF0g>j^W+k)U%2?EiCFH_uXMSvriX_}PdJA=FuE*prNaU^AYir51K_s^K+l_#4+DT{ zAehb0?N35o`hX07;7RQxCvT#5Ll@iNpC;-j%XKGrnf}y!^7vUl{VV=5^S*wJzl~o$ z|3_~3P&ImS|MAOzJU%|s-REi|99okHq1E(WJpV`6F@cuvJ$?T0{>#U&zU}AsZh7|~ zJ$n4?Xng$r(>(;wESv|s#nyZL`au#qK#ZJnoSt3B5P<-Jt@dpBKu{x!;ub+-| zhye1n#%hCpG$d)*sgZm?K{t$$PdDC0v+bD+pz>m>>%4eKGwhy(QEH9g9X@NZo1pV7 ze{Bt~7BNbBR|@-8Wklg$E?D+_wX-kzt>n22$TR7BT4#QJK;Pv)6~8k5bXbU?FvUfv z=$aWjE+(Gud9Y9c1Wbck5~?~GCkP2I3`&n(PY(`GFj$D=n_T;#|04Oz99N#xy73}6&FsME^AQVtVM6e)T` zMIHrEk^2bmADUFE?4RBxxrb{D!TLbxCD-AkWIqPpv!icDm?m=(OhXxn1Shh~M;l2k zmRF)h?ZKdU4-zBN1|z(2vY<4srRKKsW~YBp7^*YxqyZ1E;?y|F3P3LZI>rmei`XB8 zQ$`l;gpJw6&c(;@rg)usPrrXMe(?O+@vHIogON&taV-OaSW=Nwj!3RzT+d24H-*%p z#8iOEkYfeIPw@u(O+5WdI**8BrNpqrrB-5M0B&z_Y>Hp`hm;MXYk%R! zO30U;@=Yi9_sj@iDV_M6i_`Q;wf33i)=l@)r^BlE(s@?XJ6pV+e(`obUN)HD>Y-?m zRG5U@KB7LqI^JF9>!x^rlH9ATOVS#-m8H_fnYd^Jj55ke@j9I@3r)4h-`>ZrVRX8b zC``%)<+wx%um`IUO`wqu|B@hDb%sqY^6o6cw8go1kHiO(986z-cSl)!Fi@nf0)Ht7 zxihRp;Hc1&yh-QvD@lQ6wDhb>K#SG#T$KST&i;`P&&qH`n7Lj^g(uCu?pc&=CQoAZCIuSo+jwrI?CjrfmHmEtIv%DGLD2~WDLY)0;yQ1~5TQw{d z!w2x+wdjlg9PoF!Cz80cX_gv^rH7J>vYC%nls=c!wa)vUqX!QP64>HL*mbLfT_@ug zwZhaG*OL(W#LWBLs};AU;mewQK}mkeU`U~bZpzAZNbHC=>834<`}C!qe{=p87Ory# zz&{I};0t;$&SLDX|GnXV7eg!jS!J7>Me!P6Z|=w?twCzqii*kplmzg%DJw(d9a>5{PiJ%pK{&m@rZZxlEOsBl14& zT}8(%&XnSoeSK1&XigQ_WL_NRbx>kQx?^M~O}0c|6ev}MNUM6T9o7KGc3mwIFr6qV zH9#H;IchPEobxuC%vJBFu5$l9R91)2f%@x}XN%%iJtCeJUr#3Nt4vk`y>z<9-YqbP6*FH?ydFa(fT z(KbleNH;%h~e@_Ug&XYE8gK6yv24qhP zLVMqdz-8)4P|m9$My>}L|=>}Z#u?Ao2W^T3qlXg zcuk}@K09W7vi`Pi5+w(2T0MA4M)Q)u&Ghh*HEdM(`aFmc6}olvEX}s7bQ0bzhPBcTx>G(oG(VP`Wfg;L+O$+{7`Ktg z{1l@i|BbBpKxHml#<7BH3>+x)aKS~U>e)hGoIP9m+q%iFne43|jA^5Jg<~Lx`Yiqx zlr(F+F=xp#&K-PN-1kq)2R4lSKQAAs)YfQk&__awfTcZH13|0GekwyOXE^xzV{osO z&BtJ2??QaihD%Hz6Ln@C!wguWaZv(KbQH;bHO7y5e8~iyWp&Bd^^9W4=iBZm)Nb^u z%<|X>z2}inxEES9EtY9OtO8?Wz|beZ)v@7JJO0_DkN%!jCP5ah#KAb=m_Uzn7(%9jJhzZOf0BlO)= zMch=x2$tf(^w^Zk6Adr&2vhXTiXZb};WaAFA>U+Bz4 z6=q`7(Sua53NErVm4aqB_YHrRACyUT;w(>StY+=aU}{cp=wUSG}k@m z^;4Zuvd*ujn@jb)O#W4grwnG2<5bRhz>GAJlfu!Te3vf;w6yoLriJhKvXEUpoJJ)*SeoTyusOrgNI5**>7(p4i>_6V?;|d#M^oXO=i$L|61eN;yG@kAxiFPn^ zWd3$`p$Ize6ILBYm2HMT^J>c>bc^e$O7sobt<)FmGfh{FKz~rR2WFJU9=$3Zrf0k5 z`FIg7u}8c5f~X&_rqdd9n}b2SHJrAG!!YP{`@vuu__KC%J{WfUVZSr&&%3SRpwkNc zZhtuG%)_wTowSF8*07a7sFB>(pe9a5mn0n-1enF-28Y4Ax(W0#0!`T^Q@`Pbf-h{@ zKK4{~hmuR1YYH<^+$DLpwtl7HmU=!|&Ew5f0n8bz%04*uqSZXePEJ4`*lA}lw^z2U z%&gcOX#ZdGsb^}DPq$e_KKW3>1WL99->*xM!@mg9*ciXL2SxUN7ZllQ*&MBqB=;a7 zlBKyMWc~^?F)*ko-O-qHs#j%7GWzAxk_o#KH5nbU^pqWOPl{qyL>E`weIx{YDo7pP-J(iP7OxCTxu|3SE2@^gFy`!yM=qU%_~<{J@s*u z1VKnqM0PD{iU9s>OIDXA3!K{@ zkuXZHS5CWIYU*Dfy}GY3#ozo>{c|s(jKi(tS`}_>!jx9##R8k`ado0PTeeUl5NRV` zC91SDd20CkK#S(ysa`L@(|wi2(pbF=mo{lu5<-h`zRfv6tZb#Ok6~dL4EdtC0AXbkC8t^QNZzT?Cy8#)r` z)sPuGVX0erC1`0vvScTIs~M8bF)s@^hMI@so{EQjbN}hn`w1T@WULuFv?fMh=g%xn zYaciXn`W(v7(>vXH}pVo3$2W1Xo&_}_fg+{{p9hphX$|aHQE^BZMDT6Vf2qE@Ai;t zZbp+L7vk~l6r8PUtx_UTe9G5#T`^_8isW7tq%!+G`+&^9n1tKl4p-j16Yu8m zADxLF{`ZWWCeTv?2)hVS%2%X{Lr4)gLwQv4(2yJ@vO61 z1TKgj4qbT_snw@Uml6!jD?30)2i{%PtJI%CA)1MSdj(a;S{T)r^!>47SLF?n71$L4 zOcv2{WWz77h+D|cZ=40P3WHu=>6PwkdY`dOG zxU{#dv?BOYl1kM8=JH8dXqE1simRY+bK3r&`mOGDB&$QVk3`?4J5;)h+P%`3(iF^! z$3>b`L3itR$>q4RfUDeA?H-u7lGEoKyUWF|T+^s>LM$xK-IL66r_6lnHq*K3K}ZQJ z_FB$$_r{Ndu&|$-toWBSQ6=pyWT?g^1m&7;ntRDlb`)ZQ^EBb{$VIt>i?OJ0c9zsH z%(3J|V>nM4$E{zoXjJV}XynHGoJ;DXY}{?%gm*c6tzq2=6&Y^6 zQ?4sV$9vhvs{|JmwG|_y$+qtP1IihuU;gGAl3ztycRe9@5PctJcNORl!c+uc_ z7|-9P3yt<0GEb*EYAaHS8alO9K+Wc@x6)*4|8rDUYeUXV<&|(&rtbD_b=OrwG}R+j zsoquA+U&8fg6ytKpPECe*1W5db!rZNb`E)(HBG}^-qZw|Al^W|s%ejP=Ix!S4sRB* zlAI!`A^XI-%!p*ZPzgIV ziI#H`el991Ou`lh-3k_)wsR7#yh)VHf?(XXCs9EvcAS%F=S{+0J=>myO_tpXVzKL- zL?>?&RS45Adfux*m_6qtx_Ogu7e==y(X%H}fiU~dN%Zn2(W@{CTes>}Ak2Yt68*eM z^eaqaU{9g~VGf;>801Z2P+<~7dlFUjH3!4Qx#i7bScO~JJhNA(9^*9JOw-Tj-Ids; z%{O~xS~rfE!#MLfXBF0&Ql$G81exzsZxlb%5OU<9f~zLR-wvI+5UQK+kT2_Rn$-2`b`ekWVPoLXuMs=dVYedh3`7Z-E%$+L6k%8Qv2GV=sg)k5_P;^4v*)_f zEfKrsm=W_2c6*Q8XZC3;WikF(Pg{e6r!9V5_ykW|?T+KJ{Hwif`K`a+w$$e)Z(BEu zW3jVcCQkiahgPC4&cfg_3Ui$0$x&XHr+ymE<`|$rDQJ^`ltb@6e95(e>8FB_7OZf+ z?q0Pk#Q`mo;((UtYbpaPF(e~z2RDGFz3p5G zoI)guAYBB@XbuE``E;Y1L@fo|6c~&cDx>fsoZ}WV$8NpwDvGxhXTz1A zaiyh21$j-dFIVhK`^oCX!`#2cO|l}b;Mj02(R5kzvREiYypXxBGjl>;E#E~lI z3&{92qI#+asXR*^O^{Lz+NKl-pXdZiXEBl5_pC3%>dDo^);SOfoIgz$E3R^A|_KL10#vJ-t6t?z6;lM^=uY#e|=smPi*rndZ z#)4$&dsupnA>}Tu7VY1J;2kDQu{&1mpL$vtRxwVR{oC0!>`VK8$F*}Mw;{8Cn*0R` zl@EX~C!pQ(TVb;~orS$wtJ!Q#e1A9_5dF71{rPl~pUqc63&uUyG3XcBdd!*hv*_&Y zi_X+R@OxG4geHL0S@8KV_*GBC9uEh`s4e?6v~I-yeHSIQDxZc{>NNPnD#pEJMXVREVU}1rIwtf*0A3nbOyst*y?v%-O04wX-)d` zS=jE+Cc&`X%TIJ|LhEO7vhR6lrOrdESH;L?0!W>Q7N3V!)$_2&LsZhK<0PeuXQ^$U zrFPu_SasEDJDZSFyYgXbrw&tVSjD7f0%&JfvG0LsrxmMS6_c0=Aax+xqMB7c5N#z~ zI?Z`2oP_N`Gic7c;e6g{_nO^KdpH;bJ%2WBRf5*f;$+_g(M}zRw&0}lfoP`=M4Jyp zyXt}1<5@H5)OH?-imFz}J`kO{0kE=)?miHm$_Jv8IuLC>5S{8XXlGZk@3HQ<4@9T( zf#{?TM28PVr}Ba5^s=ki_gHuOP7>}EzpUb>-IZ-ztfq_ z`jbg(+8gv+vw3R*nq#|FesjXxhJ!r!J=NV5d3Kn(x|PYZn8$6iH`Z8E*eB-!hV9zC55 zC*2NSNZb8(7|aLVa4_$-XOqF8J%wM&@1zLLL7)3Fm|luLdrV%v%JkVw(Pyv20IJdF zUVb>{s5VjeZepS6H=PWoSDC2$DWdK%QTHnob-$He#lCE^pMG=}6Io@V?x%>l&qUp? zOw|2ub`|@w$$rntVEV<5A0~i)Y86a|{mOLQA7odtFPrQSoeZX5O@)S*gJxg&Tr%9(hd_B#nx(L5I<=TWVgj3a|v4?A?F{a;i9hb^1+;67N z%TS(gn$_Qbn&yc~LQ@!evAdE5CdJ5yeSuN!>;t}?=AEi9$4wCft&SfCllgoePW)~g z>yA%`^KdSoAP6Saz}bSJZysP6t2$PC`N-|=f!x#?1Z)eC%0j_!4sxf`+hZo_r=h0W z=c)%~;N0hm5AD7$4h(P;ng#uCyEPon`m@fU-EQMc-Jm%PeE4s-+nx+t&DN|BlrZQ* z1AN09OeQUU%`W$Upuv2LBMdAm*yD-S7q5g)(F1$6S9SuI5>dXdrc_zZ`c|-qO$~m# zIyq!sUYqLuxcV9KQwoy=x0OU@;3x4(9QIVNUU8Rv=RzCc%^fB2Q|^lM<5*RjSM_Dl zJ?r@B$~3|E)J z`9gRP8JrTq!yEZNIVVwl4r%>V9EK|25kE-xAAD5R-?kRpntx?twn89nqz)@%wUxTu z`TZMtGc~Vf!&#>T+RLQr4_iII)$R9sPt!)kX!yf?nxhb zd1!Sj-yLQ_r`bYM>P~uaf9SFcU@*b|RC3d>0vA(PhmsIQ6H5PMUK~EIACyf3gUTe( zPT8$nohs3SCV*_N^vgBg(|Z8&wE>F{i?TxdFr+hRAEFPBSs=~ z1QVduS+N0Ve$%VQWB@n)X?x&LhOO3o)}8fcAck9hGi=QUL2nSuy8TY42^=*ThW&oe z_Xo4E<2U=0t{+VE!-foG-RM5nv4nWDJPS-R;0>HLv-g=!dEyYGbNWGZkLyh8W}+`c z)gOy^C)=}myA^h()6R6#3TLfm*qycf!EiX8ciU~h-|r5G&FM44fdR-*5Tt z`E=Tx^?U74cFVNYF~9m#){VRj9k-Zac>)!)cS<-7J}?}kf1_{=*w1;hJMGNo{h-(D zb!NdNY;_0y{%|tyb_U@D6pH@5-R?F0?$8I#XVMO*vvwy4gJ$T5vuPDe$<6N3zI`++ zqzFnzyqSYpI-QK)DbFWkc2Av7zg;D9j0qrpIcn{5Ino!LjDfUVZFAU12Y)(+$FD*L zA4B7Dz)+F-E@dZ}F;dVy7%r#HlGFwG`F-kC?O$1^N@bg`5RW zd(HN++wFCR^C}|vFO{lF|Bs|n&1Z8`rMlf_cQ_Ba!LU6TOnY#fX?JIxVQ zZ)PLPy3?F^kDfnyI97W&!s5X3?jn?&DbaGf@>a{xi=&J6B5bI&dXwGsJlq!M-D&QX zcgI@?0CC16ZqGJh=uNJ-VLU1V;dy7#=@~T~d8xT^vYord-KiQg@)Ga5v0lBSv`cGP z>~b1%WpD-b?}eqA%@39^i&ncBF}dADlN}aXF3Zi6kXCSw1cY=<8G0~M^oALF+WC$3 zpk_88P7j)%NfjW7GaPzpA6*83=L{du$^fZUWkh%d%dA>``#43hDihDhI}gKkrcQJb zC{-ICOGRT=Eh9Hi9Ra})v&#T!hVp?S;S_;O6YAvJi?%V9u|5r#jq@dzJ_nrU6V07F zMewQa_+m8ye9m`^#dSmFZqDEPvS_L((y^aUQJ_DW+@J$w4WFitSQ@ zEEy=jb2K;3QLz+8y0)o@^GU_)0MQ3~velbk1}I(Y+MqthB$VqPa56&HG0}Ay zycE9#-Z}*eG$<~AWAS67&yeAH;@jFDnC(X>$C~VxE#G+xKbE8<%oVkdmy{6B$ohp6 zi^|r=XRF;}=FPDt@pQ3@!`UHfPXT2-TO!lJta^03V(%>6gl;5il^}PGrm9eJ_StWQ zxxD_av5uBYa~&6Oj=d0gKzJ2Qw=m;?cseo#{1V2_(vL}l)c-8F1gReaKNT&6xK2P^ z;Z7Y_OGMABm-mmq9Y6T?{*xz1 z&%QY#k(NF9Zh)2Er1yP?wvD*^`OhRSSh>C`rWrOdFq$qiZe!2hFWI)GwL5H1aGuR} zD;%`Ki9hf4n&G@T><@d>Zg0?Qce+8h+3ke0VQ&_MgRnJgwcEXRyFVE8`&k2BW$UWL zqIxO*l7%Zx=VmJKnl;U!u+-MPKNyCcU_NaRn*O}s@qNG93d7dC)1OYe!)_<&cRFF; zp9a(6AnbQTxCFO?ZZ~KK{a)61RoVV%8dOtZPKA4vPGwNwGHaSOn^)~_b2yu|=3zSs zrcI#A{-E9M_UGZWIc&}+{&dorv?lPk-|Duf-EM2pYPLG_F4%uK%tx7+hUv(pQwAs}Qpoy;&%NvAWM0(x5gW_vcD z4hFr>bRNv6&EBj#=+EbVvlBFD&8a`n`n^>)?pu~hjTy%!H_yP>E^=yhIkFm7LAP1a zG9@;zI(`f29k3iNhHbfFRn5^EU}EcyIQIPC*A6|c9xhaJmNISniEiAan1xq}UfLY62v)-m zK1#7FWxM~@841K$t&;RHrX3$mC?@D~tlclAli~(luv`Um&Sy;pkOz*mZ)G7;bgK(a zK{P-dlVmn>&8;w)vHI^dYWR5K0@egQS2N$bBOP|Q8C&!Aa{=IyWT2P&58q%Af{@fIgLt|!gewO0-mfCf3N?`z%sMWb4@Wv9$`W$U1I~xL|J>gpO?4{Lho;j++kd>sU9e`; z?9ex5vT6w3Fo%)i{*jIx!9xk`2H!@4dbQj_X|32U4rpmr4)SHk=vy$}*`mE99f4Yv z_2s&H6v%UJwIhVUa9A~Wem}8dy8^9&6a?{@GrE)`uRCmCfYP>SvkjikWzDGK zEA83?J_trA4rw4@%b41+l^F=}tKnN)*5%Xu?EHXu5Zk$-|hcY(7fxfgR^Os3lf z;y(te&*j{=3U+NE9QIuz*tqOe!!}`bC5$C`o}8Z@xPzkia3lx{)Nf+8eKMWF&RF)9`XxEn3o45)(-msD*6UfQ5tzReIjwLeX#g~RyY!{2for@qtp7mnH z0CQv~2$xZ3#gfOARG`?aR0DsWq6=_#ND)3eFe~`*(wbCM@so_BqD<&-JfBuGKRR?6 zcZi=XrK9#V07B;RoU?OpJX#Ti@Livp&_EEd`}sC*8zH>9NrFRR1t@Ty+(Re0pmFs~ zG;EBt1ZkNhOh2?0hMIKMJC-G&esxf}qxJr~Z1Ttz=v^?!?e5R$%bl|fQLG1y3pe{u z22^jHK7|kocy0(Ha|mw{9#)Z%eKLM&r5W2)^?w7vd;vVC(^&;uA-tPk8m@79g8P_k z`(TmN6`y@jgR*?st)?`5mI)gF2wKX%cBm7w?02p~Ij6~ruwT>QrGLavl>*FN)UoX< zxC*h0Mo(1MN3`E-w;TwkG7%iTcodDh;bV@v0Sue8{Mmv2&OBsW+P{$TVUQs;vL`-l z&=T)JfU^R7(Ikjl2=eZ4Kk47NaDq5^_rlE|4e1H$Z5tMSS$W81=jbpk;3?6c z=-7Ywv3q69&LjXO+r>6AeF0iNWzwgeEWc&Ai@9Li&Vx1w3JF`+&~{Yv$0r z%~4Z3m0Tx}0XtS;DWo#O@Og9)3mx#c6^Kin3}%RqJH^Wf)tWnQCQMV#5lr8Y0i2zL zlE=I+ag_77%xBTXJ7+*^!IBTvniG3dIl=wSSNv5xtuBB!!L`?_2rZj zl9WlB>S;$>e*QBgJ>YJ>PF(&ze!13m^8?PR)L6IU0P=TneZnPa$`t|SFTo)~m(V+# zpSt!%!d~*1O}!xV^D9QP8FHQMozR z6Jps;CG%UyQI->*GB!p2^FEdOZIu~w$c{9Ak-idsE3jhRfX|I{#8&MsWYdc3mC!MF z(*Vro$#Pyl_@Uecn!}HKnuIOtuAsLQRdU_UqW4`_a$R1QiI6PwVk`u%Tpkxq!ReFn z*B+4j1W7C#LBXFnIlY@+v!`Iv7ZZYSkYrXca6gZAF0A%j!M1FQmK09>JF_NNNsxto zY8J+9k8ZkmX|0Rh^)y>C+6iZ-IC-j{+lwQAy;$$~4x zJ9(1~fJ=K6exKl`2T&(js7mMq*W@%o@6zrEzc`v8nljYOvB>bqW1F&4_F28-W;;V~ z-=C+Q%?fgU%*ef{5AgZv^l!2p+OV8H_BC zaB?kBr)t};hz92+3$C15yJJ{2R-W@A(urR`3qRGzlOZ#-8=z4!VzhjT0ObR+s|V$} zOoX6W@vFQB5_h_K;Rbq+Kr8)q!`yN6f>pCaOE@a0(rn+Ax_Z(HgG85K1fve1-EOuS zn7@{F-98`8;tu{)-C39`X* zcdlfR{aqpPT>f-|eUj-~eZF1X!|GalK5-E2pzg%-X%+jsmGm)Lidyj2VmsqQ z5vz*DGci6ytEr!L*nv(p3^eBG3`=fPgVw;QyK&wHg*ZnFW$+)E(?gj=*guGk7hyyC z$W=$u2zE^SG@#|>^#rpqBSgJOI0dqeU0MPb5Q_|C`t!|j224+yD^mlo7S9G)U+eSN zn(%iT5c8~}kOcB0u8*^AAm<=%*lt*{*c}k6)FvW@d_Xe$o0Oe%y5#t7@y6;9mz?bf zryx`Zb*jSvj8Oa9^}LRQ-a8tU{XzjVmC*uR_g~1#o1`+qsrp3gJgpAmNXL>gs#sVv zk6?Y+{aC&zw0(ML9}x1{1pF1doUw%DY6#a1q3*>GK}`Ye9~M(&aIKU|_|i`0NK_ z&Ak2Bdb$b3y0LU9ZWoazYz=eyJ|*wOms%3^>w`7rrqoCj7&gI`L<2`DBeWcy>lo!_ z(qVyP8+g!Iqw_y3FbJbj`I)(sErs;*X8)e{keo7w;l#udG3I+uFawDLD_mREFBUmZ zVJNG5Lh@gGfvhFuJ2HtQZU^{Pm@`p*Kv4afCAG`Jr3PSNxlO>D!Gx)mAangOX-#V3 zDCX(Z*T=`5YV3Dz0WM)j=a&duvtIr0%m)kYw#F{N1^V{x|0r$hSoN}AR(8ln*}*9l z${JnV4g~I%Po^l?klC$Fqsn410h%7#)2~?DfrQD>n@5{pci;RtR~C4I@vR@f0_Zr`n+N=aUh?wx>N2l<=SmW_9)AA&K^m zDLT19epRXpnBl0EctR5>eEn9_%S*QP>V_1JSb}9n|2%b$6QJ_rtSABhi&svhp3n77 zLJL`p*eO`3UAk?KeMS@z9iHrVZe|+*DF)DGKWxL^z6B^RlgU;{l(>zlRr07UQH3n_ zu42QN-}l9y>3KrA<#YFuPwJVz*&K9eTAN^_b*^Z|)~-c$c}&EuMrT5O4olPZtL_~X zllr)dTq+xoKAQq4>Djo4OpxS$r0#)Fo^Q*l2rvpP*JlWMyuuCnkKDv^6G7*;x%TYx zWcWh+Y3uWhH)H5Wu|cVVXD%Y6RR41|ogtp*XCCx2KY$Ry-zj-*UAu6Y|g|yw=2is2A-O*gS0Yc&(;KppK~e9tyXi4iym2aIs_Rp zn6{WsQw~oIQ0otYpA>CIH0fb00nb=5nCsqd?`}lz8<{oHXs*@5_!j0gD5zAzYE4?Q zE=PycOnV)|Z1(#D`0UMV6f;R1)Y!L!Q2@OVGRolE46&^8lo#EO7i;LY;vbe1kjVgi;;Ttw64#leVgSt@PYiZ@{hWYq&`$h4xR2dUB zG$a)=?fCp__j4~LHpiRU=k|h8Siq;E)2pSD2v?n2#qxWfm;Ah^F|*8~U)72PR|}AR{5f~tfIXptvR-*^LDUVGbRvhJ_w~>xiEhu# zJ?--GdF3p=a$HaKu7-e(M&riNt|DbhH(Hm+_x*gK#ykvIEPw%v=g1*_UP5@9{XX=| zebjWW?Zs+6a?5tH8HGL5{cLW##!k%F{}q0|7(`j-L>Xq|r8}8ISHqX?1jJgf?)Dj*pJJit5TP39`J;H(@#x18RAS&9)UlPNR_8bn z>!#E1Qs?zh+3l)#N`qA!i`Q&tXp&R{_PsLV&KW)egvo@dkRY?Q{#cO{Yg;F1%!!+JS2t3G~F$-EcIjK%w;VRtwD#i*8$Lz;zLTGD!Wf0cQux zMV1-HYOSj-@&cb0uIx97mDOCY*ZfDN*~*AnQEx7np3JkYHwVg2%RFv4C-B`%GMFo6 zsbE-=|EtXBAJc330>KraYWglwW-gwd+|F$B#W@1}Vy5^!9vQ+*5x3vF_p5B+#W;{Yv%{jFHA8p0~E@ou{!UYip%G9InSlfJo>7kQ_&j-fYixqLN@m!XY03gNGOS3TUVC>O?JZm|z* z`afW?#!M50t#_|?c$T1p_cOE2U9|YQFYR6#hc*m5Dr)Vyb4)sRpkpo_q4|C-Xr0UcUjP;M(1-5{KvaFe zk(2kFRR_e$UataekbWvLXu;}){tv3oH|n;t{01J|c%S7CD}4$Lmd>36j#F7mRuxN% zsxL7(U^50C+wK$ZG2_FzTjZh6ik%(1`hcKXS-%_b0Lq^oOdTun9W{pI3rXgtU2+)n z527NfKvqh6^VLvp0WWiSdMcy}JwR13AJq@WQi=Pk4_T-|YNRIkfdR`|b?rcl>Y%d& zM)Yk3m9f5$C6UvpLEdVhB@vfT~@JJrA4kZ&j8D?K-E>46)VjAu|*R z3$u0p#sN!AyIGBgY(Z)+6nIx4s(_Q%D3s^I$gP+DcYm7;BFln{xb9rFw@}n$5`w~n z9kapLt(%#3n}2AkiW%Bvai+)Gust6h9wA3CB+G_r_PIRd)1;MYNuOS9@}s&iv zZz=G9%L~azVddr4Q+^q+Lk?I8)vvgxxQ{Q#f?GsV%cD7|#Z5w~S|lI%k=L_f>aSQL zppRnPaFuoY@>{@HO8Kj_3P$WbMT&BT91T#zmr{M<vImOj}OJ>zEa1kG;=g!|dw`yBC z6xHrKekR(9nqpBf>rcMbi!<8P^RutIu}$Wo;;-_}902(6mZ|dg#91+U<*2a{%S8(z zGdmftI@sdi+Qw2aZtTs^3&@J=m7bb_I!*d5t0Q;!OYvKxKEpph*WDRuS!!RVa6P}V-H zJ}-I2m^@`bHz;de%snrE#Xz#`wmfeH#&A(_m-__IahZ>lC^Pa8r2c1ym zCEVn!C6(Yi+);OY745V3|MhFhT#_94v(ua$t>L3XA;?pa1Q}KeekW!{;DK*;Zmqo(W7^ zD${x~QF2#h!5ujh9W|6;^5J}A0=_Y4|8s;MsJEJjJ7WENr}03{2|GGzS={T6xZkd_ zfI^W_d$(F@r$gbO13V2&ko?A1;iyvNtWtLFAE`fYce$Gadf4aY9U8i~pB3!B;{Sjr zxkcG_YLfIv`-(Z&dpOS!FYT~q60NNz5Xt88d1YOk_8OhT^Y#9EhB=Cu8d09+5FVYB z;WbSnqp9}+W?Ts#(2&$=7A7H5(_6oCt81t^n`g=uj;{7@UKv{N%&=OA5VBPP8r(-7%D5}I=v#5TyW2f5j>tk1%on_^8u+Yq0xj+=!p)6UFmx+U zLMLcSIOxB5vC4KMXCJ;@ixv*auqtiTFm#<%U;W&Jzq>83t@_Gd&U}BpCGWjo`h)x@ zfPnHhe}wU>;U3bu`)b`AL362-tc5@aSi2TU#5atb;UeBZ#H17rhMa~m6Jpzcfn{Uo zO=S}WbyqSFGkxaDnLlpl!98*8++h%bbdJ+)puL(H$y7_(`fAQ;eTRrYbd1S`-I*R} zrbs1zWbYAYfu#ISuPB2-=3*CcYwKkK=Nzsm8$;;*Nz^_nBZ7n52;4PNxS2QA792Gp zF7DLEpqPs&_Nl&-DRMaFR<>u#Qpu34ev%0ibt>C6Qi&6ldCCf>WbLz2&J4m(7iqqd z5z5k65C9c?ETzIi&NbljorC{s&Q-KYHQ{B2AwXV{lZtYUIs zR_N6_>Ia_!LtW{3sJf4eImnHXd;*`6s-#_{8z=4bm>q5xE~%VZPwf!C*~uK|TE0_H z4Oqo!5m~&dG9tgHe1?f;B9E$F!5$R>V8)wW4sdUe*=zk})M)6Ygq5M>7i}6`HUF_R zj5l9^dOI3dEh{$~OTaJ8J_I)>i|AKbc{|mL^{KWNw6h3}4db^Fs6brMvY#T-dY4H{)4X>cMi5BJZ!(D_2P zm*@G$-QtY)71>7;gk(2Sj_;oLj&_6oFmbK#e~bo0Q=K^Alq;=Rv16sW0EFyyTQ4SU z6@EseR#d_@6Kb8%k>X>Wx0^}SI{Z>a`C$(QBL0CBlps`_GQzXifGEiTkc;{o?p`qr zhxvk}cIQ%~)tvMQ2xI@~t}Qr6UyA_w^3#K+qNu5iG{ln+Q@ZRg=jyC%6f~$bdz{~S zIN^B@Hnm|zn|n*h?Rs1r{z|ZZ-7MdEfa`yHQl=E91ysrrVq!ooW)Bz^ST^nm|FLVj zk1Z_zw;^RW9TMl$f4lKYC9THLwv7vMXK8{G5g|h^AZ^B}b(PkHa-e8uciOW(s!5*# zoPcL5|f~}3*=md-pXzddDu5vp}Y}4hOp44l}uXZ?He`54X7DW ztvcYR3ECH!5~;+buVx0x$10-?k)CW{lQ2`lNqKwih_MS}fmxx-MN zizTOSomC=He9EBvNEU4$-#4qbP7yuztG3b~GwcMF1F{~^sFw-74kUy*65L7Mc;nZ1-~AAo zb_cFW?^G>}!ahPXVhuD0q$B=_yf+HHc5L=dpKYhVG*8yI@phq_e)&`HPl8bF6YUzH z#6D>5r)Isa<=4c=>l2Ylti^T1o#8&ihC<|KhJvuck9U-CJkgybTf!-lt`uBTEprJ) z#nSpir(9KOI!R%OUNARyw> z-%1yh_tUcJ8X!cDLNteV^;@f4@H2iEx7af`8P^Js5iTT!OX+o>`iHIKn1M$|ul;5# zMsr$T*bQwD%Qz)e)gh|BF(wb&u|s6?<#0KyeCH&G#f=vcED<7;c3s{e{=@wmsejw$ z6j+qDCMrVCCkvIsoF9%w(`-47G6~@COBOTx9JPI#HA`WhaXJzU#6~;5X9$L&XKm7} z*L1Z3E!W&cRbuMC@oG>j-yE2CXx!5xPWu`Ak7WUK$4k11YuYq#j`>}40~=d0Cy?&J zUF?gAPTy}7e~~&k5@x*7Gc|CEZ!ELQ5VRFZfD?=iE1_&VdpjwSZtFD99dmobp~heHv|${T zE(=LYRUoZacql(ZIDETd>)wj&O@*NNkkA{eYr;pX~{<=*Y=RVl(ZSS`+NI^E@ z>G(ST_!{1cqLIi=}KyX%0xt@bO+r7reu>+0$CYs}IolMK`MGxUnz;Q|Z! zYsC#!w$B)kjUd6s|Be5afX9sOz3<40*a|>QgVRD zOCd9R4+{c`?9l|e#BXhaCk>eUe2a9M1}IZWz6S{av7CPz;2X2Qg*S2FKd{Ff_;e zQP;NUZZ2I0hb2(+ClR;zEG|dO^(`z90gDFr8j#WMD;?-aZAvp8dX+IpNIyTn!#c#F_{mG2cBlxPs;P&Z zlp{mZryEWMiVkORT$2<#v9nF^Y>@XFjdQx>@Wp$*U^SR+Cj#A}wd*_^FYsfoUK;NA zBa3L`Gf+i8=*EX{j!gj*dXS4>pWv{_8nw8j@M^S``k!{Sba}Lw{bu(Qbj#yGn3KL- z_|e-Tw*p^22ur2#evb|fWPHEu^q9unTEiE^_|=DLKD0NaKM%F{9lUKVX9yBi3`P(Fo;(4?YCGJJ6v{do)93a|M4gvek{* zvqfL3&ZNuo6(u&L&mjzYNgeiWbwexn%$gLC6$iHC&pn^(U9Z4n^0@^%_0-!P>BbR zF@hM&(H}eEXolGF1DgDnD!#$vczh;qSF^4hGJ1hyq@d1TeH$sfk%-KN26=n2fp_$~ ziJ{v$j#wMFAaSEOrk8Byiwc+{lUHMjKD%AGYq%EqJo3F#S%aZe{&-{k5gk8-%Mj>w zZ{_v=oN;rOpAt*>Vfp?)f@f+7>nJ&x@-c^$usowJR5l#C{G5-P(U09v=*&Z|!t1hs zUDnQ=k9h;EC$6`|`8Ua$t;Uxjuzqbrl2W_KZ_j~rC}uO1%LxE6>3;}W#pH9a*3s-r zu^@O2MC)(UGuILSyT+J0Z^#o=5Og>SZyjM0@IWUsq^2h~5|Nrv>`}TSYgf&wJJsQE z-K>Q7IK^n6cn)%tyX~!c1 zayEh0Lq#Ldjc(vG2~)M0%SlWvAl{z8z$YwO5AE^tQO8)1*Tu!<03U!8eM!VFxQ3_!9?sAd^8n#iXcY zq9h_2M$5{dY5ja;(q+F_f_dgQZ-8%A1pIDxUn6K8*dK_5$3x=u-<(6fFXzY4Y9#J= zx=nn*y!$Hlo)gh+DwpGrX&yYhMlJyhsf@>%1~RpoyH0-#*6$E8O`qt)U>p1aK zjP(zh=IUc>psXybitHeC2$e?FyUy*KcFo+h?_t{k3#Wg>$O9%lnAB1+-xBhE4z!;h z$JFzzFHZ1PKPkFr!-z!#gLol*I|hSX$k6*b_yCB~B)B16XoxHi>!LOyZMtVeSHS4E~g92x@QQ*PZPdOW}Rc&tI zJ^8nfbuS8g7Eu_831b#M;hu772Y=2a<;-P*0O1n%$9vN2s=uYu@eP+y@*SzO7 zL}W-#K#-dSVzF8Xp^8B_Nsgywwu8D6|N6Cq2yF&OyWs;Q(>Ne7)U+{bXwP^I>Vg6r z#Nt}k!QMhOf3eB8$xP2bAXV&xTq-%4J6&@K2Erm$hs&K3WLjqGaajI+57qo36CT7{ zM;8#{Q^Ham??YrGmw+;Jj2B237-H6Jl@+|7QzzJ^WXQi%-^~~m#U;&yl+S8lX_ae+ zr&~TLJnLlGv0`&^%9kU|`7dNwgjPKi0#Vdwh{Bg+o!}kjXa^=^yw|;2)5;QBEJ2Zw zu=~m#%!?&&ZGspi2@SR|gkD0ZX8oPGlhTHdHJt|BLqD_yl5jO0t9#~HsZ^A;4nIQh z&LY)99C2o7rR(cjUzT@l{sDZ#f9YB3YfnC~B3gfIsQJJ-FpcQo8i-2_L=s{6Sj#xn zew^{7sbfMa;kuG+17)qFct9+PXNg{94_%Czp){O~@j?C+4U5pX!x?%0`0;Y!pu+qU zN3E<84_xO{BMPN`YA2lzuh`j6j}{?D^dj2->ab@mBM%p5LPXz=S>`SXWJ#^J;<4xf z^YeVPVDtH+31_{pn*8!6C()mP5OU1}+KI*xI;w~*!mi)jC0NBKs^+Qk+1gSwn>xhR z^joAwLJ)FX;?w&fwHfw?lne`Yd^*R@`KL5W7fy5<7G-546jQ($R#cDFwc6C>wp|-; zA3-Ua)xGNTnm+?>*LOUcRko*HM|kt&0*tV>Z}}OHKdgmz{qTpURc6nUtzbT*(uO5# zhT(lg-Bw)`4S`nDf?=Dhn;DFA{unJWwU+_HQdkv;Yz&Z$R}}!li5Vl=yROiyXg!?2 zVK77V(8X^?G{Vp*Yk!9XkRi4%!4(>}ZQQ}IaH|%9v~Foj703u1Z$Cn$rMRkfCC!f` zqxOubU02?HKp@r5)eAQg%9aJI>JbrABSVZdMt@)Hir|g0@hTr2Fi1SiHpMaWOvWXCxS9&Hf6YNFa-#4gTeX z_=kj#8sd5dOw>r_%qkJFhz)CtX{2HrjJ=Q2v$rz~IB>p5SxeAuhqcHvuO-t^y6I2KIq33+XYW2>0r4K@NPjA< z4wv21Xp-RJHMqqwotng7Z^b<2J2puQCr`vUE@exf)-2PvM85fFpAe8P8q;zXMz#ki zu3ojkT?)_~o!Rbb5=ZV7ENO58vW$36PL7;$V^P7spil;pM+;5ue_T6@+ zby=#Z;fU+BVJSjK)iG<8232v)DEoyQuAvNSrNY1JdNv#A1*1O}9Q`{Tn>9BGHCw;d z;O{)Z#-SN*`|q=#LzpXeG{h-uZKC6Bo?nY^%TG#|Fk&8pz~&=>gD}ns~vB64tYbtFa` zvLam5q-zae*qYZUcn z{)QYsem-YVG1#sb_vWzh#<1{RTszWS+qPRYa^T^UB~hk!5>_L?ZPFuG`PdS+*r<%uBT^aJ4`UTM+6X*S9OH`ny~*VSb9frr-F} z%(XRzcBqrLM}N7w_>05itV!jXbZ-+bRT12GKXE6+-=J5M7l-$na_BF}bvdui*bAC; z7h;-hWW-i`Lq<%s_FA+%$VYP`) zToID$=DId^W&uAFdOs`l%et;IK-~C(dRwvl7?yk@ami%h^1xuYz#{Y##$3HRg1)wK zeiTDRqaQ1_A$sx_H}ErI#^@42ZDPF-L3~OigXn$-@pe*spFXdNcu5|Ye+UksGw-E) zap0#>x?|kUhwD;k4*bb5tiR3sQ)d>^4Du{0tNNK*Kyiyxi7UfIiK1$q@poBk1NFC zwbSb!;{*q?SmAjykwdb)Azm>Ht(PMe6LA*2?7lPQFy9qTD{e2EU3}`N?L;NJn>kzx zaN{Hmm!3_M*S&agFExgnLt`*w2>b6}n|4^kVXJn{DlC-FjVx=kb=$y!vWF)QbMZJv z#dMz6ax&pFcB{yjb=i`gLM<&&%K)MkHx~9>DDwB;-YWY?HSY-N03k3co#a>3-ZWOS zWpdE{$^4nFSRKBmt{jfeDF!k_UVGdWk*zv>(~%!WBYjO zd%0aFC(Wju=LJ(ZSj2h67~T0!-H(wP7zIFs*2RK3F8m;&`%?=F!M9DD)`O0Jg8%(e zX-nc1HB-`Thp*f-s>k6L3{e%ZnKPp~Zcftwg?#T3@H-*JZkn|U@bX8Y`Q=0?dlJR@ zTgR|PzY)X%){T7&D0gKiC=7Enl}dp?f8z8W>R=l^KQtD$#suo z^hiWR0Tv;1S{l_qHB!K=yo~z}2yR90wmBRjfO$tZT+Q569 z*kFr?B(T`PP)!Qybj+jBuiDBx{-POJQ{sM~w)?$3h@BYqP+_^wX?*Hs%YbKzD5V=b z0&Fp+BYP&6>ngA%eT5!$w+LZrb4p1^5#J4l_dcrTYQg;}Vbp#8%LDF9vCUXQvfe67 zd)vKJ`N^lJsH-3(HzCND#G;Sm>NlDlt%MhoIEk52T;wU=$OT{NEdBw2zz<_JVN}p8 zufgAJfnIuEIag{GnSB_&rES|7Bz}QGZTN<$oDgsWCxZJ;+62#fjx|_@3ny9D!mFOE z4B^|}3NvDbN+5q(98_V1EX{;yXg?qP%V=rOyOOIAIl(b&u0JhROSj0^Q?ZRq8jYjr z^t39lDGhQ)vepVQMj1O0uhR8Ko%YScKSvWr{A{X#41pD{^=z#OP6)1Iqv z8dg}Af(&a};7n1>m79{}+|ipBm>x!pdGbgwD`oV9H>c9Ge6kn_TwK| zcYwuM?d$JT1VVRr-tqggQvOr&yo(3!mX4pFI(lfZaq)HOJQCajr`7e4q04bwHyu-n zlIGZlIb8%5zuXWzCfqM6TT7+VfGqU}%73ND!*`Be}5 zFnso9mdj*&b1n$SqicM_EA-&As~N3pcjfORI}fd=u@GcQHT+GFT@jMbkR~eq&GU+O z4C1ulUg!h_?>z)srOEc{D*0>Y@Ap-G9FD3};=~6*FdzfD_!~%Qzl^c3FxTjBjMH}k zrb!uG?4( z51}EB{B0F&LC9L0Mf-I0BWBzzdey6BD{fe%M=&l)KftX&;1L`S2GAWpnFO6W&JV!@ zj=xgE29+dvxqh+_2ii-SHsv4^R}(Ji1JD0OaTGA1lQI;dWj0B^!GKe}Ex@O@zqfnBJonA$;HbgU$i^V)vzv z|=Z3ELb3jwfu}jmJI|FnW72bZ}v$&<4 zmh59U#uSLEN0_>Y43c%FL1d-Da5e2pB22K$fVZ2Ej`Z2VRl*3aiC3SemRVZRg&MSK zSew8&CO?uhuC$_;P6ouBn3k3j&B3IcQ-ixbxp{bGjYqp3%q z&Ds_|frcWZ*D+d${QCwfJE8GpM~b^&PuoQsZeD!F6Tug(8AE%}-&u|VC*f>>q}QQY zknE5f+RrPGtn|x^k8OQ@^5+W6J`JEMLLgjX>8Gp-@e#Cb@a)4gRQZ^rUjkAfL3F2= z(i0xapsoXm*2Yg?<+cf7u=7&5xa1oaOk`JSFGYM3!CvQzN9pF3_q?nhFM87WTR;%-g*7a^_KV;qtLRTCnT6%j&XI+nIJ6g<=Hb0%b9@wXeXos`-{y@2iq zQ?_Y*>%F-M(3TE*i8IR;a|Xs$IUW&h7E^;AN4NO~^PX}cA7sb>ByUvGqS@6aDy>bW zS&O?0Ns2AgM)2{(ZaCW2`fSacJjJi>+I?5$U?JQ0D5KgGtz*y2E2INM~_3nSzl zxf0Am`|3Ab|B%2knmv}bXXDP*sZ^BAWH&*!-+PKQGyfoFuEb5OQW;{~ftLX=&au%7 zkdq5`nnKadCLm|WnvK9HWgo3=^OT#D;uq+E*PL+p`c2qy0&KxA=pXYRa7=Q&7efd$ z91mr8Q#^wcoLV}$(KI+H61ac%Pb{z59zVU=+Ox19Khac~kN4uJ{bfee>`WE%7Yj^) z=>K~t+JmWrBLQX&S>=CiluD^Xn;-yAvbZpS9n~j!`7hbQed!EXJj9Nxm;D+}_(zZ` z+H-k2s2uwMj@m~`N%sA3>j^`gk~}ADafoqk zC$dlSxjGpZ-d?RD3Q2{@89BD(OKq#Y!Alip?u0$_`@C7C>=C_jT2&CknU5mAzVQ>@ z`~H^mwPF&?S{EOi|3JSf;zM=<2l!v;ah>H07VexVyvUie>wlls-pB8+Z$vt%uub*D zUcQIZ)PX7xJ$>_+%Y{8qxPU7sP8c~UMSR*P>}qE#zzh);R9Cqyz&KHf5hlF(NH zGV>0Fwc{x;xx{&I6Q2}@f`sPm5u7VSeC!{w%^9|HDbmZlGE;2X`T{);tr*(3#LG5$ zK*rFTp}i9mjQr@tcnaU%HnxmS=b?G-RXrDX8BcvO}|sPlty znh^{!JHVscbGAHF7~iY*L@8N4_or51_nK7XOl7=T?=!J}9lk66+kbHFf@AvK1{R;b zd1~gO9Lxd=j-jy&{agz9zRA0=a&iZH?vZk1=5+qA7L+1ZCjtoWl(cE!k+pHOhAVei zPmR(x^Pt6rfzoR|y0tI01vc>Y1@?nk|AEB0Nwn3E7w|Dj{0G_Dq zD>Scb%Nr$#_D5`^UmX?D*^l~!aEhRh-p?*;N_u}lJq@Y_?;`^~WjC8kt!G7?;M2sw z)1Xk1k_?GJn(ot|F$UcjJ2iI_fg_x9oQT(;(7Y#K`li|x&Icsfyz-pKt^{PBa^-jX ze4ZmUOK0vh8BOAzt6HH?d$P|^M?6P7@lZdh_V5RtW}`^@lx@2CHdUt*Z4SFKtcD~F zPHHf-|5OvPB9oI*WubBrapVXYQb5OKiJ;Q;xu$Mm*Z??;;`P)|3g4@OPP)4+n*tA5 z`7ZCdbpJi=)0g}%#`)Fhy29z6>C4I}&RE)JoUATZdQjuH306Sxj!nUc< z92M;4&pCP*m}gT6N89J-f_x|Q$gCadN{^TT;b^IJT?3GePZv9Vby#nlo#oiCYfR?x z2ha>oXcPD-#zM1xG%$WVxFc%g&U@K##Xdyy(2wW-V@Hj6T}&;G_;k+~ik<^KfEKe% zgf5k5mpQS2o5*i+?O4==aMVPGp)pZ|0@;Tcr+;#+HV1$`SFFfzpOHcn_!l}JfwvUg z*7~sG>JQovSdPboW0*w_OJ8lSa*#Z?bnvmufUEr_4jBl=>jV{Y(V0X4ThFZX&!(&8 zqPOZ7pRMMxw0BOfkk%ys7)4D^wCIl-^>PMjcT()gF#5s<*k9yaXwnddchi@_HFVVn z2p`!se!|omV#XI*i99;u66P+I3P}v(d8+>oSPEZdN&%!dsgb>DfYN>l=|}4{B)b591(JcXFV9m9%S~ zU&iCOwX;)=Sw(5{!J9nGjlVgMu0%bOny$_U71uc?F=>-w(Zw|ZiW7OShqrBa-HL}M z?7I~m=17T~2no=lM{A$?SIOiU>5nvO+)y1spyirx?tfSmeoW0xUiVp)UMA!&{Yx>? zMu`;W027+qVtz(!zfdHu{s<12y-+e8gA7RJVQq+vV{6O7R9uv`J()TW;%fy z;WuZfMhlv<#!qtX)Z1NOmWL;Lx&5yD+wb!8*uf| zJPpV8%Uc3iY);DwwMjkhiPI+-znc9c#-o4dPc;XRlxp|=?UY7K_-6h|8#EhCNS7bp z1jQX_j$^=%eBQKHvFoj0%xFEkVHsz$O}Fi!r&K<_GZlBuGD>z|Y^O>~+fyNCJIz&c z^WdP#Z6P&Q=_Na-T0W^R;63qtC(d+A!rJH7iCjA++)U-&^x$6?-q`qRcAE>t$R0PK z^((>|6+F1V< zo(lQy^Bs4AXw)eI$_H0Ja<3$%IY%nCyz)*hbQH|p-f`=4;t#BvqCh_v-~Lb^qYC_< zX#LI_-`y#gtUe~h)K&99l;`f4a^7QP!@IkpaHd0P)&X&V9fj>iI+P$=+h`4$i?Lfy zQsNaL$-axBNxA~R+IK@!WGX}pXc8FwIo`C3^8Cu}0|}i-+Y16*g3`R&e-9et)Gjvy zO&|)Acp|$F%yEJdVNN+%d5nxRrvBk^GwFk!UUuf^ z=ie*EhM_9zwQ44hd_A0Nu}IP@Gka{3b0D-c6Ei$3*mGV zZV#zS6V?93qPOf}33S2$6_uj(&jLdoRKStVwOeCP2pD4& zkxChfRi^BVRg8k?0{S2-U}&=2X04mbU;6f&S}Kn{oH8_XZkDGiTdy{F5fe_8Q%=mf zwJ{d4;%yn9A1I@0d`KlIYv^T-nN85`O>PQy+$O~~d8uI7gQRS zWZRp&kBPra4LDG4~ zf9{sa9Y8YXV-9T(x55Lt0R%Hy?Us_o+x+Noc2wEZ$*j>l_LWuEG~NBnOzv)AuSt@8 z=n$&M`|(6q+D26EusVE+Y;N=3&g8TPNz=9;*4iu7jeiCsKjxDBmkl@hu}e$o(rc zWa~R*u4V~6@BK`p{#Vl3VPE3X^en|XNydEa+)c(vL&;1N3{`GK}e1DTi9)p_7 z-UbgWhP3yq->?3F@$1>r6C~zX(GSw5?S0L>w`GLiiR4J$FGi#UmcH+p1n4s4#G7kB-_OjEwSej6$eX9cnvnqDA|Z}8POf-=M2pE_k7e= zKpTL2uc=;{#Z^^s1O6{zOr-UU;ce8&C*8z@BF)gFk1T%SU)M>GL&@^(_oMy+zPzBmDo`;!Vc^&q0u(j zSOM1`+g0LIc}o0djuMyWmiYWN{UZ{tpZFq7^Zg^TP7#T8vArYmrOvo?^kRPqHHS~+ z>5wxgrhp=K0yz+$0lX2U4h3bnGc^h3LBEcF!Ym3-mn*D?8LP$*ldl|RAD(nh$_?f1 zV1THQUc>D9G5jQwZDN$?_(_->#3*;UNTfEy;V2<}O?Qdp*~Qg6<2)f*?y9*^*sckB zq>3&IISYkbOlBGBYT>F-c->p9PU8dZ77@-4Ro!sDn&Qv3)Wo2X9yFNEke4O|5K?Vt z${9Tiwm~iZ;%vR18q;F@K|7>IWdB@(oJu=8i;!CnyspCYHb}#!oTjOChE(?9P>)8d z`K|O^Ip!1Cz~p)yp}hF|)g}y|25Z*yr6ro&!po2=j2m1d9Vec8H%nmvRxvNEV%*M5m+zj(DCJ%Jt` z_I&*BL6R;vn%OC7Wwxl?Uj}eD!!y2|jY-?zP?bG=;5jvN)MxKE$pVZo?YSmDWKm!p zhV0KbQ-t?gmO~LvC>Fj|1dd_KK!#SxuZq__P$i>nnV9Y@t-n(GE6pdhVpRj&v_oD* zF&eKGxe)Mta+ya9d8FTXrwT9 z@tl!1B&Z`8>!pb%Vx3Qr+wwEYIYlTME4!uQav5!;B61RJek#NybKDm-dS;5O)b`3{zRosdf{x?XV*`Md}F<;@%#; z8CWdUe)X#{!>8$Rk3?6n=ZR(&+&Qg|DAGz39U?RYP6F2%l+Io-0aTcF0heIaW8oxh zp<%5kPX>)-beI&~%3&J!evW4EDPrs1&-lO421mHpy!!dQ21@@*NvX5&YBXYHqn02h zzm1J@N6Hh;WGngt8VM;dHyRf1R5YfI4JnBzP|Y+H`&omW-sWy&&vNxn(Ihz}cqfj9 zoTzHR_-4g(zLP$Ji2y-X1(JS?PB91(t!21ucVgyL!VZlJnE?p7EeIsIZH@UMGrX9D zGkm$b6dPx3rRylQC;hIHb!fPH+VBTEjnPXRncJ-QD)p(JtHX_6mD7qHJC%9~SW}}h+g(CkeT`$0ieFXwAUlZ3Jxg%xV8r-{JV@17s%4PafZU?%2h4g&- zyP)ko_M`4KsqnzzVW&Cl-E4R2-Xz+hk88zkN@2^jPYK9Rd48-r{%^f$AD1D?0?$7} z)*u^`+G=qQs@5qkW4#II(bYJZ&pF*5Nq{N6-2H)3y5B-SI+}Iq7JWw8;xblF&Vav7 zDD;e~`yUt4rAz(T$mL*IKEy^|G;>4tx{I_5%CGU936pR z^R$Mi_wO>;M8R_VsVPaCOESkC57`3vM2BK`5WL8b|T%CqA zc$Wap{+!r#37CqQv5i=n0JLP_x_670qCk6UDZ2EP9jT;q#NV?=G$WN%8;n)b5jPqZ z-SM?ALk59w-j-kurj15k!ykes^5*c6C&ZyZ4bOjTgi%>5f$Qcb7^^2Ge))5+$JO$X zJp#qvj(#yP>E_i8aM`>HX86Ao`a7JzHAj{c6)uz1r-w%HQnEn3Xly)ww}M*`y{AII zj`sxzeSE?>aV1>$1US16&DOoo>(ED@9|+yG;c2ziV}SG^*jXQ35i#G3U+Q zies_2RyGXXM0>bC-?Dg;S%gg-iblvL@DimJ!qIO+vs&sN)Cq+v4T9&X|%Ac(?v08R%*?!ps*tZ?iF2_<Ng? z6ZF#SB4C-PT`Qt?>x|U5TPX6?rR0{yk5uRyM|Pm@g^hJU8-1J81CW2Z2`;Sm>N~3k z7w9%z;IRwGHsY5t=nRKf&@l3<^}@N+Y%`q?3h zgh>WX4v|qb*F=c0`Ud0&YUDP$2=R6P?3Sgye){FOb}+rz%=Tp#q4~IbDanmhmxM>c zWR^Q4LQNO$t*{C!@MRB(Zr7y*x%*EoyUly=pK^8rmB4h0y6wi8u|@8A@6jL;!g?7= zWPA`OML>SNHKn(+(oeTgNE-9bF3VEU&}|=s*|mcf7Ny2lNVGJq(Jx@>o#0w8CW~uO zAuhs;)#kc^;efXeP9%;UZ@eH230N?J&EH{43|@7p15m}OeG!w-7fA4M=~2hVcBSTeLAekB1sp>S&=+33SV7<2`W<<|VmgqM=GCBS1nA>l=r}-+ z4TqG}0OQ>0j)Hd{aVFr9Y#xH~0Nu_gc|pJl5-^bfjX)8-JZWn#DsW!y|KB-aU)F$* z%d;r{52Bqz>Q%h*ZpwIvzd;}NDBB8b?;^T{$;X&uB3e$-A$=NhwghvQ_}0aH!N_NA z7BIb<5Vj=LIQBR&)IbylSm0kF{K@JPhw$s{2s&<$B5`58Ffc~G8aV>c2jv200Oxyp z7S49C>o7ECmY^f82~VjDUT})K>6TL_2%*f#mO;GHz&V20UEq{}Ue3@vCE3}N*Mj1w zgxe>ywOGF#SS3}rIq||J?C?~a2{@|>D(C_11Vve^5MzRurjn7Q^GLqmgr|gUv>Z`R z3Fu99!}EFa{2$||M^B%>{MY#S!OQ!v9(+4Kes%xlE2fnbq1@RR^V@!T&&zF2(2zVi z|3~ameMUt#NDYVH1N4D`MQqO!PJ{cANjMEKj)Ia)$VuZZU{cyGBixv2 z7~#k&-$b-jx-^q5Q@lZfOq0QMy1Upda9GVPl)ap2U%Bo8JE$}L%XBzw=@ACDy$GmO zAtg+K|28J%cEjuicp#tyQ!DUETTrGyqHRsFn#`2G$_$acn&U%L$5ymA=Hp3@^kZaU zV>m@)D0vV3B^)I0V5VKfWFf*7h0(r2wp#aoHb)!% z*VX$2E=?t(EfE+>nE$^l;GWPPbFPE~>9a0^Ok~&A`x(bL^zQSCNZ?bJ3V^Xp4-iK> z9ZX1<;A?ojql{Q;L(!^AH~C2QbkTeVS~EZ=;6h(6NWP3^$4ASnxk0V3Zh;Rc~tz5yct za^nPH({-+bt3DO(DS8;g%#k}FJMC2-mi-cMH2B+$Ev+)s)kI)3?}SFi^(0AY-OEmo zsE38n*pQRS7AZmLD$7@WmbbH^LRqU>6>vG`E#`Wz-Ab4A%c8(-^CI2p+hDP3nbD{x zD$i6yyZdfcWRi#g?y2-WZ4T%8pCqbI;Nhc@rz~Tjkt;DGFOM+N`4ZF|(Maf4VCY1L z)`jlxvC^_Z$&I$0cO|@vFampp?`0$p&VpDeUZM;`k289*L&X#Cf!job-hiF}T{fiY z&%#ACp}nAlQCkLdvH%@BG4IhObxis2?s??vHX1#>|IZUNC5PS#21IS*lY=^3Jc1>$ z?2bcrqVe;`5XhJaTu*(lrbUT<6AWetmjY%nAk=mSmhYU z2lS3#e*f&%V$o|HS5(;x%|7x2YD;LTVn>xDQ6h~PITyYhsSe$ zbj8!eJXd@oV1obJE#OkRWRpcLj!u{Ck*`cm6e)pRXSx9T_a-Q@55)KcTD(J_YCN~O0_ZbO^F{2L(#azL@l#g8d5^5J2}YlF#AJz_j7#NlX2&S_v(B0j`y95o!kWZ4{X!)b@D6EJ}Zd-uMQ zQNOrnX8GaY-_!4QFZ^(i2K2a_`7N5OWxzTdeeol?M{eUn-W(p@!~D%zNOpl=`(I<4 zSn{1JEQ|lEwtu&r1Pk;Im@&3vF$@d+@=I-&1`-Q2obLu{CYsN%X>+%Xg;NN9osfA2 zBq$uk?TH*YWdNK~Vo}h*;1p{cCVEfBhj7JvryX+eq@651px+Jt&yw4m-1RoWJ63}T zYr1K?n@*8MVH6Q|z!?D}0bv7zr@)AGwl)VnVFR;z0FUZ#Uv*#(x9Ofw7>X0j=?yy2n!l^w^IfbgDqZyIN!9 zyGuJ!S7G>hG)kJXZyQ<23{}I<^u777TbQ)*#lwF#ol<5T5Ir1JnXg2)A z=4b0oaC#BwfHv=k=HcM5)w%oGXPTzI#+5v#Wq&JD=V!*VSl$JBiIYHTb<%j{qjL8x~X+&2_>in~P6QehqpKZqQv$^@ASE>(gAHb{EqE6(-1EX38^KoRsUK-#&8wiPz~@hlIfekjSzwz~ z2gCR$Ocd0X_n+PRFFs0%3KLFuT0<)2d+KE(nBiRsFXRj1ch-Z_HoO3Z13;c`!gWkf zdg^4}p4w6mq5BTi z+7m2ffNj~#PO6soQ@B|j=&0uHYR6h0jz(87lrL=8$JZb7FucQ$ws4WXfJ2BmUDzDY z?+Kn_o^ln(T-Gvc$vDj_DlHu@RkPhRR0+IUYH(aNEh7$X>%Jv0C`Mq zP%dJnbKJvrqY;I{!v!ap;+$$N?+cG0^Mw#o-xIS)bTkFPy$Nzhu(X)uALW;uRaVxl1n;U)O`1Lx?A5;r^Qe=IX82rxg(J^ z9a2j6v_mNxVHU0*Kse|67e9eyKnbW%(dJZ&@lZbM}xjh=jrN zR?h60$KMmYy}>!awa$r(!|B;>c^;36S2{Ea-HsBiBj8_hSB<|WOU;2JsWn`vU>w}b z;DDBs%F1Q^YsEx|#HB7qYKIA9{CG%eJe;7jV6h!}KT9XduvJf;fcFNY!qJfp(d#i~ zkp9J-Abo8`zg!yLg;uYOZcf2N^w&Hb!`a*s*e@S_ReNMXKNM}tK(0&>liO?Yt%M+v z3>s9?eTHu@?4b~{TLZEWP)nxaUGixVI4oGDNC~Um7>QC(RE@f~eYa`|5E1yR75XZP z{-HpTWIWU;sjbc_C)WW#6l083DxC^8kT4jQ@`}&{*t^DR?a3)fS6~33M%ooKHx+S5 zw3JeAtv=vi<=JZ0y|&J|Rrm0pb+23Z`ft;QMUvv9M9QF;BNiit9(2hFJR3~>4(fJd zfIvH}kc5b-y`yL%{P{hjM79QBe>zfRM`@`J;N$KG>pf|IN&m?V4aEMoq0+4I|vl? zcur0;o@8DoWsO!p@TJ5!%$xBV^|h`nivsPs*~bdn#mrkpa%(Yf3b*7mGFPRP==Sr3 z?nTH{%{PUu5Er_o%(2Pw)TJ?xnEkS^y!V1rjS+2}`e9`@jvwT9EF(ard&1 zmjXfis9C$QcB{FC2LazYNXDu1{;rn}q*86bWJUJKdk#nxx#x&7PBQdfBN~D(O&tYe zCL~knQQ(vad|2$3oJDaI4e&%BBq!`t*%||KUR~ zSy+lBZgKiRx-wByv?SK4=6cnZe(P2hV*SQ{di>PeV3{TKl;nvOjsfj)jIsaX{^OT4 zr|F*UCzWQVoW9Jt0jz?taDd0pzM;`tdbIi8J*L_DrH`H~d#(^cl1MMv-mx*JHJQBv zUGO6mmoi^!>dSb&;O8b0I5fGkNVUSi8~5^xqKRmIR{7h!a5Yi_DSkpcZO5|}xzS=m zM0%PaM;`L)On8PERAo+okJ-GfeTL_tzOLSRCq-$UrHY{fccK=d(#285LGL0s52eZ- zPRM)m{2QOtq8acO@8mKH-<>2Cr&I+~GKmH;nqxg!LL*s%fJJBFL+@)e%A$WWzB-V1 zPmp`&)LYy#6q#4lMwK6sMxLCJddA0dHnG4 ztAEj%dGPJggYRBEfBcN{>fQhP$)9#=ZQ#p=|r z-EcM`)kVd#Tzv+a2^jBv$OeRbW41;gRG*pnXq;okHcrC!f^s2P(907~CX6&ohLW{m z%$agH$;xgi`JI$BbMsckX(*<{=CV|~wS>nii0rM-d|BdZaEf^Gl(d{^?TgVBo&9>@ z2)j6^f|u+d+qF{ukH{^VITMGBOn<54SNC5%e(>P_lP8T(!)r9y(}6?0%&M;H)mqhm z*&AkyqQk+6LKfHeA;Hd4(^=C$bYANI$IauW2Gla z7d2PeNYeQ=tn4FJjwtn1mb_`%WdnGL^onG}m71B;Q_o%r*^OTxy?p%W@zKlixA$K@ zJ32l#SVc+M0a<%)E0|_#;?8jAMUT-d4TNwPEX8C!EL6SQI3bn-l(p5`BPGve8n+8f&-0JdoQA8gglUr4Qhj9Of2`w zZn|T{I61FZI%=xdq*5<)Ptb~>$23yVBp@^N;p}N72s8T{UuS!3TqIx$l09WwPYPO_ zN2++lDj7eL5%XK;jF=2$rLIUI+DQUzlFYa`7f>U=`~MCsFXWOW(Rf70`FRa0IVWgX zlbgdz?@BVix&hyg*Ed3PIDEQ6I#LXrC)lt@Et%T*0bNIUW3&nu95up{IcpGi9Fs5d z39B`m2m=H;_Ns^_Ad_-A@Kz-1?SjM$MHtFDo$N0l)`2V~%#JUtaC zNOx+&m;`Q8S$XAkN^#S54;XeprZyuv68o7NrH3Uyz$Cn0arDUrta%cF>bAKylj^XI z6I;jT<`FzlCJB+2JCGT4#W=$@W5mZ8x0b8!+3Ax%{t1gwXN=HGM*h+{9ha9_opphB91;9#mf>Wa6 zznAAV9JKD4?Q}z=Tq7|Srfobw#HyHw$+xnXwS#mHN$i}-jAei@exv8i0#Nv}8LVSc zHt#1}d!*mqAASGi$-l-Aos9AisNEV*1J(Uz=0JX}xON3D>5{y!0S_OGUq1S@I1yne)4`Q$tvh~^ zMt$NdAg7w23l+=Ao^duTVJ?$vVKhJzhu+s5@n-l8h{q!ODr$#GGfEiQleggWjYCTM zG=h1HigYMQIT_Ltyo4J(3ywmy=!b%psq}#&n$-Uiib=k3mak2SeE9Fs)H>gg(@xk+GCVIESxc3a?-WPgPBmtm{@*h-F=_5TRAt9UfX=y+>x6?S~FR z<`#LkZ|96)woKc{@N>&3FccyN$c~uo3HIYMe5tBC#z|VOaC0B;52cC`=x!^1)(FhwB?= zI3Nqn2pu{IMnJXGIaLkiOkou+6sIQrM8NSfsw7M%^&>fLgxhx^F#DPa1j$B$S=8}& zbh1{^Gz?R9VwLCMP@AzWh0nHP>y4>rzcThJ=T|uh?q6$$^iVAiygObiYfY{~c3IMM zl3y+fT1d#y-3QWMLVpCPutcXWM{UuhMTksV%q0#?TP+vn=0J4qqvOncqvWMFv}zYT zrM7WQq|U}UBC@?UC?e-B!URoJ*}z9xf}`9HF*r+1*eCLOf(81f!DbU_RvKIB3X&`Z zC&=13K%8eyu~(Jy7I3|0bWTeZ+heb85l$~fp}3!n&JkJ%Uzrh=e`Gb8=k05nTJX4mKcd* z>&MBJ6=ym!6>m|inbD@1vGt={=q5}3C|8pYxs%XcQlZ(;YV3yMZ>jKHbwQZKy?j@d z0-8#v&arph{;`~;+U@OHwD~WeCW+IVlAAV*rwTYq(D;ew4V3pn^Uj2CddMR2%?Vv! z;j~3teVJ-BIP!`f`7iiK6C9Ge%JY$gsK}z}8Wqfxvnk~gpqMO`+vG40qX~yE*lQz}(&$xbtra;Z0vX_~#_Xt^d`aO4%5%%s4q(Af!Ii1U zg{MbXD0g2bGg=IOvYHG{+@;OnrewyS~$}#3+65Bupqn-umw8bI0oYfUQ@yUOH35IHh z9(vE05_Y;;ZyOl(8(mJv=izi3B+ojqL=Y%v1gwVIB8DyNoT=Iu1T zq0pC&60F46%WZJQ77T)hxnOv5oEn#NRU~c}7=XC`n~m z-g0t5IN>{bSujR}^+b~X%2Iz1y~kUgD;g?6%7i>qy>50)uB$}D7;mi!R!4fEhbYP4 zm_0ud%PIb?@)gj`m7{C!dqUalCtlnX*b^u3c&nKSZ=;pT#kF#9qGv{lnm>s-WFOA~vR2&}sK>G4 zDOF%j5`aCQ$>ekkMBm~pmgbne0ZWy@mmB-bx4FT*Igz~CT~_1f1oo!)Gtq{v4V86` zFjpwUdtVyMYh>2(P?D$ClDm$-IY>2&FUNY+T6i;J*Zo1VZ!JU1&WU-xH!3Hxy)G+w zTmMPN9T-Ho$Z?3pkMIM%8i&U!HOsEU#Jo<=Z{f~9{pytzhd==~uO&&ObO|Fls+@8n zq`d!WbvXHFn($1I05rU8XK*t?m25Pk>}6w6+Ax3BecIIT=^w|zoKk6JoCgGBRdm0x zq4^QMHKnS&_B+jhn7NZ+&ggyl#HLnd#JRdC%RTs(h^ZlwwJH~KJ^}Inru zc6~^d%W_kRE*z|rbI>&><^83dVbl~kFjZag=uv&^IfM2e8q-9+DVOO|_+0ESBA{#u!* zvm@`Z&7W-bJcm!1278ZLWYmB>95^T~*EZ-5>(N}@zI=RQ@n0zVS+AQ#Gqa?PCFFHD zuS=dMnxRT23xYc(wCyO6>HM^&;wbKUw>EGUXejdHc(z*yZ%rxAITywk(G1hqC8WsP zBW@#!M=5=+1v4hcKHaQ#>(S^N{LfweEx=nwr)S$S-0UwgsnE|~FJiw{hg;2y&5E)! zT!!x*?a2aw?KOtTzZ$++W3}!LZMiv__X(A(SBquzlf`{;uvNe@iEo3+6Y{WvH8tiqVLYMW%x)jJs))fF`rT(df(g zENBCo$Q*^)K}I9Y-YUs_DCMelpGAVCVp6Kcu<2KKLEb3vON6gr7zuCgIzXjlkx1c2 zN?EzWPgjfG#S$)TZ*ISN^!BdjzeOc28+>5&WM{K`o)8Eo%Bg#f&Hj=|@T+=u?U|K- zm2v$(%$W6WzqxHL^{w@by&Cg3dq*5zFST2e2SwJSa=YjxH%ae9<)h5}A`QUUc#I3) zVbL2M--3_`b8;0k0zN<~xJb0S3|Pju{2ZHke39KSDN-(Dn>M$>c|y3=(#TESXiv4pK`|DSmFnk)U`PIzK=yWNWs|?~R32{vTBQ`LB76CboKvKw`lB|aQrnsR4 zl*>yhET1wg&UR?3K{fg%8s2yYFz27&rxO^-Ac5LQBSFYmd6jNAccpE zQ+Cz^Q>nv+=}|eCAXYNADJhjPh4+fq$UW|v3qB3EwcF7w;bQhKp%laN1QqgI=@C-- z5Uly8h=a#b`A=ZLdp}3B_mmOgo~jgpaPKv*etxglN&iYw&slgSiQ&Rpvex`I_Ox8( zf(>#pR+`HMjIFgVIi6}s8E8<03FheQsKZ_pjO!h@O-VKzjmMmmZ%hgg+$qMAHe@XD ze=lYvE_gpP+%oTZ88&-3T@cscZdUU*&9|6({?Tak{MnIxe2ra5CGjB9kTE*tWFRTC z6Xj&~NR^zY->jKCZ-jX^EH1XJA3K~?TT9lPjRAH~e7|L8l!cFrjvUiZE;{zOz@hmy zSD51eU|L)(<^k8;4OR__=o0p1b^4ZkER{6C1E7N^av{Vw?8PTiRHH?Jp z83#-;%r)M z0%Rokq_AB9NleY5u}}jxN$%R|jJYeU0J006uPBrQ5|t80I!y^gjjRGrby)@p7N??n zpvWT@T|vW0iBr@vBJ)Md=IzvIPqK0?Y2&#Hk9vGW&v$E zTdB@1%(35ZTAjngcIz!=5Jsmi^%@;{aX za`08%b?Z)dR>!ISnWCx+Q(|p@#r{*ZWNK-1N1dD!_vRLR&)`?W5RJl<0w#~zBnDSv zo!$|9eQO*VHb2nj(rJ9QXW`Z;FnO!)^(|BPB>nTiPP-UfT-d)4t>3S$-~6Wa(&{^#Y|JJD$5^^y81EJ|mRhT$;v$nRrLQ5~z3{XkcSWjkX}to8 zdZm#SsX4uPaP0kv zZ?qEs5o@Czd8L2iS@|-nR%%u-OcX3A%nK*TnSSuHXwL^Ex0_$&(TP3hB2wuI!g`D_ zoDvV<(EvBHv?r`LL$$vmhmB^GX`KIIRDezisI0ExE}AbQ`;T_U2nJj~BL-T%GcR_`~Zs+(UpEg}WZrcrxKu6ene&EKH9P&@&3p`e81$FPXjC@EBLulC=2b)cR6%zjUT?@3b_G^I33}!-0 zk8c7|{Wu?OfR&MA<)urSpb3aa%WVC_aJmS@zc$%?*jcIl6fURNbf74lQWg8uyN+pR z#zY7;+Hb7xA)6%9iV?N0XU|{ zW_N9bAofK{oJu2gOOJOH~E2$K%x%YhOl?_t~6Caw6K?C_M@-bjL zx%Sk#>;Mf@r@o)?8Lo;1c;lQJ4HePhk+hn&lsaA$MEoU#L_^hm> zeZfjnj+k(f9~VaxXjqB+zjRV@1@4KtKx}r)ZG?IBqn|<(4*KBZceV6j&gDbvvmic8 z1HkW!0F;`RK6sN;tRz>vsK_{6EPz#mO7xOiZ#mVJA}AXn1?|fzCuBfIkrE66d z&N@L@_84c8Y2#3jUyR2zz5k(zx`1mGk#-JOC?xRT%Vl)ESzU%peqw)y?|K#F%if2p z>>Wn)&q@a^|DC1)PU=>tPF=|oD;`44{LQ0SX);yLp$q91PNPe2E~+k@%SudzT0QKX zIkgPZq$w!>jNF8^W7b!Y#A=x6N zd*4J#CzF3VoKvz9@c|P{&cW~W+Wz~p=GjKPGz#-MWI1DWs~^tZ8Qp_tRaNyc95l?W zKIEW5OvEkz7Gt0{Ow(=lNWrlHY{)x9nZPq?5fTlBdU9*a%4K?gI3O!XW2<5EU|=rN zcKP6kjHECm|E%M;iXTMqlX(WvzqtM>Gc&yE%n2u78~!Tf`=?$140!fJ%(pco;JrfW zzv|(S#pY*YQ59YQi>+4$FNOH2QZv3%;q`Lal-IOi=^Z(sa zt6;Vx+5dnSt&%Lpvbqr zTSW_xMqjpDU!`&u!s)cT`IWjof_X+um?ihGZM;SXND&lA=DDi;X0?e$?7N7ong{&=SKnw^djnf-4gUxOSW`1{ZrIxdo_(`|(}7dN97fiv z9T%`{_&?LW`L7$u68!8hPf|OBpXxFNKW@1~zc^(J{gNYJxR+bTz>Q@As@;t3Y(LAs zzpo@`@Kc&{xIpThMW<)uNwmcb3Od31Un1yFEP{yX2ri=8RsH|Z-n(wMaU=2RAgakucxFYAkN1@`0(_}J1 zEy!>_sBHwxE2hV*)XvF!)0@6!vptsKWwH4gB z25ejdK@aCcxKh+!`q}MG+ew18RY%aad{zrm(Esb6_(Sgr7=WX-Ik~N{*_4Wg#Htn_ zCV5O_RV?#cvh27vGNzPo=>_k;ZHw)-g>fTD&o>0^a#Jj?@~ht$-B_-8z9_aR)aA2Fc(U-wA5 z8le7Za#eN$Xdp#%n(TFen^yI!87%W`N8pr#?k;%?y$)XHLW{^3B=XaXHs~!Jca1%7 zP@8X+<XXAJ6fSeg~{ zol>zlRl1aV#hyu%@|EU#wpho|`WY1t_nV&`dS(H9yV3G)85V;|Q2GgIDNvX_jn7JH zC3ClF%`V|5tXD)x!GB+%V2+Cts>56q1AKj`)P(_JbK5krvc;(HVBzihbswaX_3NaM zf1c9c)3bN}Xe_c_VEi;D*&8I2@QC;$Cv`w2Dzm8vVE{PN`evOrs$#hOB0Iyp^oSm` z7oUI1&;ej(8ry|wXomeMD-Q#qbt@|M z1#VhD5*aV3{2cE~9_>Ckpl_gOk!Z`y##o@#h6$CK^wB_WUM}nfv}r_Fd)7wUac9nt zhy`>i@q_EmR#>4_|UWz4aTJbU{y6*tf zSv0X%7wIUzjx&mC?Vo{bh33mcNW1$Z}pl7dt+A*VcNFmFTlp z?(0$U)ChQp@D0PU=d}lg`B|siu5WRtyy15ezso8{Fa_&u)=0qDf=-nDc&{VeYo%7W z$Yv25{G!9;oU^j^)6saCjjZxitA0{=TiJi!(&Xicq`fh4ZUpnsqvY3~TzcmGjs1?a zcg%5*-v=+Of8uU$3o~pMCk>(p>|0T=H(OkEU6J23)rVDAx z*2=iPjS6en`B3=E*H{IyYk8rs;C7Wd5?C~UOZA%_>I9S*5 zMYeVWf7pL8IC`7#V$Q57Ge~jL;tm1+q3XO|$vhe1<^TGS#u5L`$9dnxGsn#3)H@#!@ z2*0V7K>O2yw>TzlYmFrpy8gMDy3f9;C`BbhHbsoWhEsxVumZxc{<}TM+uF)Ci2v(z zjJpCkxwdk%!mm^Q=5yNuop15upI~6`g_$;eB!n8lciWrq3h;{;g`uZ^PFrK)7yKB0 z0xaZ%S^TYq2upYQn|6^j?B+j%fS2Gxg?^vn^($?{KMpPFBUNO5t$pMcJ($OSg^a2fx=W--90>{R5AH{G8ts77aocZnVn_DliWfEEkc-%w!fI@sQ_E-NHo@4U+-x8af)#Ea-vK z8&f1JT%@$X1VcCp)CJIQu4=LN$P=eSlROgz^mI?fgUU{p(}VSNxm!q*CV?UIy_{vT&q3$G|#4e+v?TGjZ14X%1zV+5;iziOy8iC zQ#N|OdmJAgyf`?adK++fxiAd=?;l$&TJ^fiz5K~HtYRCV^O{vZeTKVMO_eDNcM~Sc zbvo53P0Wyjwqa9{7dKr4)a|}NVP5=bdJ-L}wH8bzel(u}?Wdj2vDE4PK*5KYOSB#} zo6&8w^P~AjcO7##{83e^$44QYzBF_^>13w;PV_-KVlfSw_46QCcTh6;4_nhLKL$>^io?5AW9XcVNi3Q|>tuT|$_7zULd_&a;6 zHBN6De102e$pBb9{4q8O6Y%PzdxGz`W&u`NRbT5+z-*d>1cRzINfsZP_&J7^)YeOW zTqzM)Ozzdejj}NH1Fyr!g|8Mxqulxeo3}(wsXy#k%+8(tin-D6D{zVU;lGqWsNruT zs&{TA0_$40`OP;#9A=ugD0+Dy{X0JgMuL~T-1?MBLyuCt?*sKRMJ{}`8PyIO8};aJ zvf)$_Y0j=FGXh4Iv4o28^rOuNsd{@ruj64O#dB%A1Ki@giPcds{n-qw0{ITR(g@vQ8nbZ&{^N)^G^3d2kjGq@?o3$>DM1-` z*GzbhK_eH*MyK=PX?6}!>e0_>ua{i5x3+ITlU##;vj4N-WGDKVXXjkq>Z5lXAkWn^ z=ydutsTwrL8l)nNSm%iH4D{cwzk_{!+oC_)^ykLAcg`*LX`ZD22?hz)4>fDLKAKCTUdTw}@&;Y3U}JKm~AcQs!8T3f8^h&I~IW>Ff^8~cC?z4wU&)K(sDr2XXK z)<*mL@B0t?n~yd&HoosaT7R_uebR#eZf$Lx_LI%^_SxB4x^;S%p2=sOKdlun08{xr zJ~=#YwHq6cTG3RAdlsI1tI<*L5z0jL3je;3NW-1R2N@qf z@3S!{56>T0y?ALDWQY{Pj%Bl6Rv z-;91iu>vPX%vwRyv(nYuoH(H3YKeauYP!ptOB)C1$yFiZN~53`(IPA-y)Txmmy?FW0FGGSL{=RaU&oIYHH_#EJ&f=^ZhPK$j%HCk47!Mkb(m68k~^yjQ( zQ^mBRzO#%oMt29I@vVp=J9#E8~uO(*ZSoM|e#ztg*>^HcRFN3*_LLrCsFlwJ#RD{WB0KPw4TK4M1efpf6Jh zS{4vOH=p*_RF15*_m|CS-bGzp&b8`@xdUsDu3#iYebnV7PF>)q1T?xzSZ4E$4$!`=bEp26*qoMY`z=Ikg3PcygxPVmzJBCo^X6 z`TP`k@{F4I$5$gP4I)NU2?u(GAbd)&I%XQC$w+x)^sY#_dAizk%Q_2JAW_ z^4S?yc>~-%!^rB#`g;xW_sf{eRCYS^8BD3ufh`_g#>pfD(VD85PyvkNY0f2RY~eZ` zy^qge>==j?MCyL+^)D~u{WmY-ll|k9<9Pq&8=E)4djR;;U<4;4zsxA$)+I`qd;^z7 z92$486Hx$I0qX5ei*f{^R(575mnf0nKSvc6yakoKup`#>$L1cQU8zTx$^@?v+yGFG z_N4VamP7x3zR@O&y!UH+9gC2!pt zXaT1EUzb)Pa^XpDZXG9*=J1M zcV}oN@#(#=h_e)hBv{Ij2!4#Rs;#t7Pf32U_v)7)p213g1O`CK=vA#^H;Lzaj5AoU28_)*?YsTR(JF*A zg4yZ(;O~p*yR?$&N2`E2mART+)+4Lbm40(5tktdQ%G;U#^b$7-MNvUu_LWDjfC7sy z$rYM5)9l^m{UDePG@M-XLGcacX54;YxnX$=GjgVrd`6BLpToh8US4hDl^CF6+p$Nx#8dc+PY=8POdRRUqj6fwO@;1lUc5wkDe`N&G{=2-2={L#d|zIzq-o zOzCH%HY->On$?Wnzp)}lwzzZn>|4S;$;vtg2>eAk*kqUVw7 z`ESu9TklKhX4C+b3PAP!gu`W=tILfUpK!P|L4S!0W{{2W!D5P7Pf!7fSx0Td^1{33 z{iQl*pY>MJ&NX*24Bp|;DEMFK3VDASJU1n0gm{))=!CzGIZ4VOnVzTdMS2|%(ETSF z7*m>490JFnaCzcqF8LKgXO(*%Ku}Yy6_>tDQuYUdB`kwQ|G<>rFM!T47Q=K-l|c9w z8Qc)D1C_JII}!{=r$CUGIg46UX@mf&Rcf*~>%WW{Ld-svsKa3VS*PW*9|bEDEfI6^ z2;6haLiBU*Ei2)4>g1_K)C(s^m!j}D*bmYE^3-c>u#iZM)Dt{utDlRydB6sdsmeT7 zijxII&*^B$roqTHwlE;_k-#UxDxXc~y%~8jQ$|w)m(0-d2F)1x7&Uf)_%$)Zp3cwV z$%v+a>vY=7sO)-rg9CAu_O~*yoTHo z;8Z>lTv2IeLESN&TF}}UZ2~@<|NeU_#h20{2*U|FMnvk3MP15NC^7< zbv}T9B&fbdN7F3NDLMi3?VvJR9EbaWNLJXX-Ir2)wy>$I~3s%NtqS+nJVq!^W?1*}=V#q;<^(^U z&o1mKDQ6ueY*WUiJIw`X)C^~m55Z6sxd+Q82*7xD12l(>*$!w_Ju-hvez$0n7GW8e zBo8~)sN-Ixs3Ve7K0{1;cbb$HjaM?QLJVU#rHU2mw_u+!WNNfaAJbQ0_^+}2We6my`0Cbo@r&dbNjK9~T;^ZA5N=#CCAdZ*j?(KiSN335l zuxM$pSh9IS?y;+HT|`-u=r}wCbK*#Szs8%NUA+j&#f4geJoCaFIU1pEr~tlrJAWjl z3$4nA58gg|CuaQDX+9s!e$dAJ+N$!$3=d5rc@aB>m!M}h%~x0NjR^L4xyuiR#lDy&sghZEr>*y!W61X#Iw{6r-lFTBc5|vgZAz8YZ z&r4tBXkCzdFhG57#=&wV`v@*jsY3KFyO$=Giby9j$53i~NRrDBy=BphG$H*yfJV+U z>fI35m(i)2F8ALJ^vg@HXX-2asfI=ae4~*X2t%?si3w1VhEyw}k9w+!EbhNlX32eg zoavgrkL?+XQ#ops-VdAnrmXohU$tL|NL8da>UTPHEp<9QZ(r>@qilAM&Q2oNNzZXAm0U}_-R z=i3$Ua?#`}was-o?j@+!41g}SHre`R%q3Ky1J!EyW3L^Ye{NY7jYKn0Lf&u15S!NCH7xjF> zlUZT7kY?y39Inhx(q748mdz=>_!SmTGVLun%`k9Mty&4`6n~>Ipxrc`*VZy_M6{rV z*x+sR9HPFe!Vy;GP_r|PV)2g18#=-Vd!gfk7m7w^d9`{0?>#{1-N8eUX-wnT&_0b| zVfC($C1$%-7+X@h^p1|p{FV?J1Xjr;;4F%H`NPj;)kR8DMiQWQ zap0gNfplhc&?RO#OxTjI+#+4cqv!y#6#XwLkQ6yb;gJJ}289)i|1a{?EvVBw!*px`#B;*@$zZT|35Cy{q5hU2#kUB3|N3;)zw=NR+-Wa39G{ z^@puV?&7h!z*g=$>DwjPr%?sF5h&$+)KUEY59Fh2eWiS~!Zf6?Nn_>`T%KrmV|d>o zv}w|tEo~igJ+8lyrEUST|3{jT0(t@Ff&Unjl2T;4yjT5-OsAmzM1~a8Ps{-2fm#|Q z_lXbRB}1(4X?R`M0D%~I$aeZEqPBEsM#!2iSL3)HT#SM*9MkcCp?TN&Va zn~Vk0*!afOa+rQaK$DEbY~S;0X(In6NTRl!$H9u|nD;_`j>6w3z> zI&?at^h(`4l|mBn23aqgWvN|5R#3;y zVz-$;-O9Gs{FPti{bvnVfQ}QHa2mb9q^(x5YE?4lVAJB1k-!9FKvoZ&1?OLed}O!} zx5`ktQkN;nxE?9VZ_26}peV0Jn6SRsD&P{B18Hz2*JV~>b*Na4-RcV+6?iA)7ey+g zuS>{^fBUSYuRVzd+3++#^x8O2zn9F*YxG$sNDk%2d07tfCBJ>vS)74HKP=9IzAl*s z|Mqz|D=xu?6EINv>s{vJP67QXREzFGwS=sKd|ic<1)gJy35sYocFs_wlbsP zpG{n-%|X0f($Q46wm13cESnBFrXFxHQqopK#RMv`g+1}pq<3Mt+Q;De>j4ie4 zy{nYevNKnDihi_3CQmcS?{a#mmq(@IRf|QSMxyXz;{R~lYzCE?YBbJv?Mia?RGf~h z1#?z#Ek6_^i6VG;+6(-#5b1Z%HK%zmnWVW2bj3w?WYwtM%d`GxKtjE^pn72eOJK?h z#^K;ae7rlT3j|?34t7V3?Kmi{>`F9?N4Cz?Po&D{fCv>8gf6i*XUSz+vxZx3l2O5# zzn>sh9@2m}Z|N52 zZ|%vwD@J1bTj*{heq=Q}yjF`F1T4NjW^nq55exr-Z_eHaHx9F;PAALb5%8g6?7V}j z6^k7k#ALZ72v5jm5R*X599LEy$&wW!x?-ToIH9fsb(vB*xMX@m9x92^q7jczfYqow z6~@gle92KwSI1%rb607;zVsboZi5k$Hs*9NXDQdnmW?t0_UnbxmuK04&QCI_eXKdR z!AE^dXufEjS2$o7DI6mt2qYT|WN$pc-1D6dne5^pf3$Vff;~#PrKkV4cQGF4X`GGv z={1G6HK$|BkupfnX0?ZK73#JeSGM}jQ}80#)Z!_*cCUS`2$+%;J&0O<%3SIDR!{96 zGbEF9x8PP7?%`+YEjZ%dJt$E|S`9~0AXzGzkYhxFEdrat)WUdv6op#MMY9lV?wWrT z%;abef8Ns3oT9o?mb=DT(nG5rA7OY5j=8K82&}@(3%aX9^ypnqh}KuJxZ{gOGRd%p zO7Q_pgWzbU>{J~S^mC3iQ^Y7;HR<9TybvvGPXC?NO`(9`!tZ3eEqQ1!HTCec{V9Jo z9aLyhi#u4WR3^&LzP3+QRaLC4ynS(D%j&nj5MAC`cU4BEp=M!X{qn21yZ&mystQg2 z*kia@-&H}3R)as{Slve%Rx$ff%Rgcni?vo2leQZCA)G8L<6BuJm&(efC4Lh-Afxy-VWFVRQe|+{ z>lteAYU@o4qpM94oI#5E7?r+&qwlalXY{Q#%4%4LWh{Z(IZ6~+k|8jUl5;F2c_nqf zZ8_`CIUho9GWW$aW;(GPYCIek1YtEay5G&Pj!-R}ux#bk>!YJ*@!|f7)87#BbBNoy+&UMRw&vDgAk-jTouT%vfR>S zHTFvM>3%y=u`=lRnHHA* zR{L;k++;ENSk0xp)zxKI3BNpx!2MvDc2>~4C{ydo=(R# zAYEI79iZCi17&%v?Z18Y_CJK`#T4l=S=VG=Yw~`dkyy|8+j7*uMa;u{N=w(4vbl zdbz*<^l+cs0Wwz>PHV;0h^qM&)nU5M6h>q02(j}|R~HzSYiuCnTzm~@ymve)TcwX} zld~By>Ic~HEp!5jms_&3w%L5=T7l>|K?mx{kiS{|X4NaZWOGrp4JOo&6pjfX+73>W z#j?Sfwm-%Tn$TLKQQkJ2H0nEe4QE4iqI_&|Rzk!BZb;4alvUA0g74D`Mkm~ubKW)E z(KY-LGYz8|j|jz_eO_G!)s%7eyOWN4=Kr_QjoE;IHsayymLd}A%A0w^dKmz#w$<=3)MfgFA9T5g=3tAwGaVQ-8Xc!7F% znQ?<4%7*>gRq|T7*#o19=E3h`VV%GG=xbp0=q0Q66^F|#lluhM6>9D&@4SAY9_)m* zL__7T6>eHMZI#UVK1Z*}pYN?fS@IYPY$Fjl=g@rZ8-Bwl)6zznrvK1GYR%}6J*MRY zFLh9tHQ*HIRAw>pd^bX!!Ul;7_l-|I^Cd`H;?x&% zC7KZ={xz+nMYZ6$(b5tpxk@8ZL5Ni6Z1*>V zj1b1J3fsK>0AJp|TUmATyUSvdNwWsl-^ z6$z*iVNEQ;Ju2Tun~&~CEdl7>z7$)0w`jByLQ$Jij2T~cTQ(n6Y)TQVy)A`b7xW6@ zX4NT^Ws!Rki1UW?U*+^2U60(_x)}kp*1Z_6b!1!oXvFfw%yKEr~NNz_Y5;}KP;vCw(l=#BX$F-tj} zRezi+-)c(YLcw`>M7_N_-fT8olyWhUX&V;V&-%ESo#^el z%)+P)^v`cM;UvOOKzx%MNv?`^&Dw)&^s7Hj)oLt#1EBKB;jxXqvq5r>p8GH{m@Dom ze$$Lj$T&JoGLpzIU}0DqI|rJufgve4_{WNYXf~{4sXvb0(7$E5*}!ICJ?rnHk2@kK z6tDsWf@X*x6jCvrnX?f;QaQb8Fg-bTZYH@zAQkYXr(ku#Bx2+7fZxnDHL5(J8LlqV1JpZ~%a(bjS0Nooogh z^I5SsB|2sKHX;gUg=#iwZ*4q`8A|nGX|?rf(ZVu4oS2I7XGQ_4d=FkV5O8pM^5TN2 zUB?$$9sV2uLEX^bZ{Y7u1*NuLk6NqPkSf+T+?5~)05K2e1B&nx_)l zO$8?XO&U=?(?(akDA(J9C(qCwmz}n)A9f_?^VZuB4Ey$-snczrO&gKl zS=0TlxbQ+4Aic@#Xf{;|dez3etp!;|nWFoY;NO`>s|EA0ffaV3M!#~%uGJ7-A|BWs z->NY`|1OBC`-7gz?J|4ut*ZrCfQJp*kG8)bZli~*f&FpyRC)K`!FeoO7r_b@vb zU~!-1cit(dG3}Mx{jC}O^Y54FH9lA~T5iXD%}q5{+RN-&`}@$IDR*6q*O7K^n$P0E zZ+=~4J=~%xZs74MsV2GVs1iN}{VS9CDG2Ds37OQu2H~b!dnz&AGfCYfy2mEpcmyweW+^>6N^7c9NH18T^b@qd?L+f=Q7Z>mR3@F(2ry`=h zae1eHK27605o8RpWdx%f?}boP*1Lez{DNJr6ErWAyv5j`!2|DeAlD_t*%ZLy8$C>f z*i1D+Cm4LCEIb>VnguZs1wdIc^qf!`XhZi@XO@wRP6F=5qtzywkulXYrftQ<1cmR1 z^8wyUZo}59oAGJ+ZR0J|++1UfvxLL6cRtvQa2_dUS5y;|;mFwsc0$n7@j{-^_IZMl zUwNAXiaOWRQj#@Ga|3zPhm0Q$xtS*bHo@maoX<}It%kz}7m>@H~FA|N7wB zUt@|PDJc63J-0SO;tr}g(>xu`I1#mZ5qLj{)GP7BIRAPrdCJ!>k5UTc;%yxp9=0=z~A`lB>|KxAnk5Qm}-9cWdh9Xm7c!cS&_0X6ba8 zjk0`3l0WR8QdynNfB&7aMHU=?e_54;r_}b>vwi23at@gddQ{e<6_6rPOU%GzAS~^U z>6&2qDgr@o7(x3t97J2D;AB!VD-cH;X!$@h30ip)Q*aHBFipCg7ZlZFl{p^CpPIMG ziIMkpY9(Y+P*Ym)q8~(Xp>tqcFzw|SFB3&N76_9T4^i#pO|wAT)NO2EGDcW>Qa``7 z274F%7l^d;N6`;I*e44v&WF-#;aLf$w$wG!gtr&=J3Bocq`cFEWO|<3ev@SEJDrXb z6&cAm{@zJ(4yZc;GyaWnD3vN-)=O;2bw`f(?McV!Wv zV3qlFO)@=VY<+36KgS$cIGbN9fX1)gI+dd_%%VX@(xt!oh=dy^vK9ZZ+4EBML;!C# zjRBuiBNKMLY;LMlj74W~STWyVABY4`Q<3OcDafd7!T-GBYBl~zW$9?IHsLC$wYFF7 zOEB%fMfD!b$nG~nZ6Dx2t#7ns%wLMQ%cn)`xbxZBBN5R0tK#2WD`qMju$MTNxX;cp zluThcGjW0Vt5pP5&i4Dun7gP`9V4_*n6Pt-Rd4huw|N5ejMKA@2SM+Er z{u*%l1WiwU%wCkle5~lmVGc59+Ks5n6PcI0!(@7yPP@*s?lLjOzZg#0l8Gn@gi6Sa zf2YK#SUDyTsEiGAJA@{O+q|~Uw_zj>FbwBofXOKB=(pU^J)7SuUF{C_H?JqR83j_R zqoi1a>A-{AB_o}rj-x)i-Nw@HBX`vy_A9&@wH0D)?r)6DYVUkyRAn%{rQDB9f9pAG_8mz)tldm}08pTXX2ADaG2Tb5C3)9j#hVJZHcPLYLBX zLeSl4nB^2r%$&~+YcT|qoaSbHMQCd7&g49eU*HBb1Q}4n4ibt&cE|fpEf}vv_m;!< z-Zdv*eZG6{&u>v4eTTdqZVzQDr>215849JdJZ26eY#(@sZpdu1=9FL~WbZh^QJwYe z&1-lDMCuAlFopNQ#8NeCOseBwvVST;jBh#CXTtQ45W-Cy}IJb_-uSb)~j%2jDJ$v+}(;4rmJ|Ne$ zn9yj``Dmodql5W$sitMXl$0xQnbs$YC2yzg}0C)3)>tE1!ngQrI?<5y2k;=SGD{bM`IaeQeDfyt;JW7g~1M-!bHa_DA#Pdz${l)QI09> zA1Qr2Q9BwINoP&CPk;n)%TKfO1|UC6Mk=h75FS$HOVUJA;*)~OO}ZGVDA(;x#mFt0 zrrA^%)kgarrXnBIlv&V~eA=6C(}J5V?}YD~?E0(Xo5VP5O8A%fu#Nlk!8}Lx4r0Yx zKQ59Me>RP!6^=n`H}0u0Cs`d;*=67G+RDR?w4XfO+Gv0Oeg9#9^U=n}#`pb4>yOsI zPg?Nbt*wpIezLjVK07;0w@%N}Gx@CZrxnV6bT-wqg|X}wv*}IDnx@v5fzoep3S z=&eT-S7X!G+QaQl+r#+mH((R?W*XMnO4eJgR+?;l|L`o`{yy0}ZJj0$Pq#NWHcyjY z|KaxL!-t!vk2cRX9&NSSr)S#_H`e>@Wc_UW6#m!V{7-X#0hCkR{L|Lf25$W6_l5|P zBsmrBCU2uRuwyvLQ}*mP^+?=&1Tug@rPWgfUTi+%v$nG8iJ-QBHQ+|OAHQvF zH=FQ9@erQKau#CXL=fu=~5F^gM$+iY&Ws|I3tE=T7s+1Q;h8$zo)OAo8fG^O+b zl-0srH;BH0J?Ct}NvQs%k{aRRK`{dApBz+^3^2LM4Oit5YYf%4nvb&IK!K`5EYLL|8tWRo zM=5Fsujyg(cO99lM-oAFY2)da4`46Ir-3NfA9wsnPn9NAmdA3v2()Ni9HjW<#hVQN zMu+`*3xipP*$jC~I25#^jA@9>{PJ$B(VR__QQn(olbJo9ISHi%i=Wbxptu^R%%B6j z3U>_)b%ks_Ch*fs^iny?ikZshAR;h=tC(NI%N$#raL^6olcqz+yXS0xm(>cmYGCNk zw_&%wTR%8gd)o(rR|eoNLv%m??KuzRQky;Ys#PdD7=iow_a0|O12l4Ro?im(C9&V1 zl?*<8Vje|UXk3CU?sfQS&cx@;7Drf1(m(e8JgefZHA5&-5|rI;I#b8D+GxKxuGhY+ zLic?z(6<F+7PsmZtX=r8dLOkBHCkjabM8L@yW} z-E9MG%g&6W^4Lk8D7yLV^~+>%^%DfVKu4n?i?YUywA=#!b7UVQ(TVbJsOwoNtiq^& zbRea16=y<2^(by@SG)FfwFk6%E3ku3nS(Y_l>IcYeRM>Er@S-YMHVfanb}?_GAVSf z4pjrNYg>7qrT)O``LN75%w1I;V^*|!!-ay*{2@ywCT_M%%tHr8B-3efQ&@PZOJ?N` zAR?;wZmGRs966yItd1xRMyZ@t^;&$SJ(*{yh)4#gWx%opYNDh;lekOXp`1d6l|!7O zWL#`6WGuc~#Fmtwo9&^W*Bs}qsIZRW)7SEVEb(-bUzNY1qE2{$%HQhp>c?g4M`>A9 zi9j;}CEM#2UA(JM`s#1pSd0av5(>X?m*~Bzt}ap_pJ}AtInn-`7wj_?T_kXE;hXAW zOvf)J{dk_uq!Q#ry1+~(^I0Az?~`nhoDNdFOW;x-@)5+ae)E9*Ivu@_G37y=j<9XN z_WGBXF$@}?>>r;T$NMke*pEfHMd1n`j4)RDGNa%GGgUh&20hkj;+=^6;|gGJcUpK6 zOy^jH$F}@P-heX@L{lZV;GcBY;@jo|?ok!OpGN1D2>|d6*AJ!X9ALU@xD|5R@*I<2 zh$U2kv2ll&a-!7N(KI3K!?Pd#+Hi?Y*%@4Em*&)k<1y92^H=ofgF9UN|6Hv zZcNDxBFdzZ^rqt+iyplvn>9;tIk5w5hP6w{$U%igG0=q>v?8c{YEe_o+}FM0w;1s5 zW`M-O(A#D@pIzLbRU?~@M+Bkwu{Iqgn`EafFBFO{_ z-)g-)I}cDYT(oYWz?oyPk{^eGpOw~1^f6k&< zHb_AsWkWcj3))SQGvJL3n8RbmOGE-kCW+X_L;&O!4G)2NPT3dw%o1j5_8s6@bTb0# zNX&u$UCgbK^)3h?PcYZq98kkLOrG9&G#+M{r6b8RNlEanM%XtwRxSQkCKlQlu`o8H zUsZ`Mg;h*mf&->?Yhnb6nJTh65UvsF?f<&$HqrrSm<9r?i<6BAl30o!Sdr#mILQ)n z_!cSdTW22JlXwijbfUBQV9@BNR2fXEkO54yVk=( z#?%#Gx2s))!3iGLoOYL>0i)-P9r=6;JTWC(Q1^J6?@y<2+R#J3z10Q?+Vx+uX=6l7 zlr__4G#JB0fv`CBzj!|4*@B7n25Ex+kkGw**)_-PMTYP#q{A+%y^Bt#AQxQFt)bFd z(7n`cG=PR0f;7M+UPS~BS_g<{;(HKgbMUul>_P!Ti zl4d_PuPiifh$@>BMq%F^xG8cK7+Ucg`>Zj>YRpq&USE6>Gij%^@c6R3`j{D$oG^Uq zL31jwH^}(ytGIz?b6R4MOU;vL?DJXU+J55^YK5i2{&j*$hB4rj)x#bwkGM=Ab_$LZC>0&$}eq{rjkI0|VXo1b~ zZ90?JG;s;DH*-Y2m3N%+gr040t~TkYuQut}v*5g8xd4(cWJ0Ai)DmiNu8&D+(&;<{ zF4Y5>ux<@jHz@Q%N7d{W0yE191H&0L>1m`}DoobYH;N{-pif>cCD%Osy`SZmhO-Crd8AEGe?fOdN{H@L;9h$pI511gfO{ z;<>a$K)cQp{L;@bW!Wp>T2JO@l1WUycXC{ix`uAuOY-$x zE?|_a;B2YN=p4fU4D`b-CT#j}+x*XwWtV@(8^;1)hjm>bIt`-6VbmC7rw;%%etPul z%fqAHr|~bZ4{sd+XqTf`6g4||jYDDdm$DY3?YwCz$vj*DnSvY?fyAGW6xpjojB_-c@#QC1Q*G!q;8c!qkn=ilR z*fYZFh9oU|n+;pi&-(NQi81buAE1T-o%?2WwR1;@d$?`5pi{~vk8x7`;Fk9_=S+i* z9h30z9{sam&2}^`7Xf*7@bcyU(-=Ww*zEDa(aS=c-NVD9U*lh1+HGNh#eIWSzL!jy zz|`R6Q84cf3)H9jn#Y;WC%gfQF%)#$Xfc8X9bMMo_f^L;PAGT9R#Axh0NOf64`f4Z zOoi^iP4;$QKR=3J?7lpB2K&TNtQQ(Hie_^S{{MHNRT9nDQkFCFHR7YW=j6)yP9QR^HXS-al+#pTD1ce>ENc9osGX{lDo4ubfv;|I#?jdg&-n8wY)mj%fco(ca#Aqt#po z2KY6~XDTnh6waadl-9$ilC-sMl!E-y7RjEo+`k_ZFo~FjztTTnaYZ0}5RzCp%_;pZ zC7X5N!!M87Rt1o{`fZ*J@-YG8>czQSX$`uVtXa?`l(#KT287M&D9w2(I?m{8TCt1~Nr-B>V9@axT1XrIgf<{^Y;6 zHr~nT`|LN!FJol%W)o(ZRQNq$C+hx`494v@g0iNab<)T(l)*CVkx9ZeZ%Lv&F(}g; zov8|TWYovJtfz3fM^9e1w>DYIhn+JHl_mj5joOi$sxl`;8*PrB?PB&|rNjcki1iQ` zB3u*`ilXK~bXRJ{tBh9TBdLD);n|Old8=;bgx@@K>_lH(Y4tj6gdw83e8p*wquu;< zdiDcC`?3C&d3R_>7c>%CQ8IRIXpAXx6T?V&JyPY@Z}r6;pp1G{{z2_#ffh9|pL}cL z!%zYd75LhqNVr=BDQGqZ@D8M6ee41>w|8J(VrMPPi#v*|2Bk3R*UFX`8H-2xOq@+C zKyqeMT$kBls|umvC!G!us5y49~}z_fk> zw8E5u&3@P$4~GfH5FgL_+1P5Lqjzo}E1#fKni(?s$9kUlFMFc>(@y7L^dcRCEdTV0 zJz_S@(6I&w-R<`=k##-VCmRyh?nR_jEr_LRd;Q2#of%wXof zr;X`+ly@aSOFdG$IxtGOUsq+`UemB%P1DBlES*GK9AvK8V>ZHgw|>;^rz*2|eBL6x zbGsFh(Uz`x4G80cP+mYNYE}|%)Wyl|wAa_W5j-}pq6u0-F{q&RaQ&M+YHvoDPc$6; z8Xn-5JdUnX<#WVfT4>mbE>oB?4yD8sz#BO;D=@pH{FasVr{l>aW#h$o)F3_?nS~+4 zLpf-g4&ePsRuyYDIVO&Sx9SzD3n?ccUQgDV$glc}@31^MOQV`nI8^!g zVMQ}|c;h>AmWzRg(6CCtk^90n^b%BEnYmn~30|5B1#G=5>dtcI={??%5e7`Y}2Q zaR(evt<9MCF{#ch9Y%kC7_CJ|uTBnL931bSz#F|e>_;oRD@}chS*m%u|7`b{!;_es z{%t>g{maYa4ysgvNdej)YvB8+)`=|X52=^r+L^r9QQkxUIg~pyO!{Ifkg8279t^a% zVNpR;-$nWS46757^MIT!8nDq2eMFZLpPijyt@(6zm8K&NN^CFUS(CHQM`p@Obe*rB zFgU?7>(n#_?l;SN8j_4gL^7WMWu}R8S@jVZP=}am)$7ei&5iZ%r02tphpl$9-deGc z>YKTh2|tgLe&b@?gGG)g`HYs`#ngib6>-zmu+sM_`GugLgsJVpX0Es0z&yL}LfgR> z8Qg#o@?;RrZjkO9KzpZYFQEb-g?%MVouiIwK0F2FX?R%Zf--|RgmI+|lA^6s+vFp+ zM2}<;{L}8?Q5(NMczSU1*ErCAMa3)M$!`EZVNU?pqksY>(fp6R=gfBiAj6CA0dVsA zmwm?-;II3~$|V5*bM(?u7b%;7T0(*aqJX(r>cxV$j?B_sY6&JC_+HeSMQL;h*%bxB zMWl|^d!^K(J(eN@syPR7E3_@Eg#-mLEFR%FxnHX$*nPvtw9}QmZS>0UIYx1w@(a%s zA^NmH&e$_@I zLwAAu$#3XOOeqs{v2jXz!}(X70PO8dX7GSpiZMUZGNVvuc^xJL;*XX{p?TEyaERN6j7UubLc)q1F za*kw)rKF4@`$yP49!Hlo`Dqmom9k=x53J;22wa3zTZKxnQ~?X~-kl%4Dd5MrKNfz% z&x*fc>R5h|zufxww`|>qz~pZqNBD9Y1!FPt#4YGiOY>u)xBEezH$vI|Kncd+ad6X;?2~I8~7X-88EQ>@hD9$H*jS_Tk382Lk z*n)3E3+o0G`XEsM`0c5@GD^YC8W)hLvZRrrLY$L8;pXinquzXE@bBm;Qg|Oxwg)nm zNVb?PCtLh{qTT6UO_Os>#+6LzU41D|qY6qsN0mW}zN0eQcW^%8@vCx3tdfdhq>Jle zo*KkX`9u7t@n}3{L7_`Xa#R9c$0HlW_>9C0oG$YPql8#{5)IQNhi$^PkMTIoN0eg_ zJ;|bOP~{L%nf*C>MgB)dhsN$mn1Ia)IQ$4EwSYL|(iyLN7lj5=@)FiQ?iD-{B_m5? zWh`LiTj>ZjzDCdr%%j+S%PJ9weZdc96rW>80M^BjD%gEPxfon22%?1wtvcsV{xQl+ za{W+C<98n1EbFZJ3+4D9oVb;76aQHdVGlF3cokHqe2lkRQ3Y#+SMth_e#z6b zx#SZ@jR_{VE2v4o$(2TL4bMOW1E(~g*)-{=rzxw4&27J2t(YP=+z}cN{%4yg)F0xX0lBUzND$#{0$X7`= zN;HptDB%!%17O9o`3l6nxzhNW*U)^QbY8{(GZ zNjl2WlrX(9Cc@L32!rC)eJX?46NuCVW@7_y07syU{uNybLF#hj^EpVh-3TCK_*SDK zz9hC?^c!>Mb@2r;L?d2pMOKT}zZDG5!T2lQ0oHTp92S|V^r|3NPm>G)RzRu0NXZ2{E44jzkVG7?MgFASQ(P6#I#%!#XmBSVfXeGI_9cfUy1g##6+_c9NWr3Qe z=j7voc*Pe=Z;)g|v6F#>kq*v^oA4U;=zNsr%IW)Rj0b5j#>aqicoOH}6vdQ|!PBc> zj(=)J@4J!wy^ViA8{Y-!wratFLPJ~?{556>2Q=~5OZV@Si>0xdrvtN-$<)m4Tz zoY63b`W1LmH6*MN@@N&-QrfDG;}xK8xLHJa8Lh z%5$f~=Hd=*r^8meOxzKiQbWQ_&_IJIFVkvt&GU<0O0}-BpH2qj8&p?#*U0j(6%`k& zP4Xici2{fy5Toz{d{_OBkcr&yMSb5F!9V9)pdq;ULT`fL+rMa>_2K@rzZK}qO4ac_ z#qHJqVPZ8M11^NI6RkWUVOh&I!VV^wAbG_fkt+l+WUk;Lg*XCL36>PMU(0|6t-}`* zyD?V|Puj03YG=~rC8`Y2@0xHhhPa6;y)9o{GIiNQlh@rOJ+^rA{xu8T1(hvJItcL_ zxCPT|(ux5W=qh79fuP(${=>&|auFFu*kge|2DVOizOw>y$#>Bsg9y5CY-~Jm(IG%M z&1xfRy)#%3xOJcl22xi-remT5(%@kXD<##H;Q5?1=k^1^^B?U-T;~84iRiaG!xs&l zWp+|e^O*|IBCVVTGtcMb>vWZjK&(cCN!L&<3VbPWXxi5T6Gh>jXV zkl%A9jRN_>v!_NbyQ@YdO-J(~Wr{kQ&w$2LN4#V=xgJMY$g5+7-X1VvBL*F_&xm)T zC}sd(A8_N&hx`&yK_E@1B`g`mWK|i@2g34vLuax=kdsVuKB#bG7b2srqb}nj%tJto z#!`Q-pP0qTAqp7~^syjW4#5tdE;3BB)8!q4BQh~U3w~bH_X|-)b#&x0haK*SFd9Rp zK4YBK#%Hrs)lTFh8iQU#d(;(x$O>xfn3T0kw%&YoNi3J*CK({UF$r>GeAXaR&)645 z5LJ)TS+8l0^AmKr1GaF4JK>6sL&SoGxRsvWC~81x7)X*Ule7BpcO5Y^7Zz^umxED5 z-Qvhl#O@|WPs~WeZswiNtJk~Ff7$QyW1pj13~N>i+D*`mDLDaK+g-n2KkcsJe|r3% zKL01>|D1JKjUocGNR27A6R9DPr2)&rIGsL8v}8S#TBfvhGG}zj&h6KF*Ld1@RR$+c zI)iJVlwjr6u2i{^-oB)8l?;VH#$anY`?2~lP+l%Dx z_9Mfi%18nNt*BkdHj0dfGC2@`=@SIu!<>R9pJjuA11bl6<%Vu3u%dB=@Vnw&6%(A; zLogL`vj`S1(cuj4Gm4uyldRl2yyAy%Vt!;$42E1??%_CV@<5EO+R8qLd*FSVz_809wiLT-#(D8@0!`@Y}}+Fm1xXK zyLum^o-EaefOCY89tYA4&&<)8DB; zZ9!5dTo=F9(vkD6+Ku8bO6FDTr7XG5Vpjsa#?$Paid#Ar>g)w^fq{;xPO=jf%MU!@ z@_3w(-h~mW+`+v{iDq{)!E7pA+=p_cCmgRwFF@Ybu3A+W^%x}%77E~N%MAm)Q9hZp zQYG_>V3MO#6W)`kZ&6+^ws5G(i)LWcmYT4ZABebw&;s;Dd6gwLi%U)-rNIG;XV*0j z(&}`$E|LN6Z3(MAg_#%4UL5+Rpx}V?)DWbtlCezwQGEB2nsGjYuDuJi3BY?^djZLg zs_CDPVRVt6{=HDr{`P*@H|nK_~1< z#=l@e!NR!pz!2{O%;PQuN2pmqboVAWT5y%^|2`y$Lc2|XKtysKDJl`qL={ut4P8We z)K%}Xu7p|A_i?euA95+7Dzrk}sq54M?j=>jr=ypdgJ;*#IwzjB_`&@+oFZ7JYMpZ1Bk5mvq9KHvAB6DA3GXVe=Ga z7KM_(wTGH=20zeo;L|!2XFR__hI5n9hhpd^*xXOf7r%qZaFWihs#;!!a)F;G81yB{MI@uYbQ#T*H7P}B^N}$Kbsq(!YrbF05wB+b1!uu-lUZD!r@NC~vsR=qAicH4r62W6^*d7^Cn>=R!%;#Q7DMbS&aWLcK;HH zUAZkEe|F8o&#ucxpItZgmcVHG@5N!HwPI8;Tz5NBkYktjC4KddCXwJ1v1~=OZ=pBo zlyyEkxY1^I96%Se#NkIsri7pn5^e^FElvD;fwqQHKqjDV!jESK>2$*80QJ!qQt(%~ zV}ie-CO-U2vsuI{-e%Sj`yA8iEV_l&$Gwf|A|9)nb)}t(_ist#+qp{2Dejc2f#hQp*3o8!dE+pf2&ZC?M2wN?Pbdws4-8ZGS}E}Z zhTQ+TQWXjOXZ&E1yi3N3nnWv*joFxobq>m480(@I!D}R}bFwHuS5z4owgFCb@*7k| ztw!2f348i~+FQ}(lgP@g=7CUJ36<_Iz3x%n1zaHIQKCwfqjXjVK$1(5$Fs4(vQbhc z|3Aa@3;%>tD*8tzl+P;RhYh~VFjG2~3`0xaECn7lo=8@vG8oFc;ji#shEp-5THQJN zaSbOJU2UF9Wf1HaagHWyY)>XqIQc2h#MY|VA5YXaPu3-6ZR=l)B=UvX3nv*3t$8793q>M`o95I_Q zQ&bw3;rKlj&fxT#Qhuom9Bq#W=)!5&!M+w8th11lbJX5=f)N>%H87)-oL|93A_|56 zd^o&OFLIYE{@1=h!ZX0MJ0!eic}xyDg?u9R$E12_G#WGq_DuMIiFFz)EU>&?f7h&j zlHvzx5=+*=1$0gQR*{MDR5%MIx`UBNQ00`|X+i%#e-Nm_gcF4+%*K@DF;l+fKy)Ai1o1p0}mHmjB}J6qZxM4JsKZ45my(E|S+Lzw5%N zRKCb3*6T!R)!7QI9$O#O-)`xJBB0l=mF$bOaGz;cKJLo=bn)ZNxv2iHo<0v3S+Bgp z7!{H{|M?HkoxdRe`yf00()r)lx3||f3i;o+HvX0W{g3#pEt&tlm@Zo!LD8-P|MP07 z@yX$;;HsPw!Ldqh=e>&*ea%PKGs1W-n)L8LWfanhwTp+@xl|4tjZrimU|1&Be(R5W z`C2mVUBCs@4D4@y4`e+PT@UxyG_TJDV87w z@h*mMKtdf|V#}{E4RSKc9@AgsiO2t-l*9NJl>`2<%Bzezg&8IC^)oC3M3q+=TC42E z0AHmm-tG0~!}$PFzOS?G2fpN2_H(s8d-TA!zMzP4W=xc^eP35=-y{F4dh{Ps3+q6V zroI3cdPb8j`(+=nbHgypnw(J9nIZ@-QB?<#7^APAX36!A$lDsBI-sx+cyWzxq+ zlKxIP7MAUgqK;dWbou)f7_8Ivs3LkgkxzpF6GW;43&vgax1 zOID-GwL4AElWCu_Yf+>OzHbM~xm`#=XDdB?T+^A=vXAh%JKOp0^OBdKbss@tEUek++~srVaX`QQeZ3&aNwrHi4*64q$I z3I-FbQYW1Ox>U3r%;1?!wLH7<5}BZdFSbVQ5@+FhgSrNjl=;D8gR5riRQ_#V4ZFU> ztVUQsQDX(bH$3qDlss&x9+{~}>1{ZL98*@T*=(Af&ZSTWCb?DVi~9P>#)fUoWBZjP zOk{42^%qMh$6L10kWD{a=agy4w8SmrRM~g|0N+33j9{jE?_Egj`R;MN_tXB~&##US zUQ(5*C5g>LYmn?r8sOqR#^N4pim0BUl)eD60X{&WxDY6Ca?W1Rz)DH{cy0VPN89$R zy<@4%YG@*ypEw7WMCEPiL8eQ?u4SW!s{5*E##d=aPXR6EI%N=103|)AnMwI9nwe}z zxYVpw&2_3v&9av|>3@_*`Wd>qYILdEFN_*ZYyvLDKrngDW3q3l?~&UZee}!8{_FVJ z{;%*SZE<|Ozr;3kg-IXzUt*JAhy-Kmoc?5rLRwSu3sWZ4on(!5+W=UPbcu$t+Hm1i^z~4JbrL(6OaKo= z5314)#q6kxMQp3VqOx#$j5z$93f?J^nBZJwYlE>WhlDqS@m^B3+=w+y(*`%<+Y!-; zAv{u{m~Pd1t`2+38S^pd9V59(cONd2BOz39wEz4TgyGsn)`$B`HvMcA#Z*r=#)Zb` zEmfN&uhEbgog$PP!;zrk8qZt1XQ)>vL(tn`DGV%IBm`7mS*b9X6f;>k$@VgnY%iYV zqh%)P5B3kQp10`zFN;|Flriv;|FHc1j~{yfKit^dXsti|)B47Gdwcy)(bnf$WYywj8X@PDrUX9H;AU-kd~kk7LEAJP?pSxw0qyyJ{qk&|Y10CMO6@2`HAj0lnll#fF~o|5f!%jUOjyR zNkC4sbAhP}(9!Qr7U72D{u~QNq*HX@kxK9VlntSnuIrX-@$WaxTD%{@?#c*E)Q%&$PTM zmI=z+k_(v|NHqDBHJ)M<^cMIH3XkIvX2Kw29sZ8 zLpDs0l9_%R$$;|enZsK*8J$~IymWVapz+z6RPbW{6y-Ci1?Ip1I&P5sn-`qj?b~lh zI%gk1o%nHQT-A zu`?BRt;Ylm!g#2kS=cz3br*GCSIOWK5h1Y*s%n|aok1)s>Qa1o^ZjKvGQH(XB>iqw zgO@~x!%nfVHNH}$5GU;rk~zS~REqvCCKG9dZ;kVmQV{j$R0k8aZj%f2Y+$$j94(XM z%lSlir}r!;PR;<#cknWvkML!zinx7;)xMR28()6FjibNW1dWwrbMiFHFMu@RulmuB z?_~HlX(UbuCmk!nZDCu{;-YJC_OeTkUX)UC6 zI)_w4^F@}k6G)&GhJf#s4OH~lfamc%8FUJ>EwiEbkw#9OwL{%L|l>T?PDUn@_ zWNEcGUwXD?C$*llUFbnGw$iY`KEdBQ9n!G$5hGN);hVj zdDJw|FJSrb>ql-U=_#mbo##Mb$V5I`2Lk5?dTvO1TGUv0m=HK;mKi zlpRJX9JQyh2DfC`jf6}3b`U3Fk13i{j9I)mu^FqkYH9;HDP6$N-j8f`{|PJzm7ju{ z$qYTLRIx~a7nm$+e~S^j58ke0)`wR6k-yOvdX6q@&MBh#6t?ghgkj{Jv*xwL@6yUo z(~t+^jc$BX-MD(%+y1Oen&aHwt~Z-^>(JV6Ha821`8+eax$BH>%4fv;WB6u(oyntx zkp4xu+5jOh$!2~%dabxi!Nv5%F^O1J&L!S?#ChLPI0Bd~-jEn?>fKt@FcaNEyh7u`l`!yghOlGs1i}9B>^J1GMlGPP zBVsoIZneOUG~0gmn_}3{eiOcoU~Blt>MAlS*ov@=qgou1DU4F&NT+F&u$mVb1%Ard z`OEQWPZ0pC5EgKAq1iie^wV@1HonYJ4`~>1zg8FCwT1$g!a|5x1rRs zQE$+cHxp%+x6MiX{7TBwXW8RzeNXDJjzm-2V zUD)sp2dWskl>^lWV4bI(Xhp3(kotFsSrV{OX+>Q8tf+YbU&ps?G?d4!dBH{>ZY7Q| zlwp`=Q&?oUorj-78{en7w8kz|kfVYSg^0h`Hc10{iYA)e2Ym8*KppC4mTrRHC3NQ4 zETpW_>JfEmu$BZihOEV`#SwBVQKVZmuu$*PbcU%_m$z2vT2l}Ox#9#u-sz(7Gde@m zuv&F5OQ%w@Fr#|+m!*{cY9&?6lx6+H{oMcc34fNg|Mrc`;GIpt3+%rS+b#0{Z*OmI zZES3y{ePpiwf-;r?;r75*8cmGcCoc6A>!1#R$gs#AyP!cI%r}}z(olRJIGSHpfaPQ z<~3i!IUPUubWmqbRxo?Q@tKW#<3T-SVZ1f|Uo?GY+l^E&N*T5#GFR%308Y-w=-#Y3 zySo3_eG58p9VCg_?@hA_JY-Kn^qX+CWA}n%zHCNieYB){$Y`dWuz@tLN8iLh*1w|b zA-ExOITR#OOKw9@Bzds;3-#>*8ARHlIjXENOMEOVST+vn>0L{v8G=Ne3JLJ|4>6T+ z4qAT{taSu!^t_tthZuc*voyDUnK?22&9iKP-+ZhQJ;bXY;bl1ya;=~)J7XwIYv7=BhWH5tHdz8Kf%-lcIU2Q zK1~|1Nt5Y5mQZgL)>2CEDe2N^n)%HL10%BEozyU}D?RdCMxJtpS~uPKbPlrJEGLN@ z3;MyrczN2%TY;fzcihuMbgiaY_}0tk&@_hGvNPtKGi?5mW4+V->l*&E9;v}P9i$Mf zLD=cgUe)4NzYdTbIJ2*exmYbeww6TX?fq`CFPrd@{xA~|b#s59jqs@{a4^F^vhAYw<;#V z@s117x0F7S%7Z(GjMe4a40Td0pX;>HUk3QI8Zg)g#GP3@A2H^go8lak4Z{M7f2yUJ zd-naMb?4^x4UQe1FZ?Us$}C{r`*1p9%K2ZTk!knqG>cU~XA4emMv^Aw6PyJS*E8eq z8!i(vOb7TP&jkx1eN+|W4UM|d>`kw*QlIKBsV$&IqIxH=HNoCh)7HOF z#yOSTt9>Na3lbDxhC4gfN^s=RDl`;b)XKXE85VP4bkE2olqCeD`kBz_94nyZ2_{@z zl_&C}Y02f#DXg<3r(faQP~sX>cVf|UUL@IQ)$$?2Pi?(PC!%SBxG~9w)U-g78Dfpv zkLG7yX^4KpnoaAtl>Xiv!J~+6+p3&jxUoNt3Xq)qJV8A^LHD~ZF&ZD@Kq75VJ^EGP zuVFTV2z5FGI~j~m^>U&DccIDGiwlpu_0?szs|9w1pUQW0SxOvxVqtwV-GrTz=X9s@ z9HSu1&(0#s&~0darA;hE5U|dYRO0om9%MO?C0RJj=*T_bR%hqINVjCCL$;6j#~_r(+OeP9rk|5>y-f;eefVwlVTBO=&o2uu&ZH; zz5BK>JuJN=lr~hTO}HUt(#Ii!t8Nw^tooPW!&U#P22oSuEvdOv3`;3mLSYzsewgzbcj)gb-vC z#iCZ_9RDAEcov-(V!Lu&m<0#Vis8^gE%M;w@6`K}#Ul%hM>KaO7?)VA8{)gj8YEC7 zcL9-{VCS+V?p1(IgYb?AcKiN2ZMo~L7O!#rgkA7R$B$fs20Y74+#ySqhjPbRh>Emhtdm8>5Eblz}iBuhObgi6^yqpOX1cUjgDfy>_p&8+~k>BLAbSRShbrV26yh=ubkb;bTs!PkOPVXLoa*}WXoq)FwTQ2YbK-1W51%z(n^MsE z(3e$eXYBAX3OtNWa!#)&V8h{|`q!YFQOTn>7|$VbU5nPJHL-=or?c?P=vQ-xeB^Bj zOlv{8`j18m;c-4#!(l0UeMJA!rttrjpQYpfDU00wazQT0|G2TfweID%quG;n)JMW^a3=Vah5Us86}8Om+Y(K!K93+v$@y8{Bx5GRzJJ9*l<* z%u<7%ybbh@7;!qAuZ<<;%?p)TI>&Dk2_4`E6D>SDTp*m#cGDt-!YZ_>AVj&hGU-M98)SK(ocVV^7`Ou{2#v@og83> zse_k?2QT;IgQxJ11NiD#u5=7wC(oGZ7*pT@UMNx-4bSMhk5*9VINTk{Ms6i?C(b-$F59D%+$%Zw3ucN8_{jzCn z33@m@c=05D^CCWab*yv3VK&Ie{}Rsrhkllo|JV=Werdp#&;PaFUT?QR{%dV*Z~QC& z*B|k@#>V4U>t@D!+)|Jz&J4*m+YwVEBE*Vq;EaZBT{* ziG^=^@o5jHhx{s>t4oEOet6!BG34~P9+}8fP6Eb0_O-nMET|q~L7jT^6uqtM(JRDF zGT8sE9^wDwpGTNQi~jft4FT`$dmsG{pdF#>m{Ef1;w>d7yS0MMf+BV*DbiHhPkPs# zjzIuSho>o}rJ@Ky^=yD{l>3@Bem@ZeqhoxU_UGu1NE`BubBXes(ta`qWX`6e71vKu z1NjvPMM>8Nh;90%U44ufs*+!NE_K92+_snH4TJz<6?x9- z7|cvLauQw|nD)z}3cvp#9qGu`hpWXW1P;|yc97h#w-Q$ zLFIzVm9KMCbE<#foXDjxr9_vNNL+CcU%JWpG)-0JZwd?w)ITVkY&p|Xkzkp_{pM20 z+X-TovBaI%JpfYBm4nSGsX|^jGGVBOW|L7wwi1O)Qrr>$=Ufbl@Ppse={R(jM(I_J z?Lx5e79DT_d!6jbCq8!9R`<*R9>(e(H|N5pjG`US@Msl~l2GzT%mzB6r0!PAZk2=- zme;465SSVzx05Mi`jb5Bk14&%G@Yc$Od>ukH3=&@biD;kGg#zaXH2yRoad2b@qAvlWD3Jt_dQYfIOexuea;TU(A_TY~v=q0k8mMFG3yn}F z%Gmu%2*GlADb7L3@ii|~0RJ3_ou?_I9u@gHoFF=b>R8KhLTwwJVotAAG}vRR)qw~& zD8m3hxKV*v30B9%6rC7h7iqaxvrS3=IZQ5%Roq-Id`kl77@mq)hpZp@2xn13HZlZp zJ4;NxR6l0{6OhJ6pi+0W+=ZWlz~i4nw{z$`W@mi$s)egaj%0L$0R{BsM}?Lqp>b!2 zrsn4@vXX3Qld(Z;kv(^!541w8%vhf6P;L57SctQ6<~kFKtVDA(0Rx$wCd$x!j=WLwJUk9it;w2#abT)EKvtIC#Z& zRR4Ex_Ih(MGfhqY<>r)8UzVRmwG;T55xYy*VgTL3(+TcQu2fNR035b-uQRaBWwiJh zAgO8TbH{lws+}Fq2Q~G~zx&QAK|=2;imYls;V4)m-rB=g?yKS=ME!dHRk=viCQ|Mn z>;_^hCe@im7fB9}ja2VU@p%TjCf${*PucDe?l}*dFM9eSzt4Ac1epqis^UO*S}3N; zL#g!|ozl=8sb$v`QvrpE^tX97MW-}gwxQI!Q0d($(Z)*6tWteE!qcQCbrBcw+3*8Y zp1^R(WyQL4=`&cKl*9#}znBvYQZ{OHt@#M+pU^K7JFrM# zC1wgLJ8bb`*>Nq6OK4n4`&&J(J;l{ZP0t?QeEgc#a70$-UMxjM~TKn3vur8P8B zQ58)1=bx`{>sHn`$v_L=mZp6(_g+0T^+K=e1jQPO4k%P=1{1+yhIj7qbwKJ}`~oP< z&PI|V8l4SK?-{ui&2044RqHHgEC%ouK2{;T+}gaMW;wA+uAhF|W2(Z+#c-=Sz9Gi6 zArE>={{!n%1`)*`LW+3F&xYM-n8#X0?f+t_++NOyr|A^gsaAd)wmKU}7h`yA% zma_?U9Z_05<`$}#?W^tc4b`UE&)&zqG#k_m(#>+%BXq#C5R zf?Kl^f33(w$&8EO+jSUF%ZboKj6>cdJA#+lIDVh@YQ1CSd~HjW!1gCXjmmzc&lWp3uH&8 zgTjfC`8afb*l7P)E18^NG=HlPbMu{}?7{CpM&A;GfZ4BC=y!ai;@c7PA0dgkl(*u9 z8U!aMhjKa}p`u9hBUe2^jVw0pkg%$|t}s_&#aBO*TVSX2p~!aYp?92b4pCWd{`?ll z*5vv^dP#qH8u z0j&gitkvV?Ou@006&OR%Z072V3YG@-sW7S)+Lk&#z4V=f=Tg|Hhs4xwu~9#GTd%|j3>e>dIDZrr6J2B~`$X|t)2X;cH^CQb_~x+0 zGrVUOpRmwyjuiPoM1EU>E;(D&WVwSCMzowQmhs@^3XbZTA0fKYX~owT1b=w^|$j^8fxLKFj)lKUcmBnm!_?1xnE{!tf$H zu2Z{A>(*|3Cp@8YN?1LZ1IxnTEP)0zPNfcV0%hf#RS>_yy0vNAP@|72#0ed>lNr^P z&MiL+(s;1HIl)7B46NZxgI{xIeABx~6AB8H;U%6ET{MDWkp#?yB~H_eoBovC z{H_zKo~m8;d~9XIZ^OCvENM^qY?3$3CT zp}~4r<+6A|5Lm$Lvd_Kg)WA+UD`_)2n5hslR=N|Yi;UEk==P$wLxt!S-Tmv)d4|2I zGVv74^->WT7)I6I9>8EYZe5BK)3t!yH7f0c^n41upAq3_aeb3@gWiV=(*l z8YV@njSdVYML7zVIBtrMa<1Z?4%nF-*lBjI!((YT=z`=q&c+0+pXGn2YOYvzeU?o*1#~V!o-ohslyEuF z1;ueA$a|M!Cr3n^RMcajVlL|1`hmfbjL{w@gMn{ z?T>r;S~BfjWV4haBiCN+zc_mR*Z6SvuSdU}G>84J_JtMm0Ffr;wpF&8=^P6KV>2qx zjN@c834X|DAY6->N$#VaCns=RUnH2&%~BIqM?=v4W+xu*yxKi@eem*m{ABlJ@2B{u z-Q%B>=5%*&FMe_SB7Sl3GCtmWO~1=e&s)1spT-9-U;T1ozLLMu5b!VTiomS~5{Pkl z^lL2GQE-n>c3+>=qZda{_y6)Le)f9z#l8(rzV~LKrVgD?4)zfG&-hOnMg4m6>ybSV zg7<3gIM%)0Dd10GfI67-_5R5(uV2PbetGr`o>$zDz#bnR9y~ob`7117e_t)})zQJr z6Kr>Q1mJa(*Zar&uixxHRn4r~={9<5uXgtoKFqIw+kbr|P)}a(zJ$gHuTBE9db9uf z;MoCu7n(ObqT;=ym&Yfsf7v@ZdJS0l>*3MvQ}wH*NymZVfN~O>#{CiJlxH+Z- zH!spz0*IaI+V+YXF_ldMkFHUFd{xK8JWGxT1qf$_?82f6;`+HG7ce>3DV)DACzu6r0>oxJWwweI?L3&g1|ytt(J zI~R)>kJ1K-^8GQ@RG%g1bv(uB*)pFRAFEFE^WUCF(~Ep#ELMcubN<$47Fh2E>(=2sk-3`hEx z7rz|t@=n`pr9C#0>SbJkGYfDilNFvJCGWc@Kkc9F#xD?YhTRiOtl*32@`n zY(Qb_quvG9m{jahxsU1_5y7ZSk&(p9?Y=eR0r}{^N8d$TZSlVAk_j%Cocff=-~wI4 z@dm6*DsrqZk45&+sx(_92y`3Z|XfQGkkcb0BWKF2=dKN%F@W{f?mFx4q~@NNx{(Wh=Qt?V-H$jKWaAHZF%8Y8;8eCwQ0AZ&33WP z)NZrgY;J6Do5SQ>BrQriGD?$a_PbqBhBuu%Zfv0XhdXM^v)_p@Ul(S^DK99cSufQS zP%!XgiHPznl{T>0&2@zxF39knf7%4ZZ7Rf}q1Hj(<|fwT7347yI~dvoz*}wicfn3& zY?~DqSrYz2{QOrs5>BX!)p9zXanZ+|UjL4psMYMc1+Cz^sc!Wfu6scXL>v}-Sf*KT zGMiSmJ8zj3rB&^u9BiNKCsa2z2i| z16b`$^GK!oS3NCbI#8D=Y{=mRPL(7B;fh%5!ci&px=Na`g^8|)2Uq3UoGKNjeaw6W zj~;wc^x-za>?**OX5lyh=Z*>nL{T+jmw@5s)KUzH)_j~^!_`jpaaZADQc|$1gmVcT zp!jgVi|plfIf`)_s+lhw+I75wd4bo#M`0)wB`O({3=QnG=yzkw8 z2>obKTS@iquc76aEycP`7W1*PHJ1Vju&)qqO8YZGm-Y?aiHkXy6|rQTWAH{&>cl9$ zPJ45b5=jA;*Oe*|hDiOWX;QdO=Oa>E4c$krx*EGj(>^IC(Inb9MKKgJV~GOpP=xwU zhZMVLG0nSt&2b{JHJJxL2f9D(bn$*gMHgm!fCXP*3KDoEW2@syGU{?V^<011rKc%B zkKe=S=y3`CL2Sm0drqG85~VGRWW6yi721rFZ*r}&6m1;8G~huq%C7_|SJN@bsK3oI zS=)HjIaP3bI zNCXcK>j=!YYR!u^Q?#U9Pa<@&m;_IU6fg%U#LX#{fmI5a^i8}>&O$gIaJKj;Yo<-! z9u17Pi5p7=y_u+m27EfKy*lHH!sP3X>u)qjouokZ=cF7cDU6G)xMVv}ra{az3norH z%p3rz&#;Me_72Ba${2|~m2!f6b4|rucbB(TC1VPxh>5*ljZxVLq_u{#W6NcMEyw_L z_N?V`ddw?ymj}jxnqDKwjG-Vdpqh?*vtD)(rwZdSyLu}e)>nv$)IdgErntYj|0gqCZ9TkQ*RL2$zj8vIo z*j?e5Tcf9`*e#|sk?7bg%&l^@hlEv0=RnwCbufZB8%0KdR8fGmgPrKXv5Fg`9H(X_ zTmrOaHTIp@CAh=vH5M287}er>I1K^+e_8&JOB0 zEBa4(gKY@BH@qixii7g%0)BKr1e&`O;vr~C#mF|cApEc+1oYs6`~|*AM}4Qc8%0+1 zCN0dV(83}$Ku*k44z?nq!#1g()PZJF{OV4FPnQ^cy5!($t7DBx>4~_U+TRzJW4+hz z&L~Cq&4*9ef|H>MFJG#0(m;+t|72drt{rq;W+UtQ!$I)HpfPL?C+-``vIGPBY2WM^ zW=YQ`Ze~6#*?`i_ZtRQ~{SD*7#0_#PTosK@=#_DW*F0W8N~EHD#nRiC?69$2nK4J{Dz~ zoX&>-;rcg=(A+okfmac6J~ICsmBWHiNban5SPmWF&Q5Uhz`;}5R3*}mvzqXiAC>sY z1>ANBej)DjjVLi9N*X#OnMJ#2s$4DV1w*b~s+t8#tTxSlS`MCK{+S znB%LoJ4B^Ow+?@y;sKl&(FS9wfcTZgydF3|=8iCsDM9<`^XT$3aNYGc# zd*jJuJe|!)x{4Q_SJGacI~fAh-BL&pAlqV}O!-P3ziR)glB$+!vvk3}vr@1Dm#h+@ zW<|aIb69`6QfPC_MJy`D(hgoFBNQwW!B+TL?3lK=YhdNUP9;^pR|3w(rAR5kD0%Cn z14f`@anz-=L#QJvqCy}ogroshr@NsDCi>uz&aG1ayj#K^r@jEv&Tt`{B2%}Q1H`W+Xk zgrDV>Xhmo{!n5L<`gP6)bCeq7SbKDP&1`6-NMUbrr-)RZ+~mf|jBc>Z%AafLG4O*t zy_WT_>-e}@C5uep#9L9ysg8S zT0evU-i1W)QzVnOL=uW4XbH9WQwi1J2d7_ME*)D`JfKw*l1|H;Oc#zbT|CZIjT62j z0++;WBDN?7 zjgTBju?{hLmR4qB{KH|3tY= zScg^=7eYS7ESLgYW$l56#&yX^F`Qn{bgG`FQ$53R_-de$Cc+&9X`D0@XByhdWPskA zWN}uuuw=GUCshGjxo6WGQbdn2?KHZnrO9+a^*h+pxqPz;+`TuO!N=h}mmh;$|9QxP zlERXRu@lwoxd5Lwqpvn`4=`uvEW@(G<1;%EkC#T%J^~fgR7yS6QyUGHKu&R6A=81@ z*q84R{TvIVKj2u>cmYL!`GKs)nePkY=%Rf*YF!yC<+ya4!lDVq63r!KYH6fOBcT=4{0?Ry|YtClhxZ}e_LCwvKW zR8fW$?3O#x2+C0RO>VpI8(eemNyNu&Oq5<6YJE zhi_tADd7L?Nj2nc)A1-4Kc|k72|v6^c_&iwW|G{ZLO;02MQw~{bm%3HChU?~qw)JE&5 z*{fO7rb1m@2I;JYeviHl1i%*9T)`M%P)1DS`y|J$QOh;JU;SF32Vg*fIWaso-#e+I_k*^K@2%D}oab z^I^w5*%sZH9Xl(!ixtl>#khq4mZ=27)tLfm9f}cZzIMRphn62W;Ia@KWqXQYgy_Kd zwCO8(Jat@ob%i7L!lnEaMMh@zh^e8vXyV~yHZAOG!Q0m!eMVu&)AKa9f^LPKTa&1q z!+8rfWSN=RS;*7tblS_D5``M#H@TkE{bv%oX7of73ZUgzf_C$@yc=x?MSIJ2i|_&u zi(71ae_F1LjS1=prp%Dpp|LR9q?gCiyc)08u;K$qfl7|!sqJuB7)kvQvz)%{C>%U* z50h6pC>EK7s=-t>Ec>&_W^o}3)UN4TnXY4eSrx@xA1%+4q?nR4Nw7jYK?Yio>R@IN~svkG1e%!41k%HMP zexGC&KPJ6ij2>#$EvA(%uH(_7U$fCXk6T2#Ca0)ua5{j?ud>B@#jhD9i2!MV zgq8AknrAHAu4;1@z^Foqj<&DbU18qUo2Xh3#eSzQOAbKn zvX_jOYpoB%ARC@mbYWo?b84~1l5H)60cD>bPDp*(m&_@4H7!duPB{L~Qi0U3qSJB|adZ|!RuNj1ZqWB~w1TAym-|w0uOpQTOaem* z7xc{bv?hl~&!c_57!19>G2V7E7~kNCYbrb)TcWRk#);0# z`IV%Vp=>gi-bU9>;tVr@?;*Xbh!cmCh!QAmC`4l`1r8>csqqk^1EL0RsOe37uP^px z;JIO1R+XBb?gL5R%9VU@PF>8A-_=tVcTC$X$0TzJ)29)rI(aN zx3p1r*S>k`EHNu;%#>(tRGxo_4oyk*>KQpc1qO>w0KPLk5ov-Hr@rUceOdH~wDQaM z1QHIR(T$CZJGN=jD$MTZwh{kSE}v=*w4_-Jf!N3cAmv6b$1bw+{xY@|a{|TlaI4He z>9n+$;{IY85Iddnvufk5vX_yOnHs_&IHRIO-@{$>+dNHwPuGyhi%d#mK8s~!On2pc_d#MkdFWwc0-x=e!}%~)V-zP5N{~hSpuA8vL&x2%=v%_s$4%jSilhPaBfe&lOCqb>U{rXLc5gUN-H`vze1O1UL#DgXs;M_(QgkDmjs_@^Y&l z%^2kBl633e@GRlJOA8Fy_GP1-QD@~4fJ8`EG)OD73%2Ljcdksm6Te&C9i_oWC zip2#EWlk$YyYe(M2RFB*H7mit$p^nMcy*Z0(0wVGz*#qXe+f+jNtw;>zWxqBJ>rj@ z3f^h?{saUc>zz?31s|WcVmdK3T)-;3UwCy3$@53)ju-$oZX!#|k#w-s6aSo-ls=^V zhAscL+oiuP;i<{L8+5o1^Chts|&^GG72#C zPvyN8_i_3X{CG%re{^u^ z{$wG_{lQti`RSeh8_T&ISYy5%CfD{qS!}DV*y5gTl&5I@T=Gv#g!YQ}hHx~cjGCbG zlnc5JDT%b~xFdCVV12!005X#oR~M>)TXGig()d2A9X1};BQEkV?`N~MpLP$A+Od^d z|INYvuW@_5z1>)U)ExF#DMz3U#oRcqs#V>M>=x}wWt4D>-;Oq{gO^YDU+urdOqGX! zRhDF_7o*b%>Rk7=t{M^ZsC7FwB(&1o>Bh*T#}g(S4K%i6%QKN;*hYMHVa2Vn8hM&3 zDxhwY!90(;$!T6wj%Q>-1Yu;9o|D+sn2xV(7_Kgy`d`PRs1dbRo9Omkq?j(I<;!gt zcBlv^IPZF7f{6-2lIinBi*dHFB3KtmbJ>}t<1zk@0jopUfz;;PJsBZED9(6-G)N8%{p&Q7y50)P<)S zy4qoUUaPLt72+o8X~}ag=gf%?ro^tGl~81dLoHM@dXZt?5r>jseJ~xAXxL+A>JT`a zZ_X%*(wL}`@*I%_c15H?0fhZ5hs{VaAEWu&S)2$%qDZ3>+FTuFWI_zx_bPIN`=0y9 zMM&v+tOzDoa)Lv^&G{&&h|d^ldli$qlW1IorBD~c>|<4D4Qsatrh=IULeZ&!6MgXP zvr32XJLf1l=LdePsl!tM+TxzpLcfbzPOH*b?BLuNLUVCb6}3L92hdj32doIgEAUKy z!SWlk_F;4@r67QPr(92HsBIMgS%69$*L@*){93Aj)IJm^sfKzS0?aN&MB8ijHfo_? zrBfJYd4t%KSKGQsUAol#PBd!f37m3LA;&q0_-*$_gAFNG*9q-OU_%Ob_m4Yz=)k_% z&Gl)9*U1MT&aK#EPhq=8JGfJ{bvfxRLMZ&8M!k({qedH_U-14^F26b77kKyBY#4SU z;iNEUcozh~5}(Fv)4L}4Ju6A#4V(5@INWn3q-3*i&9j%`(S|Vxp#FMr^3%~TCx%y- zl8MoSIqwbev=e!_y-57ErJ_&LMLW*2DpkJiEsF)NoUHqgoltkn1}W(uN!V}#U6dEN zm+MuOZkcl%kH%yJgYP90u!kXJ=jrJ*S+k6UaHKB*?s+!Ko6dTweQ@ufC@%%%X+cX1 zXF08^3SX&@qcIO>_w{IrHqdo_y~7Hvp1c*_$|?(3sgK+{zB1Gy(TZjIX?Oz*Ec3R# z!%7_x6bFT~#QZnjlFMt56`FWOW%dJ?OpQ*KEZRL&$cUWN%h__Bs5{AkMK0A21d$<(wR#fO) zmVk@Na|I_hD}VE|h!R|0j2y%*l`DHya~QDkt(Nj$v*I&W47^gfCLOSaK(e)v2AEa; zDAmAoXaWp0lVV#oq~67NOu@hjzR<8iSCpe&@$4Wsx&}wIkvI#jAF~O7Z1#nhXyHoZ z2X4qUT+s^*sX`uY>hKav5LH0au$5M(-6Th|+G;b&V|wuT*3tKuQk^`opH|Sho6t8v z<0Y>2cOdX0gyND2Exz0wsx|4ar=(0}kbb?S*n!0whxgDvc{w3yaaIqc;gXdtvo$37 z8E_zsWj$4Qd*KPa%Z{?}x9kF?HSZw^%&6fHE!9KaXIYygrZ)XbOrH}cZlnX2U7Srj z9TstG-qO6T$t-5S&YkF^Z3q15Ao{y#k(wVJfNfZa#j;xQs80yrwuE_?el04z#ZU)03DC%+ps3d6ak6jK<^K4trUCLc?1Cy& zIm2i?c>P*9gO_ij)2%uxJoRRtrsTkk=MVQa?H ziZ8ek2Em?A)8w)qO~y0M?co4IJB4W_duA}tI^olss9WF~U7n?XA1n7R(g}&mN%9Fv zRqOeXO!4@*Mhuwfro8LWzp8VGx@Iak%3Ayx*1pbJ)hvO}6*^FFgm{L5`KGF?e&&1a zbYivnu(rCqp00|&7S%$*xdpUGK~c@$BlNHPaO=r(wS1LSNhR7COLp?l&WGUSZXdI= z{B;jWhShTcxLA~%N+c;)X3OC|;KsB()`D9R*au&J_%4iVR~`7nj(t99yh)n<;7s^v`ur!bG50}Z>4x39 zsxs;sb6iqhb|B^FlG8}mPB*0JVm`VIA988PElL2g$CfJZqg-Cd>Z7?V7VJVdk{noX ze?Ca*d}TVR!Kr&y!sU66>E+2W2$`7ny`u7EGjwd8-H@7&JX$CkH6c?E_XG~@aadF2 zI8y#sxzySrZw4}cPUka@WM{``d{|MgV^3c<8jrNm9|THNK|1^5?4_j?Wn`BAjF-?{ zj6=Wst;%=oo};OtFV9tiondBaUlvwas|7+kJ~*^+LPeC6up6zJK*C6+%viGm19h=$ z+?JO|C(gbhr=@*Y+W+)D1vOFe6S4y4*-YE1nO*8Qppo@{<$2vW(PI+5MS=8I0KEt` zBdI^bDV=iEk-I{`w?rV{idR(!bCt+CyU`gb=ugMO$cr_lY(TYcpte+ZRqOZta!S-* zWvu90ydHx9NCfH{{CC&72G=|>1{x^*)Qp~3(H{b_vg#kEJAge#S;J&nlNx?GS~ICa zk1GaKs7M{l+@DME9A?f!$*!Nm6-JgazAl&vV`)EULdFHR8&RAvN~p=`Mi&B7fhhob zsIh3ph`FpGVFmnrm`Y8==q2nMg%7=_SO$s$P7K-&%Q+}8q?dm!t^_<^8MbT@3>g*NWaL6mRq&SOjN#ND|^xBUab=_e&;2t z-pel4Nt0ByUN@i87g@9pfWP0WsXHaLzsuTn$zE^qpK*D97sv%KNTJ!~+s1i&pF(t+&19x9)W{umA} zOC}N?&3*a=2Mw&rRa;fg%^9}*Emd$+2FZVUgyVz?{K z5(Hje@$>}FKdjt+tCj_8ER$XCo<24Ka6T6|tE!BXEl3_^kpQ2={icxmWC=r>-A5WPsBhQ2myqwSAOxwAs`Q=P8puT}-VzjZG zrI_4-F||N}EV|-~txG6i%szK^o~itLr7Y^b3oE9-(@{_LEV)GE=GGztQy?Imy+GLY00U4Rp@jh&j%ubcn3DM!4Qcx8E2eY2xIS ztrn){UQ)HvJWcgrW}{WKKe%Fw_`51KrQ*EBoc#r&4ft)BP6tz)%PqU`O2f}e2vWed z;d@>eTR6;95hEq7I-p*arm0XQ*1eYF0ST-m5b*Vx7jtJ~(YogFkW+=}kM6r;G~JrJH`=spNXIIE9)6WCCR#Jw|AavIc`+a2{C5ExDy zaSj>Dt~J$Lk~lI<7sTCKf%@w%=LaHwB{osafQKP4Ldn&#l>|z1OloqK+!zwkr2(uc zPKWYAup+sNgW3$Gl==NsQBTQ3u;ik1Td#PGMHe5CHIfmI{W5gWsEKgaA=F3>N(w4_ zMq`AACvz2;rFYM|8nTL9ko7>za0bX?%W&RD>$Um`r_*0^=o)0p@?CGf5^RL7KtD;v zg3}tXt}njJ$xq>aYj9Fp1m|CooFO>-z40)_Ws1|*TYs;q>)wG$S0s%HO*yPGDaaPI zlXb>O-HcHx347T^Lz+@sK#<0rGS==2eJSF6-ms`6WTJokBRs>I4~`j;GV{6_+l(Q6a1V z3Q@THEdxC(Q!B;D%TSj>jkWUbFR*RvVD#P>2kZ)LW!(=C zF~y?a(XPx^+VcrEDs)|6)NS4C5~|}?*7-o%qNZ=PgmEnaMycqlz$^!$K+H>w{wy%; zqFsLD59Ae-D;*2l1x`<)&Rpp+;+DlTQ7l5Y07UU@cyGa~*Ie0ytnyt|{W7Y4`7C_f zR6bQa_7U{<^$t#n=dOqJpucSpQrJf}*mMEFGPl%{gA;OeUGOSf@)@@H%~dibZPi}% z_*(u|^d)UK`0?H&cX@#B7QfQ)vwZ5g#j~qs zIc4*_3!}o%XE7QrUQ9VpEL+I3T(oi#OJ~BfR`AZKXwap$hUqZs;)!8OBw;n=BFl3X zCE1yD!}3n1wo+mG%an5xEM6N1t_nGQzzN=Z^_+NIzp9h^8&z;B46*7NOig;)TPNJ* z#45KJosRoA=vR$yW;v!=>7r}O@N{q!)mC_>jXXI^S5~`Zx68+a-Zzfv?tPXt4qkK3 zp2lpfQpgU+940RHTgU@iQjyFjl$V#hXs}YA6FswQWro(p7b(en*)`BbKWR)$f+d7( zP@J-m^2Q__FK%XGa=ELERQ#pI+b2)mr0KNmXgo=Nn=3FnCsLz3M29L#qJJy(p`9Q!*FH)?Sjf zXn)u#y+*rr8&-0j;QJCywS!1a)6k2ZcBCQ2g{AN>25mN-vnTrpC+&f*6sAHx3P(+1 z`7v$s*O;jN!2|UbThM+eUBIUtNugGm>4#f(f}(UeQdEtpuXOAhXXOc|B&U_l*f=gu z`9eq~hlUADWdXvoQIG6xTn%trUM?YuS)Glwdg;XP$39R{R9q-FDooGWgyn(KoR&+a zgfx>;1^3EKz7}(~r*w~!d)(WqO06sg)y4J#qgU0~D_MtopOxo2G6}v}TD4X6MWh8S z!aqg$7(78CZz1)nb=(n0w!Plqhrj)D zxcQHG@94#+~l$EUSuX z#q|xy%Uk@jjk?2;nhF7fb`&Xzr(L%gX;*IV9$vq>?{wx!YIYdhW2{}E%U5gsk?@6B zg!5*2Dx zTn@n~(x!-%$%24Zw}`q`9af08L%&5)!>tahs)*^Sxs|>Af@0)jMg_$fTI5s{^GlL} z9H9nXSY6B+*z}XaNIr>HR*)(yjTx+qTcBQG%9Z7wmM=2}#M0)|>X&HpYckylX3OOO z$HLL+S6yjH%D@wz(!O{JSaiciisn~7E{pa3J`I~fk0t~JC`m%nX@~8>Ybq?d9+CY5 z-ZL%sL6r^WBsV}82QQcX(C52=1jXZi8s7R!;5-M;Km0he-6iN73Z$71L zdYIpt0UO6qjJeXPGJ=;1g*vD10p z`V}Yj*jO!2U@Rdf<$j591!pfOHqc3vypH{Qp^F7e#2#4@B*%@#1vcz87njD zztaFt5(=VORjinw@A{zHUw1lKgqPpO@+h`~0=$G7H5y0X*7To0zeUWxQ`48HJcb^| zIzx6WdX4xj$p&!lUE2x>*bull4uI3)QZ}j@X-zAy17f9 znfoAy6g`HDy}G5O&V7S&m)9B9(S6*t!l`$jE{1+*qhRQrc2FMgc(-AhC; zld(jZS#whJG&HNM6lwhs?3gpUlk;KB>HS5fr2=6||2@55V>G9OphiD^5;fd6RDAt< zbKORd>doozsssF2sL{%Dw{39<&O^9p3~qJrL1-WPo<$Wum4kAxszGfD-y&a+K&7f< z2+39}ULrMXS2W{E6`@%M0{>uzC|%J6lOvpm8%C0wrKg(S-(SYI+o6R9aS)l@f-( zB8PV+VHvczm<*w zOg1uufQprCtA>nS9u4`nZ9!+-!>46j?nJHPZ>}}F(8MukR}7(z)WJctmAVsc6n~|t zs!p`!{?crQkYGvQwieSy;rmMzY8{T{HZa$mxF9TG7!Szw<$m@4(*5F2ly1l;c z$2o?^+M|#fYe}UKx0%%3m0QAuO9wm>-JZt7&grXt>_YdHO99+%apo2;ponJtUC5)Y zkRv9v>IKtTnC+!{Hm*#oHW)RbyfbMiCptlnjoC8xLUB-QA2ET>omT@A}Udp;=RIJy{; zcW!)8mN((jur$q=0NZR1(*qR2AQ1vED*0a|yulZC@xTv6jiC_uvVlaMnxvShANw*FU>N)~ZLXfW+h# z3^t8@@v4xkO`5LPqd@C_iA~m&4OwXM$Ib4tP<*sIAm+M4{UAMu^NjAlaBx-G4L4;a zWvzdFK|WQ%2*bm<5R*O)WiyMFRUsv)VvMBG{)<4*p0ifEDQ4d@2X zb8R%7nIU^rF{J3dp7j5o^w6XCN^{kGkn}EjIElPG;~ZBL?-n!rdM&wbITl#~rU%C&&nBoKWDVn}-qoOah z*J-G9RzNqdY&N0xmTQA+vGV82K{xlEs$UkXVwPUhr6y>JHr$KNStCbQEbmj8jB*4B zmK+!@h#XiVLpFX^iX49wh`*Q&=7Cs?Kqx%2H6+Rpqg#)?(U6 zOvzrbX|jlb;3b1KUzNEDetpa_B`QFWr-sB3z`zwg>ak=|E~R4#WbY=T^crO=uCkf< z=}WYiBRZ)s;nr|BnJ&*T$waJDkrnL{|LdR8?mL=%RX!z$R>3;ScT&n3E%OBi1byxY4K6l)qUY@SE-?Jusff%ylZTZr`;W~WhM#-Z zAaRq9c`rB$H-vLF=-W|;ly;1-hT^Ns^9QriB@sB|-o$ytR0W)6 zDtfz4TpkdXwU!1#qA&fS0AR+aKzA?gjpOA*mAvlcHMgifeTn;=?K?+>HzVp6+3%Ag z@)z1HKP4?bwCA1h^*>c3`v3yFz6m|X302`EvFY89LX`0NaoHjhMdI|^z`j1d?1gNHBSCSQO zW(srL0I`s(N(pAgxMXe~l8Ca3qkh=RAjWwc-1_2FD3v!sz~H!6sZ_Ek_Es`VXb7`}H(W=DOa}+e0F!Ev|>uP zGBPVoF?X+wP`7{e$P1xx=7nNire(akZLx>-GIrL91%c<3 zMI7}dV(e080gef!u%@^-NE7rS&hz9v6w6<(FDZ?8Td3PG&W2O~;8*&m(rjSJ^>b6q=u4kM=!}> zIMDespv%t@xKo)U@ShY}ZmPjAhO0tuyq)UYc>ko>@>1+AilcQ)(W;oDERWgtj%kl$ zvbp{-3}%Ua^z%VTB?Y*RFyvsOM;*`p#1k- zZCZ=tCb(Gd1-*N!rAsN*DP%<)K#}IEB$)s+tz)Ldc~L)2NQ>Dx`q@x;Sr)AcWk3zX+_@F`XZgB zH%@?Aars(6AM0y;9nhV46Pze?tIH{SogMd}1XYYX_#>ab`f0Ga{{8l+@{2oh1pnpR zab{FJ$llX$QFANV_~NGSLupa_|2Zs0L$<7DSm>gdQ7>RvG#glMOeM7sKB0wSn4fb#OoO)KtHPqLYeatWNhxZtn#`j3&@V6}iew9<{VL9@Dp1tTeOxw^ zvLuXU0|%}jI41$WHSecQ;*aLW<%Fahz{0!!y{^&<>Ou%V$yM-Pm{c-@8syN^%kn@-^veiyY>B^dZ&(EPmYbNyfJ^A7B@ zoF196AyaFYGPQCt#8|KSE? zpg6~~1QR{nj3r1CBW_v`w;CkGqajFTP3|R=Xhbo{!^z-ALpz_M7lA6Ch2^kRxFsiK z<@2G?kOyNMOXMDO-@weUG&$56#V|QGPD$ViE#-fwB;=Rf_}5|nq{9sOTqvi6R$$I| z*$k)WsXmE(KmF_T5B@aQsBT`qrZW9ER2<7%KJBfk zfPgiom9^ox-<;-m90N|%`u6%d{uem$ru|>|+xo-Jt&Kmmw%QvHH`d$h?be^xH`))| zn}3SdzsQQc&m5(%DEia1chy*L4KCkbTwW#TdGh{Y`}+L-#ub##obtNjRTQ=g|J#a_>n9;RxA2Gr;T z-KT*>=7UuEPUln)EV>vEQ;uDo4}qY1+>_m@`zZ#lou*O)@N27JprXZZ@@V(TK|R`k z^MbW;=?G>5pmWTH8(pMH9}~tKS%Kh?Ri-gb2UKKF)r+SbBXX;giVqce`6R&_jnRv7 zJ`+D)c<_);lDHeeL+|wwr-uR-2Xu2fNF&F!Fyid~`D3c{hL0nZs9AHU5^dvfeS*h0 zAU||usIUkedYVpBiaL&_$rVT}z&MiuAla?}h*ipXIgkCX-(RY%}j1|9|H39_6$-gn<4H&=Z^| znNu>I!aKTZHoCBeJ^Z!||BQ0~qoW4dMK!8VZ|wb00`wRj!E_!f2i!e8Jlfkm*?n@T zu|VNt_V|xve0&<5&Ee$eky&}rF;2>X*KhWps+o8@zHrh!&F2LM zWv42_$-up-CyB3PqDD=~thiA1N}r|!;C@q1QuQsVP`-`cb{Ed2`>sg{Q*+?cIPOz{ zVsyZqaJAbm%80{L0A5>>q}voKzuMJ0n4F{PLB564HXii8$qCr|ENL9PMo!neY|O@L zMff;l)dKWEKG$gIq%RqlhvWjU{V{M5AS42&kWeFV(QG^h&Yw_qoQO&QJ4j)_ z%{y{Dfw=*_0q4L1op4ziT6mJ=9A;#f&6Ud*kR+3#nzNK>4MRkD!yJrZSQ91rvB(3O zV6>D)s2o$SaK;57D26P$Op%T!sFtGOr_&n(NAXznK#{8(_LkUhI)d5s(ta~KMqL(h zWTgs>=*fWBsvw#`S;&rt$t6Gbhq{z>AwdKe2NoLY%X|5J4s;MBmBlcVSll>bjX6nK z){QVULFxz3Gq{VhGlG`@v%!*@I^X1YYHkj!YLqHXfSK$B!+j`Dj8Aca*OVm*u=!mJ z1YcqJr2CV|p`X)UFS!hCk;<7*Y6x|jxoT*L_m;%^n;DeNQRc+5p2foys0mD@Gz+<0%%a5K9LM_@tc=5mZGD zjyp>frgXZJp)mlEr0r)@38)Lq;hB_GFyplt-u}U>Mtf`HAuPAw2lPE}=_gYsx{fch zI{Y~p*P|Qy`wjd(0RDN)2ftYYzHNa&8_%cFvq>9(z&cQgMOpE##<;u?#F0K}1$8ODw`g2LC`MrfCh&@PP7E*;^eymGVt zC_BHHHCV4h_Ze1Jafv`BY8{`QHF_5bkeb?3xt-yubs1js-qDL!AVy}3%`x2ARx)Tq!gOx=GGBK zJg{VV&*`p0Da;Zw6EVG`Fu*% zw~)X|-ed&JwU}t7%415UW*z{Tj)64$c=x+=f_pk0Met76YVYG zUp3^s9;I2C9y#9@0mSyJkL_m-j!);BOX%@~b3Q?_8m=vTg^ytia9c?OHca8Ro$<-f zMvcGD2TtT$$;&L1rpX|0qwOGW7NTukQPN$Mcv6+pboIbt%8%CEsD9`$-Jg72#lQi|&s7e*owLIFor745f?w2d5t}+El z(oTHjY4xKd#ZFAhmqr8Cl@|%UR?)Hh{W$A0_1L;6ve1NH80D$aG%=Hx#H4NO|M=`GuI($l!)sCE7P&W0#nnp7e@nY*PU7&bi1ybRFSi7#j2&m;-$V z|3(&P*~YlXnx3Tyrv?%1r&A_(far@)8vEv0-+HW}zM3ZI^K?zi7v|~0^7g`EShx<2 za=P3ocv&wo3f_mIQF_aaQk0rX#!(a+8tLruSGNU1Jx_9*LNVh#eW&!_T0SvD=OuK? zO0~KMrfHKFQ`4(iwFq^4E2=R;tTt6g4Pcj)!?}E!7P;f}h&+<8e6iRotk9fc`WNyH(crc>*0wiQ zCsJ7_%q~yoeXPq=8>R`oLI8UE`{vdQdj3Zn>o4Hg4uS2m0>bbP(j%g<^B4p&c!!L8 z`5N6_Yd`HC9<^gjfBWWO|JS&^-rjDkKWYy9_2@;T9oX4p5NoquhPk0TdUL?m17tdb7JT}_7M zrbzl~lo$Qm2L3-8(Ra9=Fqw$*OJHCkKPSg$7S@amZj4DjA`and9HDN!2a;m~Z;|ZG zm_CU4PE)h6+&zZBy!v(b^;2`;`srjazOhbZE}1KJxd&VU`+tcFiWC4CYkO)iI!&!N z02%TWU^Z&n2_rdGBmg^2bA@Mjd+1S2k}~ZDgF=kKTsZ4rG5`^xf76ha_9NDMv0>;8 z#2yXII&i1Zl%5EQdg7pb;$1hE-sNn7*#Y4!RbB(ncaden*#Q~*p>@kxz_4O1%dDi& z2iahj!6|3wdus$oWAx&e!;^zohX;GWgpOXudq>A7YMfR(riV~rD7;rds$$Ps%jwVt zZ^PbytwEMRgvmQVS&5De9(_n#&E`(4{fOT}b-dNl$e81LHK?~;cSJNZ?2l%^NxN?^ zF;e4QS9urdQ4oIjQr=i*R^7|!M_Bx$E=oVS^(IIOUadP!u44^kC)#R#-(3x$_UXa# z-q9~F0iSPS^^XzcJ0~YO3+LZ&eqWCsZ9b|;55Ip1e{65UA6xLl!wvkdjelSPk%z4| z{IR}OkG8*mgnz(4w;w&kKk#o4@ox_|;E(O^jZ^IQHn!h}*W~sVcG}v+Kk%P8;Pxi| zx{2M<(7nBZFgEbJ4g78cziZ=nZTzl{z}wijWslIp1}$vR!UipDu>L*%fg`MM;~zNc zI{vy2zixg1J^t|s|JcSqw(yS){G*M3V3SAI2wRV^=_73V2%A3I#6Pg+O88{2IoyzPh92;0~RQMHBG-`d7b+t>*)x3!Hux3DMT zaBB;P*}@)M*aK0zwS_&lum>V{3%74;(_RCjdu#Kd{sX%s_O~{%`zChBec0N>?wjlC zj}06Z>0k@@W@}?x|ABosth^#y8wdmUP5wYYxPx15gn?uve;}YX!oXdXKX4Mbzgz9L z{sRHDEeC7-2NFAfqmnKMG}$B=sKZqw!J;mD%vC;Y9dp=fm(jOyG%!ixxB6(-E>~AE zMg&htx4;+AMiD2nMbU=gu{24Q-jUN7uW=RG%X*X_BUr);&k}_)V*jMafyc0ThXLQG z(q+hz{EVp9sfX*3Vg9h=A9$&`?z*mfZQgQcWK6~zJxT|8x}aZpEEkTMw5%JJ3TRn1 z$uI(J-$H-1=J9Vo8l#{zb+=r!SF+bpccZ<%zW(hc`j$U@7}`qa}?CX(R=BIFoAhbIcMypqk;Javj*RsfL}((!x&BFJVIp}K|&^)F*wP~T`HgLE{M zu2OCE(ri%MXsaQMxhx;PT=sRIP2m9&~}t-oTl(Hnw4B2xAW)J=%zBM$$)w9p%YovdT47G&HT7 zou)agL17lH3~)JcBo%N!*a1H(CP)5KIv|V@0EfG1-~e+XFh4}F)gD7>udi2g9PDXY=&*}|D>0*& z&yRVi+vj9W(cqe#3ax74UgNW~Je?_34CVcr!&Y}Xwvi^hzfX3L_v6F;m+{fFXUF@t zpOhtD%IFQtLMUUFPz|beLO|{LDCjSENy`I&ar86@yzN<~)BsNsrCM78IN`&Gyio#K zA!cdlh!-FDW(jb?%hIqBEk5im4|b9IZ2h_+zE>2O+F%Qnc3V(N%kQrclpiqxZu2<3>tA=yfF~t0F0XP=-G{>(#9#Jn30ILuZEK zWcU@5!$WxlJhY!(H`@QTwT%jq(_Gmm4b3d_j|gtT;lYb1@sooSODne}*`R`Lt#%L1 z#y>+#!q#@<6qvotE}JQbBr#(XIdFmQ5pBywc773^66VT>i(l=t8;;{sq{iJ#rc=~q z@esLkO(nUrf$Cow+cC+g2xh==$;f-VuU{YRKaG#~b`N)7+eTC~v}H&#W*yoTvh^sh z+)#pfLc-5~du}9*{&R7G?CWHnfOND#_I zpG58N`I1(FRbmwBM7zg(2M1Ai#W7hnV2sA)@8>IB4XV~|vG}#>c-%a){h~Nk<10!2 ze=~=zL9hB8g+Zi#OD3fsbY#IGJ)1SiA%PLwEi$c(gk zw6|GaKuWjUou$_%FdXD1{{N33qY^aWPxSV9WJ4)H&YEd6dUyLaXbLq9i#$7W!L9c1aF&beXxMF-GCVGmbM)KN zp$`U*ryVABcCVLCW@}s%d#U5~^ytOz!OQq$_j&x&{$D!LgM2msbU=&0wNhlRpkv2& zYy10$?d|Wk)9r`t{&su2^>A~0WBU>Oy#@c>fd8I8Otv4cd!H3^9^d>NiSeAp8ewo8 zDBxN6quN2^Vcp{JOWP-~dNiT+3Mj=Qjzj}Hn~y~I&(;*rke>|T+O5OY%I;kHX-m;3 zm+1{Xu?$y6Q%r`wpo5!cw0oM5r>EGkt6c@UCgMT^MStf3GJ8Dr8rCqGo|C?mo*+PF z>g?(LZE#0@N8;mdJVa{)5%9>snoKFehs^q7DH5CSQY7)_=lJQt^ZnzKr6hXW)#LR~ z$6^v&yvs{X1pqEB`P&mY{M-{cTsRSQQET~gvSjAZj~sLrS&Se`4D;=RxqWtgi5tt} zxorgJW}NiJ4U-D_By_^m<>cMtYqB>Wv-B!?L~ z$)cH1%%r_>D(2l8i;VnEX*HYMlA#gxTg2LM+;xnmE*%v$FZ)0gR`d`(SzzbFj!E&taHb~K+MBKui#j+SX&ViG-U z&}u+FlfQ}2;G#kO<+as_yu>2uSTSgZZcYk;X{>d>Nas^@&FbaKjR?cW(R&B2?Bm{e zpv4+(oFn7)4K+MZ@->xMfI|AFWR=x#{X!XB&Qu!H;N5$?)1Pn!E^#F~y|JIQb|5dE z>=M)xKk?J*Sx_CM(ok7YGpbn}nw9 zJ~?QR-UlDP)AKoHW-gi2@&4gHMPU^jfY&YULYJkcS7^zvailBeMrdzszkLU9R&oTq z8sor}Q9|5!nVHx^t}YA_o(xHXe~n+gK00~^;_L2HA3N=(r=+JsJ@riPJ_8RgB~t{Z z5YXCcQj&}g9MmIM@)ZTxku6>_5p>B@qRXvRv>myKSSA>~=QZ3SO!XVUJOypzZ|r+v zYiB7*)9NzI=Rf!C2fKbpxMTwZl^_mt^OfUepHd^?1BtRHIE&~gJYhT}BWC$Y(*%53 zrDTe9-drKY($nSYP^IuAJ?4&IAG2?XyfNhD>trg;uXL0n4uavSq&zFc8;T$HPt;44 zf|@2w+>vlqDx7Byh7%g};HqF1Y8GAaK52H7ijErMUSYlYbt$#CbZ7nbhP4ekR z&ca9I&E->WxT6w0I;YIbSjj2KxF^v5flg$(qslN*Zw|_ao3J4|6=l!joC9R_Lw(%tXqcX37Qao?@Ib)!%R4aeEz4Lu#;-9~ z>3^ZKeylV80am-5VF`Z6SvRKRt4O7cji|1Q3;1Mwh%s>n_7jk5(`1BhZ0Br_n6O`@ z!nvD#m0$b}^QR=YUv40}8?cTgN7x}cgIevCeTRVoq$6&&6Fo9;4oScVHjK}Uuu%kQ zzZ@=*2Y_ZUJJI*n!ZUV3bNZrq?f0XGKv))CzACaf?)AJyR=+ZKQiRYhKxh{sv@0Oc z&I@nv8ulZLNY9T00E;ZBjyDPF5X(-rWI<5MT5C&54a)pQGVuhjx--^$*U<3BHhkiF z#&k^?fzi|uzAW3j#j5ZTV7c%B9ww5vY%-JhIuz*j z;9L^^j!f2?FZ;gg9Uyz+F)%=fxuUc|DWW9e$clTS!9C<-(~h&LhJxf4$;b0)FJ0^7 z{3uML00h76L=V2nIVvnyMRIvYcp9&={tOc&o2@ATp(d(A3++K&?eEc)Q;iu+=7jCa z-F$Yie~8=pwt%n4QESt9YL=msXs&>rPDkBD#&M39zoJ#CR)Gs=QF8T2!I-;_Yu{sq zv7N-JUuOKD3xi&Mp@qUVR9qn5ZeM0Ry7~$O(v|uJ2MjGzU*lhPT)5-QhsGk9gD*3_ zD-RT=08eeZj^me^gBBwS!(%l(zO}yC`Bj2O@c82Rq^|tZ!=t=XIfEGeHNMO&SpF%D zE;3NrnCgl3X+yWeL$|AkZhwZMjhIy!-VrU9p2Ry5I(8|&70UN2U8za)#FuyFmFWo- zoPOi6C+P9FVNs9r_p1SxxZ|~`$6a`RwV=4?iDe@2`IBIW7F)csC9rHHX-cE(u2 z!bGT#OhF4UMUlZSDD}XXF-qn}`Y%@;OjICUP!LwrsTFC6=2t~_=vm5Z!TeGnDt9_+ zX|DSzRv*v$*T$2QsO^H%VZhfv2$Z0Ydv+$jzJ;dmnj~f_i9FibiQF#&H31nh7L3PE zn_G7@n9g@QcGYt8`y?4u96Bt@#jupmM{Vmy}Oen_ppAwd!dm4A51b|@z zk)LYL4m{y6ZE|&g;bih^8Y0H-$)Kq4Pfh*}Gk0YV!J4!5;PYP!^hT(B6u2`J{_!U5 z{cuFj_8)4FlpbN;-_;*~EI#jCI5r9uM%d58Ie?Ppm(tM=Zld`p!{pqwuajKz`dn?|1 zIQnoaSRQ8i5EV!ri*4?}uRTf~v-80n`ZiEUkS5G^F8#SXZC49L`DDe6Yhiw{+5!eX z&wABLXzir+fGs;mg-Z3R!arH_E4Hv#v;+=_N+@(!7Ed=7&C$C^Fd52Dq{|d}6LIJW zoBl`#qRDbW=yJI)F7aHR4X{27|I*=Pw9yBe+HJG>0fxV=%db0k#;`Z*C2&a9R{1GW zXZ%yeRoMyT{k7F*Z;Z+rte8VikW^j6!w8k}MV4yN%uwB16A!AMawXx`8(%k@F8_GAhG)8O)|3{a#+G;@r(A*zx z5ia~AwlG&Yhs|B?&du)4-OH3?_@Om)h>Xk6}<{=yDzhA5jf|g}@s>4vaCqM0< z>`Jc6&uU6O!J;jm#p!T7zMM~VDqC?Kw!JB-muoP7l}_Q9k#TfwzyMCMk=OGHcWhO5 zJWqzhLeJ;)rDHcfnW96g@>Z&xFt*%N-?;|l|4{yy85QH1-Gn_z|LR(kjfvYf`~Af= zA5&gIJ?eE!8ns+Qu-B?Bt=gVl*KM^Stu|b%t=DQ(T5Y-(Sag%^o?*Cj7cVTMGkLZ* z9(op6a;YYt0gSlFW`yeQB=dT{%CMh>pjSmBHif5PUNN^TYELi7(EF&eJBLRE`@g3C zZHqR#*Z(!@DnZ1w{mV;iXCc2^gNEpqx%yv?R>ALvHsmnLXRg)1(D@MC zU^i=FPX-(Vu&67w!@kzOkr8rH$8{ucYXc9*99~AD0F&_`F>W2Ej%2FInV~3y7?L@{ zvkvS_v3qO3WnsGL0N_DUM@vCz2Tt99T#coufew^=-fHCJ9c>n-djOyfm*Rnzap=JI zJySz_XQcZ+(D)5DbkL377;1uC=SZCZ_t;=VK02H0et$b2!96nk1JnNIW?8@2CHq3t?=axYLpUs!RcX!5##uBw?9G?AaP@>$WGK@7l zt>NQXF5FNCrh_?6I<6BfvTUj1xab8vtSiDs#Fd8{#sXjrTX&;dgdFgZlG zDn(3KKLP75ScOzkYE`0AUBlw~G#J*!Ig%7SPRJ$8p#l$A7{)}=nySRA22!Y6!}{i7 zaw(xp8K&@?B)x2gDN@sG^s>rk0Vi&a10#>yKHM*o>ud<}f+|6R1$@L8O8GR}F3nyo zI9^Q&O}#!k;X+-<@!syMg7@yD$Aw8;W31K{=0dygn15-(kiYJ~4i34!RUGm+Vld*d zp(Q4d_+CuufAtf8ltoY`*$u&O|FNh zCh$(jFi_FIInJgPbGmLdgz%Q6E_Vvv++frY?T2T;F0bm&ZCE#vuGc4SuO$?)cl5%W zjyp}5P2f~iPDajzRS90o9>PyBL6fR@(P?n!W#$^BNro+4?dGvcF)@%Tekxo4?84;V z=UG*vCU79V34)LqnpuEM)Dcx4{CrlIIGa8m-0{B)GLXud=-QF@Ik&;t=y_sNa5JSM zYpJ3fN?w_#lCshg8}Y(B&qifud;bj(=l)X~(mPyQ0`XU1oo)VWm@kz?W%cX~J%>ln zvFsf@OH2_{ljs>6H_{P02lUyLS0as^lbV;xkm?Gj9gfeUy#1$BjN!nvC0O!xm<{mi zexKzOo3A0M!cJ6lkOt?}pITP1B#?urxyq}{b4_z8Tc@C<*TCR8^mqtxvz%q|Y@#!> z1asQ|$1nR>)^YcEUuR{aM3s>|9Dkdm5tH!c^`=5lOm$+CCr=*yyBILDc2LG~L+C-7sK%JwjFw!Kt8&gqVW^w&j485Q%hgaM!b=!>1k+x6KrfRY;Lr`2Y^lpWpV*&TB|w ztM9&|V?@;UL5rLvC31aJ(WQ zE<;bvOQMwORO)uwekODa`)w~hULktQ8TK}aDpmeG)`@I5NlmN+R|SKrK4ff_zb(U@ z5KdLK;VO*y-OCCI-vx#)|4S%cvQw~XZk_7(h5kx3z{v-#Dr@ zYL)RT)bGPIB$N4cGRAC2PUS!wj#EL9Ro+r-mLB}LUVhtAwim8m*wg@+Tg9CS$YIA> zmC9VYV0CCX_b^{pHL!BuswxvYyB0nQ?=NF_D4>i)Lss!CYr0>%+`rk58EOeDOB zkQb@$(`qf%sqJ>!TBein+|(W08`T}deo6Icqhyv2Q3O46pu6%KAPW(F`BAKjme0j% z6GW#@=Lfn6e}pj|&>JoPpe)*HarBBgM-T8iHm1e>IY+^zG00}@j1#BRDcr2irla9d z`HB^Nj#ft*@Z_fHUZDe#e2;fMV${ ziT7|KJjfmh`vWYX*1{CFYL*2znJG>}MsPOdzQeU?I2V+Sp&~-zYYT14hvPFKZovY@ zwi|Q-j~EXZW>++UgqL+TY*X7w>*(dx!uglZCdN}7HUY95M!Y-w6 z?z+6TD>Zur*sOePpR4h)? z^eN+Z#R-}|Nj1$`N*5wJieU?ooT%Vql>nerw_#V_)47weP)Lcg!EX<3A1>Qe=RSs0 z8G68a*>deV_I^rVJC!eHLTH9&;J!gCix7T}SNPFL5&{gyBP?3X^(QG?r7lwW_c29Y zQ1UoRC8^T#+JI`NW@RT@ROT|c@}&wY(iti{3?Y0}6nwlB{$LF>atM#s6dcXrB5Ly* zyV>S|-b$|XvTmF&4sOVeMOV4b%!bL>LPwF)y~I>KqT*5)IFe$?PH$Gl>+FtRRxTxW116 zZ9UxDwEwFx^8Ll- zRdSvu?;p0W&)-kJznTvJj_nrx{@?U-$Nk5vdyqG$`CZ1q4c;!>|JL@y_IAtL|BcOc z*#Gq}wP^eEzkL7EaQ5oyUmAy5FCFD+eQQuzS&5O&{Ra4AgEX*F7Vvf z9u4(~g`s-%=4WGbtNM!Uj4hCR73j}{%3CvH}LKmhP&1y`bRx_ zj_st+Fzb)dhZ*JN_h|Y208c1s{=D^SI!0}9_FfH9VkgC)$YR^+D1M==rDU8V4udm- z|EMIAV#}mPN=Sz$Dq?D2{X7t*q>&tWui=|F!mFf!xVDe(nd+hLPr=NvRshYVGHn3x zSNykQt`hq*2;vA@zGZ;7I!(i^q-jucDJ4fRrPU}(NUt-hUB?$$J-Utu<9c*Mf4_mh zuR19kW;YY`Zu?bKi8Trxi~K)PDouptb=5N9pT$HWU ziD0Jg-kP7cssNq0O2BYkKTa7pn@FJ;xrSWbkmI z)!H5(>unb?m0+%tB(ECNEyZ5G4sOuFYE$sv3W%Wq4t6pw2X4Ov?d0+m!|b8M5unRX zgI+#>enGt-cC^RMn_&RHgjR(%8OV;ZK<9D?=xp-l4!!FcFCz*$>IJHoDL6FgG{Pgc zpphc;1DR&do~k(^)95sp$EV{P% zODSRFj?sK|;&_~Mkyp9Z>M7_!aV$XHDIjx5m7)lks$TCgvgmX^1&jl}hgi@=~brE%E5pavKTNfVJ2+9EP;EwGvXW?DPpgf0n?1M#xJd#&g zy#kWqc!DJ=O3%5i61h8-7S%nt|P6xml3nDn`f1AlXn9CNfc#-Jz-( zCw{1Ep@jZm8xTGp27fq3x%6Q?9bZ-bj11{2Lto|4K9BqKDhLlS8DDMj4;4&{6=)4Q zyI-7jy-0^AIM6cp+YN&XV8{l+Gjg%XRQua(W8?f@wTr9iAO* zqf#1B4Bo=6A*c1m0G@+`FCjcuXef%?F`jf5UqMCsOdU-~>Gl`*3+~)_zR|9hH^t>+ zJ}SM=sf9X1F%^mnT;*7N15-Fz8e6H~#|lR(cS`?M*p^*renly>#NC_v;!~LQ=9Gg# zDQy{{=+5~ztnkGQX9dlTZ<-2YeM!T$9YW2V0&etDX9nd=r{UX9W3kqY?6MfMRUcUO}B-FD^BdoeBFO!pB zk4i^hr~nRRl=75)YPfPQx&Q=66BveIyVMmR6x4(v7`}&H0ZLGdco+1^)?4~4eW=xG zh9jtct*x#GyBD=$MWo{gxxhJ<=rd+D2mIq;H$9~qxSyfU4s=(V7^jnX7{cEPd+ciH zN6C2DSzv|;;HZ**JrCAGXGi;@07$22uXkVUmyxWilUc+A@l(*ys7}?csRcN`3MUN4 zb5sp&*b-1Yx7F~PmRL{KS{ARPY7L9$AL{K9-O}c%0Qvb!AvKXI$J5f&7uFdCK~|M& zUo=2bv$Vtze(CQ;gV;)-SnBQa|Fie!+ie`l;vnq5{S;;PH!>gr;G)e9nYxFPD4ECFu1L8T z{d5aOph#8|KtU*gizS{j4>3vUU0Rc2&nWMpJyWGs=r+SH+a zLcf|fZ_~H$p~vJ_>!U)|u@q}o%~!jx(wBP&yYF^hE~qbbZeHz!H^1(_UZ$>^Zn zgj$eD$>ITczxg0skAwwT9QM3$Dbnc4Qm@`eFhTk~S?cxfi<+Kl1(H8a>HD9;H4QDG ztVND5$j54GXw9HiOFGX)@e=4Hic$4_v=xa4$`;f!^ow3&3t9>^6K}&K5p1QFLM-j1 z+0r7qif9b2h6Nb>|6=@v6^brA31_ALMY|QQU9S_Bpx(WIz2YeARi`1iOODpiu&RMR zf4=v6H{E|98DmK8suuUo!QOAXD4o1|e*k~KiL5_IC+k#y`R2{9@88ze)Vf-yuJq6g z*JdrQtnza2^}}#EQ>iOUKiR|b>AN?7sjZ_my-r2xiV;~&S_iDw(wk>H@AeLUiS&{6 z!ir74`OAI3+?D@oS!G`A)Vm?tr2TIrf@Y!K)dka+J2CE~6uw63CxEfYmcu$=Rrbm5 z!A`iK&1mz1u1iu(T$Cw* zu6%P?5r|yUEX5#~I?u)=o1G-v$(oGkQmy}z4a=?HWX|kg^UF?E4%dR(bg!tHM9DA~ zGd%S;JR3(v<@6kA?eg2Ng#JhfEQX?@u8bzLsb?_vi=9^r4LXOYZ>8{RDv`6gX;9_R z|Kk|WtaWMJupFnB3P;LUosd>MZDCHv(QtKWNFP3xz@SPa(Sp#O*8nxPl3LJ4x%vj2 zFoiyjS{Nm8%z^C2zR8q2rSM+MkYqwXk&KH2wdgiqs|?0obCH>FTCua|E*gq8$;%E$ zRJ!(n>M6@>CYTR+?=`Tmy=QD{O_q|-Z6umX#AM}|gSdb|>X{XzJQ2$zoG}=Lo`bzt zAalIieZKcsyp6-G0T)O4qwnoe&~i+w(_%8wsp|XXDa@K zWROpWx zj@5`@UxOVgfEXx{LIF5+{Z(Ozb{35s^g7?zkVz`*cF>ye(Sy=*wl~dT~Rr8p;&2De|v;8}miz_e$tC0S6)%-6T z8{#^0+jYt5c3~{(*{MAg6L)q$qEk~>%$lV@L1S0rQ3c9)+ml-oN34DnM>J|mhsFH3 z8KEnaTL-d?seE+XavjhO3D;`)K2JK(j*|7wsSte=TaJ-5@N2S>*;}Fnu5$)b`aGfK z`qRZ#%V<>oh40rq=<)PpS1VyUv@_l)uHSM4e;lUeUj4`5TK)Ovw85D1(m(yCSvYL^ z%)`Z+$8!?qBmFebhK6Yji3t2H#M|Yb;07=Bn0!1pmf|_QfSn+S##|u{@q|;_WIj=e zG?Q5MYmy?$UCbD+FZqF|u#pbRGz2gVYw75J1u&g52n}5@BORgW0GQ(wcE|VkXRwudy2GUwIj3uThoZ0f7 zWOk-F%RHbMM^p&F`*6M8il)c`xOcb28kkV}cnUgsnx- zvXlX3t>h4vLMs^ns1LW{=WY0X8(!QVe00N_8c_YI{z}-o9*yUV$g4Oj(?e;3)BXAG z)??SC%FB*eOIl1&$rId{H}FuMjp3{e=pPh9`zDnc>@)I6L8G`6f+9FsFy%xr9N$DP z72GXo-`}hw+{J_;W24HhZ)2Hm7ky<@na8Bz@7M;T67M^B4cqY6LZBe#a~N};u8xo~ z{8CznD-tob=N0^Ca*|OP{?RC#UUrj{@;n)#pKLZbLmyW|2}r>=DBzR~FhYA8Xd`|M$86^(v~-_>P|@3clwIF$U&Z37%SnRdkN;lPoAMiE z8;phDu%o0mJCr3##BH`9IrLoz?e%;lGl^C;5Krr&{94x;CivP;?2XTAAc!?p2jLAC zSp;HnM+nRkoiUc^GT;u%mo*T**bw2W4v+C|e7lI1H_Jd@6E%1YYPefA#D80`oj9zPc|| z4gk}!Pc)z-ns$9pDvzmiK<(tPEQiLOEMB%kqd8@N(n5lg?eh`d(!G3x(OEK76Vfe? zNMf4J6rd^>AxH4mEt_IGFA6)NvcOa&3G!1=7F6!KRG7&OCz@kzeLen4#u#KWoS4b_<^cp6$6 zc1mFZj5WB{TideHm0bic`=$Bu6j?JZx`%08R1 zEij!k6l;-Ubf7?CQKU;)n|R=%Ma>x;r&BzkVl`F+O@{MI1gF-K5fvCz5wywjWtJ5~ zsazVDV@!_ON&b#0GL0`BIH?@r(P3axzc?bI@j}r*Nhs9PkaM5%h-P!j7Kme|9L4&E zT7`z<*2wz7I$gt-1U*8OJApq!@x;hdUwAYb=yx1YAEuXNeaS{mA56QMN6JFp3-SC~ zm^pp)U>d9CW&s~f(?LE&Yc;;~@CxLk!yL7H>Dj5W{_rm2AN$pW3Ke}mP~CwZ0;)b5 z4jINHr+L4hozjw_iJ`nFaI91bLeZ@Xj!ei98*eu^)?c=NYIc*OJe$p@IzAUHydz4w zr$kGP2b##%+vT*4MAu68-|b_P>*IVnnNr{)X&|LQ8H*aAp5^v1v`Zb-p4oX~}e`Ef&SDd@7gU#w_6iWhX;{q0wd z=o>re#?OLwYdQsL!d^jqZvwMQ^Weda9v?Z^pgS~+yU_t&+@p2F2YauUhyj`eLx2Ww z%Lkxt_%s!&z*cr|1Hp2%{vuw6^Q6STiwum>@0hw#dK}a%eXt}$!yzs>0b^k``&^+P zvL=)&5Y{%@DSUet3H8KA+-AEhQY0CQP1ulkp6s>Br(M`=^^Cf(mt>c)r06PFRqJW& zBzH6c^+;nSO`cxCfG8n%#cMHB7FovLlanS&=3jrzkre)D|)CD}Im1tsp?@Ns8hUo(Ahc zl2Ld+8`rigr=zwI^6`2*(Z)0%lA8qT!VOF1rcH2;8LlQWR|(J7h|?T54T|IkeL2Rp z023*YFlv!?Zu-0Kkwg!j1X}Xv@2y0l!bzpuq;)pTiUE2=D=>HtERN^pyn=2#Vs4nfR}57n80x^JsVxSzVCfzf?`Ml%0eK5 zC0)C|Jj`4l8Em8H(Ty+`^lMJ~)l!Yo+AXIj_PZ;VkMI3*I3JDiG89;S1@c-33!=~$ zUJ44`A7%;Wf2hW2gg#?71Y1Ux^!C$&a>(DtRYMD==p`a0gW3nIC2LqWF*E<~6rFJ~ z5LQKekXLPEvwiVDV_z=d(P%*$#vzapSu;ZLq*hZ-R9JV3!^Mft7Z=vcN)m!qC!j}A z{f+=Pb|Pubq*yN*l!%i%9)f*W9Ey)^?jO^oO;5( zN`^*sR8Tfym5HJ)($T=zF$xZYwjrh|07=qLF76@?jI!#KW7d<65-O|=Nmvk#xZt;| zZzk)>#XaLNuO#`bFjJYl%#Qr4X$uK0~cG9%qtX z|LFLKhEQgpGCMT*wPp_**E_Y0&i6tE9+JU?@>J@z{5@PjwxnNM?P}b&fH*kI=p3R9 z;^=Tx7&%as7Olfuw<(GVS2UhvGg(YI6#|dZ*sh3s)+6JK%+TuyuZAQ$MrV?lw5k+$ zn&OlL+bZsF=%UkusWoU{!5PUTBXbuL1~N3QL7x?E2`Cm!Rt#l&7Oi`k7_uhGVhU-q7?l6>{^M>JfHJE1GN5NE;wcm#AjZTZiL;jJ;4r@^`X~!bPKv%}6;BSPdHyP! z^w^d#k+QDhxx%ct!WGOq5F^>TV2o-GLzWUL&;Oas|9195%FWD+K)KJ_~mcWHn*1K}A5EiV<8Y+v(W+9NTGEByW z=TF>VF(;_p6Xc0d-R0os5l6xZ0qMB?WNcG||K0IGs^C1-pp|%k2pv7kl|c<71q~hJ zmcwj0t0qI*3@dz6LCbEKuy`(bYL<{r4JjSvj>|+OaMwnoiWZFA1xI69u1cvscd*5V zr4rwX#yxc%$=NX*g|VSG2iEFTD6wQS5zDb*dj(LDB>yRvi=GZPuREdK|M-5(!~{L7ahR)S-<{hzV~^Q8~`si#3JtIf#hmFtrv0f_(v z+D&eeFMlmEYF(oYzYdeY2p~anU7ZZy1{!sOPN`0rdY=w8Q02hJ+-gwf741W!FUe;d z;#F55?lTYaPZw96j_~y0dY_GVA#ab^lt&yx^qkig&=W5o6Dxuuu5AOO*qUO7^~Nw> z`EO>VLRYwNS#)VyuYq28@lmggb)|s+s73$3suo>Y zE4YN_?pgxB=%MMfAl^8lvQ$IRy%pZSg;KPIB%~I)n!y8!LPfcp{{BF$e=pPtho&-p5shOOc}DfMjc@_$ZytmNby ztoQ{M6^aCxDvnRk5>tUa&L-<*v?uL>^t~d@v7TO}l6ae=?1J0%ntWZ3$yf{Rw9Elr zw&h@;_4x$F+L}u_ER~89f?TaD@P~x$rDR@){7=yx$&{ z4x_G)KG`Z}Unr;z(_jm?b0T%#hyCXCFj_3UI? z&W}&DVvFxx(MB)8TqUBT%Wl=_EyhAG;opeqsq|NzihbqY@t6$naNa+~>mbn`iU?#R zH??Boq6H`WPl|pzgy%?X+TM-ZsPhY4HqVW@%uT(TZ&sy7%dLwrS3NlviieH9kp88L z>UTif9%+oY7c(-^PJj*jE%CR-UXuoPTGE$nsRVPhxz;C@3m%{R=-2hdM3Czx3aQc7 zm!-(I!6FozI{1acQ3tj1gcu{#}QYj`ey`Gj@#VdMJxP)YPxXt`*if z4kH-gxVE?-w|E)oky7=6mKRo8wl79_5xoY6Fb;k)qZZc{ z&>@P$6re*9hgS>*9_CLs!>Z&VAe=ugj0O>6IPy`16b@s7BKZbCiI~B`Zx@mGA~JCJ zn;Qx^Sjvg`t1!DnltdA^QFy*!iS}uJsW09@)b< zRTR^gUA+1CVv;b>6y?7LgKT2(ku;x98(-i*UlO{APvB2qEsUlP&quQcd~7D$kFk)g zWlizzd<;S-pc3ShA1v2GscH8yrX2xo1-$g+r+eATvO-}0YIe9FL5$@x*69VK%P5(3 zweVwvwoq^-RRS+447+(5q)ff(kV$2u*~zMuBnLABm#(a0oZS*SebYIE!C4WV%vwfk z7|Y4{b&ar1!MF`Zv?etzx|zmj!>!^^7grQ;O;j{X(YJt_KQb0aLm!IP6h;IFGyB1s z2z+yGTzJ9W6bfiW#$aosR;iw}B7MI0c=6gxj@NTK_!cyvniX@3t$PixG~WQL6&b*C zXo(E|juH7v;pnUJqkX}mD2ky2dbDw|wSj$E5?kSswE{y~0#nFv&Q4Qtqlys3HAH|- z$s2OMi?ErNeFLGw;#zNOIUh`!=*MFh*!5z~SzCZH5x@OP$48BR9*+Et3Kg_kayrrY z?A)=`O->wz@e1|p-NJRipqz1Tts~z_$euB`vKzxzR9ZA?HW(uus?)n`OrjBfR>xM9 z3(N@@Xf+lKkeYg>>VhEPOUXvtn^+hAQ8_n<-qyYlex*kF)-za9`CW z4u@s`wDRLJ`GiTSFAzDkko!| zqyZn>XoFzH?IZL=1G_GgA8Mo{$JW7$dFtTW8H%+#azqeAJ`#sN>-1kEG3iFHi7&ki z%CS(a;c`r&#zJwVshiq{V=1)x<2B8!Fpa@ts4fX#mqMg}CGT;DD`sr00eh6yXoY=6 z>nX$|5yfJ)y)4kkmIX$N%pp^UKrCJ_$~@uBfN$A^5i?#i#9SGRb?XW{s+RSQTn zfR>tht23r_3i$?=_$-t4p)TCE9V_TR%F>vjsAIOAqgljwkfEMmTjc*}( z`JAsg77N9ST9G26lUOK0 z7`vgut=bm<*NPRR64QhZXXu2_&7gN~H5+uh)OoaUoc@wuJkmJbsZO&|CTg*Nl!|4; zAtBo*`Gp9Kl~KSi;ELlmxv64o3I$16D=C~KvY~2&s&*NrqVI3I60~CX|50s07nc@Eh{BwId*^Ff8TidwUU`PN*V>9GFWmE~&@W^x} zl!`p8voh(ypS@&U99p4q1Qt^+7er!OhCY;px7ELjY*!(8UV1l$W09(a1#;7t^Uz*17p)RKN6+mpC+A8=dk`@?8Ab5 ziMtq(M^HK~gE@LEbw7)owJqCNq2*h9v|QhUmY=BR>XCv^EXIuQt_PPL7TqpqMd${z zBFKWd2-^UaId>F@Fth#3YL<^)fkf0o2OT3%vx*>Zp;0(2b^Wt((1j`Z7Fs_lj$82@ zRz9DX>i1Su1LNe$2Ekp(`hXQLf1knO^q+vkSqTCU;YVI6yvwsei?dDOpO~wHeo{&N zB>-F*Y;XT^j521?N0VY8rhLfW>wOwG$fIbAOP=ZL;S|XV5{K1O?xB?gjA=7b4kRGT z6;y_}GnZ@3%!pe^HaCU8s*I~}C%Km#Z^A!6CC6Lzj|>+MYx(Xb5YdbS#7S>`0Z7C( z;HwAg7|t7grJ^J3&+*wp;7wLX#zBGZ+ zal*)QCG+SklO-DldY1Qp_+ZgfV@-vsUE_kV?M=&3W8-3wr}GE*T;*nC&5FKhSK16# zIJFD?6o!f+{@pHYZr!~XEKNxP+|u_SJPgBDDFoaaf6fm3^))EzfRCA@jbJq=Oo~%4 zSVad(S*ElVCuP+N6e^{@(nlw$9;J;DnUh??Io?b!(v!lQvv5bK^sw|whe-xXUxr|B z#Y+cZ-*rdl<_xSI-WGJYzY*xgR%C>tg5Qy?$RMf0W~hb8I7Nj(3+_-=h0Dko!s|*_ z2()m&rb2KG4{9p}T6p+1)1|UML?-QSWPMoG{7&5sPn}sUH2AyW3AC#PS_@C3sur2d z2$Qs{1zHPFsaY*Jw(!K-)dH=Brq|lYjAVYijR~m}cdo`pr=ui;P}ac0%_uIR3i}MJ zFZVWZYXdQ$z~dSIc{{o1DCucb-Wz=4Hvz)P!rc*hYPBF7-D5>cZ`AiMvtL|`}l#{j<9+Lgq z7>WJC8%{)r?&qlQqN{ISTU?aeh!hHCW3PoOEBJ8b**$RRQYQ~SddVPa(gwRN4k<#L zPhqO?upc^Q2}lj+D5d=mBxPFm{N7<*9;NB1{@d=mz2|>}BmSE=&&7YA!s*4PbWZWj z5xddgZHrEHb{Qk+Ih5Fpl(1u-M+#aoz0>~5e0*A^)Q6h3Rp|4Y)>Y(lJUvFr@MXq! zaz8c#Qm<2J(@1AvXo_UmK+wXUMO$}Fyam44_;L!w@w8GK3Ufif4!WLcc!Rp*AoNbM z<>ge?%``M-?>JbDUFB#~O=Xw~9YHaEV;nw`>l{x ztJ_tn6Kx)I%TlInw2}>{z*}I&UG77Jk>C`FtG0rTI(ykjy1KvsE%lO7S=XSF9WyAf z5bsgmu!z0Maz^?kv6Wce?hX}bx=`JnS2baOFxoSSJKow$D)5T!WHEl{-osn&Mq`{?W5N?YpIf$Rdsm&$M$6(nK9e6{~7eY>;wE_4@Cn}#q76u)-4 zIA*up4CHOK66!fpz8^o&Ye`2GlOdYA-Lnyf(0lddVfwfCFGV0d8*n5#-_p?kviEE^ zt#3ld>027AtRe$xxCCk?AhMNUWTz%GMdH0}pElyN>k;f94H$a&sZV{g_VTp+Vt{n1i|zzOh#NcOpv&#J%d?mSE1zzW(u@EZtbtXrke zmT_U6dKj^J+|g2n!+rd0Uuxw!A033pf|42w_pZ+tykl;JJal~08fI^2g<7Vd z-WzJvWWhM6A%a;P+O)P-IGSl~l|=zem#G{IT)IrXNWjwiA<7t~v=xWrf0|Edqs2!@ z;#{;t;bVl*T&B1g5HrxW7u7OQ#tB#%C=m=dSy#>o5m{Hvj`SFs3@UB}Y79WLV=V>> zSQ=qc1b35+l;4(e0d{lS0~vdHh5nlF9R^^Ljf-W{on839PI7BK1kv0@cLly;BSEzf=Ry?0aoG;#b5M+ zdKtN#DGuj_3LG%w8H`paEboS`B9Q2@K530ppUjb&rIh z`m5PT`uk|CV{fIW`K7v};|WbU0acYs?m!ZHN_l%4P3Lw9b-ib&=xk%^oVQxZrlaWM zQw?8tp&8m~$GNf8#o=4cT^&@W4a@{sTUplH3Kt69+=bepTZwuQvhH20m}j?wYQrt9 zDr~IT9adHoc>HZPn~Q9HgvIj^l=i zSb-=IsBHMgsag-JGBxN%Z1OfyuRa*KxS@Us@n@M{AOU=Xo=}=DtuBrt#9uKBIwRU= zB{3bc(HjH60AN6$zwjl$MOMoHtA+%y=ry>>H2()0$)=RzPD}qHrQ?zeWz%LT%W()F zV=#sFU}XKx)p^BAt+^ayBeKXb)N5k_gK&M~rc++c@j2!FhP-UnIP;)(wBiuKJZbr0 z&0qRIpu>&Iv(qpm6=6g|0YLh%tu^Z@=Twpj?J)>~g3|XdEyBQ{&KL?t69w9zljZqc z-^}~<_LfLBdMA0cebsr?=ODCX4lZ?Y}-$je@#@3y?&D;0zhkm)W!N2cs z^1qu8;2&CUHZZXQ1!-(=C-xfVU}S-f^lmKR58tN4_-`kockrLPcdQ! zPMCo}S*z1t9dm#ODx$m`KE|0A^^@wPoDT;g*nHAc2IoE7jvd)8x2(f7pdv4VcL(b1H@WIcCqO+uO{V~@_jOj**%Ut`?Qe|IY^<# z$3`x!Om5C5j%#7moFRbQ=^*esSkJ+;Ym>Vwy50JoNpA@2oRmVJH#m0|WzwZE_IEc! zm=P=KkHCyEz!)}KA#>I6KwY~xf4J!Ta{G1qeDANj&v2xF4vzoN|H9+{NsS-t*N7nn zh-+d?(PnUbYl`P8R&1xJmtfUs+MiFWa_S2r%GPc>Xf|hT*fRI98zDk&w6Mvl#mS%6 zt~(AXOmU~v0Ti5tMW~f~ABY#qCQ{D!!{SAJ%q%dHaN*6kBO%*@M17#uHAfs?n~#+{ zyeOKJPjK=X{xyOdel4o;7E|4y2?z8WLOI`NvL)Idhv#T~(0>|=QJE)l+YpA2hUNJU zp;#Ij_p8pdoUsK*rBwod{-coo?#)5^_RZewgMHrj$9WDt*!nYZ=&wQi&En`{ll9yh zMGqeQQ7HQBCSd3b3tl_8SB~69N5+) z$Y2~)Qi~bD+4+kZfIyth48tiAgar<0<2>1W4Vc?|#u=uM$|0)vRTgKVIl!FkmP@pv zlnJ1pLp5MBV3oM)ko=J+=uIthQ7KrI9?FDuXk;eZ>?CjI)1-HjU-V=kh+%#-Yfmzm z&vGzmi|{xY2trsVS;uTr34rVXhcrASVe+UnovorvR1}y2 zO03y(u^bMmQ^XIcNec?IqKrH)8?{`Wn_ua}#>YUQgm9Hxvd(6w^O4$-2lcEHa=51# znr7!Ij^2z2g26y)yGfRn6hcGPEsi9hWy6Jh7UdU)3lZgXp@`l?gb*^u!EYoYTQJ+7 zb*HbIYm1mkrCG@>rx}-bs2fw1qVT>Is7!Ga(KGbB&naT}X9wC&0m(or7ll5EZB67!aE zG9UL*2P3jv%I=kvyDZo(;7fZmsRHY9A9^y9#HG-hvHFr!L97~U;`v=-=1yWLbCw)t z1CcKP5c0_a$Q!I`FyU%uvw|&e#D=AneqqHb<}L(qCX3&=xR-C3Fd9PdfYQ{~y`Shb z1Vx%(KVF35kJs}O1jgIJCd*;9N+`oJ8yUqJsTMzEtzkB!Y!|yikZasK-|GQ-4 zn~d0b=Ez`@LI_%hRfZ zb)0&XN_AKqQeI#omts;j;PCmROS&f%2qzilI2~ff*vmHNlO5*+f+UqwEpc!_fvuJN z`u7(t>V~=sJIXLD5T%x76C@ejO!T=b37qr}sc?t6gs$~r3m^l(&iCKj>Fq?#NABy( z`S6id7DH-r*>3mtqkjulwc`4RA>aJ^zkBz-yZ#?;J^0W1|0AAd*T1{U$yU39bKn_e zM(%0LG#L-BN4AXP@?0~61I+vm3uF$9vM^-ctm4$mL}Tr$805f4M!AUXRl=&0?Uk79 z3Jod|94y#l5LAtBRTDUvBIr?uS;zm`$o)5XmRp3PZ#=mF zU}F>4|Hi$0-zE2Ne6)e*fBE`fdH$~<0oL;W&8@A6_copR2Ljmo5C8uoo@M#}{z-CwmYN`$OdWAjIL$0M$rr zWNDK`tWMHb!ohj9Y9;3<#gO-u zUMSi_j{!f+@Xx~n{B<@*p$Cs zZ1G<%AZAt2v0*tr#o>%EF@f}OJ{se{_QZ+GBEs%xE5vRqc@J+7rkBsBbWbfdR?z7igI$qiQgoAm7HfFT!2%Py5 z^VxO2$2F30)Clb7KElQ@G;b!@_n&duK5kL4GxH6+vJ05Mn$-8CeS;6ei!A)}Y2VLiNv1=*1*526OiCm_`1U=SB;HPX{YnJ>s2a^4hJxxLB8KHLF1{z^ z2r$^09?wym_w)0|k9$c2^`Klof%@nvnI2xIz*m7a0RQWuAqhKB_L^op%2Cp6iC%WQ zRug6=Lt7`S-7<66tC~I5&-RXUw35Z;i0zo5$j``j2*M&Q`iNc^0dJv3F}NTo-wSOg z8>x_*P(=jB9YpL&aE7n?)8a6%40Am=S(G%ru^E&c8eU}6Drc{oUY9#R!E3e?^1wlb zL?Xg{w36!6JkNj6wRbnX>vTF?i#)gu0PLDh0E|^d;g0bZ@Wmz-V^R>ac1V%4DZhLe zkg4;Xa2y)bsMf2bTWB!=O(|-VzLRX4OIQrX&PgBcjU+F>3zz&4l~O7ia@ye!7shuZ zwF#%qh{sjAw0{D7YkxMM=IgKaUcB2m*n9K3Ga@ASPsKrb1S|*TtMhVt zDkvPbdmv@l=1^?Hbx{HT7-g&p;|!8R5KBmc$_cg84q0|{A2!=}lk=Rej1d~%;D{XdI1{LH`Ug7wpff!B^QuF`AELUzzel zya`!NePgtnk>j&7D2*4fWM${Ws1bXr2ZlpsC4%W`hUfut!Z+dI3Do0ImlW%(@08kr zYeu(#rw8HMp%!X@Tg-PMSQS0NgUI3Dh{i9I*&KKZh)0dS5W<13sV~i*2bNiPDi((b zlrK^Y6nD3p26p#kTKm;oQC75z+HnT#3MbyU_sLdU>^s~MbS|Jknq-6nTSanPY(@&q z?W9q3@{WR{_J6u*(B&A!jD;K!NfL@n3G8(PGyHB6TW)GFAPwPxMXb4#3_y)bExxM- zPs|BOZ;XP`WY$%_=^KhFevQ;>at0y7o% zKD;qivyM!~(7>H$nxAuCBIOI8RG1qIPRVC{+JB@Vv7-ek35>)@xK}~HHZC@M`Y125 zK2&*>*@oTEH}hOjf<9sraxxSEE#I_dE1q~G#1&6e zQ9wxIXm*mnoB+mpM>(eHA+e*4*0Jv(@<0z?IrZQKb#LZY2#o%8eO(| zzFDL>E3%}A#)XI-`pmLU5AV|S6Y(QxHH7FD>e!&T*k2Tcd8*OeWXwH8gt^iY_?*2tu=#Pypw! z<(?$jWRmmQgO^2iE?5~zXRttav%a20Zj-Jb>2C-|9 zMjeg;1wd~zEg)CIcuU(p3TmaRAdPHgT9uOOag+}V90ubZ);o?K7)lTm8p=`_;ftnX z2E4V>CS5ENYf!8ZL|O%uCB4(%DX<%niN7=1K@4O2s$svwS$Ys9l=qX)p+Ts2bjpyp z@>JyvT@9!i3?c+qbQ;eilL#KT7JkSI>J`C+$p3WtA5LKz)9Zkwir&TKM0F78h_r z_I`WXu4b2<_zI8AmCT7HMx9XP%L%3?bs21VGV zy%YcyVwbGulSw(9nFLPpdbEu89)yz*L9HT2ZMjV0h}`=KdVkF`*W19RxHQ}dB_;tuPQv$y^Z8&pCqgN^q`B$fpnix00 zhN;p}CG|@uu2V=wp=t%bhTDuNAHsm-_h=MEr{BSlg^prDRj}U25oG8PthQ>RAiC-S ztKOnu(uNYisuu~Z=pOJ@9s5HEZw?zGYR;!G$)^sT?;Fjg&d(BwwdsR)KdlZteE7G< z>waD)&Y1!bOnn`l;^0EJIuj@niE!yu#B&3G2sLcU?txgJrsNvS{)yXL3(z&&x( zhoQfQ!MLKNOMl`+xN<;1)EvwG76#$Se5$(j-Ut!q?Kn?KH$DXMvwtb|?n2$39iz4V zEM|8Q+G>=GpQvjDTt{00H&e8~VNjN6H3|u?Vdk%=J%#U(MTQi+k|tPEHM)tH@P-1d zKdj0g&4?vk%}3p?kl3A!+;?=%aCQ{+xi$?8m9ly9O}4GrbgY2ls~Srnj+*%WVcWr( zfMyd&j1@py zr(37%Oa|pSPC%ZGa4sx;XO9$~)<|5%C;8h74=+@K3SF~uiInaPS}CY>q#^w-Tlv(@ ztRWCAJ+($1J-1c~kvb|g@mfQ;hD&FS7cgZ&q_oi7Wu12o%>vBY>ma==u zXZ=p|QIcN}GAfM?1%sPl?X6JxxEkIN&Yb10_g6wy2vdxQb`W&}F<0Nj%!y6aWU@MG z`O$cmiA?RSM3_&u2=!#u(j*^rG+f)*|4H%HyVQ8}No-zwdz!q!6OlE#H` zFFDOG*$Olg1@4bB0SMmw7i8vb9N%KwX?lY8#XOe zCy@iQ2q5h>;pB#B8QKbAF`y8N9708#@rl;W^(toF(1pGYPZZ9iV9n+PFR&w^c7)lg zX-S~S%~vWrV_9C;E5!XpgG&N8aI7z&Yf{-Usq#^!6%3=6>}dzBTG1vFt&NB08PGgO zy}=3Zz1Y-opK)){JI7((&*l~L=ig7$YBm@ahe?lPdx|?Hbd1aOtzAza1Sc5TO=>iU0 zscIlES>@dpI`9Fe?`WGUX+b#J;0^EjdhbeUSlORX)$GMCt)!|~#0#zX{Aq$00-VzF z>TPa@l$j+ML1D;)q*^(-ox_KasYNo%d{Y@kML3i$ZyDwyYX|PR+a7FQa4Py3^#}F} zLm zr&HZxwMK2p1I^u-;;r`@zoWf=EBQS|3vT=u)fPaENss@;+arx)Odryd<`}}C7f$vK zadkQdwudjNUp>n%ae3uVVgdvz$+yP%jA106jqWHU@yw1 zK)a??k~Dhl@jSh3Tr_)4-Jfwe!{8psRF89QCk#^e@N!&^3h1Z7DtjkbJ+yqC(VIL; zwM9{3MU;t#phrnoKaw*zrS@O}16W>D3IH64#4zCzCY5c>n{bS!clX}5(V3&o0dUN5 zPxE8sQX!V(rXBKRMoM`rIx)!ca6f4C`9Yj5$(v$SRE(Zq?lyJIDC(y^O49XZ&!E>{ zLZ{1WQVfTc*@B!-4rn{mc0Rq(As180-==_-`ox@5fE7HGPNgmeI-8Tglo?EVgg#h3 zbN`v<(xyyq3I6?hBXD;rTZdXX&ySLxJ|%LXw-3d~o|G`N z*`hgW*ymK7wWgdlyf6l|+k2-jt4s!HCRqh>`!EO0=C^66gi#D&Be1HKBDlDFsAJOy zUv)h#;yg(G1T`@d$4yPP3Kr2S+gkTLTQp@dCC%|{eaFGjw`(|HvrM!* zg$2dSSW&XJmk9! zcHdmro|`97dngTSg&QYG6KGIM9-BcWjCrk&=nGt|_$Wv?w?d)*a6|6cR zaaaen?)e^{H76#lhM4nimkfd$PVbtXS$3K?9579GKLKnV&Sx&VOp%thPK<*!I74}U zfQM)d1lck4A0n0>qixhl_KsYLv-48g&EYBmh7bQe&Rd2G2dO<0hKmtnM@l41q^cOQ zra%NXMoaHuj<(!ca-2IBWcV3&b4*-3U#$A%fBF3ENZMF$g{x%7dT zjU%>Ycv7;dhmG)vPAp2q$;VAM8BECG#&Q3;`iV&@VN(QgVwas~Uz z*giy#^r26BS?WY1YF9P^x)f0W6Dj@Y`bma0e6Y`=^8pD1uC31kjdIEqSaipH&G_? z7AY#1h^3Ztg&dz~P%>?!OVcbL^E|iZVHJ-97-59$#eoumoCm`0SpX8`gmV8X3^fW!aGVm~Ng3ysrm^LWUCnfv=j(-S~3-UHuRUgw`D&_e?L86#h zG|O2AEt(S2Ia*w!i`6%oS4UBSb{Kh^H4aHo*;B<<4-s%!KV&(-kzb9_J1F;iTe>So zxbpkcvZ~arvf+Q$=ubAcv_}#-_|nlX`K6qW?fu^Hp0B9lJ#m&!7K<=E>)DSAsFdWOHaldildz=&;?p9!!o;TG zFFA&^(N_s7!Y*=$Lfmx50JCR$gzw1p&j)ch1_pE*z{eaVlL<`gn`WrBIfS-xrdi?C zc-`#TcOD9>xSpd-yM(oKD%=qW;TR$S7LSk)h3QQTUFns~60`45W#0h^2&KcJX*_W_FNQO8yRiC!-=r+8`UE%$1YU3xrX!&n zw;V0==Az}_MpzXC8u^x`ByTwyZ@gmy@zv&Ei0W4|f>WQM(J~OD5>b$31Sp~1v1JoM z26PNaviYnWq2d>>?dmpcNhGXERccD)Uk$?p2G^K$d9~19VMqz&FMcWZTqlku#a*EZAWRSMF;`wcHu_=mdS2Q~`As7Irk*hB$10uxnYj#F!MyschdO z$DmM5kKbc3jIWFOVO&7RJ7eBbFMt>AlYMg?gJNA-2cXzj+9s5U!UwIguBC6$#`D%u zUR}b4Y$2*HUg!ufPhmkvx>WAHwJOkOz2TZipbxj;-Z7&Hi?fh@M8Gb>wuqo*ETgf_ zI6R5l72xe-()36{54XqN-(Jaj@Ex;Tw2N^u#S)eL~Cl6*@Lv*2JCO#(*RsE;d*eHyYu?{GR=lKvfHR_if^@TE~FP2i%=OV>ZmPv zZD-l)e<(iM3kZ!?m$NK_>4)FlF1n7U{cMt9&^sSJex@J^mofqZl$w1+SH?~LmWVlS(Bl+K_ho>Z(NRi z7f{k7^0oKL`WC}`uG^w=<%qT!w#6_f&11XD^g{4lXB*d-Ye8=1IVr8guxwrCo#gh) zTq-@w`z{i!0|fe)QG-gOi<+w$ESJlfOeJDvShvibg{<{U9$}Jko9lKf7HOyt9LWeBosS zqnD}-m*&Om?;_Y7ZSo0)#HrQ-gDkC)eRm4LYj>>iHD3MaZWB)8@u!_nP!P@u)FCxt_3D`}8B3Ol2aD+(-KAB%KC z#vKFy>&1c6L7-&bSZg!;@L9BW^%1MDH3MkG2FA3RaB73EXaeg8+wg{JPu)uD!KFP; z9F}l1vnL?(1da^etNmu8(}-G<(GvLOHa>jTZ2@l0Z7w>GQky6hUg5naI{1Z1aF9V8 zi^M^2*z(~bfw9M{;IkBF81{$H)SIi1H5=7c_*3L{Ot**+BKvnh^Y7Q4PJ>NHXOrm( zTcJO~oxEoI1bI;>A_RV&#T)hZg5lYl#LcWz+F`_Lo%)T9@hVUQ`HNV^quY|qBYL8zvRo+jUv$xnP!# z4K2L|jk**D1*@<*m)*snvy@Qv8sXBu=l_1sAlK2#2~B@;3e&^bF^rzR&Kr&te+5d} z8=a1kp+nl|MB;w?-dBGqD3#c9R=nECu46lDL}Tl|r6>%8{^PdWOeh=!OE) ze{4QVWKO7)(u%003BU6FC`AG*@(q^0XVMl=0TDJVM*JjcYD#7;Au{V(1n&o0a{FOL zTC&JfhI@?%U~*vz%aC#K((g;cifOc$Z&3A+t=OF;utw?y8H!t^BJYT-J5S5WCFb6t zFg$NDHBC0${nSc!KiT1UP*|bh8HNIZmbx$)MN1kC%Y;V$wrj97fNa&)(Iz}xi%key zU)|;3s3pUdQ=9Z*HjHx0&T!(c5}C+}_P~dAPyvBI(upG_7-_yumllUPMG;ZK$vGpX zG<2MB^y(5lea?$2_c_syj%zNA4Mltg%9YlaZkC+1a|-NcZ^p5j7~*AB&-8Q&?887K^?WG-B(2w(dVj+R5u4TKeM(x=p#9tJ!V5oyEM+ zWA;iViBu$i%g>6^;AptJlFQIAE6|p|nxjLpnDui+cXpJk$U4O=S)+i>WY>jW%Gp%I z!qMP14JhbwI_p_O{B9*|7t2w`*~Xt-rC|mxxitj_JvAvk3GffY;j0?q?u(9xMO6^; zI14DT(0)Ik&{)^Vn^7ZaNRc)aE?aEH&#vT@_nP3d+pYviX55Si?5WB9*6-V$&j@zXiJ&Z5%)*)??WS4 z9ikh$+(1Yz*l}N@F?Iu%#XpeJxdC>y$36>*MrWpN-1z=6n!DMu$Wh`~wR0uG>|3AI~DUSx5t-6cK`0Qbfc+ z3YcbBMiU!hd?=Fb*t{?VORauQ=(x&?F`V*f@Bx}9YVRaFA$SUvc4k{`J1HA{l=Nzz(s9`^9HD1dT{XRe=c9GY z{|ReohyuuG4RH#y*5nY8YC2mKP(@9U$~nB|!3!uethtJ)j`5LntXE~HLzFxpPtk!2 zS=tXF0bYea;KL2kp1Wk_H{n%5oXfD2=ShNvIN)-PcnSfz&NiA(^O*VfXOodU4))|J z=Bb*Zi0iOHkycT$47nDGc2x&SzM@*)#B40oVIQMZ5g25!?;MSIL8lcFm|g~=>vcWG z{zj8C_$&+whS{+0DMclu7`?blNS8FTALRd1sqhoy_IWV?Muvz!$uHpCfqT`k^F8)z zG)v)K18R0fOVlw6S}nT9n%xWZ>=mJb*FJYIu3%q6~S>;6%OS&=wSfh&~ZY5CL*>@(UD)DrGdrxZsVa zl>jp6#GtZ$|NLY6m@q?0!8yG5b$2B|kz#MSu*qBPhXypehLMuhoM54*b6>XfE+=)1 ziYv;2o7~YARXMSo5LX>V_98B&)|5LW`ruvsMFBwn7)3~2j~PS$@Qemf;1P|qlFwI7 z6N3osTEn1TENU6$^hnF?+NNEWy+1#!V>@qo>e`xSB~_E^2siFF9!@afAo(UMs-`sI zZ|1Yf9QF7FSLgY8RRUQYX8qIiY|4R0rzdb?$Ag9uo)J&fFiu_;7lCSuN(ahDUB|4_-7f7= zXLiS70*y1dqe;X^r1Hw2(s&=)qC@dY?i^h-* z1u}lDYJ2o`qM<9@=^ncRts@24y%rmU_JAPWxLW6wD>FYw(?>0G?b?vI+s zA*l!9n103=`P`T#7ihiuayy6~zRXL*KiXK|PHa%WgRYDo6{~DH{KR+9B`|~g>P=zh zP90{xatFf83Urpj%YQ;L-PCBb?v0Po7dIE`&63hcn1S-n&6^#Hp^zchC#R=Q& z<7blrvgI41hu?|ze%`~-RNKN~MI(zW>&SziG}+7mJMhLd{J?7(PFXfWVrQ2uzJEbC zEZ6fY%(f)M#HGR)v;_x63XKgrpqZ5>Q8m9C3wg8*8(sx(Wp08^Zy=*?)E%cCDtM;? zMPm1|$z)nirWk2e1&+L7p2->xb@|lh3+aJOTB4m#s`XDIngs_9l()eqBqK5mX(lTj z$h5NKzv!?pW=IGV)-lk0CBhTt!$CVA=5$xWD^+Gu*SbzEFEiF1xyawqox`&gnu1T5 z0vPWgtq3>~!@~wPS`5WKwU9#Wt<>Q;WN|RfGfVQUta#3pZ(A=EsREM`g=4Z#L%EwP zZI>IN>cysre!z?eFP1{<<12Zi%u~VLGr~wq=FPP$CT*|u`3wmG*5w_)_VW4m$(Ik)BE8}|QS zhLNijF?DmXkdb5iwTs24j>vk^9pRWm&U~!4dKfwG61wqhM>$6M-bI?XP>cVecAvBO@1c3>!FsfDfL;>#RWDqx#5^Z5p;jwo^3WLV&| z-4ihu4~yeAY=}iRPM%|^P?)%4oXteoErpMhVtrUjbqh}4&S$E@JGDk|KIcy?z ztrNuF^GUZ0(})%ojb=~ePOOsKKqs?dE{Nkc5R8a4*LXg82W6Wb4C^NBfzX(bG8AcQ z;#hG=Y%t30Svg5I9|#DdTSQ@VB9vjdeOS(BAR6A?Vn8(P&i6JSJKjWs!zxuH?{kho z!NQ-E(`kABv&?VAT>Jwf^-*%~qjC4cSlUix{mvoPY#1~^o=3Znoai>h~jgZB{aIxF zb)+fRC4HJ7&DnasbY?8Kajn+7*mot!po6-|hx&ne%-?t4y}?BxOz~{qcLCf-@ja6< zi{kj*<9@tWIu{`MC{EJJD){TDAzdM;qF@&dhv8l>X!NqC(aX9t zu5fQRyM?_q%U@FY%V_yaUH*fHjWuMwkBeFO)*=@EQ<#NAMT4u*iU+Q~CCpX(8|!@v zzdQjJ!`T=zvi%Yw!1rvuYcP9|1Ud%wk*I=!N;g_bf3r#Jp7MrX&}zCw`zVZW@;#@! zGdF<=CD2pWdG3h&Xn`=MQ@xOzx&(wnGe4j7Oo4>r9*`k=V7Gd?%Ug!GV{9$lF}4Cb z#!ug3$Jn~wjpeSs~i&|){6(AI8q z<3`@GqE*v{jAXLCDm@0mBUVZ#gu)4+mp9H^NxQoJVylUEsATY-V1nT$b9{@zvp_rt zWLcX4S_ew0J7Y`5>Yv1Yx4x45{-n9DrZZSY>Cpt}=gZNgs}@Vji>2FrKKVi<>M=>@ zJc=B(o}UtCe2#iFiE~m>#o?v=)*A_0*XTV#FOy6C{!+PUQ3VX$AjaRg==3*KyYzL_ z{<>*>y)^4yx^*u%?XO(d*a$Y5TW`d-f(>iq*yQq?@$#G2#=-C}FNgXVjo-m%u5gY9rG2Uw60oFlg@rlW8%^+oT#a?5#!cY|K=O1l@Bv?olo| z)z8l#H;!_f+dgMDi#5O3sidBFlegH|b8M?6UUl)5(M@)$clpuJc(Q!l`d%|->=2?S zSKL_Bu12Rk#^HNK(T^hMQQAMmk@W6XD_PS+QJbK|6arjxkBxcY!04|sKHBhSue5@*bKy zm|l`v=s-<{9sq-(Sy1QKCSU6GkB%GgbJqO${iwtwRs zhVXN|<<|O1);dEzfJ~)wI73=S(uPTbFK*ooTfIqW^5b^I&5G z|J{6e|DO5p#>Up&hxazOzT3PHf84!ycXQ+6cN=%N?r&~>mu#%u(lwqr-UB4bchmlP zdt-BWdUkSpo*h@&*~6`izMO zSdvt~*c~JrkJJ2;L#YrzArc=;FU`*P-xJ4~4Z2<7>4v^Dz^X(@!WP9Q+|OsopeXOh z5q#wB&e;0kYmnnT|Kxmdvfu8i`$_?x7(TQ>>pPni-L9OOJ;8PM%lWh~oQ>uD$O`xX z4vvarEg#F%0hH0(Vk-%z&ZC@#EmZ7ZX#kvA$ZP^1kvy;aIhZ`pFl4)OOs-DTNp^`> zfZgs}I(-6bJ)UNxr@+k(^DLv9a={j{4$!&w^VtY?h!zFop*$W&c{Uw(JM1R{R7Agf z0q2=uKpY)4;L5T-h;dp_|62AcoNAIf)6UXUyZzi})@$1moB=(-*TG>N2oNz>k zGDvbFPjOYi9F6Togx&_Z(il?KFy*Ty7fySE6hary&;v`RAT3y;0x>+_`|IwrbpK%I zV3)75gsBMZep`1WwN*DZ#I&N&Dl zwT0w#q%<9NQF(1wgCf8YMu0-4jE5;1d0*ak;}1n8T*ORHEbe#dgV~QrqDx-RWJse{ z;cPUanmseW82snMM$+jdceaFdPF%p$w#?d;kR=+za|x3+^DCy_R7UdUVWh zVa{negobE0f2|SBR4{Fh#KUHNON^zK$33OcA#~h+f@z2=zxT|}(!MTfgso?%r^kM( zc!Q2ttT`#GS$Z~FwVJ@96DCJOU;v_WtgZ}pyka$Vm|N82MYe~_Oc=+pd_DxR-=8X2 z*7v)ljr96DEJlY9Bj3(p1gTZP;z-w=yJx+EqEZxJo~U$;$J5FwA?}?$+yqut4O3 z-QP1|{ul0sZh?Nv795waFJBmPgoE4=^bnW%deBa3LS(0& zGbv!J!16g&6pXTcHlI!%>+(xS;tsBgC}o@&AY7Y)kN}ObF9=L8kzft#1DVNm$mx2R9bp$8VWsA;cVFO$~k({ zuv&&#(zGRWJ#0$osRl2)DN^|=GqvA-?QnJsv1b%kvOKzmq-ZcA!!3KVw?$H6y6v4F zBeN4>N~)w}zX1`u#soIV@piBn!%3y+3%qmQ@ZWxwIcW#V96FmA$tUSD4deI=&jSzn z_>t1IvEOWNnjE<~YC#VLTc9LK7d?K#06*!Kp%*kCUiiSkdheQ^4I!liS z84`+-CKlT&#!7n*C{yszm`S9j9>CX`O7-@q4heEZjZ?$c+AE5-|Xkp#%n1xkDa#(o8 z;Bhm#)Js*RDPLQ}NSEwFsQ98zh&pTD4Vr66LQ_Ru7MH}y&)dOia%@WM;U*%E$weQ; z7v9SPJSk{K66{ul`T{+)COpGq>LQl)}tWQg8YPoKpKm-CxV^pYXZ+so~AyN@eK*MxCLA5Px zW;}brj}2RLbik?Q*9|RLCqS~XeB4>&op@Mwon5)J5iWUBcqKROlA&GOP`4P|rZJH_ zc4!FZ#6(3{Ex;<_krxJwu~HdUofotINjsa45>j+2HBET+$z^A{#RM<(9C-qR7;PtC z%E^~Rg3yQFTjj)9e2c)*yv?f<=9gUr-T3eH&D-?t`~6?ir*B^GA2=jIrEvj@s9J8F zSG%v$mwN}h?{;3sY7&bG)jN3e>+b8?T7vOLE2nRsKi}Vt_IbYfAXN4J<^!ijHW(NM zcb+|SbH~lifxmk1j&+-17UoFL$3Fym{x3In*T>e5^-+g-{JZN34cwBh)|)dI)p?u0O#DIXu4z+b@sM zqx6upqyv4e0;BdJ<#k=Cvo6g7S661OI{`InBG9lKC%Y?XSY-H<} zRu&!6wT-c9%4yCd?IwC3X5IoSJcH+{SN?$!GP`1_5!RxGuwU-9LeH^07r8?GZ& zuzoF>_uRXB7(X-$zubHM&?#|PV40NCG^=t?_ON97?#*AqrO{d*qhRDrb#u$zR6IGt&?5^ch3M&0=yv+L)+elJKHHHU$Tm%FLylVHB1j-76*2@Cop~P zu5(CQUtQ|S?!k^zU^Z+CT4+yU;Jh$qeZH+cUZ;W?cg5v z%g)P}yRTokglFaKFsoTvoR_#bBN1-B!W+i^i7?|C^HG${c%*8MbdK6kM}biWJE7Z3 zM^Gf_sE=pGr#@c`b=a+XeVAYtvc*(%S|+J*HBD{=Xmkm6bhAB<-8;wuRB@yoTGMV}c0`lS)KdMwEN^ImY!I7pn~N#vs$B!XWxh0Jewc*=0q;nB^3ieau13 z-C1T;z8Sk(&#fFO&MP4vm@T?yW!m#9Zy(NQZ4Lna+poge3yoErE1Mzk@|kGdu#RKj z!EtHjr^A@jEs+Wb{wS6HT0o;qi)JU;=~J>~)|h7^90X~|PxE{t3A!yb=*9R9wySJB zqc&aIqw^R+!5eh0OEl23Ty>{82V*N`cs6)}x_lEH?18&~ecL{oqQPE&n2jcQlgYPJ z>q0?eQmwNt@vlbha&JMiG9aq`FI*veNH8|*9{txgtm#HgryyI-LjyeoF=BP^$N`|J~2pllFhn(4vmZ3vtpF%k<+M!<_1<58jK)GlXoV5 zt9(?%l|37*a2XokMRa&N_`EaP5Q5CFeHqEn9IJ=NB(R?kg7l|^7Mp4}LANUx!v?HeP zi##qFI=^v$GCiP0}21e*Na;kctUc{e56 z4ya(aD{;}l_)f@&knFa%Z8D4|0G1EAo2yQsAw%bQSRR73!?}Q?mHjlt3p<)NlP})a zS8$}lZlbSwcmQ`mh`*sMNCVpKk_Be^_;F*Y1!9)BZy$IH(!g;s_7C~d3^9xW1nLXlQ- z%c7}Rc3JXn1ZEUZ4-ddPWF>*tB*1<)IaVdm) z5Y104ZphUwuo@eKPK0&4$}l!SAHYCn;4p#IaTZ`9#LJ?zbGvSt)bhw>k>jC3ZLvD^ zgc!GQfyYCGxer&dH1Ltvt1;87uVs&>ymn2-vIUy}M3eoo~Ybb&;>! z4GclvTdK=3&>42iY4rqVs9|GL)c5)qSZH)8bY7|S$&C#sRdGyI!p9wvqqeg;=%|GK z8)aX&ds3o~fYkskIG?r*)mmG*);ggej`T{wS*<&nTIQFkA2(L}_Q1fu^N8?Uh2 z-aA~?YK_BT5(92iEbKlaf}NKQKVb^NbW~c}A_`Qb?g`8mt=E=#l{^ zbgAoVxpg?M59-1cPBA-SInsv7Xl5xcs=ewMYVvqYih1N`;|jG!r1fEi!Zbgg53{MM z)mdkKPI8ouieX`^hwu@tyB^k~YsYaQ%1kO6QY&b0e-M01R{oHOr`Buy+G89)MG;{IJ2p9&tPbx)5T4pGw`k9wABnkGZl*4wA?#r?qOx%t}s_pu(lvpqoPnp z`Zd@;Yd*!xAiB|@^Dn;>BaaH=n`WYM5(*+})l zr1?dkQG}uTs@td>J?_XPbs-1)S4BXy5yp&~Nod1r4%#z*>td^%=$x|w0z)0RkE{4u zOLxJTKzrX0O@}9f34vE4$^RZb1yDzv%@adjcf0IKD|J4Bno5pIQ8U{3^2ObR8IFX| z@CZ}GymHM74Td0*S{#MAh>a}Zfj@kx8O>W=^P_G&q}gRYX|yCKkvcyRGgv#|rlaAb zwj7gB_89YrC|KQUqkBn}mKqqt|0ZK%erpUV%!}<_{e}keXe--XqW3;25?udv%tKC& zcZJnZvkvOiS`Ka`Ry4N=oi;q`51vU(+6f<8^hCrnvM<=B?M-l*CFn04vE1t?Hbek5 zLO`rv!F6Mi{0;TSBx*c+x&2v&=(%6?`D?mmb58bst3M9m<4Kr~IS2Wm1$UxIjauTV zG0cjVilf*mXNv6IkQ{H9Kgp^zWLW0Ei`J7SW!BG#!8RT_S|Ktb_ddF$M{b}Fo2d*+ zEkL90cox#=BZa5c=@bm`n_NcS10hcfTNx``jHT*tx66r6X;+uB9FP_ ztV$@51}8>?qc2A!oDYtTM9iTx!!aAN2X2_?OfTYQ$y`}Zq|@v|oxv8JzSOZx*zmpB zIj~M#uwD&t{w=VG;wt(hmY}YFWiP?L46718FzL^Y&`Ak#mon~Db&qiyf)F9t98;nhvVC{=vP6a za`76cE8M07QE*HO``RTL0+0vemNg^Cr`_%>@?mAk{&=4sitrX2UQaP;6zfv80T&JI%)ENWN{fvv{4-a#R(9 z<|V;7R8>0l)S%1N)08e(Pd{IA6TNlem5gH0mFN-?m(UuHGQAoSV?`18e|yy?%hCC`;5TSJ${g!*oQ;ZpTWo?L?;V@) z*vXnF(o1iO^(jHF7!lq4C_6)%3i8xOgRb=b>%9XV!t(BxBc~CBl>4`B;;Azz&eDEf z3>ylJds7K~Y=DYv(&*5C@B$bXbPSP?AK4AwNj5(|GNy}ut2PFc4;vrhf4G<875fs? zV~TQkt*1zma}qAkYNdA9;I<}r6ni3S-IH6lA`B6~YOt;+FwU#Jh^l32o^hdbLLGO4L*(aW6} z8Pv9I98=J3v*GXJ=BjXqi9pl|RIS1|TBtnD@HS8M9b-# zAh&Rub(cPVP|bbR={$ms#3>*OQSudh6S2$ktqmQCHgyKb){WJtvNP=r_1Sq zs|nO5_Q=(Y($+aunSzAON|&1wg4$v%-NNBCW9wCnHL_CTNHgoZ;>E~#r$A;wM#5Yv@O@Tum zr+$RE+EfR&Go+A5{xIyFOmQJc`UVmAmTFIzaz$5DJl4gnJ&Hhu8JBwz83AW8F;;*% zK>ZTe0bK*s0fz?76bpYe>2}`;`KsG}fhlA2sY|K5LZ)_taJdF2th%7crAA(;c-%0M z+lNyElLR8;N!E5&F-ed!2}AC-h8bRr|MBiMm%Mt9hkyI?3l#UPg_u6yJQ5 z6fNC2+=ZsUy4Q7cjcyGN%aLdf4P}(BOe_Y+RAPo$P&NF$JZZ&(Kh) zNwNLT$puh_?1NEWT%!3}m)EVxB4>EMpedw^y}r&#%u00cLeFP^l6S_J2}pM$oS+d3 z4zog1V=}56MP!=;?t20~>|UuLP4X#lhQkUE3jGsdD|O6aZAK*$A{;zimr9y%H07cR zSFrjgm|0qQZA{UJ5K~6Vc!j5E1~ck1_h7QT$(63-fVymK8%fHBlsZ#G;k1c}Y#7 z;Vr8!OQp6|L|b;fKNdt!S`>tR<6>)L!-+HF1opuqTN{y^88eCx7QD9+yr&_xnxJ8# zpGOHgiqcuM>{CWl+<3CX@+=o2G6(svIHU$_b4Icz%Jjqvpao6ugHW-Y`Rr+yn%kRg0xEhSjU_ZVN0A5$D0N_Dr6iWiI z4?Mo|w%h#~s#+>O+~kK&aGB?iFy_!myh}7wi?P22gnL z5U|vuF7IZtVN3_cV%oTaoXtcVFQ5 zty+}G@LIKyRPZ<~^)QACD`Xs&{BsPR87U4uf~|MdlNj>Mh+wj&dPj2_>zxtetrqJ> zXg7jaH-=EeGeS|#lm>&E)e?-;Qtcen#bS&5g7X~+Yo0MRI)-Cwh^t(5B1h>ky2s*k zcMHng$9yqv$e}h;+%lNcSo26JLSc-nU=4*9@5{}Q67(n^<1M5?Q+Gr^9ci9A$%S=? zp|I+r6#?f_fMU5aH%a&J3T7Z2W1z!zG|BG?ySlMKwKeg5M%i)E z@9KD2yMF~S_4N+y;yW+)p4NC;?@xvz=9(XKf$g$6h9)Yb*L_#rb?xfHi9^uXUH(+B z-%kW6m13-$^hCno3Fl87UZ#SfnkM}{aamT`_aTON!%;D<;EaUlEYnR(hK6g&1fA81 znOIeacVkT%BD-w_Qb5J~EIU3{Y`>WD^+CH2r}fb|A^$g_UFGc18VADWvEs`P_U7h* zeH5@%hf+%zSj89~mVF>KjxerADqLMj`6_lGtvN%5KsGIYXUCUU`>$%ZBFE8L(ZtPr zz00%xTXMLz{NBw}I(9fIBE<42c~uOKfF6FdG}OHXWFoZQUF}Y<^4bUrvY<7@jjyr3 za3&tN{+?GBFrrW&&E8;yOu>tzhg1n>`cSC`Sii%Qd24%BQ){1fgP3=~)5j z>N}bxCqN^4TpZ=7wbx~sz9?-PU+LwkMMZegH!5a`%$}vv>ft?DPxO&*;xNS5rNkIE z!$i(n>AaG;$;UYj!34(6A{bc`Xg-^EJT}iMinet&Z1!>>&;7I0PQOA;MbuT_@_yBF z8ef$fN$gTypmyQyDD479-CbT{3pYenT|lzN`_F4o0Gky`6nmei$=209Qj`fhoP@)WbJ`E z%v|M*uXy2HPB>tMdP`(XaVoN5aXiik!IU)8O*b&@k(`QNtOm#XRRi!7DSCBnFH>Dr z`t^I2JsqdxHm1|$$uI%FNHA2c+|r-gbfuIH*dZjy5POcnkq?J?*lpZ&V=^Z=?h`G} z0lIb&v7(e$@s2TZp_Ul8qP7X^jx}YnYFLXa!sBfxUjRk!1rPbc4k*@{i7fBP8TH_m zF^3voxaODSw#?aw#(2X(6)(nELftu}g}7VmsUR_EUvHFW>Im^AbXUeU|Q zih$O@W?QtNn^A8gIXOXf3j*+npXD!X(3#<;5zipWK&~QzBg3!BtU$C8FfowNSvD1gJW~Vtge(o@Lzh7dbc-v;B(nqF zXtui~TUfC2)d54UeZ~%ABEI&+S9EyK&zE8X#w`T$&t1FS(AMRQ`P$3-tr@|?KTAm@U!IJ)A9Jz>P7QG-`bN7?KL*-HA^9Q;)X#vi+WZQ=2z zmhQ_?kPr7+wlPAiNixfntluL4*KiM3x@?<=v76x?0^lFYIJix*ut@L0Z)7+Q`egR( zpT4?`bK0H6MA@}h)&Wgu{lZ$RAzko)@lshzqZ3rukp4k#3@UOatGPmo9ksi#DuFaO zY>15n9bJk2z_*?W>#CKZ0tD&ep-gbS19ppey%lD7UJKeL? z+$;4?{k`bU0G|M%MJG0d#z5C20hwZ1z)+9Ps!1chki^FEK~kc}N~W)yaGKhD_MU6c8-ILi zBNJy~WryA3WA7~hP&YKG^qgStSG4QIOBu3+#e_-NydTC4V0M7)i{mlgV^Ak8hkvIi z{lnwI{n$nEOA6whCBJ0Da?6-bINKV#a>xv8{_V5QbcP=1mu>PI ztKhQ&l^-1e1nnidz&XUDRrN*DtbP^Vrw!W&!zfodkg~$wwyLnQzWF8;+Eb((a5*yi zgN{U9@;)`@G49MnX44|V62SwrjBD65X1!cpS0kNZDe z0A+rLxxQ+yH6tUwij9~@N$HdoebJma&PNLG%X$QA5>^n1P~Gey<*QP`$J1~7P0eLa45n>vz0)fYmUyE-gR~| z?Liu^h=Vlk$btn!2=dLEm!=58lkFL4CBh#qjFHF!MYLRlP@;U@9+|VXxU$R6WRkOS z4~Wgm50?EIeF27yPL*&{yLCu+Mr3lvo_-BEfg0^5c&tfws(1O(&oJo6wQ_`U;y6lv z;K79=R+u}mB?(ZQXjVxBmf>B38*GqH*4RsWzIFdWLrlJy>(2!8%3TO1@mn6&dPiKP zc_}jR`opDY_hPfTbO%~1^vxu!0a{Nvq@&Ll{rPl?q$RYJNN@fA92kl=KldmswyFLx zq~?0@eKm=AbA+5DNG!}D;`8PB?YHVa*3TJ@ECtCt6(lzCBb!m%#1dJ*NYJXoYna)^obE}Q ziV2d-(^NP@;IJ$wY2fU&6a~5zMm@!I<#zHV(jQk@zs&yS5T4k?ZNj?@k=%`tok@B` zeumM(|3i^%|>!{l?-PM{T3D^_3x^Q zHSE$P?ieLEn^^tx=QVG^)sAN24)3^S;QE@*#}o!78~g*9GoY_0W_VD|?i5n`sHXip z#chN($eYa`A9npk``QV{0)R1-I!x_x&JpX5=NR!8=a)l4R>ElfBp*&hd>&Yg3LpoH z?3a^ES{*taJAoXC8xzus4A7%?%nEE4qAN}erlH9cTQKI94q=1VyTd#?6LDP1X>nYj zmjj_8sZO#9Z9RZ2n+-6YQbG_M@@KFW4O2wt3XA}d?5_444Tf1UBi+EcTJxjBDmZVM zSwG|~&W3y&1WJ<%$KJ$mKg$+{`olK`L{eaf4YpguL{*~B2Y~SLkynFlyQh7sh2>E} zY9opid<-rU>99tdLF)y2g^NmdPVRaL)6rfHkzIXYSu-hODI}m@y1c z4%SNLt5@H@%jhsIiyBubn(@C#ufO-^1lg>#65nzdEk4X_HTzKE>6nM;pEZnxx&VI7)O8rBoQ0+HHmmoRvSZL zx+zGkM+(k_D>?J$2#Kx_MYvg-WY4^$nmG= zz!z(-vBKza%o%+QSwv;esV_AE;dU@;#(2;$Xdy0mNYc5c{K2z^JZd^1Ln-d8VUMII z2`R~5Bu=-m@5&Z}s{||}jLvVG{PTMQjLS?9rk4~oRPs`?$ziV4CYCcRD07Ksu&{xw zk1$9llA%%!MaeU6ZlgyFpJgIrE+ut8mhLz|IwC-*_j!~&Fd%V%h2xm176NW2Y;vSd z$y7%rkw%*#z8BUf$*+_LX4^=G=@-eS$5ohfJ`9wWS+ejhR2ddYuDngrsQpS5J3=gg zWZOWnBo-%~N~4RnhkpPLn(WpS za+CnhjaYuXZE<(tjk1}?$-M}llo@|4w8+OUz zCM3d&HfO_Ua5bm4ME7Xf!61Wy0Y&=M>=YG;pN!>uxDL0n#^-kwA6ynoGA=ck=&=tU zNeST+QNbUd1tenqdgLoRP;h2K9-eS+GO26eTgcS0G_|#%|JD32e{DcT4n&01cv9hU zO01T^5TL=(AqT2X7gZgGs|MPLp~yuDr4mMt7uHrGtK(_sA%@Rqn6w0GlFQ(2FmP_5 z3)Fy^><_;Ta=IyAsn6Cg-6hF~?9yg~GLej!@$e4272IJd#1vkm2skEKg97xr2;Z;K z`BTB6yRy&5CU@2N>={GQ0RK_K*1HCBr{*`7^&+u53XO_AXxU3RVpNU-K~G$G3f6`^ z5HCA>%7!zecMlz*poU{w@_~03B;vxP)SmlwdAY$70PGUp9^VMAZ63F~w#~(?QtvR= zg#M;7zVt1EW)G%i3V9AW8@my9!ArYc*VOddO$|d$*`;xD)t$#_1)iVec(q8RKx)^7 zY!NZW$QUg@rUhkl$Un_7LR-)7YtIT%Z;ws2EG$jFA+0!Bee_1ikpthMW*g zu2f>IrU&L!Q`OS?hUvUd@wHmm4a$3%jW2a4DVAALVZ>Bg5}b@Ag9e1d zNH*4PBy8oA>>ZCwL^KtmR#kOeQB`tY&W8iOi^dpLvkY$y1Pv8Bol8&Sy+?qu;+YQLjTpANsBB6 zNxOM?_J4}7>x3(V3ECu!a#rk=5=uX%VJhjwVO{Z5RF-{-{FAM{-Gy*VL+x<5@&&Ah zsznT;jblnNMkh666dhtwT)S?2r|dk7pilErd1iOs-`-s-P-o@lEoqX)5#E#`7H^bf zoVAnOE?lN z?y7Glw9f{|B5&(?F#v{X2457aTGM;fOIl)#(To@(ZJ9BVY}Kf7@d{>P!F0GXO05a? z_o^ll?nYErMKBmaOhy;8gQQVd%1|sWtVWhb+p*s0^4dPi!WJ4gVj_Sk>!sNU2@?eJ z28hvnFU=YzyebzwI5VxQDr?TBC8f&BII5}2*(M5^&?v7|KJBQWlvNIbE3Rk?(EHmf zz8x43+CV}8VvtXO8c-p|c3Fqz%z`(~k11lEFxSOwR={z4iaZGl8Tj=?zVl+5;B8FD z>Xm^kqE?_<^Bu6TQKr89oARf4e#9Hz~D{yGCDO3hem^ zPZ`iwjOmd}IzzRYUDfEQnI=x5_FG0#Zp60m~db1iSh zKuEpVfYdh{6T>4QUlQYoxQz^CSF|Geb>YQKb7ObNY_2qVQ*Tv9F z^p(S)o))IYc|H(vZI2cC1}im{@R>*G5QAkVr9gHC-Hr0vtss;AZ;e z;f@xe+0(FJc_!&acZ}~GV^jh3E(rX#qna;0$$`m^- z&*jo&?Fx>A_WKN06*IyGGAS8=IDYb95qv-mJGrGIH~;)&Y93DneQ@%NoArhl3P0o6 z^!RH9Xj{Ad$IH-aYsNeQ!FJ?FyN*hIfzHDQ%I#7lN~&_Y&K*58*Ebofk<6)}8!#5u zBgR#X_1^smui>qK&`b5;8QoatXs^|`l(pG`Mq(?9eDqIx`(IElR6uCMK zq)7opk>~1A=)}fQ6rHXL#UOg&djHv32dhF8rO zb~|cev8H06tKPa|K3%)6DCm|YR5ATU%~S>3zGwi$6jsxSXbRN-4a7q5?w&6Wh38f4L{bk777Y-^NWRW=B^bB$u;%< z&}Gf@<9F4Z(z=>|aA$FP{mz;cQCD*j7oxi<+JcskHn7^2n(PlYvgY5YIRKZsRU>!{ zZq;HPUE*fV>Tx7yfgig`RUvmO_xus67@Rf3;E`ah~ z%Q)bW`=43Zn40T2{8!{#i2%NpJiX=7R(pTrso zaIb5%!K+|Wo|_RN1M6ccxJ1+@P5;9{I+K`5+y7`8(_>85KOBnr2NQL&jNa88o9)Og zfvt+6Fej%3*hWJuBfbiPWv#%E4PDXiKN^-IJGl zub&xPA0x{~HItMrBhb`*15tJ1&{x>x!;H?M8`_{&-}U`TTWxAdeZzyMcS64T(}xT% z*Bkv|F_~O;yR)*yR5zFCu`?%Y@#aS=xZGVoMp3g&z>HMP5{v>z=6~5Bo6MZMeTE=h z^(~`c>ES^4;}tuoD|l#HgEn)@K27vNn$e)1PT9VcNp@Bi19Vf*$&g%`lpFA%8KAm0 zIomNP=&C{%!8}7u(;}UhJD@Ofvh@GR98sfj>oisuT^Z7T?9Q)s-yg zRlQ?(Ds(-~##$1B2`^IF(^r49d*V+LXB^$d9o-5Sk^+vfQA1$HKv#z&4BY4nS);EG zj$MDap`{&l(p+9(l2GKmufJif4(kxO#J~h*>~yO`tL7siwDP{F#@%wdzvP}D(qIWN zY}I76=I!Thi_W0cKK_*gkJT$Ok5t&ylH|K5@S7KfbDXSU3#>|7TaD*R2mxvpKK+E7~z9btYKVT1&`fNT!4s$3YKWc`Vh;| zhL2dPam)Eo1~+_8%xh%-v&<~_Suew@u5hGa3mG2e=PUHem(hy#%znNKQ1Q3utfyAR zTX1dZFIi7hI*hK?AHgm$-~EYoQNAbw5iWWZl{}{d-y>pqc7_j#v8S={3itpOy&q4} z!k7JWk#3U)4=Bl|Xh(lWfu$$2%O;a22ATG#(SQd6R6fne{k(mY6|?9i}8{Ils;!Gwjp_2xsH(MW;$FR+yk0{0#n$L3I5=a0L(GG~zZYK>Ihq7|s zMtxaZzD3yt5EXXw08rZ&Fgg~F88L~VoqP;$`@~WR=bacRJaM9VC`^k8oqdwb$BN^i zYc<6vLv~>t5@X=18Twoy+pa`7IPN3)w!yH{lTPxgm`=+npGZ+g4bZoMrfz8!i(97z zeb8q>d3a0dEE2h8(asdCgwLX+PWZT6S+wB73{dzuiL=ZnGPtFK7|JIc zBn+Q$1fSDT0Dt*tV>~o zomI-_ODA}g93STht#QlXf*&?Mn(_xpy`kJw8n+o`)oI)cb$s!pEKbD~By0PU`m@d{ z^4Z4JRm(mKXf?4onrtr0)O6yDcJlepg1YeqwfurH&B@4G_ar0l7*;1R^;zbyQe|M3 zGgKMjX)$G$U;%fnEGl)lOrfJdiC73Qe-(yM5x{<3&@Dqwqm!#tKBe@IPOzrvwD8z! zJ~zzf@L8JG)k49?9%y}(OnjD`e)&X}2tLTS43&CqL?qTkCzIE$!c6N}Cq9aX z>SC!AY9hn)1D^-jMpSDfB~P^Uxv>n1mW_nbkR4Rq`2@&4m1YuN9cvzB`LKOa3|Dm) zHq`47PFyvI_|&p4fHirj8*8hl&6w6sK5?TP8ch9>t6rPomR7fHmZBMPxkLiV(|~PR zppnHQOPE0NBiH22`V=G(S;rv|E*~cl!s`+nxZgu*BE}|QUW3bQ_=_l!P!wW7aylwuv$;H3n{|Q-E6t~#ylEGJ;;>&TtKQP8fv2Egi)1L}*yf&+aCYzwM}Gh;PY$%MVHk{Tj6iF7ZrI$NgB z#>gm6dm}|lf2725?de`pb>WL&mVLb*eVwi%qNfP;|JzycM=kMi;E3bX1JzAWg`VPsr}p7KH+5=C9bxxg!-& zWInJq%UBOcS1wglEz+~Rd_zIun3g>HP`9%Ay$ z(S+jTQ@KiQ*)pM}ikAP|EA)QhSWXnQCLD&7LhLKUG73*Sga2ljRZ0U>E04l+Q`A^8 zu~MMeCXDh(6l3zJVI31LYawi?iIMW#U$>2PYh#&{#b0W`Va1=YdoaLCLDReA3oEO7^p8N@)3vf#t#m^)374vsH z$B8|7Z{+f}<_L=Ki{H=Tr;~2O0rUiWWl$|~uDY(WRti)9rRBs4ElCCJiLrWSe?rR0 zyWJro8qUbwZoeEK6~`DE{`t=Pmj~&8zkhSExBL1aeYyAQN&4HX^v&CS!vQ%wW9p!2 z&eME6$k~JGVlpiHaLA@Ck>!LkYE4RbcNt0&iPca8oej^k%L-G`uulE-j`B)U zpUUy@lA#y<;4) zZ%N|#P>Ud|L!;5daD@7mDjeVEc&H6k$fqI@vC&e)_}e(jT4X6%39?mY9g<(5P8&5b zldP&bKzAI@#Dr4K56x>9bXG(kH4J(p{bnC|Dj4+oMa54!$v(}k)MTSih5hS3aF}V9@1JwO+xFHvkN`Ro10y+FzGD@w#-{U%y5h z8}K~b*uZ}`AKt%b{wtsFHt%oUeYo}T;k}0szT3FFwRvyjyX5|jk2dhkG2UR3d^hc% zw>LJ2r)MXp=h<^u ziuu30ad-3nCd~ict$TOBOE$jIn62l3`TS#s#kbG?+J0H|^Kq58nM>pRcax`2H`<$> zjqlgje@G54C$R6U>mn7ygKu1*1eZeRd!Uf{Fh_A=kPnMPx^xFwv>M^v5#H<2y?H0u zn}L`;l|kaF90Mg(C)p%V$|Hi-tHvOcD1z+$SgCf`L3qKuw$M7|Qx%!Sp-nANqdZp5 zX9Ox6loJX#P(XWVbin!C=i@1!`v%D_W~ZIcCUYUW?^LJRC|gI_hGiZQj3~+gK^x?K z*pQNw@*MA>rgSEtQOK@xpa^(#Nk%dtTazpYr{7{gQR%93KJBZ4f@D8CA;E|iBc^p9 zU~o@)zMPeC9x0D6$%0^n_gv-ha$JrIkQ_13qqr}7`*fecF>cB!Zgby%kFs1f8{k=r zj<}@#=sr0B`F%g1J>mkW%9w#%3}5!-pO5Ivs2GefS{_D{J&5(Q#vz zSF`3vyA*SiZkOUzbi2DsKz&qO?(@zVM)y=?#&Pf3u0$`rG%(Y{`3J) zXJ>iiDc)itpb3C|mLJZKTgh9@DV7a)KeZD4zxerPI%p;IAIuLA!@<)GHPjThl_1mr zK7WO|{HzX6+*6ErlV1>_kuY0{97D+|e9&hj0gb;|mwE{5muy&WB|z6Kz)kZZi|pct zQ)EAe0_Pq?S*e>8ceh#~!+cM9%!BD+gb?&rf4p@DZ4PDUoLL(q> zbQei|ZHQ4&-*un)vQl=Le#m}nnelsU`By+3oVSmX7n`&`ix~yjq*cr)=2eYnFtV&z zflO_BL>ne3ESq?T4ahkrwxyewY7SBZ5RV|DWU~PnFsU&3j(uG9r^RF@8HNDI6fXFz zG6)9y*m-=~1QMurcWc&Hzp=j^-=r%$S?M z<2}BCzg^v{Y?kyc#4>w2pSEIU%29rtCASk<_O;5d?iVJ-2!?Q+S0V+y$&OxPtU`&U zeOOf4)IgKD>_o7!@(2V6QhE@WH7cQJ@6VLMWu=+$_ck*Hr6J5V6F2Ut7g zgq5R$6W9QOyHnHUu zdWU+77g_1p^{g_1|`hd^jh{XZ_cvv37$KGX+f~y9VDOkO6OPzRGOmU1y2%X6t{$cLm;*|)V zEPiR1KE)vq$P-|kjq+-Oe;ttw>roZPv~K4Ys8xoAEcB_Yr$${RV9Z(_XhL!DZs+N) zHY?eC2LIhV_*?p9XMYz^`QTo%EsW^9;X;q19YkT7)h87Yb~cov)^$4xCrs$*?z>>; z?2n`hHB_`;zqa0kjE8a|uHDZDYsWL@C-GhdJ|=09O>2bq*C!pU*-fMx`e!N2KK72l z*MXi<)q3z!Lc3N2@?c-z#8c_0N1@UCE4HEB{3@drT3^g$tr@1J9-gFE`4oCEJ1>pK z+H@;0AC0o9;v}$|M_5#P=z)+-(d4@%?S%BYv|MQ>J0LisZyi4FNimCwdvEo?ZzFnBSI1<-qXg%b5SeJ9s`J(dA^pYlE(rkxv9a&^! zGjlx1rNput8a(fbVQGr?p!g3mHs86f6Vv86O?C8sxJxr)nU#IKbxzTVZcdh zHPMvpPhExJZG$*vwnb8bfj&WL&M31Ypo*pw;vYj%hZjHEqNbKatj#a!o0NB**Fu)% zx5RPO7N`%Y(s)cxBl5s)RnUr9P#k$(NxpnByI_z8z>)K+8-wHihB2wJGI$X365c|9K;qG867xV&HL1>o3Rn~DT)&uP zY!1SZO{!4Q1ZvK8spy$JRx9PIA^g3{E{f57qy|Bk2chdbir8J-n9P0b+YYc=Or$Hp zKLssE2O(Xbs0Mdmij@8=IKcc9r;!}c>zf8MQ&$kRfRw{z4XFD2&oEpQmA}^kU;e%q z!OGG;MCafFG^SEuDg&ypLWTGARMh0@S?1`nLKAZDUD$}mi?~o!p)CYO2eHCsRgeiE zIdo)fYm*Z?7LnTm?ki4Hej5&aO3xiQ9{GcCu41c1T-MG`rse$j1n+Ny15%f{se}-n za6?JgXXO|0R^aKd?oYBR4}!?@+Rw0sFByz z#S;1C_)Yq^NcLSiV`|+{tQzX&3KOZ#hyEN=nXau5Hq?-S9-&tf05J0sc9%nKk-O97 z7()RT{bXp}WEi(|W_$h0W(W2qpn*HqbIr;L`hy5-qJSdKYe9Kgkh&@@26Ap5+*<%$ zjy9-i75%=f2OGU#Aswf>V^NHAgn`B25G}NJ{`{~NW{Ln!=3@w^y7B*ZuybiFW2yR% zAgdeH-5OW5VJV6|n8IUY6Iw}t!gi~zjcJwPj22^x!4VqnMuaaf@w3o>pbHZ;-<}mC z!MO4%ieA#T3Jp$Cz0p3&v$IRpKLzV(2#XH3wcd!^S7z$d{yOJCQ+Hs~s@F|`N1Uwl zposq{K<3pAin_>5T5Kf5lFPawAFR(rU^`WZiz;YQ5ut@1hPZY0E_y8-Azz^+e0hYY zDP=OJW9Oi67ss;cO;~0gUZyI-m0nI1ERXcbJ+i*QFwRgx`rpZjJ~V-3B#D-~ys0wV zWT(SqU)cDYS4Rk$aH}ykpH?N=J7<^Vjz;G}zz^DDDF9(UK{r@E6 z5(8yk0w_7O7gBGAM!}aUoB(?tTYS9LXa^cE&_^;$W@Of$V`@0!Hgh->O@wORqxg#2 zB<=tkg#zb}1KY)Alp3+u7(nkMi6Lm4m+YR=nqwJO#*kp5fWg5klA~?$>=k%)0i2%F zE?G`Tw9<0ep3qK$C%{teIZWk<*S6m&t)%N$fjCE~@zd&r@!>*&C}sd$hnPkmqeTT_ z+rHX{(?5o5ZhV2M`@)F%p|MtsiH22(;BJf>j$BAM^3Vb%@`mM_Hep zHU+^ecue@hLuKbUpDhJJp5Y0G>~A~S@_T8YS2?_SpfmAM=Q=4! zFsOM57Uf#)42rX~pBKYMu;+RuUOCC`qe=xDti6C$Zf*N@AeIKl(cto5VyU$iE}Jx? zG83%>NkwC-o_UhN&c!rSHD*E>&M?mlxSZL@w(6&gBK2JD8ETPem*+>Fnft!xNPm0e)z8Ed$H z9?dU_t>G8e&`P(j47@iY6PKRleHXX9c;mgdzW=Lr-qpec`tKI`R~Ujv+^)Ju^H%qZ zi-DySIZi0p#zsf;?Wze=JVYdXxm64rRCtpITjw-=TjC*rKc|XYeLkt!{ZY*>lIh@a2fI@m9 zL21P2G<9I>Bs~}{oP&z|_Ku~uw32uA|v9*NnafU>YUe)zCKXnmxo1j*d{q8!yj=_QF^gyauF7{wuL+A9&-)^}U5nN+&OHKS zXU+bZUE&&x=9sVET{9maFzuFM5QgK36+3>ZURsCIcxTCO+@V48T-9J3z{CaXQ|fKw zuH>Zg*XH(k4*y+m{Plmv?M;I>34$)?xc(|2*kRuOB{|CR42r=XP`y;Cpbu@<;s1zS zqOIFEp_wFxN~}k0f_h#6k0q^W1S@% z?v#<+h!YRgIb|EsL?T2kHh!~It z##n`BJUhgo7>>ugC9kk^k1!8GYCs@>_n~y#)C+&zzAnbQ2(w!z*uD0Hq%kP_)p|CE z4P*V6otJO6(%*L9?LFVyeV4x5{cUgeFX`6C)`RxOPo2@A*;V(70)oRAjC~Pg>`Lrq zv~N`$wfWuiJ-NWmA8nw=CX!O|{pV!GbJ&QR~2E$e)56gNb!L>jkMaIbaZ) z*HcVP6B6yd=Oo$CZI1^-9!Dzy4Woo+7`PFt_VcbK`mo?kr&ElDLg65du0TWOd^mvf z?x~PI*}lQLSrxD-_Nl%Cj$DJIsLX{_09B8+@OlvMJ^`a+?Din9F30_oX*uQ)BRp>8 zR#VGgjm~Nvd-?oBn&A(i-_v6>uE(nhl4j@{S=^nmH4kvELPT`ZaOji{QiPawS4C+3 zUaUDmY-NeoJ143(jIOM_xiE5$8^Nq~fTCz_x=a*4HlWbVboj zvugmvDH@x8C!+Ealu*C@S>WQ!1fQ?lOB=vNGCtstZ#w z)(p5NL`!(i{iUFduk6?1qyGrxpX3X@F&9oS0E~$I0v%bN`U1ftyuJzO-g_M|X5-q_ ze>3fG#@lxl85Zk{sW3>@ZQ|PsgTn~6598W>Q|`lLt4k+odTj?SvV>0Q!PqaS)4ZCL zY(+aO#g5w2s!JAF^gSm!K+!?^FqiF_fOP=&o-qGQt&>%%H=P~`FL0ux%_z5Y!?TmJ zvW|dypORMV93irr!Pzfr=t~nR_2vsKeIvPEjcO|#m~GghV{-uRzk|ZT9oUj;hgEk_ z139#I-DdyTee{p)&9~W2zj6f8QPhp(UtmvNH0+gj)&&a|pW2Ny+<0_5wNbY!N&Ycg z>>tyMdKPT7Zf67AZ4K~$n`5Ip%$mdFqGA3K=d>EmwB%`RF;$x4f@cxMxxAH= z3y1{)-){K?xG(VJ4PSR5Z7suJwP~gO-9Fg&NNIGLX2awBaGDi;!w$LXsVmhBaVdAGJ>yFBfe|GyKX%yrBa89D*1!@-1_C3>v4$1HNv@|Zw zOvHvMOwZkoQI?3`5cD8-LMvDX8qKCnUly5|lWt_$LoFTIx`wQoVQN=1S4I<%h7ZX% zbS2{>ubc*MTak!e)a!O|cjd)Nuf9lc>pRI-vs2ASu3@9PL*1?my(J$JX{=vykSuKm zNKN9qFI1*uL|~A%#-jOFj6HR0CdjTNgD?bPecEq`eG1GOYXx6I;Dh9 zhkj+t3NQTCu%-)*T-a;b-#n{3`*TeIR@(ZUSDL)-5B_2eSGTSjOCKmNN6=@AS3PEFb=Ensf27`a|ni-H-N%B-QvOdIT-FuHPL zccML~lou?2(qLWzO_LcPtGF-%Z?x_xKWRqSQmM-vp&eATcW zhJ8Wbm3#E;F6&p>B*{d?;Wo!+99p4xFNMYfeeoMo48}J)l7o_p>3zysp9IA=1CGC( z-2ua9RY^~J)b?6rBQ4CERpTm(6KC?uv^%(I@~n!}y>mtp+gM*FY#J~CB&Lqlj`KZ> zbUzdy@!SHPAR9n-G0p;EqK?MiS%8tpJg4O#L%8h{D|$1*<@K{ntHd8dZ0V3)mxSMp zwE%;9Pk$vYR(_IuusGT2bDO71wnvlv%ze8fs`~1>DM!sCUk}w+2S}TMxEF$UxOr}7 zo7)Mk-q%1Z-WEmap*dAF>?lLL=sL@$MJB>+i}hmW=W|JuB6ajR8xgv<40AM0nvW(d zLXpXu3Mkcc?DTplkD>spz!@P$*tA?bYW86f>nO-rqyVGd{qby{zAAAk>njaAh=|me<(eLfgSE!_`;9tjx z2%l(|BSqr_u*x^BO(1+2mkUA#!9L$k+pGE-)2F0bH)5ADg}89G zKifUHN=ErCTQHxhXUonD?O0^Es_%EjNF#DzGrSL5xC=p*2#oB`*FmMbbE}wC1}eGN z+n)nnx-xaKHHfV{)+~Wy=YXQgzf*gBaa2b6#RS$K48W`)0fqdntnS_Mq~h4;hyv3n z72E}FVz_48N|>~WDS$tqr7%9OK}2Y1y8N2-J9DMFvi&*OsjIbRC`D`}3t6IXM-*g+ z+4!>Y1qOvBf+M>v-*TJ|FMJG>gxZy$?Yh#wiy<~UaN3UpJzk2XE!;$a<5x3!%iwEObWEj z))(r(x#X-5*I06(8RZ) z1^>LDsKfh$50Omp%L4O9FMXBy)EF(USkF#y6|8LI<7#;Vw`~%0?TeBKUle5?K>q3nb6|XWBs*!jYziUhXG}!Nj@HMl)ivL;1Y~|eO-s9b8{M_ zuUR=gB-6@SnLIDDS$qE^8x2I8AE-GZRD8xV={e;I)*Mhg;BU<;R@u1^a>TfQU}i1zCC za#>_)In@AfDCBQ!;!~6Ba(-9dhkSmwgmtO96_6Q7Nz%A2ZYunRkYX9sG`l9IE=4Wk z|29dOh!R}?W?6)JHBv_#ix@#|pKq3LmEHCr@8&Ut``>3YkTF02N$%=U07N zK|R>WYFINs57Yh=q2MK6RA%nz6>Zyr8%oKn-@}Uo|GR{>fuy8{3!w zV)s^T3qNc}dUE}p#!Yc?8Br;igct0?!Wj~SSOVj6_yMy#haNqH*6Uyb7v3UT6phr~ zQZ_4(N0j$Xgu!aC;+y(HkY{b+As=_-UDR6yqRzpD2x^lEGpHSfv z?YyUKQI4;VjSV_r;ruoFmT_HFGYkz=RIHujkY$M20N21r_V#+Zmp7-4hRXfmrcEA| z1J1fFMv7^XrMXMW<}Tf?MgnD?ffqWpLDfp07t?C?mh;N&=fF7z^uvhVGO_$^_`SHV z!Umz833j5}olNuLd;lWXZQ&QdX_`S`)UVLsW`Be#!P$A)R$475SBXkxrE))t>@Xz& zqv(#+Oy_+Tw~l>`yV`!7gfce-47mEZEZnle#Hn-(vk{1^?G@Twq7YwWQaLl^S1iUl zmsCr_FN{%Zrx;HwMNgZ?8XN#wgU$^hYnQdxFj8_p%R-4{X@K~#!>otL(8xAgiJbaw zw?ChHxnX(WDTRv-LfAARV6h+w#s!ejnGJ>BH|W1694r`wqcJs~+K}XzhWumE$c%N; z?MkLCucJ8vbz|)?tBO7#7Vvjl;o*)soI6&Znjf1%KG?UcKL7LqN&KUvaGjkx70I?! zaWYjKswEd)lg4>9{_!MCdzXqq>;#yfSJ@$~ZgPlhXl_-r0tAX`sa*~=K(F-A@-%xh zSEAC^As3k>Hk-{DB+j%R10?gX3pni>Kq`B943?2z zT!7n%Lo-r&8`n)erH0O&!D&EjA&rT91999+8k^YsM^#{n zz=zZk*R}7fyRuRjZc!f$(f&iH^U(%<>w_nJ)(P`AJyMSXCtNq6?9Ei8DX6W+MrU4Q zZLivOu&58HOJOk_BWOuXELAy%kA*>euGxvDu^XyvnSZP{8H9evl@XTYy_(W7^WqjS zrL9(?fGVrzk2UZD9;6JZ&Wk$&&}R}0{ZGkx+abb`2RA;~_u{770Z;Du^a$)|7gscd zFHajwY%0}hF{#LuHE_76eTGi>-+D{g2#o0mgkoXl8{5kI3p8y8_w`WER=FOb&MbL1 zQroGTiA54VweOBd=S>R2f1$H>w)M|BkmqAMv*e%Vuxe(PaEh+~PVLqgkqy?Idqi5s z*$Mpj8y@wSIORtxZ-pyw-N;eg8NWD@Rrmx*BoOiI-H;Z^LeQ;Qpb-dLCWNi)K)9q-z5A(}%Jg{;?-kgFnJwheoGSUNotmsxGlvcACH;gNj zYbi9t_1&GFGFd4Iixrz{h%xmh7g%b`c90N-$R+;iib{`JdC2ohSU9`mjM&g=I^jJ3 zFpV=E>dgez<=TfxvLhJ$6)g7G3fNy*2rbiExt;OEMFR4U|^l#+R+oXjgd zNkuZRf3HKyf8_dq0lD5ZIRCb}&pRR+d^6?|8d|M70-fsRO2-Au8{M)6X?#JY%onn5 zaAF>WrFz-EE53)9u=Wf}r{r?v=e(}b3{e#LRi@R@BH8mxs0jKi!$}*E*YFD0WFv@Z zO>F^;C~Ar~UoPttS+e1ypKJ+EVAH9-+;P34*XkK&0Nc_@D4ma8rzInHz_-P_b9FP# zad1J$EwtF$49>(tO`U|w2ihN^Ct9I*r&gOBxWi~4(;_v!4#X64&PaY(q<~wl?XM;w zd%arpw9seF4SO{oE4FBO`Q?}_vzvT|f3LjAR)RLArO*!sahdcgXja<%q;x{i(Sg#F zayX#7$O;XJe5$LQz|MlO(YTBc?48a7C$1&m*OR}WC~?m%q4a)6p}TG&RA!h3ymovA zcm!T32GnZOimat<94LsoK!#2j>PsNa(8WO9>Vd(s>e7U2D^ZsOYG_v(uF`j!pgpZ? z1iA&@_Un{){$_r8n!e5m7Op~5$XPR>mAx%oJM95o*&T4@xyj+o4sjI|>dg5UMia5) z7o7=QS<3^4&+TPl2(y>31ELIHJTMd~tr%Ri66qf6%}zWrnu#41seD`5uHxO-|CQX0 zRKaHhZBiXR=$@U@t0`sYpn(}L<+YUoWLjvwV9h;U)K za!q_w@Hs^GmWYkwB2~$}9zs?gJ6l%W;Lx?9%^x{>rk<5YuPnlrLxA^cse=|UrZqZG zSXPPz(OtooxjFPWw8IIG8o0TV5LP~+sYV=NC|ab;X%+%ijN2Rc?!D#9{_KQu#}Z3J z0KGY=wOUvvIH>}%R6wyMh8y*)O03T+&ix7)^nGMJ(OFnG_+$|}5DJ;s!^aKXet|%_ z_@rRQyNaJ5gYm9v$Tc+D+U4drNWjmO0<>1&7)LAkipXbKpAm_u@HQE7*2U*4HkUFP zjmnX>6zf=wW6S%7|9kcQcmH|*DNl!;u&VW{1a1!kd0Pf5U$3V9^JOO!W5IU)wK1DjrvP zo3EpB{=3Q3ryK3f&c^ra>p!6MLrK{Oi6jXYJy0&hfY$qhd~}@q!+9|rbg(i3c$Z_+ zd5Q!)D6->mS*41iBDk%mJ~u&ENyQ$A(b&<6zTw_h=O(y+`1Em3!vU4l5) z0(oy#Qo?!uiNKYMCX_s$W~1aN>%(?WF^~z`sN~>TaFE5snwWAPI@j)t5#x~>Xk>=b z|2eh{M%$*COcn6?DjAd*O`AZWwfF=FI-U(LVL*g~gp@5wH7v*>lmj#?G*u_rB=3Cx zJ$iZx{kX)i^gPQBi*ENVj`Jx10+B3x$>XE1(7|%RrCsI5E0BI$$+Haq`*t=JW(23d z!yF6^2>f@q%g6&bZ~N6N`uiOm(~D^?GG+ZH`pn-%AA)b8BS*!tXiu3?bU#a@ho_Vi zm4xpnn3V&7%TFBC=J^oTn0~pB_}?Fvv&w;)iW5gU?RL*brmG%j;i{6e5y-r-GZjad z8s1wbg(o;Y-dmKR;Q-F*7zTuQ9uJ~*Z?=tPWpV+@wP;C-j7)A|k#q*X^yve!nVS{kZ>j1?U74$w` zr>w(*BmMS@IMh_KM#2vcBZ2P&%tfGb$s-Zi+|8KLr|9Sd3q3lq&ZzylMPA+wE(EtE zu{5tJucW|4;YY8uR}lDXU(yX5h6PH@K*C2B&<(H!zdXh16BlD$BR`5i3kLdOY0-*8 zv{T|BxvZ8#HmW}qShe2?WOLYk2W&EcBMZ53>1_(50gidzP)PzrkR_7>r%%BV>5fX3 zOlHdN@;s6Xwxfh|TzoPpO-u&+{7SBrd`@!lXV+s{lFfy?KAn#%&OZ&z9Mj@_a>zOx zUnXPDn~l5WAsRd@c+|h4$WZ-MK+xQqay7wBKPfMMj&2%{4G-&DO1q*-M^dPr9uZIN z2=^Y6Kllm<$0)^{^}o%B39zgQn#2V2A#rH2lz2 z?pgh^oPy+%iHop#FdGCyOC^YOl1*pEB^Bi&p!;uN|(G){EewCH1Kc$Q?n%F?nCowq2 zM%XVH@!m~t1!p6LiAWz4UYzusI*v{sBox%PgPhXs3z4%Sk56<=`)&8#-t)huZ{NLn z^IZJ*>Dz;MjuFe*DPDe1!yOp_IXydd?c5qdm~N3^*dm#@m84Bw8Q-V)ns4=IbhnDK zQqdOza^u$7scR5#$j^Lt;0n;<3PE16I*y)nsUp7x@=X$&Iy4m+Y^h2~@^UvIf`W!v zq(hB-qu|CARWF`}Se*sMU5G%9e$9(h5IEmYw9WltXV}ygK$Fb=?o<5_h`{D=>tfh259++*zxepU5c_uyy+T zu~fuZpXvx#919JmK-GDHBUS_J*Ky1~J9S*?1>*^#!q@Z!B$*J3{L6!L55y&rMei-@n(B&dIxqyaanxs3 zi`Y2_(rz!cF#H8I$lN#PrWYJ*AFGhEn+;uZ6-${Szu>GVr7$;L(h zhsK%$pz|>%XGJ*_!3){2(=z13WR9$w=JRqfI^<|?g;oH8XnTxz;WL>lqv*HG2`Yhk zo)hC*S|lB&8xs|&l(RVUeFteZs-(w^rAK)~iy5nOP>UoIRM-GBGW5Z`qP<#V_3R`R znA;NLGfF9F8OetNJEn*SU_9NAMi!Na4BV82=b>PSc z5DxL`K{1tG9%t7&89P3&YU~IYfhU<54BN2E3$*NOk?}D!$y%4u5jtyQO;a%;Mz$EM zZonS3QQ8rkrDENat2`a)LNZ#QDytzYRs7o%m_Y}(`YuMq;Ptp1?tK(x?6qYnzU;!7w*H*?LvQBu73&jvP< zZGDQ zmt`ccdwpHU>+0g!@J}PR9E$e@6=$*{BEDBDEY=e~YG(Hx%%73eTo~jSS)?iv^1cW6=B(0NVezvyCJi$t55v3e2I+gvCy6r0T zWhYZ#K2YRWf9O~;@41?C`;4Msi*tk4;yQQG`V`}ehX3`*?F8a4 z+>Iq$Wf1LYevGmx#ts*e^Ox%esm=7rrGw`2W~yf|m9uvfODDwOd_giOr$;a#JKcV< zX^@;wcCr*6q%s4YQYZa-g`ys}F;?RMWG0vhDJy^2wwekGh>LSd2<4>(nU*h(P{2<< zcmM0El`v9h?c$5N91|h6fZ1DH8{}Ceo5T0S0@$nkR4=SrJG`8IO^yxER1rf#%uX~u z&_HE~nKr1oB@(`vonBPb8^U#vBvg!O!6FgyScwtFc7}|J)$Lz{CxVmEtrv)3eNt}x z_G`jdjY99jeL+Tq9WZ{#aR~kI$wa34XM;kSa^vP%Nh8{hN%lBkvU%Z^Tpk@^;yao7#b4@NAV~Y9|0F#pGZ6rC zE6!qk_boMQSr1yLvM3*ZFq`jm%wNeJt65&=A8q)k-4WoeXnGAe#n7F7^NaYm1E*gL z92Z}Zh1dIrPlRR5VHTW%*;rPCGDkbcnXs+Gum2|qndZLDruG(eKUJ@M%v?-9kMKOv z{l83NksPFkT2ghb`xYL zB`Uqo+&Jw?(BGEu!s4Aip!=e!@$GANXad98#?f%u5lOp$y10@8Hvd{$G&OI+V?F;G zd7XkGk)KE$K~itw75++$&GK)7F{hIOw8h4=oQU&;uHc1EMkJjd3^0F=*pu03U9BZt zHNvh}?8+uIta1**NqJteDpcGDW&PP4ZNLFTlR4Q_ON9!p$5(VM*)btKwJxmsfI3*D zgOZ?j@glR&k^^^BbyW64N6n@)IX(IUpm{P>lis1_S%aSstEf zkN}5D$1TvT6OiHzoM)DhMwX{SU~S3i#fd_BEtk?FS&V0Ve};ZV$!UJ6kr}^;m6k6d zZDvs5YN?%VMO@15qyEa&z@wFQPALL+copSw$B6Rg5T00XE$LEnnMe_wZgLs0D%~STFz*>c!5hR}Qe_Y&5ziw7=SrF0KdV;1_Rzuqam>;ex3vqgY$>d#Uzn;UP zXo@cCy~c}8n3;Yy%%;s=LN>ONm8(6ZB>yPj=2^c#AL0H2-1gP}D|O8kGSOYa{ep(# zU5eTpHiDL(@7`A4_+oyJ#f0N1dpt&!Z6FF)!S|~*qzV0eq*LdHqrP=G@?&GoM44<) zT?-P1U&yOLwmx19M5zjl;EoXhmu5F+!PwX^9D0<8CvT@(T3<;>X%U?2Br|A)#I80; z8;&4aPN{g~L(ld%3T(Q)k4-6-ppZh)gt>6iA7-OT^}Tt`syz@*{b}Rv=GOYl_5<$a zpzK%c*?dsU)`2;^*-FWAXK(ji`fm5Pz1_d0TN_&s+8aN0MuTQ2c>_WMhvujF4bwSD z78Nx?z-H$q9%|6_Rvt?5u-Ey%PMomzcy^4x759v1clcY{A0EB&Z$;ekeII=3mwqek zm`=+MeWYEPX@XgnQ{M^D#)6-DFMc z%bepi#(kM}C9W2-QrHf#uzPc2m?W>#D<@QZxNC&s6}KYlrm})xDk6Py+lv75mpAX8 zrBD8Lu)F`&Bh~#!<9>_|RgPIV;S3thsW1W;8o!b5egaY)nkpMa(rd9!PI>{-F~Wty z3kya3rB5jx7e>!Atm|Q<7dYOIM){zCYH--f4)KsosiA=xCg)Q?tqTNZ@i?EgNR^lo z-^6{Q6PjvTNP(Gb*h}Y5%}l|xVx;~Iog&i;7!SexdQu(G(O=r*lCxfzT*a!MqQVHX z%Tm$nP%TwljVeEyyI8->paV(o!?0{6C&kAeJDDbENg>o(Xkd~<*Dm?2$t2TKI|zXa z?IJ%`&c@S8dM8B>iGVElkz~>B9o1UMbMPX9fDuJYB^u0Xe+Y;;%VBSMqIXC`MI$sV zaeGH@%G5t8mVX4r9pm_i#W-He1Zwh(VP@0k-LN!be3Yg z;xqqrUZD(9j!CI7E$7E4QbmrWZ~_uCYHp(2o8!szFSEflM9wMtr)lhIQr_8)Y|*Co zt>uU${E+lcH!J~&sHSMt4F{;w1e||K&dHqQak60>2#IgBvdk}qX_lddNhCTXJ>;F5 zv<*XJMdNEmXHSZo?<}w=F4eAMRc7^z8yZoAS9|k6!30-%mW}_H9Tw}?Z3CnHJ&eZx zqle=E-QRd{|G~y4#{b*c-25)Nf0F}^J^#z&|E)6ra2C5(2*~>Qj~g5JVX|TVw;tTP zfA{X)hcN$JoA>VhC;sCf@hltvap%b%Usg(Y6=|?E(5iJA5rfa_AOckVX)!^=hNB}g zzL&8eQAh&`mF>KR=iwm7(uaI)m#|eqWkiRpa^Vh%CJFNqX&49?-OHhPqWv$Wu0Z$k zZ}Va2dsAM4wi)mv>-D@6PHPwiF%VcTIZ(rTLZjmMSC9T(_ncMMKgY~oodeXbe^~vz z{tf=Wb${bO@n8RtXZiTAWH2W*d9)%U%e~FZUAZ}#i(W5CKVB@Kc+RuoX{AAvfuM-U z0&AE64a;&;X&Xtw82F5rVN`TF#Yod}VlH@!raQ%>GyU*(aT)jP2GE zc8O%fIpu579-dBm^}$-D)cctnh>{nZ;>4P0@mHK#rK1G}Zk2K9@igAD!ueluI8ZlC z*3)uwDS~C;KNOgvmF#|k%IGkd4R=3$6;Qd$~wP*+jWS2jooNek87LY?f?M&kSj2a7Do`IMXe6M4F8v`FUv20nxl^B2q3Kso<*69^QDP;OQ=NF;rB75AiIG zc%b#x#-x!TFY*K@4KZO&uZ8mk;I+}>>eCel?d;le3>N!~a6Z_=BSM(ZJS{=UkM|xE z!lHcp9s7dOZg0wBfMcIdn88pI8#GWA8H_Bm!eMz_^ttEkAu8!h+|47fv7;% zuH$^xxGhnJxhy9|K5)}x)}<8VMtrj=5r|nNhW5X&dCZIBAW`Ij42DBkz54K(Mtb$J zn;e($mYXAYW|ai?vzoa7y0V=|oN=guCU>@z&5-fFz&?2)F@HiC+5jV7yK=dXINW!{ zgn+iY222~}p1RHL@%h;f>Do)^9u#BlbCP+(t#B|OjV=?NUJJn? z2y_|Od`)R2IUI1+Vyhesw=y61#YJj%S((0(3LJ4UyaL7Z{#51Fm>{(TL%T;};x1g# z5g8C4g`nUUjVkMNEJiUUxs~&;8-3&zQe?C(^5@z`$gNnf@h<_M;~z;~E4!ungmL^d zbR;h2FQRLgwu!!-D36xhY_Jszh_;*I;*Q;6AhVldI`&(-7^QKA3=lbn>B8N@e8Lfz z<#WrN*qR~&?ZE=}wjpzChsy>O2J%@Gd6Nmz0jDN6F{X>nnqb0ELF zD4F<2%{WQ~R-+4C&`%$=Cf8owMylJuvTtx3AOuk(%`eO7fy_tL_ueaw&A$cz;PGjhxM+@VO&c+%edtDr?{pK358JMLoUlc~50^VQf1D%|Os^I9O9j(?I8 zM~^`hDk}J?iF>%}lo~akpXOTTAB-DRs{lARQlv%(}^X%JNCmN zkZK*B`<{ zg}7P_5|{xaR3}7n^;Nu$TeQ1EhH)A!*ZLx_=7i8_w2h7g{LK&?OqBS57vqSQiaWsN zDT6cb;x%2rm`EROZA2z+WPL(0w%ldOBuraPIS_k+*Nli2*<&>>jNFKvwUYkj(#oZM zl=Uf8dacGB)yD{N>2ZXHu13Mzh&AU-mPO5ov{b=&kqI`dhC^NmG!rVntXBL*XN6=0 zf@X#`)fqW!7xCir*}~;*7nkPjw}fhjar48rY1B>y`zKiuI3@Ug?W*I8m_%5FUxrus zH9rPe0%l5#@r9aU+rXE@f-zp7IdN~o9pTOZzez1l^&!ftTJ@aj<1*cE1o;z>9(@?c zX@%PUU@1513PY@BAadgnyWMi!7geKt!-K&Gu7=}*i?%}?@bD}bE=xKvJSOoV6})R# z>)StE*EB3_+iF~>y~-|xpO6u#hfN`rn_p6Wn&N}XzourE@$&@v5%g}Hd)U-H0 zM)MRo5Rp@-61}LjYR1Tn%OQ2<<0PxBP92r#R!@=w_TtB?lkAKW_I;{`I4DFpumUn# zt&%n99QT*Hnkita$7?Nt6p-I470XMj=Mf6@Jv+*i`D7yLrSA4iCr(jJjVX%f4|?|{rhhE^!@%Xdv9K+*scBKwsG-gr-#~+L?nWPFT;4r z(wdi<2}&DU%N3UymC4x?m!P;Elk}g^jv^c?OmOpYzZ`>X%Mn0&ZZPD}YeJJZV+ERdU*APl4qP=c6$P%MigD@K7R18x7~l2^vOk zLhJqZYx?T#!MolgV5Go#QLC0xfRD;pk-S0=^Gj$kwPbWB@fRwafV-x0Sx83cUp6D2 z8j>zpa7Q_T`APUNZ``|hY9qhNJKKQ+fftrE%zMbRgg$Ar5-WTPI>H97ZVrLQP8Wyr zgk{{u zX3`)|u*x5;2!fh?&x^tA1Ovpqesf?1XkcMm+J5)sepkrtP{7f4Eo@{)ToMDfz}iB? zJKz(CAaH&{i=$aN$S#$K$t4uAS*Zvot+;U`qcAxX+Ha8D`)U2&pW9^6W(eyl$WI_b z<|Ly?w6cp$$#Aoo8MzvRQ4&|?70j~NY2NQ=rzSALgNXB~m2Iz3TT+(BBJuM}4JmL< zQfJ!s_ihoP^NbaWlN9kWlDkEqBfHaI-}K6xwXuvI1-fY<*4E4#LW=B~qwi^&n1(`u zaW6vED7#P?^7sq6+uO6>q<2ow4Gn%kLGOVLD5fLdoOW6sf;B?5L~CepL1%r9EGZ*rr8N*HE4rR-C3;L%4`-W8ul*>gLq@ zqHYd-J2Vp+j#O@#xS&jI_K)uYeakdHp>Eq4Hxe%!$y>36t5#75KKlcP9UTuEjg3yn z#A7%dlDIHPzeLQTnqS`u12OT|d`qGmXxXNKc;mk5PSY{q<#|MD&7N3+Qz%{u{J;5x(q^d&8CocnQlH0dmnTzk$d*e*bSPa|~4}+_Y#-n*qezhj#87 zfNSBM+rYGW%AMrCrPZp1Vwxu;7G!`^-;WSVmGy#+$%co$J3RYMW3=$QabLdF-FLCO z#DbfMOjMQNG$~(grN%WDUy4#TkkyuMKaC*f%i71*(6yMq*TjW7UG1k)Y91Gy=lY7E3J!@ zxNZ03CZ}b?9Ku4LQVnBxTgO);|d)g!s7~A_S=GU%#yS^2VoiJ zvV{Y8clz`z*dD@Ig2A6;FDo2N=?@7v44BaE#YclkU2lrrk zFUiwg^A)Ky)3^!O4qC7*TbYe6mMtBSnP`wC!Y#=QBlby6F$ec>W38nHtu1s#?EZW@ z%|(_#Y0km1P*o4lnkS%ug)H+-qxP*-n9Ob#?qeGhz#k1h!H)(1kH1(hz$ z#Pt#0yMfS668F|mD1qUh4{+Ml@7wSncj|s<=)QH>u)>tjlE>R_GfT*e2FN;{<(4BK zZf;;dZ2?jCd{vRrry|PtT=6OtqY)=`zHCT&oI(j~Q50tJ!5c?m*wMJ&WnQyu0_1zn z4N4*;E-&#~#59VaOCE~C#}Iy0rVm55EivIK>xZEI1!W;UrnEn(ADtfOXoLW~s7;}> z&Da-9E+G&B{=AT}UVjm7`76@CblXmTdT^tQ%mR-KZbPsts}Tw}eN9V<>zF`%1Jj2m z9FSTjiHlo62>PK={)6HemRHM!!<>GG5zGq*eKH0ZVymT$p!gnw;=hfPCvOgZ@z#Su z;tjb#JX@h=$C>syD%sS{iMZ;edtGsf8@aJ1o&*2+Gv5yRtTD#a!hF*0h~tbS6DTK` zWt^tqXR1OA)?BJyg5}zl-J*6M7HBUF$o}1vkJ&qt9Gf;p;Q(Pkp1+N6IUESnN_qcG zh8R11Xx&80@EF1szy0M?}SrGsE?#6?APWS*JY5$4Bh*LV8n7;?EXTns*xfC9UTrYTME`rb()PbkyV8A z{#I;w#8Pe2lZaEvzIxd8Y(Q3kJxZRHPkRImD(AS9w|n|KM#7zB(`-~>f^z&9&`UVhTB3b8D35Xx+19Ye$R`A1Jq)_j*ud$K$e^6@4F8uKMJBfT4Tum>j*=NVEP+LDk*|Ns`eI zsiIY{2-BYT`s`F7UXG^Q4W(wOk2@T6A_*qF{Mncw>4=Zi$kKBAlOz zEQJk=QG>F>$kHY;{`~w?kk|wuA5z>d-6^CG5(|r)Sp>Vu8_JXTbAYb>-iSOogs3E( zEl1fq0a269Q%lCrLM?oLHd<@iGlTQ&lS;RXS)kr=fa?MKe3PNsOF^>{tEzw7Q1}0N z0?*R%|0Qp|@%aDuHtuhc{CD@^-FtU89#Z~~2U~alBmeyo&$9C0Z?%G*NGv9W5iJIC zYI`FG07iZ%Mdf>)+@wC#z@)t0mHU%iluyn^%TZ$A;4?FRe;9uFTJK znFBD%j?lp(GopzQK=Pbm8B&R%sQZMWvCX%TpQdx*${?@|3kt&AeZO`80n1I*Np=@R zpl7U!N`55+ZTRYlI&R(oy%DRNW*|^VdkB8vX4LvzmtBA?hRoEe{64l3d_J0{FafhH z9pVLGHf$v?_g+1DnEvhk%k=4+-RIA-mAz-XsryupDr!9+dC?nYy*Sm$Eq|_sR<56SlfzO59U`mU z@Ekd}Q${j8oLU^fHV+}tO;x7Bi7%*KH-L?-CTwAjhQLYfta}1Thcx|F$1K>0Mr_iP zvb}g@gcOnGgYM{HmeDLvI7%BFe%UPi$Qh6qwHXjnm95K7gVP*|9|%W zwX2OR*&l?@>-rQ~^g3?IB?(DjyIL;%e<+M?rohmE-4{2VBvJxdNJ^Db;!>Ei=GC)i z-p-n}<^#<)IiF}EWpVsOwBjwJ0jU788cEm3V-oHwE@m!VYf{v>sy?Zn5 z!+gZ2pzGzgzE$36(0s|u9UL$m!DKpt%WmB1mI)n+-b8BAF78FQpvnbFC1q+xw+MsT za0wp>m7Qi+6!j$F&3kq_5y`5@GgI*92uvkYHk;SK+NC{dR?XKukMms@$g_5bJ6{5qKrrf$!S0|RphM$}qho7?uojT&~1;b9ck0nP| zVr9MnyKfo=gt1EIN=Ch=YKD-F)5~~>#xGU$)AZYy!Akq+l`CH=oly&4-Ye@|FB(Y} z4r#LlpFihEQ3PK(N+cLOp|E5WV_&QSdVwRo9sD}i1@4!p+XN)!0$i5qq2h8t_u1H1 zGNCuSDJ;w6+b@HE*ql$)VFg<27T8My729dXeiJxR=B^d*ukURYf@zXHaxHkGWCi;% zU5d!ZY-u+io1QGHnE7K#^a!ZKosKl%SIn0hx?HZeC@)HF#g-oJl0sgTMa5SK-@|0% zs{4K}@2Dv1ctDG=*^uZ{?zsa|DoG6brBbi2DIP)CRh7>^=zVsC=>&3f!duD`0V)nX ztw?!T&>1^aU<4!vkGtslALvcuZYQ!R*JFeu99^vTY*&3I37Nc_Nh#GUyyytsBdo^Cxhq=*i$d1gJKe)6@_+CeKd|w zlWQP-X)p&0I!$0vD>yE*8m@SpRcnS@kxtq1@rOXIM+H5AgDdnFl13|o0ic0x{{S{2 zNdMyz@cW5^Q_+U1UOeijH|#X87%cYO8ro}J3UgPYi_Kt)SR{Cvm{Ahkj9`yOFoA@6 zM9DD5J%&|`EnEdmb)_<3Qg4zT;eVKgdTBRXhB=GJh(NIXdUJ1k_isBWfvmrWMSH(N zf=IZ(d9b(p{$R5)=-Cb}G>ahG00rbpRL!fPkGwQ@d6EB3Y3%t&#Sw_ZUgdLT7!BY+ z3#*@lr}$^EwiYa@J}i0OlRoOO*ykWXkh$;*vx#)0G36O8eY^ECH)26`X!3}Mmmo~3$pMmdh6;KG5i53E*{&v84-G&;#{mT9ifa@IaxZ#^SGX~ z@z-gA>X$9IIs5&J>^SdV#EhCgU#&JKsb&RkK(1YbssIF*dCIGqHQVTPzFTR(n(?NO zWg6nFGVUx~G3T2cXQ8o`bFYvOxVeY(_%Nhqz}Bt?Yp*0S$@PPc!a;2-dwcMw+Y9kUf zU_I)s&q0Nj1%3sFPk*XsZsdxF0IIyF8*%(^waC(0Y&!KCOlx^*_x?6i*LZ48ZO*1s z(^ar`UCZgnRR__;(>t%-4@;Br3k;cQN$^(a z!6&HoNJjzX>LDi#!_W#%=L>0bEyuWbf?1|mOx#eR>~S8WY(cIJcRP6v!Hn6wHnRiN ztP|=bVunM!;6&xXsm+VIVdIzp*{Oy_!fI7A6Bl8RKmzES#tlI~d2s5Z!F4aNp?0}U*fT)?(& zS`An$=k0@TSU;9Rjt=_CK}Di*u4p9EWcTsn9m$Lb{gi?yzQ;_y=&M~cDqDe_PRNOf zyLF;jL*-yHCbvUjpFw+0^%d!a4t{*YbVBm%Ve_#sLz!MUfj`AiU~55Py{i8FYb-rk zu2u!u&{F6&2~uIFNvkDgNLD_R8|1|2im-w>*9qnqjeq@qG(vnf;d^N|fH(ZZl!sf# z*%olaz6vK%((eR6qT+?&r;PYsqo`tjX{|*esq(?tcwjJoqsCoy@?;$?vb$>Z5h|G^ zee`JC>u+n~S0jLy)lg&q`06q-bU~N?{%{<}JJBe(h;K~n zcb9HXM25ZO)JsBZUf@Lh0Er8ICNIVYXo@a)Px4?KPAFTKd)ws^IrJ%CO~%f{oGiIf zcwfd(gAB4*dU`@}J9fYPWKS>pNZ(vc0osl(Gy^wj->ddgIa#R;wA$mYj zWwd251Ls6|grA{vk%CP&gT>3Rh(v9|%rX>pWh!y8b{J{|IS=ekr>MTk_$CC}3`;okn1vUw7lU zm&v92M`6XHG6Ql#P)z0a&LohkCnuWx6pqLHhIvk#A2%OBWvTvl2~7+c9oHCFo|79m za?OKiB|kEIfk2Ei=13rgCBAdp{1mUO{J`-rh=2r^@PI~}iJFJ-Ho0>(A#V+S!74EX zs5vT$fVYArGJ^%2xnvceD@oY$;c# zM=&_aW!Z66UXStAxG%Mp6uJxp(gpPbbd%3P)Mz%kgHh$lNu%l7$o%?^qt{qnaT_x- z-Uz!ySPRJ2DHu|$6dLxd@6{p&zTie0WEc~%tL86-{bFlFK>=hvSjd+#&Q~TpNnCh9 zt1;{rUqVPKGD=s!gf{3WbUeWPlxx=4@Xd|4AlWMNb5vT^Ggsd7o;mYv&+_EdhVhqK zt;7wgG3%|mio9YhYlS`$G?9#5N3n)0^`z0(}}V&niv1G zUzo22nBGo-rGyJ8X!6Bc&vWHjCyd$Le=3_3$O$_KJK^5?)_$45&@4D?jGltX0X1T~zS=0LH#-MK;)0bTTp9^D0n1{f?3rV>(Inv>q-<=p=eNk*(kxqs z-=ZhEbjk=ZX0-CPbe^dy?-^x$W(OhnbUhSyYk1Dd(5vcUpB8-FMFhqi3Iq+2@$oWglk+ zWH#u=**N0s6uQkAr$SNcN7)39<19HF#*|i}a88WtwVB@gg*efj+-1sahc8xTjamd&4keMg+WR74H!O+MsUKVE} zVEK19bC8% zS&kp~aWY!a^H^nOjb93Z%}yi z;(uKHe71bwHW20GMKS&xei;9w{o=*y%5%hjYd(MeAHlQ79B9$!e>ncfBI|!&48T(S zmz8F#)ocs=7g+gcEyRCmy=ea%|K*qX%!~g*ISMd-W`yP|1k4ktctPc05|4ssXbGfn zk!ajKPbR?X;qY7D*?PObez>*!zA@-k9UK@SCrki7NYGs(3yud#?-Wi)MUX&#h$&}~ zUZ*2qvAG+Ji-!_({p6-jV1&sq_}jG47<=c**?GMW+GbxkCE{tEWF6IuAZRs=SX0I7 zf10A1ub-fY*D-!cDABlhr`-tl5viJNEp<34>J+1QtgNRYIb#gsUV^6(rdc{hkquAc zgsv{5iKr?dLvM06%z_vla|}lYN?XjP#|*EhSh~Yo)F^|MB5yc2KzrnKKe^Er(%ok| zPR{U2oqV(c5VgoHS&d<(5o|(BI9Jr4j()$65ma>%7nB9k-okx>Rk{wI2I(L^i~b3Z zj>)}@&7wV+uVmOY#un(eF~=(BYo^r4H$2CU!e)=JTgTAk6*{$WM(ATq3kg#Zk{fJ2 zXdPQ`Z>TqaLV@j5c63bsKgS}u5WGphVTyD3yWm}xYLA1j8Y!(%o z1X@x=Rm0(I3;UEgYFd9FT`}|tjAq5|EfHNNP=PT3%vgDB`xuS27^FFtxfG6hVUMp@ z<-F9)CdoW~OtSs4%&3d>k4{fi+-e?i-f*}-KOH6T_44g83W&NlXwiqk)d`55?$-Iv zUf^*~_(I)mo?qab0;srxP}@`&_6VDJicV_RE6`x|So4ARDH>0V4f&LIuCW1uqWaUG zi1x!R4pj8BY|m5Q)43mvYu3zdV}dM)Cjg<5K>-M6{e$@!i$A* zU)+ZrpI5G{$1iOTf`N5{8;CeX$_=6Gl4?(&QAUr4)9?oCqAq6e6E0C*{>nVf7&b1B zs!xQttH?BL^SIK2nZN$$5UNy@fzVy)xM5BC8%+C-lwHp#DK*kMF839?k5M@0F^1q@ zkB$)r9Cs-OO?C-Ai#L?&Nd<@_41*j1 z*8Q9hdncUfW{bqf8o2_^U zq*J3NyRo~!_u&8zMPBWw7mai-Y^sPnI*{BH0IuM`bn(N~Fi3HS46sueAPeinw@WxU zyloEJTos+&l6+w^5tKS1-}a`1!A+g^+wy6Ag;6Y$5U{25=rTd*F4?JGj3-+%L{{I` zCsExvi401@GfM}%GHU_Jfq~mhjv*Mv2Js@`6F&)(A8g=c~3$_`&#@M1@v%AO6+}l9PJadTBhIfWNaTy|Q4f<{cs9US83bM`8 zM&IC^>|}!jbRva1yV(wv+h;TY;ioMxarl|&e(<)n{u*O&_dXo@EUFqBE`KW=>}?!` z2Ztb-ZD1OPAGY4V<#Y@+uYuOM?lF80B+i^pn+)CmGg8t)Ivryun~??T?})@D@P0w$ ztUuldtNWOj+!~MF%vZ}4On`@e-<1_RBn>Lgj601t^RbeYSQdC1Tpv?Kz|Fe-C>aFD zByb4k&WVGRWDT+*oDP}gK8@S^cy}1@C2=?Ax+LZ)1VkH|q*@Psya6AX#bGROK6nKoMhIyo&lgoScs01o}N( zMs)gSybWxR1qA&jKI#y!An;zCw%ph@q`VL?+#op`5RQ$pDmB%4W~*2+<$qA=!!dNi z?x-_fqca55;-q)?WP4Xl=B@-C``)E_6=x)8w-J4OT9#Z!aeJ-G;3i(C_jiPnNH_%( zAu%yN1RcD~e)SQt%9mAbs6f(}n=tC1fl3r5U3R!4wx5w;%4tHT^5i$rh3Evz2r^VC zg{tFxw&`=0P2?}BIsqG^(yGxFfwEVts&Hdx7s+TuDQ>!v#A@kIK@=QNO`d&h3Vg}f z<`lR^Wh-VNQR6Ec!btR>BA}=J=O7-O@DPtfq8s$pBpQ}6>>Qg+HFeCVP5^5om!GhK zmmT6w{i74bs`82JU&w7Sqod|CPlf@#l!+r~pgLc*Dzkh*VQRPQ?V!Tui)k;JEWcad z-fe4ChW*WtTbq9g+s*d#dh=VfWgxuB)ld)#a6Va)lGZYikcShHdQ(!E%#{)FJE+vc z*{m)#cJ>bUkI@ULAIsV<;u!P8iq$n(4Dne!HQnb4<%-3`v@w7m~Klre>x4VD1`C8l&;a^+tL7;fQu_=B+Dfbxb zH`}eLEKag6P&+a28zHFBO?tHv>?Ld@p%^>Zd@OO1%v}?aF=Q>FHJ24}aNNZ(y#mbw z=h(ohLUk|2WIkfgFmb@1Kp{&^udF9GMI2Hyh%RCQOU$_-g5EeC1(@3bHoiRh8fqt; zwbacP>;S=wIkJtewOJgjEV=8iE*5Y#6ctmqt7tkQFAbd(Q|}xZ1B{X0PsDH4S-@Lt zguw+5zFxEX{MktHDSKgycbG6h5XzRIlS=6NPA&0--*Oe5|8ZM&zlqZH$XmYToCfKz(c1@ z$dzFlQ23yfOD(GtHpyMV^M7&`v-nK)kU4`R*=p>BJLIw8Mu>-)n)fp1{A(PHgt>Nt z{kYDOwyMV(6{+}B1sta&9yv)QK#b#45=2rSLd3&L#@#9G7#*dk<^}j-LKus3>#=S4 zx>YADB=n#cUsKI^X3|>qVLZlJ+KXXfdKm`!B%sBCd~&}%MZ2d=q@eO7Y=mGIy;Xf&)aFA3+txL8TCjFg<3qd=s?crcpWSoueR)TiTNo*f#ej#`6{OVKl2vfuw$H`IwgF0h#4Q6h%kRnF=u!WB&N~fG!bH(v< z0c6w3*_J>YnT~_cp5JlV`~eS*ywALicVz+_7VZo=*XWQOS{l&5>P#bXf6*B=W>UHf z%V#!46Xy7^S25p^TRgW1G|v`)*@&Plal>g;6VFND_G~~DvF&b{Oweua(^IVTNVRIR zM*@G6<^9UDTiq|OA#0sR9gQS9tOX@E-XR)2D$ZeQY#2SPIjef&&XcIj7bsM$4dd?S4)H33O7RBZN;pG&GHI+-H-I(0J70Qjx+e9~sgwp3aV{62tgr z(Wp=RrkPR|0gbV)iUK0X1LK?QlB%SAbqvlqdFHjK6VPnWWl6!srnDFLrfes(uX&9r zVBmU=BSc7nx5-TSSL&5(9&~JX$TmCj5*E zWNRQM4N=U7fBSTLt?^7-fp0tupPA`lV%_EValcf5!*;C8msY1l;eesApyI?1MwpIzcxd>0*JR4*(I3yPlgaGRE4z@lk-k7>ky%nQSh z=jq5B4857>EHz-$?sa^M3aEeXd8jxeqX?SpaPi{|B?Vk$ahb`JTROBHY~-gW-tjqb z8o76Q?(^@K^n2U7>7Pjj!fo0LXaA72)l{?(?`m zgY@*PB2Nw(2r!)_{fs<0#GpcQVU$*Z<63|?Pv~fi?u&`=Jv?@O8;?~65CJB(k0@H` zQd|8}o@3Ncf0PZSHzj9{sx^2}kQ9Gj6ZvIpYHh=PZanbs_ z?oM08;1sauQy9%tEAB#IU!rp;BE_jF3{?aBubB}Ocx}i%$4Nr%4a=efmN7q8#&*l8 zjD5$V3FELB^T6H0>&vXri%e>s)1iLRL-Q0&kYC!opVP6Qx`S4y)d|kVDX8q~3gpDR zvSyD!rV(uD)3I{3`#1OoyCv|QBl|y8Yw(;v`tcrkm=5dgZ8%Xg z#)dUFG+;R(uN0)z3MHU&X`C;S@&2^NUfL02wA9$sLSN+;w5YFZ*=Ni3)b3z)#`-1f zaWIbQu9u7w3ctt*Tv;~8#CN;W$fs`032u*E&h@Gt8pKLh;7Ey@ zWqc~GW^>Qk-@97VuHb}$i;gYhKW2R0OP<`q_t^F8@{&+RnVIFqrgG=f8&&5>4&GuX zZ4%>D6&K{2PH@6lz%UzV|00tbLbi0%$e4Z&AAQ1nC zt@nz+&oykcVeCt4!B1rDb6jMMD^=rM6$pyd5|s=G7(6VK2T{TUyd#x7_bDYSkY>D} z=&!1CPE#Tg6raUXR`DA3YyN_`V3P=z9VH$)4+S}4#2ce&c3v?G+fu20(SmV(nB?fV z;&UIxAQLg+oJk61JV4c!4Dmp+uzojgedxqHgqcMT1!XeCWu0ZbKgJssw>I(}xQex( z96CP=q~;#5Bn)U!qB*SAxrDnWvHqo79dUnHLxw>{dwPaUB+|Z`mAG-%kZzc!n_F(2 zw%c1)1v)&V0G8~W+^_Rady&!CW+P7nAuTLjNe^AbM4607kRB~E((Yy4{rZz$?IY8- zN(yXpi+vahNY!#CP2RE=pRxBDar%zhT16X66ExQNMDQ_9wu$6jB9p>*YoN2)R4u3C zr86Yi#*-0NEh1j*S8)qbM~xjca(5nnxDd_fsBo{iGf82Q^62uNT*~{&;qad66bM{4 zXDwn@$Y0`XI*QH;=2cJ36B?UmVq^`o=7z9vaAtDSnftM1CuDklTb7oGM)?AFGpAql zNy<^{(=(FkOet4HKw4)yUydbp^*hRa><-SS9>sp5hdjDTkW`E!ijsI6!3G2A)2R*u z9%uyq*99rBtrZ-rMn|h$_Sij-BOa727UFQI7JQ#(z^KG@JiK^QbXmL}v#c zYwg0Gv_9kZ7A+e0fw|U1>Lg?9U~?=Km~DOPHF7$d-V$mv8hSk|@I7rh37%5VEN@e_ zV;);)-!jhe1C)i0`1ObD?Zt8OUqJbuKio)10BsH@W!kEU#Xr{W1IKt;Q(P^+g8HGl zrpzgvZ(F9;S~0J?t23jGHtC8u>J#dr2npBS_@r7rI<~`)gz${J>y^@0H_U|`#~Fx5 zGBg%d9&>rfy}`t9UnGtzM@@QWL2!YMVY^)8pokanoa*87^e1C2)7bMRYT%(dtNBXL z;cKDqX_1YkBMq^jls)56$42x_a~o1ndX+N(l+K+t16W&0@+GBKD%G9XcQj5i)RfR4 zmuDVGP?=wjrBcsDW37kh)O)Ggzf|7K@paTi5!{Lq$>KqTDmJVLS9FCUc_l-wLR8cj z(Xi;;gg@&=sM6K>Os^ilGFnJ40YQzlI*hn#G#3t{QBXlaI;O3Q_cv3Qv?%sp)+E3+ zgiA*8>q=v?MLWA`p_!_XJMH3I)7#FgsLJ|`&V&fWS|Ea}lS+DjDDB2Rfkbt^YjxXV zHy{r+>DyNMJo+3w9g!wWF(FzZ^=PySX)}pmjVaJxbe1eFm8ywHzyYBb7OC1&eUu@wZgt8( zMd&+*j!Fus1oWUiM*i}w%d(ZssjM)3i+h>*)Yrt@t)DN#Y|`r|C&4jCO`_3ma$W_Y zStKaKw+8xLl*$M1BDXp@dKp0jY&}bZ=xiLvFF8ExDv|l=$?{AA()rvS7&8!&Eu@36&kRw+I=}7^d4%9kP2>cDx11x1Py5Sfw84Fv9 zs%{mz)Lk<02jg)>P<-)rsF=CVMU4tO&~OaG!Xd{I!9JmrCmt_HqlB}=<4`LnRsUu* z;#%-5M7yIA;DW)SLpGb%86b)J#|B_|R+&o>kIh_H+Oos&0j#?TV0hYGN*2Hk=hjA= z7B3*tQHLe3S8GALc-AQ2+1O1XLQ<{GR4ksQ1T732A|F9A;$ayf0lC#xG@}q5#T_9n z^-}&2o1#i4yEy8hB9bFBVpYO=KH&B8YQv&u${u-)2Fc^Rol%Sl%|Hz{k7MQT-V(L- zlT%m`;BIa`h(j|@7}10x$tZ|Sa}wbaD-0aNOPKVCU>Wix)}10bNK_irR7&^eHVZQk zN6D|z#hsGIz|qoZd1QkGg@Xi-MI~7Hj7l?;R$%?@PiC`6BDl5T_v66NlG2X?{{bt6 zA);Q`Wv6|dRy>95I8FKS2pf58Bz|mzx|kd`C#qR^nJ?2eB^=V(4I`&7se&V$umM=h zAHou>+B}k`Vb#EqiAL%gG)ZJ`qsZL7h$oh&#qpU^pQ^JcOlWh2uya6hZn7RivEn)~ z`6rNTJ^~Tr7EC^ zt$Gwx3Ofy5VB8R+ypX$tsk8PYlp-Q`(C|(pH!s415{d`|W+14sy>y30OJcb0(Xt>o zSA1DjS2C)!VH;%+uDn51b_19_#XwoD`P5L-LPv=?J!W0jP(I-i0@c!S_7uA4yH7HM zJBYdZ4Si~@{gDTLz#E``t3$bzbh`w!*6HwIj6hA}GS9!YS3#GUj)#UWPhJV6ZE=QI zEmxrviI4*E3{pmpEK`;Y;quxsgc`Jsh}B- zMmWcrWBPF6bqKSV*T;IJ*J?Q~0`6d54foq2)USRF8@Vxg6$P zgm|^HR2gpBpGLbp$tzufIOQhR)~IvW3UpEQsV)&4G@4a3l&Vpzb()=noeXg!knd#d z9muF7?mY9wgW{CO!qfr-yc(n4$jBPhbL-ATxLC=6TC@?XeO4hT$WE@YGLx{n+~YWX z3t9nF{!*1jn5U39T)JZcN2D$dfemngeZ_tKQ*tCOAcI6@dL(5Ii2PGZNx+C)VdC&l ztB+Jj?$0K5^JU=gpt(CmRj@ln{j@u|$E6NUMV+#CkTw>JKwPV01vTKC2$?O-7Y}dJ zK~1BQ~yZqlep=IzIV;=N-Yn-)aKkOLiN8=_e!3p&uhq+Qi z=U={$vHcUtK#B@%ayBIwINN<7cZISTU|Y!!LTA)93kFUEgzE*BeOyBW0{N8Z@4~&1 zAkh`ijjQ+~e{=C>(YmZ$qwTq2jOXYK`QOAc36p6ut_!c`xR-M#2r4)SoemO*?sQhw zQgW$d#uFGqO+>l4V`gF!(IJ|V%?@UlP8U@jvP!a^-!WB3ne*usogy%q>0?ZRVd(bb z&mN4J3Hz`Y9ChC(gd1Z6E zo{QV&L$2DE!|8e=J1VToU;FTJ!IHcboX#*)RtvsQLrB&yQ+GQ7SN z(Y|toBGp&V9kP5T0aVnCg=qtWS^Pa}G?u~>bXcR*x3b!uFq zoHI)`8{<}-)AWo^=4y4W%0@{+O`}9tW7Xq1x7E4FvL~F{($5X3k&wLUCZ3Zi$t!=n z(k2JXt-X5t*~$wu&k5=!;&7M0h0;^t*E`~c!d@zxYX$DXfW%md1wbAOH|LTFWZTD0 zO<9ps8(V)9_Qy2M1a@o*6;qK{=D=phm=xFJ8Jk_5>c01InQMbvw*&cOXU2hppGEdF zWs+iK`n`<<*atfYI|YXhO^%~N%(}ML^Wojf*rW=86$=TQTTgo7rFD75>K*1h-a+bt z%-~9b&xxMQ+wdqcTD20{%xGD1G2N`)u4HDL6o_J|7IlZG2}eQni9yFMP<%6TU56-rfVuE9A3rt+9w8cTeI=u@soo&lxUc;q`OnT&UH`f)E z3}gcObh7tInc2|vs3DU*VHfcb8}x$*BsbU`kJawA`oDC0mp{QMahX_b`}pD`O`Tdq z|I3ml^;EnRw+U+Mu@xu820yajPM8gTsDcKW9DEOG#u`A~#$r|No6X&eN=2KzJ__V>C)a8*bzTc1{0a( z`1|dHR=d9Pt(+VljP^$E(F`2!rj(JHW0}>uc zRGXT^n#lQwBeG0TS#X~8U=2)Q4?BO6oghV@JFZz&F+sylQ_Kw?U9Mv`igqHIRQicG zLD_6hYM6LDh9@(vfRI46M5f~J)~voXCg~*V<9ravrUC!0cq9Abf4yde@XgQN^1?ZT zc>?31K!uL6nWSMDcoh+71^sRLJ?^aN0mz54D=t5?J6*(>=oZX9HfUlBhN~}1O~T!pJ@&-ql9{!!7hj8@8znd6Z6-Xdu%o~e_X?;M422H? z+4_~bLC3P|(B)bex#~{Y3m#ttZqT^j?2@luiNMe8SeJV&o^>tj2p5wR_+H(isH9}* zy}{T~Ix~gh9wnUPbm*uCSew`!C7dC5g@T8bRgs;SO1dQH)e!E;F?*gP0IRGHhXzw9 zzXriU*nFDw!e-^V8hjJnJUs|o_`Sv78;wR#*M%$RVG~ob{ zv>{8rnWFcoNP2`OcUJQx>OaatB0FqPqBt2_2CqIw9${8<|~vLw=i(Pxen7ri3kl!X{CI{2AvM$xF^yv(e;v! zb;Mg2(p{)vc*^L-_dTRcK9LN0Ge7y{ZeuCXo22|3uqPC4$-q_Qo!u&h_Wa1J6b#bWLjLW-C^}=*AaZKb-HEP~!F0gsKkFpQYO*ED zh`Qr6V~{8#F2x{Oe3J?Hz62{zoF|{W=Z%k2#i>xfv<5AF_HHoqv^NUdX;iMwdfD4E zOvja`nnTL*D&wn9iQQvPsk6n^b9i8H?8gmPYO%n(jdNndz6trWHY5)43A z!R&TzCXt-NaS`Sz#k>#~ZqIoug>0CL zi-yWzCK(c+(Q@ro(wm%%OjA1Z!B6Cbqfc|(APD_}29Y!!vA&m0NAbAI zLFmDs!_AND+u{E1_I7yqZh!OO-R|~lA@~9ftiBYMHg#mmScSHr^jWh)fm7wDl0{q4I^{4N zr^u1mLdF3CM)(hTN=8_y-*-kRO_rD!OaE>%217?NDn{-=tyvjzOc$RdVc z8~wD4HV2vTywhPDhG24chV@eoL3hrXAg0i-ybPycF2z(Tq!Ky}NW8$~GDBNV_q@(2 z#AH4>mPE!z?sV7i!+R<;i`?hv=l zU*I5)gm*Zb?nG+fVH(KGm_&uc%L--C>(3ZrJ?zy4pr3*)MMPb+)>ZMURN6+#{Tr$! zNkrBpt&qYldO+#_u#0tI>c|42jb4CR=rP^=?e@Ea+WxzPJB}8PhZqQKCSp}^tjX{c zD*&#VP00~YbpzOcJffT=H|AZ*C>m!mMsTsMNa>Tud&0802eZ@ZNK?&ma5lxr>q#6_ zI8{H6*u^y1_T^1CV@J^Ji8&O<7+ixbzLY`O$;1l8RYApqfkZ(sK8>b*0brBMAS0*& zWCa6UdTAyok4$FSb4lYRCvv3FmDJ4I!m@jQWr1LptpyD#OerU^n0EBIt=dWTkd9fH zvbmWwLp{k1qm$oT9J4%%3iu_{6`c%8Fp+MCFX<;6dgD>lVBMW1YS!W%2z5E{pqzVq zzA=B;pr@Q2Hb`#O;=H7DJ*4;9vv>}%6oc;kL-J*cG(FfE$F%sUrc=br!gGlut!mXs ztDilm>r?$)gkj93J{dmft|Ey}>pA7p%B9P5C}+HkW8(+<$KKMJ#MtvJqH{BL-3mDu zl6=KO%sf16RJsB@-3TyO3=ofD*p0|81!h7fv_<7|%4#DWczh0;m1!shkY+Y^cZk0> zf*;~|Bwmg&y!4t~5YZeLLH!tsX4ax#rK>8AXCq9B5z4dOWP~?&$xxaB&0A(!4X=%u z7K4vT%8MuRVZqL{_Bwm%9iOOb`pbFJnLvJgP;Kv^O%?2no7)tIEC zw4a{cFfb;Sp=uOj86&kUE@9v?H%3><8HF^@eV(VG(>SH|e(Fg9|KAKx-u`|;heO!-b>5Ak4x*C8AOLkbRAq9nnAfAK#f;lETF!5<$K94Yy zAOB!oe~Q_9W!Pt0?QiQR2o4=(7eqnFvib_M<|+ZHIWSrs^}Z^899+O*EPX04f9G*G zPWqMiA9lj;w+;`MzpXB}fvj84kAag<;!IT`7JGXW&jWRzDez&foDN(sbUA=73p)`T z!VdR8yx$0S)(?IN;W11f%r`W))Vw~O@mbQM*q7IBL206BLcKiA}OTd8L^dJgSw) zOq1&E`uo2LuLn8I?)YXjNzXuhL^4cxyEpAqI!p|^lvpsb zE{_fzRK$Y5TEh(OI7U){acB|(A~M`KPNrwSwwhZ+FZWV&mpS2w61I@$G6}oZi$)Wj zQ0SQ0ekj=fac~M{BuCIgTFz|vfg0JCr72dR;MRCfKs-aq8>9SJ6q)Np_DpETH8_p* zdQ~KB71`8lYi7O^pyE2af&oxv92N>F0ZT?9^kh9|30d40sA(<_HJ zO%=9(BcmO~V|UUMwDO=np!+>M36;92uO3S593I6{k0=LYoDpl9B9)+11G@;lWZDW*!1VOgpxq$Y z-#rZXcDLRi9`I544GPFl3AQCY#XPLa^M|k9j*TbB@>FE#1x(FF&7sveKk3JAk8u~G z#3`l6ph8eb&#SOyK%wZxr+8cCbg&V;fl~x%5`m~iMdUO@l%3rSPSQRcgTVS@$~z>o zLJZI)LE0zKh(Z`HS*#(T`zZ+232Y4RMB|ZHIS)^UcX5K)q%UV45}IDXg6!tzccX+} zV%`Lo1yr)C;{aJ?!BT~){$`i3&(}d`Eg1CEs8{(bEk$(+vnH@AQYm|rC{e$?yR-Rr z{T?-d9&zc`vi1I>zb4au^_QqmLi$yNY3(o(xz5i6)B#H3**Q?iwE&~J)O*je%!y## z8-egieR|1f=oPkrm$N8p43Z&xlPy#ej?Teqi>}3$;Zx7TsUyNZ6rMEAX{7jy;T*Lj z!+b4fj}37g-Rsb9lu8$HHJO9x3?J8X>Wgq2vUdtAB$4UL!PrDY3$=EVngbg4U(EEnpdy1kxK8IP{RU zhGW(j4~b-nd4i;V-Hqd(Qcqehnn8Q@hwmi>ZJmz$enL|3uqWkZ={qW_M5$-gPjBd| zEGHTpa2K?H(kTq_YG_(|gYQvtGOHxCYup%kaJN*0+BM4-Pl?4mv^dd=g#L2SL=wJ%)MD>$fy9#9`EQLk5V#I0Iz z+xf#aF3UCQDj@lVbXvKRh5R5g<{+n)Ym)vz}eR)^jdIj9E`41 zVs#6}gX=DBw0C7f@B(o((HnM|+WvDbN!^1l`)_2UGvZGHIN5^Dx%H%C1p7IIbh z5!K4SSzuZ51LSxJt^Az8dEo8|nn52f5E3*j>8glGcjoXr0~!@15isa zT5>Yc__TA5mPX8YwIV4}{;2i7gdZQujP=|)oYmP}T%MzgDogriL)(4$Muz~9atg$f zXLe|0bFL+R%yZwNVSVniwp}6`6s|6QG+wnS6%?13i&82>;KxTDclW1kWJv{c0RP<0 zL%?&4kgpg!bWgmwzqP)-_4m!!Jg3y^_v;6nAm)obguHY5e0Ao=@UnikW%AHz7IL`a zk8Qqe+vZDcRj*vP{@Dx~4fyGw71QiZfrU9k<^ftU8N2weEts6YZ0_f5lY~-XTc}oJeR8HNk+1{O+Nwnvc8t7Vvg|0QfflY7$d$MaVlO=+* zGb3(BXA4y$1n}YB2vSt1C{cr@B!CR2o<0Lt_ZJcg@E=A zkHW2i^D|4yV-F;Tq(^C%uJI7Bf}om##>a`u{;T~wxX9%)`tSe!|28ZFSj&ICXf}g0 z5gn?7DFilqUIgK5)<%$}{cim-iRu`#JsD5W&id>pHIC0P%lcU1*1C1TfYmhca8>Fh zin}m;R%+HAno)lT!w|)` zw8wb@W+iCbBLsbks9)jkRy%Gn*d7yLHhAVG-?XaY&ruZ~{P+L)e*}M`S*VcuFHk#j z*~kKE3i(FNxA7S3XtlT!?7HV=#eA$^|Eo<4u#7{f1^@5=gLJVL{MYkUUYBozXH7gi zrU)!9iFC${D5sdZ=@c_N`&%xhFO0P@&ZJje?v;Sqz^4SU$CaxL90*Bn^nA}Wk$F?` z?ib71j#-oFhWztSr~O6vgsha1zPOdnW|{R zl1PV~@M+Mc_`6U4>&R*6(1x#|JPhoHLs!(~OM*s>etN|WL1c#++VNaw!<T(Ew7!$1$eY(ahke zYhJ@)_%z6Zjx+a_R`BL0G7D87nQZh%dAvGBZ95``Hv1 z&8kSiC&E^T75j})pf;*MaHyYQkA>-re0YNMwBK{?>~PB}BMFCo%NS^1{=1?nlTK=~ zJpsRE76}3-yZw#uaQ*x3O(s72sQH3_i5AH@H>jxo7{Ky&yEp|rHkd-pAw`I9s9Z1_ zoC#ZlDI^6cJOdFL9lFh`RIVO52Gk@_y%GA3=|87ICA90ESr?l`&(SUZ1Z|gyj-3#Y zBrL77|B9wmrvn-k#ZSXw7@grV>pN87VYR@JzmRbW@G~>uJtHZLdY{t?k+342W6PSP zZaM~uYXavD>xot%1L4b@0BXZ!!HZ$j8a!8K0T^5UNuM1mB)qnxMif#W#J<8sq-8ao%ak+wt#ci$D#U7uA0%o3bg$L=T@a?U-^g#yO7s6}E$ zVxlq~PbK;oqP?9=*#U;so+OtbS)YK)(*={ClY>hpa-dU2A@aRo=|KjBN4eTmmkb^n z?8lf(o3a< z_-1}8!WD~Wm0}GukFCNd`l@P)k%mba(S4K%sP*kD<*mUtaeNw)WXY3DAj{j)8F}2~ zC{{Vc|nLmmPh^ z3CmMEBlNDBnTsV&e`+4(8QBbU5wj@vi`8fBzzEeHIU4qmNAzt3+XAB>q!1`q8nPiTZJoIY?Nrj#_ZR-wppqJo_=yP+XOB zNfHKwH7QvaRF1o_QMPtVq`KhfP*)J-WhROD0w~S$;^6$KAO|_=r`@w=_VsfQ5url% z(+lIDzOHo59b4n!7hLdCFD_IH=B|z4GrMiK{jVzq)K4+ckH0g{ywALG#*e&jnt8b@ zKOPAgeIXO2fguZ?^M0A@bCAj1Ptj=e_se(Q{nZBQj+M?%2j2zKBOFI~zXO^DInj23 zkvCLoZ@wj63tA+?4O0>gT${3J06q*1TFq|*hd#{nV1D-qkDak^8Og%ii#xP*-o}@A zIm2S{%&ZU;kYytvb3n(yVin4l^okaOlDq^B@Ol%sbrIvy*E^S)pbvaSK_w{N5l7~k zKSw~&HE*NYf?&;o3bRf@DZ1zgM?oh*G9|l+bBkR`o+1Owlb@`B=6GaO;4?x%Ei|~o zx(ce7S74o>C9aC0zmnykXhT2ZwUxNPDyWBTK~-gHphe@$$2Ru7eli`5uoSR*1ni2& zaj&2%0c4^Uh6Oj0{m!HQr7$WI6ghXfpdMB&um@)ezGdFGDmtR8N7+PLP?Nl4^c*r$ z)S`o;7wfaiU_bfYP_&^0t?-3|djUW5_MxC=zr>QGlT$6WFJRtrrlS7rV0A1lN72Q;owuc{c8j4TaqBFGU(#bRO`NRol z2E@UXp96T{odu*Mo(b*IX3t2uIB_xCS&imn0ij}!IpMoXlYP*a`*RJd&}I!LB(yUJu9L1`vYBUpJ-Q2|O+;n%Q1R;4c>&d1!EBet!p&o9z!Ef5 z=)lq@&LHv#HZLAiOnmVBQG(~!Z{LjBvpo+BoD3~F{5LE;dpow6^4UOZbfs111I;cW zrd3_@#GE+7yb;(yQf5^zn8|zTsSBS4i=G3x05CG1hP&BE;6pXT`!TzmP49mmnMWniU-5J*a`Y$d}%vlpH&u^9y-oKSlxr zS<(HH7|6GMd1H78Y)q#s;iCL9ZYpaBF2&!&g_9-7Y8W0_ z{SiAmN8k>fiUeSkckT?+Xm7NwS4mx>N(BkYKweD4=$gr9sGW&AkDv*f^d;V(k$nzUs3I9=oFPi)x- zU9MmPf(5pXe>6NI_ZMQ%oTqHf&KSW%EVkz?*>2SNw#qil9D>|ziM{Y;XArX`wS4Ej z(azn)`HVQ42#NP5yu@iP?6%HyO(%_hjTb0Xs%Us?kMOQAY*Mt|osPL}UmN)F{w)+} zg}2tASuNy7{HkF=UB&dF8WCf=Gd$Ft#?5HYKY!Rg+yd@aV2mzNl)P%WST;D;k}% zr0}!oIWCf67h1ZPb436|>U zo~{e`8;8XQijIt1vYXw9F_gdI(7>1CA|Ab?OdflDnqSOn_i)l;*{p<)7LYpJqe2KS zxXFAAUR3jpWhz3t!H?lYm3vQCTl46J`T1c%Pna3d07te5x_uC?1>JLWK9#uulpDAc zXXtS<&p>{Rhv+Mi*H35C$y|Yw2nvWvmK8ub)XGT;GPY~p=9|8w3Ci89+$&JiP05p9 zXb~9?NKQS0VI8EqHm{pqp9TxRiOCY*d?jWP`dO59I%h4c2>z_(2VQ;nc+19$F_=Zq zYeD=|h4X$Pd*|F6?wB59K|nA{GDJi#>h(Q#nP~_k`T#@$=%7Bk|4~&vew;89Ezp8jk3Js*7tG)~(5s8T8oiK*7 zP8eVObR1{r@_ORX$hR(QqoGnhSCQ%H5-r5j(Wsy3*CTY+#B3SVwfV`1M82hO2fpJS$X9Ul2@a z^J#G1hViP9S(!|>MBh;Wq{)HXVd z+p4);e0!*T4A7x>X+kOS`gx=_x$7|>n&Eo#GIwcvh8%>hO{XI){a=HBwgZHu%}h*e zMr7<=hd(0oGT-l`YikC-6RHp27%R6|_Uer$!j*O;Bk*W;%v!RDTxXGHq`Pg#foT#^ z--a|rpOjF-@D*d$mRz#UD_&AU#z}aa-03wcgQfGF`bn{c+dkc`wT=6f(W9Sc({bE! z5s}rrh@{w*ddt3z7CncOIS63h{+@fsxseGAFB%JAg7XC>1YsHQU|0w|s8m6A(~c79N}A$VYOD7o3&-aB26f1y9^KG#Q2F59&3M`Er50bjC2Jk$KkYlXF{^ zplc|>TSzc*D>+E}Ne}OqIFLL$PX-#CRB|8K#~>)BLjubGev{!!Ro-BuHrW*IQ}$ms z5_I+{Jt?dP3sw1WL1RQ~#dk(aW-F%a&&G_611w$2QWt3B z{_##=pk|+bJdz?S#t>DlBSBO|N5z^HyyRiUU z!MdyRZ|tb!53WLCdu08fG5kn9ni-S}EGdcl^)4EaIHnr-SF5AD#T{xM)kNjJYYeBd z>Op{Mdd+wLkDCU4UNm!-liED;UDH$eMA_!Tk70o>aH=b^%=!K2%AwTfk2C3An}Gq> zE0{k0qyqZV?T9e<$1~l;Wi>Jhi?|16DrnA(jaWEL#e~t~Uf*gScc=RwUvmFzvUC0m zmRX}Slmu=~w0$ZR#p^aV!rx{ie$NGcB|mdHRlufrOIh^#0d9&;K$t%5SsUpuoKY2- zFso3(E$+WN+W$YU;Vmp_!M9R;q$h4IT(HKw*^QKU3kS?|=(83u-wA)rmr??&hrPkC z_*O2o-mT?*1V?56hHMZZ7qezURo{(^U1$;3b{*hf$-HP;jVPYJWX9gk2 zd&0^w05KnhM;J5%v!kft)^idEJ3wA%DTv<)3WcG*3a{y4>;2p9&4A}+_Ogz`rdZS{ zZ2BH2;_(QizN+8W87~=|ZU%drCRPZ0zYF=Ck@x|gbP&2%8R}K81N=ppJ zQy-!AhuHj2h<72n_!7UZaX)4EpoK;Qx>spq|EfhDgfET3|l2`OH!mbj50ynbAvg72hma#K%3y3B%0I@&Z9vx zCMg9r&2*UHDS_#Adgv>1C6#a_@^KdZcPops0Q1NN0vy=20U$7|k(e*Qw3~PbbCqPd0V+d+$R8<` z|3+}EteasjL~QtGWLX671zVBbwJz`p6_?j11LJBD54Dc$DAbAm$s{D2vWNVsC<>fDt6Ke>TE| z9hlW!?irbaDM#cuC3F^MuqpKJLoz&P-I36u`Op%93&Dvv1ahi|OxDY_Ql4`2{O9{D zBvs%Kv>3#*a^qXivUqUPzhT2q*0`DWfhrE1tWx9n#~6{VB7*ew!6cih$JqIw5e=@! z$Rb#>oVE6cyRUaUWILRWPou6#+d4=xU;?Mf*>tRKa3qyc5-X9F%B?Lu4I*JHpmMlq zWN~yiY%pXIffKgT{Y`EYVPc#+Q*)ttyEjqudcxtP!!JqcQV6scLt zQqOCksqUv96cPZ%GA3OSXh&L>XK|fLk_{)koHoso8 z56x=v?4SwZA@lR2Z+@WC`DaM*9WhHSuPQ9V8M*e0dv_T>5&+=G65qOF*Yy1ASkrOg zosNq~@g%n9NodIW$6BB?^&brleRLr;^fHIx@)72B;qO(JbFJR+Ng*UrM91qO@i%Kh zqtU3*J{Z8UkuyTdA4VG zxWgL2e_LWD&Ca z`!h{+`8~fojHSjZVTZ2H(?07(^DV(oj_s1hL(mqSj3`gEDyJb+ZG4TcL#PV$lFOtw z#Ve#CU9e{jk!X6H4%|wTH8gZczmR0DRb#FLqG1n#px2s|r(u?a6a;L-Kq5vXhNNT< zxs&ze>Dmkm_gM=u{+MCfd0ax`p~zfmo{%tD9iQyP(3L876O}SD1N`^@|Np{2NLpZZ zVFs^CTS`>|BGFoiFz15VT zxnj4Li~-Q*$F}Qm9LzfP@;o7-dsDQZ&6Uq`_71Qq*?Xtdtt=2EWRx0R!+xpTw@g~i;xQ%hAP1iATGwHG3u95VHV z#p?^*Nfv^7{5S*D@b@;n9c#i8RoLV&@8SHcV`Z)|prA0Mf$~dSuZrxFuAlA}TfWfLrBEd@ zPU(OeB00k&PPxdEN0zx0zDJ{k!m=J=*0vj~p&zmgX`bA4oVEj9eGXrJ13h>X!*7>y zOfcd^6wRQWf8v$Ds^lB|MYt9}g=Ojr!BX>8{)lu#SuH^aTdssstNGfsKE*A_7Y>yx zWtiy*c!p;u6kD072F1K=lJxr$VdvyVI;_`ZWhc{#2}i@Sp$W<}ykUP46spka3hm^0 z2}@}Kry0S|$jZ#*31-FxaaW=vcsR3yz(EtnJCS5T)@5Z`fC}`8e@o85|Fdvv44|L$ zXhf+$>|Y3#rbeBv1y2~%rLYbO-Qv{Ipx=vL;-D?}6{4z;^8Hv&z_?XT*~9^~jM@3< zE=uOM$O25_ML>MGZ^($CV#};MB!QKLEd&^V0W1g=MfT$0Acz=O3CWt0ho8h8{UsbB zfb$J4Maf(4d=kb3pcJOy5N6ZUji1YQ`^2Z+nBF;{5>nzM&9zU_vd4JV# z-d|nJc^@N#ufq&P@`>R_Z-u|#dmd!{=`aol$#9xMOGDccd=_Gbe*%6p;RM$9Unni> za%oCdH)&X4WSf-vQCF*OX4X|RGb>uK8gL+6Nm=vxSnc$teD0cckX1=04PrERw5H15 z;8eHT-v%ei#6aepFFR(QjB#us^{6b7sn>o}P+7CQCiRyJ3j^JKO$b+Z1NX}Kx#WyV zXb{G)phm1N=$trP7Zdg0W-7MTYB85*bhh3#Pu@{Wg|@q3j~mTHV$^VkN+Yh-oKGi0 zf0n%5E#u;HavFV`59Nu1ma- z{q#SRm;3w7Y|_w7jSh-fw){1s%Q*GnJg-tDUNk=*ttbyKSpsgRp~AxWdW2w7pGD+= zFizJT;H{Z9YYVG)Zt$@(;IYC@IIk^fF|e^kfX1ATI;L5cTYVUh_}ym@uQY2xSPj-* zi7CwYuoBjSCY4ZpM{SK*!g}Rj3#~V#g-U@5yH&8ss8+PFzVY zk$-WZI74y%SH_2X#O?TRj5z-M8zb&_fD!jNbpLOhxclP7nRlU&wlv;RdT0F&0Ze%j z!WS}u+H>fr#_md%0jkc|JC zjh2@)qUWIU7H(8_y$}sAM~g;&KA@tl_h`T=q9l9z9SA&UG}V%enMWBPS_#G1MFH=M z?iUIj9X#F*AH@`17Tef=d8dZw9iky}rDXSA@mv-Q0%S8=@85>o?+(yCDak+CrzhIT zRSzzozD0Z0%2QQbzV#OsLlfX@bS*xP@sd6sWd<_YWH4&sqSY^v;nD0=-lAdtZ7UEV zV;E66AvOXk3ftza_X#ZOdIiI33p(8~d;JZ!N&mE+USqIZ2m20-hE4>y5BSbL$z<5_ zN*!mCm*5`jwLOB0+y*a$QnD|-NOQMTBY1~T{V+UKAF;L*?xMOQQvGiX^b7o%q05$r4E zW^?MNFqG^n!mLRglc=i~H}dFN%|6r7_-smkPSF`ccumZj-nJQ|605*BGDJD-$&$hQ z&9~t}C<;+XC9F-w=%js{mr>hs!TSt`@F_bA+d$R57#Q|IZ^StG;qPy)+NAj}t`w|M zE%?-e%BqOlQlYO{ch!5P;z(2OJj2Xy6$?{lw}87K@J;=)%8YI8RlwP!-!dZ^^`qes zaq;-Ht&z16-7bR47`tD!js9L20;2w`!v#cAH*t+(7cH*6~bN{J~(CH~!rQSOHM#^AH1+tVQgi_8o2`GTp{=~DY&Tjh` zUwa|M&BK^Ii(STU&x|6YV9$1Dx?~rs_KZ&{*Al!lykIjfkQznDcVKACh z($iDncTz>a6H%R^Bo=y?!}(?RdnnT>7;H>Ww8 zl^#*y!tKj9tsY3t{O~+R01;Zq_&OeU6PXlufWRG(2cUHv73)k*Ji5pAg|68O4g^^+c_10YxV2(&74qX*Tt3oO)_BhF?|9@ywtKRK6`A4qaB0y}M_WLNJ!2r*0!Xyhh4kXOd z>9`w*z-vRYGNFkGxJoGRx-6*S~nKbTqN$3y_m^hg*ijlvf`kSMkqwvwGxsIM%*c_r9I4 zd#k#8&ws)0wdb6@Z*}*gU$T31&R$n{FD~nz!(GPlX+}s?NT}L>h$8(uo$v6*A$;{J zzo}^($nZPRUOzM-7ew zXkk2zDK$2)fsnj|bn5s*qx~=(7mgQL>6tN1-3&iaqiT%OksD_zSBgr0`Mwj`czJ3L z%`_ZE;|b-k$ikBwm4X7FSqxOcfklS6NA5?A0%jJ36>s7#8^W(Pod+%Tpho|+oagNs z&sW^%{7>C1XTGv2GF>?xgyA8m@NM&segh4q+su_{QHfg6y5kbiR=1ri)y7hFc*Z5M z;EJ{QI7>qxPFRCTQBZSM>Qh_83z$3 z!)|{HiW<;eO^{a2Af9{#%qgmDA*#`C>^F4MNXt=}i^CK6ZPeKSxo}dzc8p>*rd;S| zyB4e*Id-!5=~aOBaI7w3x85+qDM7KqZzvMNaq3+4G2rkT{Xt`>z>xf1vDTJfTwv@b zgSE-T8kIJ$S?h_0D%shS8|YOxX5?KnJqa!Dc`DEnt?YWD8U@zM5YIJqVt@+zXxkKd zq8Nm_jt~$ueGN)bVgh$zeDsa%jF?q)ZHO+@1b;vjYH@u`_8AdZE5k|6dX7aBJ``iZ z^z>M*Se^#6rdTCw)-e-E?xfF}L{Z@swhn6c1*DZV1w~nDKva7zZ+k6Yd#(A}YsvOt zmwB6Pdz)TH@CZM@bE@3=(FK~@T4hlSBKsFF$<1aNV+&WX8O{=&#g@Ff>#2!>SOmG4{4(cIi* zH+QpovQpNQmBOAN%F4+niHD)UC@X-kB22D(-XD4IeWx#H4$Se$nVo?jz-arIR}_`ztB51#lr z87V?>o_Wtido91Nuy2^MWjv`^(uvP^y6{a)Oj+nnTV5%Pxpu3v3MvAA@|@08dbUK#o<+|L}g8`2s&wiQ(<<+E6j{=N*Lyr z_m<94AlPLDr)xK613eL+Vs0mJ}_Wu*}1he#RfJ&f{Sip}CYyq!S;q~Mz~2dTSxRwm2V((WDZOpbJGZRrxT1kPzXtb(d6cr+&#AT+n!T5edbqY zkGyo~oqN5nYKAXwDNmep4bh%0PHpmh^zuo}jic7sLT1a(BjF@WtW)QRFyWg?X$wS) z3=l`)aK9eko7Zl!$WoUXI)06%#w~;Y!if{AoUh&`W-FPr53o%PzqRig!G|F(r!Y+6 zPcO0fkglR5vl40?-)z6cDntqWbL(Glwc9gSn{a{!;jj4@s=%<*ZT(UDkf+`5bj&GK zC}INim7s~UTu`EIZN04_5*)4~=YawBe~OFR@z^!nh=hz7WG$|^W>&=5nr)4&2xDqj zIV~ByP>HXJ%FYBOp@%tMjbS=Ft3y=2?UZkucpga3@kZ;_chKoEnq=#Cx^8b zU$Njva<&dEdal4-{-?zn_0(xM>H*((8qFD$7U317vf{r2j!d8Ez%hC~a#wSX1q_cF zB;#>9X73Ruz=?}!CcR|DnQz&}^^ropBU#W(2^UZkn2~86+aS6nClIrmRA!Z;$G8D5 zh6Kxh9^V)krXxM*SH;=|2qv;t+ zwuF_-yiw*93(<8~_=4nbEBPLVd8MLd;!3JUbLlZ&?F`Vzm2y(~-HAVib^@ zjXGsXNVBzex=s2YAynN6^!hc!{<)$(S60w-#ePe##hUzEturNe5-V4E0@GLvo*1q8 zS(vI&nhKsf=6=#;7c-%#Itz>_WX$l`HEO{UI;alf@tMpAj2bqSS(>XN!{D)^_Q>5= z|MBn7@A%VLmN>F$Kj|fto4QPQNyxI&4SkvXog3rqK5aDN^Ss%_e_Jn}t(yNfo2$>- zD=%LBM+^U1X|A-Mwf>_CJG1%XKZ53C57zgYVn}un{KvR^Rd2TX7nkQ3SJ7D(UA|~v zpIwgrbTuCQh~;KI|DAsDN_p?~U+ddRHwHzpzD0q(xc;4BW20GbHJV>7FMl0u3qrt) zVst%6Nt$T_A5#(2F@BT`gMM_APABZR5P_7AsWgCrVaz*8@NkyFZ!$$~FZkQEPxTl% zd-=M4FhbxCiP{x>+|h3Hcy}anqo?DuXedDcM5^?R>N|4@tWwA6Px@1pE{CmOxv=clKg&g~mKg=@jyI2pwB_uWf+sB|H6rH6NKzwc))IGx`7 zh6`x~-;oEhEfF&kD$NxO#A7CQ+58hzV%`EPp)(q4#@ute=AfVe)7~thV z)$>s>dUB-OBJXQ8yCMpSCmo2||L@NjcyZyQ!K z+}PdU`*6?+p1_`CN3O04!4n=>=uP=`WvS6vhX2WKWXp<8F29TVX1I}uRD!cTL zp#TCZuZsLC(H%h@?;DaYKTdUf%8&kFkY2=(*hf4K((xm8)064@5h~R?;!*3xu#9+p z*n1mgk6Q1?i|sV(2{e>P>E9&ax{5ZAm zbsuSYT)dh`BBXr^P<~K_`4dIW>0=ORN%imLF9fY6Td4{*zQ;*ZK#MMHP zs=@FY#l096o|a~JJh$*c51&2UBQV!Gxsm$yyKLHp`-CH@Q)C8!L0G)UdJ*R z=_4Lyl3b!b!df6g#$~Lq(-|*=t+|v3ucts$WRc1fHY%yC03BuXBMxBp$DsXDG)%fc zCKJ0mCh-cIQY``F6!fVEBN$i2D_if9A=9i5en$hb>NS;a`LbRAU{hf~z?p`fujy3Pe3vF`#C;US%u^gc)TWzk0*fUNQXL(to=tnaFj z?7Z3QncdVo{L>ST5psHE^0W{*rW`HCV$+(Y#J2}NiM}^{O{PjFStv7 zQ`QQb!+#uxnroM@3|2KZ(JVQ8x_eVdD%(lOX$h{2YKye1V-mp&!Hj3|q4 z2S|BDnXvAs21VjmcQf$RVdtY@k_>Ou7zm_^o!%sX6$31(-7Hs9ZxvY=Wncz{03-0+ zizOr&)wxc`qGtS%hXs+bOcu@GLT=4PDd@^8g-~@%ye7XFyvPdtqHn3gQ6{pMC!rZB zNl&_Pq$0cxCd1JJ4^j3>)W;@3Jo=19KYPLr?HOSICUFQv;tEgRd38G7={T3q)0!K* z9>tCGb2m?|!t&v-(wWs+^%-}JoetemstL8qnd~g@q(zQ9MX5^tGw&@dCjA>@;=Yl? ztsA$TM74A+QhD=}fP{N7eZK0tCgI0LM$ulKcP7acG5J8Qwj#VccL%RSpUzlrW>>EO zc^c~L(}4z+6C)4K$XCsa)r{+$kaC(l8Co{{Wc zR4P>`nWlcz5KNG|-mA3gVt2^n8!>Hg8Q44QG9K3Z$>0Rf))*$Jeu_>IoO@gvkJK&p z$DQzS^MLQX4}>HI{N%+;YVj>wJUAmvn#Du1Rb6-ExF?VS5Hb`Yx!@=SDwwkC_z>94 zWn4%42K}*zx4=|gmP#CY88_6APbUF^FG@i`dXIeEDeNmArQ#t81wsb6!ui)eHO@TJ{YyGkVihdYm=FPQ zN^vToDyr_dKsG!kK`D}K3zv>E6kr+yXc~<=GJ^ojK^zUJwo`nZ3_Y}fH}3Xw2E!QF zc{~Lvg`*9mctdd`nWPZLeMIyLR7o=^5F1ht@z0w{j7A?ep#1m${(sBX#wx`HRi=zS zf6M}m9~h0(GZ6KHE{4yXCLB{v@1u(VPFUZbpX0{d61qbX7ji{9x(<8gGuEI2$JRz8QHy&~%ZLZmDwGz*P$%9&xNqfv^v zVUX*}%~99l3UNbtW>$kf;JSn(ywiT;2pl2tBgZztO=X{d0Xe%wepW2#a-c`>Ffp2z z|5NkmUsRCB4W{Ud1mqIw_NYKAB`6_vv~$K}%9siJhU85m7W@lNycYpF_nZykfFxy` zfwZBt6}R_V1d(EPCO)jYX?zNdk#nso6kdEJ;Cl&%p--&Sg!)0IMip>EVE>8j&_p?9 zNdaa6BsBm5!B1Cm`6y*tu*Q7EE3F9>5C1bGRjR)LK|>LlN`qO|*A=r%G?maLB^FjH zG(+D6EzEV(dJcclAn6AWVp_8j|#*7wMflZ~qGtbMYJVlW+r zb;aIk?uB%remq6QEfOM78bL9XZe!ENob1o2hzPZi_w~=S2Q$8LX&tSZb(HA$N}U(# zd+8u?EOqQnwTM;urDNWlMcVW4R0B3A>X*}h2``H+{fU&q8Z^BHOv$S-lLikjE!C6& z(yV#a+P`n^?^b;s$tT@iNTC(}y|H1JB~kw44@w>UxKkIxKPtGkRa&_5BGj|=L%YQE znHl_h!S~+0V#;^@JM#E{Ww=udM|hwQuV1@(0p5_e+zQThi1N91SnqT)(27G6KY^83 zS`wCq0jY%St$Nbwh^jjsP>7;a3K*M?D$i>yMML$*`%+WNDFjl_kOeO>DhaxHP0IW69|&vf9gws$BPX^;S^nrQK{f zn)Z^(^1Joz-FB$FBlb5xZf*W0Y&YA_>&8=K7TC66&u6$~lR$1T^1GnSp}r_q}8+Ls{^u;T-e@n9_s&1Lz5=W7JcsEehUp zqCe>KMLcA2Z2kS;f)o{B97s^Fld`}KM{weToYvQBOD#wmaf8)tppq8PLKO5;5Iiw6 zM|jreGC}r7DA3NZ#ssJBM?&{%n4TfoI18cCP|Tjns=z}CdDRI}U4rlnb5w}!D5nvO zT_CUk3^l=solb`WcQ!CaXB~u5RJ!Sl%%6f}ZW0yr)Vuxlrbq|zS%g8Q7mc%c682II zHL6tU3q3Oni~eILF&ibd)8H;+uAhjyq*SDwcSbH7%q46;Iadh=9}h7p5Oh|Ip>Y=W zh0in|N7SF1*$dNILy-tjp^n2sav|>xq#2j2oiv|(2EO!n{_6#LZ?SmaP^5pv>9X^aPZc$#fzdhH2d@MBi1O6wDzaCnXS*@*A3libZ0S z+T8eV(Ol77m>U?z&U<&>(c`U!0=dMD-?Te|s1L$2z6^|s_YX0gNJHnuCLRIUGyf44b!+dhR19Y7nX42 z3{xJHSZAo#g+SF9F+$9xT$hR|1uk|7>GfaB$G0(Nf|kH8FLLpBT%?6?ho)eO^S-7l zZ*Wo;IIFC&sq+foA((;@rfxzT8a~!io*ab!#eSYl;z4G8HH|8b)1;5Te8ys*0|7$x zbtR!7Rw=sfF=1}OkDZPT3ao@xLv3h~-Jnv$pv@7yGVkY>EQxfO!U_X37!!fuP08>^ zUt^ebp>HW_(n#}waj%|qBQ21x9m!`;0QEr!*iS(Hs%nbUHXNNsO?$xiLiOeeVQ{I5Gh zCob!g!7_~efc3h78?F5FqEH&-B3RBwcu0pIy#wt`!aaG zdZddWB_o^+N3$0NfQ!Su)8Wg=P#*U9wqY#$^n^$q4iHHQ#_YmVoHX+n-9OcJ%f`_? zM_H<;jz8!qZ(0l0-Yv!K4KvRD6QppHJ%z*A;856k-I+(30WnShazKs0w@3a7@lT3( zVrX(or-)q@O6P})Gm|9_pyqK^FnGiC57`DXz=si*!aYp?uTQzmzr z+tbIKGFkU;iP5$Hl9<~V_EvXI?TlMSqY#l{1}RIfBqa*BK)!OWm?=)PXqU*VHf z)dI@vxZ97$=mdO~=3L;X8uptmY3X!R4nJMYdX{7=vp3a8h^l0|S9nPBG-2!VNlae# zqga57MU*+6_)9~cm>-7xoPAc=fpx}#S@O!i&r9dn)63qI;F8QP2sK{#l=H&(I(&~H zt|7=F(yZrrPvjxvyAzr9{8-#?J6W5;saU1o!I7@IDnng<$4B`u=7Z~-wvw~?_j(Z1 zt)bxb#|jn^FK3ZO^n#fD&5q{nxK&OW5$TelZ-d&i9;5rUlV)$RZhI}Mzo6)hyU@(i~$ z`odwNL%iZj$2ZnQQduLc$piIk*b!A*+yt>N!e+`itpncQVd4b*r?razzR)QE%oN@D zdV?!DA(&`>y}V>UMo;1E)wr-+N?HA6!Kkp@AUaFBH67)(`PakE{rBtJ;m-Qot&KUR zSTr<6LS?@Yq+A4U2v4TydSp#<4zG(6O%!2x73|yG3&svs1KHm^{ILH%+}S(aw>B?1 z5E<;u-o#=AYMk0Hh{qK0n9A?{%lb#Tk#N$2&RQ_Dv-xf?h8W_!1*ws^5s!R==+?gd zkp|e!%KM9-ujlUc!RGen#^LUMxW2KG>oN7(+XY12iu)pNPZl_tb}wQ?w8#FF8hDk~ zk*nn9{XC9(a^5uym7ZM^@;2zj!*q}g$;oFt74lF&xr{LxZZeLcaS~N#weju2msUvOh01xspG$fyqd=~3atjg zQaDFVqJR^uv|ltD&swBVWuv4|$Wlrh2I(y1G+k8PRWj@$FbiG*AfmS!wm3yevR)5R z7$TRNct}pxF~Nsn2jjX-3{RDHq24a~wRGb~uqS4NK`7CIQ2?ije!vtW6fCTc@(80) zFbsF6+ES&!)7Va6Jhp$AHJ!XNAymr@Lr;E~q2poqT!wj+czG4vaC~V$FEKNQrcAGKh6 z{q6qx`?s6n>&^GOI|q4wqxKQKAJF>*14a7?seyn3m}2D8*_)1*ubkiHdP{Q5Xfj6j zGP92yW1w3k630||ne+$6>?E9L+V1DQ`ZmB_A6Mjtt_9cOu$t@8C>{@@A@VDDEcQay zPbacNh#LeVl;jrzg@jUw!V~Du0_3G z#oLi#8lFo-b9dwdBT{H5y?2*W^B0jdy`X_{elHpKdTR0PAl z^0@^U9v*mZ5Vk^OQjuU(f|@AogrN?`>6J)(emtBGl$|6yCcRy7>eFb9F#L^dn6B zJ>|9?Qe$6||1O}ywo!2QD6zmYyyqZgrc_ERtwl70Q<+-#0M;*mN+C=|qQ0PC!58k%oCk(BH;c z&g<%3>O48{6F&)1RB$|sBeujA6?Jtlq8!ji@zATO3gj<&T}_m4zH-x0<}$knIlPw=;b+T00{70Y=u zXEFbZHZWnaQ8yDxe<%_fkPTKJPLyiNQv%3~+nz)~Ve~g5Z0B8;7?WMN^Edb#CV^0p9GUNRdO!gLdjL(EMUhdQjt5{{ho0j7N9Borvp#hmhnQfBta zh^oWPKub1Q#FHmw^_=#n*?CwnSWDZJ59%mI(&#B^0y8X3UVs@VVHfu}u2rD<#yWeY z5Mj&J&yt=FgAw*s4VLD@y`)5w)kP{3mISH- z@40(UogkswYCAU03SVa05hwx;5zn{)#(@!jR1iy0GZ9}`aM>iLSI>)>=TLYog=bL~ zcB9dV7I%VSor+40t+POS$JPACE6?Sq-jK+27}1Ggrfa3CB5e{e-ZMEQf?klQo=>ku zco>u@0l2L6zE1}!x{(g` z>;av^TI%WOUOj-uHx4#CXl1%r>u6Mq2c!B43HAY3hsu2~$xu=573@)cgPD%6qH!<0 z3EAK$_vje-fxICO5k$*6NN!BjGmecj;`UH*#|vXM995LUd20FJpB4Q6qTqLq!Sp>a zS~xN`rOc!)$BV84Qok6321z57I7qdC(a^92qoF;85r0G9-H<19p2VbJ6)&wqH=yiX ziKn~oH~AsnwqT8D0JQo7wW-O*kJZFCYr#``>nYc&eWJLLr)$BD<+)^fFgTM?v#Ktp z5p@EeMI)kxdr`@s=BAQ%!QwUxes33%6$djZYEZ-=$1_T^gv?pk58x+S8s#te-y>(i zX__%^W{qQA<(i5$B5?@gBWMRXiuWn z$xhSxvSuzYE{o_VjYI0t>f%{J5Kw;e;l%W4Qrpm3A$y2=gxI`Gg|zWXS9m7xaTk8> zb$9tw@rvhrSs-R>=LSGP@=d#7!5B@75xndGQif0CbU@RTIHRSVDXh^ zwV;oKY2WJOs?o>i_wHl6R@{{qDyZIG^8&w*&nhb3SoGxErV0LXckk(1x%XPCd76K9 z<(KGjmU{J}OYL^J+jJ7$%?#)^`frKHl4%lL?wa2>(JCbDdU}u6f_8~P(t5W6XLc5z z+^7lDeWPv8ra(HFae(R%d%Or??SQU)% zRyUrebSI8^VB^MIm>?|tc0{wC4A{{y{7&Q`(}!FD$K5H- z)F2urr^syJr3f*RIR8qB-hwA|NrJu=wzXFngw__|QpQPH&RJ(LofRWLj%e8nH+mAGJFZ_K&|F0=WLxs)4j_K~K*>X^B7Hx*j?Uz49 zSMd(!-J);JB}4}WHH3`hM&#^*BWL^T?14X@J@7-S${sgWUob9yCWggd9&1#_31jOA z%=#qekgnBWK>3I6{?C`Nc47JBR{k+BY5sSb6Z>bwSS6fHi z9T3mViw6PzYxgTUp0 z<{{!uS^5WHO+b=F{(e$&irN$phmW8e-|1M|qN4o;nw?4akNB3mUrJs$P&aOeAm|!f zOw#-OQmjG=i79jhaYA^01+w#RT8dp%7V}82zcpFRBfWlUSvXUgR%+V z;#Bw5ZXb(X6{xif?FLsyQafx8Ql3Y2Y*ptI$mXH=avdwJw3+Obv}#4w-LI-7trll2ok*2qV79G_O67=x}dYn1IRY#ydJr9shQ z915#)hGp37k7F1%pSX5mzfIU4oH?IPFO37E;xECPj~eCN*5tfyA!uBXBn6t8ghz`z zJ90zSt9?!-v6JVbXRr|k~iO=gG|ZBn7^hO693FM zb6T>Wr6^*`Mv?UJ0Wv+0fb$_ONH?HiL@d0Yo<#jn`YjaSny<9qeuf ziz}-gy3GcJLl4xAeXwhmwfB-ULIt9Z{AaN8GFOV8EU)<n2%zXUU0Lk%RM&Ft@1yUAOnzn@H0b{$^0Nlt z1Z_&*`oi6g_;E4FjHIOadGxDPv*J>}60_jr-@AFYkKhS}cj7u96_izBC8qNny%n^N zd|PeS?P_j*a(9AANcmBUt5!MCYMxkm<2l!_1zXU!`*6efOXJ6$JM$ZRno_s&ox)E( zAE&PiYHun^Ll?LCJEgs^d>`e>S6G7TE5DvDahgL(8Or-I2|Jxt6!pm*sGB{0!Iz%~ zr$6B#Rsr&dZd4atkh`ynzmWqN!_w5qu@GIray7UeB$vE!fKjxzTb}3MS-9`nfg|}< zf6AS}mDZzuNyBs-^^aK`n5oZ+w*nUd!3D+8CTl6 zPqPcmceRb5druGDz%4L41@46N+bsM%_kozn-Oi4vhL`OqCITDlHW6x!kv5Hw zkt%{Q$*9<1+8?C73VPpP0}YLw^`4wYk2pdK+0W8-WG}-o6Z0bJGMhKJ(VNYSsv~ z4ZIBxp3RtesQ1~U>f0W0$=Zm4V&4u`1I8clS69E5r=2{>YV1C_pF!cq) ze|15qXqvl-0agq4k3ma}<;w^`Oi`65jPsYj|enxI*jZl3^ASsgwIdNBt}wpG;&5ktNm>quR!G6n_GMJ z_Oq22^%1Zl;0$kDgeVBKcbbf|Nu6d;!;Z_!vS1j;Jz2@+Mc7NuP@XhWD}e(e?4OsyHL+L&DdC`OBECPSbllt7cTeCUmr7#W-eAmlpT7~?w1Szkur;_DIJ z3zM2Y9l$KDZ*K=8OdD3@EaK!07-@aO+1OD`8H|!X-%0~)X5S@Z;wG)|;)({cwNtPsc%J>5Z5N7#=JPRV1g} zn7wQXnAX*KLg-J77V~cX{pD@j@Ct_CnZZyqeIm{abg+yqqanijIxJV*@ zc#5coBlsOBhmOynLZb$99QJTdcIwSl9w9-5GP1iMOL*x#9>)YW*-K6dEd*CBxIi~N zZW^EARI3p!8v}g)Of3#l10rN+5=er9SOr!S;fp39H&-NT77Q4UORNg7V>xfS@b|=& z1cUSr3wkt8 zMmS^=#xn(AL8Knaafd|I4+MrM^Hw(t1?p4|)aBymGu*rl2Cr1y6!&Pr?aMjp$EOns z49;x`wAGk^c5svgaXpR|Q^u?CA+Auwn;RGa?jxu~>PhRv-nMzI)3}-TJM#4)Xf+sz zJShO2*T^CU=6eNL8Ia4kPTxS|f+f{e2B;{4DhH)Ai)s5ruZENRXC#Y~H4uw&U-pp1Hfe?GJ18}>jtFvlD32VaIi=o^(lB$^$WX4p} z#Ww-=3?(QuN!V6sJ$^vLl_`>iBTJ=n~TQ;npAO-Tq)+N&S{j{ClQ}Q>bz4->L1?9H1DEQ56@Q`Zzs6LuH7x=-pXBA*ni#mkNn(HS(R8Y zMsj;p-nQ0XzYgE7AJl@|+rVHOEC^=}!J8UqEsWKL|D#;+`J6lj@9y$wUL{!(a>KMc z0)&el30r&XTl=%SGsp({?pRGcTHmlkTkqde@7nY9ZWJYiX!g+l<$C2`#GT#On}6La zTSb=08Z(wpoZUteieUfUL4X{^;HU|ml!J(n)1cfWsZ$gJYi6aCnhCO$hTsIb2wI$4`0bL9Q?bH^cM?d);?Ck!qS&{%n9k;@h%aj@< zVx;5{C~dJ2QI4TyaMW4d6T72%-R$NEJ4ZcgyF(2p)-W+mBm?4&A3QeOj*?#kVNcbZ zzd?w&re(vp$T0m#Eir`P5m8TIHBV?Oxuwcnokb?`&|^|8S~#UdXE=909)E(j`G}Va z5+F;?H=|UFLcJuTfdmBV9dMF57FT6fkbW{kxhS2Uor?n+M&T6)5miu$f6_AzZBpSS zUofka6{M3ufSOA*Mfgigzg%E~-_0hz2g1 z`hZ6HM-at(XE8gqHM|Wmx5lMIq>WZP^yX`FingI>yB)rG@qA`c(43+0i$A>xTi>qg zaa@4@i%RuH9FO1xkFG@9q zFJ3?~Y4?z%_(#hBTE}w%l!dr^;cr@=8*=!qW;^_o*^Z<_SgJ!BAS$EmX_VdyBT`!7%5$U5Lo?fr;(qFELEA{I0ZB=5f~tXL zwE;vIUdz)d*WKwHimIg%&V=M|5D`10(8n7ICngaWl){C@oNzeL#dN6Okm~_!C*QGF z#QPG@tDZ*NGK(4p-ez+C5vX-?t^jXibQTU_e;eBTuc7mKW$v$IU_`x<25 z+=}4>!N!Gp{inDX&*35nmTral{)*8abz{0*+zt1$!s}Y#<4Try;S71&^ z7U4;ZbL>pAL6=*~T8xIS5q6{(e7}iu0}5v7bX8+HA&&r*gV^zxy6`I{bGF_Ir2$|5@J$$}!f#5bB0# zxrpGul+H)(PB~AW6&B{Rf^~lI8kdi4Z+~-RcV};Fdoz5q4*z{!^>Z!Oc?^F&VW#@e zf@$CbLFH6h<~6EoPqly&_WI^SS-y-Qb~j(wz0Em=h8IuzDsx9@ZNq0=S^C?wAN0~V zBQpq$X*{XR^u7hvR2q#&wfZtRo1!X`Gt5v%9^^LsrlVrNyzhAYdr5v|H)oV8p9-xz zmk-^_Q9T;P(bzl40;>>y7BYO?XB&9t2Kfz&GAu&r(Me+psqK^>PX4kjeyKXcbIya) z1hT@2H!VI5dG=mC5KL&>z! zx{c2AY1+eo6H+jwLLfBmt1%|6YrhSyjQc9Gw;LBVoaimWVuUJwj$3EQR)Y8^L|X%T z5I2v|I3~us8uCFZ>QxCmF*|4~?x&>JCEMYz;^<-s!==2SRM|<23BrW+fJ|Fcgf!_V zC*uhEXBxg_sdJcKT)LjRnQPeD2h_BMG-)AEny><(hZm-#GxFCBdm+plXccg##+H$Q zl1g+sx1(_~K&M{(X9GL9etJqaJo-`#-eNi76OHc;lHM>mJD-F!8qmycfri8@Z(Dog z6vN7s%h+_se7Mpl3?X@lh49Q*XFP;iq`%Hum~R`iP-GR^QTSEPP{jmg#j4C9SmiuT zw-;!;au$3OoK?|vC!$VJ%Y}9_Q&rXLsW)dukDro-8(&-Y*S7t2<)~`P1T))a%JFu= z;ycEqV228ywMw3~OP&eWQ|h{B0K<6p!A@n?FqXX7T>D1_s^g-(X!t(Ia>2%1qf+C??C~c9pMFQBz zB{qMV#8=kop$)2Tie6!KAWsL$qU&^3FUB31;}#e5I59bCR&=drBTX+I;2U+;4w3I} zfEqC!E-QZm+01DiA>>bHx-Jg7>FB0{31&p%tfG4qGL%uUwYo#8)`EMyWVRmvB=Xwa zvjbH;##`-`RjXE1uXqk{)-Hs1LT^gqk6r`w6_N{7JX=kjb=9E$O6SNiUicxmV>$s> z@)pj8Dta%s-ntJRM`8g7l@M%#samC-{0T zXj+{%iBMUWV8+>Tl$^)Za0Dab`)!gN;<2z`7c8$>Iw*`<-msg*Ss1|v62^OcL}Ey2 z`j|d^flGwL&A;w#ZXCi|e*7WaTmRek?)vL+d-MIo_gw@1}Bc6D90bJ31lizST zsdxp~GXIJsnGmzL+Hdk}Bza;QZYa#=u;z8MWmjVNxS)ONa?S(J?2b+VICC8H)l)pU zeNz$_4x1l;2oy!!phq!tMl$NpdRGeX!m>wie!)}7_3;_YE{X0KveF-?!ult&z~BGS&hsBwEfCdU zAb6?w4FZ+kSsm87;;|DW;hA(g?W>upt4DP{?$Tu+h+CYrgcU96_?P_4@tR+joaL zl;i-WPNYx0$GZGf0dlb;mhSFq>e`ts5AQ$hgj??q4%gprY=#?n2UE5x%nM}&>dsb> zkY)YWvJYSI)`fvR={lgqUUvxSV ziPQCH)R@@_Up|ys!$Buo_SO@QV@VcxENSR?3%eM@bo%{hgz}era1B$=9c%hbu&G_h zqacC8DkONT0mR47xO6=-OgSdLjt*r(27`~roF_28PO?e%AYY0l)ngHXg-WiqAoMf) z$1T)%1ckugWRF!e$Nhvv}s-`?h0+2DE<}=q_Jz>8B z;a?-&Y$GLP1?%5$DKB)((8uQh4;SX|l0%i|l`)aW&lW4qoaM!1Fk2m%6m!qrqNaW#2YW8FAH5jN3h&{MPXwj5jU{ zOMyNTu5WC7*!i$c`N#D;MQ()T4pmqmMi}hAd2_IN=&K4hR(g7x!Q2&9fP=0;lE)-){$4 z5Ba7HPQ>21H)W<5B?z5Hif8 zNG)QThJCAKQcWG%z(~+!=)K`(% zB(R;zRe9oDHS5kxcmlwbO@T6HWnwZgf+-j)?XrK% z=vXM~!#QKL0}c@c1%;82!AG&BLL&5B3fb{zu1_?4N!d$kqPi8MJ4plGqJK1 zm|*S?PwDYOrCF8a@*y19xEc+@*=v$%N!RctjPvI1QOhN;Cy0LQQkj#6DAH1yniyyV zS7jmH%G@vF+*G-AfGiZnff{p~3=x#`i{54_pC$p}8?bj_P-)hhRTX?lJk>>Lu_ z;l%%?C`C#;>PCm;9hY73;sw&1GrKpD$QnY;-xb01fcj7YKTXbT^_#4Fp|+K+1?#%X zP32*V7+$Nj;6*KX<_V2ey>x18INv4jWmhI*kfsa6?nTAh_?r*g+kXo;cDJ|J_YO8+ zhkGBs-`?5)wSMozA>9KWcsw<~uDG31CjcVZTl#;cwOVZe!K4?;P1hJ*ZcrvGVw*j@ zU&HP<@A>)*etku`>QV$H?j;IlC|VU=VxGm(r5|ZsI9w0?pypi?qYGuL(JomHa}=JL zY=nPcgQ2Mu#7c^xHLYG?M&873GQKAP1Di*-bwpdbG(#`>JPLpFmtwhc- z=GY0u^g9{YV}78+g05^vH~#E;!aTGu{tELQG6f=rEI}h{1^LlGIf-Adiok?j){=JW zE#yuNq$x4IFz?8@R6Sy|I#7(0_=;^i6OxI=r4A#5C5T=k#b*R`lhlCgnOW(%1hQVU z@oi(Ji5D;e_k!?0wa*xtK1azYrg+B@RIG{Cf2HC^Wiq)2l6*yrFLQUGw@9ORw)ew< ze97z>`RUnxauK{L+(?amCYRZtzAm;%b@r8viuoX{fKclRy&LEyYQ854-P-)ZfgbjZ z#XnUnZvar~uwOc9i5u`B3Xtm-bzfY97`N@d{gu0Rk9xvPgK^zrO6ZCX>wM6idfw<# zFi6Eyc^uu*WNd|YOi%L85o!X8W@ttPYr!<=D=`05i0LTe>lipr=>dB&noCX)<^*Ap z!n0N=NB%f!DRi?RJ38slU0^kcL`Z1Llqwk_RBp9&?=eAR&dUBv8H=88*m<1_ksTnOZfX%}3% zbVLuBZcX>Mj{VgaP7^fxQDa3GzlE8?67R$8JQ?6Y5FxsW4E(Iqv+R#5ajc$4IQ8Oa zFe?m9jn#J@2HZnpl|A=PPPCepBu11@>R+}Q}7xIJ=vrb zNT_VN4h`d|QoS%Jf()e6<#xgW)yu$`DVW)DYbSgYbPtu}3Ea;^a*NSl1@BEd(eypS`wZeY0stf%#tr z9?H@Ap7&;+YR10Kn^md*IZs2}B6t!|NAPe`>A~dsxuL(eR)w?esSMJKk@VpdPH%_XqR06mzxwS3qPab`zdHpPIHp}{<#3hWbl9CdlXw(@- zL&Q+it>3)vMAi}+y)lTepPrFD)&_^=LGv6K*9&J!CcTD@oR&=KDvtM>{v^LE&2^7 zIBBS2(!=hX;KwDu-9{mQ2P#eHQq3fp%F1&qs-v=WN(nUGQZ2WX1idjBy?%$C7FJfA zm*m;rKNt8A?i=kF1#gTC-}u(sF%WU4{fRq>XHHp_ju!LXWLR41t^691+Pa;l}RHyzR|gBfYt2EshEP zw8*j)B%Qq+h=4WHVZzFn6O%s^x3;IhMkQJHlX=jL3~%M(ArD8Bn~C%>V2vJ?Ti$iefT%wLyu zizl&p-HNP3nGIBIs;E;oMcEkxN{?XO6HTt>7}V)Jn zZM3u7f=hg1#4j**e$^4>$LB4)V5(g_`W9F$lf$x4E&q`R0vkwD>&c5KVUW#MA?q z2(d9v)j^Hi%DVAg;3&kH17vn+Sf$|PwY8w>a5bc$WH>dL;hnX6=pu!bmhRV|s5Wlr zrCs%rOS<;tTGX44@Qun7sv0vD+C*#B>(H}2!R};es|;;XkoQuc_&7L#dX_v@BcU%M zF>x4(v<;`)&rrE)qwVKx91U!NX^No^r~UNG5R{aUgK9v$T6yy6&*AP~xc>U}QB}lR zgz

    m~ew_HKHEZ2|rU?8~kcE=gU{(A}ntLl|mBT8roDMRP zk4*sxa?5Eg7q;YsZYfl~&~zGce(HE~6^}k*4kp@j9XKv(OTBtC zN!!{|LKx~aog-cxg2X0jKthMFlHfcFPQo+fx0C5HEJBhDMYt-3{Lc2E%iK6qQ`1hm zWcS-9NFi)-{5B|DdK9q0W+@B&pqMXS~QODQWmD#PRVDW}{{I7Ui)cI`jZ*KF+uYLZs%u3NhRmRMqyfpTnA=B!cpRwiqcVw)!}3cHa5IuRx58A zl|N)XdkRg#Fa&2$+diR4Fv9+7etA6yDkhVK%#ft4GnV7ZGX;~RAvEn0R}MxhX#_}O zFoxxe&{!ilPtwz<|AJ3Jj4GMJu?u3#C}QgcAS$eFK)E}MyD^a9ILeqN(a|r??sq~g z&kVwlX%#>?VF5i%2T+}{9f`{MNeqM@MIb>_s4;=H0ohZG*to-YI39=N435&tc@&LA z+o|lE&dO|%pzA};Jj^mwjb$8o#!!~Yvx>azYL<%3C{^EVcuv&1q4-E)XJm#pLV^Nk zi%|!ZAkWLs=9RwF+soq!aojM5Go6n_R~zQLqc|Hj-TKR@Sel}-V|M^75Vi&<#Zip9g>KXfDfSn$%%Wj9+f$(wAl-(i zNzyK1Qwi$2p!k5yTt*^Q77P-#YLu-?nIwIaqqsV2h~|QD@!OjUf_h9+6F>)QzvhiG zWFVR1SzwfHIsKX|4(LT=eMF@L;E^9;JmF^Su@s#FP1uWV+D|^C*OmM$?SUj8hrO3R z62Br%LAA$uc!6s^!T8`zEi<56=V+0(=)$CC0z|mkNg>OORI3r#SP8icg~ElX8gncL zq-ZOSlS#zpP)F0030#`=FcsD4m@!Ta1anX1fL)hl54VR+^12r?cND2p*=!5Q(*R)r ze+>gPWJB48s(tDR8r3s4q}4 zzdb~sCS7s&1#y752~Hyn;(kdrK-w@ycxkhs+eF$CHd=-f5EYngv6njc8M)45gN{;2 zZsFN#rK5O2A(MMDMn=zbteavIdJt32wI0bHR4K~7sr5v!ZIo6Kf44>#trlnStF?WJ zc-mN>^g#AES9BH|^@RyBqR|fC)c}#9`Neqx(Y zGsrxekjXfInq z!NC;L7+cucCg!wT!HT5fRvC5VQloM^p&RXr*e)U=7wne6{JiRZ_Jj{B&1OKb4KIUG zjLTC*f!Q9j+7hi`^{ElYrZG26R_BDtT5i&LbTOw?WdZN2N7?@z4JX2Y$B1li8S1b?U&S`p?5+%8hqjd~N4}Xdz#H^IcWR~xuR<@(Tpb@x(kpJDo zQ$vl6`5J0T1Sl5jco7WGjoZE@68XXr(J;d6Q`)crjxSQuj67Ck)b(H&gD*7#J2|hoCB2D@Ce%}ii2uPVhe;48_YQ;p3h^XI`^Hw>o**yx_{y}s!5jRW7@Tbw> zLb@Nx$Qu2KqQj)}GHWa7Ps73T7*0EdZP*lsY{a_5C`64tC?uWEr&#aupgu zc!U!`ejSPmSQvsj^c1JTq9Hde2DKuo6GPG@=Wxnv8ySyH%*Rz&d-XT2^~-NVz&?>` z99g8~|oU#x)|&Tn1S^84B& zr|1xEMPM1bQ6QtvHKguBE=wY`wY)xQq#7ePGhtbxTI1epa*t5pG9(do|0q~LNP*Jy zZKozqmV(aMpxSP$BA9{twpz4q1Uqwyu##K{yk{Lwq`lpdxJ#wVyA)6dW5#{k=7jO| znj^%S0m_TdTb?ttTi>d@)w#_JqoYj4sqR?4s-JLzenEsN^ zvCVnnwo^zrTo<`OENb;KD~vJV$S#u30I7aUl4?ssA}leClcSmINY>j3-tb=tws+Vh zb!up=@^_zf-fS@7L_4-tUG$n4>4al&Tg1tVTs0pR((79jS-4gDGk^;X5o18XzG<~Y z_ca`n6-WEZf*7F^5aE{ja#`Jinb5OARjRO|*q?lMVbG%z#jhA*1TU{PUaEwV!%S&LOH)ZU+dZDI7RhGA1#U&KHwb9AU7&tkVcJ3yP z10gbO+hcXLypa!5lUto!!jMa}G77!%hNv58b*Y!XUJqTHnH3RI&WH2`Fw}!!bJOTD zfGtY~LKge9vYK)dWA&K%Y#FIu)6H%L)oY(6ZtHA=8ZxU#nEiJrL%BpE@5`JBNnAQ7$;oH@TW`JTIj1R2f8Ww~i2KvV$lc`Jso*ILb)I{^NFQ zOySHGU^2I0EWe6p?(|X)`dNJ%YiV^U<;$wFr4b=rO3XAGV3_fL7Qo0h`+bt2NQh&5 z;Y?6m$iCdd5Gak{E&TucO_|6WMNA9@*24E%odjdE5*oah!VWb}HY8e22y+^}nNEcH z77cQD(_h`N5yn~^V*TxVG+F=HeVO3!8cu_&Vr@Kdw%?*X@R7s zC+sHH@UCV-D+oUmcxJ8*FUqls7Z>C@i=idYvc({Ejb|-%?LS~G+5|$Ty4L|X8+6S9 zZ=D=Sg<@7^HPE#VAQ}u>tW(!4j!OI{R05uyZ*c5bR{1j(1@{O#4+wg6X`n+I6OU8~ zLo~?kNsYf$&Z!qIeH%ct=ENwwp2^NNQNg23N6e+nH)YAM*dtee&6sNnq*U)nniT!w zOnyXYZQnVk4GgT`MjRz`?w41%6R3&d=J;-7#>v`>}nUN}RdO9WpEL#`~e%l(UybLmSt zR0VoskG9yP0W2LYUDeN(A(mK>pyV9XqzMnwvg24?7e4A}4kRvOax2O|M$zYqd7CE9p6nnJ700W&=~ABF-iR}%=G&)s z>mF@@??OhI>CNO7D|7Gnxu@~DCf6u7HJKX2avR7%@l9z0%J|dXhd!#o@4VYc6#s4` zSTz$!VgY$%M2MayAMcO`ZT(8uISe1BE2^DFa8D$LOWv5qsJVaE{tl&7rbu|XdweVs zVr~~5-(YO=Xhi8~PQu^AwBJJXq_DDpqhY$-pN-;p4ZBn z$AndDOr$Y zdLo$^$2t23jnNr^-93f@UP}et2v29~Jv@f(phtJ49O2O^&^LnSX>^h0l==mT#+=QP zaOd|bWl5J01sXw3c1MX;+oZPlBSp@G&Zr6dB%7d(4PGQE_cs6qy{9#n?YOPb(uGh8 zT_tfV5E@VXTq}g<+o>s zrPiZw&w@P72uGuY{e@dpqK1rxWagM}L*Skn+e|jk@%Y$=SbgLTdjoRf%)zECdbIYg z&vN6y$472*IEduNr7{KFH(zw#5mcF8Dl*Lm;G3m@#b=VV)EGoB$h{l-V8bAF)9ln- z7B*!sUlp~$pDxh_S?Q&Hd(JskO1}p-%jWh}8S+hOoVMh8?zQ)E|t6ZDv>gC5Ou5hKMmLE;GMYhV{0E5{baLk`do@_H)ZAJ;?E-VrR(kA zJ!E2ZKU9sa!oR+A(PM1(a4dR`MGxUNG?<16>pz#~VJ4O7ASpi7VZyzbYGTV4P00#) z_sX-nr}KJrp^n`mT;opUxI71HF}S1Ors2SZHM+}5SX1UL{&7?3ADgXAhpDiO;{39J z4%0|0x6h^B4#Zne4>{Uxn<(~-}zHGZc3YJ84E*VbTVmkkVB~wY=c;-_Mxpvly~kI z(%tflp|PS{b>$EA8;hq#QJXqZ08^FU(qdp<v<^08oJez?lDE`3#_+Ax}gLPg_-A(6RS z4=%DvG(@Zj%WnKFg-;|^zH;GM>2dBPQt5)h#`N$h#}H(24R$s z4nmi-BF;w^V0hJGIIu&3IN4x`nh5t@3fqyv>^QChyr(OzV@f&9^Uj*V-XsX)A;oq` zqa&OSwPuD0S?pq*jR*sRB*$@YF|ZxM1&U!{kKQ23FvbY{$-#mL5y$V?!&n^@f`BQU z6JLZT+E1VWhS^Ue8Pt_sm~rSd>2N@ejoE&$+^UfA&IIU-qCf!oqJRCs01EVIt&_JH z;vfN9R}{F7K?e}yg?_vM9A81z8LMUG|6wPx^Zq(j^D zF-1S&WC_P0W8!&&tJu=15;3oW(W)>bpFcT+Cow}F)&it5p#6%Tn{B}Ph{H_FCcSqu zvJsVX%Y5GmOd?EyPK455N9i}i!Fawix&4-_+PGURw$HkIUax~Z*>b%Q{zMK4W{8=rJxPQGubKKm zd~{7MO0BrJY;`KgSi4DT>{44uYml>vQw4E_WFWI$A$2ha*->RX7VC%)rX5liAsi_r zYZJ?vGmM6!-*`Y!TmheJhe%-zRe$+%%GqlocFu+~pHC}?FLJfee@AJbISf^9dK>79;gzriZ9RQQyQ&Bc2*v+1s`{k{!&Xh zuom176xk{HHT^}i_Xlza0@(YC5XOd97ada3t-J)PEp8o#45nAMA3qq{8!`~rTVv-zH9jTkB^~#%Ubz+_NXfwK!KKCE}_!A+gD9)@q72Qn~kd;&%1f? zaz0PIq9M7=rM!Ljsoy;I&n0o%UGKiRRpmKt4@0XuzApSFT>sQ9&Rw|wsm5>S0{Asq zgPZWGU=jYpnabbVo6&;ZZF)3b6VG_oe;)UZ2d~Bluf{*MSEES)zADc~b6|7JpLy!@ z;Ne(K{2#m=uX|qJil^h>r$4(lDQjNCIg2b3fXq>jvjy!ucufyMm%AaiIMWr* z>j9^H-u%99GV3)-vMDeQG)K zMciD*w~HBSv$-mnfKwLEJ{n6%M3F28bPx~8`U%_l)WO>l$v<=s8{*R{WQhS(W2 zahO>=Qe%4!-=n@58+$v7nS{L_GLiOF2C6us0rGm20KX_VzD?k-fGLy4EWC`wx)P{Q zl0jeH>>86iB3oYU92(={B0LhbN8_bZ%|VaD@Pg9{^rxx0wH1IG7EZ7`qb#i&f;mZ! zPVu%lGx2>!xt7cO=E_h5h6vFzFN?nmw$YScuuy(5Aq0*i*qq@&qOQVOoW8si=S30T z2C6+aYX=-K#;>_%m?*FI5XC^Yp}xSzI<cpycTq&q`8q1`_#STTK|76(9@&LW}XWp6LpsF)nmGSj_| znm5$LhALiBLbhTxThn#D_xlpYBV|D)YPs+%%p?@`5qK{@YSR;`$zZlr+yi_R8WGo& za;6jX#}=)bZamkm>8dL{#c??pl#4^(v*z` z!^S&I3A#x#$XzGUMdt<=re9^lDCz&okmF8Z&x0(2Tb~I4Nges-@YBo*VPh|UYKe9> zz^gE8Bh9w% zYTV9k`f|iRk46{HWtf7(d^2Cr7Pv=jSZ3Z(wfHo|OGqR!ekjqMcMu5=-Z^0=Zp>ZC zSr?mL5bDczXTk-uwX9C972grwWf{|Ti&TG`i3#;VPVG$waO#N|HsomxlxEZ=MQLA4 zN~5zV&FDxw0)YWp+%Ub!Q^h?75gdjIG!{-0igELMlqL;vE+UBCafl)oAeDQZ0-`nZ zU1PrZm>(UrxHwcy3aDJ~oU2kgX%x~G1SNRIo&??i2d;f397WIYZMSdhFpGchhcqxS%gpVCu>OqoCn!&bGvK&nZXflu760mGxZ(@!NIh!E*3?D`) zN{OgQBJfh0^ryYZIjV`TFuH#0ggGI4m=%dFilx=Oc3=hw(3SmFw3DRa>%fd+CjbN#b;pL@Cjwup^?Tuyn z_ZxN|)*xtWAhWCXiDRRNriNyPT+AyWrOChO zovW!Gwjz5WFEAJ+=bT8DBh_W7ikh4w;>(C`At`sW2=?)jXpfY$89NE$d_Hw#WC>@L zFfLv~+XX>+7N#+7CW8kN>TlM_%D5hS$osGMTNsb-Jedwqw-p={G+?u%FCo2DJz5b@ z_$S^c@ClGmd(gllg~ba8i>fI59>V@Vo`xw%ks`5dFG)c@A19-}JiurrYe=flF>-<3 zfQAu^aJK%wULNnx@HTP9UPTy$j|rN^>D!Q;%SFTTe$kBydR(auQw_w;Y&wddIS1u4 z4Uyg~a-$XHmfEzbp~=RM1nww@38_3~0?&I%(dil~i|an`k{rn{w}CXs_U(9(+#WSH z>;ZGWCy#)#>S@$uT#SbHHxVPwNoiY16*8L;$~&Nh6lv&B@>n`=z>4q@r4?(uhFZ^` zz_yYJn$2UJ?h4@l1?wjxsbCk-BidomD8eCz&fyz6#b`Qg9hFX-@W1%z0&g2|qsq5z z^wG|sVg_7RAHTDsH>v9F0BnY@jEL6t!SeC6aYG%`AABC4bFC{rAH)Yk&sMtX#%POI z+_LwyJ!*6oaO9;VPsYp1EL%+&e%15Kw}bl*t;3E_g3cuA5a-k(E8b4fg*EGE4Z0c3 z9OBxIW1tLKEx@Nj%4Hrj0841CPH z8F*~i&;bIYStM=@AN7?*Cn$4f=uGlu<^0YHKDCdm_g60aI7^btOKk?Xo(NNa zc-%=-IxRwJPABLvtUGuXb{L)=%?8F=#xXAgY!V!~JrLh%xJBo$PK+3HWL#iSdSU8OnBPRc?&`F@I(aqo$nE>=`m02fE z&O38%@WPE065K6FGphKf4qGdfAb?bo7}$@U{B5y9d62ws5l3-#pPF`;hs6ST@K(?YZY$0?#9Em;9>{c6s_fM zX$DDhiopRX3Z;9|QKoShu}?h;cNwbFP;I->Ix8#L-HNPPH~MxJ>lHfpDbuM;@I}C( zSe0%@d^Jtym1@B_X<5kEF;%N?a$SdTDI5UP)W2YSGE@kE=uwWNyY-Vimq!Yp`Oook zl2qx~E+Jg_+~jtF6WvPl~-$W>!-|w8Q3hBcnI=;wT?vnaSu zVDhLxkk;Mts1Hnk7DSVt>EWU`xkHk8vyIazqnlpZV;4GW#v(?sTvT?tDkPkWVmpem ziJ_BI0UX&0hfX`kca+38P06o8dzFq)F!ne6Azaf;60W+EPL;pW(E191 z*9#JD%=O1eoS@FBsgbi0bT80v2TMUDO%te+QoSDg4sI019?H%RL9^>Ik$5MZWt7685?rYAoW z&)}rSR;2IC2hhBoOcg74ny5lF&jiwGaOOeWzO%FyV~kJmO>J=>?_A023kC?Rv^}IC zJCO$7tk+x2h5ar(McWlqS`?1NY`A0~4>7v_R*yISmlgcz=8?e4G{@)tTDP@K~`1-&xDW69uKt48Fl)mH1v z$5qU6*9bnYUcGoAF<;H&-T!78qNt zALzf#^uohql@4?yvSNq zeHoqalr>!Rd7NZ?brX%ILrUrglnW^!Thoz?Ik%6xL5z~xSzwJcM#6*912Gj5!cL;W zm@bZ@5#F!xq@a$7GTfIIZ{&xEkqJaY(A7A^Tc@TT;aEo8LPEPdIZ5eCIW8pM6AtW{ zP0_P63p%ida-8Hf1k2fJ$XJi)LDa{z;oTVRCQ5?^*}}byT_dp4FcmzB@c=H?nFAdb9u3=aphU4rr?Vsc|C0!dU|#7BIxje)VK>>JnO+e&^bV6g%(!uUK zg{U69N(c)lskV5dLx)CYgzr^W-5h6RqHV^%@sKEvyO{f+!!dSXOsU+VN8uogT$~_} zR2h1UY(Q9(^5~R9|@BOH3Igf6@Z$8_=GBVWHFQ+PqUpH$GJY}bIlRxO8c69HP3~I!r%5BZqP; zYbXrX>z!t>FV{*hpC1D<6$Z{)o!?`iAQJo{?4ty}u@W_4Pk*h?Pd=de8pnsE-(^AD zpaXwzIHzAmzsE#p80`evV45&2-e`G=ugS;{H{_zPzCbdy?-3S)dHfC>oVNxKeBGW8f0pxu!0m0&- zxdfbnyynOg9}8^ANk`$_%~jhgqMz!AZ6S;X$>_degbJGKFd}u%^?<}3RYEUI;`4w{ zNRV@)nU5X&d!Snxyoyoo&f)bHp`KU|q0f4~^Hx|+$WeXz_yXS^nn?K}4M!QOdks*l zavf=n*7+po#a}%9hxgox{$WZJJVO`GQ`w z9BfL~(1$HoJBxvGa1C%Oy-;5NF~-fCG~-E>vVw+q4QeRwYq~^rb8)n(CEIEAY9ap@ z^pj^+_T-xGnISv(*nVRV!<%9NH27nP-3m*Ny;e(pZlUtEH^F2pva}h`(}xul=HK7E zLKMw+e2jW8F^; zsgB7?F|=GR&7%2Bace8hrs#o1(Dr4XUDGXk$s1jAksGGOJ$%KRVXHyDbH=xqTbrBq z3toUN;iu`jC;1SbqTf~sOCsZc3$N2p9oY&drUB$(pRsZgc9aB1)0E`3NF|@byD#Ww z#DQ73ZLg@Lno%ryaKPqD(5|;m((6sr2K#T5LW3QIFUE!w)yIx0wee>Hl<`wq)f^4NH87DTq`4sUOgy!U$(TrKM?c&UV~%_0ntKoI~T*ffHh!$tM{m0*Q&j%r9enuQ;?2#T)< z5|4bKxEG{&G;6nDSFTe8HA1WU2>5AfNRC-DZW0^YMl4VdLP>^ zK`$fQmXdg84%r8Hv)Bx|X7>*kRP8zM-qmDxE6Aaif*)#?WLYd&o=1PH^|{sA-tGcv zHuM(vkC)lJ`}HZ89_%^a-u`hWJ9~MSZ((_EhEadE^|{sA-tGcv-ryGZkCy|u`}HYj z>Fhb*-u`hWJ9~MSZee+DhEadE^|{sA-o^s?9qWqoM(ccnBBwjqbu#-%)us7>h>NO$ zQJOrOs`}E#lqG1zQrDKa&HGpKLa1Q=eSL7~K(Piu=7Yz_3PHWA!C;=Lze=W*u8`(s z&3!JH$GxNABALoK?84+mL88-;sfp44K)X1YQ`Ih$M{$}>TI#3iP5BSopRzYi&!Vi= z+WigvV|QPua$c{?FSgrdxhJzbL9a{ZE{jjKwYuS&NhMo8dcC1mM3+8m_Gtxb1`2h1aD6 z*P$Pc5@-x9q0nv$7oZ^whuMNkyFKAIYi(4nc4tX;ujeSo5Y-9by`cP~<86Fxk2n5{ zj3RkUAz;emzpSmVK6&ECe|h%gA^yv~Jk{bqNrb@APdZ{uZ#brSf&&h&51i0XVRmwW z5x0+q6B!%E3<@J7LQ&|bR*T{+wsnSWD<{Z{1*7B_&b`9HF!x6N=(BKox_V(nnql(7 z;by*Y0=-7CHM(es5R2MP6+?wL0vU0UBEwR)=qsigg{&P1z2Tz@Mmdc7F{V!AR0k=B ze@TVKD++ZoW4umBZ)Qd~xES?bMdK{^B5C}GP5qK`s?aCw?Wbrk#!L)UQG{&aRbxNA z9w2fuG@|xmS5|l&uF6@c`}rnB)ORDJKugt^@!cuzZ$9qoHpYgG$CM{+`=BM_$zvOy zFs$1w?!LLO!mn;)O{DveMPT<_q5$;;A0xh|`PvLLO7{A~-_;DF3LOO>xf-DXoWTac08e0YZRSJf!`R3 z)2lsfd+03&C1&Kw<+q2P9_fBxJ_(nC9zXu`u?l^7RE|CmjN!1DP2Z<6r7`T6uz`l5UR9M{4?VmBp9)Y+Jgob z2gz~V3kQp;D7nX@LA#xFtGS0; zk^;(C2KjIoO!9{TtQ5h?u@%Pvfqb?iy2C$uWptoMcs&G-h;aVkt8*c|3hcf$q=Y%!C%R zrE$_ekO6Nmmh>AA15w0bHt(|gZI?QO67 ztt|Q<0jS#O!k_#QTP#mvTc zdUSlX$!xueY-cC2H9#?wz0(KH9p;u5fe#d=6CAQ?2Y7RsQ&^A<>t=~$U+82n7_mR( z)QB=GVKdl8wq42X6T*NLJzRsBH6-Vxm*|~RBLtCX!rC1n@=!zv${cu3Tc4=}XL-Yd zlsrb1$_Iq?go0&;`GCgyMe2HGq;OM2ZCSb;x1<~f{*zcrDd8Mx8c|- z@KEFsXO2V5n`%~-hoJx>8*zuSpY}`o?+wQ?=%R@Fr7fW0TdTE?;v+7J8!^F*73Rj; zsIjGo08ttNt*FbCSH?>bekyF@C`>aIqYX7byA|uTYG;L7dem*M_!|>_xAV=kxe05^ zt=4N03d={;cIV}9=ts&MXJ`?eD>bgSUXq;>Inr-y!Z^XAYo0_ENtBN8uN9n@y!~(F(8bOfd4^WSx80VAnk}LcUY%RM@sR? zL}6o4kG$ubF}_EPGhDG4J`$d@fg?*AgP*){M_pCNF z=FjnedZ%Kcxyf%cA#{jyGt7uCNM?~y2nrFK*0f zz@e28&Q_lC*%I4?jvX03rQ>%>Skg2 zV(6lr?P{kB*E83-^JHFW66`LWkiv2T<=b#hja2m=*)G#SweL&+bdBA}Be|R1ShMzy zXK&&&*Z!mmGxjK>Gw%YPU2dNehS)y^GI^pT=P=6Azm+0T6$NFxEZd~3m@^>g3zqFi z{>tjPYac-swQ>(9(0!jkbKXg|uW{tGi*F_EGlDZMU=n0!kmWkdwyCsi&!M%nd;f8e zbV&ol^|PQ4tRsjSM@PUF8tkOYOnRBS5@loC)Hb$fsvGS=?nqs)nQ!7c1AVZ${F)!H z{iki0cVjEia{JHq^(U)N{=ap2{rtiH^FE$(`%glI0_)EOaR}JfpKro3Q(Q7Z`oe^W zRN6+mKsQgIFma+|x6GbX*_$adPO=!4rk(VIK2$g2ymPZk2BBe9IlrBkWfp6idC@`` zwq9Cm=)Eds;|?B>mV2sP3Fn z=8wKjgHHxR8xfU6F0RxtloTYhDYK9Kg87QLDf%8Su8rLHAjx?u|y2@5K>ld(J(f*@^w7 z6s^4%Rj&J8HK00Y_2%4o{P#FIjdcVTBe!FkB2;@;dn8mOIZXzlqnSxiGk-PxXRGxK zv})T7*x4Y}pXd@H^HdaW!6ubZYMUf&E5vzWH-&)Wb9*DF(R0*1y{u_!$824tp?>yg zU)cN6RVYgJG#dQ~JAWkgeD*8W0OcNLawp7KSZ!QhdNic$Hi8Kkv=6%Z$O%K4{Kr&y z{VUiTip_r-&=YnJ1nK5VGtSzhWE3Il@Vs19!2Dz)TQ~O~PNY(7MOrl3%o%P;GRrYp zsHW9u4Nd_#Ls!VEKnw*YW+b(2xPv%|>3*0DRx&uQ{4Ft2MwXwj4AdGXVXN^jqxbz|JrxYdMA_dxlov|2MayUcULQO--MKY8N ziE|Q1hX25ObZth?q~m-z*rXh31Fy3jQA^z%Ks#-HZ?NGVo0@x*^Iz!S99jq3ZYUnN zEqGkT8r5BL1q*1E)pP_&o1*9N7B|sFE`2RNm3INd@oh5M67ANOV7S&vlgB<7p&kaO z{D5sdh6ai87N|^2LkRSrA_4IxNC=>wU%2;ES z+vG(7GT{}7_2Qo|qyox#X&{l#q@rKKu4^A9zofa;*b0#YIxv<;HKk(fS}v12yV$kKsB8ECu&Bw0wcyTXfoO0G1U+A2QN0! z%#w8CJF+WqP^0K95~fM78O()LKKrzC*x)}_59cArSMGin6TOr(hN&ST{Ku!>(Q$1O zWs~~h!Y}~|9{!Y`jgD$jzAA|Ja{#AmmO>Iq>NZQm47iEj9wzZOUk5oD42NVzv0dD>3kYd_o8uO6h@* zgi)gTQUkX*FW%3<+^??zPCYRW9NVAusjaaaF{I` z5K~>eqfb!S5)Q;dp(YRzsI639hC!Yq2FnLuJKM)?Rr%u8hS4MxY7iH*BwUT)aNZTg zXF%qU8<>|jYzoU2Cb>Rhf~A?66*T~!r_-@uRCK*uMWb+S5tu+G&zIza;S)s6p;4jc zZ_@~fyR_M91ah~uTCnSD?nx{k%C3jSX@t%q5{P}HwP7Y^d^KZfGLh;2_b5+2AK5a! ze0VimR)6_YxWp=i25%sxWDqNDSDGo2%ST-R3h|UC>Zkp1CNB1;<3ZdbV`ZfnS@d)7 zmpEu@u4r}fVLhy&5b^hIje*HtLAUZ@z&5G<@{+6NpIzH8hIgy=@16Ji1%eAcb?=ue z&w*KVT-wS8_72Cu5bC69wbJRR_H!e6WYNP0qx_+ zWVUFKe%KWvMw9WIj80ah68EKR-DxOyFgHb8tRGPhkuzzC0yh4}1^4IDE z2V*~T9+wOUk_?%W$tWH7eT2?&dNyaUDSryJ%q`CMj`#&1GbW$>gn3T(xK|r^^p^Jj zz?BqmC2Y|XtfA)u?9fUru2yMr)x+NWeSK6d|Ib0(y`_{N)`MEHV*k&Tm8Z|2JNZAJ ztgfy+_KXN?_1cTkb(p9 z5kH6H6r+w#lAs@F>`DdAg&2&z)*Hm*@kOhZj4>4wY*+Dn7>+L57@7rnv6C=uW3+$_ zdVre!Xmn9aVV$7kR;!yPrx6A$0G_gqLxEmT&62~IV!X83ohP<^TYcqVddBPNC<~8} zA?%}ALQY_4XV#Olf_y;+T*l92aG`&}*hX0|jmMK0x`}>trc01(>We>~>{$C>5Bu?L z_JMo+dCC5VhxY%oCr{Vc*Kz+pU48oezk;W?If$a?Z@&MF)*o>6){cU5`oFrizLLxT zw7#zRKLHbYr!LZ;{@rIVDj)3J2s-iZat~98Q)GPQqcF zE?`p{gR&;s=Nbt&vKL19fH+an0k)@UhQ9poqp;rye#QGiGf=?0G#*AWS^&BtzJrq^ z{wzFSi5LAAhL3sbj-l~n5cgu~ynlj@Go#~ZfmKmIyx#hGXYGgfyZ1Z0d;g=o{nOU# z*E?^2+-U{V?}24rsn9_|OZ#u$?7tPwtZMgT1r20CPk>Fu6uhPvavGs~G%%^?xqX32 z`v}Bwcsxq7N!-iKU;_~q(II;|eTa-akc&d*&~iY`ZihUU+rptFaA?vPH&%w6?CHADq|purnqOGUa?4m6L`MvHs^ zXg|WNS?Ie8(=%qubIZtM(FiaWi3v4JHx-IF1&VXrDUK$chAQQc-9*0q3#->Y&&o2F8M@ zgnlO?F{Rg8i5k%`pr9Fu%tzBvPvx(%yz0rZO+m?vGuT3lBVHRwv&Z}6Vyto$oR~dP zIr>TkU#NN_w{?YzT+#?4zc-38xNj^x2(g;*Wv2Ctg^w$0vvhx3yi3rvkBOVCz}v@8 zgaG}CNWrZZjoV1nd+^&dihhry0yXV+)*KWLr1Mip-6kY$f|a3& z{z(ALj`?5GAMX`T1snGJDusxFjZLFJ-h+?wG(~lXN0K7U9DSiXJvsv7iict@XleMy1}DQXfmCl)D#srWTV@^tKHJR5Q#-HC@ z@>(f47ZnMeRdZOFq>TpDi9%T-%h?DxT6_E&qz~cdy!TgDFbg|mJb`@cTaq6{4P|docgrVUpXKeZ7;s$UMT~ifvTsR9U zrz+?%in_sWcv4Mv!@_t6kEonG?82kQ9g=8|-TgTjj?+|SQtydLBw9a?CM+O}U?3YC z*5`4O#YoQKOPJ--Y2YIwNiguoaGO{Sy1d+%x~ zoY11-^Em2}^}TguHjUf&;y5FSkL}UR?MConvoPAu zYW;&rjJfY^11CQS{-v?NaI38}o1;2M0%%{FY!K~{dR+&M_#5Bd-o{g;|2OrvH@yfb z*Z;3Qee&G7|5=BZPapLE_wnd>zH!nJdpPV%{d;!+9Qj(eoy9{e!X|}{;DFO*XTcBr zoqk`vP%8T`n27C{QHG#A8^La?^=ALoFRy<&XyP5ixILyzp4#Hd z=S9?ZN4=^Kg?FvUr3)sa# zejq|)KBC3C=RS$Go*xdpCJ>}W%N>?E+J3k%wv9U*=yrk&Rl_o^-*tk~7 z$)hEAD3yDcBr-PuC8yMly{&|0MbpMS%Nxz6(CrrzC#|Nex`?vxR?F@kPW{BZJHF0}67=yPu{f+; z)0!yX{dyM;DR-`vAOuUclGxk25tD*51u)cTk4*HCPcu1fCutiGc(m;{WOItJT3g&3 zan$@D-Uj0YlaNPZ*h&Swc#9afn_iO)+$IgUKLVf-!r&I~92@9JzbP(cWZi!Y$Y5wr z%hADiGi&nF&bcqSvK&8++!!4FFJ@5XXBJt;Prz5@8uKt#Ci|&d*i8lWrz|hpds2f8 z2<_u*Kccpi=?3pE-E9v+VcAMt9%1SU=LL7>-If!Z|4NmA6MU{$$v1f&RO(u z&^#P8g19K`ta9GWjdZ)eUGszyMr5~fz?3)jaK301sC3NCK1WKi;LZ+~;*y)_xtkwT ztM&GmH|-zxJ{;&9mdC;Obqut=cHbwKcYJq#gjG7tJh}v>V+`EqrU#ojqKf*#B87(@ zrtD*F7kfb=3c9q(C^A@jrXoJ zX9_2x1^7=2d<6yBL}SMIcsUyNW35tTtsvPVS(cC!dR3$t6%7O&uAQIAq)WI;a~lQoct zm9LsQkAnY@PL(0uZ{{cnAW55zfnioI@@QJ1iz($%ViAiaGRxjD3K}3tgu$;N6X2D& zUoKD%cm=yFCq$}IJ35PNu!g#+2fk1?@%8Y9^C%$h4!`EsP`GPQq-Aig-NwbwQRZTHtQ?xVYmhZ{*mbSF83f|d!x4iar{dq8E zw}$D+75+_oOOrw1W0CX2t*(79&~OmKlH!RCc-Z;eK8b_c`Wj}&QEhx~0}~)#1{X#N z_#wV@^7&)Q;3tT}-bv6)lC+P;y{pfH-=j3ap(__R^aW>|*eBl`Oo(cS%L&s`E%bE5 zED}73Fr99464E{<+eO1t1e$6E4UQ36*}V>DPXpn`Ym{e9cnT=^)>bepjB25WD>5SP zIt@ii({Ln5wVaKkUa<1{$;$G8O--cBlC_WG zcQZ={t(GyE;V>Dsk5}8~@^|V%b{dbVvGwntEO%qzkmBPJ{V_mvNrPC!XB%Zw;{53VHf>YFTC(a{xXf^ z8q_+H@B<9d3Vj3&B5;TO;Q#wy|1YBwXU@we@nB$gIE*I~HujzYGSlCv+L0I@A;0LM z8EhCMh&wfs7krruCqrTqeF5nW*%wy)8%*dW+JK%g0hZi7aF*m#>veo~H^iw~NT__F zVAa!bJQmj2MnhqW_KLxOe-;R<<g#j}@tv+iupFQy? zI#?;P(riBY{?JqJd-#HwR8;ZF_s!;ie|BhDwi@*xWQ0FnMwm-?d>1^=-0I~b@xaj$ z--mSYpq9Q>we%e5RV)VFrsnz@a={;Mw|iTUW&ce^W@peQ#bzGv-QT|xL17&$;iARcETDyGgBNRy*v7>~%f6@&MCV1Stn!%D^Nktnq}GU97?Jr)ZdI_poJeiA5n!9rkaZVBYa(wF zprgmjN5+KtaLz*jefp5^fWZKhWPJCX$4gMkzQxXUxjU;PScr&hmZ7^{UnjC^t0lp< zr0TeqyH4-(bY8LVs$KI^%<5k^*Dx`>-U_&W`IywQ7qn71!gpbc0XTMkD;{3-8*|)^ zfOtr8!Aj#n&4e)?($57oqp(Lkv4yI%Fq;GzKO~F$M3U4Ur`}-l5qvN0w?O}0$4u~; zgS}B)`g1+F3~HZq)jp#R1$%0r;q-?Xs(Zm5=e{w#&yQC`$*PMJ zP|Z5!u5@}De4 zm0>nE^%aYq2RvZnsX0K%OItYTbebv+}LgdYSm7w>%;Fh#+Vc6 z%Lh3NkgU}y79yedHs@Y3Ep}-nypnF08zy{S%f^Z<8qYBxUbf}Z4Ti(H9RlSHtP+7*F5g!;xZBzM*Fv!C z!|yi6I2VDM4aivp3VOdDfm)tP7Um;RB?Fm3pk|EZ&2(^W zf*4}ynV{|`i%Btbe!VkcX(lC}?@TBe$c!^##z^wLJ$7OVt4+pw8WH?gy)}%nc5|eE zrp9%bQ!19JTR*eD`g2u%Dl6-jO0?A8X_}+~)njPTI^iK$6F15kQ)fFZ-|06K1eBY$ zWd1y#qEbaFKO(6ZOKquKX`F{eiZ%jAXvUAW_~P0d{?uwp0SQ-WsG;G#6`To({9T?8 z5xiG-W+l8~q@5D=S;dMPR~XbvvmyeyV9cMxdQ0RLr40yjs;zYk`Ayr zO>Gh?Hx;&;QFcNiiwFK$w}~9J_XjMyS`#=T_uuXSnt#5nE5#-2tXuM3S>_gUM;I;n zAuBJ^8o@Y9(N#yJ4w#O}Mk(s6cC;lFp0QC6Gqj}_dB>lQqiO&QaI>C$%CWfSa5`G@`gBDY0C;VlL1H1Dd4}? z%okmFQCn@SXke1xm?89N%#z8*$t-NG?zoI~tvU+TWF?{%R=RRKe#07SXmKDoLil^d z9Vxp!hVdXnjD$&3oP6AU%FYzMSuqbUFv;mK90cifAoA%+co=?FMmXSF2px9oO|?bg zcnOVP{-tVc~7Jj@U1Le7dmwop|)(j$PtfagLo`E#KXpl=iSQ7F8^Mhv2FkO<>!$uJ2Yq6LvwBm6;SV`P@#MAmqLU!lwoX8 zE)ghK3c$GJf^jCIEg6Vr{9S+zOD;Az?ejAEn7eVBj9mtgGgPRqdc(11l?|^Eaut#O zAy-`F%3${L{vq?nZ4?en#=l5u^TI6Q)jL=vJVLYe9ruj) zyV!D$M%bJH2XCn`WJlN_NnL7a4Dn#*#C+{YiNBzoa-D%{g^Crm;Q^7ajVdzI)jXi} zUtT-_8G-DFXi-{6{6>yk8pbH&>h_Vus2{9c)xTLAsDGo{O8?q}fj7)Sa6b88-fq4B zS9|~6&ikzo`|l4hpo7&p#&&r0Nws2qYqhNLIN#jiIiKCpI-l*qJ0JC24qs>-Erc3M zP~-970+HCn-c9Kd6w158U1u!|6)gmBQj?&0`o?Ck92Q+CGaRr?sP(-CWf>@3Rw*wF z$|8igBqMB5IRqA$Biwb$6{tP=82BN!&H>KB{T-R}Ip@K5WI~gBi8rY3$#LZ)DppUD zU{@?@(Vwb2%xK0&7Cg`OmYR0;4?N`a8|a6<{0_1kcearIvDLCVbU#`Ha6hU6S-YTc zX681qplI!bM$o;%Za`-V#5EMB3z2-<MR*9E^&FEBY4N29Z56mzR|%X~KZxpc z4(hSYx(-*G}33zwHULs`PagjMC^(TTWwEqqlmFu5`c$j~Mw}m6h2#?ge z<@>&jPGKkESrmk(Gq?z$knmwE@LcT__|PnD49^Izg|VbAB$ms{!8nZ5^BC0<9EKX^ zJ-Em>*Bg#otzr1NMvEqn1-<5*!HTsrFqXZ09nW0?z%oe%J$v2SUQJrz>|}a$WOKN* z+iJMoTw=A^uy|FAQ6{mm%*8-X4C}1(3FY6 zY!T*Q-^S{pNkAe(o2x?+IcM2uU-oY`XIw$MQWKzy!#(B@5T-H|Gu++G?=6K&$SW%@ z*)^y2FrX5M6mW8kam!Rw0(=fs1Z3W&3Et5MuwC3el{N9k6@{*25Vyk7L^yfUzNW}# z9I}20jF_)!w>c~;eMLDGyojVr93QE@VTF;f2%&y$*qyyinDcFti|OU7)#9TJqAM3!n{0hRT%BG_lyOgD|fQ==gm zeo0$sD2TPDqZDKMVxX9BiYWY5?(LP-ZOz1ok%vAbvyQQ8N8e&D^HG1G!>x)1sME^& z8VIT$Bct?^)ehD zC8D^mT|MnI!i1Y-@iJlC6pGjALDIWNImUm5EAVq}v}na84<8=!c;f$sDInS~ zn#8?ZiU3$1|8ISDb?u20|MA(g^_7SCfA{fV$UZU+7;+Fmz=pH950syy%?F4Q@gznH zNy_MqxYlfv0v9z+g>3-ct2Q|NA4RysGUH@$fr^cA5EvM>u;AS19t|h07O4rD*xT2+ zSDbww%`qKAKjS`EGz8zi{D5a4+wC@tAiCl%c#JQg6n)snn_f|f{^pR}qA109-XCZC z=O6~i+iMsQ|HeUiuZ_PP9l>|217o_i%I@cccR0SUm27_a&;K? zQ_yycG}mAVCdyIn5)?iB@y8MJANshTooF_f>WE6@=;?ZYS1Pp7)L#$ED9HB z)&qnJVYfH8haBH6oYXs>aqXc$#ituro5K0;>~`1*6u|y zT@%R0J=s10jBxWUDAIp9ehKatnoY; zn}_K{q%w*}a1x8ehQtz}$O#BS>V;0&A>ORh?dTxLY#BNo{r}nfx8*jjWMLTWYd=Mq z9YYsr5F)9Ay&;JmvMhBg+Lp9Mx!t?D*+3B}kYxfW7zOZPkrNYhHUHJzOw9Gf{7>*t z#KiYs%+>b*-#o*7Pckbr*CE%T4j?I6>aE(lEuv~2bLGmFnJW*Z7CRF>iWt~boMIVW z^zjBjy8*$7QMH;(AQatisiqNfAUzyIPmY0Y`9$saL;Azo?l6*9-@oc|Li#8C!UWia zHm+!a{!nC4?FfL>W94yUju29Gp)Og08xZwS{@{ccVf{FYHxe{?+&Hw45b;^T{`-tL zWkyW_zM_-<-}`VV_x}!e>wRR#u*Ni(3Z7v)*FZZFsMix4J_DKm(N|)m3SjN%MK^je zUF0toq*r+){+NIn!&gc4d>7&QqD=`T6!9cwFXLWbfawV}(UrDJ&qV)2)uuqKXP{pN zs}l7N*b=An};a*Y&%-Z(pq`sR@6)3gDaFtq}%*wSd6 zi=Wx#P_TE?L8@H%FywV~yjTdC@Xnnh(dqKABZ$nMxscj7MbRVt>(1dgKfIIv+r7hK za`%qtZ=TFA?hNvIidqeX&K)ZPGwwR3&(zC-QTrFYesxdhRDe{d|nO1FEet@iP=-DbNJ%GVW z;js;^PosMpX!;9vy#-(IS``v!Sz&ZL=Ps;XOp68fOBb(0q^dXyO21{#RMis4um1nL z!T%Q!yti>r;Pl;%Z{hDPr(c{trNc8T@!-xqQFgm?|2!&YX*v{w7aVHIoK*SK1Tr=n zWOka|OU3GpiyW++ra!)pFh5{CON5;9KxY+1d=}_@c6QbgyL~E1NIpNhGns7;^T85j zygT%M^IqqEXEq$Eifca~r&BmY7`F%+7(_3SFK|e>s#idKNCq-CE%E&fo(3BPm4Q<| znThlIJe!Eq2rj-sGYv$TtVm#mMY%~XFV_iSv1Nm0i(EB|2_OlbC_$q_ZOX!o>xl{X z^w8;Q2Y4AF@^;p&H3ES>1C10_Oy;T0enkKMf7>=k3y}WxkvX##`9cUT02JhuZ_4QCUMD<@g^)(7e;-UV&)7+4`3O^mVyg6g?WM- z(nWcbiWup4f)=|I{SrJ*DkPOQVFvOHFl8l?ApORNu|j>Pi4Lc>T5M5{yipHs23mK?IYG znTk}yR3LcN06c+djfUybJWV-|e&Bq0E)~Sb`#uo6joPfnWS9jp57qOS{;a;H~nrBHn3rlIcZ!d3G6{ zp~(JN{JVYNc>4)h@(DnxZJT~Q1xxW{x?roRKcm=!Qx-iOlq+gr)@ZN^(-na1c0s!9 z4H9wIf(;WN0-GW3tzX*FdG8n8QnHwoMay@N)n$E;fU*wqL(k{ElgdszqihT>FW2J} z2zqrHodALOMOr^4mqL!)4sB{2R%f;>j^hn6HPOB3s&x118U?$6?&=l5N7+>BJ3X0}1N^{W zVwzS#8weF=dT7ju2qanBVNwOr011S&sjRtHLO$MxQVd-Ol|b6Xg`-#^0Ynpvbs`O# z8Jc@&(}-MJoylY%h6*!)n?M zgLxa^PZDnuP20e&4MD*VRTP)vD)i$f3!(&q2OFaiP*uX7qcBz zY$1M9N-zW}m5|_=2nzBU?Z}+nWCaU~UBC%LbvPXZz~k~TYz;tpgLMHa%s?js!a#KD z`A#zsqi^=owl3y^r2&hfO@TsVG5e#mfXuCMt4$`!M{upv{VqHDN&KNMuw^Z{k&@|R z?X-AkGB*Z^qM)SSq+<@NtH~Cyw5>k9?OTl^1AKUatU7meJCXF3^a*gQwvGT1)DVi z`wmf*pyZkjKTj&*0lbO!4|iYgcA zN1{^JGN!>RQI;?;L0}MDws3)Zh{7^~6n!$?dlW4MQGKjHJg;gRhiCU{`dYagb_N&A z0oXo+BL|w!N|ve}kx+}BT#{8Sw2#-3XBZmX8<2O~W?;|;OBD>~+%}Ps-|kB1;kWKf zsr{EA8DF5#_*S|ENLtb@n`8S6guq)3Qc+)@CoWS%ED5#9-Xh}`i&MN1?A?rBw0~rlwOYC*IB7G(GF7!y+geh`Np;4^$xor4=fS zlS3g?SJl8OdLE1eQnOI<(g;%13pr3Aj3`bhW0)fG3g?~18{Be&&9jr9FT@EVSjR$x z$SH}_v&!KcrxeXe6@yapjYMCircje3^x?5c6_&Bl8OwLa+h=`YLBkx%T2bX0N}G0O;U8o(+|85G}?C< zkQEd@B860Iq*j(#Ho?~kVIgJqpkkZYMvFu+ce?~(MPAtzwv3B`SJ~>i`VJ$6zH+X05`2Qgp6UlwA5t2}r_z!EA}} z2{y_o8R#(lBN7x+-U)qY6XiXb^zkwI2F7!SuHH|P7^~gQFXyY2ueBO-RoMW z@VsmT>(&7KSYv7pSc9bCM!EGiox+iv#} z`RML)sRZfHO&Zel5)~tbq1N~Cv|^2{=9u*Krj3!Rg_~|&EWh5dA2Bt_cVA@0{Dv)>g6*b}7dYH_qUYqok zq>Y}6_H;YOoa&HN*?qGleaD}RdY3Nv>9E~=8bac8CK8x{8Ix6)j3e;S13mDM`E+q4 z*wXohr%+e*QIBm_NuW-fm`EC$v56Jjb4sCN2KEfVLX%~U5VE9F8B;+FVCSy@8rh&_ z4Z21yB?tE=Ir|Qjo(5oha%hQ)rmU^g1aH)LzNO5z0ua?IBdC2W}J;c_%eNsO8at{BW% z&hE&X01H_<57|M}}8%UI`WwI8c7Wk@u0Q#)TE08}y3DadAhG3%RdIqH){Y;a^ zDmv65eo~YExzVKK)~+_+f;9pS=#ij@WVMx`lE5YbVJK*eD!9YwQ6pe4AKDnZaoNB~ z^GX|q0&k4?xd0EV0%xRb9pYR(dJ81N+H<=w&zX>5hUq8~(`ENGlJD2;_O9CmIIcOG z!oMKTXS8`3$1fRb|6Pvds1yVOL^JJ3^K`VDkIoXhR|P|3wNq{4+K!5xqa8UU>HRAf zYXRoRnUF3-aR{ts>)>Eqy^*JOW2@DUtc@kLP}c5J(x1DgQWM9}O)KP9U)|>@oHHyE zaw!aco}9_u&Q{ZEM?vG3n$c7Y+Iw{pS2fvNs=})AmV+yA@%*66UOf5G+k>@MkdO7# z-QZrrnorr)$y0eDf*L)Uwj><)w$kT>d%h# zZqL)5-NR^@r{uRIPvD9}_htt!+x)ijq=Z7$Q;KrORu~!s(BlY)(17HJeO_tG9o*|^ z$sL=<;gBGUu0MqK4bvba6lGS z4v!3Ib(6vQM7!bOD$*?)X0V=@T8X2y+FOaQyaDy|c+uP7L%m#p!M$I;@2S@g{?kjw zl$;t&aA->zzRii5hMb=&OB}B#Ow9nQQoG?i%5{dpVA#8APFr7P{}siRBq?LN%Ni~n2E^rJ|(ru+$XX$3He zk7N!vFBSq^dT@QRRKp8(fE&RO3m6$=IVEt2b?u67aoB}&vX#Jj*KB^$BqBUVoSB#* z+9>YsnyIy-b%^czINE+_4L3!>YK+UX=y6=mpnrE$wj6G9 zUbAQ<(B!UrcP`dP0An98E4n8yZ2Ti|T^3d6p0uhFHJ5jH)ESq`J;{tz;OYr}YT)Zz zC^N8bmxe~9S`uePUKn*|cT~bs(VQotyZ@6Aq5jM07 zdui6-&{1#M4AJyx-+D}L?6l)yci!D;Au&|2*PIFL5xhtP)hJe?jqe7I!NwIe{1e~Z z;$V$i8mfOz7qq$2C6js5k?kbe$^-!323obG1hr!_ZQ;vdd8!hz^lS<3CFyZpgk#Ak zmY^K^o-P7iVWDD=Q29Am2lzIi+$|P-rukBAL@~TFt!>E9ND7su8BFDp#n$18jkXZf zzxP$g=O^$4?*D}JcYAk#@KoRbZEfvrf8*T$-QT(YIsW4Zc_{v4ior>A5Xgbxox#vQ zDkg%iwZ)maEHKcB(hn9Ck`dDNnb?jG^*eckY+k5HAuN=mEF-V_=$L=_nMQo*C$#^; z_6n?qZi@=k?Ejs+54PR=|9js&_`Lr=#G|&OjQ&8(Lm>WzGyp)~g?BGNqDY6YWuPG) zHVT7Pskd*^k@|4u)Ha1oRrk%6vXjkcG6NlPKV4OD4}Si*T$l*4bg}t%e(^jX51&kj zZ_rTy+#H_mvb)R|>K?p^`pAPW<`+GTzShD&Re1S6@|k@J85+Dh%D%Y<9*GaY2_Aw= zQ9h0Os!X@5I_O7dphCr)dA-Z}k#c+)jgupA`%*0qGo-phqfG@$-B+#kz`BnH+h=yz z5JU=G*$z{Tk59$`2?F0%srDsLj_~PYoFcT75H$x0-~^5nd&*~hAy5gqcao;0_C;9h zrVjJvbcl>HX1VB_3FGCCfoh*5N`z@gR90%4z?@7z3slkQU)c~+t}HI3Bg%91xdgux zE0&chFDGD%i}~`IQvxUUBGiyq=phd!`%GZ|ZW-bM61`y89Wo@B)%>%-yBA$=Pbg;_ zK9F5?&G9Khkvl=4I!o=ubv3?rv@W~0RhfLJvci{?kV94hw`(Ek9V(aR&&G+~W1auA zaXvk{bL)M;A^%MU|1TaV{`?tM2XK!s_e);NF9+ z&+Gpoo|^SPP3K@xIKPo7P-Fjl|Nho}oBzMN_2AyU&;0*~c(kQ2@Q2Kn_Z?R~{w&zW zJx~R_5~4Z;vB%42W%^qzXUNw-nIB>JLP#eku;xNA!+%XLq@k}g-<7_>fM?w*Ep%{4UPpn@42lA{v=ne{!OCszc17Ig=}4Lu+w5N&t{_8 zcYjF=Oi$DX>lXQ1S~qK(U}graRJfD}L-xE#hpx`{>0UP~AM&H;`o@C6Ksgrn%)F&% zvS_Vq+SqM7?#*m4`BbIEbB3h*Gu3$4GE$hz7#D26q~#SRD<)QSInbc4H0R;{rE21A zh}|yhf0xFHEUCgie}ek5%7^PC%~RTQ(XVUgWQq#D-rx?sW;yxRZT9>0q#LcvZNPVn z1q%mD=~Csb&q{lcq+PU2_bgiQkn>?E)QuG0KYH8k!r!cC^$M^G#L6qs) z(#gUPge2X7HwBMWwwXI!9Hqnkdf-!bUZQ9(E1)mSFGELoT7mNwLBYn3tb>5}q}xR6U}#aE>=q!2ezm z-ckQ4#6G<(oH^G(h*?drVEZWQuTJm+dz%p`u+V3~*DmImDZ`>C<&>l;fv}E*DiZPh zBc=-8Syi&R^5GyoP5rF)!12R3Erf}00 zt_3_uA)$bmQMhzzU$g5);#Tc6g!N6}{T^Um19uIGl0#&@(J2BCMn}Ua1oi>r#%)#) zq!+eJI!StgT2X}Cu*4Y(3)^Uem6a?(sj}i4bawG8D+&WYQ~7C1Qnw6a17taLn1(ey zkM8a^I$PZ{u7=h9btzCYEgpR}=j`oQ^C%!Ii?>b0<@0XzoSnVFP<56vNOazgs1+Rn z4-z@fox|*KoMD8i9tFlJlvvtvKXBIzsCbTxOvQ&efu@40hTwDM{8qRKJ^~Ag zX#ac%d+?s3AK;j?l4E$}my=zcbAcB~l*S#1vNeN_ zFSb$0L08Nx&47Sv8EehVHi(&SkhsNGa9ad+!?|}$)a|}D4f_P6f-cjx}rH+Sv(|GQgv?|;7k{UDEZ|EsTLy^Nq&D_;$>08mirJMfQu zfo_Kn-PnY0rbkc3AI^2M{CAMe2g_{H?LL`av?FuJ{2G#3*WNIfDC{ipPR?1$$)tN@ z^q*~cRN2XJ2-Y37F46q58WTbMAmaeapQZ*)P!caQ0DYy+$I#>^8_J=1ceiUS_C;|g z%3qsj57igogV9khSuEyUzi^mN2gjQ#lG7SweKC=z`9#6*DG+XchjqO2;o39C?(OA{tP1ijTZ^! zyy#fHQ8qmBkrY7a+4}0`GrL(q2{0CQ8m+f4`C$}JG6cq4u}Bcj++5V$tyaF1N5cwCTCj{txN zD7tKn1hB}d&#vn>70-IV#8MrS0lNPuuERfnQ96<=`cEJ)@CB(#D{9aN)+pS!RKI3G zNLM0gQS3e$ck!2n#wV3hnA;b+O~5|RR9%QCG8cPNB`U^dI`$QTTKh>p#7LVxnY+`3 z=m%Vp^r|z}`FIYTs|N5xLf$&1WbP^32(o`RZmTMy*E*F|=#>I54KL()S`__}@QO*` z79N$S5`$UliBV`12@Tl`_z4Bmyuu?mb-}LV;TQK>5UYev!mz#uOFxH`4@%+@SW)nW zJo2EdI{y6PSN>%Y<7+A6gR_F|=+b)wqT!-U<3@@7ygK-Ai>(X2fc0?7mTJIQn2+)@ zu$t7)zFZoN^AWcW_Ho#q&VgFs>PEr{)U1&(WZ>CwH^_!KyJOt!8xCy5eqYD^F8&~3 zh2u~8VU?~t(-LowQJ@<^{qjR_X~vC(Nd_TikXXUc(Wx#T0%>C5ab{MYOH_@aY@a7b zVnl5sQjjeRvhHQYF~(Lx`lC~(xlKw60bWnwHz)}>a3@qrH6ayh;^6g&m^wZsr4om) zyiN)vFI+bi)ut(*NyoKFN05(UKQ^Lu{G%iIADv2#b|fAs5AL<2E&Bh1lFfqDsf0MW zObCBmvYOa?s(V3-VREGs3X! zMl_Y_j0$hozoCsSHoxypTa4S4Uj>Z|W!{xyqRcw8E;T5X(~={cre{*pv?r~E&+xFq zMjoz=QSTffIskPHz0gU0Vp5N_qjeXoWi86AHtzB)a!Nal%j3=-4O7dujv1m=jakA` zY_A%32e6cL!howpk+9v0-bgIHuo>%4_ zWj6?qzUsB3=fS&Qx|D@%ojh}-N<#`ky;wV7l}-81&f64%P0uSZ)Kz^M&MiIU2lQ<4 z4VOcn21s?`8kw!SLS&A_Sl-eGDQo^PtRD&|0{R?zNXeS+0c)MVsKUE>^ zbxiO}wfmO2{VJyRtJzUF%Kc`#`_+-{J)oJsqbW0zFH?N;GS^nXI*Lr!I>|G&hw^A> z1eQoxL6jw%#nlY%z1(7DMn7r~G(6e3g}U2^N8+nH^*Q#2#+#mXc<|s09eOt1fQQqL zY9mT++*fM#9}vuH>uHcWmHi{rqc$$FfhVA%8AWFhPZ%@tKpr3fGv;!|sGK=~2SO&d z^=2WB2_&XXq#om+OSjb`hgRVRh%QW(?g!2FNbQu5@U~&ToMLxs6(En$uS)@Q75AUD zO2L11byTr{b*~u9S6)kyr$|mk6r6~Lk5UM6-D!l%j=unIwTAuzwU`gjir5d&&5e(P zX8rYuM8}p%@~G|pTYs{V>)Mw8nhyV~n*UohEE@v*@U(zY?Fw6Q>X+C~+Dz=DuaZ^G zC6mxmFW#q$Qld%TN~-^n99r4@pFltlssm9;T_@Ww8#eHL{s`ZI(_H) z8Ku%YODWJHg(|cfoMOfadG0UVhABsN5gj3E6y?XgtxgEhJ(yHtex?0>$v%MRI_q6+ zyMKfA_Fk9U&i~$~tDm1+cxvpwPtuE{bozenzjy9#-*e-C-QD_}|M!DD%BVZc%qdfC z76F%t)2b1Gy$?Sw7v-^kOHbaXDnKCY)T~ydEN|OU+L=8V4i51mgfYzWkGhJ#aS{FNK<5V_czQScdVEzhIKA-yuzcd zMAatU{Fu*8H~1Ec6s9Uxu}rjW_}XF>D5t00NOm_9Jb>CbDD_|}G0W@g#WY(`dSk)l4Toq>FgS02CxiTZv!nfg6M!H7tsY(F5mqFuOoz6@fN0RQt zvu~8wvPHBHu3=lPb_D-!i+?+v4*i(I{i7RZLbi(1J|yy)O7+4omssbQR!c?vv1G3+ z%gpqya?KV0r}7d2>a=I2|pd0bDm? zG{z|*WDm8w^oKd+udk|0Mcm5#YC!-;UMM)41~#zff$TzYt`yaZF9(;=05XBCv$mbW zn58k6nHgzHFZ0EVDfgA+wYioTM$KVz>%-=aUt`=>b?br{$O&Xol;P}+LS&>@AB^Qu z2$VR!&!BKX7-@~@^3p86SC@~(t!(eSdAeB6r+^`9a^K+)pC{RPIZsOo)Lxp3$>b-< z-4D|uJDPI#zB3t;kRFL|sBi^Rgoh|t6OE5@WI;OqjS)>7$dkG^65H7V#=ZjC!9%aM zoVZ)vg2%pw+kw4AFK9K824Weaf>V=f3ma~Wb05;d9_u5SFQx4Ju{D$+%qde?5WuLG zhbuFnSNo>j&ej3{wS5ph;ssfkP?G=LcCAa$HFJ_qx?NyBRH{1Fbel*SYoQbqeoW^_ zbjB0RXvSzSg{m2VsOFQf=Vmke`f=l_`FM~;)&j5sc|LO?p|B)_mNV%4F$0Bt%aldV zR@0T7aw8~Og$3{&&eP-kfLc5|tVYkWhof2%ctT@D$n#>+rcLs5*!l2`D znT?0N(~}#A3M#$3uXD^JO}8lE%3hY|9p`-6VOt)J6PH;|PMbd|h*obJ#k8?B8wQFAuu30?83P3fb?f|DT@T{kIJuw=w(>pp~^TC9z>ApdD%^5_m=4o za5WtPzMg!EqaMaAVaXTQ$Etc9^6^JA?<&!YH8TK`^F}3jDMdVHJiAXf1Y2!+ZNDwW zGZrgHJ@g0U&Q||;_U2XC+X^b%taKBP2hY@>_bawZUSip=rP?Kg zv#c@RcWw581v^Fc3^TV6nVFu7wnY!VDJ^tcVwTQMDrYY{tD=Crp-j8gDtRBQRg+&; zo4U}%UO&s#0auUL_Qg7P0lkGW4K`jDWn{nF%2+U{UnH}byk7W9M=U6;T5w5yHv+ZD zWxfJtogbDgblB;+fS5PhPil~ZVGVc$bgTvBo`Y%$}0Yrvpk0OO=AbZM(MDBc=hTFHfe_(QdvZT)<-em+`1AFXaV zxu75NXf1qC7ENcO!=xZPlaN-k<$h%YBZ)x|6Y2e8>VJs0!0gLhGE zsvraNzQkz`)dpdjh!>DEA3O?0Hj`cXpM$msP+V;ZO-5kuLHa@7dee=5zkn5Au|*|0EyY(Ckw` z)%Kr&91m>!&z%Q%x9@+p|NIcoojYGf-@$@UlKBak7J>0$wg9_1I67Yc@apAXBN+u6 zwJs1|L%w+Unc{x(PwD=@mB`=pRPX=$_r7`H(*JL^zS;h~|3Ac2v;RTpbZCH%7=D}- z$K>8FjkO2htT{)gHQgjLBgfd`&*%B%r)dWF3zRsnI)XTh68`S#{9?Aq-%O9%D*Er0 z?zk%Sw~iqGl>T5gec3ck=Gkx3(~hQyQYy-b)@R3SW}F`_XKlLp7GuBYDW}OE*<%6( z?bOzWiI?5D#+B6RvGjRYzg48N!n~R;oiZ~21P-T2dlWLwF{(sQT8iNS9QT5SS^#mD zr#-czB8Y~_u`-=QRMph_2r0lQCOWsv|AMtb7WNJ8>c5c9hN7A8B_Pu`k8JJ+HrH13 z=zBI$YP%#t`bRT0(EwpG5Hh$gk*DaBjrUP@nof<){PJ*|4d}W6ZwR73X*Bw1ou*q7 z+v+5}i1zyiNc{t{oH$DgZ0abTq8v8Vv1x@&rG`URZ8VY&#sD(|)cDcIcEA?yw{)Iw z&XOU;Jf<+`ph^_qB?MAAU+|A#z`PDqZR0-5MDeUh2`~bw$QFE*k8ws5(~jQcpu8Ps zVn9m_RX{xoB9YGU(m)0yG-JlR0R4`yya~k@59@Dm{1jqb`t>%9A0CJk{xqKs=3@OM zedtE=53JMVN(kMMOPr4t0(H^6#p>ul`2px9P3IVL8p9qOL3{%=7MBYQ!uvFzZVq&4 zA-tu9xYuCtts670lKtsnPnR~7q_5l5Ry=?35YA)2RyRP2X> z;zC-3!s=d5LS1N6H@nt4h{B_^Y^B-T^?mri=LZK8d=nL}9PifT$pC)a`nYh(iWT66 za#YYO`_y{G&a+9H6ibTB-R=G?mgQ|WNq42bPTFuYBFO{9nBXuCBcE4kA~o^-nh``@ zpMCY(cD}Knq7U}VJ)j>wxF^Q-jxFdkU(_yY%Un@auC8ccOI{9VBfVFov&WZ@&ANO3 zAHGTSi>V;_*-(Y~ENn$GdX@04WSaJ3nSxoU)A5(g!+*M*=!x_~mh6|8Uj0WUaM1PY z48BWdM>AyeQ~_pamkvlj52p{=`s!U^kiUZre{Zy$Vvxvq4eS5yuWRk-@{sEj4@q-~ z@ov*$>`s}5?Fc%2T*4L$dO-u4^mH%-;46DDT2gT?Tz#P3DrY)jV34(@+r`a;>5093 zO|m(+FEe`W6HuFY0QI9fs;qM-u9vun(1Lj^Y#(r2f^{CjS<6| zbX+@pF6-&oq&7l;uMqMRz~LRc0)y|)-~va++CWE$ zW6CsR=dUh=sG9yJPEFOmjxtC0%mRla>5?LIu4Dt!M(}eM9pi8;%u^O6awEh`(mDLm zY6fh)b{k;19EzNAQ;GR1@#*?m{ANcEFTkddS7j`VKL^39sst2cZ3WtRtyQ znjlUG!xGc*0paJaK|9Bax%NU=2KUIh^abY+c-EOetD=hZizwj?TH$ zk-yQs7;PbJ+$twh?o)LddSz=)R`@)#(sQNf?^ryd&vQF`1*Ij@ToF}M|XE0DgTdE*oR!OprMO$)jT*U+w8 zp;zTJs*EmG(xNK*(}3o@FFI34Tbj_51~g=Ky0IFqxF&sQOcR>XfrX=O3_W2CDA|as z?ro=;2Gz@W!$XTT)U4Ry%AB5TkCJcr4XT`k*Ww+y&6jS`HpBDMVKSysN2^|eP2{b= z7YW_Gkz1yrsE*~U<@K&h`!pwcV=nRrEMx;t5vUxGWk7VUo`Gu03^ie}fF6~mmkU<7 z7OS*6i*y6l=&%v*hg-D4I2yA`O<1JQJWIs}S$R`bZGS2)aU z-AJ8EpaZu6y}FZ)cyekgBslcylpGantTT48)ujvokTZ}vt!%rw)}z5x?J48RHdTLM zVI_A6EW{9kf?k}0eA3qHR@|p%aebDveU*fJVH>)ZZ`$YEWtCo0cJ{E@0a(EnDJ=gY#iSiI zrUw@*vQ&C|$>oilrD#Quy`9aOSwi^?B1d<;rrdRHwK~fw?0P-|j$LBp^i%g4WSptf z#NA_wg{j^OR`TF78Rcb#7j!U#oL*|lb;X=0eo<9Ug5cFj%#3H*jKaIlfwBMI-9b_+ zaaKs%Hna6hj!wzB_9~?{%1Z+LmW^A&A~}(vM5OK4P#WszqbR|QcjAw; zY%xuX0-P5>V4J52b7a7_O5GS-F9zwsK+X)Gm>0v1y$@{10_FD5LoibQuLcpL+EFOC zt@al9Dv3%R2E?}#pMlRF0regMxG%bqV|1@Ry=PN@6R!QUd4EImek{9GfjJteB+&3# zhNpmVHKJmLN+Q0jGAwsI=TL*Rju_+`mseZj2I{+<%u}9OCHi%lFER+2!@@xw$A1Sy z+v!sLdnf+;Kc}0Jh)?U@I;y3gfmHW_fQ{45<4xm3*N5a~=@iy~NTJ$ESBIwnm1lu+ z9;)_o$RlwEo?SQsNTE6#XA5!+7-y41I#5u(M=o-5|0>>#hoe#x>rut#D{4XH_qQLm z-7as-P#q)Sot_BR5dI)`Dl|s*NW3bajCwvU!}I{qj4^Tv3?l8lT4|kr8~otM%l5(3 zq0MwflFA@ulRsZUfC=xmpJA0Lp>$-q{d{<*o>Ir-l3VGLo99(rIM&NB!YWiR(w8Lv zEZcd__?)jENz8$#S+Jt z$|;NoQ*I}Q)!DPcyFpiV>-;V*ZrnaYMGb%uUGLM|&9#B+Ng!4ZDBu#u*TIQq3CfNU zWr6r3#ZbM}NwG#5c-Rtap>@lykq zI=c-E9wAGH3RtXi9b9&G+e~FNs{&@F(x~zl_U5Z#&V0TO4F2^Os@@9t+VP4tkgD(o zD}W_$4*%a3_ODey6rDvrlEgGJfl;Cuf|TZh+~GlH`F4pm2KjuR7PB1lm1EjPaP3dq z#t#ea03fLbrYbC2dNEO=S(r5EVzJKcn8aiz2QJy0(e?o&kLQ@F%&otnf*wMV^n4}; zR><(X4Ll`XP#6$gTa>MgI1^^6$aT4dmkF{GR*5pc!YUMIGWf&kxRnAWy^PjVjlRPY z=|`E0IW<%3MK+zL^Gg`A_?I|Ci<0hI~I7poBx z_mm5lvQ>QL16xgn8h{C#K6$YV9!(70AEq-T8yGig@Zk>uW$a$e%J*Pz5U8aH9la@4~zZtSez$0ow|g zhGAI-!*jQC1DM%+JB;lZ+9AqksmU<7szN7dtSTX2VwA?WC zUVQ!6_p9hB?N)_|WTGLk7`=2ZXhH8X(n*t5`trStVv$Z%hGAuJQ)_rVzA*u-O0 zcl?KHl!Q4zkTWp`%#IEuIfrnhvQt!$n+l?>Y>utjrUcES6=Fgv)n1S6Go)1kF43nR zukgc!_4_D7`hC9V*G$MN_xxnD^wSIhO+$3k8arR=gPQM1|I_FNWTMBd7w2XbTt;(w<)yUi^n0H}=ry}fns?l;>`{O<=3?mqY& z|NBEcIxzR^xgdYfvvfSH3CT^=wF{N7xQxMFEN2+h+GQXhFOd@OWDCJ?-726qb1qg9 zrk_kNtZ35j-26*zc98PF-=xs9AkwnEH#z-P9yOXJ*f9~KDZ?}hZD4MEu2Wnan;yaZ zARX*y@Q>hCMhh^9ll?_~@t0?D2xbwgL@yhj$KrqLbcCwn_`ADV2I1|;0WuU|*8s2pvWCR(kIIPrSvQt&Xt7+Y$!bZSS%@IU!eAdzH@AlneNzLziO+Ok9Q zff*PuX<-?ycooBguP8~Tx`^&kAzYiSb9R!6-;oPe?d1Ci(ZJ{={30YlqiA7RAi8B&25_rP8{ z9x+jjRgeM=;La9Hsg8Yw5%JHdv}wgnK(@8~mEmMnUWj zk75d~KWEI%vH!~Tq~#wk?4QaYod#yUAp$*T*fRlf8}1fIj&vVJD?xBu(c@jS3i})4 z6`P4y)gno%y0uodO%Qb=64ApmsjYDYoAdP&e7*NKc-4b_jb8g3>d%7%tA(rbu}CVn z(qJr%y4BHWTDj7A9IU<75gGD`tr4-4KHTXZA4D`FEcThcO#< zn@=Hl#um#%5W92(dxEK3sR0>S0lx^|dd1#A%Yf}wp?qGgnUhFo2 z1{#Jyw&d(+s)H=-EpiVo>d+4(hdT7DM_;mOH z3`7Vf?1%}Eqf1qRA(ndqfJMOG-M=x@OXuGU>4oz@Sxe`CuJ$vw)+^L@jl*%3z&VcoanaPn{-CTOB$g+?#rS1Rs<5sD^)Mqk+|EOyc^H?U6^1{mdHQ!l4Uyvz zv=Va3@!lA5I9$eFc0Aksg)8Nxex4^YI4b*p7JnQ|%~?M0l}SYCIV07%-a!s6o1Sw;InRL zBzEE=oeG!>7#SFQR{UY~-`(XydaLXuLNjyh(*2e+^zBbg_GZ&vsk9u0fwy5YVN@K# zO1o|fGj%WY<#KYEBH~(Hl5UIAbXlygyn42=7OoM% ze@Mfv0nW-g<&b+39FjAfl_7}Z-__EL+r2wDKA<;gk&jPPI0;I%QGH4Mf%s<&oh5T9 z`C2Z~%&EDU1eEC1CWj?TwbP~c zZ?zpA<%{T@80?>}*2<4e2j!Y=G1%qg z)!NfKV8}E*stZx2yH_^7foYW07~S z4dlZ_GXnFwT^I;sr+|AoLYInZG$=aQK$vC2Ry?Mw12-+xVGI>JEW%~nvh1(n%cYo1 zho3W@WH{^@qtzG+wOU?6K6pYk+3Lq39=WkXt?kdVT4TqI#+-Hd!EydF%%KFZZTs%J zj%hbG?Vjdkrrh^v&axrT{XhP9G;1r4vk?%h!wbQ0hMkD8@*a zIJIB{Rba8f!_2YkB0Hj6C+*V8a`12?cgyENyuT!HyBiDs#0(~-@%zd_1hSuQbEPd8 zddjX8!&brk32e*S4y?P^vZqysf$C{6eb9y&khMei4iy1U8^&BL#b=aDP_E)ATodTJ zL$w$-RUvd^gs;TFM$;^tCEK+$blkMJgPyCSC4+f+q2|a~iiC?Xf{-UOzEVQ&o;|=K}tI%7v zR}MlPTKVT764xPZ4c`*}?4K)v^P-d?6%x9VZD-5kI5v`~CD3zW`K=fJ1I+}{K9Zzm z*Sk9)FJDK-Wa3s?u#kaP)6}rY)gtohEO9A-Z@}g@XKzaw+DeNj=T13*7-ks}HE@bubwhm~FEY9l$%v6;Mze|`3Nt;|aTxUA9$m{G zg`)a(qjlFJU#qp@DbpXimL=o_=9!5EtV-%jqGiOjtxh05AbO$z&_ zFN@aq>k@SxI4#nJ5Y?;7`@-tkaktj@YcpT6y5lYI6m&qyKKI5+v8X8mwsNOwZ=Ro3 z7G%Tf%}%sxt8@iX`|N&mG||#G?YnLlWJ|(Uo?uB7(Y_I)+;;TnQ51{PC#r0;se+-O zSVuP0#8_U`I{q1MKa*p?f5 zGZ21ip${d~M;gt)t$BxQv&Hc|O@`3sJh=cg87${>h`Yc(y4v_yJhYEZ0DY6?O7jRxi=F0B7|lH7{J}1b$z0izDgC0(8weZI1Dfl z06<_B6$@@*G2zD&3SUQAwH{1Ed&qz|WZt0rw)FNu}IpMc3>=z+afTS%WT4caq~@nug1-iOs|SAiOK z$t#!f1y`+5%uRSmJVgP7hX?7vJG-N76n#lr&7w!AQfRAT`tWgvk^W?qA81>gdG6cL zmdATX!GLHtN>NqWP{f;Y?6v%LwB1tfktOXBT@%Pe!%%mYf)UsWR~V+_Mbc9=5>upa zMC;-#J|Z3_a2oUK7TZHouyw8HayYw4T1xa~^@*88)k|O$FrN!V`vo#3huDUOJD~yb z;N&%V6@%(myyArf6rwxPTG^CK^q}P+>R_WWq|`YR!dWGb)bw1{3)Htd@p`fMOk|{R zf1Q|%alCH$x3)Ae7k?lw)!k16qG2>DF?3`wkKoz+;9fi0qW?cAAs@GQWUh2v zBKzH&rsoT3sOx$|x1(+5|14dfD@Y(U2&+}vphYe^Tfyc_+Xu0JDu4wEd8RD04dqsW z%~Mr%+}i>Pej|#v1vU8%e}Q1XRa!~$5=|J6jpza#zCoJUY_iwTj0#3G-oii2p;|U; zgme9*ar4l;f9s9KU;o^}>5m&vpG~n65@P!GI~^xmdlYXppc&0t+HBfVeHz3K3C#xU zbv{UE3m-q*QA#V>5K({YW$+g)*Slrvvfg%W^veoIBd)^wp zTd)tR=9i+22A7+wVvBkN)|8X}eL0AOW{a(!&5F}RHHqDUS_DY$S*Qwb{X-ZAMB-DG0i&-;k5qO?VFSOTw4~?v4 z5XgPmD0-yFt%G`rRX2wL39u>DLfoJw<-m`PDILV>?KR0N3}|PW-c;AAhb|)5hV%*} zLv`?ZCXtY#iTZ*>r;d&{LhE^UbX<+s^+yIEwbUgWEVfKFZwCi&5&v!n_ihXCuA0oA zR?0&X`|N0h8t~ZFM62u1yWQ`f{qXk5jnFE;mrMaYN0n+RvR8d`f zgQF#ch%V5}vXGM1adMhcG}7n<_;)d~Njk~rEQjiGE|>`r@k6bP5*L`bQ!L98GfzP7 z&~)ez1?a|cIu_)@w;``E!0pI7;pDJR<8thwsT@7=13{jT?J z>k{`q)~mN#1YXg!Ts<1uI?An<<8P?Z2Ch)X4!F8`S*~t+5K2O_DY6wxuZ9M^=)VU(N=FR5U#ICCWzpkiNmY zBt<;zkj3%RcHK}^B%^UaF=?n=yvx2>sR3Ph<&1kz4-X*8;y)27R;JI{MpFy8RN| z=rB(y)h0!RE+CvUgh>=LD>96J_{$PZpukra3+gu9kk7nW4l zxe=i;VO$}`Apj=@mK2$8$;2vzVJ?syXG#Ks)!YxGS9z4TP?Zh^J8Lz?NOB{GDr)K;%`HPq4kE&mXj3k6V42q^gZ5JI(!kr4&k*hm7axjGSB-wcv5 zczR)sfd{b$xs_hR(T0)eq(ls);p@ufvUgb^1{js9UM?>8nk}M?E3evfS3x}i+119c zibG&IF=6+E+S;F{!<=V$A&zkfjx=DE6>lD*`i+V8UMmFD^^J|g5`c!#=@5?pl3}Um z1`F*}KP;(EqbP488?gaAF2{;$CC;jta99PI*QM0@ zHC-uJQS57C^EI)!DfV7o-URQ;iu-W%@vgMD?XuoV_tGkRsIGN?@2oQRowC;JaaiWL zsn|5DO!L+T652&!h}2M#24@W=16r-)dh%7@F+>(@M7Ao))k^(Tlc}a;XAf?`FiF&? zEL-F#+8Dv=$SZ~0+sL}vS1+H{LByhQt3eg-b&CZjeOd?^RRkuyCgZRwvWTIruzsFy zYqbOi`tBXA08m?1mPP{}`^p)Q`VeKuvpLrO(!#MEok?@~uCnvmK z2)G2Z@qrT1gWGE1*h~<(26+WP{)B=!T9eUTzjN}ro3c8uJBx3|bEv>&$arj$%2O_S zb}5U122&BGi-EEzuZFMj%1uVd1X5?cmF*prn%_fO+{#D|b^uM723NkfDH*~bfdou; zCU>F=_WYo#o>kzUBQzO1g$z`Z_Y5#8{K>B%%8gmpZP55Cigo+OD^S26k6)<7_NC0; zrQF8lBNigLo7C4k{KWrl4!)s1U#5n8MpADA)>KhEX(^)sV!D zHFT~@8t;)~nNMhsvedGZD2IXbtCgGNi8al*cP|8SqAQFFg(y%RfvzRa4G6POl<9H^ zvtUV(dO;1HLljcpKGY>kgDYOcPVi<%cC`*o+NQ@WR~4DLBvtTbME?fJ2*lHyCDUy1 zWxRHp&B1z8o8}g1(m78d@ZK;QF6VH+EwA|yb=CsP)%8o%^_SUBmf2U8n+@-W4-5Mi zBN&6nZ}V#9@k*cKPiMf|>G-1>vfi|pJZrsog%U8YTfa;$qs_okB0jXE!%NhtA69+d zDE+K<2b2lz5HA^*x_X!F($yD#`24`rxig#R`KY*4%m;U7<9vE@2g4EHxy3%V#PiM8 z7W}*Y&Ha1)U-kT9`~J?(gM0Vy-o5+HAGUVx?}&e*`?olT(q{?uI*R@%P+!`DF`T1?v#0^_jnimNep(a6Tr}|?`7)X$7tu6d z2=+E5j~bjvO7YKRx|wl?fjv;hT$m0zyp8-2GApB*=j=jB9I{}PETHJ|VlnI9xpQ`Q z)=6-roqT?DXG~>^J3qX5`t0T2Gc~`Trene78JC~Kizu0a7ZW;6j+3(p!fZis(IKW= zoknN#3~b@V;g*jUXM%x)W`CokW=c(xb4dJ{c;_44}{Z(qE6DSkbVp1k~z=&vtce&3E# z0VmOqv?&1jYm#6l0m)TT$vbH9W*Ct{=m^VKphv~SjW8JnjsQw-JKH0jE*r&x{p3OwF@BSjB zcTAxI?pE@(CemH1s02ef6*cNZ)>1!&rnVFdQ`%Qhg$DW$JhGK5%`Y-%Hp%ARt4Pz@BYyBzM&fSd-) zh@#|hQC4nk*8gtPe9I0Zx#_ndp8`zVUPHc2!QG^W3TGJ+B_u~JO2VBCdv<$|-gemz zZvwAU%|4?aq~Cwb6w_}|HTS4=gA<^M0`6k9Gw@#3joWzBjTC(n$|cVmjCWT>tSshduO>G^Th%9$E`mZS@VzkgV9kuN)xzc5@pwl ze4Gsh>D*N8^d?xA2?oYU-+WcOT~(on<+|N@I>_h49x~}Yeo!c=w41NTsLk7s-7 zlOvUE@D-Gjm9ofWkWM;_?(%PVIaNk_;o%5me+dpFM0Qu?o?J>2gZl1gBx zRVzsSyMm#{-~oc0UVu{_a?D zIiPUC*wI9TztPcDw*ujnVEvaIM>gyOYXDD!gXoh(Qg`eXCr~wl@`4Z@>XU|qo6yO3J`UiiP!I(6P9+Ud58rzR(7MWqo)wa$~i;NRb<-Jla9<4iudkmkFtWE8$B&V2svNafw1sU z?csgBXah9X-EI!{sMa_rwurU5j;p1k9PV~s=Arz5 zcWUZTr_+4bkp5M13^hbJq~QE>5^kq)MzHSdp?Hgln_xi zrvtWza?5rG$6~|BHnz9qTfN4H`2OD4z1~xL|4)gbZ{ha8?*9M&&eqmF$NuA+?VbCd z@Bcr<^ZEY&^ZozFdjJ0#NzjV7|DqyRMu)382H*xoKb;Q+-EIq@bFQ=@AfHmQ}OUt|y2LI&_b7^$37sy7}Ax&IH<<(uUc*P~cY0L2BN z-^APM1mX`1Od5?u4`Qnn%!cCKv5?c0v<97Caf^!YKtuOpDu%ESeDXY>{4~wP0!>Kc z6g4uqfX0MC3U?-Ru(^0TznCrZH?R}Le;{qWE`+(%iAR3-V!Fs*OEd2`=}58hqEq=& zy=i9CVf2{Yu3`|((Z8a_hq1zMBNmt2ei#|Lu@Oi*5<~bwkPflYQu*^Wv&^7vgG`qh zm^KyRV`yR_0_B#AOze_wA_&y+Bwb_!Q5=J~a)S_Na_fI_f2h#hfc44h32sZ=!$36f^*lw6Z{ftkpUQ+Fd9WaJBh`l3ZB@S50sGGa$%) zBLd%gB2>+<=Omyh>&+Ne%#hYQDP^?H3ZCZL(@{{Yv2S;9A>fYmY@k|0&Ao~*DzFus z%0PFF)Kk(p6ZPahuM-Zc%4R6AXv+7&1)#N4eDGJVbxq{~5rQ6z%!)vh2;d`u-Ch72 zSW6TsoqP9GkL}9caeS{OqeVLBE=UzdIL>;M*y041V4%)i$Li+&Sloz%5idom4R4+* zfEHEwtat=KypWlWxowhyCLE(=DL3)2xNr{&LV29)kb0@LQxv_D$c^}N{yi4+8%wCG*BIi^QGh(&Qa&h zK%Hk!PfwW#2hIds$-trk4t)V}Au)K4z04n%e1gaw5o&&wMEg~nig~r5`_r{*D!-m< zRknQQpdR;S#>|h?qb?~jC9?!-O3gv7bg5ZJcx!Gqt2U_15*n*bxCUrR~L0Q zUUlIn2>?ohAC=^qHOUI?TbYNJyR+bo3SgeZVFDp+rQfTN&O)aX3gmF+SXivS*qB_4 zy}ko$S*{0no5bvIf9_@I+ZhR7R3-`Oq?6g=qNk8DZndM!WH4w)^_VS+L7aP_?SjBK z;c4waHm;fi$<3GM(P;d60=xD z;fibvMXRTD${^GD&=9=xll5!9~c~aVD_%%+wj? zPRdP`_a&0+yAz}d9bV=wB{tlS?nEl%A)rFbA+RdJ@Gupl@WZq4Bxqg;7G6`Zd$^%X z^0ld0ELa9(vEX0L^POQh7OEUcyce zHd#JwT$~=Rh|StSiX*lLqtF_NGIZBMsvf%Z!8l;EbULI=C<0ar@={p@w>`;Vo)?9_ zCSnZ=oPli=MzSb;8P&0{f-AoD;cB?#=OwIg=}Bf66O-wcGsJG)kkEj*fMCPk5CZP- zss~Xw7at{*{W+^Pqq!DLQ^x8=u|}{ z)Z-Bgsw>EZwEeG4>&QYkA+az5(#pvZ;R?2rZ16q>5YU#|#jcvz%Mc0*61<4g`=YssmY0m(b^&&%;wumK3z4t>*l@)49{6&%}Ej za06&N8lB0^#(QJK=E<~t2Sg5$@fW}T`+qxzcbm~f{BtK>i2r`g zQ#wm_ST^|VMMHJ-FO*uQtPKz(6U zMj(rk5PQi+fMx$awUYV5nIc*OGnOb@L}M{=7@;hS((nKLKmFfuTr^gA)rtO`;GN0@ z3}w`1g=|jG_bgwIVI+fmJ{NDqq|@`kcsYc@O2)bD_ z+;SGFY#X@>g{FH)cUiG_8v89bc2Tzbx~AgMa!KY&#%J2HqCbhx!9ucsEdTun{YwFR z&^s9HC&|7R@6RMlq}!_2*@Yd5R|~GPnx5|5(!s6hk$gRG$*J! zeTf~zLV3yJU|@8P1r67yeJk8wXe2)EbmODz8gRC5ERiG+j!Ff+=3q>w?$2 zp!Re*IZWs1S%t=`eU$mJgfvr?Hs?{FE?WAgm!IJpBax#~My+<1bv4KZxiEM$%BcBi zJ{Lp{a$R>JTZC#;j8S{+ME#S#Y!moL)m?wlw|c_nWN*yyc9s_z+E*W?i^3j4|K!f1 z&x1<}eqEY-$-$4Zxe)aF%$}l;f&5V^2Uhw5z=!$bSSjPkmr4$!6Md%ydQ=`jMX4TR zfjY4%y#EF*;UXK4(d;b2cC6tNWMY&-p<_8z(%WHMN+L~<#DrUBW`B%cLtcVHzo4HH zrR#81imD$%oCQ~JX3*Po6GqUY9}8?w=DT$wWI& zTkY;w7M5nYIG#rBvQ@T1zBRaTXK6FOFzmf$osU|;VYh3%x5S%gzqVzNJang87K=fT z3OqlDB0naxhboU2xx58U%MmKnO9W;rLH%?m}L0@&-ptO^QR#(@Vy4;B|s^Eh- ztQys*+_6AH7J*eDv1W0SUKH$tP|T+tZMD4nLA_y}JSLXv*w)*_Qx#$X=M#>n;4Omv zd6bQz)@9sl17KR0(U;<%PFC~)9=+3K4iNTQ9RYhQfG#SEN%mSn%_|3=_Z6D~YYb4J zpO)NYE~jVnWY&Yu#zh)mnyf0EKD|5b{^<&d-w2d#09NUGip#Us;+Ui!buDKw>pL(q zQfDQch4RJ%FI|wl+h$1;u`p-~?JTUJnxmC1-D7n1TcljRHT6Ra&Mz6vOT;#l8^>J; zLD#eBk!9cLuhet0n~d#EDHbQDM$J0J>)S0fj(Kp;5pK(J8p?!;z>kDg+tC>ubcdh?N#-XY6uv%Ari*+6i4-LoDW7XR-XH2$6B&h} zH(1V31tN8y|7t!mx9V4gU>#Uf#c~GyY{*w5x^FZpXvOv*;rMkISq{$B{OWQw3~KDs z+y-UH5u+!k9I+`gxs?;pKkfs}4%C3*N3X;RnxAucuLg7$BS0*tnGlCGTerX6j&|D7 z-F9@(+!6sU5@~+yf(34Xt?@tqRifKAAXq#6ZKvYf-HLDb>~9B-#n{`kTyoLe*AsNx zX<;r0(A|>^z_ifhSUD-Lz-yfj*){L_ zHFtQ;?b4d}+!0x;BNIM0^lb<%AwXEL0uKdlItUoMdhzw~Hqc!K;r+nUmSzQPY)ULCS;#H{d!Z#S34yO-injpU*ZVB z0KaJSlw{x(fzrzTwlq}Biss#8+Z$38{lvuQ45v9V`wBeC8NfoMnUb_t^m} z?2hmb0BKzC__MA!Sl~tljxU^#m@B^ceenLe^ZG!i;iq#3Zr=gca@!h9gGaRUH^TBR zQ}OQ**V5LQzr%F&-!(zxD0xRJOCzxSiVb_pS@mYmy&r zGzXk$HPzV?{|{6Lt=V=A>$;}eSfgWE>Smc?ow_Zd`;i@&>-~Kw)>iXxL5ii}LW%|T zFF*+HX3kPF>n0wF&;0ixWdHVW|At>-{A)DSHKS+qRmr;Ix8Hu-xZ+1j0(U-65_nxQ zWN-VAFevTk=Yu_g_`i1i{`a5%cl-XL& zp6~>;gLFLZcHg9n2(uMX%qydiA{b^wp0)zIglNvzKpsZ{Iw5`mFcelf7qMxIKYG zW2+~&?89c=(^~NiQ4NRi>~Bwg2z0*FtaI_ld~_wRsQf!W?`wy z_}+E{$WGvTSoI}XRUsp0ztKgCnI7-;hZirOJ$duuA5S2jw!eiKXzx{YJ<0@?)V3p= z5HCw^B5R6!&whCJ6xQwes~^4(Oz}Y@3!HA=c^)m_Tu&C&i%XJh(?EC%(%Vt z?IyG!uvVG^;?^|78zvCM2C!@StqF{~2VSv}ypu;qARH+nBYG%J37t4lo7rCDrF94;%EVb12x7{ESRP1X`gRXz89%58E4rc#hZ_*cMx%5^{5} zZ`vBE_0WJMpK*u)Uo=OPUUWj0ppgYA!9WF&&BF+fkAG|V?L*PG^fret`#bkK9r30ENkB-EgdzXpb!@S-$a{yW!~hkz!a)lf z5aB>z)`qTa9!s8I-oj8+G6*PUD6T|BqM;5DRP{%H5kkUlBY3R8Z83A-IHY>G=Dp+Se*Hi5S2HH$N2ptJ#n4g=t7LxKczK}NA5m}k}ok4q*c zn0`O#yys1iy5J#rGnET*6d6L$2JZ}c7$6{Cp@4zw2O>2MP-t}$shlp_`;p8fPu>i1UQ-S7$Me^c-szm>#q@~P4P?rc4{=jea$KiK}P|NS73 z$@7#_>Y~wP(T=iQB~6lM!tb6;FCaJugg0x`y)OMwx=7UeX5f+*VM9tW3zj?iKnM)c zaEY3R89D1hTCqVkA1t#)R9s92g)K5vB1dmueg6ve!J>C;s?fnL4~6J4PLnBR)(WMP ziNL6xq8~7!xMXnRr!_P^4we5+4iH0a>c-OZ1k}HnkBh`1L2f~PtgMivOiJSDo@z7R zTRfILD(oLb}NQ!rKVp@1rf`JFH}vtWpXS{P(^l8 zfTyz@ULg*pVub13p!`!^ZV!t+PqOiHo|?v9EiobBA=p+G7;N%f3VKO*L zW%!xzu#n$`bO}e`<6HU0(i$jDttn+*##!F&;<7RTf}WLZowit8s~?}n3g<2O+Q!=D7+D` zN7>PGP8k|ib3<{E13C-(6OEx{t$4I0S6=M|%h7h^X z2URt9n5I)1qbt>Bhmh-V$rVyGA~C=h)7R!(Os^jay1L6y`iY`Y^K_i3BtwbiYDTRh z3C0Z(n?D`mviD}sVBav8&b!CSX)0ZTF^XOUuBUqINGv1TH7}?K@=hfu)s{}qgi)9u z>5aLIZE(^nSY$Lrz!`NTvxPxLw3m)Yjp2X(AAp5R?C*$v&?Dhb@OAgq=S-U&grMw!CBIUb@(|A zi+!Ch7n}KL(>h1bl7gM3FbjE_mUN*GQoC`C#J{QHu8=qjEoTJOlD7CBao5g0jm6@n zWlPrtZ&~x6JT~%0w6zltrcy!VwpvyFXG38OZ<~3R7 z=*Xs3a>P;3tyLGFS`+J!|AO1KiicQr)<%$ESI7;N_HKLuh|m}8a?+9ff?$@C@#3Pd zFEOzBMu@= z$E+r2`J_t{G^O^cSjXiQbYKyftSpYD#P<`vqZWRk4>505vuIK1E$>qt{*xI7hNeLa znu*o{*6gTH@tS^@jo-8dF_93TMRUrE+Zg!1QeUN^fIUVMkJZ17%k-EWZ(-gir(-%} zWKOTBSg+RY(QTl3I?4pv_GpZf)J-pzj6(vF`3MYfwmNHmqg9lf&nt*lVk{7hdfXEj z2neMDDYHiKQpl$6UAqi)LllR56 zsbO2JHHD;y;s`~#6=Z&bTSFJQ@rZXcThH2f(L4F`iiGrc;_Ve2pK`t{V2vTUzqiiv z^K*MoK>x2e>RY=3sMP=OJlMW>@4ln|f3SUb=d=F*Lp*4ai~&N3C=Dhv2tp#mCg!sO zbpOL)I}$?Xl{l0i8slbJL0S(%lF_aVUe%UgFb)oIc^9B6qPKLMqmdi_rWly-goHm_ z4g`(dTTZTc=Py%W3YLe|`4>(U6dX*N2$@Fk+4%2kF#L5cFEA`?n~Mu=&>n$(H4<() zE2(&t^P*hQ$ zt5TKAZx9c%tHOrL=x~c{TtLtnGMyKn(`>h>_P>IGwUJVXsbgE7AO9L_Di6n{K5_N%2M%>Rt{|46+4D8DSPk+V#!jv zc*UQg=0ioi6D&+u2TVo&%*s-$@9gzl@f1s@Qh$QE++p^v6(!72+fsrNC9|glB(*In zr7reqm%&b*($;Vl#)~pN=vP!Qx$2$js!`RD75@j9-PRzcXR!?$yPuHeP)W)(NUMe& zIEOAI0AhHvl_^QXm`si&NSUy=BvDfLhVe?VklQp&xT<9~F4q3~Q`WeOhN=s?eUxDx zfk1G=iPV{&njoBf3{@yujf5@;*dRNm)!2Xs8f>jRer{Mf&(AFQE$8l_>xapPW+D=c zmQ5R!ira0?hA9F!~0 zZ4TU{t4~N5rUeA3D>es^hyjiCLF1*4SGdmi7Q>j38*D|(Z{jOz0qK`_>XaZ9N|ggZhze_8|L4;MKG ze~(VmbQblovA&ouB*RM0u}x+902>YKp}~WSwKg4Kfv(+;!tmGDdo^!_6BaV=V(9G` z*5yhxz;a492*O?p3#OpiIf2P4p~D4@^*-KmBChYH18`EUA1)PaGG12l76!cS3|LU{ zd6V&CxhBIk1#e-rJI-jIOdUK6)00|x;0ZPI&SleQgsj#ejG|iV{BX8b3!`ad;!TUm zSs&r?USPk}nZd`7fm5sWSg_mTA^Q9Dr4QOax;Bz~-)88}VB67#i{%hruRiKo{eb=R zfQb(l7l&)j&DWcjd5~D^$iMJe>gP#<;oJ@u5AiQaB2{60R!w+jM z-B8=FtM^=>y80Gu!9By35NBcBrzVWYY^?5r#}>TWHuzf6r7R$6uK61`K&hPF4)h`S z&-l1#wXGdB7jLjR@kufe2;sT<>8vo2RSLt*H2{$1dTtJp=#ipekBBCB>ZdKo({s{a zT-p=pwJbOUi#iQgL+ppNC_(_^FxM**?2eaQaS~>!OGfwSc?uyo%D0H4?yz>shf;Ll zK#UG1$Y9>qO$fIa*6*DIEtHN-_F-F3!6Ox6@;m9RtpY{`nK(Jjv>2qgL>^;6gC_(X zqOKnbIM`c^|NRi4shPW`5g%&$s>4|Q@eu&Q+NbYf{*9O^wMQj~bA?oBrCn7Cxkk_{ zhoE}oF57T+7y&uJeQ3^Qg)Q*D=MfwzXOmXO*AF>j_sl_m7eb2NfJ6YUF2tmEfU?k2!DC&0%Ef6g1+>Js=An_ zV*D`AA(DZ#(w?Pruw8ND4w#I(d$KVKPQp`c%E{f?FEU4QgtH*c7`?6?z5eKdwvdqCs zmkHLB0wsO#??=?_u9Y7a>OxJZf<9kTIZPTPTk7@WOaoz?hWhV0unD1I8EFlJbKTRWZv4>^%(UAwwz* z{r$p>j!U3W_Oo2@sxk4BS zhN6kfdz(QWmVYX`dQ5Uix}%ZyMC^_8qimq1dNC`}pa6sr)^}qAB=H6KWQh%(*o$uvKk#+2)} z)%w%JYc(pU$o5K&%6f%#qm}tjrP2F#%PP;%nl~j5a=7x-$b$Q-^48XhejB>ARVWxU z>kO$Yf|IpntWYGqGMAjs=#WHX15M7Pr6yfAN}oDu@Mqpj_+m@)5|V%tu;0X@@?wx& z1OS6&(^9WhiptJ{N(W|5FJVd7FqQU5wdh@_z9^g-t`!)ye(g`u9{!=f5Kn=DHw2+n z`BkI>0mGbJF#A>=aUb)|Mbn&A>rvq}YFm~UJ^Ie9IAEDvJC1F47V26!vuxK@Csr3t zjMulq?R)0Cp$?$TO18vYwWZN@1FPA*BB{B=>5OxXR$_!E zBG(hP?63ZuLU>|LtjgJ;YRb&Vp%EVPvK~rSLPi>llZChGMOSh`}lB8wP0JQ`DV+FO$5WR_>@s<6&PL9n9o94$N1}gA#Lai;*&vJg>7Y%_>}Q2 zXkUo5%n6dFgpw!Ld!;{t$nO|O2E#6Cv(xA_OTM5`bw6mYPsvYX{r*8mf=}iOB8M$B zmBD0v#1u~(*Z^vOowYKGlkbB3=mtR?20(ThcxT~X~YC0CkC8M(|lQs%|wzy zrnwl~VTa84%0a3_{%NT>TykYgPtQrjFC^q({VmaB_EF|4LHUZ3dz$CRDfUd`#3A-#>>#7FuVGE=CGOgpE40J_p)Mu9W)i4NFjg;J6Mfk`O_ z+66zTV2AlYQ8*#YQlO{Ak84yn!!V}lnbZlOauZVL&E@`9ac()Gc?}uU3$V&POOc?P z(+bZh*;FhF^waZfA=O)b3?9e>okEP*blCEHc!@^A3&^WNc6cnQ9!z;TL8j;-sw)Er zfb8%1YA zgdZkqKRhqrbSX9hg{#^%7eOz@3Qk{5l~Mf5HxCU;KOuYqqN2$*AdZY{hq-FtkR?V4 zF=wj0hX z?noXzX-7}qSTHh!?M6>j_yPNlFaWzJHiVwMF~ED`fR(}S*?C6%iE)x=>bOd@$BVoQ z)MtqBUj_HgZa3@M;?SNF?~s(JNay)k$801^J*n_SFRDQp{mMohejH#EWT-3e7}Q76 zrFAZbwWqg+Zy+>fsl>Q+JVqJAb3P*Z6Ag|BOUNIR92VlkA~g`=E2(%L)#z6RU6Zu| zTTvCSp-Ojusyn4ucD9(lif%LTaKNCJA2rVe9!`wpY32A#${Xoeo?$Ib4fw6XqrbJI zzX_6g{iSwkg}P=cTWxq2c{lpoii`g@d+`Y#e|y7v`kTT56=4T1soFQh9tB(}Nthsr z29o&Y)&Z$_?td*fF3xh?F9kZUs{rN&^1TYaFLoF_2J5v2E;kWN!^INRAJjX)^XLBHbA zh8l=RsaR<(B`DgfUUZG9#WurpK3AJ(kBjAD3m8gFjL?X8zczQFyIGa9U={1R3SC%1 z3^FzK^xF@_PZLj=Q-Tu85uQ=Day^oN0m$Yv16U5xqhttpO4-I#Mq2`3iv>;_jdRG? zJQn8%Cb?O_0FEw{VCtHhq58{INzv2?G)|j3DgH{-Ef$_3r*HElcylm!PjhoA*`9h_OHq_olT_3O?ig zh$>oG{za}^lfu0dHJu1q(E+d(MsswQL6&>*KRl~IW2DrP6N{2D?$N5&viX+zqHr2)HJ&g zO;JaK1nVa1l?*p(BG)}QjTSehbXrV1D=|3p|!8I5fhgzBT$jgGDY z0HFnkQU%LBhUQkdmV`tUv?bS@gLI!#*#&h#Sqs8Labjhu5^Kt~DJ5h;MH%kalKTvS zjdu5(N@&mqbYo^}R+ghEKl}wWbU1j_(xW-d^r#Rd;3PGd6Ufwn4fIpB0HDNu$l7v=KEeyU_{*<07|P8<@63y(x<~(9HxR`WciYaE|t?B+HAC( zaCWUO{|x z;uHqo+tdXTQn+qGvsXsv`((tfsgdEV<()}ScgEDtP$@XCc{&n&&J+_$(~+j(F0u0% zvlQ4i-MCJvg*F<~Di`Zoi!_qh;7+L9rIq6z(d;z?5`O0aK^Z|1z@~#5tjuO$n!cQ3 zn(aIqrf~gom`dJF5M#7fH)rmAo(LuzBjsv^3xAg`1|5jNeuAv_d?^mP2?H^FV{E^Q zjBb+}c^36G*af#BIGwq=0PFYMji9beL6u0+`oMlVDKZG5vBW7F@`{T*%%@*1V1bPY zQnndaTsS@I9@`{ZcSjiyiM_uw<)1F~ALgE0CTV{~>9Jn}@oJKH#=hBE>TMe)* zl<*Vu+UfZW4?3w9(RWXF7D|h)F}g%L^7!=I753LPT*eRi+2$}knx`qZr?j14rjY=n z_#0Ln_63^fALo#zMaEnDf;NY|T{Q=_d&?TK-J#r{feS#7Qy|_QJYJ^xL^Ok?R3@hQ zxs^vxRXfcDvWm09G7i;-o$8NZRm+?}>Kf`Sm!K8bdpp#)R^MukZKIBKLso~r<9oPE ztp$$-lA^G3lU~D)-$6)f9Sp6QR?!%ROsLj0JwkTOS@4(iI{q#{e`KM}ZlD!ZI6`2s z5o#k%Qpc z&n3aNvQhLU4znXMTVHe)9ck`Wur|Vht;!m}{N@|Fc3o7ftJ2vJr9dc`&jUZpAjDbG zn+if&8j6ejW5(!$SK@=ITPBkgYMt8!hV#}SJZijS^@M$h0Czx$zhHF>ob(GpN%?kY zBs%`Jit`+9ivdMU79;*pgUkaD>9@3t4E1n>g_9Kb(_A?_kcw(ZMpgN!S5yZNd=E>i zkF!s6QNy0ndfFey`Y8tF{j8wjE9%b?#Y7}nGU@P>4*y$q1_`DiX-9`8I1*~ipVVP( zsq%>`uHttcgycZP775iBd>(yrE5wNKWrDWR)YS%HV;~0paMi`wdR7?qnE4lr4B+cp0T_omnY;X5^wy< zWUNqak1??WCe+psoPrMi)VE>iFlv4Yl*V|MUN$Ao;kdaFqao?2eH%`|s8%n0B05VG zF2rFUE@6Q;T*QH2xR8cV__N$!B~w{W!XM;@DyfD0$p02NCZ>8tnw|~SC*70^ z)U_hvIQcC@KbR(xp>7Qd-j-z86GOOo^tNj*us%zQpT49B&u{5G7ezkHj{ikvN8H(; zPlH=L4d8)Y^^u5{pBMOdU0|Pu{=6W+>w>%|!Bl<6Y*L*;4#s-t+2SH@MUPV~AD&7CfTt7*;Hg9etX+W&@PrWpo|2p7avcCXO>cv*qZRl} z5q{sJX;q~GnD@^!v2J9aI?B@dqo2E!nk>t^-Jjv3j_!&@=hANNXOn>sN@@eyMrn!a zgg@-*%a}TBM{DosTlY^_Yb(ovZd>Z({=2IK3MY#{J6kKrh5lZUy#&`!b{+h-hDZ%# zq45L@1&mr8vkw_Zh(AsFlLn?(*Pa~h$KP{yjjWQcJwHWEe$N>iiGN^pMpe_)J3*J1 zTfw-Z%j6PGhft?ApdLF!YD6FL;aa@82C=f;l1ayBK!hvR6Yqul^hlc!KM*MZK z)x!@4hX&%w2ZP1N?+lB2mS^=Dvi-L4ZiFXTlam=eqID<6^V0a3blA`-vZ3@c5tE3_ z_zKUO&gI-v%4AE(YJ15tzX-d9%hpBQJ)~%5TVK$8*c`~}{V5l`ArD7b% zv~$#n`rFah(M}(|dHOrz@9jQ1&#F)+x-lG+8FR}H)MsGL9Q77Xx?hz+Ww4wVnAS(L zCQtDVrM>=JI-ozeog{|i^VW6UwASh@r)TqI7PCq;fNmFKjw~0WZ(}NpMxH&2-qsx79I;ntMXCw6T~*Iu<^ zHtK`|*kW1uqa$J3)KqnnoX3f&BnXrGyP^e;zM2-qhB$082BJzZVr45@GJ21KJedih z<2;+FJHY{BU7|dswMt3j9wRRt`Iz$QGXmZs0$NJFucP}75ixNq9=b2KE1C*mWLCkWBDll9W_u`UqQ3tY7vnqfs(;^WCmrs%9^Zm}-)WwA|8Vt=!i8 z$wruX?*ikAdGvk#QSJj8O-pjrJBxSgkcxWUbX1flHw(Dt=9~;&^qZJ*RzD z$h5Btm-GPp?j)O$|L|!t&%il2!7wKfu$MB4$au{Z`ge>T>l1J#2lrM8i*lCChlSfL zY<+Ra9A*&lr*i|Xiel<$qH-*c^~~u-yoL>}1r%bmcHFZjtoDYm888Cgtc2p4^1KnX zg^aw;8Ve*}ga=)Bvf+8FVT(}IZz*sC!`lk>tUBPD1~X><)>jMj`bsNd>T36*vU-GI zx2JMyxboD}=cWG;OYe^g!tFr*hXQ0k()E3%LlBOlZ1EKa6$UABl+B9;ed>7aXsm4CYQRMg1d(RM{u_ZGJ{8{T77ierHyl$jyY>3&aty~K3IJ4RX zp^6@iLR?#oGS3YpAtWKpRK0v~Z+F-HS;@*m7HTxy>qeq%Ncst~qR&Y=B@F=s{I!g1 zAuyt}dkp9EYPpy#fks&+9;)$8(<56f>vm<0@Bmr-5z@tB<@)ihzs~_~asje*C{KpN z8-XerB3llbGLMU{U8pjThd3c+{;3kVvjtL?Xtb(?jrKFh7w~1g27=IJwjf0>MC41{ ztd^KN00)mbxA}>5<&F^SQOdCKAJ5*raz`*Mf5aY_w zZ_%}fmR|`<<>SNpSIKSRgx6FhURY|6uL%L_ao7oYbF~*ldZPIaL&^HA6k1}!5b;mhbj^7*USYN*d(joIeUSRk)egiF=#X!nVmhBr75+Zrm zqz#o-t~o47LVwGAQF)V1h#L#LcU{&Ybr)A1npX*sH3lcc=htHltB$c{vIa3 zn~z2i(Ou^{94w1PKEc4yeoSDz3$@d$vY?`J@?QGwKrW|d`L!VxgUnjPT2RWY_$kDs zQtvd6mWc+twuZMmIAnK~P-$DMPHjh+q2x_EdL)|B zNVwN_##TS07>3lwZUG0q7OpWp_-`jEdh>J?w{AMq@^zy0C~RieT&&Y{@a6vPt=NH? zh=6jm*u&j zK9#!{#v`>u8?X|GwIv3%C5j$KSD#;~l18L7Q^606a>i?;JYQ=^m+;{-G607br|J1Z zHO52X!o`yUFff7V3$zU8Rg?O90vEh$hrw!xb=3yJYJ-w$R#mYJdXsFrEP6>)A{f%r zO6hPD4F8C+v>RiX+3jL}4Gn)?1|GdkZR<7C5$g>+LhQ%1gn2$r6S#s+7+1@NuHLrV zfhK4fAB#2llK`+dd=X7b!Fv5#}8sOl%g2v94BtbYLXrPbTQ8%g|p&DC=Zot$k09cMt^yh z432r;_Wqy`irjuCdF{T=;~@&2rgKo^U^+*czeCp3?e(=fSS&{0GU>EX3;B6sDmi#| zV;{C{AEqyA*pI?F&B6=T?K%fgNyr$hd-g-x{x87vzcWc@@#Ww$8mO?(V5tDjRa$J{ z{t9D$7Ne6dREoNxywE#M#}`q2nkAGdtvK#>RWPTPZjJJ>EX7HcL0X?w+4TVZEmCLg z3+b#7%FLcd=~OT+156B}kql8vC%CnuQ1xRWvG%fP{?Ckev7a3P1&g=Ee~eY+2F;+~ zraYTbe-1ei%`C(QOBS1Z$H^p{vvjEFpF%ZdrjO-R5KqD73`{l_A9WS{>T#G$^DZ*$ zZvmvHkGF%`ntS?4k$RXTPRV>e8ezrS=yt$to6_3C4oJpl$wd)a2_@O`K+dw-g?Vp; zgm}{T3t!3c{u$CmHBbsbxdu|B85-qZCAe4#YJoA8?`?Uct(WTO6t?2vMC&`W@?QJ} zS+^EIb}+?rj@I}X@Vu>4FP>qNV%^-5h|C1j$<4E)BT)k_cEm1D2PXw2kOC%9hN<&X zj>t*KpK_d5+fVR|;!h0GGfnrFyZ-UC*%2?7e# z=rIaA5H8R%ICCfD?wK6sl!!Cr{RoQVzzg4`pdIzmGsPq&MB;Il751_jCz)!0oUJl65iGzyP3wSN zMCxL|XdJ72s&eb)?o5&q?$>b4f{Z1mwa7}9*5=(%M$eLIit@c|c+MtiErmPV zZ3j(siY&@OIHMG@BP*|MIz7$i`IJ%(7E2);B!C7s|fm1Wu45-y|)^Z=!u69_hiuXTrJHCJld z<$M&mrojSetV=;+liBbjM&c1FmUf(u7J`>O97AElBB}oL7Y{@*Rzjk(?#WaisEpr# zC)%U*uE@-xb2m&06mNzZ_gBUnpY^#Xvn|2U$RVKHMGpbSbySVeM7L-YG zQMr|nL7}3OkML1IPMN5?EF7zQ7W}r$uUFL6&CD@P;UYbfK?D57Q8lEi`vsg2;J*Q3 ze4}AjEQD0Ikf%~1$(O1lxU*3*f5@`;+Tbf)RQBGQn!+&$3VI&~;h$%hY}a{@i!C)k!lvTAZ*=sUD0k+QVjnuV&p$2vqzxk z9wv(f6x4JJtffpJfjEbR+X5y4!9-XJaZGt{65UeXbPHujb2iJA($b=g0WvR}(wbXF zJ^}<@5Ql6cC>^Q4x;8haZ>Zj=+`xoUSPAZ#oeb$i_*;AgZHRYgjMu~zihU?BPk?#o za8s`#1j*3jscgfccbYgm%oN!BFs>%VMFooZ>{Fl+%-4(Y1G z@^B`w!SP%Wtah!=^>Lz_sy&VD^tH>+T^a=I$FP>+c;$6%z^uP=@rFR`-1b2Y`FGbw^nk+){1tv%R1E z@9t*uOX!{Ce=^(1{ubCnj+WBiGxkT^Bf$nGirU{?)VIG{xb0XH7<9EiNMyBNYJ?2v zTLJg%*EX&(rE2t;G%F9S#cklJ8%8>Aqg?9YsytIYbb)(K_g$;Bs*OsruKlvSvWsW3 zy8F7k0b`ckw$YM7!15GF9%+-rGcZN(T$(Dc)MX^b+j9;Z#jFe(vO%A z*fb+YY+m?|z^YsFN>NN2yXGD3xoY!%;SPvlH=+iuT)P#h%UQ`J5{q6`>ppX~c1q z?g%ykkRc{DY)4*yjRZ01;T;&@@+Ilx`87aGmTY-z;6l*>$oFK+j)wE+Oly(!+m@axjh zEt9L@jM3?haueEM3pm2dWx1>TcS{HyD7yvRkc-RT~)7M1h&*fwALMBzAMipDp(=+dP*ifk47T4 zs#7g`+xj6gny3-ERk>;jT$QR5$u+2($mptYspRewjAy9gFNivDy|KI;Ky@)Nf=A>0 zP`L+S@WZ0Wj;8X)TDGQJ{bRJ34b#nZG!mFwc%R=IdjMr1tFDPQLndnUuBX!+63?xU z74D!#sxt1)E6&3&ZTM*??0B7OyUxE(@!3*v%d+G{zn~nPnt)%j1m;L66N>u?z?Qc% z=E5vLRi<8a)r90*-%8q`QI#G&4Y`{I0oHOxVBAr^v_%k*fRdUtoQPvvDDzZ2qE*T>HwGWDhZ8L&d9 z`qo5z0Nazr8JM5o)v(hA8TOjPk#`4|zi=`Z6!mj4IQ9qdViaBE%jgWY59}_COeZhF z)IB2B*P-X_9*l_}9LIw0j@xMLx8FY`1$2+v=pTUBqAU(;1_n%H}bzCE&C!&tsq zjXC<2G=psOC6;!bQW5Rg4#J~h-;HF3)K?Jv51VJUTT0qSb^z7)wo6|07TO`?ZgG>} zAX8<}UwW+>`>0FYT$j%7*CUPbbIZ3mjR7axRIqg!#mMW!y94!-nW7pp;4y3EXift! z=vvafq{gd9>_@kBD=6>vq??h5Z=qvBi40WM1BUVvv25Ufya*Ps%x#QiI*|fW>Bm+_ z%un7{lk1U+3I^HMbvurP!_d$EK)49iaODbvkv2l}fzk>-rj8^v$5TJXFCCeSp^BiZ zXM|CUX4t(P0g5d>(NAgkQSk1aFG|t}!Sf}yR1qg79B>n!H9s(UARtOqEN8PZ-O#&x zZ!Oq%D4ifYG*W`0G)OgT=)=nopGqKa+(2wEv-SPT!3|A*Y}6w=xW^G^PdkEtkNF&} zkI4LluQ>_9ZJC67@rE^P4mYgup9MGPW5EI6Dtn+?abxFy09Jt&c#rG?@1=%iki;1n zI-6-=AF9{}`2O)yc87Ivyxbcx4-5|fD(nNIX30(nh;lb$A);8a0cI!UN0?HgI6?39?Ikm;(`&>_^`(_JjYs4F^C~xTZUQ%cHp*3}igcj8*?_XE%Yn3PX zV@6*;jiB)-f(6#AQ!*asZm1I-rLDhF${m-uXvu+4Whx}Qo2Ll&jEvZTT|}Dww$O` z*7Nk&Wj1G_P|2y#aodAPKvp1xv5?u*d6Z1R5DZMyrcp8g_0af2nrKP4P3HI4CO7Bv z1QY^ojx*szd{q=`#nTco^({qNhNycqF7Fa=X`3I=>KTUtyx9`j$e zYDm`!D*nFY(6XXF6+K)ES2wdp>o8ds3l02aAqJEb7~+u!AvVf9J`NZ=3v5LpdML7O z0ikUL*g%I1ru_2K)Yexev)TB<*t;(B9-lk=dnL6if~;$Y;0@_q2WaoVf+lXzp-T*^ zSgnd%PJhd0u?s9OSdVp?Y<+nctfB6S7BWufwgs@#GI*xJ zt|B@n#4&y%auIQcKro0}aH^pP(U1Z#E;&FNAgie9zSPzOh8aEfKJj($@H@%FOLQDO zjNU~Qxj(v!(s7Z}Z%9WVFkNZq1$RW#+l>Q6#sl%Ux4sHmVyD@i4#J#o%kc1AW}FoNmo@cGufW$O0axRqzyZOiV8ZF zP_RQ82xyw0@#e^%#0pYH9uz8m4Jd$lH zfkxaVnGGavnYe|RDSk?d!>fATjhqm~fUXzVkk2*Ly78v6Sx&%P>BH&dey~8$Y!HrN zzQDTPVcMIDLktnFiw;lh!q5Tsh9np8PbYno8*4 zfF~RI11~8G56HESD-?=Ff)hB-4l_K>A#SPQlhb5Q;T5YIvjZ)$_(~ClXtd%Yl{TcL zi!aSt$9$)JA_mV@_*Or-^!vKqtph7-lht4d{7A+x11AEh&>B{e3ZIqgIQiB?wX`#j zgIIx7-J$BqWweaQwajQ z5X&vHjk!0+V;&P19#WOe=B4Dd+yk4J@-xdhq)D2C1rbe59YT0EnJK6&U9ZIYN%O|! zM)Rz}g1}IA7C~^(N0-FVTW^IsXdcpY?au8Yx)=YO=@uKhl!iEL1^hY!k+W$mBe#() z2cLGR?$r$!64=kxFxIAjnysMdANJD7GUba?J9az*B|wac<896bwpb|zA8GQg=Ahl; zR-OgcTzL{|6bj3!6{bZ9BS`RG;wFee0JZ<(MxWzxJ^-eVl$|kcc@sdjvI7BOYUey^j`lc(&C8kB-1H=qa_o?YpW#r#x8ECtl(k znJ;okNmJs5^fE;~g$*p`5X9gWehUx!(R4%Vj|yMhClqG_5aI_KD);M>W0k=uQf2=< zkQa;X=*gR)qbD0=n?<4QMo$Q)2B+Y8BIKkg1$24x#*FpJ8|hbSj)dVZ!wb2C+h!7lK^bD#4R9osq&&EV00oj*VjFfjZz4 zTF3yl_~ZuB>~<-gow>Sf8wCkELXo1xRjrtQ;+Cg;4!E=Gb)81~ZnDAB!j&>#-gfjh zyu!D=u87+KM`Cx?rK%4GTJAUeX`_am9>0Wdt2y5ea@ePUr|FTnVG$9VHd$se&gv{C zGfZ3;BvGgk4C}q!yA(b7E(OPBR4i~T*t&K5Xb>Z+0f7#ncVMcU`k zDT%oh29z{)aPOQ;+UN;E!Sq^ph&LYb^~ZUG(Un0~oQ@RS2ZMM>y8(=tiz1|M4x<3! zzEbHAR0tR_R2^WV$ZSEkJzl_I!?py&5eu$!K}HSA0-~U>!^H%Y4s+Pz7|S>>3qh1h5tjuKki{({#9|9gU=21thVeJeGoO5>1)$uu*p!Ae8|5qu1St;^A^~ECZvw zu3kgDoxyO9k0rPvNhk){xS;U|rkVFp&N1e!y zl8#wh8)*fM!}byVylws^x6Q|k|C!BPb6j*{Z-q}>ZS!}1E~+}lmj!XvTQ#KJ2J6|W zH;@jZ!2E$GZKKL^vn-J9rVCCJ)sMiwGL2xBs|Z91eK5hpXjDBMRTCqDm`w<^%EG!igAE}O3kDt7s!kBM#=Gw?=@`N)jF!_umM<`3 z7(rG7gCN@`C+?FpDj>ule%egV5~j$Sr$xS;52Q(@MiwBM`Fxnp+vF=Qnm^66At=IR z4;Z6NH&dKsvl%eAg8?S&L0ed`%S<5T!E&0O&r(cMnia(|Rr>YO5<(vmV#1*nz>Rea z2d#_jcUR?Jam?Y;4-T~$zaE@sct8-;&C0CI?Z?)J8 zu?+I6-FU0hd8|977OVk!0^ieoGJ~5J0EaZ5E(1;!qcM7N&W+K*T1DOpl4xWMSZ&)w zY0#~K8H!y%g?cK%tW>`~j`l6!85<`aB~IB@E7NgT%M!RFQXn2*M&m$zT7^I>c(3c> zWoTdG`^Is%<${YZmuLgi(L)KeS~j?{K#m9cFL$6aXe<5b|r-uWZEGTD^s;z8HY*AuGldyy? zUZ$xyH;ZJBCmrNnBjaK$r`y7mXt|Q>fP8*cC_M;I9czbKkzMsm+@%oU*Mi(FzIe<|rL<$HMzf zG-(bx!35ytPic}Di|B5&$R^yD1RKUIZf>|9(0>D?H%q6(l1|zxQqDz`%q4i%+am4zyAb6{c7uS=Q2w`G!Vn;KV;g?to(yHapPucoP6 z2ScPu&|vPre0hX3eu^bZCSt(nTvR92;t5|0^NiNIjiA;TA&d*M< zoOHV~;g!44h`Y=O3nt@j6S!-_tc3Yg6oD-xNds>Q%^`BJHKQ0%qIVZ*>^vVX1y%dC z2dx&ZZY^$Z+v7Wq&s&&G5tICCzdvbhp*KPS8ASQ%I!{jp@5fsbf)H2$96bbX9Qw1$ zry!dfYYR!4^N~&PFp8K33>PmFOgTBuj*j899;H)(eaR67D6)?Dd^FlTyx0V{s}!=E zl#-xQz%(67IuI+hfK4|)f{BAfAQs74JhYucs+9dk`;p@W!Gp3Z;R;(;C`|_q9^&$Y zkSFf$bh|%3`8$l#Js{yx4#+PncC9!!M`OV&4S_L_w7`nl8P_a@ptG66Qj_g)YFLFi z-0UC`Qc>1W($xYtw-Mr`DD50|yir?BgW^}Ahq{~x9)r=sP3LuBK~XF~L=LObxc6=| zp1_;dRTPhVYD*Spr)(^KE?sXRRy(CzDIjKBDqHiN4<(ok%o~AwiU<04GsyG4rBvdApgiNR zHvq1_3UOw(Ej;gA%du|nf#ktnx4Lp!$2zl#MYhySw@Yiu{od@xu2kOcXXmrLkZIu8 zPAP%}x%{tL#<|h~QC=NjPz<^_7zj>Huw+1xutDSGAkBCGxKHv^j7b~qeBO5Gi$E4{ zAUl*g8EzN@`PE3#>bXaftGqH$c1q#&q%*x40L#a0kHjA&%d7}tHfjf{%(!_%W!|bI ze?WURArHcN>zoO?MLauZa%@gm6adnK2(fJrJ5`_t3V4>_Kn~8nt-A4>=xWPwoVewC z=^m=y%;-{6{bZ69_jJ>i=ek_k)GTXrF};M6^MV_(nw>v6&$-nJ4pkcHtkF~{poSOm zP@15Y%(%uK-E%_+9IEg|hX{*7i-%h8^SL%(P8K}6M#%z9eM`$mOF*@*6{+?8ErN9C zq<>aj1}hNc`&tKtBi(+>s?3r_FsrT!Liw^ea#Z7mQ}wPHWcB?mp7yI%f2_KIPK3+f zVJkhEUaY*2rmLhHTVX+(WFoskbUeM@niME=|E3Y}0>Mm6!=>JGpj6hp-VVBl#_{SJ z9NbzY^%q`$vKCss>>6XH%2lp&FXsarp%S|y$`&6;*9mW?1#c^s79Wa4Che`}ppaq- z-h#I+OWmkbaU@f#?J77LSx z@xe-qgQBt<{is&+MuG`ey($^=z{_%ir7ITT3EmCdBIq$16vPMX%8*S!cI@DD zOdm72j3|Vffm=qO&K#X^W_lYAI0&^(nE4@~nW*>DQiOFbbW zoQkFBKK~UiQT7JOIGM}q7ARLNg;3w^8tNgx{c#^!JW%8Uy|atuBzD6Zf~Txp3`Uu# zn_XBP1c5bYPN|TlZaY-kE3i{n;4Uk0@X#9IF3OjAhwb}2J6qq}e;~g6VQc4`yE|Kd zh_-HFeznh1aMtrE`ony1wz;)EJ~=%;IZKX;to)b0N}x6lV{@o%d3|CYP|AHe76{w?%f`}`N*|F!F{ zw*Czcf*Sh&&E4$>_WIx5-oE$XGyVS%4@zEWHcS#J+_`tV-@Tou>5s`w@Jdi%Gy)DU zo1}QVC12w4(CrczjhNHz{tb}jBAXulHI>=|R4R1e88>{rrp2T2MLxDO=%7gbI9D3looV&#~k6r5#au*o7*aj=v_H_8Rt z8)A%u{#GBuJe>D^n?h_zUGTQL@DpD}{k`5+v=L>)-WJ$`ejQziUwgf6dbdsQI-L%D z`R4?`P3YT1e4{q#*^J_2(bm_|`9I%HH@B}usbkTOsx97*H)8RjMPJ6CvWd_C32)kc zJs=DfgX0sQ`xkw%PKBwU^90<-YRz0*6*||2nCZ4(Obq!KF=Q;9MDZ+{OItYzWVaN5 zw3ux!I_-gBCjnG9ve)|s8W4PU1~#&70{}7otQ7^;*SVpar@-$+>v*{=0|0YCmc#;X zN4eXd=rD{=>MER@^YvfHe+SR=?LK79!7w(wS3lCPh5>@EkNyFNU=WDV;)cxAA;cSA z7Hzjd(Hcw!Vzi;i2CxUfTb^K;R63ncq#EjlEwKT(xkx6r0U2A^gqPTHhcrk*B$hIaH^rG-8{ z0Rs>*fruZQkDiNDa8DLF??%t*uM1ID{&_w%f4hipz9`h~0gf`b6{^#HF{iGX$wB)I zd7r}Y^%251q9I9z8R(G2qCk^9foGr@JLwDxGCs9)8iUdI*X1K2M;@}eS1n^sYQ4dG z68#I{qb-sE)1x+!=k}m0sg_`FjzC# zcnlFDz(3 zboa8lDZ=nFoe?L8R#q#;6*-IE$qbwk!pz=_+%?MpI&s?Qx(&9tR`3A5>7yc`l6Cz!LM zh~jAq#*V|5+nPM@+3{V72JPVY>MqU)ti9-)j~%43$A4ubjz#BjN64er=bJfwl0P=G4Rn*#?Y%0eT?|{sj6g1#I4cFaG7-EYGrKA2Wo9@s+rl= zYL=CCE4E0o$_0TYf_d)$K>Dm7zJh4EYix5I3xo@j4(8fjNx!jCLPO1ob3v9jJ{26_*3Tv!T^3$5?~ zEk~)6Bc$Vy-I}pt!*HxXY;($Z8Ttq#W2%iZSx|igkssjHQ)|@2ZSP22N=bqxr>MA+ zrBPY?xJtAfv&^1mz~Y3SW{Y@s(h*`4WVjyY6UcMZ>P&S^0>*M*CWApc@?^RjN^&qQ z(Xbdl{P%0Ilv092yTg4Y+a53*(wGah0a?tIZ22QPsSw7>gQt_;h+x`b)0SiS=J-U3I1qwfh9zP11J*`HRulike`)EcMKUtVfP$)HPTpb( z_VsXtCld?{b_|@@QgAE-fSdS4aoP9Y>~)%vE_<~!u6d#AASI}aZC128$ap($N3#~h z12Pn2#>3qKH7p-ZThcj*Nau#X6dyV>Op4Si#M!qFWq8IfiLsTfhj;70lBOXb|D)CU zZP@*&r>XtVgM0Vy-n|R}Bdk3WFZK?RMdBmN!ei0^UtxJV!n=c&rBwo2r7n_Q7yUYBfe9_;`wz09uz?HZ{U>7u$kZZiR_zqbX8(WPQhKsHbd(z?|wSNOlZJ z=t$>ZKiezhggq!TI&qdwMlF&H&?%=X@L*xRAf4cn^GNKDllH%cV^}Hwe+&1%>Z#%X z?>`XCzAgWKv%PcwGyne~9?k!|wvg>;Wr^UOa^Z%ftF8INs|pFh+*x$HYAd#h4%z~P zIR#d`P=2O6_#XA;?dXT(NE}Q@sdwXSw*70weI!lvas@#H$}Jb!xafA1xq#XvU1S5A zTyMtuB7sDlg1uz1nDe9XFr5yLH!$n4lZ`DpMMw(Tp@n|34k@pKQ9^p=Sws_43` zgo4Fu_!IJIGUFw>xe*0jpWcuCM2t4foX(|!huP?IK(hf_ib{L76#f8P!V&FWnUkSYN zGX77WfBYwM_ALgz7*FU^^`PYMeL>@5C`%>ql742k4Xe~HP2iYhas7xBJ`6xTp3gp9} zsvuj3=@1)~-aq?)NyhoX{xSSlu-h{*uo0iJ2)*q_$BV_R=-#=L&gKxeE=vaUPCh@n zv$M7RZ+Eu0cDAWBjkc!vzumt}0`B2BIZ1a8!M|-NdHMplo$u&9y&y3ceQmnkkb7Z; z^|TfB{2k-_+S-X>J_tWG5xO)n;zd%pdN!T z55HJNo30wL_2*u9__heWE{>JvqC#oGI>Ij!SSq}b9aHEF>HQ5YIP|418^=T&a{8{j`2`OMR;cMYlXT0J@zdkOd-;M7KXE`YMJ9BxIX@ z1s?rCLuI<~fpS;@IjJLilUZK7TtrsZ-P!@4+#t}zR4j6z51wL>XnHC$bD0-CXau!H zn5H3mDg*KhBq&(w#lQXa3mjhbw`XtmUc7oK#`CS%z+2~AcONQtoGyg|ko&^OH8mQ! zawSXy1-XP;ChGunM-ZRo09+{RQuaxgsS)W)c+k%^vPMj9-UM>lJtdon;U!UX5ZJ zEvMI<*N^#hagZiAuL|1gB zd_BNRyEx`uC4SQt{x}1X`=~UE| zI)vCtup_$to7}K4TVkc%Kt(wj*BI+^>Xt4_I zQbf!z0km*;r_~X{ z@|d{4B5v^p;Yedbgc#X+xWS-q1HMT82#riF9Pi@FrZGI9d0ADiU5Q(Pyk5yrlOuIZ z14Tmj1VxkdX)e|#A7rRm*?&r>^?^^YRHODj#1_%TklG~A^f~wvWeznnHtBcjDVy%C zi~vAK)a{SaUU$jFK(O;5#Z!uj#cA8>A?#<`Nn93xwlk!6{+? zO>%}On}NdZQNm92lnv4X4*B81Kxue#XgD<+5>s!cGL!~5J*b>LDm$?=sh_5j)~ql) z*1J7VcXkg=8e2(@A=$0Y*v%*{P`O8Mx{_Qbz+UE%BYBa^4Io%J`olP)MM$@kp(ev` z+MGNHy9l4j>Swb0uTECg9^>TorWCYNq;5(UrM!w< zo}eN7Tgz`BM%yeHJ`D|RN_**fGFT8X;q^G*mW`CC8-4lMDz(3L;IM<_-VPUeF^u#X zX`4LbL~K@l|7$iKf*q}3jI-hQiJOKGp0(xFWcy~^y<>ICLls?p;Q{7k6=b|1+--vd+Z-Pn?iFp&<+75lhc zf9G_%E*6ZH4N6`RZ3UFeAVE)4a`B$0vvD#o(MF_OEQK#I*&~p~g09a7XL7;<9ICt^ zlwRjyq~ai|?@kVn7?>_E&vwL$a(1~F}bifE5(mNLqGC;Zo;2rpX|T1j-jAHo zH=BV~e8vWi1D7j#Yc3W6<$2_)wMlYd7))2}yedZq3)gG*72Yv0z;8ns@oF902ETI^ z%j4X$#6c4OwXX~dZArdQ6j~F>(yi5A2Vvb6u7nVBt6vMjQ_silDYMNLtWPZ^?^6oE z6AkE+iOd!|78TT2M)J6jtVw_oIR)m<$rWv2>TDkGY_K;5J11;SY2p5sqqASbg;qM5 z<@02I(WYChOv)r^SYSs)@o%pvhz`4j4@~zsDFoD`$5vC8DTa*j+JTY^6(8Jd0iG85 zG#ST-YhX&Uvq@;MDUe_dwaY?2Uf3{(qY+qzx!CEMjyz`c$@*Fij*X*~B*MNkv3|#! zgwz46I8-v745W*sVaOYmYlEAZxViLH zw75i5G>G~XC1;6b(1N`R@bmU?GPC7;mKSM9z$?`zWJiKwSRTS^+))-I)5Y2R3f6wrzn~qMEVZAaldN zu{ywz83$qpreM(^$J4dUKook{@Il?OE8|iIN!6&}ndC@7QQ?ik%h0WiT^#m;^b*FD zv9KgWceD()>jB=F!K-AtWutP8k-(hH%-dRH^O_H)j{WvV<~AQ1lgp)BRzd>{7y*Xf z>vB*!`|DU}Sqc$*FSCI?cdeJ4qDC@>@%$*aqrb5OBu~b_n}Y4gvY_Lc0;!HJR3?}x z8Q_dy^CL&6leG*fe#C z*ESgqYe$S??9WnwUW)0@#}}j?wP>uZAO*ho^u#{%>Q5G*Z4~`dH04FU5Y%e6J!~hv(B8GDCy+b$~9=}`8wL(LD@!XkyE_SkJ722*2>C3RtL!vM!GiM z5*+^;ZMd~)9sV@iXARkl!s(>S?IPyf18tzyG=sOUajn5TD>+z6;xEe}@<8sQ}U zv(@lttKnL!;pls?$S87v*C?A83)GINX6&0bP-cL6312};Z&U>_Hl65E$l?j+L%>kT zIVF1}2ryBh#c9*~v|CoRtImox?3WdwCTdK)a;4!dFIa7F%eS#*C1!AztsC4{L23U^ z4;Hko*9}}2?e)^F@pT(z_m=i8wz}#)+<7|&NBiTgwv@=)mT+|d7mzAph>8w^3?t<5YvWzcpl~jz zI4u|T15UcG@z9?_4KUdXEtYt**6hk-;y@FZk-01L1Drq!6@b3PhA9qCk3={yjR8iq z#S4tKfe{Rlq1H(t&`X^@U~5Y$Ux-ml&Y&{m9cIlLr&ewxG{=QTutBFGX73;+rLv|w z6`9y@(B7&IBe`HYXP`;~btJ%zQS6dvUl7a#pffw0n9U6vjrx94Go7sn7BQLfl^~`( z)=C8|VYK^JUdHmYj4fOV(egg^eIPRskzgrAzH};twyw@exFN+%mWweHd*+<(h-z@G z4PF44EXkxe^kxLnf@F141r^HyW))J6u(9+ZOIJV2l?KRMFI5KRv;%xq<^!aA9wZk; z{NUDtE_X_9F6hXIrrcnZI*cIy2#4!)70Xh_A}syRmP{XK3RMjk93BS$-a{A z65~8SS9mD4@7OXT4(bsdSu-|U~_^Q>1&GfPzJ!mbdl&E zN6BPjehI{4-^zlf2E&hP)+vyx@PkIW0A}q_5V)bqsD_>e$auRSc;fmoEgF?o;!Q8> zQ7Fjswt!(fiZ|ofYyE4;X(lLLc6X=M>U17&$yUjBu$TV&Wh@&fE46mCBkH)#SVI9u zU5rFl+uu6iAF-xb4knhUg4>-=yd7%%KxIb6=$pzkR7KkqbuVQaLY7*PdfQ^-2sJH- z#y7JbRxpp5O&FYy-kx{9^WE!wvNs=3d?rri9tesS({&k(hmX4LkgS&F=^=hm-|!y0 zYK20R3SzDHp_Q}FxXcbP+q<;7v;1fIgZS#b#pz(p@TY);>_Y(!^)8{6&;-;2-#d)y z5~w3F$h1LncX=D|kWi~ny~oII=u`pWAi4ZmzoZ1hmokxXI2^5AqjxEexoI}|GG05) z=3t-5{F5m4F6F2kF6Xc;xgc2+$qucxn)Cn(9mLex>9>!sI>;V$meaGjfKuyVg|;{< z-ncOvlds>LruCPM?C^42>6B$!2w*s*UZH9c5!EeOZVt)5(e+v8i#ZVRh7~QC(WxhV>vPq-z)$ zdJHkBfq3cHtMI3i*BybaLTD{*jRlCTUd2)!mixGRIQQ|jfYs##d|!11>r|^O$p~0= zL7SjdmlZriT>)Pa>6bx9qq-3AvehM!!L2TGUjDfp2W5!(%P4+{_G4+Q1of|nl#S?}z)zf$%t7nz{te&cv|L#+NXfTgfPp?Qm*DT?j%rwU}{Z-lKjOvkJCUv_eK({t?;RSdG z$?CfZLk1~+x^xv0O}~ZT^!Y<&!bX#uX*)8}`1cZ!s@=%^{BM)qwLF!bf)RM#%pu__ zSi91K;zcc8q7l%^u|);~(6^7qK5>x?Sr%Z$deX2d8kO zKaS#QKHbz`TAk=+u7U^$yc<+gs<%i*ni8PV0n5OXn+9Dh(a6|zY({BJ6xB$~H*`%n z1rtF;hEBwCI+;>OxiYAg*+Vqg=sFXOr@e84UUZnA=5m~Yk#&e4@r@f)(M??xY&7)i zo_-B>AnW_Km)L=GUnmQ$?>|3KpF%n9c8*mofb>n{-yu(|w z1L?7yjY7?Wq7#$JSy3BUlsy??Pe#vsq3TJ!t~8j!SaFBFK>K92>Av0HI-tQ(D<-;x zT{oMChm5iz8*a(eD73|wkIRNu8d=3?V=9`tVH1)g34*ZQBl9!f}x5wD4kFryTf>>L5=$} z99hBaRe2b8bV!BRd{d^QtLA@a`G1>afj^ccrYZ-#la6xj^rSb;1oyCTbHV#@EBKXx zV}Z*T$^xa;W(UtR*DhEbqCK$gk1xdv7ngvWg(?{`AtpQ5OBFl{*UBkJ7iYbE-V214 zzBN$pIH0tE;DS>}{Mg?4Hnzb9k#NLYAG#`Z*bQlwA4#WCHF*3O9Xw@acwa$xn$Up% zS@p<5MVk)BhN`Y@0t^9Ix!tzvl)|jm_89IJE4!^;g@K`{hv9y|Dx|v23V5MiqfB?m z;1<6w)ATpxz{I$HO~RC6gcbMFl!K_7zJ0V`$1$8Y$GaN<)$Axnq;-2pq6J4_2&)qd z6a%2^(J4kkTDkBhO`!u800wcHQvCF0Vw0vaFce(U!B0OF6b2XYrz@)YZxIW6Vu(RZ zz=INdX|uI!DaR-Gp;1|op&|2AvvLf+(lV@IhU3+O$>Yb-2K`m8k>0R!>M|@x*9aHA z`LpUN7J3>HVMHJXn<`@LK5JCjgYR0kDtVoOrQ)(N44fUwBpHV;RqPAWDQ7&E5M8SG<8P=+X7=fFZ^N(5lV`2^WUR?o_~yJ0N7 zEwq)C($I~#WR-4;zPH9dG;j2$y=QNFPyh1dhaaB3{PVNk+c!_1KI?t=WbaueE`MzU z9}mO__sX$)ZCMCZ(RC_z%KApl1yca@Wm|y-!>c>W=wLN`ISJ}?vCA9)U}K%6=?oNV zblt8sC#2vUU!ZOH3>?m6gupTRS)fgAL%doQk8XlD-?XDO9Nt^+q0J*M0>kjKnrx?g>g54;P>BG!K=Sel|OlyduSo9UbMrH77xE|L(Wq|!$TVj z<&@BhCom^vzWxzT>fgkqaCk5){6kI4aV{;4PN&Hhs@N^uV^v-yRPGon`~x`^Q!Oh7 z9(W})oW22y8q#6UIY>@S<8EGewpFPy7bxZXKG2f>_#UjOsA@cElb2NMGMW&a4SdPr zP0A*s^&)Or;Qo*#1dl7v>Ek`^Ey1FF=^4v}bhx*tq;gd&&RkvPN~zI{uQS$DSZyyi zI1WpWHr?Thhnu?ky406o93jQ9F<3pq?sq@OE)2m}*Nnh`6)b3Ri1X^`Rk`>$PloL+ zaWq`Ov2dY|gjXlAb%(`}Ai%vE)dvx(u1{61%X7k%ZU{?FIesE_OU@@#I%Gs;+c!Ff zw~n1;>E61K_xdg6DXgx*?aP1X5?o(o18U>~5r9i)*mF*9lo-zk;_`sAEV|Ug1v4cC zRX5cUyQwyJ--B_IP12#`A6#^t3w0f_g|+

    7Kl-wR~yyO*JN@#a!&7w@0Q#e2hBS15Lab2f0OhR@Frcuo?3Ge{l94HGbmmJ0ju z>oOOT)pWrkK19dy-{CT6x)lH3iU0o3>E?C|1HEu^#7>>)X9$^w5#+$5b)0SLv{ezv>cCM>>r~-LwMoUSM$UW zMN&NL3tn+@Sh#JX;N0qzZ?wQ9t&Jv-R(B_g*zV&HGbJ>ba;`JfTV-e4W&`L?FjMuN z3>O(Q-}YL$xg9|uB~4&3PBNAEaaSYnXZZBWZ)nQyWGc*Kq-1jLOD0*Nqr#`t0szRp zzq3MPtDq1ChGazE@;Ey>hRt!9913P{abbj)^YmOKc!O83Q&OoeUE|im@q2=b(Mbt&Q=%Gsb+99wh;@7Yl6g0}HU(D^dIV`>O0F$qQ;u5qN?k?i7>-M;$z3R0)+CP96fSMD zs(N@R)|)HG*b5-7VJXO4xxH5?45ap;yHu4fT`QbU*=Mr#@{GdHdxsaX;Qzbb!DP0I zDHw%K$$EvIR?ftdvD$LHkIx;~?oEz?osI`33Oget6^^%^S) ziMuUIN>#)wA>BENzBL<0Pi`bdWfi(WY@S9ov+kpUmaJ&Q0?%#OvB0wee*`04#fk-< zHO^Xb&|qsd_AKzML%AEp%y@M|@q9@K5M$t>(h8MCM?IXrTT(>cM(LN2k(~-mX%%f`}xKwyB`}Rrr zw#>`A*}XxaiMsm(Vj|c{&;5^Y={82ug%ZiiGR{-{039z5)wnK|2-^=LsRF5s#unZr z?}?z;CUG^yqnu`}VA}%^(hdq1Xc3U&hF4FhJV8rp70Z}3ubZe|qDVR{hrC1v&`9gt z0gmy$ymlCYmVY_J5^IyJ07-u>nvKD;kwn4mD0WPB;WlCVmChv?nb>Nfh^KZG%C?M7 zX#!uh^u_@7EOWItxXjf~mj4qx#)#Ge4N_C{%>|KSLvBaOpb?!9|Jr(m0Gdl|HqEcK zc|<&ei1c5ywj>)%0S?guT2@MMP$QBInDA-LT+()Cp;|&-a)Ah-hW2$pCf69*00a0g zkbZGYLNb2!@>$CpxkiLQU?I|9al;TDs?GL12{&RQuRgXun5|fD&B4lFMs*{&k?{#1 zrE4tG#N4FGNpUS36xPk9Y@%lN4WV!Ys%YCcaM1Zi2o=E7g&Tpd%D$l%fLQsG+W6hU zcYT6)tw^S-;_XK>h38rkP0f%>qMDil*n*>Gc`u<&O_vSBo2m-uy=hN~+RLK14Vp3F zE6;)Zm$cT`KHAkSDGL|J;c;ELyh@A?O6{|}$S_^3k)3<3OII%5EpsLf>Hvo4UPQ^Q zgMIP(piD2KmVqajzLB~RY?TGy^qD(aZUNEv={5v$1*d%U{V4%y1m+gqHqjMd#*TX zZKAPqA_Bvfvlw2$Jypd*d{f)X5EZPV`zs+Ru3qS_VP)pT5m;&J3R8#w4X^$$D{Mz4Gf0dTI^hy6>|6ivAJ1JA8(n}%EF z)PN&|g?*+vNzoHXKXHS$mue(PAT14bphVPI#-Hb=ZlPOF5@Ol#H)I%ln~1#+e!IG% zA6~qC_T{2n;?>LE(^o(K_~Px4K(tCoRoQw3RyQ0tuym#2ptNfdgml(EJ73?{ z`L|p=3D)dT4#^%y1W^f=o&DB<^#{XU(DDK@AYf#=!Pa$pi0PP*HU%Hry8Y(&x0c^N zjJD42Z5^zNF4U{NgIznV;5eMs4VI}8&YqICEs}~5GMfj3c$tD%c}Sp~wFy2T+KE6m zp;~(RT{rr7*~-e|8fIEU7mq_0KLtmi4+1sBpyjfjVT0T_Ui9dy=pJR|Dq5-(^@53a zYKxW2Yz-3fcqA`;?O1*p8OPNz$8=&JABN_oEK}M^ZQh2Gx}FtzMR^3H!+Hcw#V`)6 zw7(DbD&v|5ucmz-uH&r=e`I)a%qG)ARbo3@*J?({b6OXz+zPZxl2K)Oc#HxYO)OGr zIeCsf)*C=L!Ct%FCkTYt)`&LA`r{*wV^`834UV7XhX7e;e^L7NssslcU_+VdBF6_x zCgX2b{@ffbZq0BD9+X+HgJ|&F5ZU1I5Kj5Ltd4TnJcLP?<-VIMp-ISd-v zXTbwPe058=i|YI$S>44$NQ3k0YEBFQCqu*RGMc%qRW?U=kqsL28Y)Q#;3umn@f5eL z5d6<&7pY}Io!}8H&vPUTQNA?X4(JW)xTnzYC|MQg8ng|?r3wwu#2BJ9?7}tZ(JEBq znv}w$4$onMnv({wC{_kI*Eol~jCGX+AYjDZs=&v9Ze1hxx@}fsZ$Md}xS1SCr4-D= zb{;xkj4|B$nVhDl`5Bl?oo1qqq2q$Xd~b?eaAS}`7#)yR8_e~L2lYc)Lb}kQydb0y z8735Kf`E?*-I&&AE=q z*Y;$`JoDwQ>=J(O&1?O$Q~GD8^v_P|x8am7jlu>g-BhbI4&i(0h6``>PyrEMe+;~G ztyQ({RaIz=@K6^fwaD)>^3N%pKH(>j|B23+Tg(1blmBUZduQhxFaOil);FK?KYfVD z$=PIOc6x`V0ek6!atQsH%;*pCMoM_qDW2d>J`)YS0RzsrxtsJUOUL5m@^e4Eo@bL( zel5)dwNm5*=yML?^#w01PLfx}o9WR*_wBo<^NZOc7oXaZ_|H@E(#tgP^oSpYcar^IpM%6MtB^hEy#k^?nYmr9F> zM_D2*kXBYsq4gS@R57%SlG)CqrK_PF(IcDI-W>Z)#{8nPF3(mv8VL~TfLY(8z-)%~ z46mlr;Sb3X8YasM&QH??|NBh}SLdQPxezopl-x}RZ*s1v4`ueM%jjk2?s~_QcLBtE zGd4H{A=st#*OkfT^_0gb3x#6o^H?m=od}|_fQNglkJ5z+nnE&}!16OO7`(SS<}poJ z#1}4ODUoes<9oV+79z!Qa+>AK`Nl>RSBG=i7-j`VbJ=KhX`p=wYH>%!Uuh6|MMy35 zBI-{!clsE4r45oe${O$so0B4~5hKt!O1#{Avj=T}S(Ru(z+?m(sO<=@L4#vz0g!uO0TxC(z~khAWK2&qK7&0e^*b3PIaR$gcU(Y9?LYtDRZIv~Z0eZ}m5@HoxtPMxzQMRx8BD@nl zQN@_`glz7bP)g5}0W23Nj4|%sI3+O$h0*1BtPwE)9zn_}M&KkLlH}YMq%xTleF?OQ zU{(Z-#A!4WeHi=_xG0E#5On)7#zNYN!iywFLwg|3I%x-qvFIT>N~fqgmAKnK`3mgq z#o@6NPept2P_*0Xw@~d7<0;Vs?S~@s$Jo)MTFEmcaca5n8i~%N3WX*i1ZI#fU&D`7 zpqD&LNaHC!x-?xkI$h%M`2f(#J4ESsn~CY5?z3B?+9f&O>O|sqN~uB2!E&&ujf};q zaU?x4Y4(V1S|p~W6Sbsfc$l4v(-!jC7fS$3S`ds-8!I}PD`r3i2BZ0R z#PUuDaElR3NXa!+4*Fs{*2e1MT4ojeEI?QTq0bbjqywG7oTh1Xly_8%KmaA#00IP5 zNk{^MkZU?5XF}HFt znaTGFH|oE7==4i=oG)*Q!?EC_@BtY48tYrrh3Py{GS>M4@w zp(s(!X^G?^*;0RvMpq@O5JYA>iG9tjU zqm*JVa$V(AC8Cazghd3jn6jkBA{8x`A!=HILvN7SpoJhUSXuQl@uCG_h{{PxW;h{( zCLp&XD2L33*+RC5dpx###Q=Hdk=Y_cNvNo1n1i18Xs@qYq;UsC0j@L4vEGnwSCvEJ zX2jzDu*Z0NAp4^7zg;9JXlDoWfI-BfcTF1Ha5kBG3>F_kea|ttEz@<;u5YcVUUOj1 z-nQrWsJ=?;Qtm2$xX_G?_&r%tGX3~ZBLS0XVK@Szxk$Uxmr1#ZLMS{ul9CbGi7lGC%IRvUa=iNHZ( zi_Q3b5ZSEKWjl4hDgkGQLs#r-UP-|nXNEf6Ix^5H)Blas6b8Zajz%vfzC#pkbvmYi zy9Vd%L4ul^$#F`$8$sA^yE_HNSL;j{{Q%2`Khk?SgB()s+&fFW>3%VZJ4>Sb1yje_~x(}YWe<@ zg#vXP4y6Edy~&OA$eLF*(&(!5dIWRlp6v0i60u!*x#67`-$7N}TgfXTq;*eHMN`Gz zNSy*?;@p%tGFkHTwoT#^Z4x%y*wUo1w+s|$^A^F;REhsuCT06zwr*nR`YN8t$HbM- z)J;6!d0}_;4KmR|U#a)XK2yU11+CY|e3<@GG2r>5DKlqL+QAJZ*tIbQ>`vb*6Z^YN zhNl@*mpxhn1>-rt1mx=OlmK2U8u@5#J7{pm=U-G_{FKio8&i-UawS2GQIF`}?elnX z@nAAlxq{f{pv)ODfW8SC5}?ZimOZXI-4aA~xP6<`D%G5f2OwVNO6}X#`d_NkWYtX3 zT)<-6F&5BMip#}oXxAK9UKu+AG7P6v$pOZm8jW200mmjlsVM$1ImJ8q$R&F}Zv5D< zx_uww1vbOA0$(*BgF{me6zV2>Rca-y-t?wE-pejaZA)+GkvYu92i*h>y!0&rFco`s z&`3KVRN5jM)M_e$Wel(JMSh(LKzNHU{;K1oSBd~%J2wDeQ$%%Flx`Dc`?<5P9@t$b z<1LpY?k)C%hM_OhqfT|+Zb$mNxCrW3nGu_M%g(ARXr(<6~{yWetO15gm2GTU^;A>R#wXTHZE2NQI*Fi=T30m#jzss9Pt58!LMc_@ubA9c zj+$kvy@QOF9=vNvCmHe!Y5Z)%_`7MfaIE5u!zq|0BXf9nydlB@{5+6Kg%iwo)hddu zJX{2|UUJRW)bh2o!W!C(E^;rHi-B9YhN{-iHRZ*u+e$2fY`?p>h0e8@y&z|u2}LI^ zovUdwEVik79awJ>1Cb0*F4+D=?*)Jnkjje_y68?(#?bNx&8?lZpDTYRo(E@SXDc0# zubfrWt<5R?GHP>lNh{1R9dUliw zMNgQw&09+zj>Gr<`uGK>cym?K^Xy335UL~pP$_BAb}1<-Ljm4PjPtT&r=Vmo%QKs}a>3lCsxnLR?cdbwF4pt7KbS3eSZJi(~g? zj~doCKyT`!Gt*o5Vp(jwt^p+{mqFR@)wa+~lA+hhkxFr<^PROd4k{I)*RlKjayJ=# zI=qtol%gvnBQ)i|_7XEh1JhQ;rHzNB6}=YTDi3*Lk`MzE?UF-4L zedC}t?s*6l{k4uEtP(4TiA{#tJTu6OXJMFDWMOy{rBK-(?Z%Rd@M0xHuNh$K6r|v9 zMe=546_tjsRa9@4-odi$9xEZ@2_KOCxC6f0*}=h$UWH50vP>i6;Nu-?WZpuHLXkyk zkolgKBhD;X)+gsd;D5Q+Bbb5J6H+u!M)CIe|5LOQ)oX(f3g49TxkaR0{vgNAd1}UUYtE|D`F=PiernsRr zgYzEJMLRLy%zJboYemG!(A_eX;d<$o`-~H*1Oa$GAytoJnC~qPdcug=H0t>hrt5WM zcq8U&BR(KoVC~zR>6=zk!nz&}ll(QBfNwm)yww<=gr_Ww}-9;a7Jo2EHm#CE7V)o!?f!O0<{|S;l%}+&H)nj~#sRr>kpiHl*twfEU9j7GsAr#1x3au}${O@=0^_c1yBm zl{C|YE_IC6mWeOPO$ARvkyR7pM9p~EuYSEX2)ykjhPU_)a9eTT?PPZ2o2A$td{qa` z`?{c;`chswN0gN@ER9i8JhodWT8TzbMhFteQE5dRPjBrxen{KZ3il8H5dyMx18uvI z#xeIm`Cvv>j?&1cz}txc28T>*br|MSq$G&GBddI3hQf@LSCh%N+3cXISMlh!(AOJr z^jCL5C}a7AmaaeUcF7NLv32KnsWW)Q6}$}cP}^=rU$5quqgo7|a;{^z@gZ}EDh9;^ ztNK#uDbx@*Xs!PCQ?}e8X~ijfc9gOoQ&4_ojnnV%eN@fn=m2J2SAG81oawQq44_ro z3!^et+ZmkX1D~guZ^j3fUH`Q+ZybGb5XOu_Hn^ghi-$Fs5O*Jmh4Eizwo`Q+_BzvC zHOMZPuvNbq0^hG&lGAdT67dnN!6BO! z#v#_%$==FGS%&kXR*zKx91UW`x2f|k#3b?Ak6O%{M#cFq%?v7 z*rXK=9;K0#1kO~1pSiDfE7OFOY_>%8vly!gem&iUilnNJKZGv==a^a@~ud^A!wPkOAE^% zZ(NaW;Ehf(IE0sj(PEe1Nq&4sQ8>tgXm2upE-@B{7pnp(r}MCAIGs*IP59^>pTZ1q*qV6V6jM_eb= zP@+7uQ$fh|tqDaomdw8 z|18I(Z|OR7Jm8F{Gbq?B&DFD`G!~Ad=0Z~$wcoE(>Z}letVU_4oHo{duMJYFH3KuvA(NCZ{S^==7{b<1Uew>%zr%VUDKD!Jg*88dc%wCVi~l4Cjd-?3H%9yga(NHM6?XGq(D*-?gS|u<}yf^-s-hj4-K362@?J zMC+xsGZukf6z`4&%C$)>$!}9>v%)<#q^PUzpZ?A%_aND6>DlE}AlcnCy>fPB>Wq_8 zxXyTiZA>bU?SbjP?pKi2S8L-V35TnVpx!>QdKgt3yIgIT5_=107pfGh9GaS?Jigx0 zVgczZ7H(I7Bxcu`PsrU-nqFC^z8-p3&Au0E4yl$~zXqDEAUE!2@4}E$>-WDnVq)Ua zLV}67kOJFBuZ3(do8VQ$XcW*@siZXJ3Qq&4ILZ|v@o(SO#h-rJ<)n6|xt0C&V2;K& zO{xftN})0i8}G0-rWCGDBSyk}ERO$CpPfRjPaIUNL+_#`Kc#T+#wINGqf! zpFBc|DdvFM9(TLXo__6;R;32GZiyJ_oArCD)m7KX71zgQb25J%BXaTP(Oj+~xB|3QW!ENETql02veb)TRW*+8 zrlC4dcWY;-y|YcVI``~A%C2^_Qz(xNR>|Rn3!CkcBl>Jh4Wf~VLw(4-$h1^5A)&jc zl3}boED>?~^-8!tzTQXQaaVlaA7yj8>U4K|7<+P&!V|>kbF!1dU#j7j%Jvzzs-aA? zWSUWR=?VvVKwhPUXsnA|5kzV#xX&Ix7qhtJmUKEP&}gxmQHGb}ZgosaS0$rVR=unM z`<7Vp4;~s%;%YmJu6h(*i>$97y5DX-J!Xh+H%%4{O;_bXXep428*=lx$;CWAwU_e* z>3V5LYN*(;7=w01l(eFb7eBzT3??CpK_Nla!s5u8%OC|%M4DzPTZGGDg~*_BG0}Xk zILv_j`j}Qxf?+JQS2`Z&mI=YJ9v~pLGHEA0Sb#Uo60VUXHJQd#>oK8r`6|2Os#2>c zlsfCzk|f+CI`P5Zz&U4yEROtepotnbGJKK%mPzA9@{c+eI8Ei@`5E#rKGLa z&iWpJPHwNnsA7Ew4nF(1B8=}n5Y`ngHBnKo-LTWH-$K{P0sm#UGKIDrk1K(OJ^E7h zMzt6ild?>P2UCG45T+NO-ce2-(w3lWlDzTaZ#lE$HPNWg@C` z#GuJ(F;`u;eQv#*rYI|$;oA2fwv&f1d`vy0f7i9=1pUR%rtts;AzB~0$b0z0;`Lz^ zCMu`ZtBNnbO0EIu7XRn2>_ww;% zad60ndD%%;j1XE%kdNGSwdPm)7&@clgXh!K-IhI{f^0nOVFI@Ff{R^fNgr!suf6g* zr75AJ+dUdjPRHr36TjHxs5dd=`f{=u4@(n=#v>)-M~b1||Gu4k5Bx>ZlYwao%eBx!nIO7vg47P!Io}QQH4pQX4cMVhI9L<(6U+5v3^ij@jxJ?;qwFZZvxiC)I2pY}IrX0T zcw7v}#lay|CxG4V-uTXEpLe_GU*b z$G>3`m4&TQSGkq>e*4<7%{};|Qeb+foJ!Ow{JS#+LZ|k0&y+Ss039ezX+b0?LZF)) zyP?ZlRQe*(1>Zv)+VTyZ?+s|im}=B~LJKpFNZT_hEtoISLWASkz9*Hq!o;Nm%6ifF zjwy8Uy;`|BoMH^FTT{lOY(b@De;)XS}z3OZmZI?nEcV74YePX*}dQF?MD!3D6U zwXl!`>?*|I3;r_fcJC8=+U|CXap4#~KO*j?qH}UG_}OH9Abf1y6CZV+3O{h7OQM(M zEXpes>VdhtIjq+Gh0tQ58=G6Bqm#p<)9j$kPQJMF=HO)d?@wpPKVrFM z-+!ggZ*O>}Oa&@yMvJn?H#HxjNJT0}M?hZQ3pDu=^|n4!U5OSBWi z^&Y9qOka>{vsq%>5gXg)O3m^xqh)9DgnwAC3u8&7OUTr+_Drfa5ARZ_Ev~!T!j21r zcg>3ZGxgU;3YpG+cA3r}U6vNQ zUEMsFHx??^&0udb8EJ4h;DlPCYX+@zra*oMml_CTB`V;@@AtquXnX&<_{Z z@9M%@7jW*a<5#5b>gM|AzF##(k+1%X$FuRl;YLPFyyNTaG_kQh{&m52p2oI=i zJh8C^qLinQ<7&|>uesjxO1M{j8~k^A(dD`ZIh}oX*NNWEyMMRz_i*w4%euj)>2hEF zYA&$pVzrL8M*03cW-8>Bh*8yyuXXC`auL7sQhoQ5`PV&aB^MX%!^u;)un64@qJqKXvlt;xhtwI2FO^YwwRCILBFY|j1F7f@1-`|gZZB~UJ zF8tr>!vD7LZ$_`*<6>MKXQQNl)W-w%K>N{~6mU9y+7a`kf!2$3G1fcAc*p&yD%N}Q zNNQ5Hb&zCCBS5Ie%Sxr43lwiQqVi^|1KsQ$DZPOn#y2XB9flF=OZ{J;gPOzJM>?UN zmXR?r-ECGYEa21&R6U?Hszc0X0FC6FKCwhiQC`joEwlXfqCkgl9Y}){^Xb4Cx0RE3 zHvDl>&P$blZjeKvp-k5Y*rm%d8NK#qnIK!HUL}7jb7;@IVx?Irr}+RzhqD4rz|gQ; zn^==4+My1qgzhYtu$>9DHDtJ1Xe@zn13lIYy8hxF&@he+jz>o`G zIyN~JLYZ$PT2X6iFjRWgYDGQGN!{Ibr4f&2{yGJQx%$^gO2fQefT=;*q5Wh*(vO># zU=`udhN*9bSfQA~N&(q*RFMy?uGqF)5%pfFdmBcxhk;>eP#tW|4`tt62dvcKKJwbh zIwo_FzTWbDp%uo|Tl!}|8>8q(G`spZ$H#=eSHB3oSokC5hBbr5XzqEE9 zOQW~{>BYc~t0ixy#Nz6aF`F5gJiG5LiqR0h+pKMx z2m1?DfYxlmhN^y`26HV@vQc|0c2SiU1KnapI&MFNWzeT6w}O$%<)DZ^Dtd@?(nh>? z#SxWnqLDN*T_T2@9CeeJ=&*{M8isjUP4IXZg6J>n0@>f@-|tm2;lar!g%`)MoS?3K z=W3h3g;%-%S0yxkmm)xfqcq#{$E$7e;}2W<^=;{IzvoqMr&rkgmgUTJ_dgLdB9i2R zn}@aCtR0hB(+xfyY+Z79!~nf|WApB0y{L%0cG{Lk2qtwi)^nO62)_5)%!a`IIB8!;-L_oX04PTj` zSd$w%S^`B|~ z{6ujelOaJ^u0;{7wtXv6tXGQ^B})^bkr_!8J52(}-%CE-y>8Ls+^39DZ!`UKOTT^f z?5k&8rRoLIYmc2UE<>2Qd&Sz(BH&Vi=mR+0{N%SLncGM?exjE04>=q6_XJ1t6BOeZ<(ZdF%Y zjBtYu&_Yey)d+i>s=L$a?8*e%v-|}9rDIfd^Oc&BTLPks@k@)zNEai>=TdS8BK0EE zVCsc)fqbBHDkhwDjZ)D&`RkGtmEjuNUcQeMiADV^b**Jn<;@g!rwRQomnI3+4$4Py z@n|F2imrgL3$cm7Lao|bv1w4X!dbA~SFe7AifcXWAtTDxh@i_fsk$hvg;`Q}__RM2Y= z|8y>jd7DsptlpXH-DD#EAC%msd~g0Ao1cDq_w&I2 z&+}YigRWEYjL0bm2q5{t;?b7USnnqVoD9gWsl?#zTqQfs)!k@d){UwpW!mi|sHzC( z=4HYVN1)2sY&9u2R;aFHArJEmW!_<~bS7lKS*Rg%LRmI!-(QS4xZ!jJ2kC4uSR7;a zD46QX?#KvrOQY0!3ZIL8i@0Ei6! zR*^Afk37U52k$BIP3!|@z=?ivQ{lvloY70AL!~1}aUIKtz|qO@+Ln**Tx0_m<`SY*-yzwot$8ni&JfS3Z#6OaU(+pVZ#+}Y47E>jL3Di|b zVJ@J*khg1z0x8r;QY^5hKB4nJfcT##i{v;vqr2h-MWfRL$=?j}>73Ks9)p-cH+2+u zVQw4fNEk|)pOGQCP8_8QCK=klC5Q9*w0ryZ>FH@Fqn>sqvxD0sE>qtA_Q|8KpT7KB zkMB?85vFK2W_5dKNj9Yr&S*F@%1#rMt{8 zm^+x#9fR@80+`Q!oUA>3nLK&9mVEi}<&&3f1oFd^SATf+r&q}j4_~}^`1IA2uU{t5 zUL=p6J^kv*t0&K%!e5V*hfn{fO%oZ}3!5VmHxMuE>Xku$Ou6bU~X7 zvh`jufT4|Hdq03p9;KQwo)Bw_jE^V71rjm_`Qc0I%v@t^Xng>j-e*7(b1SUhNOriX6n?OS zF^uFZlqe|Tw%)T7o!?_OMQSL49N_F!jOU#q8_b9vU}@aBz4h6ro2@nh&W71^uFNVI ztfyxj5Ga%riy>Nqj;-D^InBsvl!QoiG}D3?i_M8L zkp=ozXEa105j)KAFyF`b$sFmjBd`e)7%cc=oQ>2pKnwE;8l+FA%JPDgSQMLFWwvzk zK8=UCDoX-K6tXzpfK@X%GLSmSv&GC#79T$eVI?nSm9)p=jgOf5oRTzaCs{&V8C6>j`wi?`al1F|L_0jf$)ntaq0e?zNUwh z(*zUnBy*7Lf#T;ltw51LhQ}D(NTa)tJ?WP%JJ~OB^9n}(Z~x`L^0>oK+y#Y36!$| z7&F`T!z|por8k~iw~~ID{<+m>_6$=8JN97C1j9ED0+*@6cJcZc;DeY^cJxowwMvIyAKrPiw(-$t$Ig*U|R(# z8MQZ(F5JCBj}>=dl=pbK?qwqqy+8_`d2g~aKie+LbJ&~J38&E%&U4o&JLo3N&cJ>)bCG4m$L23W6&s-t-&ZWQpai36_ zjnJkLw~%8LwP?u#x0;*41#LrX03B&@G3Egp=Am(O68-@+5^q|J2bfZiNfOnu2<;)@;jCb;Xt9I$jj^6W@Xy0f3YP#f?|*nl6yV%7>jUF1bZGAGBA zMq)SJg9=DJBV_p6_9RJp)o?$Rh|Qvb+4&WzO6f$&4Y1XmB7#v@sq(|>8*$_=Mq1DS z?OmNTQQ(Uvbe4vCGY~rmx!qAWfCT@Lk3dcmA`!9y%oX16CSOzICC-@GE^tw*d4-it z#DJH*8lX#;2<@1mJwi$=6K@ani3yhhN=yVV!SjfwMnR0Gv4>Vl!j}HRExizO6pNa= zm|E~4&TLpQMm43Qh7a&^&F-N^H~90O=x5Hj-ob0n~2xQHS3M zDK06Yu@ZSs$XouB{;&V_U;g>ec+dG4=6T5ah{@nPL?AJiDz1XI4apvzZ)dc<@LEEI zY%vq=pvWLtHDH4$;UszJWulVRpM^7!`ctqWrT~5j?8CpuYHtfB;1;(;6RuL_|ifM`%4$fg4XAyP9vEQqpjnfy-0 z2_p0XcRoPx>$z3`v(TtuAy2xAb*5hLIxM%Dt&7|#(HS!7hs>Ad0|oNXXX8n#2GMd? zQdlrMIGE)J?7Ioe+wYTP^5MEU<0~CIqX!qS1f( zXQ0df4L0YrX*vTRd*?@RsQK|S#S?E`uL{1bQ4z8FTTqZTo1S{}zx+2On4U&WPobu- zxge>DXlo;Yw7ms*R7PR60El%F@s^ZJ%CZ1uo`b5ve5mfkI^NH7xa9CL9XrVRqYNN8J`mB1qf;h2y>TU59~ zkuL3&XwO$5iU%?vwn9+jnpKBBtu4dL{~ znm~B(z1A0b%G}{$5}+?p*2Fv^nkI>tP>d;$>1rl^n`vM}rHRq?(!6uf3AR0N&ujHt zI$4rdEZmlR+oGgB$|^+EWgke+|D*4%baoX_9@;ZFK{NDA%zrW}8y>1;?D*tYo2T zEOPmW%wa)p2}7l_z@!^O*&wLW`sagGLxIxG3wEYss$C4&{-w_>Q>=Ir^(M1}Y^-!5 zRJXt5^U>WM{-sAd`EI{U$P2k}HtDq56_;eRC_|HpL$G5D1{ql6R6vxYl<19BH2h-`hJ=J@4--%|4zkfzWsQkFbE`cm$BR zJ79N1S%?o+S2w7uxk74rkLQ**l>>BC&^vuPOF=p&R z{!T$vw^}T$CG9_S=nh6JqFTa^rK9cas}vKoiJ__{n`0V>n?24jL9f~MP#VZ~hS*Mz z5u2`gZLN7>z&N_s8X|SA%?T(v_(!~$Mz1NVU&MeTQ9Ug9h81j!EqZXj?`zq&nE`EFJ><0{|ax#DiY z0epvk+x7Qje>+~rAbJ|0W)l%s@lJR}fV+3dE4;RTR$ieHUdb`k_jk`XyqT%w-6GJH zPyh#F$$l}{m;TWcuYtwuxugF!?}ZR1D)-+`UqGrZuW1(F)G}Erzp>3nK0llcwQAMC zBkh0o2II8U9l3qA0EUy$Y^~!jEg=8#UeJ*qpoJ;JU zSNy?{_zQiTfJ5hMYP_`vCcbpg`r;UoGq9f0sP#13RwC~Yv?&I{^U<@DV8-Nt;N7j3 z!x-En!MgYfctedctQZeQ3w>@!MYyvbTvzBsXEfNtHjR*XOH-NinfE%<#W;%tkEohx z?w}u>4tA~)4DYzE+=EnYI;UrjvPHQpiN@P}l0Rb~0rmPWn-xi5B+P0oQxLWv5Lxw~n)HBthsnxPdU`u3T8QcFpoC^%kaVK&+0~;?$IC<;W^>6$>vV zCGg;QiUCI6q*Y75UEeqngvVeaICBaB{`@WCk=7*Q)Qs~}e{Mu-WGcErBL- z9qK40hO16?cvrTVj`FetCq9LsKHlRQV9I25*tS+r&i&~`>QmW7i}}tykkraj2gap- zJ%uA)pFf*BHHu2CH!u><^3(e-F=oz-eE&YQxGkats$*UlfyRcURWC%?T!RfhMWvCW zlzT92$@tP{95>YP0>4Yu67-gDoE27S`vdGEC ziY*ZmG?|&X%uebC&{^Cklg=m~ryl=`$O^HlJDa<)+9nSp_I=n3s(DmpqcmCSqf}HB zi70*C?f&KK7tdPvoRRF_i*<5W5Mek_NwmVRzO#?nva`WqdV${f1ip3QdE0Z!&R+id zMoI;E-0fH=TCN*D6?fj?BRdm*6uk>Sithf{HY5x^uEY7xkGneshGa114d6>(sxpJy;GH3uJ3K>4Sf9~6e zM!XI;?Ff^Les+=u`zIx<42a&6#IywAF8TGco0OP#6)Wp~YH_TTNh|9N#(P>6YI;(z zbRO4(cT`Wtdl=km0mRVq5%>}noMrqf5^rJSsLaMjFQa5|gcZ5Q(#~1PLseaQpH+*0 zost3VX^tnrvh{6REqeO91{Rt}7Ro@KY-ND{#>0{=4)VGwl^0`Tay|8U?F?6{TCZce zDfCEOhZ#G0))EGZ*Yx)V4-gkSMq!IYM8n4$Sd@7fZLS-|&Sx53PX><`t{CSMp3$v3 zR0M6*@)W~~EePcqhZ3zLYbzQt(eG>xktKfJk?#cVT&;Fpmz3$R*v;!Z6rezMXUFN! zZqT8ia-}M}lHRM?w7&Vm#TYKZsXqL+Y8h;loz^M&S#YSs@YG!V_yV-Kpo+4soZa2n zFG2CUE=HPNc3+f~=xyo@v!e6P+*KST!da{U_JQ!PMEJ3g6y{Qq?Keta?+o#euhMjiOtNuMG^^tE4u^4%aqF$2sRjH$FQ2BdMSv9yE+qy5A5O>hnQX6ZGgF3}h8A4aw1(1;GEW8BmB=H&l7 zWDSIx`wfDl-SP0!6vss#;hojiH8L@bt00U~Tbx|hEP?wsGnwb{X6C2j>unmI#DAlc ziua0w-Z}4dPr3v$lp}=B&IuWV&z}E6MetGVbA9Krh%U|HTce*$M5^dl8UDt8p^XID zYohbm-+zL)01uMKnBN7)VmFo0&Npff?CG%eMNMhqB-${7HiDpcF3_%nuEHm|aD-!j z|MRsiRTppg#4g|Hy}4rJnm)`Bc1QO$jTXdb{h}NIb`s^vXb7 za$OyaA?OQ1+dJl0oqn(uMs|^GWVHp_$=(IIDeW~Wc57)dO$k`Gjv7MJyo^w*I@@-; z_c@;Uwjk+CcS-5J>+P0QWL>6}wnNm#s)e>c84a~sww+vn{MRP%7bptiT`lrS6e-}H zGpOjOfTUTDcn}?Ex^ATF@H)fAlhs=;A30s7(YZ&Z1VKfkZOYhpwL0Z#Htq4!O*eg2 zsqx`_fQ)gIxFW@&W(b9>@%`Cdg7^0JA2muj}{Pxv8VF0`!h?P|H04>LXuCKvHPR0ezE!K=7;!?@8hAES8f0{y#KT$AatftFV*vhk z27U@Io{VD^rL#9!%uaH^Q;9=Dy8!s{j65{!;;}ndCGlJ~-E-ZtPEbS9!+Wr&>Kr(U z8%20BHk##2gH}N-O{2SiZQ}8KMd5f{8nKk&5W@4>WI(%{z<>w?|FDAiU2Q&4eCToH zU3D@vX+5WHm6TH3L|F;1B~(ck6h#Vp>$l^#=6NaPr)kUp%~rBakVVgK{r#r457p_< zl!2s-ZmMDyL{O&zz7j*FaBWC+a5_IQ#;i&Q%5g(T^`a0oKrM|`#hbk1+Mpc7x2Q#! zk7>ELMbM_l<6PWVS+}dU?>J&3XD&i9Y6~Qxie|DSraU)n&>^;J~^xJ?~}K76rQY0w*|mfhNB## z)K*zP69Q73TIUmy@~A}^lBE;C)n6ya`9YRI*}tOfpQKZ+_g54@lag@(e^RJ$$Mu3S z?N=M-qj~nXLe>9sylShW`_E+3AIj=x7jRn#7&awjO(;xOfrQ!NqyoMrl%F{0#7{RB z0{)h=VxpdO_$mP^{kf&%KFQUm!}5Y8e^N{qCH6{Iw}YvgKZAfV=||_z_?He(QO>8{ z;?Tr^!^W=v?GBH8*;pwe7B)z?6gIFGUum(~JO$L6%MK;^xLnL~hsTodKt9{&Kym{W z`n2QQ#LjYcNoLL#)?h686!Q;fv*AcZ)bSRVuw3vMzQy&YlH0mWC>!e3o1CRc84uB$ zZXz}VnP{lkPj1jjOwX#eib~h{jh~gsDLh@2hp8$Tq!&`pX- zxBCPBv8~PL=+jKO9REO(1VJqCN*SH6+9ulT_qP4ON&XABd-gWO1mubh^L#Kj#-s@nUnohOpV>U@SE-8;8VtcL2z72*zMj|L*nb4 zc0yM=Vm7=?1+=;205gj=%nY?_SNNoTOLHb4w&F_SF@f5?QB1p0<;9*?7z06w!RcG)hs$y?*wR z1>@tV3cd{NPH8J#l|E1|UP>LbEk((r@m?I+b_F)#N;ZbnanPi|ddxT#s`;pyV%3uR zCRa{n^T`~}Fjg!lKCM*(CGakcEpL>c=*qa?kKiL@?@`r2ogOkWYTt#kNp;G{zIr`H z`UabCZ=s4(p_9s*@9bQ=)2c$Q4QgFUJnN~F%2V?(v)@K$Yt2m7+R4hYH?vFLHqa(* zM;gp3qZrD_4d0YPwK6yNl#98HaX`vaW$@-IPOZ7GYsrS)(3WSeA)EXX*s;lv(mv0# z&GYT@9J@L!zonqrY6`gSt2Lj>{lc5x`1|Hu~Cwf*05ZG_al;W4v|qu~W5NTEeny`PfMN5e`l2 zS9&9(V4+{5gQRg$EoG`fON|EM?q{j~P&t53`FfGfIF!Nq($XOo0bx7s|9GZdX zTh+TtJXhPw)lQM&xW;beZEWapm}r-ksIj6}lFhF!(53-xJl5?yri9I^_3&^!G`WI! z1BY#%GCB|uxKnSC}OYXYFw z@mWka10g%nc9Qb!tB$suG|$|2tCIRn&i8zOP7aZAx-~LIXkCO4Wpbxw5wzXnbb%ab zKUSB9R%3o;hJK+`t{2HMWzOcm)co`?0d9~Z-hUpBL6~_+JA2v#_O!jEJU))aFzufm z)U%>AM25dS3rfvvFV?%=!2+4nZfygX%e(s+rHy7?l?Kv3Lr8Dv|JtOM(*WU;y z)ekTEVC7crGx$^wl$O-32OzJI!PqD83o)u&ku?GznRUh2*JWq`$Sv^Vu+B@teqM-Xr1;>@P6YsPj@6Q z1DKXQBIL#AcXwMANa2(>7^B!Q7{@yH?byYttm2)qiE2V#g+070*07{^%~`@bWC!s+ zUe?V%uPA5nx=Uoqg2l(JfUq8`)v?kdPl=C!Bu9NB;mV$WtT)oSc1Mbdj#A|N$1=qH znVyLKC*@UtfBC;R?|$+5=VAWuJ0I*n-^XJO5Ou)1Hpgwgro<(yn?yFaldp{FeJx@7 zMJT>21ktXF(d>ocqeT`sjzHTz!v@0<;Zr*lV(BZ4fw*n0t)RoGu}4i}JH@+D5l`i+ zW_aW)q2gdZ(D$IRc58w}+D#6_HQs4!fI;xc%~lH!>UR>#BgD6Fq+obWflqNp{c9V_ zh=v(+$grX+0tJ?k))dhHzi z5Objsz0qiRl|fyG zuiwA>ZT!05%Afl!{kY%8f4kCeTl#CSM?A5mqju$Y>7l(Io5)7q$gY=lDh!Bfc7TXM zQG{Ckkl{-lsn@-Aint+tiP!np(9cL~w(EvN%Wa7a^ee`_Ar4uujWe_5WxGNAO4q~9 zk^hJJ$?bO_W1^7%MYa5ok0<|s`q`&n{3iMA9rPu5{=wz{VE)Mi<2p}&Oa1>o{}d+M zJOACe^Vx^<-}`v%`Hz@`GLodjLifv8AO^q8l`VqIYDvaG%4tfU53Q6G^Ctt+>UPmF zOC7hAds&%hqkM?oX!!H_VOGM4?~(Rfd1M&*OA4IdhC|k@oKrE?dLZ!W>`&Iey6R|X z*{J&-cUMd%p6K!4=dar0B;MdRX#ZZ-R1gosc8{SdUoi&7w#GaWnEi4*#MF}0QFf*i zezBXB%IK46M<1D1@@q~zU7A;%m-lv}r%TP0eigV0K7Jkf$h-pQl!HzsiS+~JM3!iO z_Yx(={PAcqnLQt6m@o3OZ7L8Us2N6_mG+Y+ikkViZ_0M^^=vkgpxJv+t6TZ~RE}|?rXTo{OW?TyCsr+q50W)CTN@Z>^0-`6gD{|<(`%HaS{7}z z_QynQFuxd{0uxE+^5muz2f8#q9D#Sp$Vyx0+ocb8Kx2gdrN?ATL>7hq#A8@}Y{*WK z(-;L;fNmp%juNz$2Tki(NWW9M(X# z#6lO|_<}L=H3Rnw)9U(H4ELhd_oCJJnpPh~s}Cxw2Oz}K?RF{1iNO^)2!o8v2mvgl z6y^y;+Ci(e+j2l%M!>TtC7kTWH|Hv4Fli&Sw<=kSjL+s2=f5x+Ux`C@97rAqh?8u2 zHU=h)nka1!+v}Q|^amZ4HAB?IYm8$R=i2sW87)>hu>~yFqcKJk&*pZ0BzOyX5Az8O zCwYk@<#c=G_D~Sl#UbpBtKhT~I@^z*X2zjqfuoYeB z4t-ps0r3D8R&dj=Q;A6&E8#^A1celQt#najLERJGBt@+JCi)tD3p%VyXjk?~H&|(| z(ve${hjgwolcAP;u#QnQQnkR9t}C`+p_f~}1QPxY>VuR^zg8>FZMV7CvuuiaujW}X z5}vlknt=%2+w8=)d2fYYI>37f7gvp99voGQ%d%JLplqvg1+6S!t94Cj@V@Rtuj_%A zqK)3WuVS&zNO6y4FQlj~9~Qf@2r0|!vQgmU$mCcnda2zJYql!vR$WN0Iy*T#E=*@4 zLJ?hr$Cub61}s!wH1=Z2;PoTVKo&-Wc$@gF<9V*zWj4zx->O@p3Kx3Izp%{tC2?mH z+kdmBw+uroV>N)s=a>J1V6a+L+07`ELw+|?5=wLE4a~y!74Rt@N0SE+#Nm{XPe}`5}*`gjdt`!;CiggL+b%Y(SW)at@Vgu~f zmbhG%l%HHHDGTktY2gvi7c>#v0?1bize}6Q8m^Sg#v{0y++2B0Y^3KIbow1p``QLT zZvy=7CY$d?8lemK%a;@2<9q0uu-8FGKJ5Xk-Y?#yH#b&CAPf+M*7Lna!@Lp>v4u~X zws0MYWMj$Hqb&I3zG#A~bRTy2yq(YwGNE*ab&H3!oY`nNAY4bmqyVSY2oOSu_J8l=EH`IK^3Vlzs>#pC`#NS`|`W4dms(4sYNdJW+0?r6E`5(9ps*GS$ z#UG7ilAIp(-^mXHE}zx z8*W`)L%2TzNld5-!$~4lnWNBi%!2Vt)!gE@MrmkZ64K2!MuM+9p#S}pOS9e>1ma$X z{~V(~H@v`1^y1|T_1j6hhcEW<#hwJXr^?Z@`z{4y@pI$~&fB`IY3ZK_iNf$S^|M5;!K&Tt(X**dvr?Qvr zHJi#L7D16}jK*B&X?C1D<$s2Wsh^EvKM7~fsz`3}^wbC(0z+F-)W~P)xl2IXTn;Vz zR)C1lRdsb|?#?f7n|ph@(34kW^r8y*WrQqdD*UktBBs3D*shMIEW*`*EkH37%28P- zQB970hvpqOdx3oil`uvgx)050&LCl*kkFMVkde_e#MSB3r8!E!U6ef)RjGnFoL+6P z7EG#}tmXXgBQsq`b^+w>S~$}Yph4Ya)m|+n8V9^%=b`mnY6?}XQqhR1>du$DzpXVg z6bZB#qFpJzvefI(zv>$1XXEJP9j>tWutWAX^d%sKVTcdHd|Cn`upjXO z`G*Lz)PHXC>RUJ#+=;V>WT#pZKUw3r9xZdE7;X3Lg_Kt73icjw_;mjtd;xBWLPtkZ&l?vt6 zw)L>kp4tQ0xpX;lC)4{bnl|sssJoBH=|6FD74=!V>vN38;IfYN_d0qNrYm@0v>3+q z94W;2KzH#D+cM?6!DOH4QiMM~0dSqoR`TzXu`Nu4*-=r?v`6}mQyl}W;r_Pk&}Mvc zdfHk37dK0eNc3x*De?k>L18ni%$kKjW20mPqZA=@*m6cjct;C<_@Wr5JBLdqO+|a? zIf%Eio(^vfMAEIpd308^NPJ&QyWOr7BNZEOI%(d%XqJNAysCGr_|D|M?O1Ml39}_> zLBti1=yIz^@7FMF?!_Q>moVr=gBCtOIvI! z>^)B>V^qKmQCEPzRyKN(PBWG#!wI@q?M>!~`79|9DN$a>MFweH5OL9~m1vKN-c{}@ zH5c*wAhv8oGEJANf8~NY5hi}hB<-Z;)=E`?xK*UJT*jo=Kvv?cVp!{>0OUW{r*;%(eN}Zv!#hk5Bo@Z-?3VNFS(JdLjYt>S3AX0A(Vhuko-zh-HLPS*&UfS-E@M$(Otg^it+QaY0vL6^4`CZW z7*j@^

    ~bV9^vovp*C!j7y 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
      sSNBrK({A@Tdt+{??9KK0AF}e0Zm#i{ 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

      {B*L5T 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�NHL`2(sN0toE9n;5{v9 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

      0wT zQ;z^hypW)xY8f~JAry@mfBSG}1)rp+R$4;B(nibkjrhw5YBtR=b|qg1y7N|f+-8|D z4e#j>O8JjYh^R42|I*0GE6N)rC@A=ME$$+KPBV6G)%(SH*tfUtVOHWPHVcazd`#lA z%F(AGs1|_!(s&!w#ym;LMAFbQm`NiDJ?j8rZ8*FZ3C$V-;)-GyYDy%_T3j$3XES-<{oJa%7^rvk7yUZ z+6K6-M!YVz1|H+hi7*`s9+%Tp*J>RUR$>)eIGv!TI55S9WD7uP-WOmIN}v<8e=0eG zGQy#V5Q~v6-2Qh7OUp0l_vgnp#k(YM2$$>l0n#R(#CqpjqP$S z?m<520CZs{^d?{hc;+73jod5<@JYw#;MY(rp{7VAWyJx7b`Bn|Cd zjrK0GinX0LYyeV~!*V?1-COgf9!y{ml*Blt2b{;V)*8j!IqVmn5Ntkh+z)19OvQ;- zC>dg>=wOA&=H*t9)cJ;Rwit&$QWpT>Z~JE3O!YF174{P^dODOqne_o&vUtsFC!H;YRXhqwA5#zb>Fj{ zPW+nZjc&osC8h7B>AD-BuPplh+6t)0bG>U*(@*H7J93&d+W8Pt5nfIx9ZrPX>Hg-vdtB(81RGsYhq_vxZGN`p7@)cM-=AHR;ZU zB&5eO1l?CUUfy&P><4$fKeJ5%zWk$+?r~irCqu3g(O;Wq8XE;3AKl~{`d)q7D|c81 zR}n0<8|6dKyFhYf@28iEzPM$SO~TS%GW2RvF(2LBn9*>HGvF`g&wk&#Mcyd>Vf>XQ zBO-ACe04}H{}z5Rk5mpYyvQ+dhRc!v2*fBm*9Dpe-!p*kEd(XK#^_S`o^V73o0Y>z z((m8b<%$G!EB*?#tw};q9V-Pn=l}yx6`JGn|VJmp?X

      3jLBB%3MBj`!v#-XW}t#!pfC3f12G}`O!-|1 zD9kQ-USPm`Zn`~3{SKpsP0;-@qme0cD<7Z2n2G6Qdpo&P{5-y(FvJ)uT&5EkbBRK_ z{RNs!5*}_g?T8TEH4J{ZUjw`+rE|xaW)qRdcICNMU34wG95UxBmQK#D^CpnLSiV^H zEa2+oD|RWlhmpTnF%jNl*l?#tMe!ax03ZPS0KiDXr)Zxg;smVp=;xQUt=PIqa&{Vq zx~+}!Ig*I5mp7=84<6NqvdYLld5a-o0OuNM-pajv(WOaPGjgJJ5VJ`9ype<-N;tiPf`=H@zRSO1zFtAk?dR zxbpF(l@;R&E+MyS4I0CLD2V*gQ3ampgW`kE)J+DY+sEh`+7*(=wR^O1erXv#mR&4IwCXD zYQl}$IqJ+K$qfXg&4f}>3aJw_w05P*r)2`ucUfe&-YKQ-Q2 zrSivpD{rv!My-t3l^@o~y?pUZIAJ1#sApUeqLq;}+?2*q9gXvKGmi*PnfVPxkyD<2 zR)0#iTS+GW$i6afSDI?s<#j2$ywa18@)N3BqmOBn7)iZ55Qv_TXY;gdc!6@_K*C_= zOsvHFeS#^Npwf7Xj!4Y%)K_Yw55;)8QgSivz+>GZMxZyS5G2O!Qje;FI+5mx!>A-k3 zksTDSsq&gNl_KL}(`&(QIbM{?iR&+Y^}0O_V8<|mo0bvWbgiGPTL&5wl(2ltmwMwJ z

      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%0DpsDZ&E|2e2Q*iB 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 **STALE — regeneration required before any deployment.** These artifacts were ++> rendered before the MF-1 fix (`MODEXP_GAS` raised to the EIP-7883 bound and a ++> constructor modexp known-answer probe added), so the committed `.sol` files ++> here still carry the old 1360 bound and no modexp probe. They remain valid ++> inputs for the *replay* tests, which exercise verification logic rather than ++> the modexp bound, but they must be regenerated (and their provenance rows ++> below updated) on a host with the pinned solc before they are used as a ++> deployment source. Regeneration needs solc, which the environment that ++> applied the MF-1 fix did not have. ++ + Pre-rendered artifacts for `tests/ivc_accumulator_replay.rs`, which replays a + real IVC final proof and then mutates the accumulator public inputs to check the + decoder in `templates/partials/verifier/AccumulatorHelpers.yul` rejects them. +diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +--- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md ++++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +@@ -1,5 +1,15 @@ + # Moonlight Wrap point_pair Replay Fixture + ++> **STALE — regeneration required before any deployment.** These artifacts were ++> rendered before the MF-1 fix (`MODEXP_GAS` raised to the EIP-7883 bound and a ++> constructor modexp known-answer probe added), so the committed `.sol` files ++> here still carry the old 1360 bound and no modexp probe. They remain valid ++> inputs for the *replay* tests, which exercise verification logic rather than ++> the modexp bound, but they must be regenerated (and their provenance rows ++> below updated) on a host with the pinned solc before they are used as a ++> deployment source. Regeneration needs solc, which the environment that ++> applied the MF-1 fix did not have. ++ + Pre-rendered artifacts for the `point_pair` accumulator arm of + `tests/ivc_accumulator_replay.rs`. The IVC fixture next door covers + `AccumulatorEncoding::new` (explicit lhs/rhs scalars); this one covers +diff --git a/proofs/solidity-verifier/src/evm.rs b/proofs/solidity-verifier/src/evm.rs +--- a/proofs/solidity-verifier/src/evm.rs ++++ b/proofs/solidity-verifier/src/evm.rs +@@ -346,6 +346,19 @@ + /// are routed to revm's bundled implementations. The runner keeps an + /// `InMemoryDB` across calls so tests can deploy once and call many + /// times. ++ /// ++ /// MF-1 coverage gap, deliberately not papered over: this harness cannot ++ /// exercise a chain whose modexp is priced by EIP-7883. The pinned ++ /// revm 19 exposes `SpecId::OSAKA`, but that variant is Prague+EOF in this ++ /// version -- its `0x05` handler is `berlin_run`, i.e. EIP-2565 pricing ++ /// with the `/ 3` divisor -- so switching the spec here would produce ++ /// green tests that prove nothing about the repricing that bricked the ++ /// pre-fix bound. Raising real coverage needs a revm bump to a version ++ /// whose Osaka handler implements EIP-7883; until then, MF-1 is guarded ++ /// by `modexp_gas_bound_covers_every_live_schedule` (the bound is derived ++ /// from both EIP texts) and by the constructor's modexp known-answer ++ /// probe, which forwards the rendered bound and so fails at deployment on ++ /// any chain that prices modexp above it. + #[derive(Default)] + pub struct Evm { + db: InMemoryDB, +diff --git a/proofs/solidity-verifier/src/lowering/layout/mod.rs b/proofs/solidity-verifier/src/lowering/layout/mod.rs +--- a/proofs/solidity-verifier/src/lowering/layout/mod.rs ++++ b/proofs/solidity-verifier/src/lowering/layout/mod.rs +@@ -139,7 +139,7 @@ + + pub(crate) mod gas { + //! Exact gas schedule for the precompiles the generated verifier calls, +- //! from EIP-2537 (BLS12-381) and EIP-2565 (modexp). ++ //! from EIP-2537 (BLS12-381) and EIP-2565/EIP-7883 (modexp). + //! + //! A failing EIP-2537 or modexp call consumes ALL gas supplied to the + //! `STATICCALL`, so every generated call site forwards the exact scheduled +@@ -153,11 +153,19 @@ + //! amount succeeds by construction on any conformant implementation of + //! the current schedule. + //! +- //! Liveness caveat: if a future fork reprices these precompiles UPWARD, +- //! deployed verifiers start reverting on valid proofs and must be +- //! regenerated and redeployed. The constructor smoke probes forward the +- //! same bounds, so deployment onto an already-repriced chain fails fast +- //! instead of bricking at proof time. ++ //! Multi-schedule bounds: where more than one schedule is live across the ++ //! chains this verifier targets, the bound is the MAXIMUM over those ++ //! schedules rather than the one for a single fork (see ++ //! [`modexp_gas_word_frame`]). Over-forwarding costs nothing on success -- ++ //! unused gas is returned -- and only widens the burn of one *failing* ++ //! call by the difference, whereas under-forwarding bricks the verifier. ++ //! ++ //! Liveness caveat: if a future fork reprices these precompiles above the ++ //! bounds rendered here, deployed verifiers start reverting on valid ++ //! proofs and must be regenerated and redeployed. The constructor smoke ++ //! probes forward the same bounds for every precompile the runtime ++ //! depends on -- EIP-2537 *and* modexp (MF-1) -- so deployment onto an ++ //! already-repriced chain fails fast instead of bricking at proof time. + + /// EIP-2537 G1ADD flat cost. + pub(crate) const G1ADD_GAS: u64 = 375; +@@ -196,23 +204,65 @@ + 32_600 * pairs + 37_700 + } + +- /// EIP-2565 modexp cost for the only frame shape the verifier emits: +- /// 32-byte base, 32-byte exponent, 32-byte modulus. ++ /// Modexp bound for the only frame shape the verifier emits: 32-byte ++ /// base, 32-byte exponent, 32-byte modulus. ++ /// ++ /// Two schedules are live across the chains this verifier targets, so the ++ /// rendered bound is the maximum of both: ++ /// ++ /// * **EIP-2565** (Berlin): `max(200, multiplication_complexity * ++ /// iteration_count / 3)`. With `words = ceil(32/8) = 4` and ++ /// `multiplication_complexity = words^2 = 16`, that is ++ /// `max(200, 16 * 255 / 3) = 1360`. ++ /// * **EIP-7883** (Osaka/Fusaka): the `/ 3` divisor is **removed** and the ++ /// floor is raised to 500, giving `max(500, 16 * 255) = 4080`. ++ /// ++ /// MF-1: this function previously returned only the EIP-2565 value and ++ /// asserted that EIP-7883 "only reprices operands wider than 32 bytes". ++ /// That reading was wrong. EIP-7883 changes two independent things: the ++ /// `multiplication_complexity` branch for `max_length > 32` (`2 * words^2`, ++ /// which indeed does not apply here), *and* the removal of the `/ 3` ++ /// divisor from the final `multiplication_complexity * iteration_count` ++ /// product, which applies to every operand size. A verifier rendered with ++ /// the 1360 bound deploys fine on a repriced chain and then reverts ++ /// `PrecompileFailed` on every proof, because `staticcall` forwards a ++ /// fixed amount and the precompile runs out of gas inside the mandatory ++ /// Lagrange batch inversion. + /// +- /// `words = ceil(32/8) = 4`, `multiplication_complexity = words^2 = 16`, +- /// `iteration_count <= 255` (32-byte exponent), so +- /// `max(200, 16 * 255 / 3) = 1360`. EIP-7883 (scheduled for Osaka) keeps +- /// the same result for these operand sizes: it raises the floor to 500 +- /// (< 1360) and only reprices operands wider than 32 bytes. ++ /// `iteration_count` is the generic upper bound for any 32-byte exponent ++ /// (`exponent.bit_length() - 1 <= 255`). Both exponents the verifier ++ /// actually emits are `FR_MODULUS - 2`, whose 255-bit length gives 254 ++ /// iterations and an exact EIP-7883 price of 4064; the extra 16 gas keeps ++ /// the bound valid for any 32-byte exponent a future emitter might use. + pub(crate) const fn modexp_gas_word_frame() -> u64 { + const WORDS: u64 = 4; + const MULTIPLICATION_COMPLEXITY: u64 = WORDS * WORDS; ++ // Upper bound over every 32-byte exponent: `bit_length() - 1 <= 255`. + const MAX_ITERATION_COUNT: u64 = 255; +- let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT / 3; +- if cost < 200 { +- 200 ++ ++ // EIP-2565: divisor 3, floor 200. ++ let eip2565 = { ++ let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT / 3; ++ if cost < 200 { ++ 200 ++ } else { ++ cost ++ } ++ }; ++ // EIP-7883: no divisor, floor 500. ++ let eip7883 = { ++ let cost = MULTIPLICATION_COMPLEXITY * MAX_ITERATION_COUNT; ++ if cost < 500 { ++ 500 ++ } else { ++ cost ++ } ++ }; ++ ++ if eip2565 > eip7883 { ++ eip2565 + } else { +- cost ++ eip7883 + } + } + } +diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs +--- a/proofs/solidity-verifier/src/lowering/tests.rs ++++ b/proofs/solidity-verifier/src/lowering/tests.rs +@@ -1459,14 +1459,107 @@ + assert_eq!(gas::g1msm_gas(200), 200 * 12_000 * 519 / 1_000); + // 32600*k + 37700 for the verifier's two-pair check. + assert_eq!(gas::pairing_gas(2), 102_900); +- // EIP-2565, 32-byte base/exp/mod: max(200, 16 * 255 / 3). +- assert_eq!(gas::modexp_gas_word_frame(), 1_360); + // The rendered template constants come from the same module. + let constants = crate::lowering::render::TemplateConstants::default().gas; + assert_eq!(constants.g1add, 375); + assert_eq!(constants.g1msm_one_pair, 12_000); + assert_eq!(constants.pairing_two_pair, 102_900); +- assert_eq!(constants.modexp, 1_360); ++ assert_eq!(constants.modexp, gas::modexp_gas_word_frame()); ++} ++ ++/// MF-1: the modexp bound must cover EVERY live schedule, not just the one ++/// that happened to be current when the generator was written. Derive both ++/// prices here from their EIP texts instead of asserting one magic number, so ++/// the next repricing forces a conscious edit rather than a silent brick: ++/// `staticcall` forwards a fixed amount, so a bound below the chain's price ++/// makes the precompile OOG and every proof revert. ++#[test] ++fn modexp_gas_bound_covers_every_live_schedule() { ++ use crate::lowering::layout::gas; ++ ++ // Shared inputs for the only frame the verifier emits (32-byte base, ++ // exponent, and modulus). ++ const WORDS: u64 = 32_u64.div_ceil(8); ++ const MULTIPLICATION_COMPLEXITY: u64 = WORDS * WORDS; ++ // `exponent.bit_length() - 1` for a 32-byte exponent, upper-bounded. ++ const ITERATION_COUNT: u64 = 255; ++ ++ // EIP-2565: `max(200, multiplication_complexity * iteration_count / 3)`. ++ let eip2565 = std::cmp::max(200, MULTIPLICATION_COMPLEXITY * ITERATION_COUNT / 3); ++ assert_eq!(eip2565, 1_360, "EIP-2565 price for the 32-byte frame"); ++ ++ // EIP-7883: the `/ 3` divisor is removed for EVERY operand size (only the ++ // `2 * words^2` complexity branch is width-specific) and the floor rises ++ // to 500: `max(500, multiplication_complexity * iteration_count)`. ++ let eip7883 = std::cmp::max(500, MULTIPLICATION_COMPLEXITY * ITERATION_COUNT); ++ assert_eq!(eip7883, 4_080, "EIP-7883 price for the 32-byte frame"); ++ ++ assert_eq!( ++ gas::modexp_gas_word_frame(), ++ std::cmp::max(eip2565, eip7883), ++ "modexp bound must be the maximum over live schedules" ++ ); ++ assert!( ++ gas::modexp_gas_word_frame() >= eip7883, ++ "a bound below the EIP-7883 price bricks every proof on Osaka/Fusaka \ ++ chains: the fixed-gas staticcall OOGs inside the mandatory Lagrange \ ++ batch inversion and verifyProof reverts PrecompileFailed" ++ ); ++ ++ // The exponent the verifier actually emits is FR_MODULUS - 2 (255 bits, ++ // so 254 iterations); the generic bound must cover its exact price too. ++ assert!(gas::modexp_gas_word_frame() >= MULTIPLICATION_COMPLEXITY * 254); ++} ++ ++/// MF-1: modexp is the one precompile the runtime cannot do without -- the ++/// Lagrange batch inversion calls it on every proof -- and it was the one ++/// precompile the constructor never probed, so a stale bound deployed ++/// silently. Pin the probe's shape: right precompile, the pinned runtime ++/// bound (not `gas()`), a return-size check, and a known answer a stub ++/// cannot satisfy. ++#[test] ++fn constructor_probes_modexp_at_the_pinned_runtime_bound() { ++ let smoke = include_str!("../../templates/partials/verifier/PrecompileSmoke.sol"); ++ ++ assert!( ++ smoke.contains("staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}"), ++ "constructor must probe modexp at the same bound the runtime forwards" ++ ); ++ assert!( ++ smoke.contains( ++ "if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) }" ++ ), ++ "modexp probe must check the returned size" ++ ); ++ // 2^(r-2) == 2^-1, verified as mulmod(result, 2, r) == 1: a precompile ++ // that returns zeros, or echoes its input, fails this. ++ assert!( ++ smoke.contains("mstore(add(scratch, {{ template_constants.modexp.base_offset|hex() }}), 2)") ++ && smoke.contains( ++ "mstore(add(scratch, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2))" ++ ) ++ && smoke.contains("if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) }"), ++ "modexp probe must run the runtime's own Fermat inversion as a known-answer test" ++ ); ++ ++ // Every precompile the runtime calls is now probed at its pinned bound. ++ for (probe, gas_constant) in [ ++ ("modexp.address", "MODEXP_GAS"), ++ ("eip2537.g1add_address", "G1ADD_GAS"), ++ ("eip2537.g1msm_address", "G1MSM_GAS_1PAIR"), ++ ("eip2537.pairing_address", "PAIRING_GAS_2PAIR"), ++ ] { ++ assert!( ++ smoke.contains(&format!( ++ "staticcall({gas_constant}, {{{{ template_constants.{probe}|hex() }}}}" ++ )), ++ "constructor smoke probe missing for {probe} at {gas_constant}" ++ ); ++ } ++ assert!( ++ !smoke.contains("staticcall(gas()"), ++ "smoke probes must forward pinned bounds, not gas()" ++ ); + } + + #[test] +@@ -1560,10 +1653,14 @@ + "generated verifier should include a deployment-time runtime prerequisite smoke test" + ); + for required in [ +- "Smoke-check the Cancun/EIP-2537 runtime features", ++ "Smoke-check the Cancun/EIP-2537/modexp runtime features", + "mcopy(add(scratch, {{ template_constants.word_bytes|hex() }}), scratch, {{ template_constants.word_bytes|hex() }})", + "eq(mload(add(scratch, {{ template_constants.word_bytes|hex() }})), 0x1234)", + "non-Cancun fork fails during deployment", ++ // MF-1: modexp is a runtime prerequisite like any other precompile. ++ "modexp (0x05) known-answer probe at the pinned runtime bound", ++ "staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}", ++ "if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) }", + "G1ADD(identity, identity) -> identity", + "Known-answer probe: G1ADD(G, G) == 2G", + "template_constants.eip2537.g1_generator", +diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +--- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol ++++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +@@ -169,7 +169,8 @@ + uint256 internal constant QUOTIENT_LIMB_COMMS_MPTR_BASE = {{ memory.quotient_limb_comms_mptr_base }}; + + // ---------------------------------------------------------------------- +- // Precompile gas bounds: the exact EIP-2537 / EIP-2565 scheduled costs. ++ // Precompile gas bounds: the scheduled EIP-2537 costs, and for modexp the ++ // maximum over the EIP-2565 and EIP-7883 schedules. + // + // A failing EIP-2537 or modexp call consumes ALL gas supplied to the + // STATICCALL, so every generated call site forwards the exact scheduled +@@ -179,9 +180,17 @@ + // (EIP-2537 "DDoS protection" rationale), so these bounds are sufficient + // by construction on any conformant chain. + // +- // Liveness caveat: if a future fork reprices these precompiles UPWARD, +- // this verifier must be regenerated and redeployed. The constructor +- // smoke probes forward the same bounds, so deployment onto an ++ // MODEXP_GAS covers both live modexp schedules: EIP-2565 prices this ++ // frame at 1360, EIP-7883 (Osaka/Fusaka) removes the /3 divisor and ++ // prices it at 4080, so the larger bound is rendered. Forwarding the ++ // EIP-7883 bound on a pre-Osaka chain is free on success -- unused gas is ++ // returned -- while forwarding the EIP-2565 bound on a repriced chain ++ // reverts every proof. ++ // ++ // Liveness caveat: if a future fork reprices these precompiles above the ++ // bounds below, this verifier must be regenerated and redeployed. The ++ // constructor smoke probes forward the same bounds for EVERY precompile ++ // the runtime calls, modexp included, so deployment onto an + // already-repriced chain fails fast instead of bricking at proof time. + // ---------------------------------------------------------------------- + uint256 internal constant G1ADD_GAS = {{ template_constants.gas.g1add }}; +diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +--- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol ++++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +@@ -1,9 +1,10 @@ +- /// @notice Smoke-check the Cancun/EIP-2537 runtime features required by the verifier. +- /// @dev Exercises MCOPY and identity EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. +- /// The probes forward the same exact EIP-2537 gas bounds the runtime +- /// uses (see the gas-bound constants block), so a chain whose +- /// precompile schedule was repriced upward fails here, at deployment, +- /// instead of bricking verifyProof later. ++ /// @notice Smoke-check the Cancun/EIP-2537/modexp runtime features required by the verifier. ++ /// @dev Exercises MCOPY, modexp, and EIP-2537 inputs to catch incompatible chain/fork configurations at deployment. ++ /// The probes forward the same exact gas bounds the runtime uses, for ++ /// every precompile it calls -- 0x05 modexp included (see the ++ /// gas-bound constants block) -- so a chain whose precompile schedule ++ /// was repriced above those bounds fails here, at deployment, instead ++ /// of bricking verifyProof later. + function require_eip2537_precompiles() private view { + assembly ("memory-safe") { + // Same free-memory-pointer guard as verifyProof. This body runs in +@@ -21,8 +22,39 @@ + mcopy(add(scratch, {{ template_constants.word_bytes|hex() }}), scratch, {{ template_constants.word_bytes|hex() }}) + if iszero(eq(mload(add(scratch, {{ template_constants.word_bytes|hex() }})), 0x1234)) { revert(0, 0) } + ++ // ---------------------------------------------------------------- ++ // modexp (0x05) known-answer probe at the pinned runtime bound. ++ // ++ // MF-1: every other precompile the runtime calls was probed here, ++ // but modexp -- which the MANDATORY Lagrange batch inversion and ++ // every scalar_inv call depend on -- was not. Two live schedules ++ // price this frame differently (EIP-2565: 1360, EIP-7883: 4080), ++ // and a bound below the chain's price does not degrade: the ++ // staticcall forwards a fixed amount, the precompile OOGs, and ++ // EVERY proof reverts PrecompileFailed. Without this probe that ++ // failure is invisible until the first verifyProof call, on a ++ // contract that deployed cleanly. ++ // ++ // The vector is the runtime's own operation -- Fermat inversion ++ // in Fr -- so it exercises the exact frame shape, exponent width, ++ // and gas bound used at proof time: 2^(FR_MODULUS - 2) == 2^-1. ++ // Checking mulmod(result, 2, FR_MODULUS) == 1 rather than a ++ // rendered constant keeps the probe self-contained while still ++ // rejecting a stub: a precompile returning zeros (or its input) ++ // fails, since 0 * 2 != 1 mod r. ++ // ---------------------------------------------------------------- ++ mstore(add(scratch, {{ template_constants.modexp.base_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // base len ++ mstore(add(scratch, {{ template_constants.modexp.exp_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // exp len ++ mstore(add(scratch, {{ template_constants.modexp.mod_len_offset|hex() }}), {{ template_constants.word_bytes|hex() }}) // mod len ++ mstore(add(scratch, {{ template_constants.modexp.base_offset|hex() }}), 2) ++ mstore(add(scratch, {{ template_constants.modexp.exp_offset|hex() }}), sub(FR_MODULUS, 2)) ++ mstore(add(scratch, {{ template_constants.modexp.mod_offset|hex() }}), FR_MODULUS) ++ if iszero(staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, scratch, {{ template_constants.modexp.frame_bytes|hex() }}, scratch, {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) { revert(0, 0) } ++ if iszero(eq(mulmod(mload(scratch), 2, FR_MODULUS), 1)) { revert(0, 0) } ++ + // Start the EIP-2537 probes with the identity encoding for G1/G2: +- // all-zero padded words. ++ // all-zero padded words. This also clears the modexp frame above. + for { let off := 0 } lt(off, {{ template_constants.eip2537.smoke_scratch_bytes|hex() }}) { off := add(off, {{ template_constants.word_bytes|hex() }}) } { + mstore(add(scratch, off), 0) + } +diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs +--- a/proofs/solidity-verifier/tests/template_digest.rs ++++ b/proofs/solidity-verifier/tests/template_digest.rs +@@ -13,7 +13,7 @@ + + /// keccak over the sorted (path, length, content) stream of `templates/`. + const EXPECTED_TEMPLATE_TREE_DIGEST: &str = +- "0x0809729cd0ee884736704458fbc53a2afc62c0de675b3a749b3c22c9ac797671"; ++ "0xfe89267c0778787678b938eb6f56f5e79f4bc11578786da45f2aad82384349d9"; + + fn collect_files(dir: &Path, files: &mut Vec) { + for entry in fs::read_dir(dir).expect("template directory is readable") { diff --git a/_to_delete/pr2.git.patch b/_to_delete/pr2.git.patch new file mode 100644 index 000000000..a165c8421 --- /dev/null +++ b/_to_delete/pr2.git.patch @@ -0,0 +1,739 @@ +diff --git a/proofs/solidity-verifier/src/lowering/layout/memory.rs b/proofs/solidity-verifier/src/lowering/layout/memory.rs +--- a/proofs/solidity-verifier/src/lowering/layout/memory.rs ++++ b/proofs/solidity-verifier/src/lowering/layout/memory.rs +@@ -528,6 +528,14 @@ + /// selector accumulators are accounted for. + pub(crate) quotient_tmp_mptr: usize, + pub(crate) quotient_stack_mptr: usize, ++ /// First address past the quotient VM stack / callback scratch region. ++ /// ++ /// MF-3: the interpreter's spill pointer walks upward from ++ /// `quotient_stack_mptr` with no ceiling of its own, so the rendered VM ++ /// clamps `q_sp` against this bound. The region is sized for the larger ++ /// of the interpreted stack depth and the structured native-callback ++ /// scratch, which is exactly the ceiling both uses must respect. ++ pub(crate) quotient_stack_hi: usize, + pub(crate) pcs_q_eval_source_table_mptr: usize, + pub(crate) pcs_q_com_trace_scratch_mptr: usize, + pub(crate) pcs_final_msm_scratch_mptr: usize, +@@ -1099,6 +1107,7 @@ + lagrange_denoms_mptr, + quotient_tmp_mptr, + quotient_stack_mptr, ++ quotient_stack_hi: quotient_stack_mptr + quotient_stack_len.max(MODEXP_FRAME_BYTES), + pcs_q_eval_source_table_mptr, + pcs_q_com_trace_scratch_mptr, + pcs_final_msm_scratch_mptr, +diff --git a/proofs/solidity-verifier/src/lowering/quotient.rs b/proofs/solidity-verifier/src/lowering/quotient.rs +--- a/proofs/solidity-verifier/src/lowering/quotient.rs ++++ b/proofs/solidity-verifier/src/lowering/quotient.rs +@@ -187,6 +187,8 @@ + selector_max_power: selector_fold.max_power, + selector_tail_updates: Self::selector_tail_updates(selector_fold), + stack_mptr: quotient_stack_mptr, ++ stack_hi: memory.quotient_stack_hi, ++ num_consts: build.consts.len(), + program_mptr, + operand_lo: operand_bounds.0, + operand_hi: operand_bounds.1, +diff --git a/proofs/solidity-verifier/src/lowering/render/models.rs b/proofs/solidity-verifier/src/lowering/render/models.rs +--- a/proofs/solidity-verifier/src/lowering/render/models.rs ++++ b/proofs/solidity-verifier/src/lowering/render/models.rs +@@ -706,6 +706,17 @@ + pub(crate) selector_tail_updates: Vec, + /// Operand stack / callback scratch base. + pub(crate) stack_mptr: usize, ++ /// First address past the operand stack / callback scratch region. ++ /// ++ /// MF-3: spill sites clamp `q_sp` against this so a malformed program ++ /// cannot walk the stack pointer out of its registered region. ++ pub(crate) stack_hi: usize, ++ /// Number of Fr words in the generated quotient constant table. ++ /// ++ /// MF-3: constant-table indexes decoded from program bytes are clamped ++ /// against this so an out-of-range index cannot read program bytes (or ++ /// commitment words) as field constants. ++ pub(crate) num_consts: usize, + /// Memory pointer to the first encoded program word. + pub(crate) program_mptr: usize, + /// Lowest word address a VM memory operand may load from (P12/L-6). +@@ -1218,6 +1229,8 @@ + selector_max_power: 0, + selector_tail_updates: vec![], + stack_mptr: 0, ++ stack_hi: usize::MAX, ++ num_consts: usize::MAX, + program_mptr: 0, + // Synthetic model: a permissive clamp window keeps the + // rendered guards inert for layout-shape tests. +diff --git a/proofs/solidity-verifier/src/lowering/tests.rs b/proofs/solidity-verifier/src/lowering/tests.rs +--- a/proofs/solidity-verifier/src/lowering/tests.rs ++++ b/proofs/solidity-verifier/src/lowering/tests.rs +@@ -1511,6 +1511,176 @@ + assert!(gas::modexp_gas_word_frame() >= MULTIPLICATION_COMPLEXITY * 254); + } + ++/// MF-4: the typed taxonomy exists so an incident responder can tell a chain ++/// fault from a rejected proof. Three paths used to conflate them -- a failed ++/// precompile inside the accumulator precheck or the final pairing surfaced as ++/// an input rejection, and a zero Lagrange denominator (a transcript event) ++/// surfaced as `PrecompileFailed`. Pin the split so it cannot regress. ++#[test] ++fn precompile_faults_and_input_rejections_use_distinct_selectors() { ++ let corpus = verifier_template_corpus(); ++ ++ // (a) The pairing helper: staticcall/returndatasize failure is a chain ++ // fault; a pairing that ran and returned != 1 rejects the proof. ++ assert!( ++ corpus.contains( ++ "if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) }\n // Compare against 1 rather than truncating to the low bit:" ++ ), ++ "ec_pairing must report a failed pairing staticcall as PrecompileFailed" ++ ); ++ assert!( ++ corpus.contains("ret := eq(mload(scratch), 1)\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }"), ++ "ec_pairing must report a pairing result of 0 as ProofRejected" ++ ); ++ ++ // (b) batch_invert and the accumulator validator both carry a cause flag ++ // rather than a bare boolean. ++ assert!( ++ corpus.contains( ++ "function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret, precompile_failed" ++ ), ++ "batch_invert must report whether its modexp call failed" ++ ); ++ assert!( ++ corpus ++ .contains("function validate_public_accumulator(success, r) -> out, precompile_failed"), ++ "the accumulator validator must report whether its G1MSM call failed" ++ ); ++ ++ // (c) Both boundaries must branch on that flag. ++ for (guarded, fallback, what) in [ ++ ( ++ "if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }", ++ "fail(ERR_PROOF_REJECTED)", ++ "Lagrange", ++ ), ++ ( ++ "if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }", ++ "fail(ERR_BAD_POINT_ENCODING)", ++ "accumulator", ++ ), ++ ] { ++ assert!( ++ corpus.contains(guarded) && corpus.contains(fallback), ++ "{what} boundary must split precompile faults from rejected input" ++ ); ++ } ++ ++ // A zero denominator means the squeezed x hit a domain point: an input ++ // rejection, not a broken chain. ++ assert!( ++ !corpus.contains( ++ "success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r)" ++ ), ++ "the Lagrange batch inversion must thread its failure cause" ++ ); ++} ++ ++/// MF-3: the quotient VM's terminal checks (`q_pc == q_end`, `q_has_top == 0`, ++/// `q_sp == base`) cannot see three failure shapes, so the interpreter grew ++/// guards for each. The program is VK-codehash-pinned, so none of these are ++/// reachable on-chain with a well-formed artifact -- they are containment for ++/// a future generator bug, mirroring on the deployed side what the reference ++/// VM already enforces at build time (`stack.len() == 1` per identity, ++/// `const_at` bounds, and `identity_segment` rejecting a native marker inside ++/// an expression). ++#[test] ++fn quotient_vm_interpreter_fails_closed_on_malformed_programs() { ++ let vm = include_str!("../../templates/partials/quotient_numerator/QuotientNumeratorBlock.yul"); ++ ++ // (a) A fold with no live cached top would re-fold a STALE q_top, and ++ // both terminal checks would still pass. ++ assert_eq!( ++ vm.matches("{%- call q_top_guard() %}").count(), ++ 2, ++ "both FOLD_MAIN and FOLD_SELECTOR must require a live cached top" ++ ); ++ assert!( ++ vm.contains("if iszero(q_has_top) { q_program_fail() }"), ++ "q_top_guard must fail closed when the cached top is not live" ++ ); ++ ++ // (b) Native callbacks used to RESET q_sp, which silently discarded ++ // operands spilled by a preceding partial expression -- an identity would ++ // drop out of nu_y(x) with the program still ending balanced. Assert ++ // instead of reset. ++ // The only assignment of the stack base to q_sp may be its declaration. ++ assert_eq!( ++ vm.matches("q_sp := {{ program.stack_mptr|hex() }}").count(), ++ 1, ++ "native callbacks must not reset q_sp; a reset hides dropped operands" ++ ); ++ assert!( ++ vm.contains("let q_sp := {{ program.stack_mptr|hex() }}"), ++ "the surviving q_sp assignment must be its initial declaration" ++ ); ++ assert_eq!( ++ vm.matches("{%- call q_stack_empty_guard() %}").count(), ++ 3, ++ "each native callback boundary must assert an already-empty stack" ++ ); ++ ++ // (c) The spill pointer has no ceiling of its own. ++ assert_eq!( ++ vm.matches("if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() }") ++ .count(), ++ 10, ++ "every cached-top spill site must clamp q_sp to its registered region" ++ ); ++ ++ // (d) u16 constant-table indexes reach far outside the pinned payload, so ++ // unlike the u8 forms they cannot rely on bounded drift. ++ assert_eq!( ++ vm.matches("{%- call q_const_guard(\"qconst\") %}").count(), ++ 3, ++ "u16 constant-table indexes must be clamped to the rendered table length" ++ ); ++ assert!( ++ vm.contains("if iszero(lt({{ idx }}, {{ program.num_consts }})) { q_program_fail() }"), ++ "q_const_guard must clamp against the generated constant-table length" ++ ); ++} ++ ++/// MF-2: the free-memory-pointer guard is the only on-chain check that solc's ++/// stack-spill reservation has not grown into the generated absolute layout. ++/// A fork that recompiles at a different (version, optimiser-runs) pair can ++/// still fit EIP-170, deploy, and then revert on every proof -- so the guard ++/// must say *why* rather than reverting bare, which is indistinguishable from ++/// every other empty revert. ++#[test] ++fn memory_layout_guard_reverts_with_a_typed_selector() { ++ let verifier_template = include_str!("../../templates/contracts/Halo2Verifier.sol"); ++ let smoke_template = include_str!("../../templates/partials/verifier/PrecompileSmoke.sol"); ++ ++ for (source, name) in [ ++ (verifier_template, "verifyProof"), ++ (smoke_template, "constructor"), ++ ] { ++ assert!( ++ source.contains("mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED))") ++ && source.contains("revert(0x00, 0x04)"), ++ "{name} memory-layout guard must revert with MemoryLayoutViolated()" ++ ); ++ } ++ // The guard must still be the first thing each assembly block does: it ++ // protects the writes that follow, so a bare `revert(0, 0)` left behind ++ // on either path means the typed rewrite missed a site. ++ assert!( ++ verifier_template.contains("if gt(mload(0x40), TRANSCRIPT_MPTR) {"), ++ "runtime guard must still compare the FMP against TRANSCRIPT_MPTR" ++ ); ++ assert!( ++ !verifier_template.contains("if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) }"), ++ "runtime memory-layout guard still reverts bare" ++ ); ++ assert!( ++ !smoke_template.contains( ++ "if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) }" ++ ), ++ "constructor memory-layout guard still reverts bare" ++ ); ++} ++ + /// MF-1: modexp is the one precompile the runtime cannot do without -- the + /// Lagrange batch inversion calls it on every proof -- and it was the one + /// precompile the constructor never probed, so a stale bound deployed +@@ -1572,7 +1742,7 @@ + "ABI/proof length/instance shape checks should fail before accumulator or transcript parsing" + ); + assert!( +- verifier_template.contains("success := validate_public_accumulator(success, r)\n if iszero(success) { fail(ERR_BAD_POINT_ENCODING) }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), ++ verifier_template.contains("success, acc_precompile_failed := validate_public_accumulator(success, r)\n if iszero(success) {\n // MF-4: a G1MSM that could not run at all is a chain fault,\n // not a malformed accumulator point.\n if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }\n fail(ERR_BAD_POINT_ENCODING)\n }\n {%- endif %}\n\n {%- if self.gas_checkpoints %}\n gas_checkpoint(2)"), + "accumulator precheck should fail before transcript parsing" + ); + assert!( +@@ -1583,7 +1753,7 @@ + ); + assert!( + verifier_template.contains( +- "if iszero(success) { fail(ERR_PRECOMPILE_FAILED) }\n\n {%- match quotient_external %}" ++ "if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) }\n fail(ERR_PROOF_REJECTED)\n }\n\n {%- match quotient_external %}" + ), + "failed Lagrange/common-polynomial setup should fail before quotient reconstruction" + ); +@@ -1843,9 +2013,9 @@ + let verifier_template = verifier_template_corpus(); + + for required in [ +- "function validate_public_accumulator(success, r) -> out", ++ "function validate_public_accumulator(success, r) -> out, precompile_failed", + "Fail malformed accumulator public inputs before transcript", +- "success := validate_public_accumulator(success, r)", ++ "success, acc_precompile_failed := validate_public_accumulator(success, r)", + "gas_checkpoint(2) // after VK loading + accumulator public-input precheck", + "Batch the prevalidated public IVC accumulator pairing equation", + ] { +@@ -2399,8 +2569,14 @@ + verifier_template.contains("function ec_pairing(success, lhs_mptr, rhs_mptr) -> ret") + && verifier_template + .contains("ret := success\n if iszero(ret) { leave }") ++ // MF-4: a failed/short-returning pairing staticcall is a chain ++ // fault (PrecompileFailed); only a pairing that RAN and ++ // returned != 1 rejects the proof. ++ && verifier_template.contains( ++ "ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }}))\n if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) }", ++ ) + && verifier_template.contains( +- "ret := and(ret, eq(mload(scratch), 1))\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }\n ret := 1", ++ "ret := eq(mload(scratch), 1)\n if iszero(ret) { fail(ERR_PROOF_REJECTED) }\n ret := 1", + ), + "final pairing helper must revert on pairing failure and normalize success to one" + ); +@@ -2487,6 +2663,10 @@ + ("PrecompileFailed()", "ERR_PRECOMPILE_FAILED"), + ("ProofRejected()", "ERR_PROOF_REJECTED"), + ("QuotientProgramInvalid()", "ERR_QUOTIENT_PROGRAM_INVALID"), ++ // MF-2: the memory-layout guard reports a build fault (a recompile ++ // whose spill region reaches the generated layout), so it must be ++ // decodable rather than an anonymous empty revert. ++ ("MemoryLayoutViolated()", "ERR_MEMORY_LAYOUT_VIOLATED"), + ] { + let digest = Keccak256::digest(signature.as_bytes()); + let selector = format!( +diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +--- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol ++++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +@@ -50,7 +50,10 @@ + // verifyProof is success-or-revert; these errors let integrators and + // incident responders distinguish malformed calldata from a swapped VK, + // a non-canonical scalar, a failed precompile, or a rejected proof. +- // Constructor smoke probes intentionally keep bare reverts. ++ // Constructor smoke probes intentionally keep bare reverts -- they report ++ // a chain-capability failure, and the deployment transaction identifies ++ // itself. The one constructor exception is the memory-layout guard ++ // (MF-2), which reports a BUILD fault and is typed on both paths. + // ---------------------------------------------------------------------- + /// @notice Calldata does not match the generated ABI shape (heads, + /// lengths, instance count, or exact calldatasize). +@@ -72,6 +75,12 @@ + /// invariant (bad opcode, operand out of window, stack misuse, + /// or evaluator frame mismatch). + error QuotientProgramInvalid(); ++ /// @notice solc's stack-spill reservation overlaps the generated absolute ++ /// memory layout. This is a BUILD fault, not a proof fault: the ++ /// artifact was compiled with a (version, optimiser) pair whose ++ /// free-memory pointer starts at or above TRANSCRIPT_MPTR, so no ++ /// input can ever verify. Redeploy from the pinned toolchain. ++ error MemoryLayoutViolated(); + + {% include "partials/verifier/Constants.sol" %} + +@@ -159,7 +168,18 @@ + // reservation is compiler-version and optimiser dependent, so + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. +- if gt(mload(0x40), TRANSCRIPT_MPTR) { revert(0, 0) } ++ // ++ // MF-2: this is the only on-chain guard against a recompile that ++ // silently moves the spill region, and the failure it catches is ++ // permanent (no input can verify). `fail()` is not in scope this ++ // early, so write the MemoryLayoutViolated() selector inline ++ // rather than reverting bare -- an empty revert here is ++ // indistinguishable from every other empty revert, which is ++ // exactly the wrong signal for a build fault. ++ if gt(mload(0x40), TRANSCRIPT_MPTR) { ++ mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED)) ++ revert(0x00, 0x04) ++ } + + // This block owns the call-frame memory and remains terminal. + // Generated scratch starts at TRANSCRIPT_MPTR, preserving +diff --git a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +--- a/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul ++++ b/proofs/solidity-verifier/templates/partials/quotient_numerator/QuotientNumeratorBlock.yul +@@ -9,7 +9,10 @@ + sub(ptr, lo) > (hi - lo) cover both bounds (~6 gas per operand). + u8 constant-table indexes stay unguarded: their drift is bounded to + 0x1FE0 bytes inside the VK-reserved region and covered by build-time +- validate_quotient_const_slots. ++ validate_quotient_const_slots. MF-3: the u16 forms do NOT share that ++ argument -- an out-of-range u16 index reaches 0x1FFFE0 bytes past the ++ table, well outside the pinned payload -- so those three sites are ++ clamped against the rendered table length. + -#} + {%- macro q_ptr_guard(ptr) %} + if gt(sub({{ ptr }}, {{ program.operand_lo|hex() }}), {{ (program.operand_hi - program.operand_lo)|hex() }}) { q_program_fail() } +@@ -23,6 +26,35 @@ + {%- macro q_pop_guard() %} + if eq(q_sp, {{ program.stack_mptr|hex() }}) { q_program_fail() } + {%- endmacro %} ++{#- ++ MF-3 interpreter fail-closed guards. The program is trusted through the VK ++ codehash pin, so none of these are reachable on-chain with a well-formed ++ artifact; they are containment for a future GENERATOR bug, in the same ++ spirit as the P12 operand clamps above. Each closes a hole the terminal ++ end-of-program checks provably cannot see: ++ ++ - q_top_guard: FOLD_MAIN/FOLD_SELECTOR consume the cached top. With ++ q_has_top clear, the fold silently re-folds a STALE q_top and both ++ terminal checks (q_has_top == 0, q_sp == base) still pass. ++ - q_stack_empty_guard: native callbacks used to RESET q_sp to the base ++ rather than assert it, so operands spilled by a preceding partial ++ expression were discarded with no trace -- an identity would drop out ++ of nu_y(x) while the program still ended balanced. ++ - q_const_guard: constant-table indexes are decoded from program bytes ++ and were unclamped, so an out-of-range index reads whatever follows the ++ table (program bytes, commitments) as an Fr constant. ++ - the inlined spill-ceiling check at every push site: q_sp walks ++ upward with no ceiling of its own. ++-#} ++{%- macro q_top_guard() %} ++ if iszero(q_has_top) { q_program_fail() } ++{%- endmacro %} ++{%- macro q_stack_empty_guard() %} ++ if iszero(eq(q_sp, {{ program.stack_mptr|hex() }})) { q_program_fail() } ++{%- endmacro %} ++{%- macro q_const_guard(idx) %} ++ if iszero(lt({{ idx }}, {{ program.num_consts }})) { q_program_fail() } ++{%- endmacro %} + // =============================================================== + // Batched identity numerator / linearization target. + // +@@ -473,9 +505,11 @@ + // Fr words, so shl(5, const_idx) converts an index to + // a byte offset. + let qconst := shr(240, mload(q_pc)) ++{%- call q_const_guard("qconst") %} + // Push semantics: spill the old cached top, if any, + // then install the loaded constant as the new q_top. + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -496,6 +530,7 @@ + // Load one canonical Fr word from generated memory and + // push it through the cached-top stack discipline. + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -544,6 +579,7 @@ + // impossible for valid generated bytecode. + default { q_program_fail() } + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -595,6 +631,7 @@ + default { q_program_fail() } + {%- call q_ptr_guard("q_ptr") %} + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -612,6 +649,7 @@ + q_pc := add(q_pc, 2) + {%- call q_ptr_guard("q_ptr") %} + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -662,6 +700,7 @@ + // constant table has fewer than 256 referenced slots. + let qconst := byte(0, mload(q_pc)) + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -697,6 +736,7 @@ + // constant tables. + let qconst := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) ++{%- call q_const_guard("qconst") %} + let q_const_ptr := add(q_const_mptr, shl(5, qconst)) + {%- call q_ptr_guard("q_const_ptr") %} + q_top := addmod(q_top, mload(q_const_ptr), r) +@@ -708,6 +748,7 @@ + // Two-byte constant-index multiply. + let qconst := shr(240, mload(q_pc)) + q_pc := add(q_pc, 2) ++{%- call q_const_guard("qconst") %} + let q_const_ptr := add(q_const_mptr, shl(5, qconst)) + {%- call q_ptr_guard("q_const_ptr") %} + q_top := mulmod(q_top, mload(q_const_ptr), r) +@@ -918,6 +959,7 @@ + // u16 ptr} pairs. The result is pushed as a fresh + // stack value. + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -956,6 +998,7 @@ + {%- call q_ptr_guard("q_lhs") %} + let q_lhs_value := mload(q_lhs) + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -1003,6 +1046,7 @@ + let q_coeff_pc := q_pc + q_pc := add(q_pc, {{ template_constants.quotient_vm.limb_pairwise_coeffs }}) + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -1081,6 +1125,7 @@ + q_pc := add(q_pc, 5) + + if q_has_top { ++ if iszero(lt(q_sp, {{ program.stack_hi|hex() }})) { q_program_fail() } + mstore(q_sp, q_top) + q_sp := add(q_sp, 0x20) + } +@@ -1214,7 +1259,7 @@ + // stack. The Rust memory planner must reserve enough + // words for structured_permutation_scratch_words(meta) + // whenever this opcode can appear. +- q_sp := {{ program.stack_mptr|hex() }} ++{%- call q_stack_empty_guard() %} + // The generated lines below call the same fold snippets + // used by interpreted expressions, so trace IDs and + // y-batch positions remain contiguous. +@@ -1240,7 +1285,7 @@ + // f+beta/prefix/suffix scratch rather than as a + // conventional VM stack. The Rust memory planner must + // reserve structured_lookup_scratch_words(meta). +- q_sp := {{ program.stack_mptr|hex() }} ++{%- call q_stack_empty_guard() %} + // Generated LogUp code follows the same y-batch order + // as the Rust identity stream. + {%- for line in quotient_native_lookup_computation %} +@@ -1265,7 +1310,7 @@ + // interpreter stack before dispatching. + q_top := 0 + q_has_top := 0 +- q_sp := {{ program.stack_mptr|hex() }} ++{%- call q_stack_empty_guard() %} + // Native identity sub-cases are generated from selected heavy gate identities. + switch q_native_idx + {%- for code_block in quotient_native_identity_computations %} +@@ -1283,6 +1328,7 @@ + case {{ template_constants.quotient_vm.op.fold_main|hex() }} { + // q_top is the complete value of one fully evaluated + // identity at x. It leaves the expression stack here. ++{%- call q_top_guard() %} + let q_eval := q_top + q_has_top := 0 + {%- if self.trace %} +@@ -1312,6 +1358,7 @@ + // are codegen-known sizes, so clamp before the writes. + if iszero(lt(q_sel_idx, {{ program.num_selector_buckets }})) { q_program_fail() } + if gt(q_sel_gap, {{ program.selector_max_power|hex() }}) { q_program_fail() } ++{%- call q_top_guard() %} + let q_eval := q_top + q_has_top := 0 + {%- if self.trace %} +diff --git a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +--- a/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul ++++ b/proofs/solidity-verifier/templates/partials/verifier/AccumulatorHelpers.yul +@@ -248,7 +248,13 @@ + // carried-scalar and fixed-base-tail arms; renders whose + // accumulator layout has neither (e.g. point_pair with no tail) + // legally leave it unused. +- function validate_public_accumulator(success, r) -> out { ++ // MF-4: `precompile_failed` separates a G1MSM staticcall that ++ // could not run (chain/gas fault) from a public-input point this ++ // verifier decoded and rejected (bad packing, out-of-field ++ // coordinate, non-canonical identity encoding, or a point the ++ // precompile found off-curve/out-of-subgroup). Both fail closed at ++ // the call site; only the second is a BadPointEncoding. ++ function validate_public_accumulator(success, r) -> out, precompile_failed { + out := success + let bits := {{ self.expected_num_acc_limb_bits }} + let n := {{ self.expected_num_acc_limbs }} +@@ -303,6 +309,7 @@ + // is also a curve/subgroup validation round-trip. + out := staticcall(G1MSM_GAS_1PAIR, {{ template_constants.eip2537.g1msm_address|hex() }}, acc_scratch, {{ template_constants.g1_msm_pair_bytes|hex() }}, ACC_LHS_MPTR, {{ template_constants.g1_bytes|hex() }}) + out := and(out, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) ++ precompile_failed := iszero(out) + } + } + +@@ -418,6 +425,7 @@ + {{ template_constants.g1_bytes|hex() }} + ) + out := and(out, eq(returndatasize(), {{ template_constants.g1_bytes|hex() }})) ++ precompile_failed := iszero(out) + } + } + // The caller checks `out` and reverts before transcript work if +diff --git a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +--- a/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul ++++ b/proofs/solidity-verifier/templates/partials/verifier/AssemblyHelpers.yul +@@ -138,7 +138,16 @@ + // The function returns a boolean instead of reverting so callers + // can combine it with other `success` plumbing until a section + // boundary decides whether to fail closed. +- function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret { ++ // ++ // MF-4: the second return value separates a FAILED PRECOMPILE ++ // (staticcall reverted / OOG'd / returned the wrong size -- a ++ // chain or gas-schedule fault) from a REJECTED INPUT (a zero or ++ // non-canonical denominator, which for the Lagrange batch means ++ // the squeezed x landed on a domain point). Both fail closed at ++ // the section boundary, but they are different incidents and used ++ // to surface under the same PrecompileFailed selector, pointing ++ // responders at the node when the transcript was the cause. ++ function batch_invert(success, mptr_start, mptr_end, scratch_mptr, r) -> ret, precompile_failed { + ret := success + if iszero(ret) { leave } + // Memory ranges must be forward and word-aligned by +@@ -177,6 +186,7 @@ + mstore(add(single_scratch, {{ template_constants.modexp.mod_offset|hex() }}), r) + ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, single_scratch, {{ template_constants.modexp.frame_bytes|hex() }}, single_scratch, {{ template_constants.modexp.output_bytes|hex() }}) + ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) ++ precompile_failed := iszero(ret) + if ret { mstore(mptr_start, mload(single_scratch)) } + leave + } +@@ -227,6 +237,7 @@ + mstore(add(gp_mptr, {{ template_constants.modexp.mod_offset|hex() }}), r) + ret := staticcall(MODEXP_GAS, {{ template_constants.modexp.address|hex() }}, gp_mptr, {{ template_constants.modexp.frame_bytes|hex() }}, gp_mptr, {{ template_constants.modexp.output_bytes|hex() }}) + ret := and(ret, eq(returndatasize(), {{ template_constants.modexp.output_bytes|hex() }})) ++ precompile_failed := iszero(ret) + // Leave before the backward pass on a failed modexp. A failed + // staticcall writes no output, so `mload(gp_mptr)` would read + // back the stale frame header and the pass below would +@@ -274,13 +285,20 @@ + mcopy(add(scratch, 0x80), G2_BASE_MPTR, 0x100) + mcopy(add(scratch, 0x180), rhs_mptr, 0x80) + mcopy(add(scratch, 0x200), NEG_S_G2_BASE_MPTR, 0x100) ++ // MF-4: separate "the chain could not run the pairing" from ++ // "the pairing ran and rejected this proof". Both fail closed, ++ // but they are different incidents: the first points at the ++ // node/fork (a missing, repriced, or short-returning ++ // precompile), the second at the proof. Collapsing them into ++ // ProofRejected sent every responder looking at the wrong one. + ret := staticcall(PAIRING_GAS_2PAIR, {{ template_constants.eip2537.pairing_address|hex() }}, scratch, {{ template_constants.pairing_two_pair_bytes|hex() }}, scratch, {{ template_constants.word_bytes|hex() }}) + ret := and(ret, eq(returndatasize(), {{ template_constants.word_bytes|hex() }})) ++ if iszero(ret) { fail(ERR_PRECOMPILE_FAILED) } + // Compare against 1 rather than truncating to the low bit: + // `and(ret, word)` would accept any odd result word. EIP-2537 + // only ever returns 0 or 1, so this matches the strict form + // the constructor smoke test already uses. +- ret := and(ret, eq(mload(scratch), 1)) ++ ret := eq(mload(scratch), 1) + if iszero(ret) { fail(ERR_PROOF_REJECTED) } + ret := 1 + } +diff --git a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +--- a/proofs/solidity-verifier/templates/partials/verifier/Constants.sol ++++ b/proofs/solidity-verifier/templates/partials/verifier/Constants.sol +@@ -232,6 +232,7 @@ + uint256 internal constant ERR_PRECOMPILE_FAILED = 0x84e81692; + uint256 internal constant ERR_PROOF_REJECTED = 0xc3b0d8cd; + uint256 internal constant ERR_QUOTIENT_PROGRAM_INVALID = 0x3cc81b89; ++ uint256 internal constant ERR_MEMORY_LAYOUT_VIOLATED = 0xc9888d23; + + // BLS12-381 scalar-field modulus, used for transcript challenges and all + // Halo2 verifier arithmetic. +diff --git a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul +--- a/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul ++++ b/proofs/solidity-verifier/templates/partials/verifier/Lagrange.yul +@@ -1,6 +1,10 @@ + // =============================================================== + // Lagrange & instance-evaluation block (pure Fr arithmetic). + // =============================================================== ++ // MF-4: hoisted so the section boundary below can tell a failed ++ // modexp (chain fault) from a rejected denominator (x landed on a ++ // domain point) instead of reporting both as PrecompileFailed. ++ let lagrange_precompile_failed := 0 + { + let k := {{ k }} + let x := mload(X_MPTR) +@@ -33,7 +37,7 @@ + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) +- success := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) ++ success, lagrange_precompile_failed := batch_invert(success, LAGRANGE_DENOMS_MPTR, add(mptr_end, 0x20), BATCH_INV_SCRATCH_MPTR, r) + + // Convert inverted denominators into Lagrange evaluations: + // L_i(x) = (x^n - 1) * n^-1 * omega_i / (x - omega_i). +@@ -88,4 +92,10 @@ + gas_checkpoint(11) // after Lagrange + instance evaluation block + {%- endif %} + +- if iszero(success) { fail(ERR_PRECOMPILE_FAILED) } ++ if iszero(success) { ++ // A zero or non-canonical denominator is a rejected input, ++ // not a broken chain: the only way to reach it is a squeezed ++ // x that coincides with a domain point (probability ~n/r). ++ if lagrange_precompile_failed { fail(ERR_PRECOMPILE_FAILED) } ++ fail(ERR_PROOF_REJECTED) ++ } +diff --git a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +--- a/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol ++++ b/proofs/solidity-verifier/templates/partials/verifier/PrecompileSmoke.sol +@@ -10,7 +10,16 @@ + // Same free-memory-pointer guard as verifyProof. This body runs in + // the *creation* frame, which the generator's memoryguard test does + // not inspect (it parses the runtime prologue only). +- if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { revert(0, 0) } ++ // ++ // MF-2: typed like the runtime guard, and for a stronger reason. ++ // The runtime guard turns a bad recompile into a revert on every ++ // proof; this one turns it into a failed DEPLOYMENT, which is ++ // where a build fault belongs. The probes below keep bare reverts ++ // (a chain-capability failure, not a build fault). ++ if gt(mload(0x40), {{ memory.constructor_smoke_scratch_mptr|hex() }}) { ++ mstore(0x00, shl(224, ERR_MEMORY_LAYOUT_VIOLATED)) ++ revert(0x00, 0x04) ++ } + + // Scratch is reused for every runtime-prerequisite probe. + let scratch := {{ memory.constructor_smoke_scratch_mptr|hex() }} +diff --git a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul +--- a/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul ++++ b/proofs/solidity-verifier/templates/partials/verifier/VkLoading.yul +@@ -126,8 +126,14 @@ + // validate_public_accumulator returns a boolean to share the same + // success-plumbing style as other helper calls; this boundary is + // where the verifier converts failure to a revert. +- success := validate_public_accumulator(success, r) +- if iszero(success) { fail(ERR_BAD_POINT_ENCODING) } ++ let acc_precompile_failed := 0 ++ success, acc_precompile_failed := validate_public_accumulator(success, r) ++ if iszero(success) { ++ // MF-4: a G1MSM that could not run at all is a chain fault, ++ // not a malformed accumulator point. ++ if acc_precompile_failed { fail(ERR_PRECOMPILE_FAILED) } ++ fail(ERR_BAD_POINT_ENCODING) ++ } + {%- endif %} + + {%- if self.gas_checkpoints %} +diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs +--- a/proofs/solidity-verifier/tests/template_digest.rs ++++ b/proofs/solidity-verifier/tests/template_digest.rs +@@ -13,7 +13,7 @@ + + /// keccak over the sorted (path, length, content) stream of `templates/`. + const EXPECTED_TEMPLATE_TREE_DIGEST: &str = +- "0xfe89267c0778787678b938eb6f56f5e79f4bc11578786da45f2aad82384349d9"; ++ "0x063bb003b3f8eafacd300e1a20cb645db55832efa476689ddb83f6d781efb7dc"; + + fn collect_files(dir: &Path, files: &mut Vec) { + for entry in fs::read_dir(dir).expect("template directory is readable") { diff --git a/_to_delete/pr3.git.patch b/_to_delete/pr3.git.patch new file mode 100644 index 000000000..6407869ea --- /dev/null +++ b/_to_delete/pr3.git.patch @@ -0,0 +1,239 @@ +diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +--- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md ++++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +@@ -1423,4 +1423,51 @@ + rest are mostly edge-case, interoperability, or validation issues, but several + could still become soundness bugs in a generated verifier. + ++ ++## 2026-08-13 — independent external review (MF series) ++ ++An independent review of the rendered `moonlight-wrap` artifacts (verifier ++sha256 `555ed976…6798`, VK `7ca78ec2…b7ec`; byte-identical to ++`fixtures/moonlight-wrap/`) run as three separate passes — cryptographic ++implementation, ZK/protocol soundness, and EVM/software security — plus a ++line-by-line equivalence pass against `midfall/proofs` and machine ++recomputation of every recomputable constant. ++ ++**No soundness-relevant defect was found.** The transcript schedule is ++byte-exact against the Rust verifier, every absorbed proof point provably ++reaches a subgroup-enforcing precompile, the linearization/PCS algebra is ++exact, and the memory plan has no live overlaps. Findings are one liveness ++bug and a set of hardening/diagnostic items. ++ ++| ID | Sev | Finding | Disposition | ++| --- | --- | --- | --- | ++| MF-1 | High | `MODEXP_GAS = 1360` is the EIP-2565 price; EIP-7883 (Osaka/Fusaka) prices the same frame at 4064, so every proof reverts `PrecompileFailed` on a repriced chain — and the constructor never probed modexp, so deployment succeeded silently | **Fixed** (`modexp_gas_word_frame` takes the max over live schedules; constructor modexp known-answer probe added) | ++| MF-2 | Low | The memory-layout guard — the only on-chain check for a bad recompile — reverted bare | **Fixed** (`MemoryLayoutViolated()`, typed on the runtime and constructor paths) | ++| MF-3 | Low | Quotient VM: fold-on-empty re-folds a stale top; native callbacks reset `q_sp` instead of asserting it, hiding dropped operands; u16 const indexes unclamped; `q_sp` unbounded | **Fixed** (four guards; u8 indexes keep their documented exemption, u16 do not) | ++| MF-4 | Low | `PrecompileFailed` / `BadPointEncoding` / `ProofRejected` conflated chain faults with rejected input on three paths | **Fixed** (cause flags threaded through `batch_invert` and `validate_public_accumulator`; `ec_pairing` split; triage table in `DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §6) | ++| MF-5 | Info | A low-level `staticcall` to an address with no code returns success — a mis-wired wrapper reads it as a valid proof | **Documented** (wrapper obligation W-4) | ++| MF-6 | Info | Single-reduction `mod r` sampling bias (max point mass ≈1.36× uniform) | **Accepted**, parity with the Rust reference; already covered by §5.1's ×1.3585 factor. Regenerate in lockstep if the reference moves to 512-bit reduction | ++| MF-7 | Info | 128-bit truncated challenges cap batching soundness | **Accepted**, already recorded and signed off as §5.1 (L-10) | ++| MF-8 | Info | Set-0 has 43 eval terms but 42 commitment terms (the committed-instance column's commitment is the identity), so its eval is forced ≈0 only indirectly via x1-batching | **Documented** in the PCS emitter | ++| MF-9 | Info | The canonical identity accumulator `(O, O)` is well-formed and passes the pairing layer | **Documented** (wrapper obligation W-5) | ++| MF-10 | Info | Native-identity selector folds appeared to hardcode a `y¹` gap | **WITHDRAWN — false positive.** All three emission sites already use `selector_fold.gap_for(identity)`; the fixed `Some(1)` is confined to `native_identity_estimate_block`, a size/gas proxy for gate-selection that is never emitted, and whose doc comment explicitly warns against "fixing" it to call `gap_for` (the fold plan is derived from the selection outcome, so it does not exist yet at that point). Recorded so the warning is not overridden by a future reviewer making the same mistake. | ++| MF-11 | Info | The transcript stream is positionally framed (a point and four scalars are byte-identical) | **Accepted**; identical to §5.2 (I-5). Any future variable-length section would need explicit length tags | ++| MF-12 | Info | `assembly ("memory-safe")` is unsound by the letter of the annotation | **Accepted**; safe here via the terminal block + FMP guard + pinned pragma, now noted at the annotation site | ++ ++Also proposed by the review and **withdrawn on inspection**: a CI job ++recomputing `vk_digest` from the rendered VK payload. The payload word is ++written directly from `self.vk.transcript_repr()` in `lowering/vk.rs` — a ++single expression over a single in-memory VK, not two independent paths — so ++such a test would assert `x == x`. The residual it was meant to close (that ++`vk_digest` binds the *semantic* constraint system) is not reachable this way; ++it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. ++See §5.3 for the standing M-4 decision. ++ ++**Not closed by these commits:** the committed fixtures and the Sepolia ++deployment predate the MF-1 fix and are marked STALE; regeneration needs the ++pinned solc. The replay harness also cannot exercise EIP-7883 — the pinned ++revm 19 has an Osaka spec, but its modexp handler is still `berlin_run` — so ++real coverage awaits a revm bump; `src/evm.rs` records that gap at the ++`SpecId` pin. ++ + [1]: https://eips.ethereum.org/EIPS/eip-2537 "EIP-2537: Precompile for BLS12-381 curve operations" +diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +--- a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md ++++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +@@ -38,6 +38,24 @@ + root). Without this, any accepted proof can be replayed on every chain + and against every deployment of the same bytecode. + ++- **W-4 — Call it so a wrong address cannot read as success (MF-5).** A ++ low-level `verifier.staticcall(...)` returns `ok = true` with empty ++ returndata when the target has **no code** — a wrong address, a wrong ++ chain, or a wrapper configured before deployment reads as a valid proof. ++ Call through the typed interface (Solidity ≥0.8 inserts the `extcodesize` ++ check), or, on any low-level path, require `returndatasize() >= 32` AND a ++ decoded `true`. If the wrapper uses `try/catch`, every catch branch is a ++ rejection: the verifier's failures are custom errors, so `catch Error(string)` ++ and `catch Panic(uint)` will not match them — use `catch (bytes memory)` or a ++ bare `catch`. ++- **W-5 — Bind the accumulator's meaning, not just its validity (MF-9).** For ++ IVC renders, the verifier checks that the carried accumulator points decode ++ canonically, are in the subgroup, and satisfy the batched pairing equation. ++ It does NOT check that they are non-trivial or that they continue *your* ++ chain: the canonical identity encoding `(O, O)` is a well-formed accumulator ++ and passes by construction. Any "this accumulator continues the expected ++ fold" rule belongs to the circuit or the wrapper. ++ + `verifyProof`'s NatSpec states the same split: the raw verifier checks the + proof against the pinned VK and nothing else. + +@@ -80,11 +98,27 @@ + 6. **Retire** the old verifier in the deployment record (it cannot be + destroyed on-chain); wrappers must never point back at it. + +-**Upstream repricing note:** the verifier forwards exact EIP-2537/EIP-2565 +-scheduled gas. A fork that reprices those precompiles upward bricks +-`verifyProof` (liveness, not soundness) and deployment of new artifacts +-fails fast in the constructor probes. The migration path is the same +-re-render + wrapper switch. ++**On a fork of the chain you are deployed to — check this first (MF-1).** ++The verifier forwards exact scheduled gas to every precompile, so an upward ++repricing does not degrade: it bricks `verifyProof` outright (liveness, never ++soundness). The canonical symptom is a **sudden, total `PrecompileFailed` ++rate immediately after a fork activation**, on proofs that verified the day ++before and still verify against the native Rust verifier. Triage: ++ ++1. Compare the fork's precompile schedule against the deployed constants ++ (`G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, `MODEXP_GAS`). ++2. If any scheduled cost now exceeds the deployed bound, that is the cause; ++ re-render (the generator takes the maximum over live schedules) and ++ migrate per the steps above. There is no wrapper-side mitigation. ++ ++Worked example: EIP-7883 (Fusaka) removed the `/ 3` divisor from modexp ++pricing, taking the verifier's frame from 1360 to 4064 gas. Artifacts ++rendered before that fix carry `MODEXP_GAS = 1360` and revert every proof on ++any post-Fusaka chain — including the pre-fix `deployments/sepolia/` ++moonlight-wrap deployment, which should be assumed bricked and confirmed with ++a single `eth_call` before it is retired in the deployment record. Deployment ++of NEW artifacts now fails fast in the constructor probes for every ++precompile the runtime calls, modexp included. + + ## 5. Accepted risks (deployment owner sign-off) + +@@ -139,3 +173,30 @@ + (which does cover all of the above, off-transcript). Widening the digest is + a prover-affecting protocol change, explicitly out of scope by owner + decision (2026-08-13). ++ ++## 6. Reading a revert (MF-4) ++ ++`verifyProof` is success-or-revert: it returns `true` or reverts with one of ++the typed errors below. The taxonomy exists so the first question during an ++incident — *is this the chain, the build, or the proof?* — is answerable from ++the 4-byte selector alone, without a trace. ++ ++| Error | Selector | Class | First thing to check | ++| --- | --- | --- | --- | ++| `BadCalldataShape()` | `0x1b99e37c` | Caller | Heads, lengths, and EXACT `calldatasize`. A calldata-appending relayer (ERC-2771, multicall, paymaster) cannot call this contract directly. | ++| `VkMismatch()` | `0xa447d73e` | Deployment | The pinned VK address no longer has the expected runtime length/codehash, or a VK header word disagrees with the generated constants. | ++| `NonCanonicalScalar()` | `0x77530042` | Proof | A public instance or proof scalar is `>= r`. Usually an off-chain repacking bug, not an attack. | ++| `BadPointEncoding()` | `0xf27905ec` | Proof | A proof point violates the EIP-2537 padding/field bounds, or an accumulator public input failed canonical decoding. | ++| `PrecompileFailed()` | `0x84e81692` | **Chain** | A precompile could not run: missing, repriced above the forwarded bound (see §4), or short-returning. Also raised when G1MSM *rejects* a proof point as off-curve/out-of-subgroup — the precompile is the validator, so that rejection surfaces here by design. | ++| `ProofRejected()` | `0xc3b0d8cd` | Proof | The pairing ran and returned != 1, or a Lagrange denominator was zero (the squeezed `x` hit a domain point, probability ~n/r). | ++| `QuotientProgramInvalid()` | `0x3cc81b89` | **Build** | The VK-pinned quotient program violated a structural invariant. Not reachable with a well-formed artifact; treat as a generator bug. | ++| `MemoryLayoutViolated()` | `0xc9888d23` | **Build** | solc's stack-spill reservation overlaps the generated layout. The artifact was compiled off the pinned toolchain and can never verify anything; redeploy from the pinned `(version, --optimize-runs)` pair. | ++ ++Two rules of thumb: ++ ++- **Chain/Build classes are total, not probabilistic.** They fail every call, ++ including calls that verified yesterday. A sudden all-or-nothing failure ++ rate points here; a per-proof failure rate points at the Proof class. ++- **A revert is never an accept.** Every path above fails closed. There is no ++ configuration in which `verifyProof` returns `false` — see W-4 for why a ++ wrapper must not treat a bare `staticcall` success as verification. +diff --git a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +--- a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md ++++ b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +@@ -1574,9 +1574,14 @@ + The generated verifier constructor runs smoke tests: + + - `MCOPY` one-word round trip in constructor scratch. +-- `G1ADD(identity, identity) -> identity`. ++- `modexp(2, r-2, r) == 2^-1`, checked as `mulmod(result, 2, r) == 1`, at the ++ pinned `MODEXP_GAS` bound (MF-1). ++- `G1ADD(identity, identity) -> identity`, and the known answer `G1ADD(G, G) == 2G`. ++- `G1MSM([2]*G) == 2G`, and a **negative** probe: a point on the curve but ++ outside the r-order subgroup must be rejected. + - Largest generated `G1MSM` input with identity/zero terms -> identity. +-- `PAIRING_CHECK` over two identity `(G1, G2)` pairs -> true. ++- `PAIRING_CHECK` over two identity `(G1, G2)` pairs -> true, plus the known ++ answers `e(G,G2)e(-G,G2) == 1` and `e(G,G2)e(G,G2) != 1`. + + Deploy only on forks/chains where EIP-2537 and `MCOPY` are available with the + exact addresses, encodings, subgroup checks, return-size behavior, and enough +@@ -1591,9 +1596,15 @@ + - Exact return-data size. + - For pairing, returned word is 1. + +-EIP-2537 and modexp calls forward the exact EIP-2537/EIP-2565 scheduled cost +-(generated constants `G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, +-`MODEXP_GAS`; model in `src/lowering/layout/mod.rs::gas`), NOT `gas()`. A ++EIP-2537 and modexp calls forward exact scheduled costs (generated constants ++`G1ADD_GAS`, `G1MSM_GAS_*`, `PAIRING_GAS_2PAIR`, `MODEXP_GAS`; model in ++`src/lowering/layout/mod.rs::gas`), NOT `gas()`. For modexp the rendered bound ++is the MAXIMUM over the live schedules -- EIP-2565 prices the verifier's ++32/32/32 frame at 1360, EIP-7883 (Osaka/Fusaka) removes the `/ 3` divisor and ++prices it at 4080 -- because a bound below the chain's price does not degrade ++gracefully: the fixed-gas `staticcall` runs the precompile out of gas and every ++proof reverts `PrecompileFailed` (MF-1). Over-forwarding on a pre-Osaka chain ++costs nothing on success; unused gas is returned. A + rejecting precompile consumes everything forwarded to it, so exact bounds cap + what a malformed proof point can burn at the scheduled cost of the single + failing call instead of 63/64 of the transaction budget (M-2). The bounds are +diff --git a/proofs/solidity-verifier/src/lowering/kzg/mod.rs b/proofs/solidity-verifier/src/lowering/kzg/mod.rs +--- a/proofs/solidity-verifier/src/lowering/kzg/mod.rs ++++ b/proofs/solidity-verifier/src/lowering/kzg/mod.rs +@@ -109,6 +109,17 @@ + // as 128 zero bytes). Pin that justification here, where each query + // still knows its provenance: any other query source acquiring the + // identity pointer would make the emitters drop a real MSM term. ++ // ++ // MF-8: the visible consequence downstream is a set whose eval-term count ++ // exceeds its commitment-term count by one (e.g. `q_eval_set[0]: 43 ++ // evaluation term(s), 42 commitment term(s)` in the IVC render). That is ++ // not an off-by-one. The omitted commitment is the identity, so the ++ // multi-open equation still holds exactly -- and the omission is what ++ // FORCES the committed-instance eval to zero: the eval stays in the ++ // batched claim with coefficient trunc(x1^i) while contributing nothing ++ // to the commitment side, so any nonzero value breaks the opening. The ++ // enforcement is therefore indirect (via batching, per-term error ++ // 2^-128), not an equality check anywhere in the verifier. + let g1_identity = EcPoint::new(Ptr::memory("G1_IDENTITY_MPTR")); + for (source, query) in meta.protocol.pcs_queries.iter().zip(&queries) { + assert!( +diff --git a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +--- a/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol ++++ b/proofs/solidity-verifier/templates/contracts/Halo2Verifier.sol +@@ -169,6 +169,16 @@ + // assert the invariant in the deployed bytecode instead of relying + // on a generator-side test the integrator never runs. ~6 gas. + // ++ // MF-12: by the letter of Solidity's memory-safety contract this ++ // annotation is a lie -- the block writes memory it never ++ // allocated through the free-memory pointer. Three properties ++ // make it safe HERE, and all three must hold together: this ++ // block is terminal (no Solidity executes after it), the pragma ++ // is pinned so codegen cannot shift underneath it, and the guard ++ // below fails closed if the spill reservation ever reaches the ++ // generated layout. Lifting this body into a non-terminal ++ // context, or unpinning the pragma, invalidates the annotation. ++ // + // MF-2: this is the only on-chain guard against a recompile that + // silently moves the spill region, and the failure it catches is + // permanent (no input can verify). `fail()` is not in scope this +diff --git a/proofs/solidity-verifier/tests/template_digest.rs b/proofs/solidity-verifier/tests/template_digest.rs +--- a/proofs/solidity-verifier/tests/template_digest.rs ++++ b/proofs/solidity-verifier/tests/template_digest.rs +@@ -13,7 +13,7 @@ + + /// keccak over the sorted (path, length, content) stream of `templates/`. + const EXPECTED_TEMPLATE_TREE_DIGEST: &str = +- "0x063bb003b3f8eafacd300e1a20cb645db55832efa476689ddb83f6d781efb7dc"; ++ "0x07b952304f2e76417023f215b63e13226ec63c14928e4cfee3312ee8fc3913f7"; + + fn collect_files(dir: &Path, files: &mut Vec) { + for entry in fs::read_dir(dir).expect("template directory is readable") { diff --git a/_to_delete/pr4.git.patch b/_to_delete/pr4.git.patch new file mode 100644 index 000000000..d4aa21dd1 --- /dev/null +++ b/_to_delete/pr4.git.patch @@ -0,0 +1,130 @@ +diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +--- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md ++++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +@@ -1463,11 +1463,29 @@ + it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. + See §5.3 for the standing M-4 decision. + ++**Verification.** The full EVM-gated suite runs green against these changes: ++217 passed / 0 failed under `--features evm,rust-verifier-trace`, including ++native-Rust-vs-Solidity trace equivalence, the constructor precompile-rejection ++tests, `typed_errors_identify_rejection_classes`, and ++`compiled_verifier_runtime_fits_the_eip170_limit` — so the added probe and ++guards do not breach the code-size limit. The MF-4 Lagrange re-route is ++observed executing rather than merely pinned in template text: the ++forced-domain-root verifier reverts with `ProofRejected()`. ++ ++Caveat on the compiler: the pinned NATIVE solc binary was not reachable from ++the environment that applied these fixes, so the suite ran against the same ++compiler commit built to WASM (npm `solc` 0.8.30, reporting ++`0.8.30+commit.73712a01`) behind a shim exposing the native CLI surface. That ++is sound for exercising behaviour, but this repository's reproducibility claim ++pins the native binary's sha256 — so nothing produced that way may be deployed ++or used to pin a hash, and the code-size result should be re-confirmed with the ++pinned binary before release. ++ + **Not closed by these commits:** the committed fixtures and the Sepolia +-deployment predate the MF-1 fix and are marked STALE; regeneration needs the +-pinned solc. The replay harness also cannot exercise EIP-7883 — the pinned +-revm 19 has an Osaka spec, but its modexp handler is still `berlin_run` — so +-real coverage awaits a revm bump; `src/evm.rs` records that gap at the +-`SpecId` pin. ++deployment predate the MF-1 fix and are marked STALE; regenerating them needs ++the SRS asset (unreachable here) and, for moonlight-wrap, a Moonlight checkout. ++The replay harness also cannot exercise EIP-7883 — the pinned revm 19 has an ++Osaka spec, but its modexp handler is still `berlin_run` — so real coverage ++awaits a revm bump; `src/evm.rs` records that gap at the `SpecId` pin. + + [1]: https://eips.ethereum.org/EIPS/eip-2537 "EIP-2537: Precompile for BLS12-381 curve operations" +diff --git a/proofs/solidity-verifier/fixtures/ivc/README.md b/proofs/solidity-verifier/fixtures/ivc/README.md +--- a/proofs/solidity-verifier/fixtures/ivc/README.md ++++ b/proofs/solidity-verifier/fixtures/ivc/README.md +@@ -7,8 +7,9 @@ + > inputs for the *replay* tests, which exercise verification logic rather than + > the modexp bound, but they must be regenerated (and their provenance rows + > below updated) on a host with the pinned solc before they are used as a +-> deployment source. Regeneration needs solc, which the environment that +-> applied the MF-1 fix did not have. ++> deployment source. Regeneration needs the SRS asset ++> (`zk_stdlib/examples/assets/bls_filecoin_2p19`) and a full proving run, which ++> the environment that applied the MF-1 fix could not reach. + + Pre-rendered artifacts for `tests/ivc_accumulator_replay.rs`, which replays a + real IVC final proof and then mutates the accumulator public inputs to check the +diff --git a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +--- a/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md ++++ b/proofs/solidity-verifier/fixtures/moonlight-wrap/README.md +@@ -7,8 +7,9 @@ + > inputs for the *replay* tests, which exercise verification logic rather than + > the modexp bound, but they must be regenerated (and their provenance rows + > below updated) on a host with the pinned solc before they are used as a +-> deployment source. Regeneration needs solc, which the environment that +-> applied the MF-1 fix did not have. ++> deployment source. Regeneration needs a Moonlight checkout on the branch named ++> below plus the SRS asset, neither of which the environment that applied the ++> MF-1 fix could reach. + + Pre-rendered artifacts for the `point_pair` accumulator arm of + `tests/ivc_accumulator_replay.rs`. The IVC fixture next door covers +diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs +--- a/proofs/solidity-verifier/src/test.rs ++++ b/proofs/solidity-verifier/src/test.rs +@@ -1554,8 +1554,9 @@ + pragma solidity ^0.8.24; + + contract BatchInvertHarness {{ +- // The extracted helper forwards the exact EIP-2565 modexp cost; mirror +- // the generated constant it references. ++ // The extracted helper forwards the pinned modexp bound (the maximum over ++ // the EIP-2565 and EIP-7883 schedules, MF-1); mirror the generated ++ // constant it references. + uint256 internal constant MODEXP_GAS = {modexp_gas}; + + fallback() external {{ +@@ -1566,8 +1567,14 @@ + let r := calldataload(0x20) + let base := 0x1000 + calldatacopy(base, 0x40, mul(n, 0x20)) +- let ok := batch_invert(1, base, add(base, mul(n, 0x20)), 0x8000, r) ++ // MF-4: batch_invert now also reports WHY it failed (a failed ++ // modexp staticcall vs a rejected denominator). This harness only ++ // asserts fail-closed behaviour, so it keeps the boolean and ++ // discards the cause -- but it must still destructure both values ++ // or the extracted helper does not compile. ++ let ok, precompile_failed := batch_invert(1, base, add(base, mul(n, 0x20)), 0x8000, r) + mstore(0x80, ok) ++ pop(precompile_failed) + mcopy(0xa0, base, mul(n, 0x20)) + return(0x80, add(0x20, mul(n, 0x20))) + }} +@@ -2868,6 +2875,30 @@ + call_deployed_verifier(&mut evm, &fixture.proof, &fixture.instances), + "verifier with x forced to domain root should hit zero Lagrange denominator", + ); ++ ++ // MF-4: pin WHICH rejection this is, not just that it rejects. A zero ++ // Lagrange denominator means the squeezed x coincided with a domain point ++ // -- a transcript event, so ProofRejected. It used to surface as ++ // PrecompileFailed, which sends an incident responder to inspect the node ++ // when the proof was the cause. This is the only live path that reaches ++ // that branch, so without this assertion the split is pinned in template ++ // text but never observed executing. ++ let selector = { ++ use sha3::{Digest, Keccak256}; ++ let d = Keccak256::digest(b"ProofRejected()"); ++ vec![d[0], d[1], d[2], d[3]] ++ }; ++ match evm.evm.try_call_with_gas( ++ evm.verifier_address, ++ encode_calldata(&fixture.proof, &fixture.instances), ++ 30_000_000, ++ ) { ++ CallOutcome::Revert { output, .. } => assert_eq!( ++ output, selector, ++ "a zero Lagrange denominator must report ProofRejected, not a precompile fault" ++ ), ++ outcome => panic!("forced-domain-root verifier did not revert: {outcome:?}"), ++ } + } + + #[test] diff --git a/_to_delete/pr5.git.patch b/_to_delete/pr5.git.patch new file mode 100644 index 000000000..f56377a3d --- /dev/null +++ b/_to_delete/pr5.git.patch @@ -0,0 +1,100 @@ +diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +--- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md ++++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +@@ -1464,7 +1464,7 @@ + See §5.3 for the standing M-4 decision. + + **Verification.** The full EVM-gated suite runs green against these changes: +-217 passed / 0 failed under `--features evm,rust-verifier-trace`, including ++218 passed / 0 failed under `--features evm,rust-verifier-trace`, including + native-Rust-vs-Solidity trace equivalence, the constructor precompile-rejection + tests, `typed_errors_identify_rejection_classes`, and + `compiled_verifier_runtime_fits_the_eip170_limit` — so the added probe and +@@ -1472,6 +1472,15 @@ + observed executing rather than merely pinned in template text: the + forced-domain-root verifier reverts with `ProofRejected()`. + ++MF-1's probe is likewise demonstrated rather than asserted. ++`constructor_rejects_a_modexp_bound_below_the_chain_price` renders the verifier, ++lowers `MODEXP_GAS` to one gas below what this harness's revm charges for the ++frame, and requires DEPLOYMENT to fail -- with a positive control deploying the ++same fixture unmutated, so the rejection cannot pass vacuously. That is the ++exact shape of the original bug (the shipped 1360 sat below EIP-7883's 4064), ++reproduced by moving the bound rather than the schedule, because the pinned ++revm 19 exposes `SpecId::OSAKA` but still prices modexp with `berlin_run`. ++ + Caveat on the compiler: the pinned NATIVE solc binary was not reachable from + the environment that applied these fixes, so the suite ran against the same + compiler commit built to WASM (npm `solc` 0.8.30, reporting +diff --git a/proofs/solidity-verifier/src/test.rs b/proofs/solidity-verifier/src/test.rs +--- a/proofs/solidity-verifier/src/test.rs ++++ b/proofs/solidity-verifier/src/test.rs +@@ -1727,6 +1727,68 @@ + } + } + ++/// MF-1: the constructor's modexp probe must actually REJECT a bound below the ++/// chain's price, not merely be present in the rendered source. ++/// ++/// This is the property the whole MF-1 fix rests on. A `staticcall` forwards a ++/// fixed amount, so an under-priced `MODEXP_GAS` does not degrade -- the ++/// precompile runs out of gas and every proof reverts. Before the fix there was ++/// no modexp probe at all, so such an artifact DEPLOYED CLEANLY and only failed ++/// on first use; the probe exists to turn that into a failed deployment. ++/// ++/// The mutation lowers the bound to one gas below the EIP-2565 price this ++/// harness's revm charges (1354), which is exactly the shape of the real bug: ++/// the shipped 1360 sat below the EIP-7883 price of 4064. It cannot be tested ++/// by repricing revm instead -- the pinned revm 19 exposes `SpecId::OSAKA` but ++/// still prices modexp with `berlin_run` -- so the bound is moved rather than ++/// the schedule. Positive control: every other EVM test in this file deploys ++/// the same fixture unmutated. ++#[test] ++fn constructor_rejects_a_modexp_bound_below_the_chain_price() { ++ if !poseidon_inputs_available_for_evm() { ++ return; ++ } ++ ++ let rendered_bound = crate::lowering::layout::gas::modexp_gas_word_frame(); ++ let needle = format!("MODEXP_GAS = {rendered_bound};"); ++ // One gas below what revm's Berlin/EIP-2565 modexp charges for the ++ // verifier's 32/32/32 frame with a 255-bit exponent: max(200, 16*254/3). ++ let underpriced = (16 * 254 / 3) - 1; ++ ++ let fixture = create_property_poseidon_fixture(); ++ let verifier_solidity = { ++ assert!( ++ fixture.quotient_verifier_solidity.contains(&needle), ++ "rendered verifier should pin the generated modexp bound ({needle})" ++ ); ++ fixture.quotient_verifier_solidity.replacen( ++ &needle, ++ &format!("MODEXP_GAS = {underpriced};"), ++ 1, ++ ) ++ }; ++ ++ assert_pinned_quotient_constructor_rejects( ++ &verifier_solidity, ++ &fixture.vk_solidity, ++ &fixture.quotient_evaluator_solidity, ++ "modexp bound below the chain's price", ++ ); ++ ++ // Positive control, so the assertion above cannot pass vacuously: the same ++ // fixture, same compiler, same EVM, differing ONLY in that constant must ++ // construct successfully. Without this, a rejection caused by anything ++ // else in the pipeline would read as the probe working. ++ let mut evm = Evm::default(); ++ let vk_address = evm.create(compile_solidity(&fixture.vk_solidity)); ++ let quotient_address = evm.create(compile_solidity(&fixture.quotient_evaluator_solidity)); ++ evm.create_with_two_address_args( ++ compile_solidity(&fixture.quotient_verifier_solidity), ++ vk_address, ++ quotient_address, ++ ); ++} ++ + #[test] + fn production_renders_do_not_emit_gas_checkpoints() { + // The fixture's base variants follow `RenderDiagnostics::default()`, so a diff --git a/_to_delete/pr6.git.patch b/_to_delete/pr6.git.patch new file mode 100644 index 000000000..d0b72cfc4 --- /dev/null +++ b/_to_delete/pr6.git.patch @@ -0,0 +1,82 @@ +diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +--- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md ++++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +@@ -1487,12 +1487,32 @@ + `0.8.30+commit.73712a01`) behind a shim exposing the native CLI surface. That + is sound for exercising behaviour, but this repository's reproducibility claim + pins the native binary's sha256 — so nothing produced that way may be deployed +-or used to pin a hash, and the code-size result should be re-confirmed with the +-pinned binary before release. ++or used to pin a hash. + +-**Not closed by these commits:** the committed fixtures and the Sepolia +-deployment predate the MF-1 fix and are marked STALE; regenerating them needs +-the SRS asset (unreachable here) and, for moonlight-wrap, a Moonlight checkout. ++The two builds were then compared directly, which upgrades that caveat from an ++assumption to a measurement: recompiling `deployments/sepolia/moonlight-wrap/ ++Halo2Verifier.sol` (a 21,161-byte via-IR runtime, at the `deployment.json` ++settings) through the WASM build reproduces the committed native-compiled ++runtime with exactly 40 differing bytes — the two 20-byte immutable ++`AUTHORIZED_VK` slots, which a fresh compile leaves zeroed. All 21,121 other ++bytes match. So the code-size result carries native weight; re-confirming it on ++a pinned-binary host remains good release hygiene rather than an open risk. ++ ++**Correction to an earlier claim in this section's history.** The MF-1 commit ++message and an earlier revision of `DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §4 ++stated that the `deployments/sepolia/moonlight-wrap` deployment should be ++assumed bricked post-Fusaka. That is wrong, and the assumption behind it was ++wrong: that deployment predates the exact-gas hardening, so all 17 of its ++`staticcall`s — the three modexp sites included — forward `gas()`, and an ++upward repricing is absorbed rather than fatal. Only artifacts carrying exact ++bounds are exposed, which is the population MF-1 addresses. Verified by ++reading the recorded source (its recompiled runtime reproduces ++`deployment.json`'s `runtimeCodeHash` byte-for-byte apart from the two ++immutable `AUTHORIZED_VK` slots), so no `eth_call` is needed to settle it. ++ ++**Not closed by these commits:** the committed fixtures predate the MF-1 fix ++and are marked STALE; regenerating them needs the SRS asset (unreachable here) ++and, for moonlight-wrap, a Moonlight checkout. + The replay harness also cannot exercise EIP-7883 — the pinned revm 19 has an + Osaka spec, but its modexp handler is still `berlin_run` — so real coverage + awaits a revm bump; `src/evm.rs` records that gap at the `SpecId` pin. +diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +--- a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md ++++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +@@ -111,14 +111,29 @@ + re-render (the generator takes the maximum over live schedules) and + migrate per the steps above. There is no wrapper-side mitigation. + +-Worked example: EIP-7883 (Fusaka) removed the `/ 3` divisor from modexp +-pricing, taking the verifier's frame from 1360 to 4064 gas. Artifacts +-rendered before that fix carry `MODEXP_GAS = 1360` and revert every proof on +-any post-Fusaka chain — including the pre-fix `deployments/sepolia/` +-moonlight-wrap deployment, which should be assumed bricked and confirmed with +-a single `eth_call` before it is retired in the deployment record. Deployment +-of NEW artifacts now fails fast in the constructor probes for every +-precompile the runtime calls, modexp included. ++Worked example: EIP-7883 (Fusaka, mainnet 2025-12-03, testnets earlier) ++removed the `/ 3` divisor from modexp pricing, taking the verifier's frame ++from 1360 to 4064 gas. An artifact rendered with exact bounds but before the ++MF-1 fix carries `MODEXP_GAS = 1360` and reverts every proof on any ++post-Fusaka chain. Deployment of NEW artifacts now fails fast in the ++constructor probes for every precompile the runtime calls, modexp included. ++ ++**The exposure is exactly the artifacts that carry exact bounds.** Note what ++that implies for `deployments/sepolia/moonlight-wrap`: it is NOT affected. It ++predates the exact-gas hardening entirely — all 17 of its `staticcall`s ++forward `gas()`, including its three modexp sites — so a repricing is simply ++absorbed from the caller's remaining gas. (Verified by reading the recorded ++source, whose recompiled runtime matches `runtimeCodeHash` in ++`deployment.json` byte-for-byte apart from the two immutable `AUTHORIZED_VK` ++slots, so the recorded source is genuinely what is deployed.) ++ ++That is the trade-off worth stating plainly, because it is easy to get ++backwards: **exact-gas forwarding is what creates repricing fragility.** The ++older `gas()`-forwarding renders survive any upward repricing but are exposed ++to the DoS that exact bounds were introduced to close (M-2) — a malformed ++proof point burns 63/64 of the transaction budget instead of one scheduled ++call. Neither property is free; the constructor probes exist so the fragility ++the current design accepts is caught at deployment rather than in production. + + ## 5. Accepted risks (deployment owner sign-off) + From dc70d6f8b4ced47342a40f455a3d85067222abbd Mon Sep 17 00:00:00 2001 From: Julien Coolen Date: Fri, 14 Aug 2026 08:42:13 +0000 Subject: [PATCH 108/108] docs(solidity-verifier): remove the truncated-challenge security-parameter analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the 2^108 grinding figure and everything reporting it, at the maintainer's request: * DEPLOYMENT_AND_INCIDENT_RESPONSE.md §5.1, the accepted-risk record with its per-attempt probabilities, target level, and sign-off line. The surviving §5.2/§5.3 are renumbered to §5.1/§5.2 so no gap advertises the removal, and the two in-repo cross-references (AUDIT_FINDINGS.md, the spec's transcript section) are repointed to match. * HALO2_VERIFIER_REVIEW_2026-08.md: the L-10 finding, its summary-table row, and recommendation 4.3.6. * FIXES_APPLIED_2026-08.md: the L-10 open-item row and the two references that carried the residual figures. * AUDIT_FINDINGS.md: the MF-6 and MF-7 dispositions no longer cite the removed section. MF-7 keeps the substantive reason the profile is accepted -- it mirrors the midnight-proofs prover, so a verifier-side change alone is impossible -- which does not depend on the figure. The mechanism itself is untouched and still fully specified: the spec continues to define the 128-bit mask on x3 and the truncated x1/x4 powers (§7 step 23, §12, and the reimplementation checklist), and the `truncated-challenges` feature comment in Cargo.toml still warns that prover and verifier must agree. What is gone is the quantification of what the mask costs, not the description of what it does. Two consequences worth stating plainly, since this is an audit trail: * No document now records that truncation was analysed or signed off. A future deployment owner reading §5 sees two accepted risks where there were three, with nothing indicating a third was assessed and removed. * AUDIT.md's mod-r sampling-bias derivation (the 1.3585 factor) is left intact. It is a separate Informational finding about challenge sampling and mentions truncation only in passing, without any soundness figure. Verified: cargo test --lib (174) and --test template_digest still green; every §5.x cross-reference in the repository resolves to an existing heading. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LkVhkWAGsAV72XGvp9wRMJ --- .../docs/audit/AUDIT_FINDINGS.md | 8 ++-- .../docs/audit/FIXES_APPLIED_2026-08.md | 12 +++--- .../audit/HALO2_VERIFIER_REVIEW_2026-08.md | 34 ----------------- .../DEPLOYMENT_AND_INCIDENT_RESPONSE.md | 38 ++----------------- .../reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md | 2 +- 5 files changed, 13 insertions(+), 81 deletions(-) diff --git a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md index d8c0733c2..13603b895 100644 --- a/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md +++ b/proofs/solidity-verifier/docs/audit/AUDIT_FINDINGS.md @@ -1446,12 +1446,12 @@ bug and a set of hardening/diagnostic items. | MF-3 | Low | Quotient VM: fold-on-empty re-folds a stale top; native callbacks reset `q_sp` instead of asserting it, hiding dropped operands; u16 const indexes unclamped; `q_sp` unbounded | **Fixed** (four guards; u8 indexes keep their documented exemption, u16 do not) | | MF-4 | Low | `PrecompileFailed` / `BadPointEncoding` / `ProofRejected` conflated chain faults with rejected input on three paths | **Fixed** (cause flags threaded through `batch_invert` and `validate_public_accumulator`; `ec_pairing` split; triage table in `DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §6) | | MF-5 | Info | A low-level `staticcall` to an address with no code returns success — a mis-wired wrapper reads it as a valid proof | **Documented** (wrapper obligation W-4) | -| MF-6 | Info | Single-reduction `mod r` sampling bias (max point mass ≈1.36× uniform) | **Accepted**, parity with the Rust reference; already covered by §5.1's ×1.3585 factor. Regenerate in lockstep if the reference moves to 512-bit reduction | -| MF-7 | Info | 128-bit truncated challenges cap batching soundness | **Accepted**, already recorded and signed off as §5.1 (L-10) | +| MF-6 | Info | Single-reduction `mod r` sampling bias (max point mass ≈1.36× uniform) | **Accepted**, parity with the Rust reference; the sampling-bias factor is derived in `AUDIT.md`. Regenerate in lockstep if the reference moves to 512-bit reduction | +| MF-7 | Info | 128-bit truncated challenges cap batching soundness | **Accepted**: the profile mirrors the midnight-proofs prover, so a verifier-side change alone is impossible | | MF-8 | Info | Set-0 has 43 eval terms but 42 commitment terms (the committed-instance column's commitment is the identity), so its eval is forced ≈0 only indirectly via x1-batching | **Documented** in the PCS emitter | | MF-9 | Info | The canonical identity accumulator `(O, O)` is well-formed and passes the pairing layer | **Documented** (wrapper obligation W-5) | | MF-10 | Info | Native-identity selector folds appeared to hardcode a `y¹` gap | **WITHDRAWN — false positive.** All three emission sites already use `selector_fold.gap_for(identity)`; the fixed `Some(1)` is confined to `native_identity_estimate_block`, a size/gas proxy for gate-selection that is never emitted, and whose doc comment explicitly warns against "fixing" it to call `gap_for` (the fold plan is derived from the selection outcome, so it does not exist yet at that point). Recorded so the warning is not overridden by a future reviewer making the same mistake. | -| MF-11 | Info | The transcript stream is positionally framed (a point and four scalars are byte-identical) | **Accepted**; identical to §5.2 (I-5). Any future variable-length section would need explicit length tags | +| MF-11 | Info | The transcript stream is positionally framed (a point and four scalars are byte-identical) | **Accepted**; identical to §5.1 (I-5). Any future variable-length section would need explicit length tags | | MF-12 | Info | `assembly ("memory-safe")` is unsound by the letter of the annotation | **Accepted**; safe here via the terminal block + FMP guard + pinned pragma, now noted at the annotation site | Also proposed by the review and **withdrawn on inspection**: a CI job @@ -1461,7 +1461,7 @@ single expression over a single in-memory VK, not two independent paths — so such a test would assert `x == x`. The residual it was meant to close (that `vk_digest` binds the *semantic* constraint system) is not reachable this way; it is covered by the trace-replay tests and, off-transcript, by `BUILD_ID`. -See §5.3 for the standing M-4 decision. +See §5.2 for the standing M-4 decision. **Verification.** The full EVM-gated suite runs green against these changes: 218 passed / 0 failed under `--features evm,rust-verifier-trace`, including diff --git a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md index db0cd1811..aae9060f8 100644 --- a/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md +++ b/proofs/solidity-verifier/docs/audit/FIXES_APPLIED_2026-08.md @@ -104,7 +104,7 @@ end-to-end and all fixture tests pass in both modes. The committed Deliberately not addressed, by explicit decision: **M-4** (`vk_digest` coverage — protocol change affecting the prover) and anything outside `proofs/solidity-verifier/`. Remaining open from the tables below: P4, P8, -P9, P10, P12, P14, L-4, L-9, L-10, I-6, I-7. +P9, P10, P12, P14, L-4, L-9, I-6, I-7. ## 2026-08-13 follow-up: Low/Informational batch closed @@ -144,12 +144,11 @@ The remaining P-series patches and L/I findings were applied in a third pass `templates/` tree in default CI, closing the committed-fixture drift gap. The deeper L-1 legs (expression front-end certification, native-kernel differential) remain future work. -- **L-9 / L-10 / I-5** — `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` +- **L-9 / I-5** — `docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` states the wrapper obligations as requirements, adds the incident/migration - playbook keyed on BUILD_ID, records the truncated-challenge ≈2^-107.6 - bound as an accepted risk with a 2^100 target level and a sign-off line, - and records the transcript domain-separation gap (I-5) as accepted — - it cannot be fixed verifier-side without breaking prover compatibility. + playbook keyed on BUILD_ID, and records the transcript domain-separation gap + (I-5) as accepted — it cannot be fixed verifier-side without breaking prover + compatibility. - **I-2 leftovers / I-3** — smoke-window comment corrected (creation-frame memory cannot pre-expand the runtime frame), `validate_public_accumulator`'s shape-dependent `r` parameter documented, the unreachable identity-flag @@ -264,7 +263,6 @@ Each is fully specified in Part V of the review, with the insertion point named. | **M-5** (remainder) | Fill the `REVIEW_PACKET.md` §4 manifest (currently `fill per artifact` in all 11 rows); reconcile the three conflicting provenance stamps (`3fb6d84` / `a096e71…` / `53dc872…`); add `--optimize-runs` to the recorded flag set and remove the `SOLC_OPTIMIZE_RUNS` env override from the reproducible path; ship `REPRODUCIBLE_BUILDS.md`. | | **L-4** | Decide: relax the `calldatasize` pin to `>=`, or document that ERC-2771 forwarders cannot call this verifier. Both are defensible; the other four pins already carry the security property. | | **L-9** | Write the incident-response and migration section, and state the wrapper obligations as requirements: replaceable verifier address, wrapper-held pause, and binding `block.chainid` + wrapper address into the statement. | -| **L-10** | Sign off on ~2⁻¹⁰⁸ PCS soundness from `truncated-challenges`, or disable the feature. Record the target security level in the deployment record. | | **I-4** | Rewrite the `src/codegen/*` anchors in `CODEGEN_ASSURANCE_DOSSIER.md` and `AUDIT_FINDINGS.md` to the current `src/lowering/*` tree. Until then the ~20 findings marked "Fixed with named tests" in the 2026-05-11 addendum cannot be re-verified by a reviewer. | | **I-2, I-3, I-6, I-7** | Cleanup and assertions; low value, no urgency. | diff --git a/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md index 0ea5cfca8..e392efbaf 100644 --- a/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md +++ b/proofs/solidity-verifier/docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md @@ -44,7 +44,6 @@ One new, empirically-demonstrated issue: **a single off-curve point in the proof | **L-7** | Low | Zero-slack memory adjacencies; `batch_invert` scratch ends exactly at `LAGRANGE_DENOMS_MPTR` and would corrupt silently, without reverting | | **L-8** | Low | No on-chain provenance: no build id, no feature profile, CBOR metadata stripped | | **L-9** | Low | No incident-response or migration story; no domain binding, so a valid proof replays across every chain and deployment | -| **L-10** | Low | 128-bit truncated challenges cap PCS soundness at ≈2⁻¹⁰⁸ (intentional; should be a recorded accepted risk) | | **I-1…I-7** | Info | Comments contradicting constants, dead code and constants, unreachable defensive branch, stale audit-doc anchors, missing transcript domain separation, two latent codegen divergences, unbound batching randomiser | --- @@ -647,38 +646,6 @@ Immutability is the right call here: no admin key means no admin-key compromise, --- -## L-10 — Low — 128-bit truncated challenges cap PCS soundness at ≈2⁻¹⁰⁸ - -**Where:** line 1353 (`x3`), 3010–3017 (`x1` powers), 3379–3389 (`x4` powers). Mirrors `truncated-challenges` in `src/poly/kzg/mod.rs` and `src/utils/arithmetic.rs:246-256`. - -**Derivation.** `x3` is the dominant term, so take it precisely. After `x1`/`x2` batching the prover commits `f_com`, and only then is `x3` squeezed. Let - -``` -g(X) = Σ_s x2^s · (q_s(X) − r_s(X)) / Z_s(X) -``` - -where `r_s` interpolates the *claimed* evaluations on point set `s`. If every claim is honest, each `(q_s − r_s)` vanishes on set `s` and `g` is a polynomial; if any claim is false, `g` acquires a pole and is not a polynomial at all. The prover must nevertheless commit `f_com` to some polynomial `f′` of degree `< n`. Clearing denominators with `B = Π_s Z_s`: - -``` -N(X) = f′(X)·B(X) − Σ_s x2^s · (q_s(X) − r_s(X)) · Π_{t≠s} Z_t(X) -``` - -`N ≢ 0` exactly when the prover is lying, and the verifier accepts iff `N(x3) = 0`. - -- **Degree.** `deg f′ ≤ n − 2`; `deg B = 1+2+2+3+3 = 11` (the five point-set cardinalities in this render); so `deg N ≤ n + 9 = 2²⁰ + 9`, i.e. `log₂ = 20.0000124`. -- **Sampling set.** `and(x3, 2¹²⁸−1)` leaves `x3` essentially uniform on `2¹²⁸` values. -- **Bound.** `(n+9)/2¹²⁸ = 2^−107.99999`. Untruncated it would be `2^−234.5`, so the mask costs ~127 bits. - -**The bound is essentially tight.** With `A` and `B` fixed, an adversary can choose `f′` to interpolate `A/B` at `2²⁰` values of their choosing inside `[0, 2¹²⁸)` — `2²⁰` constraints uniquely determine a degree-`<2²⁰` polynomial, and any such polynomial is committable with the SRS. So all roots of `N` really can be placed in range. `x3` is hashed after `f_com`, so the attack is grinding: perturb a free part of the proof and test whether `x3` lands on a root. **Expected work `2¹⁰⁸`.** Not a practical threat, but it is the real figure rather than a loose upper bound. - -The `x1`/`x4` truncations contribute less: the clean failure mode is `truncate(x1ⁱ) = 0`, which silently drops query *i* from **both** sides at probability `2⁻¹²⁸`. So `2⁻¹⁰⁸` dominates and is a fair statement of the PCS soundness level. - -**Assumptions:** this isolates the `x3` step and assumes KZG binding (so `f_com` fixes a unique `f′`); it assumes `x3` avoids the poles of `g`, which fails with probability `11/2¹²⁸`; and it is a per-attempt probability. The `mod r` sampling bias above multiplies it by 1.3585, giving `2^−107.6`. - -The upstream docstring itself warns that "128 bits may not be enough entropy depending on the application". - -**This is faithful, not a bug** — and importantly the truncated coefficient is used **identically on the commitment and evaluation sides** (verified: `mload(X1_POWERS_MPTR + 0x40)` at line 3399 vs the same slot in the `q_eval_set` Horner at 3072), so there is no asymmetry. Record it as an explicit accepted risk with a stated target security level, and note that `truncate(x1ⁱ) = 0` with probability 2⁻¹²⁸ would silently drop query *i* from both sides. - --- ## Informational @@ -755,7 +722,6 @@ Nothing found is wrong today. These are the places where correctness rests on so 3. **Strengthen the deployment probe** with a false-pairing case and a wrong-subgroup rejection case. The current probe proves the precompiles *exist*; the accept decision needs them to be *correct*. **[P5]** 4. **Bound the quotient-VM operands.** Defence in depth today; mandatory the moment the VK stops being immutable. **[P12]** 5. **Assert the committed-instance identity invariant at codegen**, or plumb the commitment through calldata. **[P7]** -6. **Record the truncated-challenge security level explicitly.** ~2⁻¹⁰⁸ is a decision, not an accident; it should appear in the deployment record next to the target security level, not only in an upstream docstring. ## 4.4 Robustness diff --git a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md index 55f9dccdf..6ef6d5337 100644 --- a/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md +++ b/proofs/solidity-verifier/docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md @@ -1,7 +1,6 @@ # Deployment, Incident Response, and Accepted Risks -Closes review items **L-9** (no incident-response or migration story) and -**L-10** (truncated-challenge soundness as a recorded accepted risk) from +Closes review item **L-9** (no incident-response or migration story) from `docs/audit/HALO2_VERIFIER_REVIEW_2026-08.md`, and records the wrapper obligations that `AUDIT.md` TA-8 places on integrators. @@ -137,38 +136,7 @@ the current design accepts is caught at deployment rather than in production. ## 5. Accepted risks (deployment owner sign-off) -### 5.1 Truncated challenges cap PCS soundness at ≈ 2⁻¹⁰⁸ per attempt (L-10) - -The `truncated-challenges` profile — which the canonical artifacts use, and -which mirrors the midnight-proofs prover — truncates `x3` to its low 128 -bits after squeezing and truncates each `x1`/`x4` power to 128 bits at use. -Consequences (full derivation: review §L-10): - -- Per-attempt false-acceptance probability of the isolated `x3` step is - `(n + 9) / 2¹²⁸ ≈ 2⁻¹⁰⁷·⁹⁹` at `n = 2²⁰`, and ≈ **2⁻¹⁰⁷·⁶** after the - ×1.3585 `mod r` sampling-bias factor. Untruncated sampling would give - ≈ 2⁻²³⁴; the mask costs ~127 bits. -- The bound is essentially tight: an adversary can place all roots of the - lying polynomial inside `[0, 2¹²⁸)`, so the attack is grinding `f_com` - with expected work ≈ **2¹⁰⁸**. -- Edge case: `truncate(x1^i) = 0` (probability 2⁻¹²⁸ per power) silently - drops query `i` from both the commitment and evaluation sides — a clean, - symmetric failure. -- Assumptions: KZG binding fixes `f'` from `f_com`; `x3` avoids the poles of - the batched rational function (fails with probability `11/2¹²⁸`). - -**Decision (2026-08-13): ACCEPTED.** Rationale: the profile faithfully -mirrors the prover (a verifier-side change alone is impossible), and 2¹⁰⁸ -expected grinding work per forgery attempt exceeds the target security -level below. Disabling the feature is a prover-side protocol change tracked -separately, not a verifier patch. - -- **Target security level:** ≥ 2¹⁰⁰ expected work per false acceptance. -- **Sign-off:** deployment owner: ______________________ date: __________ - *(recorded per deployment; this repository documents the analysis and the - default acceptance).* - -### 5.2 Keccak transcript has no domain separation (I-5) +### 5.1 Keccak transcript has no domain separation (I-5) The Keccak transcript absorbs raw concatenated bytes with no personalisation string or `COMMON`/`CHALLENGE` tags (the Blake2b transcript @@ -180,7 +148,7 @@ the midnight-proofs prover; this is the same class of upstream protocol change as M-4 (`vk_digest` coverage), and is **accepted as a documented defence-in-depth gap** until the transcript changes upstream. -### 5.3 `vk_digest` coverage (M-4) — deferred upstream decision +### 5.2 `vk_digest` coverage (M-4) — deferred upstream decision `vk_digest` does not cover the SRS points, quotient VM program, accumulator schema, or feature profile. Compensating controls: build-time SRS tau diff --git a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md index d8df0a6fe..60afe2cb6 100644 --- a/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md +++ b/proofs/solidity-verifier/docs/reference/HALO2_MIDNIGHT_VERIFIER_SPEC.md @@ -543,7 +543,7 @@ counts (no two distinct valid inputs share a byte stream) and `vk_digest` separates circuits — but it is a missing defence-in-depth layer. It cannot be added verifier-side without rejecting every real proof; like M-4, it is an upstream transcript decision. Recorded in -`docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §5.2. +`docs/reference/DEPLOYMENT_AND_INCIDENT_RESPONSE.md` §5.1. ### 7.1 Transcript State

    S%O~zk%!EuelZ!=gtA4q&4`WJF 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%0DiTZ}u{Iz2@3kbUCWr#?6rsYCVK2Fd4uEFx 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≠%CQC_| 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

  • P_u#=!uzH7&T|(2IHl~7S*b3 z(DlTYKUF^V0)8NOs^h;uNjOsz^;%FH^%`&~T#eG-;;+v`I3U(5e@*pNjZr2I<}@b- zq@EpEQA2g!kLjVoE%p;M7*dtR9rl~2$H0U{0y<-m`9_?4_&W=5(|zeYbwpDpmF9bf zwLuVlLIr(-1^@-4K1C#e!cm`s)@}hp7KCsu#BT`+7Lyexw4rZ;c9K1aehKi-asX3t z8Xpf5JCVId(C#M;Hoi+vzFTg-Q_j6&YVgyklGP}^LTd*|7lb^6m^6P=m5D>^RQWw$ zpkn~s2SD4pS<)EY41pESzzSa=I_#_VHpW1>zP60JEu%Tek!$3L7+YIopc`={1(;e9 zNuas3bzveqLm3G9Wc>3CR}~cTPW2wM;-fXiKc2}-z2amw#K&V2`sM&iR$w z+db^r3yIKZyXF@j$@Gj(?Gg=VeB7JbJ&fafK^oHa4*oLK_YIbOLZ3DFIN6|o$xLd- zUAcaYdlAP zmeq%-eu>vD9kMcdfvT>}r!-{!$V5_Gov*LKYMrWToG+^R>`!I=cLsF$PoN2ss<=an zo$oG10*lU9^6T#B)BgBj=i7B>;$`RipTFG+<4#TEs(14kpEA4kk-uYeU1m3xQEzpT zad-8Yr>ZE2DfD%u4|YbzX7;xQmiwa8^Bik&NVs@I=QllDBq*Ot^yn*?&gJDQ>QTa% zPbf!;wO5>KXfT#1N48-pAQgb>1d20O8oLO1pn6!HS&O0 zfRuOmkZEM08tHB)wOA7vm;(1pjPs)}-Gs5NoeZEKMZxG_Vb4!*+R11WSx7euidvV} z{??yjQs3GNDneft@6pSGxmU_kN16xmr8L{|?p1m5r<5LzZwD8pKOOe&WjX$0)4NP+RJhvmAsfSFTEIh{j^5GTk+tsP%8EfXSMRLgsd3L+j^mO>`U%f zsvt9dwtZ+Tu#f$VyIS#2Q+Dh^GnPEqh~w5>t@tOL71R9pbg6~xAI5s&ubl+puN7R+ zy63K41Q>4(#a)+KXl;APUAG8$+8Ua(W;@r?{+_d@8Su0=jJLqj| zZ)yh{b?n~ti~;4SyVa5bJsGb4Pe{#M7ct<=dF8Hu061gKHL!>6T5H+&j0NYYxAf9O z4*YN!`!xj4Q6KY17Bp=&S^J-qhMNyTQ)Bx3jXVRMrju8Z14~(_?s~_7bJWwc@*rtz zEWdAtchJKmm-!XIzUHiVzI&XG(cAPT8M&Qy(prd@S9)L!02q|1w+9&2i=Rvh%Rgq- zPh^ce>7#A!hxga?Px?%=OV*rND)ZxzP@tWOhwc`KVjI(2!)4`>3tQq4WdQ z(qMX8X39-0wH8VjK}HFzquczr*22=g8d^d3+BHbtw_+kkIz&(t{9DEoguQX(laVL5 zRXbgio8+P!?aIX1B>&N<&1!Q!W}@O0CQLIMk5tiFI`kHQ=rx-oP5qv$s>Uxj(cI6p*br$_k7~3KQvJ zMT;%`iGfv)VY)bYTeLv^+7Tt5fdbPZFp9=9 z<9*;6nH3OM^2@o`C^K_=EiGzrc+wHg1QD%&tBB_@^&Y(BkOd1%cFlcqJS=k_gBgG| zBBebd#QIPvB84c$VnJv9*6Q)v$|9*R3GL~rpI(h0|A%g3WIuGt&Q49^$-Zy7poq4~ z)@d5Hnv*x$U9BR0_8ha+?7`(CR((>aOWXO%*?&sw$lfS84A*&z3!wNyS8I4f{I>YZ z2AfT&{_I1^E>+L>4m=>p@A|i!TB?;&?m`X9^e4e>^(JB`kO$o2&-$M%Ipj^UD=A#zQJuD+qhc-9 zM*=A{XsqlaJ%z4m+3byQ0c!K}nw@%6B^&zBR6<&HqGdrEH4_Wv>0m@;;RvKhRhEfM z)LuzzCPN$q-K3~Qa99X%m4j#k+zQYm_2(M33ZbzSy4?Ec3}a8;A7p*JreFdjyqPo{ z%%G)~vW`J(6Q*N>6#h#Bcid8y;@u~ZHD4}ul971!c<0YJzeQYv!A|~m0gpM;qSwJg z1}8uv6B8(|oTlB0Z8z(^*nurs$_mec2LVQLkUvm-nYD{CIOB*Y9-6{(*cC-Bk|fN& z4iG=5Br=Swfepow0Q0fb2r6q0GER*$8-mG9_Qb#HQcKk# zvMC;?fvg(fE4=Cotp|fvzCd+Fc(V4H%c)m)C4c*4|FDpv_P4iaiXwn1!==^^G|!c`9ZYx23&B1qZ8V>k@OKch@YasqyNS)~|t7pI0r zpfBswthM|TmRU5Er!_O=G^f`lOrcsUqcvSoEP(ZRqbjNqe`220mPMI3xhTgIi7zo5 znlBL)gPAyGM|-c$E3UvJMCg^CsT6Bllt3fGDl{Bi5$xh+_5|Tihzuo697h4Cpuk;< za4w$H0_jyP@c3o)K%UAvwXDi?YBU6SCF ziP2qXby^Jadb+7owQJ%vqGy#8!tI>Swe)@Xiu23NW}ItS)HeWOojuDsr8ctFZ0leu z4FVUQE(_4ehTsXIXme^$q+Lvq4Kw)e2#BmoSdjw%iEV2k9r-_$r)ikfT1eCEp~bg| z7(KKSJ*2gXxX_X|ks%1s3ANTxSf?^m4<}mKecUfRrd}F|;@U;W!oa0(si!?nA8_{X z^B3ns-}W2d(9-k$wD*5$JI#s1yU~7p@}=LsZ`ksGPWqGUf0t|fJKo^iWivQC9nMZ{ z;qSlP1D;&#`+3c@q5u1H!tLLo@MwP_?dW>~H*Ut>yNc zrC%DC5&3aG_k(}gWjMT!F`?&I_c#uZXVd(9TngMTbN{OJb-hHboIvkg?idWa-u8Lz zntuE5e;?=Lw`kusc4NKuIaS++)l1!ed7L3m>+gEn-yGn|`Fj4GKlATCT({$O`R(HO zw@nX-YTJ7lJy*83U)%3CI$t<0ZcJHcwfDdNi0Ah|?{6CC?--9BNLajSzsY|6m@EGR z)z3AVzPjZ3{wvQOXNvK2yPvt}cRsIUftu@ceIILU*>qgrTj)RBj~m;cWbygVbD{nm zUH`-{mki zul28W_h)yWcVoZxBvkyy{~MM1*6*>0pUoY&d;D8H*KIj${nq1Mc9Hx}%J${k-_CUv zd{h=L=V9Xw%&W+}CEsUBEgV0m`)E9zb@%;w@J7ByfeqvHvUL5X>q@$O=Odh(&!_sN zMnBj0&AIojhNt;)=`~v0|NFVlU7qXn?{Id`^RxJ7yIPyy&53Ii`=zh{zaQUJO8DHL zX6f5}hvirF-O8HxgNM7lx7VcJwyxW+>G=)!?B2Vb^I*vOw0)2JiRmq`yJf94OV975 zv;2=+Gx|I~nQ6t7P2Jk3y={wLpSMc+9EWjuyWZRR*eya@@&2q`67StQXL$a~wPwTD zG1oROrz5j)9M8AK`uq|aP0#%iZ8nXM@(M5KCw{rxd47k{WNx}{zr$s7zK`4C(rP}> ze_fHv_FE?xXM2A~v8nkyJQroJ@Y_7!*wXc%gHNb$_s?U&jq1nt^*`oX-)x(=OVrt6 zO6j-0`zHV4dAYpp-}qf+$;KLBSyn7{YZ z#B0|!T>8PhyMKL@I%_vw|Hn`Fy7KQEZgJmJh1RRT{o?HN&%Wl3{chOef}<|{@gW~| z{9~sjx4gFd#Pqqp`OnRv=db);;4LMax%#EAu76GI z2Pa>#*=7%iF5mCwQ1l*J)6m ze(>;bl7~F`*0Y=CH~Ia_IojGI+wG^;9^ZY#y-$DSsHH2^{eCg`l>eOkL}h;XKj%&P z`8ChJebcqdt~c!4_S%Q}7rqkT@9UR;cv$cLkDS-!gKxNW_Zv=o zFLUaf_h0(mE3Uu#!3($C@00IE&dBs_eB;p%E&uTo7fzXX*?G@j`SMv``^y1azCJnI z^5Y+zv1!xQ_bV^`x#u5#{NRM&%$~A#_|ga8zv6ozUiQw>xAk9e;Etn*Y<}xG6Y?K6 z-f-UJX+!sJzTU(){`q2Qz4W8u%&qEkn;d&y`{1eXymMOY^aVHVx7WEB{Nv#lK799r z^SV~-G%2EAm|c41rul8|`|ArwT=c7ayVkJ9!RP(+`7=jP|K!5C&+h)tOCK$rddfNr z?mT1a8HXQs*~izVcf0p*nFoILQS!u1{(9b_Prul4)GH5Mzy3W(jWkaC(lbB%=7pXA zJawJ)%!i(S@0XV>n|#$9`lSz^_4oY;ci8{%@7;FGI^Uc+b^SwEl8s#F(tpj|^NlA? zo87wI?C0Ou<@h`9eB_Sb)aK5}yt3Abd%b-59&7*f$TO4oJ`-s?@Q2SWeJs_p;*l@|JNiFY+?M*!67@@Wu8eMQ@HhW{eCzN|TRr*e1Bo~HnXG^H z+b4eG->;tBJbCBGZrtX`Z8yC9(G?p^Qva~wGsAE9e`nE-4Ifrd{MGwEX?cF<@{`$~ z?DlH=MSuMBi9=gn^yIByy6?z`COn=!`m2ZcUiy#ozJF5gioKrQqWJXR_S&-fC%fPB zt(W${@w9i2FQgucT=PlfcZWUSaBSO2J0I6rec_ld|K+iVZ(h9B$y?mG>4giwd+~SX zzIEGg-kg5YAK&eK@RH1nj~#a6tfgPO;=b9J-2ImGOWox9(i_`?YwZMggMx3-@9 zogZhjmoFLG=h=&I-}l8M9>3u9d68=y%3IvM==e7e-)-+VKc4cKex>o? z9}FaZJ9*pn&YpZ@ru_C!S3bVe$scaF&+Cb+u7B{lhWnm+dCK6~`dY_6cGfN1Z}ZE{ zvGdNajOwRschiL0>u(=aeEF+SedqgEj#gG=PnxYXb+@1U@5kPn@r3sFea~IB!5$|) zarU3yD{p?$z5nWYZ{05~dGsqye>ya`>08^(eDK1%{`%*`u6_08_b+N|Ik9bNln7YFSXWe_#{o5xlN^S7cW|23iPCDm;o~0X{{L#PrhC5ogY))HcKvY4VDaS3KRG#~o_oUOC-lF0_wM`se!FY0|AW3H_j>orTJt9_ zEPrOd=k{xR@wk0{c8GT2mKXj0Tgge6we7j%Nq>B6@s1k~j8~rcard6be)vNF;KHkB zJaP4X58abU{`Tq{e|y|jKUuQ$&p+Spr1qsBPnj^B{rjf(?eg;t?&{j%=l7_0?fr+h z-g)G$L;pDSo${oeW|!`I_m5W&ux$~}@T$E71H}j4sU;k-Sy!GE7_xyY3 zgWm3*yw=_~ZTy$E_kO=~&*1mh9ogXO8=FqmD|?-C!p!dSo!gdP-b-`n;p={x(6-S~HJw$z^6{F09@*)J9E{_B&kD?k6*!j9cn z=AZi20Z+ZYUi9{z{*wEi+Hm%8I68g9-HQMES8e2+B?s@a&dX>1Vw)Qu*zK=xZurgF zE4O%ik+NjT4v`#ns@Y+ptr#-uP)`_=veZ1Xy?{(ew&h3-GJoyjDMz%O( z=`G*Cv+s(AgRa|ZWVefYFW+^qJD$FB`>Uf%GI!j(`wNSH(st6a(;v9wmTBKU@ZGO} zx#5XlpE)Od=^w6n>Cv06oAzS+FZX@n%1@3s_10y5zuI8I{r?$UJ~Ow!e(qKmF00lq z-#NeH;pUTW`{AvJe*J~nlipnV`w!C{&HX=m?96`__S=2QlGbnBxZSN&c7E!xTmO7; z>o1c}P5bEB%6{t|e(Jv4@ATktTMu5o`(wRd`q3+w{PLdWDObL|**1r4y&^noqdgA# zZu1d)J<|8q1vA3W@43VF^WS;><{cO53lG0>(Z1if__Ce0?0)L5{ja~}h0S*COmDo? znX$W5HxGY!$U~D(p1;w79m~GD&i0YVH$43aefn3=dHI#0+zAi;Zr$&{e@X6*Wq18y z%mtiK6>B5k9=+ZR(tLA z!MRNni&H=BeEWr)_r5-NV0EVh{`NxSKRV7|{G;^Lz7>tnzI4b=CseNA=YVZb+Wxwm zYLEVY$A(u^rK4VIzHr^It}N}g=U=97d*9;AQ`_IP^3B7~zxk#kH!4p)bH5MgH7vjC zOOJlA{J#@^_ThG4Td?R`zdr57<8Qoc?)6jJmRvnW{qN}~J$TWs6Q0^}{?m6ZJ0r~eM`TxV!h)}IecbM?A_5H#Y(^F zeR$cW-#F-n<6HV)yXJ&Ddrx0=d(kb2COT_-2ncUgA)zaF@J`47$<*yD=E zOV`=->R$~kpSZz+PiF2pK6>qNdHG_xV~I`r7b$Nlz+dyhEn_(RUT>Al~d`_PP| zzq;k*hF=~r`-jUvx%kFRcHi&6aO=L2>Y}e+GOc{f@mC(X*0E=QtKqme8V;QJm9FWp z?R@O-zmdM=$=L9*`Rz;TLa7j5dffImeRSBK_q-MPftD832>-8;LnxdP(+}5!FWru9@*Y=H$7_Fq9pR(1? zYsLF6nfcg%kGy}zk01Huu&GDf^MmN#_pbk!kFL11_RIst*Z;cz)~8&5$1i{R#Ku>> z`1()I89M9TUB9NhHig{x9}Iji6hCaik;U6DJ$y#v4j+6N`)JF^+S_e(*m(Kpn*NMO z|K}w_{7eAe`hPT$h$L+Ke`~z;3;lnMe0Dx@=dFDn*~|Oque|K@`(gHP)~?g$U?0Ej z?$IMYy7gDj+<)?0?;fz$pPxVY*SQ;y_)Y%c=DY6d{@00TEr0yG2Pfz4bi{<~H@^9k z#~M>F+Q)BLrwzkCexn%|9r^f+yDZ!2$OkvRx9#oH3;V8r&^cRP*mc#EJr3$CPrP{1 zv zU;g#JyPY0i@wcgu%ztg<<>vmO7av{`?d<-}3oZ8Xo7ZV$v5((mUh%X&F1zHWTh8nK zcZa^X^Re1VU+;J?|LYeD8*0=4-u0blw%)n#fiJE7wI6*WwdBm3H$2%sew{jPHV*n} z-RMj4J)g?IxXbMieDmm|_8h)!`a}CS_Abl!JowvJPPuko{-~38{^;c+zCQPZWf%PN z;?vXi@f+7^1G10*@^-&}D4O2wj#+1Kcx>-G*~`B1+qItB;zyItifs71ozHt@#^zr? zzgJk>9pDUD> zyx(jezkQuHG{^fdd20O~H+XB;-@kv~<(L0s@$1!T<8$o)-Zva|^gfq;`Jw~A68qqm zL-$$d-Se+69R7=sK3cTi4R_zZ^Ec;Q^}-K7ydm{gb>}00@vqHZ`?h`jm+G_`+Q+ZI z=!APtd1%8)Z~tz;v(i61W9Dg7-#_>-U2PxSbxgxPTi&qb-poC%C(XIzHybT^a)XtJ z{OyciJMdqp4bnb-o9NQ`{_p;Et@U2mOTQ_y-TSw_*nQq-&Yk)Dmq(wO zw(;;ww|{;22a3to%tMa(*J;zVkKg+Ct(qH7dh3E8y%xLePqX54k8OTBdvn99=lAXV z-oO7aGU1_%rk(KNW%FJ*?&w!`xuW$aA35;1R-HCd`|vM+_xQeT9-26?%hVv%b=N z_p7D14%)2oz^m?Z6-oH*=@{<{D2cLcBGgp56;}7lQ zzf`9U*FJu`=D7!+{Ne6D`^`mN(?`F1-2LshzTEQeuBDH!T5{~@!qGFXeth>cws>&D zwzux~+8+-1#=u=au#exYPMffO{0`Ut>BgV_DZci%3djF?`l}!2FS>L8&R75Tu)gf} zZ71|!KDBlK6Wit=bM^kO?6iEt4bHv$hJO3__3N}TJKn#}k*|$j^3G=8`r(BSZMgXs z*N?Q`aMOuvow)aw=UzXu@AfA@ey_gy95tVOZinZufBm^X{O%O{_-)2%v)+925xaDM za{hLwKHGWodN-}R>y`(eyyH6AgI>Pi=_l0nA`ka}_stjfc%}c9S8m_^8|O^krsYWc zc>8Dac{enEn4fUYt(zY*y5oTt^xt;$JC}Xg#B(>aC+>tciuU5 zu>HJaH+fFIH4}a`y9{$G#=kArh?&Hf2JN%5PXWY49ol~YR{ph84c7Jy6g`b>0dgk;0Jn!Hw8aglh z=Fgt_(zM2rqwZP%`UhS)s^i6{4?XX%o1B>Z=vNP9{&w$f>reeZ_O3jxiR;_rh6`4) zRsm5Q6)Px&OeQO$f&xOZq9BMCOeUEL3<*h0!lqais-md4KKBi(ViD{5P}I6qL{UI- zR}idqL(y8b?)tlTCJ6+v;l1|v`{TXdKm4d??%D3S=bk&0`@KVlwJbP1Z{|dY=!s8P z7H^{-?DUGwIr#k2nUT_#Oa8F>Rp$G3{Dq?>$Bt(7esCkmjvuu2{DT1_Uv6vJF>g`g zH1F0D%I(2}Bl^RW1I1;NuCI!8WnVriT#>e=MgQDt?}eSO`c52kx`mU3%@4d(bP z*XPt?znq{|5tZX&``w&rjV2!Jj7Pl{AI^I_i_=TlYR~s}clZ5@96NWf{q)@{quX{* z>y}^U9DD|JrPKhYn^WJzJKx4Lj4<;9%0iZ zwF#Ho-ogi4PcF?>ce>`Cr_7wc{`YOcGkeY=&J8@1R@C`WdA4oL!h64Di(KbAWeU<= zZp^sK{;-=}B35NQUYb9#>Z=0h?>%h2f4d~hDfW5xOXi503x^+mJ$>`+aalI`ofdTo zKXA6}(dTn2_3cWIqDePi^j|$udB)*^TQ=rTygiWaeABtqn-NDgUmG72l}ivCrmy24y5ZdR z-GW=(6JD!ZclWx&l`os>`o%%VjPdwxr(r|h*Np8uvnC_#L?^9%!OF69D{6K0km`#? zE_;jj?d0AcZ}(=A}kw`g~@8>z&t&YRU7y56fP!6ZuCy&3zSgS~+)`ZYocZ{i6EL zo*DO^9M38q+3lf?a@uW{wOen8ZGB2@E{Qh@rnt9h(|=#@kb|>CHk;E|jV||TakPD> zG%x%4IbBXY{n@Jck*&?l1Dk?=M?V}c6kK_^{KA$jf8V{WLO6RPH~OR$98Ju%Ze^9$ zv3j!WT18gd0AA$A@4Pykwd(m|2$!s#(#Ipd| zT_z4#o@OuX@NQ9CKViiBWwQ%eYfe0NvYON;di93jh~-ol0U&RGx5#>uM|`6HePtAN zYu_HbiV4mqY9tGC7p%kCi$3HoQb$LvlDF*<{_vN~9s>kF3>JP>k!_nrrfeNQ_oiUN z^$C|1l^-nS2TM(qX}A5}q^R$A&b^Yq>xz(Dc&2FAdEcGmq9v7Y(g*l&a2%|CJoJ}o z4@(|DyfyYXUbx-C@3{5$-bFS~iG+be-cJgA|C*1nw%jj2I&vP)&F;|0sb+`k@-@7% zg~hh}^E0)L z!=OMi<4tRqv^I{D)*kJ@cb2C6G3_@$U5ra~_8ix1J95ALi9aTukn=9*v+MD^nyc;8 zCC8-Qeq2%AviH=ewMp?WU#k1I9f7(htaicYDIYl=L0jLy7=CT3(q>PwP5-e)0jiN3 z*bY%qNLX#B#GqkqYo7Eyo!>X9%ibw2d7;PV7fkxEPVDqsUY~m%d3@OK`FgweeuowY zeBSR_2Y>)oKtSRJ~pe%I%=YFq+)_D z{oU}3!h`&&_YTdt=rrVzUH+H+s3_+Nsy|kgt&w=N3vi#@HKkj}+8skY3J>P|x~6k* znR9M**SW=x_7O{Fws!ns^Oq4}`7_5+VLcAqe>}$CVZaS{-%SrgOT1G(W>4wgvS+Mk zWVdu|lsPZvx4L>}fimXT z>a{&bP^rt?o@3j~cO}1Vm!iMs_j|wEXH}0jeJoh{@b0xPXEp2>YrE!6d(hryuOqee z!?MzfZ+4}>O1*Qh#i`N3ttM2=zMZhMr2n_Mj`~RDzOe@?Ykl4fRS#mVd*$feWlXP< zsYRuO?i71tVLd8JZV7AE^)rY&tZ^s-wCbh+qId_r5u;szW7VN$&;bl}#`EpzA z+29M>ggt0Rp{zX8dXPf?(=MBq+g$Vd%U3K@~h($tgZugra47BkeJ(kEQXwyw5y`D%5# zRoae>IojblJ;U_uh(ne0BM4dk<`0ThL8%8_8s>}k|HF6S4g0qozd7s2!b;YNkUkHV zj&O<@a#PhU>G(Lk&-RPC&ae4LV4#~tE+yGzrA)Pe!H9B zD$L5M%a9vlU2E-FUN1od-tf#$+76N z!qlNNK9p?mJ(c#cY-CPoL;bt_#dqp0vU8#$`rdWsjF_vaNWSEA=C`YyH-FH)4VQg9Z9F3-mq~=#Ao|L9?_zowq_Ts-2%PQ{;WYGEYOt}=#Ae0G-xd?&>OvfZO|;) z-{}2YgLc6J{hbARum$=r7U*sk=#Ac=H)xICPc&$jew~b2p#Pt4mcRdLb-25ZidNzD zhd;9qfX$Qvzw!w_{rg|ojNkvb0xsW*jd3v^#|mlm;`86p{-1yU`%B{wPdLDH5jvKX z{1X`#e*cYP?E1g|M&b8gKF0p%`|p3ErM;guBp@kkM|ghen;0=oc(cpQ#9CCPnTiZP-Z;IYV*Jn=d z&Z!rAR}EX*6#a~ST<<6L*gq$1{%QY~_LuU10IpPX!r}ADlqx!iOlAQtjb;3K{^tq6 zYHyzZxok|p`zQbZCmKBPImS1_eH0}lRXWl=kUpsl$KMkfF@o)mve+FufQQCVDiw2{ zHO_<>V2l(uc*s+#*2f?*xDp=ggeM*mg48J0$@KA9cx)boSpqIqCU-Dg!l#EAH}L$o zUaeNjVsJ{uLR`i%=g3uhEiTg!&>`A*piCSI&wXm(*-qw2BG3c=>qbA50 zTt^>Rm8s)2l#6;6GGLkvQ8`#l55OF_78zkM z3Q3Gn>qvuhfFboPlmw0r_Zb!Fi=?C=(Iylj6TCn@))E76f=ob$C+kUs4g2FNBwhua z2h^t2@R+`lpIQUm0|$wqv?S00{&0^*0fLs3Nu&(I02z3LVbMc;BF3l8ad0K2Qq)rg zdXYJ2P2b^WGy#k!bM>KzX*6iC1GR=Cbq04cBH)zM(+8;av^WHSrSJPa$uM#p=o6vz{x6wN1U2qX?32S^)r=(){VxN(BdkcOiO9> z44VW63+gV0SQZjQ3Jgi0Kyc94Kmrp#Eyk!Jki`rT&2JQAiVFxljN?vQo2b?jIyXd0 zMZ1IOq;QohCOLqNU)6GIZN2%w*4*h>b}rqJBga=DH)Fu0z+Y@FocgH=s=&zBcNHBq+p&E@BW`uBJg#flMGLwItkoAS5n} zp}9fF(L-e5f($~adLx0*jz@svh$rMsP|>7Lk2KL-{3pBBiwm)q)M$;)7!m4f#tnts zRPk|Q(`Lww%z9~juHYFha{uh>xnVv zC^C*N4WL5BNzFzVWj7>?rC>EOdjw^%P%e1N04mm$PF!O~Frn>faDpHSGgVL?i^btU zMx0MF5;lhs2V;Q+4KOkTL-}7Y!cdygAY`m~jL(Eo!9KoBZ%<@$JXrMLsv8a=18I-z zAsUSamnleQg@Lo)oS7LT77H;lqw#hiMo65_aq)(j{FFGF(`YqVAwB88x|>oMTr(sl00?6ZLsu?L>12TPYq*vgQz3##{36EC zSPf#3zeWW6`UUue21w}Q3RfjFNmrjp;tI%=Ab}6z%7E()#RNj4GN=#M3DY_-u6}lh_#ZlmmO-x^ab%oY zn`{79s-NB^ZU%mMf*Mp-VDUFqHaegnGA1lE0ONQtxD*H#7e|7X5mq9JF%V1xLUF)O z3{n-Xv4NjV4Hy~L<|aK@-zQ-4Rza*6cV_hl{|20BC?hGZFjgrvmXlf$uR&xn@hSxb zj{@;auL!yrP&F9@>-5@q8QcuH(aVwq<^dYKiWKWeB^VtwC~mh@$_0t$EryYdQ9Twa##?-nnedAT>^p5z?1+i zA%YAH2qUlzw3Gf%AjqHzts5h)o_#K^^&sMKosNtHyOIW|ade@@IE^Vq8$paA#v;g& zJPfXKGveJChr>{0OG#s$O?-kANT#3|1f1%8TUVMfMKtaDx*(w%L5wwIEirf;Mxjg@ zPmpE>o2gin7`GLO0Us0$CiGoHb`WaDxMG@ZOWE=i^T%p9{b7gECMRB%Vz~;)iav4SnahaTC%Y_^+7+;(~F|I(0350T~ zT*N0iY(4>>=K*~%HsfWw7;lzToRNx&P$@^q-C_LOzep zziwO9EYW|AhzfKSqc|y-OEDZI6`YWQ1kaaB>*Olc&60~Z)8j%ZCg%!KpbQSO59lT$F*ZpExF{jS zNv=_Da&zr9%y79(&ifa8SJNxkja>Kn72XH-u!_ZxS_WAJ*#w3&yC5(~RxuDpwv2hB z7+&PR=dj;xSyFc^yoS)5j3fy1ll*RxJay`vBAeHPCQF7<%p8Jss-yD=(xaP&I7Sg^ zTelNgkKP+KZ)P<`M?85AloX3m ztPP+%)XGI>P9Hs*c1L}rbkf`{SWsmQmRe5+a_`+nnJ6F{ql`%yVpIVdil;V;g#=s( z_u`*CdUMp9xg1cU4MRpjvFuPnW9TpxoW>p#wdJqp)dAQUSKUUMNqWJbH7~yBVEB9?}9kSWFNCW374NaX_}He)Q<= zwLX%1Aal7EuL&atKXERij3qDZstrs6#bjL4@PUF(pcD-Sk|Ly8wEHKI-W>IAUZ>Co zml3hvp>VGR`dplyD`MtDhx&j0`10eq?2bov8)OJZHd$*L>J=K>x@PSqJAmI^WxCfQ zP%WVI5GMApZvOsA5&RIR9%C28+@_NJbP#*#2it+rZHDh*t>d;+H3dakA@ z_MEHV31D*uc5@%LAQj|Vql(&KuuN~F4ngKVa|Fh=$W%u@{)!JHHjsHTIcEFbJ zmrbJp#IGZkOQ2F-PDv7Y$Pz4KBk=BJv>)}`|0De8ce~0}4&H$=6$Q^vj@ld=r!t%& zBpv=jHGpnJE5ws9yes9=pl>Y>cs01inEU-0_EueXeFINx36<8W_q1dVNF?==; zUjQFH4SaQT();W=Ewxiy>SNVFSGe=clcsvQ88Dpy-$8g*3#KovBc;+Y%^C8N>j(;E z&0$Q7j7o!bh^5N%YyyIcExWSlpxa5O6W|-Wf{QJTL##Sx{G=Vev$ByRviMjL1ZOEeUD%m z$lcaQGKhSbR{*y82zEb)J@BPX<|CdOFybTv%rBk6O_FH#GAP7yFNR(4rGxn>Nz34T z=r}6GA{8z@pz4oNIl)jvdL!jL4CJ3<$}B0+2crO41Q~cghJEnGr-5&i`Dk@&74UNu z;KoB_;J=%~5Woi6?WD&O;JZpaj+Ivv7Bj6NK_?gi&?|QW-53n#WCQ-J=x{i!2KPDO zsG&e3)8P9tY=Uo>`ASBK_Xwd`IKvU>#FB%W%cwI3y%)na_zvc?>D8o+3C1h%o6H8l zgBRH{L)C)-VYLMz1aFX`G9c0uk!CZfp#1-`u99A?p4c9)Rde3fcqFApu}9Ckjzy2*J?ck@I9Om4kpJlLQW2$L%&c|2LmNITvt+0qL8bRje#us8smQEW zPyzgY4Ex|KPXph!=7Y$#;zASRd~{@+OPi`T#O&BO`gp+Q1o#f-TU8YH8_urQSy0HN zck7^lnPF|RQO$K|)zxN(-j)da>n2tj*bobJKZZ^4?J^${Fp|UQIvnXNsQabI;@_rX^W=1V0CWtD{blktpYBOn2%+Qd(W zoy3!Z=wi7phP+?f*b_UNvNp+pnuR#APIv#VW4L52*Y*qUITfW9HK7AVac9{=$ zif3RL|1Oz(f$fN1j9RY^g8OE`dIEgcKA*0dR#QpP+NlRXOJXkIG=Pn?bp#RPD##F9 zE{e)qQ24BK>~q?!*3lE-+hjgUlBzZ@jydQcLL`MsUV+)_`P_?P8+-@z)tY+&iE*K! zqK=xA$_z3fIUG1Q&|aH$ZD1R+a`kFy1ZW=~x{S~L7)~^qpSH!JyP|Kxf2P72{(r!Y z8EOsa2U@#8FV))-(}_I}J-APd47ogWCBUjKf`g&UV80HEtqpcK!hV#NkndoI*dfRv zh@4Rg`Hu3W6Pp~meK@Ma1Ply+dZP?2qN@imM>II#2Q#q?K)vpAj1f~**JwIDx>Y?Q`g^=WWB6571eCZ7dX>VF*zf zX_bdNz4a3t9eO>BiA>hj>kHG9t#ZN@)9M+d*NetR;JVf$6hK|gFNmX|okL3*Se&== zlTPe(=q>{WkC=g;Ix+*`7=hQu1QY_)SCCuLPbaoI)UPMydMp5R2H%egCzj!CfbiCm zwskg_Fl08$0IG|uH5hR^5}=6PYeCS-y$*WXW=GqVe_52HhS_QaC7D%+`6cI(V7AI_ zw}DRVcC@SW&11%@vw>SRL=ZGX{+UYTo*14F^{1EyiLnbQxYJXig0PlC3U}uH#CAv9 z<-ne*z-5B+Q2VBhwoX2?02+-12g0(a!x0l?Ie$>!*&!!O^BXQgpi{o z;vJk90(VpR-E4vaF`*mt{h2t0z^Cnav|SEd;ub{!m6u0{^#}K_o&Xe}f~xKy@Whr! zJ2;R^ft=^;z!#>p_LM9Ni01Xw%{o<5llq)Fq1dPnalJHJO9K(KJM?p6&!g>fAWXMr z7%-|+J@#5`F<|4FW`#t#8^ksOudP2wYrC8vi@l-br**tQB8+!2&T$(^`$Iu&B5=0{_(y`+M&Q@{kj`xoClL6w4UnR`Uh>H6Kyj#UGgHnT#cp<}@htE?75^eR zoXV6DYHz+irPbPP4~|Z3fs9=aM6nf!ty)&$_PI`^dt?tG#-w^@@lWi5jB6)QSJOGc zeavh=~)?Y)ohem(qcJK>y%^6EiJPOBfxYxh$}EAR@(anqYy7tS0y9S04n16)>=OoTYf zI$Q+&xoLL@KwFKE0Id_3f(_9N!4r&OVp9Ej_V7U@n@HR~1Cx-HTp4Jzp29kfgOph3 za5bl6bVRjz^@(E#&&eNcJ#kyW1pb*|j2UIaUv{j*)ptS~-)!Ha(7H z7n62SySH@bX;H#K-TxF!;q#|q(9z7)weCi!WY z+~vu2K4qPa42@7JJr(IiV3V;fLuou1^@*m9UC+v(Hnny7Re^u%SoPsDVw%>uKqhpU z)uH%ntVIv_Co(bhtG^A9*q0;O#N;kdqL@0$CVVXP3c{%CJTtFGXNaBoaU|QAJa{rz z>req>wI*spImS<8h?MnNHH}bBv?vq4eTF$yDLHw-SE7~mQTQ)KvW?03EKK^Ye+Cyq zKj!t}CFzh)(Fb@8LM4~=vAzeRKGDYUtBLNVT5N1W&_gK&?^Zadx5`x|p{jSxJ&IB{ ztjs#Z(75>oDte~z2$LszIljx21nV{Mu41Q<+dF zY{_M7it6OWQ7P8vp0hzW7`M`Tj=6A7#uI{S%u2zrQteBTY-3WMhROXiHD&bDa-_08 zs0s)`UFNYa5YIXvA>l-0#}A&&kOCd#Cmd@>MR&*|a=;RGdLr>_NDvOtPraJDz(Zt_ z!t0RrG?zz6IMLnlU7l>t&~?@@3C+TQx(q2R3>ml!zdw#-8x7biB`}2u<1NwDp&=HqqAh2I5>r{)x-o(iv|H{!cW2=9MQ~pYE|VPFbMSa~TXfnJN`n>$TIj4sLWCsMPC{i)FZUfFcw{YL@(^ zNH#IK%aiK}Qeg@V@`lrC2|lpbz%elf@W^eQXamiIC-W3Qaeb(}L#LEV?oibVi__t( z%22aXRycau6-T+4NNHFhvEM2c4gZ_b5MP=4?6jrUFWKEk?ihwI-uF!6f?LMn3JSCuDz~wAdbB3OHRHydO z#?tn6Wb691bzuX{Hf(NPcXSohRq%L-BRxXG{s~#SUQ;%aZcwb?J?^L$Nl+X5+M%Vc zEw&s6!R2rq4K}+~S?6_@NvyF`vxjc$dQSFpbp3F-{_*uvySKmHxpVNFU*5id`RrEA zBks#RdY^y82N#gPd3n7%@%7sA4>x)P#_!)=?iasa%=#&mUvH=U_^v<-^`i>~|K}fG zfB*mR(v7e5{)ct#`Q3LvtRD;N58wX)-JFF!d;d=XHU0hl56}4Vr;YbN{OS7ohvSBL zr0L2oWa_W))@8gPhQGaeeeJ^~C)efvbKPgTuAm>+w=t~rT;J;5FUYz#FZjxbw==xn z!uhkmLH7Q2T}1rfZ(iQ?w|>0~^YseMb>lMfl3s7x{GB+Cmjzs}t-W4(4=%javzOP4 ziU0h=KmFUk|ML(3`u(3Tcf-GaFZ_7_%dhRP7uIQ)+nV3~490pvWj-z*#&;X9mnDzC zeEWi-yglxjeXY6p`fo2EzFGIT?|xl(A%FYrH$QoMdB1i8QIbYjmw~QVNw8eTim&+tEhws-uT%Y|qvvWmsxmWew+n4W-8-TxG35@^k*UN3T>!#exocS;9 z^=jkq{+G9>|4!Ui_FwVYUkWV{z5*fJ_8dY;!dnO|knP7k_c^i=#5V?04B5@zbN}}@ zACfEsX`J5fbK5il&uAo#Ml++)45OGO0(=#>xI*1 zgKH&(n3SGIN3(}7R+vs#SI{Uq!xir_2A9fModf(a^uIu)CE4=NYZ3F58_Fd{!(3$ z55HfVJ#Vj^NU-sD!4?=&`hf^x=B(WjYncpGm5Tj@*VKe6)j%JZJhPtaz(%g4H~@75 zQz~P*3BA;!O{z+V-Pd)b*)AahS3-v39Cp==0-^XIeP29U^%qF7m6(|LPw^!HCzOR7 zL848}h_!BjL%Kxm09amfChrvX^U34ag{mZCmtX1WH49us;}rPGl#!q!JW5Cv zQsp*uULnF}lC-NNLj|41T0>$FaG6qR7n9pvK8bKgc(Q-8O40zGP<*XE&k0?C~qyA0;0 zYR41vOSB0V0ru$Pwt8B3Fi$Er_*5>{ovnmvgkGTFS2^61HZg}Y$U_;w(01i||XbJ6GM!8CZ6JN88`@yN7@vnJ} zs*MH{Ws^ocm8$yQR1e6%hvu)V$tysHe&sB$v(tBA?kJD8FE$(8O#x|Q&|!-8w2`() zr=kVsW|@>N_{pMXjcPMeaPFW*RdCRnDLBvcJ8JP`yUPb&||` zAUC+YLo}c3)cjc1$;nw%7k^ImA`g-rNS5$Fl(B0;FKr`T5y9Hv?)SR~7_F}*^TuJwb6JP_Tu&aj{riTE49iJQQWEP`O3ekN|et^f)Dl0H^PIX~Y< zF4Z8qf3FJxNLXJuS6~>~w782(QhXq3S-pBss>;R#i7P(qszxweFmot6?&CjpQht^9 zw8`wYl4FXvMI|CRKX-u?5+#4F9;)p5RDJ-fM5vdkd`>J-Lh2F^o>dw`7gtXHuIk)=P@8IFE4qFk>4!?IH8nlUtv-LUFj;NX^^LHgeL44Q-~9N_%?Q=*tD zT&ki5>4NB3K|YR8fP_a?(;(ihanG|T($pNS=YR~WYdL`a^LIQN+w^&jVqOFx7D(HQ zFVQMmK0CQl{iI*46+jaD@rl?$Pfu>z{bAMp)E)P(dfl-*?tbcZf641|3@L3Ai-GKX zkkfH7+7veuH6E(!1VUGCHaKCJpr5#bR09&b8dI?HY3z|P*AeO$G4NB2ytNDB2Uu|- zu1-0lN@OJUXzvB}=(AX_sq{fXBNHIUS4GhJqE!H|JDQmUbs8N9X5tH26G%X-|Ki#x zB&1CLEOt|z1>bv;s#hSR;KmB`jg>}VcOi*}-HuD&Wa2DcPLF}vw2~5g$wuD3=s6&r z*3!vgov^rI@aTuVAaTJlHIAro2@ML@7to_k<)ye=G?~tYm}x2|*hVh@{(#IWm(N>i zP195!$pHdTYgF|ze-i=IfI8tn=1q?dXg$_LQz^)%?9<~Qi0SQPG_{@e&I>{1GF=7` z-n(KYkYZThd+G{*bx0G6v|Xz8+i2C%jK>o01uCdX-r%2tD5SzQwv5u+1Zf#4o2cAi zd_V)KBcKnFIRz}JXs3b|tn3`25@v6NO?MUYmuS?>g!n+Oo@kR)Rip}nAh3D$AeY$9 zj0}P+0)2@|=A_S|wS^tcaZk}u21Rd?PgdtvE63?Z;DfPx^51>YWRoXroaf#Jvkm*`G zy6B4KG)?L?ZlqPN>d4aM*Ku)k>8Vt?o}{>sCQYx-B|47Lx^CZ1Z-(RE?^L2mPp;F| zESD6S0_$fhP#&?`XX<5IZv=YzI9B0IV_ZF;nc>(4q59q1>*)>qcvKBTus~6nfh~Py zXt5wvH8BOrT~l@hD@@4f#zXTmBq-wbYPJ6U4G3(&)3*TXvRCde!||oVg>~vpQE$!X ztyXzfnV;2a!V{I6=bwpY)yKSNO$tqYmsu^2{ zh7~~WMdCESqYF~&Vz|p0odC?r7!CM6f1fb{1SlwL;7N7Pa72&E84D(w7xV!B9)>k=jaT7r?*?w~b~0_>cDf0i6qy=40_fMxBEAYX##a;;*SpOc z3*FkKxRL^0suteioElwg+@0QyZ@G*ox|AK%=tHiZ>R@e0Fl#EPn=3Un!$9wOfT;uM zpUgPcHbn{Ow^8cT5?_tsQmlC?B+6D8V7XHq-YZ%F&g!M9tX z-~Sd`_N#NMA6+mO=e62sWMv72yX;+eC)2ls+beNmgP&z?T|X(}#hbuyfrd{uxc?^b z;h=lnw!vj)a0X4c-psTZ6Ugb%?c3nh4B)W+xb05oZgAIcPlsb0yq=YKfOm&iSCg(i z@6GJJX$t&J^R9}~+VF3hcvUpkfO~e@jX2I&_(m#)swUrrooH&ahV6ULfqAY$9duZ2-1P&xm5ne1!A9l*9}IyM z%qQ=Y^g@TGC$Sd&LM)f`Cshe`69EYyJ>!or@FRi#QYkoJs`Pn{e%7;({`96hZSRjk z_C~dN?zuM4mm9xKAZ0NU%S%9wE z&~KBn09~`8-!|OkYIa^f(P|lhzkt-lGVh045277F%_fl7kt-QG>yN_wBIiMOn~zT0ox3J!*gWrps%7yaJtr49YYb=P;x zHgvXiXDpTOr*_{4*9#A4M=pf_Or=`S*=eELXD-&C=Ga3rn1 z63LT)p(mquZ``}R-V-2xTPm#|ANqcj{3 zr|xLjyS3HI+AQl@huv{B{G~g#fa_(MthSFh;OO=T%NFBRSP)_i$!@a&-VdL_=!~g& zw5pfRZsfsapu1;Igs8+efG)-6k+eGd_y&**bme?x1~WQ3nxmlH(OJH+YqdYZ7i;0; z@Y&05w~>yPT2P1?#@er*acE~I4w9%wFNZVgOf(k7 zQn7Qt^rQ9jJxg{N+s||^&!;3w2Q9TM?>yrPkeRD;f&RgGIy=(ZfSR+W^g&c|Om0qC z$&Xrc+A3}n82tf#cR;nX4#i6KoV+)90&t8vvo^OFA&H&THQ;IT-(wH`2oLgCkzq~t zt$Ok~O8bgt(hpVeBFzS}pW27j=zYhBZ5)UoLs+)~O>QO@1nakV2|HPDYMB#Q3L;^^ zOUcnd82Pn|mcScDTqioFA~)n9RwnVL#<4RP`BJ1>Z!KIoxvR~7MqZ%gMv;&x*M=q&n-DvA_K(np|gCcZ0&nvQiI_5-mKiyP-A z+N|Wp7}FlIq;zVeZ4m#{#&7I*CxxPr&C{)MukE9rqi*0)Ek+c5X;(pLE9b`;q2t6NB{0ViJBsAuqVl&S5nn z2d^kf1A_yKu%>;fLUm-qVRR5;5Yl|Z`$*GnDcN02K^$RdZ_}th&)6Aa_={Y^%JZC1 zh+9j^8G%57xi6yNgt^7YQ+B#!H;Vf0>v0=B39yKV18ZU%waiN7ble8>;11qNz?+E^ z>TmbxkD$vwtcV3}J058$xS#FsQ0bsQD}Yqv@%O_7O}v{Od3IvZ!9q4({R8ool1do8 z7w`MWzJvM2s5i%ou;T^)p7yvzlUi^zys?<9og3q^_|OMMKvGY$IFCX+%%Rg`6J}$a zd2H5W<6O5MWJ<77CrKQtOSh2d0Kvr}z0X_jy!Pd%9v)Q<2Z}?;SHw*;C*rTPJAl-SNQv{mRF(h*{d+c81Btr8B$IA6h8uMh@p7uH&c#BLC)Ynt-JBTX|I4T1?}cQ!);q}n|8n(=?&g)vm$rY5`its(nFw4OLdyByHE64EjDT=jk+sL#8?y$!&egqK;;coEpumTs%*eaGv zV#xmALjkTU?aNE|x;+6|Qfs~%bcFze$p8V|3i|KpxP3!wEb>KkAjI5mbLNunIOAZyoZ5ul?NdAVn^dmjNQbj$5k2|d~#jIpRv23|Nmnv zcK^Jt?)OT9vJbgiq3_=z`CRLaTAqbC}gYJ6@@8!i(vQ1HPzWQ}`CUvgFp9 zQdR*{3`r*(AYVvcQKV@6kjT1ViLpW`@uC$SN*b?&8M0u5Sp)d)G2RMg0f~2i*$?&} zZ|0@ z7tlfc+b%5P7NBp_s+fM0)&bDm<8F`xQu6l>TOWAZ+y?7%>4ncX^hsQL-i5~7N*9`$ za=ad9bPGQBAg1Ikj&5x51)n;1tfVfl!(XQTb={?|xMnz93e$FV&-m*Y9Z(M50L7R( z3}-)~%SffoH@Ot@Cjq`=)N(IfRPZj_)3!UgX^)f*Mm{C4)snTQ|7xHx;K5k8-eiDI zCC7dckEqw1vt~_Z!E-wVRlW^BdmTKUfFJF##?x$`*2?92H47f>7o9t~-P_La5_ZOf zo_V#|D#I$tf@d`Df=w{$^}Fs>8-89|{W`15vr40ti5`xr9e4kSqL$O+<6{n^Gk=x^ zk1oU2DCq&n8ktF`W&vkX={ipmGw60Do869%A@fJ8TndU7wuxOg6d#RG=}gA$aw zql>#xw8jq;F#f9G;H`89GWvV8-9}5;2oK(VZLFX#E?C&TgJtwu-k*xVn($K8TFtp^ zv_##jc%tbw>b1Hj{8{rg_Tq*)wqtnPb^AlraHHOA*1fa(yoLoJy?LWqE6=K;Ja2gL zU$qWxdN@a3<+O(LQ48dAlnLE5-(Q`(P!**qq1355b%-iJ0L-CCE1- z61V+(_m|%E26jsKs^7l8cl52BKsg8Ls-?y_r%>`QMGGU&S+@B|hGo?5eCS@f<k!czB(-1wAgBe`j7tO|o&U7n@`G}H%zl}^kNO13}g?k?Hn!D7cYK6xt= zZS;t$`jQ>I=kH0}L7aVxyP8Hvx1n=*QJn5Qh`2})*2OA19$}}0P&PB2!tSf%#tUWq z9-l?*7;Br;*(h@xPwNWlZtmF~$82%?9x&dZQ*$!kt=Pe#rp}eY8vE~Bj)`0zC=8x( z!9E4@v%2$)k5I~;lY7T!??ue9^Db|_qNK$Hhj_k`vZ!9vC%x#?q1qZ2fhA5v;zhG( z%JQNQ|1Eqt;NSb8ks|Tm^S!(RCih8SK#exv#VRa-8$wNwF0k$+#27IcH#Gg69BfwB z-6759z&T;G*hvy=`E>TNVD2ooIX>jXAep?$qv!lvDX_URe3p0qbC6hVq7+^VJTMvo zd;3(|XxP#Wk-N{b>-B^8wzcAXt`8&+TH@uVT}k2z_=yyHPx=BHP6w0_cLx-qv5$wm zI_!F&c|6fgt4N0uE^%MmY<&GvpE5h*aOhV>7A@=|V>X}d=%%SpBY88$-%$Ov8s6hevyOom|EaCgV%|{kABra$bGqwk4@Vv9Pt5D zcoo48`pj$Fljn*{t_#j}-udY#r+U550Q*R~BsK}!5nl8pS&k7i>_?U94I@b3Hnp(P z8l<2L43N_Kr#L`pfrr-{JXWXmikHe~5xKqbpa7F69js7euwi(Yu(^|>aWqrn&3cMp zo9nQQ^^P(=>?6dNSY?Mcx0vn*I1H$Z=K=S5$%g_-&Xkxl$dXt-EM~=BjaF)04*N`G zMwIt0CAZ?8x7b9x^*%z@9XWiACl>RIZ8(%E3CiPSMAU-WenP2_j4gcd0z0?`kCJZJ zq09E{@5Rxe96WOGCgkKG&n_@AT^s*D_Pzr=j_O+2gk}gf1RO#MFqi<6y(?|gsu+xA zTe5}af@F-rz-o4PRvNt8UGMD5k}hnMkfaz^h`sS8lQe2DXAM-x_IBqX{jp z#&gkTBJ5|HT9TQjCar}i9j(o3R3%DBI<68OUd^UsG3cihctp!KC!*OFRdcdo>8s2h)VU@t(%O`5%96R}l95O@9c{^^W0^=I9oMqiNIa8i zP9)S=OACOGKo5m@tTjQFt2JxU035%?!SP!>IsQL8iDw|lb*gg_VCk3e@e*SqOpK{{ z*iFr`Oj=W0BZ+LXIYE#x(gMcvrij{_Xo_T*Hzeq5x%AZ99E)bt@klG-{E=u3y4yu! z*@&8nH?^qAn5xBEa?MTYbW1LpX@3eR8x+q z@oFN|l+3nf6Pau@na)PjX|;u%2ca#k&571*tVOaZwr`~3s*_r-7jw7(&&}^G^HT+j z&|1E6WITjLS1}zRt3fF$7d6L-XYgu`UPwScCKV98JsSGbNS6aq0X;68s0IDm~4JXlZJE;1mwE=ZVFILMgg+NilfUz0IGFc=A zN+yjSjFT#zoPD|h@*09dQTjT0jXbKj7mDFOFsg+qWs@Neh%+_g3cDyLf@+AE7pNgH5+mWM%S*>dH*qjM0G( z%1Z7_O%RsEK$uZZBl>eT%osNf(1+-&{t>bIyI814fF`~PxO1^Gz=bbG<8GN+;?pb@ zXO7Me8ZW{ML$yhb8n9%luA_ayWh3Cxu*jOxiov}zG$NLjipM&J{GELmzS@UIWhcPp z#cDo_v8%R_Qzsv1MT#qyPY4VBuSc$0>oW?jx{hxO#Oi`_RTcVMld*|NHW`b?((!mE zm&?R+@#bV)YYoJ}dFR;XWF*&0#D&(@STY?;W(m#8wlrz2v6e(jJdsGo6UlUoMp!O1 zO(e{hQ2DqPZ%U|XtvQm+1m>zy7grV7X$)5th>HfGPMP}2b=i7l0jrcLN^eGk(yfkQ z`N<`-q6&@YBgA1({PPe@>UBx+=nH^n_Ey5PL~9w=B@c@C_Ab_ZE|b&}&1#k$bpm?J#nK4^BAq1P zY4L2dxj8~kEfS93A>r8sw8qS|WTLTXI-70@^sa#I<)U$oOdttMiMEn0ZqBM1 zf|rq&mRNHlmuw33F4jPV8%;*C(O9N67FP-MOq`q>!NpcB+Dhnm3&D_d3kcSM z-WBwIB?(VRsF9dPXh#B?$&&Mm0TN|mE$PYKy9p<-uLf#k5#77Yp<*-k`A=8l!4tqln_yoN0wl^Xb-X6O_PB#Nx?> zmdwRl(rScgFU?J4t>l&2Og5QrjkjiE87I!mBLv`8GVy|5J((<^Xz09*)hm<8pJDd* z-g_(20PbX0P6=*m&hB%FgXrRzRGbll*t+ZeqXZ$<9^+J%j|S52vW`7tf9?ufrgY}@ z5{nzpKzWH-&@u+1(~3m+2_k|7Ma}iWsyS+|UsnBZfhp`i-q;cZReChscAr2Qf8Fk% zDH`SgD}&3*rlMv86!0;XlC7~3qkM?`K4|djlL92~&>3oSFtvPI+YH)48WpU_B-PGY z$#PdiG1E^kL}g*PuL?GXFfZK*h>Lz`xybfP=C^b%liL728!(Gt@mTq-WIhZ=DqLZ-73 zD6Y$vBgst#wx!Z-`%i?Ic+SqFv3dFGmYC6hss5-H0GR5JkvVw(c1XPwEY|0(lH1Gk z9&H3~kOc>dp}dvlMI=$s1J4PK_c#$Q9;E^l3{8zRpAwwAAs1;GfNoNBG76k4>-U!i zf31-pv4^x98swGhnIH%moZman{vRO?S|}-%04;P8kY;nbg+f0ipy$xlQ*0Mqpax>q z*>hk7EpOV0Bky1aErNwn&{h@$3xlTJKH+@W8w_p|GYgwhgE5dg#1EiAv?Yr09_Y_H zD0FXGv{Y$leN&hj+L~*h)k}=^aO~qRqYwqAQRi+9vuLS!9l`Oy@{oldI%;L0&Eh56 zFiR^DR#ninEM{4xH4#>c^#%s-hny zDt!vLTv)0wlrVE zdmC%{kv6o>6Pzm+D@KSnf--^WW;bi{qnWMWwP*%d)*)vo#L|OUVF9aYGS8GBF=6pl z(4M+rO))15)FAA#1)0aufy_TjxIdWcoe_1}?BfIjT1BA}fy8gKbQ{=kgd2*RkdT zT)mIhB(pM==0O2KGqR_TTogm=YhW>5W?&T08aIKV8U^l8MusccV$qrVPNTuQ@c( zoS~+t4IHM{@jjNNBB2v5rp#;K@wB9l#qBc|b{~ktu|Fcq<`0SeYePb3O0hGt*)ot; zl!GOj1vWv9=~FBs#%KZLUSq)`i&|mAF=xADl%0(_Kuzz;aGEX)bw1J zEzCoiuR^<=Qy5{m_IQQKTgU~4t*gTZ*0}wQECA_KM+Q|WsA!P|LSP9SH|muc?eidJ z0Y^BRl(Sl)QwRlxBrJ0C24Iy?+`Ktl}XYb~|dzRs+8IER?k`{E5US6oc zfzp+SX&hM1bJdp-HEh#~2xWpJ2h8iM?rDe_gS<9ugEGr}k&t!<1tL_7;q*EBLiO=n z4;Gs#yu+*)O^e4UlgN2Zg4n~%p4J&+kH9dNPGtk=cA;4bOa??eDpnzRa|$i!&NCxv z?Pd6W{Pdk#!>w;wov z|Ah|5MCEcyLHK;bIWyL`YgjF?ajnkUp0+mCR<&Z`otA{Nz|q!}R|)1_ z%2h+G6)Z0uA!PO8JJ_kV(|A|PF{!P?e*9AuF1MQKfaFau-%(K5Gn+A0e2vL?MfPHf zyOdU%1x#sEKJ!pNRn9LvQcwq>&_lT&1wGb3iPc%9 z&DnL{A)KP0D#D}aV%J4znOJK%0W-kuv7y?sIPh{vozAhF^gghz$)w`o4xyfXh#VIAcEUHI{2T0`8Ft1H!ifAR>EM1l!vD(cF z4Pz;@A>3Mog@HiWzl5rmqD_EZK_RrB!7DK#P-2lzRk0KmbJLfl84JCxc*$=Q0M9C=6O^ zomWd{H5|y@a{>c1ud^R2y{n8Su!32pBxQ+DGH}k8nC#7PBvc*1h|4_7;S@wHmnD=+ zT)bu`CbQ6*&{VyrZOt{aW+#|RQM*!IZX{7=LQxeJqH>s5Hb)tmmfzRPERGc`&>8Ne zO_ZgW+G|#vDF`8+=%%Vr1;)nT@*|QcHh8;LFCt7;ea+x+AQA^HBuMuTd`u0>kx5W{ zYL5K2>;j)F4B1Cac1{dbD?A{{_Q)h<)2J+| z=s|5Pn7#~%?*vEX7o}Izl-dHEYfXEv+s6rx6{Txq)pc#(n3ofSzvCb@Ez2k+e*FC~+O0nF&yXk-A%* zgo%?nPn2@F+PMsA)(G@=B06{^JiHbR(Yb&w+86=ofU0zsd5^ClU1f(~Hyl#R;TZWp z*7w8KDMo;V=s+a}>hPwe_^kqN=w&R4q%N;jxNq4_7|ndcEYK+d4r@zt7`2N4AK)Er zEu!WkjtXO{MWYfXES|GZs*I^%pv~uj!Xc7jOF$^!&oIJuS%o^MoK4fV9)!0IqDji* zoay$a2!XB}rWHL3Lvj)AAP8oF9!`a#f+i4Vix@JSSpaeGEKf0QU_i%_YRkYewFWDI z*pz9aul7S#I$DRDYzlc-19b_x5T3!phRK#jh8-_L$n@|`Fn)r@QPb*kkv3k7K?ZFY z_-;SZ&kES*Is#Ks$W0z5f(`Ikb)?>!9o2#&?3&5I30+#qwgD_&{RGn=48mTq0T=ao zGyA9v5bM&p5J4RRwUGg*ruC57rVCKtQ${9(`(Z8>chjwsN^7vFXi2AN;ue=J zeIZ|gi)j@wL=PfT5wCKUPLHG=-tbzDhfs+U4W=OKY(%zjU>DKW7Jh`tuiIn~D#{Xw zHA#{4LH7mygAAj8&^Q$GJyysK@p6iXc#%tR)0c##6bR9E!4AR2Zq?()&21tw62{L)*dNRl zZlaQ_QmH>4`a9T136;=Rf}2$IEY;$KR?@N3i}VAo;~cXtx4?jC6<L?O^$HU?oWQifQe}itIh6<{G$XwZO_=oxwY5{v z9jhH|&<4_}Np<{PE+$WFPGkL2wmAx`7>;7F#_9sHC9;BD?lqc~xY<~2z@>sj0A`-f zWoCabcN`P5oz>ByskBy4IYz_ga+YgtdyxwI4%jovfiaBA-<&G7**YF$Bkae9onLNGq&_0RZP1 z5yDsD9+G?NEv?!gm&mCV9zth68IRSvqV34D34&Ng;8{^-Y19i&8?*~?oF-|dE@4>_ zsbdVf8nn>s;L11~P7UZ#Zg)79FT#IE*uO`}zX@leH_TR|*JU_Rv&@n@SxL0G4wU{@ zZ?+qA4tHZDL@==Z>#LQWI#-DID$$0#5NTr!fIVj~lh93-6*lCJvQk*J!f0!o6Yc3uog5Q`a|04X%w8P9qd5w>G5F zEXY+XL&fsGdaDMzcmUu?DOL?r>;k(U?dV1hgueZt84&Ygp^A&5@eF3P)6$eoRIQ>rqC?VY8{bR`$1EwmOvCHKk7rwkgE3= z6aZb6mi)|tQ_~>SHiK!xtXrKM;j`sp$&eCcHW!!&=n=J$$@K4&S-0`@ZKx3_RHkOO zCsv&rzjN7`a`fKxk*m~azl+S6gMh8l$ZiNM2&J>spv;37Gj5AP#<{5H`wz)xGGvmWu7wd;Fp)+1m4tYwj9prKsff>dG==5^AH@uNHf7h~Yg3sKp8iRP2N7x7ILKZo2Z6Tl4mq&>$ikd8Te40uBUUlyl9#wmvABY&vE@ zF@7S!pi#wYddOo2>qlj+A)@1;j-Dkrk?HedO$pQL1CjqwCx`O+; zE6|TYQmHZ8z-|T$LS*T1n3%zwGm_$ou?7md!W0l9J($&DaOr55q84e%@Hly?nqP`3 z)U+8!5!cuFQu1ox~5 zA;oh{(ao-7@1~?Qg;b0EP4pZyfsn?sA8}X(ZFZ`z0`q21Qu&g ztex_bI@n&geJk+6g$I#6fa+(+NfWA#DlzVET0RkPlW3avgvqoi>QGTPgOs@opGUzv;GusK$riae%p)au zQ;~W}rw+k)*0i}(M}A@`@>`Avznx{%qPY%cv3k2h6fG*qXYD>#FJMmBD_bU2>RDK9 zgylJbjigd6hNSz&;PFr!Fy|u-%$lGLP$2IRQ9()uh5fU6Ez6!FHhg>$p6;&<>EYw1 z0QT1pe{JveLbHsai0@}tgc zC5p)A#utHgF$9#BUnH!`aRir}LJq-&#|FsCZ}9gyxUuJ5`$uvqc3y~Icn-s!l#3Aq zh7BPy)Z;nFHv3U30kz<96SjPW{8)!md63s??6rNLamd$>bneYH-z&Sa?NsQpD~^z& zjS-#XrOC1}V;c}W*RBntryh!i#M+q%dRTWBCxfPNtZXDy6pU_ixeD-g1eUVpZx`aVU zg8&EK2@B@Ql0IDSTLuU0Gt^i_Gj7D&NtC-KGOI*A8c$@<`qgq8YD$@s4%WrTTrP@W*J6`pSX(Q7m{ujUF&JyS7tV{q4!M~%Zipo$2ruJCeP7{#Z$4!X>^MS> z!|>$A;_*o#_z$-k%E>5yM$RRlfQ&rAw#jjlOe96yQhP2-*k$?ZI2=}y(i4z{2y!@V zheUiar|0>!4F{}Q)bb~EqHZFDkhrw0Lq}a49b1R<}*+2Hz+S^tec^4>ZPbNZ2g-=o}Ho~fi zn5_zBaCin5*(ao#bv+#m_wSj61d!$?(1sJO)((zwl}c$Th*iP_xj z-N2KDXsgp=(cRAj7#IuIXQ4SP%L46;m=FSK#;k5cF>h8MQL?dKoyi(nY!4} z!2Xzw^+dhm@ByLvqe>mE?GHuxQ`6gfJKzf_=u5sSJD!-=F)P)Zay;jb&8LxL(9xK- zT&{x-B=O(eMEytos!^}7%0MjJ6x%*mq(qO6Qkv&?HFd8 zp2x)8Qux|d2VCFc_zWm+2tjx(87OMY$RaeZ0Eu2!94APExEk5&DiLi^&7j5N!n8ytmWqO73>r(59r4*9X&vB$={~hPj8yA)qY7>cBvQz_3~gt6{8ufN@F%nz2YH z$xFw`8Vq6@AYTJiI70E0K}JD}7x%T5wZ?$yv@1iOkPxhPM@!(@3@IIp7hYuGna60eT<=!kw3WMb$+rS~hbrX&W_52^X8M&oFZIXmG|s{mOL zt*?kT1EvbG$;N=5tFTyoot149amwlTL{ZZuS*#EQX1kgvWX0b>v0Q{AC8!9B?FbEr zGfOh2X#}8^#3F=2dx-t8H7P=AQaF(mu1h2Iu$&1Y7K9WtMbeG~A*QLTS@0X9UI4h9 zFUnJ&=Bmb06D{er0eFN2H}p3sNEOJnH>+f_+#;!^!m87x<#S;TNhB-nk6|YQk29HWpgS<{8t#m}I zMOuAfX`60?ei~-z1r8>KSOMuI!vuO! zR%Ho3mT)9Lc0XsAg-mcM>AxI=WfYz+h%Uu?9h6M#6wiT`aY4eY=*H^%6|;?G(w;XD z3YHJ5B?!Nw5OFUmMVe+q4uz6w{0(d|L84u(JR~p!K*?EJaM1I@A#^6RLh1lqFfez? zE*Mbk`Vd<#6qY9>Ph#)oppn`$3mU+~;htMtB1DWaWRsJTP35_15>Dm?$`p~{0ya|H zJ5Wj|BlBcm{6nMOa2X-s>wdUKvp#@Mf#e0{PS`luMGvCH-qBy7^o>5xHo3;@*izf+ z`9WYMlvB)R^Yp@VA%rZx5y_AN+bdtC0B&xP>aqRxa-n;A=9qx2U9(NZ`n_|2TqXe`U*D3w8xUPG}#swe{> zy`bgcx)900i8ZEZryHqso{)#spkAmNDMG;OsDy^X+6duT?vogyA)GAF#gXMgzVS+K zsj)j|R;N{ZQ&4WX;3CmcpjHcPRViPUDQHYXaOrfe&Jbi}3=*TwNA*Gu^8QCC=?C`%p043)Q0&GPuy~shsL+;1%j;>47Gr0|4{o)YD9i)E zPju~4g{LNB(;Yr3us!pF0w8l+bijS-WK=*JfF+Z);Hp7NuM*piv&VA>(SI zUTrghv8r}(lbp~%re@l@&4PwE#LTg`aGOzK9jkAH1yXvyOi3gR8bmf|BC(Za3%S;U zq792eUz<(Qb_jHEJBmvsm!r7UZBt~komU-9Q+l_J@slJ1$JU^gSl zHEX&g3XaSR^Z-Dj0u6m}+6|)h^{$or=;81?AsWMiI?lfeiEjq|TznR0U_I!stuHj= zM^Q2#R7bdUPIS%XoD};Q!30?NRD;r97;$4XPZOb97tc~RJuLGB1Tv7)4dU~uVIpPpJH!m5kS0zBd6M(BVi7W56&$cN zMN12lh(s`L@5J;*Y?+d#dpYcKj!^5P5E)rv3cs3w3Z$MLzU31b=N0Q^R zBvzk+?{lpY)JT|AA1(Br!J76MiIyiKE9=!Y>^WUXh*ZmE)`Sxl&UzY&jv#a4ct1e^ z@v{QCJy2%sFM5(Z=@!{0^cTT@sWoFAtoL~Gaw3OVN}x*=Nc$9mRwrQh8{N{pbenKF z>G9L5Y^*sJo(h;SJ>9>i{AS0>hX(fI!U(sweI(Wv+^K+d{OO8I%s-J@UBN zo)SHw4PJ;c!@3Ea=reKH@_$fUKFD>{qU{B1FQWOPcLgf%qZMyJZzQX?x@Wj1hUG8h z#VJDPAGI+~3Lo$`VP8-%OH8%e30>4QX>)y)>o zb!rv#^``7rRS%WWZj2+C#fIWJddQaumpvDd%!r&Lw~#d^6RiJ?43Od2 z19}B>Sd9t&31E1|sw%oHjG3Ew)I4U|)36qOuv9c?u_wWPj-~x+p@w)%!ULX5Y~v