diff --git a/stwo_cairo_prover/crates/prover/src/cairo_air/air.rs b/stwo_cairo_prover/crates/prover/src/cairo_air/air.rs index c928cf6f..f1024965 100644 --- a/stwo_cairo_prover/crates/prover/src/cairo_air/air.rs +++ b/stwo_cairo_prover/crates/prover/src/cairo_air/air.rs @@ -24,9 +24,11 @@ use super::opcodes_air::{ use super::preprocessed::preprocessed_trace_columns; use crate::components::memory::{memory_address_to_id, memory_id_to_big}; use crate::components::range_check_vector::{ - range_check_19, range_check_4_3, range_check_7_2_5, range_check_9_9, + range_check_19, range_check_4_3, range_check_6, range_check_7_2_5, range_check_9_9, +}; +use crate::components::{ + range_check_builtin_bits_128, range_check_builtin_bits_96, verify_instruction, }; -use crate::components::{range_check_builtin_bits_128, verify_instruction}; use crate::felt::split_f252; use crate::input::ProverInput; use crate::relations; @@ -63,12 +65,14 @@ pub struct CairoClaim { pub opcodes: OpcodeClaim, pub verify_instruction: verify_instruction::Claim, pub range_check_128_builtin: Option, + pub range_check_96_builtin: Option, pub memory_address_to_id: memory_address_to_id::Claim, pub memory_id_to_value: memory_id_to_big::Claim, pub range_check_19: range_check_19::Claim, pub range_check9_9: range_check_9_9::Claim, pub range_check7_2_5: range_check_7_2_5::Claim, pub range_check4_3: range_check_4_3::Claim, + pub range_check_6: range_check_6::Claim, // ... } @@ -80,12 +84,16 @@ impl CairoClaim { if let Some(range_check_128_builtin) = &self.range_check_128_builtin { range_check_128_builtin.mix_into(channel); } + if let Some(range_check_96_builtin) = &self.range_check_96_builtin { + range_check_96_builtin.mix_into(channel); + } self.memory_address_to_id.mix_into(channel); self.memory_id_to_value.mix_into(channel); self.range_check_19.mix_into(channel); self.range_check9_9.mix_into(channel); self.range_check7_2_5.mix_into(channel); self.range_check4_3.mix_into(channel); + self.range_check_6.mix_into(channel); } pub fn log_sizes(&self) -> TreeVec> { @@ -96,6 +104,9 @@ impl CairoClaim { if let Some(range_check_128_builtin) = &self.range_check_128_builtin { log_sizes_list.push(range_check_128_builtin.log_sizes()); } + if let Some(range_check_96_builtin) = &self.range_check_96_builtin { + log_sizes_list.push(range_check_96_builtin.log_sizes()); + } log_sizes_list.append(&mut vec![ self.memory_address_to_id.log_sizes(), self.memory_id_to_value.log_sizes(), @@ -103,6 +114,7 @@ impl CairoClaim { self.range_check9_9.log_sizes(), self.range_check7_2_5.log_sizes(), self.range_check4_3.log_sizes(), + self.range_check_6.log_sizes(), ]); let mut log_sizes = TreeVec::concat_cols(log_sizes_list.into_iter()); @@ -170,12 +182,14 @@ pub struct CairoClaimGenerator { // Internal components. verify_instruction_trace_generator: verify_instruction::ClaimGenerator, range_check_128_builtin_trace_generator: Option, + range_check_96_builtin_trace_generator: Option, memory_address_to_id_trace_generator: memory_address_to_id::ClaimGenerator, memory_id_to_value_trace_generator: memory_id_to_big::ClaimGenerator, range_check_19_trace_generator: range_check_19::ClaimGenerator, range_check_9_9_trace_generator: range_check_9_9::ClaimGenerator, range_check_7_2_5_trace_generator: range_check_7_2_5::ClaimGenerator, range_check_4_3_trace_generator: range_check_4_3::ClaimGenerator, + range_check_6_trace_generator: range_check_6::ClaimGenerator, // ... } impl CairoClaimGenerator { @@ -195,6 +209,16 @@ impl CairoClaimGenerator { range_check_128_builtin_params.begin_addr as u32, ) }); + let range_check_96_builtin_trace_generator = input + .builtins_segments + .range_check_bits_96 + .map(|range_check_96_builtin_params| { + range_check_builtin_bits_96::ClaimGenerator::new( + range_check_96_builtin_params.stop_ptr + - range_check_96_builtin_params.begin_addr, + range_check_96_builtin_params.begin_addr as u32, + ) + }); let memory_address_to_id_trace_generator = memory_address_to_id::ClaimGenerator::new(&input.memory); let memory_id_to_value_trace_generator = @@ -203,6 +227,7 @@ impl CairoClaimGenerator { let range_check_9_9_trace_generator = range_check_9_9::ClaimGenerator::new(); let range_check_7_2_5_trace_generator = range_check_7_2_5::ClaimGenerator::new(); let range_check_4_3_trace_generator = range_check_4_3::ClaimGenerator::new(); + let range_check_6_trace_generator = range_check_6::ClaimGenerator::new(); // Yield public memory. for addr in input @@ -237,12 +262,14 @@ impl CairoClaimGenerator { opcodes, verify_instruction_trace_generator, range_check_128_builtin_trace_generator, + range_check_96_builtin_trace_generator, memory_address_to_id_trace_generator, memory_id_to_value_trace_generator, range_check_19_trace_generator, range_check_9_9_trace_generator, range_check_7_2_5_trace_generator, range_check_4_3_trace_generator, + range_check_6_trace_generator, } } @@ -285,6 +312,20 @@ impl CairoClaimGenerator { } else { (None, None) }; + let (range_check_96_builtin_claim, range_check_96_builtin_interaction_gen) = + if let Some(range_check_96_builtin_trace_generator) = + self.range_check_96_builtin_trace_generator + { + let (claim, interaction_gen) = range_check_96_builtin_trace_generator.write_trace( + tree_builder, + &self.memory_address_to_id_trace_generator, + &self.memory_id_to_value_trace_generator, + &self.range_check_6_trace_generator, + ); + (Some(claim), Some(interaction_gen)) + } else { + (None, None) + }; let (memory_address_to_id_claim, memory_address_to_id_interaction_gen) = self .memory_address_to_id_trace_generator .write_trace(tree_builder); @@ -303,6 +344,8 @@ impl CairoClaimGenerator { let (range_check_4_3_claim, range_check_4_3_interaction_gen) = self .range_check_4_3_trace_generator .write_trace(tree_builder); + let (range_check_6_claim, range_check_6_interaction_gen) = + self.range_check_6_trace_generator.write_trace(tree_builder); span.exit(); ( CairoClaim { @@ -310,23 +353,27 @@ impl CairoClaimGenerator { opcodes: opcodes_claim, verify_instruction: verify_instruction_claim, range_check_128_builtin: range_check_128_builtin_claim, + range_check_96_builtin: range_check_96_builtin_claim, memory_address_to_id: memory_address_to_id_claim, memory_id_to_value: memory_id_to_value_claim, range_check_19: range_check_19_claim, range_check9_9: range_check9_9_claim, range_check7_2_5: range_check_7_2_5_claim, range_check4_3: range_check_4_3_claim, + range_check_6: range_check_6_claim, }, CairoInteractionClaimGenerator { opcodes_interaction_gen, verify_instruction_interaction_gen, range_check_128_builtin_interaction_gen, + range_check_96_builtin_interaction_gen, memory_address_to_id_interaction_gen, memory_id_to_value_interaction_gen, range_check_19_interaction_gen, range_check_9_9_interaction_gen, range_check_7_2_5_interaction_gen, range_check_4_3_interaction_gen, + range_check_6_interaction_gen, }, ) } @@ -337,12 +384,15 @@ pub struct CairoInteractionClaimGenerator { verify_instruction_interaction_gen: verify_instruction::InteractionClaimGenerator, range_check_128_builtin_interaction_gen: Option, + range_check_96_builtin_interaction_gen: + Option, memory_address_to_id_interaction_gen: memory_address_to_id::InteractionClaimGenerator, memory_id_to_value_interaction_gen: memory_id_to_big::InteractionClaimGenerator, range_check_19_interaction_gen: range_check_19::InteractionClaimGenerator, range_check_9_9_interaction_gen: range_check_9_9::InteractionClaimGenerator, range_check_7_2_5_interaction_gen: range_check_7_2_5::InteractionClaimGenerator, range_check_4_3_interaction_gen: range_check_4_3::InteractionClaimGenerator, + range_check_6_interaction_gen: range_check_6::InteractionClaimGenerator, // ... } impl CairoInteractionClaimGenerator { @@ -376,6 +426,16 @@ impl CairoInteractionClaimGenerator { &interaction_elements.memory_id_to_value, ) }); + let range_check_96_builtin_interaction_claim = self + .range_check_96_builtin_interaction_gen + .map(|range_check_96_builtin_interaction_gen| { + range_check_96_builtin_interaction_gen.write_interaction_trace( + tree_builder, + &interaction_elements.memory_address_to_id, + &interaction_elements.memory_id_to_value, + &interaction_elements.range_check_6, + ) + }); let memory_address_to_id_interaction_claim = self .memory_address_to_id_interaction_gen .write_interaction_trace(tree_builder, &interaction_elements.memory_address_to_id); @@ -398,17 +458,22 @@ impl CairoInteractionClaimGenerator { let range_check_4_3_interaction_claim = self .range_check_4_3_interaction_gen .write_interaction_trace(tree_builder, &interaction_elements.range_check_4_3); + let range_check_6_interaction_claim = self + .range_check_6_interaction_gen + .write_interaction_trace(tree_builder, &interaction_elements.range_check_6); CairoInteractionClaim { opcodes: opcodes_interaction_claims, verify_instruction: verify_instruction_interaction_claim, range_check_128_builtin: range_check_128_builtin_interaction_claim, + range_check_96_builtin: range_check_96_builtin_interaction_claim, memory_address_to_id: memory_address_to_id_interaction_claim, memory_id_to_value: memory_id_to_value_interaction_claim, range_check_19: range_check_19_interaction_claim, range_check_9_9: range_check9_9_interaction_claim, range_check_7_2_5: range_check_7_2_5_interaction_claim, range_check_4_3: range_check_4_3_interaction_claim, + range_check_6: range_check_6_interaction_claim, } } } @@ -422,6 +487,7 @@ pub struct CairoInteractionElements { pub range_check_9_9: relations::RangeCheck_9_9, pub range_check_7_2_5: relations::RangeCheck_7_2_5, pub range_check_4_3: relations::RangeCheck_4_3, + pub range_check_6: relations::RangeCheck_6, // ... } impl CairoInteractionElements { @@ -435,6 +501,7 @@ impl CairoInteractionElements { range_check_9_9: relations::RangeCheck_9_9::draw(channel), range_check_7_2_5: relations::RangeCheck_7_2_5::draw(channel), range_check_4_3: relations::RangeCheck_4_3::draw(channel), + range_check_6: relations::RangeCheck_6::draw(channel), } } } @@ -444,12 +511,14 @@ pub struct CairoInteractionClaim { pub opcodes: OpcodeInteractionClaim, pub verify_instruction: verify_instruction::InteractionClaim, pub range_check_128_builtin: Option, + pub range_check_96_builtin: Option, pub memory_address_to_id: memory_address_to_id::InteractionClaim, pub memory_id_to_value: memory_id_to_big::InteractionClaim, pub range_check_19: range_check_19::InteractionClaim, pub range_check_9_9: range_check_9_9::InteractionClaim, pub range_check_7_2_5: range_check_7_2_5::InteractionClaim, pub range_check_4_3: range_check_4_3::InteractionClaim, + pub range_check_6: range_check_6::InteractionClaim, } impl CairoInteractionClaim { pub fn mix_into(&self, channel: &mut impl Channel) { @@ -458,12 +527,16 @@ impl CairoInteractionClaim { if let Some(range_check_128_builtin) = &self.range_check_128_builtin { range_check_128_builtin.mix_into(channel); } + if let Some(range_check_96_builtin) = &self.range_check_96_builtin { + range_check_96_builtin.mix_into(channel); + } self.memory_address_to_id.mix_into(channel); self.memory_id_to_value.mix_into(channel); self.range_check_19.mix_into(channel); self.range_check_9_9.mix_into(channel); self.range_check_7_2_5.mix_into(channel); self.range_check_4_3.mix_into(channel); + self.range_check_6.mix_into(channel); } } @@ -482,6 +555,9 @@ pub fn lookup_sum( if let Some(range_check_128_builtin) = &interaction_claim.range_check_128_builtin { sum += range_check_128_builtin.logup_sums.0; } + if let Some(range_check_96_builtin) = &interaction_claim.range_check_96_builtin { + sum += range_check_96_builtin.logup_sums.0; + } sum += interaction_claim.memory_address_to_id.claimed_sum; sum += interaction_claim.memory_id_to_value.big_claimed_sum; sum += interaction_claim.memory_id_to_value.small_claimed_sum; @@ -489,6 +565,7 @@ pub fn lookup_sum( sum += interaction_claim.range_check_9_9.claimed_sum; sum += interaction_claim.range_check_7_2_5.claimed_sum; sum += interaction_claim.range_check_4_3.claimed_sum; + sum += interaction_claim.range_check_6.claimed_sum; sum } @@ -496,6 +573,7 @@ pub struct CairoComponents { opcodes: OpcodeComponents, verify_instruction: verify_instruction::Component, range_check_128_builtin: Option, + range_check_96_builtin: Option, memory_address_to_id: memory_address_to_id::Component, memory_id_to_value: ( memory_id_to_big::BigComponent, @@ -505,6 +583,7 @@ pub struct CairoComponents { range_check9_9: range_check_9_9::Component, range_check7_2_5: range_check_7_2_5::Component, range_check4_3: range_check_4_3::Component, + range_check_6: range_check_6::Component, // ... } impl CairoComponents { @@ -561,6 +640,27 @@ impl CairoComponents { .logup_sums, ) }); + let range_check_96_builtin_component = + cairo_claim + .range_check_96_builtin + .map(|range_check_96_builtin| { + range_check_builtin_bits_96::Component::new( + tree_span_provider, + range_check_builtin_bits_96::Eval { + claim: range_check_96_builtin, + memory_address_to_id_lookup_elements: interaction_elements + .memory_address_to_id + .clone(), + memory_id_to_big_lookup_elements: interaction_elements + .memory_id_to_value + .clone(), + range_check_6_lookup_elements: interaction_elements + .range_check_6 + .clone(), + }, + interaction_claim.range_check_96_builtin.unwrap().logup_sums, + ) + }); let memory_address_to_id_component = memory_address_to_id::Component::new( tree_span_provider, memory_address_to_id::Eval::new( @@ -619,10 +719,16 @@ impl CairoComponents { range_check_4_3::Eval::new(interaction_elements.range_check_4_3.clone()), (interaction_claim.range_check_4_3.claimed_sum, None), ); + let range_check_6_component = range_check_6::Component::new( + tree_span_provider, + range_check_6::Eval::new(interaction_elements.range_check_6.clone()), + (interaction_claim.range_check_6.claimed_sum, None), + ); Self { opcodes: opcode_components, verify_instruction: verify_instruction_component, range_check_128_builtin: range_check_128_builtin_component, + range_check_96_builtin: range_check_96_builtin_component, memory_address_to_id: memory_address_to_id_component, memory_id_to_value: ( memory_id_to_value_component, @@ -632,6 +738,7 @@ impl CairoComponents { range_check9_9: range_check9_9_component, range_check7_2_5: range_check_7_2_5_component, range_check4_3: range_check_4_3_component, + range_check_6: range_check_6_component, } } @@ -640,6 +747,9 @@ impl CairoComponents { if let Some(range_check_128_builtin) = &self.range_check_128_builtin { provers.push(range_check_128_builtin as &dyn ComponentProver); } + if let Some(range_check_96_builtin) = &self.range_check_96_builtin { + provers.push(range_check_96_builtin as &dyn ComponentProver); + } provers.extend(&[ &self.memory_address_to_id as &dyn ComponentProver, &self.memory_id_to_value.0 as &dyn ComponentProver, @@ -648,6 +758,7 @@ impl CairoComponents { &self.range_check9_9 as &dyn ComponentProver, &self.range_check7_2_5 as &dyn ComponentProver, &self.range_check4_3 as &dyn ComponentProver, + &self.range_check_6 as &dyn ComponentProver, ]); chain!(self.opcodes.provers(), provers,).collect() } @@ -676,6 +787,13 @@ impl std::fmt::Display for CairoComponents { indented_component_display(range_check_128_builtin) )?; } + if let Some(range_check_96_builtin) = &self.range_check_96_builtin { + writeln!( + f, + "RangeCheck96Builtin: {}", + indented_component_display(range_check_96_builtin) + )?; + } writeln!( f, "MemoryAddressToId: {}", @@ -711,6 +829,11 @@ impl std::fmt::Display for CairoComponents { "RangeCheck4_3: {}", indented_component_display(&self.range_check4_3) )?; + writeln!( + f, + "RangeCheck6: {}", + indented_component_display(&self.range_check_6) + )?; Ok(()) } } diff --git a/stwo_cairo_prover/crates/prover/src/cairo_air/debug_tools.rs b/stwo_cairo_prover/crates/prover/src/cairo_air/debug_tools.rs index 888da1d8..04b07244 100644 --- a/stwo_cairo_prover/crates/prover/src/cairo_air/debug_tools.rs +++ b/stwo_cairo_prover/crates/prover/src/cairo_air/debug_tools.rs @@ -21,8 +21,8 @@ use crate::components::{ jnz_opcode, jnz_opcode_dst_base_fp, jnz_opcode_taken, jnz_opcode_taken_dst_base_fp, jump_opcode, jump_opcode_double_deref, jump_opcode_rel, jump_opcode_rel_imm, memory_address_to_id, memory_id_to_big, mul_opcode, mul_opcode_imm, range_check_19, - range_check_4_3, range_check_7_2_5, range_check_9_9, range_check_builtin_bits_128, ret_opcode, - verify_instruction, + range_check_4_3, range_check_6, range_check_7_2_5, range_check_9_9, + range_check_builtin_bits_128, range_check_builtin_bits_96, ret_opcode, verify_instruction, }; use crate::felt::split_f252; use crate::relations; @@ -485,6 +485,22 @@ where ); } + if let Some(range_check_96_builtin) = claim.range_check_96_builtin { + entries.extend( + RelationTrackerComponent::new( + tree_span_provider, + range_check_builtin_bits_96::Eval { + claim: range_check_96_builtin, + memory_address_to_id_lookup_elements: relations::MemoryAddressToId::dummy(), + memory_id_to_big_lookup_elements: relations::MemoryIdToBig::dummy(), + range_check_6_lookup_elements: relations::RangeCheck_6::dummy(), + }, + range_check_96_builtin.n_rows, + ) + .entries(trace), + ); + } + // Memory. entries.extend( RelationTrackerComponent::new( @@ -563,6 +579,16 @@ where ) .entries(trace), ); + entries.extend( + RelationTrackerComponent::new( + tree_span_provider, + range_check_6::Eval { + lookup_elements: relations::RangeCheck_6::dummy(), + }, + 1 << 6, + ) + .entries(trace), + ); // Public data. claim diff --git a/stwo_cairo_prover/crates/prover/src/components/mod.rs b/stwo_cairo_prover/crates/prover/src/components/mod.rs index 28e9590d..3bae603c 100644 --- a/stwo_cairo_prover/crates/prover/src/components/mod.rs +++ b/stwo_cairo_prover/crates/prover/src/components/mod.rs @@ -22,6 +22,7 @@ pub mod jump_opcode_rel; pub mod jump_opcode_rel_imm; pub mod memory; pub mod range_check_builtin_bits_128; +pub mod range_check_builtin_bits_96; pub mod range_check_vector; pub mod ret_opcode; pub mod utils; @@ -32,4 +33,6 @@ pub mod mul_opcode; pub mod mul_opcode_imm; pub use memory::{memory_address_to_id, memory_id_to_big}; -pub use range_check_vector::{range_check_19, range_check_4_3, range_check_7_2_5, range_check_9_9}; +pub use range_check_vector::{ + range_check_19, range_check_4_3, range_check_6, range_check_7_2_5, range_check_9_9, +}; diff --git a/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/component.rs b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/component.rs new file mode 100644 index 00000000..206a36bf --- /dev/null +++ b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/component.rs @@ -0,0 +1,137 @@ +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +use num_traits::{One, Zero}; +use serde::{Deserialize, Serialize}; +use stwo_cairo_serialize::CairoSerialize; +use stwo_prover::constraint_framework::logup::{LogupAtRow, LogupSums, LookupElements}; +use stwo_prover::constraint_framework::{ + EvalAtRow, FrameworkComponent, FrameworkEval, RelationEntry, +}; +use stwo_prover::core::backend::simd::m31::LOG_N_LANES; +use stwo_prover::core::channel::Channel; +use stwo_prover::core::fields::m31::M31; +use stwo_prover::core::fields::qm31::SecureField; +use stwo_prover::core::fields::secure_column::SECURE_EXTENSION_DEGREE; +use stwo_prover::core::pcs::TreeVec; + +use crate::cairo_air::preprocessed::{PreProcessedColumn, Seq}; +use crate::relations; + +pub struct Eval { + pub claim: Claim, + pub memory_address_to_id_lookup_elements: relations::MemoryAddressToId, + pub memory_id_to_big_lookup_elements: relations::MemoryIdToBig, + pub range_check_6_lookup_elements: relations::RangeCheck_6, +} + +#[derive(Copy, Clone, Serialize, Deserialize, CairoSerialize)] +pub struct Claim { + pub n_rows: usize, + pub range_check96_builtin_segment_start: u32, +} +impl Claim { + pub fn log_sizes(&self) -> TreeVec> { + let log_size = std::cmp::max(self.n_rows.next_power_of_two().ilog2(), LOG_N_LANES); + let trace_log_sizes = vec![log_size; 12]; + let interaction_log_sizes = vec![log_size; SECURE_EXTENSION_DEGREE * 2]; + let preprocessed_log_sizes = vec![log_size]; + TreeVec::new(vec![ + preprocessed_log_sizes, + trace_log_sizes, + interaction_log_sizes, + ]) + } + + pub fn mix_into(&self, channel: &mut impl Channel) { + channel.mix_u64(self.n_rows as u64); + channel.mix_u64(self.range_check96_builtin_segment_start as u64); + } +} + +#[derive(Copy, Clone, Serialize, Deserialize, CairoSerialize)] +pub struct InteractionClaim { + pub logup_sums: LogupSums, +} +impl InteractionClaim { + pub fn mix_into(&self, channel: &mut impl Channel) { + let (total_sum, claimed_sum) = self.logup_sums; + channel.mix_felts(&[total_sum]); + if let Some(claimed_sum) = claimed_sum { + channel.mix_felts(&[claimed_sum.0]); + channel.mix_u64(claimed_sum.1 as u64); + } + } +} + +pub type Component = FrameworkComponent; + +impl FrameworkEval for Eval { + fn log_size(&self) -> u32 { + std::cmp::max(self.claim.n_rows.next_power_of_two().ilog2(), LOG_N_LANES) + } + + fn max_constraint_log_degree_bound(&self) -> u32 { + self.log_size() + 1 + } + + #[allow(unused_parens)] + #[allow(clippy::double_parens)] + #[allow(non_snake_case)] + fn evaluate(&self, mut eval: E) -> E { + let seq = + eval.get_preprocessed_column(PreProcessedColumn::Seq(Seq::new(self.log_size())).id()); + let value_id_col0 = eval.next_trace_mask(); + let value_limb_0_col1 = eval.next_trace_mask(); + let value_limb_1_col2 = eval.next_trace_mask(); + let value_limb_2_col3 = eval.next_trace_mask(); + let value_limb_3_col4 = eval.next_trace_mask(); + let value_limb_4_col5 = eval.next_trace_mask(); + let value_limb_5_col6 = eval.next_trace_mask(); + let value_limb_6_col7 = eval.next_trace_mask(); + let value_limb_7_col8 = eval.next_trace_mask(); + let value_limb_8_col9 = eval.next_trace_mask(); + let value_limb_9_col10 = eval.next_trace_mask(); + let value_limb_10_col11 = eval.next_trace_mask(); + + // Read Positive Num Bits 96. + + eval.add_to_relation(RelationEntry::new( + &self.memory_address_to_id_lookup_elements, + E::EF::one(), + &[ + (E::F::from(M31::from(self.claim.range_check96_builtin_segment_start)) + seq), + value_id_col0.clone(), + ], + )); + + // Range Check Last Limb Bits In Ms Limb 6. + + eval.add_to_relation(RelationEntry::new( + &self.range_check_6_lookup_elements, + E::EF::one(), + &[value_limb_10_col11.clone()], + )); + + eval.add_to_relation(RelationEntry::new( + &self.memory_id_to_big_lookup_elements, + E::EF::one(), + &[ + value_id_col0.clone(), + value_limb_0_col1.clone(), + value_limb_1_col2.clone(), + value_limb_2_col3.clone(), + value_limb_3_col4.clone(), + value_limb_4_col5.clone(), + value_limb_5_col6.clone(), + value_limb_6_col7.clone(), + value_limb_7_col8.clone(), + value_limb_8_col9.clone(), + value_limb_9_col10.clone(), + value_limb_10_col11.clone(), + ], + )); + + eval.finalize_logup_in_pairs(); + eval + } +} diff --git a/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/mod.rs b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/mod.rs new file mode 100644 index 00000000..6a1bf663 --- /dev/null +++ b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/mod.rs @@ -0,0 +1,5 @@ +pub mod component; +pub mod prover; + +pub use component::{Claim, Component, Eval, InteractionClaim}; +pub use prover::{ClaimGenerator, InteractionClaimGenerator}; diff --git a/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/prover.rs b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/prover.rs new file mode 100644 index 00000000..5951197a --- /dev/null +++ b/stwo_cairo_prover/crates/prover/src/components/range_check_builtin_bits_96/prover.rs @@ -0,0 +1,275 @@ +#![allow(unused_parens)] +#![allow(unused_imports)] +use std::iter::zip; + +use itertools::{chain, zip_eq, Itertools}; +use num_traits::{One, Zero}; +use prover_types::cpu::*; +use prover_types::simd::*; +use rayon::iter::{ + IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, +}; +use stwo_air_utils::trace::component_trace::ComponentTrace; +use stwo_air_utils_derive::{IterMut, ParIterMut, Uninitialized}; +use stwo_prover::constraint_framework::logup::LogupTraceGenerator; +use stwo_prover::constraint_framework::Relation; +use stwo_prover::core::air::Component; +use stwo_prover::core::backend::simd::column::BaseColumn; +use stwo_prover::core::backend::simd::conversion::Unpack; +use stwo_prover::core::backend::simd::m31::{PackedM31, LOG_N_LANES, N_LANES}; +use stwo_prover::core::backend::simd::qm31::PackedQM31; +use stwo_prover::core::backend::simd::SimdBackend; +use stwo_prover::core::backend::{BackendForChannel, Col, Column}; +use stwo_prover::core::channel::{Channel, MerkleChannel}; +use stwo_prover::core::fields::m31::M31; +use stwo_prover::core::fields::FieldExpOps; +use stwo_prover::core::pcs::TreeBuilder; +use stwo_prover::core::poly::circle::{CanonicCoset, CircleEvaluation}; +use stwo_prover::core::poly::BitReversedOrder; +use stwo_prover::core::utils::{ + bit_reverse_coset_to_circle_domain_order, bit_reverse_index, coset_index_to_circle_domain_index, +}; + +use super::component::{Claim, InteractionClaim}; +use crate::cairo_air::preprocessed::{PreProcessedColumn, Seq}; +use crate::components::{memory_address_to_id, memory_id_to_big, range_check_6}; +use crate::relations; + +const N_TRACE_COLUMNS: usize = 12; + +#[derive(Default)] +pub struct ClaimGenerator { + pub n_rows: usize, + pub range_check96_builtin_segment_start: u32, +} +impl ClaimGenerator { + pub fn new(n_rows: usize, range_check96_builtin_segment_start: u32) -> Self { + Self { + n_rows, + range_check96_builtin_segment_start, + } + } + + pub fn write_trace( + self, + tree_builder: &mut TreeBuilder<'_, '_, SimdBackend, MC>, + memory_address_to_id_state: &memory_address_to_id::ClaimGenerator, + memory_id_to_big_state: &memory_id_to_big::ClaimGenerator, + range_check_6_state: &range_check_6::ClaimGenerator, + ) -> (Claim, InteractionClaimGenerator) + where + SimdBackend: BackendForChannel, + { + let n_rows = self.n_rows; + assert_ne!(n_rows, 0); + assert!(n_rows.is_power_of_two()); + + let (trace, lookup_data) = write_trace_simd( + n_rows, + memory_address_to_id_state, + memory_id_to_big_state, + range_check_6_state, + self.range_check96_builtin_segment_start, + ); + + tree_builder.extend_evals(trace.to_evals()); + + ( + Claim { + n_rows, + range_check96_builtin_segment_start: self.range_check96_builtin_segment_start, + }, + InteractionClaimGenerator { + n_rows, + lookup_data, + }, + ) + } +} + +#[allow(clippy::useless_conversion)] +#[allow(unused_variables)] +#[allow(clippy::double_parens)] +#[allow(non_snake_case)] +fn write_trace_simd( + n_rows: usize, + memory_address_to_id_state: &memory_address_to_id::ClaimGenerator, + memory_id_to_big_state: &memory_id_to_big::ClaimGenerator, + range_check_6_state: &range_check_6::ClaimGenerator, + range_check96_builtin_segment_start: u32, +) -> (ComponentTrace, LookupData) { + let log_size = n_rows.next_power_of_two().ilog2(); + let log_n_packed_rows = log_size - LOG_N_LANES; + let (mut trace, mut lookup_data) = unsafe { + ( + ComponentTrace::::uninitialized(log_size), + LookupData::uninitialized(log_n_packed_rows), + ) + }; + + let M31_0 = PackedM31::broadcast(M31::from(0)); + + trace + .par_iter_mut() + .enumerate() + .zip(lookup_data.par_iter_mut()) + .for_each(|((row_index, row), lookup_data)| { + let seq = PreProcessedColumn::Seq(Seq::new(log_size)).packed_at(row_index); + + // Read Positive Num Bits 96. + + let memory_address_to_id_value_tmp_fd7ee_0 = memory_address_to_id_state.deduce_output( + ((PackedM31::broadcast(M31::from(range_check96_builtin_segment_start))) + (seq)), + ); + let memory_id_to_big_value_tmp_fd7ee_1 = + memory_id_to_big_state.deduce_output(memory_address_to_id_value_tmp_fd7ee_0); + let value_id_col0 = memory_address_to_id_value_tmp_fd7ee_0; + *row[0] = value_id_col0; + let memory_address_to_id_inputs_0 = + ((PackedM31::broadcast(M31::from(range_check96_builtin_segment_start))) + (seq)) + .unpack(); + *lookup_data.memory_address_to_id_0 = [ + ((PackedM31::broadcast(M31::from(range_check96_builtin_segment_start))) + (seq)), + value_id_col0, + ]; + let value_limb_0_col1 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(0); + *row[1] = value_limb_0_col1; + let value_limb_1_col2 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(1); + *row[2] = value_limb_1_col2; + let value_limb_2_col3 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(2); + *row[3] = value_limb_2_col3; + let value_limb_3_col4 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(3); + *row[4] = value_limb_3_col4; + let value_limb_4_col5 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(4); + *row[5] = value_limb_4_col5; + let value_limb_5_col6 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(5); + *row[6] = value_limb_5_col6; + let value_limb_6_col7 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(6); + *row[7] = value_limb_6_col7; + let value_limb_7_col8 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(7); + *row[8] = value_limb_7_col8; + let value_limb_8_col9 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(8); + *row[9] = value_limb_8_col9; + let value_limb_9_col10 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(9); + *row[10] = value_limb_9_col10; + let value_limb_10_col11 = memory_id_to_big_value_tmp_fd7ee_1.get_m31(10); + *row[11] = value_limb_10_col11; + + // Range Check Last Limb Bits In Ms Limb 6. + + let range_check_6_inputs_0 = [value_limb_10_col11].unpack(); + *lookup_data.range_check_6_0 = [value_limb_10_col11]; + + let memory_id_to_big_inputs_0 = value_id_col0.unpack(); + *lookup_data.memory_id_to_big_0 = [ + value_id_col0, + value_limb_0_col1, + value_limb_1_col2, + value_limb_2_col3, + value_limb_3_col4, + value_limb_4_col5, + value_limb_5_col6, + value_limb_6_col7, + value_limb_7_col8, + value_limb_8_col9, + value_limb_9_col10, + value_limb_10_col11, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + M31_0, + ]; + + // Add sub-components inputs. + #[allow(clippy::needless_range_loop)] + for i in 0..N_LANES { + if bit_reverse_index( + coset_index_to_circle_domain_index(row_index * N_LANES + i, log_size), + log_size, + ) < n_rows + { + memory_address_to_id_state.add_input(memory_address_to_id_inputs_0[i]); + range_check_6_state.add_input(range_check_6_inputs_0[i]); + memory_id_to_big_state.add_input(memory_id_to_big_inputs_0[i]); + } + } + }); + + (trace, lookup_data) +} + +#[derive(Uninitialized, IterMut, ParIterMut)] +struct LookupData { + memory_address_to_id_0: Vec<[PackedM31; 2]>, + memory_id_to_big_0: Vec<[PackedM31; 29]>, + range_check_6_0: Vec<[PackedM31; 1]>, +} + +pub struct InteractionClaimGenerator { + n_rows: usize, + lookup_data: LookupData, +} +impl InteractionClaimGenerator { + pub fn write_interaction_trace( + self, + tree_builder: &mut TreeBuilder<'_, '_, SimdBackend, MC>, + memory_address_to_id: &relations::MemoryAddressToId, + memory_id_to_big: &relations::MemoryIdToBig, + range_check_6: &relations::RangeCheck_6, + ) -> InteractionClaim + where + SimdBackend: BackendForChannel, + { + let log_size = std::cmp::max(self.n_rows.next_power_of_two().ilog2(), LOG_N_LANES); + let mut logup_gen = LogupTraceGenerator::new(log_size); + + // Sum logup terms in pairs. + let mut col_gen = logup_gen.new_col(); + for (i, (values0, values1)) in zip( + &self.lookup_data.memory_address_to_id_0, + &self.lookup_data.range_check_6_0, + ) + .enumerate() + { + let denom0: PackedQM31 = memory_address_to_id.combine(values0); + let denom1: PackedQM31 = range_check_6.combine(values1); + col_gen.write_frac(i, denom0 + denom1, denom0 * denom1); + } + col_gen.finalize_col(); + + // Sum last logup term. + let mut col_gen = logup_gen.new_col(); + for (i, values) in self.lookup_data.memory_id_to_big_0.iter().enumerate() { + let denom = memory_id_to_big.combine(values); + col_gen.write_frac(i, PackedQM31::one(), denom); + } + col_gen.finalize_col(); + + let (trace, total_sum, claimed_sum) = if self.n_rows == 1 << log_size { + let (trace, claimed_sum) = logup_gen.finalize_last(); + (trace, claimed_sum, None) + } else { + let (trace, [total_sum, claimed_sum]) = + logup_gen.finalize_at([(1 << log_size) - 1, self.n_rows - 1]); + (trace, total_sum, Some((claimed_sum, self.n_rows - 1))) + }; + tree_builder.extend_evals(trace); + + InteractionClaim { + logup_sums: (total_sum, claimed_sum), + } + } +} diff --git a/stwo_cairo_prover/crates/prover/src/components/range_check_vector/mod.rs b/stwo_cairo_prover/crates/prover/src/components/range_check_vector/mod.rs index 67b7a294..f9f6b254 100644 --- a/stwo_cairo_prover/crates/prover/src/components/range_check_vector/mod.rs +++ b/stwo_cairo_prover/crates/prover/src/components/range_check_vector/mod.rs @@ -70,6 +70,7 @@ generate_range_check_code!([19]); generate_range_check_code!([9, 9]); generate_range_check_code!([7, 2, 5]); generate_range_check_code!([4, 3]); +generate_range_check_code!([6]); #[cfg(test)] mod tests {