diff --git a/air/src/ace.rs b/air/src/ace.rs index 22183128c5..d0d86e1fed 100644 --- a/air/src/ace.rs +++ b/air/src/ace.rs @@ -49,7 +49,8 @@ pub enum MessageElement { pub enum ProductFactor { /// Claimed final value of an auxiliary trace column, by column index. BusBoundary(usize), - /// A bus message computed from its elements as `bus_prefix[bus] + sum(beta^i * elements[i])`. + /// A bus message computed from its elements as the bus-specific prefix plus + /// `sum(beta^i * elements[i])` (same convention as [`trace::Challenges::encode`]). /// The first field is the bus type index (see `trace::bus_types`). Message(usize, Vec), /// Multiset product reduced from variable-length public inputs, by group index. @@ -157,9 +158,9 @@ where sum } -/// Encode a bus message as `bus_prefix[bus] + sum(beta^i * elements[i])`. +/// Encode a bus message as the bus-specific prefix plus `sum(beta^i * elements[i])`. /// -/// The bus prefix provides domain separation: `bus_prefix[bus] = alpha + (bus+1) * gamma` +/// The bus prefix provides domain separation: `alpha + (bus+1) * gamma` for each bus index. /// where `gamma = beta^MAX_MESSAGE_WIDTH`. This matches [`trace::Challenges::encode`]. fn encode_bus_message( builder: &mut DagBuilder, diff --git a/air/src/constraints/range/bus.rs b/air/src/constraints/range/bus.rs index 06086166e6..270fe0d2c3 100644 --- a/air/src/constraints/range/bus.rs +++ b/air/src/constraints/range/bus.rs @@ -18,7 +18,7 @@ use miden_crypto::stark::air::{ExtensionBuilder, WindowAccess}; use crate::{ MainCols, MidenAirBuilder, constraints::{chiplets::selectors::ChipletSelectors, utils::BoolNot}, - trace::{Challenges, bus_types::RANGE_CHECK_BUS, range}, + trace::{Challenges, range}, }; // ENTRY POINTS @@ -56,7 +56,7 @@ pub fn enforce_bus( let b_local = aux_local[range::B_RANGE_COL_IDX]; let b_next = aux_next[range::B_RANGE_COL_IDX]; - let alpha = &challenges.bus_prefix[RANGE_CHECK_BUS]; + let alpha = &challenges.bus_prefix.range_check_bus; // Denominators for LogUp let mem = local.memory(); diff --git a/air/src/trace/challenges.rs b/air/src/trace/challenges.rs index 56d689ae8f..0f86c14f88 100644 --- a/air/src/trace/challenges.rs +++ b/air/src/trace/challenges.rs @@ -1,7 +1,7 @@ //! Unified bus challenge encoding with per-bus domain separation. //! //! Provides [`Challenges`], a single struct for encoding multiset/LogUp bus messages -//! as `bus_prefix[bus] + `. Each bus interaction type gets a unique +//! as `bus_prefix.prefix_for_bus(bus) + `. Each bus interaction type gets a unique //! prefix to ensure domain separation. //! //! This type is used by: @@ -17,14 +17,107 @@ use core::ops::{AddAssign, Mul}; use miden_core::field::PrimeCharacteristicRing; -use super::{MAX_MESSAGE_WIDTH, bus_types::NUM_BUS_TYPES}; +use super::{ + MAX_MESSAGE_WIDTH, + bus_message::{ + ADDR_IDX, CAPACITY_COEFF_END_IDX, CAPACITY_START_IDX, LABEL_IDX, NODE_INDEX_IDX, + STATE_COEFF_END_IDX, STATE_START_IDX, + }, + bus_types::{ + ACE_WIRING_BUS, BLOCK_HASH_TABLE, BLOCK_STACK_TABLE, CHIPLETS_BUS, + LOG_PRECOMPILE_TRANSCRIPT, NUM_BUS_TYPES, OP_GROUP_TABLE, RANGE_CHECK_BUS, SIBLING_TABLE, + STACK_OVERFLOW_TABLE, + }, +}; -/// Encodes multiset/LogUp contributions as **bus_prefix\[bus\] + \**. +/// Precomputed powers `beta^0 .. beta^(MAX_MESSAGE_WIDTH-1)` for bus message dot products. +/// +/// Layout matches [`super::bus_message`]. +#[derive(Clone, Debug)] +pub struct BetaPowers { + pub label: EF, + pub addr: EF, + pub node_index: EF, + pub state: [EF; 8], + pub capacity: [EF; 4], + pub beta_pow_15: EF, +} + +impl BetaPowers { + /// Coefficient `beta^i` for `i < MAX_MESSAGE_WIDTH` (see [`super::bus_message`] indices). + #[inline(always)] + pub fn at(&self, idx: usize) -> &EF { + match idx { + LABEL_IDX => &self.label, + ADDR_IDX => &self.addr, + NODE_INDEX_IDX => &self.node_index, + STATE_START_IDX..=STATE_COEFF_END_IDX => &self.state[idx - STATE_START_IDX], + CAPACITY_START_IDX..=CAPACITY_COEFF_END_IDX => &self.capacity[idx - CAPACITY_START_IDX], + x if x == MAX_MESSAGE_WIDTH - 1 => &self.beta_pow_15, + _ => unreachable!("beta power index {idx} out of range (< {MAX_MESSAGE_WIDTH})"), + } + } + + /// `beta^CAPACITY_DOMAIN_IDX` — second capacity slot (e.g. control-block `op_code`). + #[inline(always)] + pub fn capacity_domain(&self) -> &EF { + &self.capacity[super::bus_message::CAPACITY_DOMAIN_IDX - CAPACITY_START_IDX] + } + + /// Dense `beta^3 ..= beta^14`: Hasher rate coefficients then capacity (12 elements). + #[inline(always)] + pub fn sponge_state(&self) -> [EF; 12] { + core::array::from_fn(|i| { + if i < 8 { + self.state[i].clone() + } else { + self.capacity[i - 8].clone() + } + }) + } +} + +/// Per-bus domain separation constants: each field is `alpha + (bus_const + 1) * gamma` +/// where `gamma = beta^MAX_MESSAGE_WIDTH` (see [`Challenges::new`]). +/// +/// Field order matches [`super::bus_types`]. +#[derive(Clone, Debug)] +pub struct BusPrefix { + pub chiplets_bus: EF, + pub block_stack_table: EF, + pub block_hash_table: EF, + pub op_group_table: EF, + pub stack_overflow_table: EF, + pub sibling_table: EF, + pub log_precompile_transcript: EF, + pub range_check_bus: EF, + pub ace_wiring_bus: EF, +} + +impl BusPrefix { + /// Prefix for the bus index used by [`Challenges::encode`] / [`Challenges::encode_sparse`]. + #[inline(always)] + pub(crate) fn prefix_for_bus(&self, bus: usize) -> &EF { + match bus { + CHIPLETS_BUS => &self.chiplets_bus, + BLOCK_STACK_TABLE => &self.block_stack_table, + BLOCK_HASH_TABLE => &self.block_hash_table, + OP_GROUP_TABLE => &self.op_group_table, + STACK_OVERFLOW_TABLE => &self.stack_overflow_table, + SIBLING_TABLE => &self.sibling_table, + LOG_PRECOMPILE_TRANSCRIPT => &self.log_precompile_transcript, + RANGE_CHECK_BUS => &self.range_check_bus, + ACE_WIRING_BUS => &self.ace_wiring_bus, + _ => unreachable!("bus index {bus} is not a valid bus type (< {NUM_BUS_TYPES})"), + } + } +} + +/// Encodes multiset/LogUp contributions as **per-bus prefix + \**. /// /// - `alpha`: randomness base (kept public for direct access by range checker etc.) -/// - `beta_powers`: precomputed powers `[beta^0, beta^1, ..., beta^(MAX_MESSAGE_WIDTH-1)]` -/// - `bus_prefix`: per-bus domain separation constants `bus_prefix[i] = alpha + (i+1) * -/// beta^MAX_MESSAGE_WIDTH` +/// - `beta_powers`: precomputed powers `beta^0 .. beta^(MAX_MESSAGE_WIDTH-1)` (see [`BetaPowers`]) +/// - `bus_prefix`: per-bus domain separation (see [`BusPrefix`]) /// /// The challenges are derived from permutation randomness: /// - `alpha = challenges[0]` @@ -33,27 +126,43 @@ use super::{MAX_MESSAGE_WIDTH, bus_types::NUM_BUS_TYPES}; /// Precomputed once and passed by reference to all bus components. pub struct Challenges { pub alpha: EF, - pub beta_powers: [EF; MAX_MESSAGE_WIDTH], - /// Per-bus domain separation: `bus_prefix[i] = alpha + (i+1) * gamma` - /// where `gamma = beta^MAX_MESSAGE_WIDTH`. - pub bus_prefix: [EF; NUM_BUS_TYPES], + pub beta_powers: BetaPowers, + pub bus_prefix: BusPrefix, } impl Challenges { /// Builds `alpha`, precomputed `beta` powers, and per-bus prefixes. pub fn new(alpha: EF, beta: EF) -> Self { - let mut beta_powers = core::array::from_fn(|_| EF::ONE); + let mut arr: [EF; MAX_MESSAGE_WIDTH] = core::array::from_fn(|_| EF::ONE); for i in 1..MAX_MESSAGE_WIDTH { - beta_powers[i] = beta_powers[i - 1].clone() * beta.clone(); + arr[i] = arr[i - 1].clone() * beta.clone(); } // gamma = beta^MAX_MESSAGE_WIDTH (one power beyond the message range) - let gamma = beta_powers[MAX_MESSAGE_WIDTH - 1].clone() * beta; - let bus_prefix = - core::array::from_fn(|i| alpha.clone() + gamma.clone() * EF::from_u32((i as u32) + 1)); + let gamma = arr[MAX_MESSAGE_WIDTH - 1].clone() * beta; + let beta_powers = BetaPowers { + label: arr[LABEL_IDX].clone(), + addr: arr[ADDR_IDX].clone(), + node_index: arr[NODE_INDEX_IDX].clone(), + state: core::array::from_fn(|i| arr[STATE_START_IDX + i].clone()), + capacity: core::array::from_fn(|i| arr[CAPACITY_START_IDX + i].clone()), + beta_pow_15: arr[MAX_MESSAGE_WIDTH - 1].clone(), + }; + let term = |k: u32| alpha.clone() + gamma.clone() * EF::from_u32(k); + let bus_prefix = BusPrefix { + chiplets_bus: term(1), + block_stack_table: term(2), + block_hash_table: term(3), + op_group_table: term(4), + stack_overflow_table: term(5), + sibling_table: term(6), + log_precompile_transcript: term(7), + range_check_bus: term(8), + ace_wiring_bus: term(9), + }; Self { alpha, beta_powers, bus_prefix } } - /// Encodes as **bus_prefix\[bus\] + sum(beta_powers\[i\] * elem\[i\])** with K consecutive + /// Encodes as **prefix_for_bus(bus) + sum(beta_powers.at(i) * elem\[i\])** with K consecutive /// elements. /// /// The `bus` parameter selects the bus interaction type for domain separation. @@ -67,14 +176,14 @@ impl Challenges { bus < NUM_BUS_TYPES, "Bus index {bus} exceeds NUM_BUS_TYPES ({NUM_BUS_TYPES})" ); - let mut acc = self.bus_prefix[bus].clone(); + let mut acc = self.bus_prefix.prefix_for_bus(bus).clone(); for (i, elem) in elems.into_iter().enumerate() { - acc += self.beta_powers[i].clone() * elem; + acc += self.beta_powers.at(i).clone() * elem; } acc } - /// Encodes as **bus_prefix\[bus\] + sum(beta_powers\[layout\[i\]\] * values\[i\])** using + /// Encodes as **prefix_for_bus(bus) + sum(beta_powers.at(layout\[i\]) * values\[i\])** using /// sparse positions. /// /// The `bus` parameter selects the bus interaction type for domain separation. @@ -92,15 +201,13 @@ impl Challenges { bus < NUM_BUS_TYPES, "Bus index {bus} exceeds NUM_BUS_TYPES ({NUM_BUS_TYPES})" ); - let mut acc = self.bus_prefix[bus].clone(); + let mut acc = self.bus_prefix.prefix_for_bus(bus).clone(); for (idx, value) in layout.into_iter().zip(values) { debug_assert!( - idx < self.beta_powers.len(), - "encode_sparse index {} exceeds beta_powers length ({})", - idx, - self.beta_powers.len() + idx < MAX_MESSAGE_WIDTH, + "encode_sparse index {idx} exceeds beta_powers range ({MAX_MESSAGE_WIDTH})" ); - acc += self.beta_powers[idx].clone() * value; + acc += self.beta_powers.at(idx).clone() * value; } acc } diff --git a/air/src/trace/mod.rs b/air/src/trace/mod.rs index ab46d23626..8e1e7acd30 100644 --- a/air/src/trace/mod.rs +++ b/air/src/trace/mod.rs @@ -4,7 +4,7 @@ use chiplets::hasher::RATE_LEN; use miden_core::utils::range; mod challenges; -pub use challenges::Challenges; +pub use challenges::{BetaPowers, BusPrefix, Challenges}; pub mod chiplets; pub mod decoder; @@ -188,45 +188,53 @@ pub const MAX_MESSAGE_WIDTH: usize = 16; /// Bus message coefficient indices. /// /// These define the standard positions for encoding bus messages using the pattern: -/// `alpha + sum(beta_powers\[i\] * elem\[i\])` where: +/// `alpha + sum(beta_powers.at(i) * elem\[i\])` where: /// - `alpha` is the randomness base (accessed directly as `.alpha`) -/// - `beta_powers\[i\] = beta^i` are the powers of beta +/// - `beta_powers.at(i) = beta^i` are the powers of beta (see [`BetaPowers::at`]) /// -/// These indices refer to positions in the `beta_powers` array, not including alpha. +/// These indices refer to positions in [`Challenges::beta_powers`] ([`BetaPowers`]), not including +/// alpha. /// /// This layout is shared between: /// - AIR constraint builders (symbolic expressions): `Challenges` /// - Processor auxiliary trace builders (concrete field elements): `Challenges` pub mod bus_message { - /// Label coefficient index: `beta_powers[0] = beta^0`. + /// Label coefficient index: `beta_powers.label` (`beta^0`). /// /// Used for transition type/operation label. pub const LABEL_IDX: usize = 0; - /// Address coefficient index: `beta_powers[1] = beta^1`. + /// Address coefficient index: `beta_powers.addr` (`beta^1`). /// /// Used for chiplet address. pub const ADDR_IDX: usize = 1; - /// Node index coefficient index: `beta_powers[2] = beta^2`. + /// Node index coefficient index: `beta_powers.node_index` (`beta^2`). /// /// Used for Merkle path position. Set to 0 for non-Merkle operations (SPAN, RESPAN, HPERM, /// etc.). pub const NODE_INDEX_IDX: usize = 2; - /// State start coefficient index: `beta_powers[3] = beta^3`. + /// State start coefficient index: `beta_powers.state[0] = beta^3`. /// /// Beginning of hasher state. Hasher state occupies 8 consecutive coefficients: - /// `beta_powers[3..11]` (beta^3..beta^10) for `state[0..7]` (rate portion: RATE0 || RATE1). + /// `beta_powers.state[0..8]` (`beta^3..beta^10`) for `state[0..7]` (rate portion: RATE0 || + /// RATE1). pub const STATE_START_IDX: usize = 3; - /// Capacity start coefficient index: `beta_powers[11] = beta^11`. + /// Inclusive end index for the eight `state` coefficients (`beta^3..=beta^10`). + pub const STATE_COEFF_END_IDX: usize = STATE_START_IDX + 7; + + /// Capacity start coefficient index: `beta_powers.capacity[0] = beta^11`. /// /// Beginning of hasher capacity. Hasher capacity occupies 4 consecutive coefficients: - /// `beta_powers[11..15]` (beta^11..beta^14) for `capacity[0..3]`. + /// `beta_powers.capacity[0..4]` (`beta^11..beta^14`) for `capacity[0..3]`. pub const CAPACITY_START_IDX: usize = 11; - /// Capacity domain coefficient index: `beta_powers[12] = beta^12`. + /// Inclusive end index for the four `capacity` coefficients (`beta^11..=beta^14`). + pub const CAPACITY_COEFF_END_IDX: usize = CAPACITY_START_IDX + 3; + + /// Capacity domain coefficient index: (`beta^12`). /// /// Second capacity element. Used for encoding operation-specific data (e.g., op_code in control /// block messages). @@ -237,7 +245,8 @@ pub mod bus_message { /// /// Each constant identifies a distinct bus interaction type. When encoding a message, /// the bus index is passed to [`Challenges::encode`] or [`Challenges::encode_sparse`], -/// which uses `bus_prefix[bus]` as the additive base instead of bare `alpha`. +/// which uses `bus_prefix.prefix_for_bus(bus)` (or the corresponding named field) as the additive +/// base instead of bare `alpha`. /// /// This ensures messages from different buses are always distinct, even if they share /// the same coefficient layout and labels. This is a prerequisite for a future unified bus. diff --git a/processor/src/trace/chiplets/aux_trace/bus/hasher.rs b/processor/src/trace/chiplets/aux_trace/bus/hasher.rs index f368d7c663..da8824370a 100644 --- a/processor/src/trace/chiplets/aux_trace/bus/hasher.rs +++ b/processor/src/trace/chiplets/aux_trace/bus/hasher.rs @@ -1,8 +1,7 @@ use core::fmt::{Display, Formatter, Result as FmtResult}; use miden_air::trace::{ - Challenges, MainTrace, RowIndex, bus_message, - bus_types::CHIPLETS_BUS, + Challenges, MainTrace, RowIndex, chiplets::{ hasher, hasher::{ @@ -29,13 +28,14 @@ use crate::{ // // All hasher chiplet bus messages use a common encoding structure: // -// challenges.bus_prefix[CHIPLETS_BUS] = alpha (randomness base, accessed -// directly) challenges.beta_powers[0] = beta^0 (label: transition type) -// challenges.beta_powers[1] = beta^1 (addr: hasher chiplet address) -// challenges.beta_powers[2] = beta^2 (node_index: Merkle path position, 0 for -// non-Merkle ops) challenges.beta_powers[3..10] = beta^3..beta^10 (state[0..7]: RATE0 || -// RATE1 in sponge order) challenges.beta_powers[11..14] = beta^11..beta^14 (capacity[0..3]: -// domain separation) +// challenges.bus_prefix.chiplets_bus = alpha + gamma (chiplet bus domain separation) +// challenges.beta_powers.label = beta^0 (label: transition type) +// challenges.beta_powers.addr = beta^1 (addr: hasher chiplet address) +// challenges.beta_powers.node_index = beta^2 (node_index: Merkle path position, 0 for +// non-Merkle ops) +// challenges.beta_powers.state[0..8] = beta^3..beta^10 (state[0..7]: RATE0 || RATE1 in sponge +// order) +// challenges.beta_powers.capacity[0..4] = beta^11..beta^14 (capacity[0..3]: domain separation) // // Message encoding: alpha + beta^0*label + beta^1*addr + beta^2*node_index // + beta^3*state[0] + ... + beta^10*state[7] @@ -45,7 +45,7 @@ use crate::{ // - Full state messages (HPERM, LOG_PRECOMPILE): all 12 state elements (rate + capacity) // - Rate-only messages (SPAN, RESPAN): skip node_index and capacity, use label + addr + state[0..7] // - Digest messages (END block): label + addr + RATE0 digest (state[0..3]) -// - Control block messages: rate + one capacity element (beta_powers[12]) for op_code +// - Control block messages: rate + one capacity element (capacity_domain / beta^12) for op_code // - Tree operation messages (MPVERIFY, MRUPDATE): include node_index // HASHER MESSAGE CONSTANTS AND HELPERS @@ -61,6 +61,16 @@ const MP_VERIFY_LABEL_START: Felt = Felt::new((MP_VERIFY_LABEL + 16) as u64); const MR_UPDATE_OLD_LABEL_START: Felt = Felt::new((MR_UPDATE_OLD_LABEL + 16) as u64); const MR_UPDATE_NEW_LABEL_START: Felt = Felt::new((MR_UPDATE_NEW_LABEL + 16) as u64); +/// `beta^(STATE_START_IDX + i)` for sponge `state[i]` (rate then capacity coefficients). +#[inline(always)] +fn beta_for_sponge_elem>(challenges: &Challenges, i: usize) -> E { + if i < 8 { + challenges.beta_powers.state[i] + } else { + challenges.beta_powers.capacity[i - 8] + } +} + /// Encodes hasher message as **alpha + ** /// /// Used for tree operations (MPVERIFY, MRUPDATE) and generic hasher messages with node_index. @@ -75,12 +85,12 @@ fn hasher_message_value( where E: ExtensionField, { - let mut acc = challenges.bus_prefix[CHIPLETS_BUS] - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr_next - + challenges.beta_powers[bus_message::NODE_INDEX_IDX] * node_index; + let mut acc = challenges.bus_prefix.chiplets_bus + + challenges.beta_powers.label * transition_label + + challenges.beta_powers.addr * addr_next + + challenges.beta_powers.node_index * node_index; for (i, &elem) in state.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; + acc += beta_for_sponge_elem(challenges, i) * elem; } acc } @@ -96,11 +106,11 @@ fn header_rate_value( where E: ExtensionField, { - let mut acc = challenges.bus_prefix[CHIPLETS_BUS] - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr; + let mut acc = challenges.bus_prefix.chiplets_bus + + challenges.beta_powers.label * transition_label + + challenges.beta_powers.addr * addr; for (i, &elem) in state.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; + acc += challenges.beta_powers.state[i] * elem; } acc } @@ -117,11 +127,11 @@ fn header_digest_value( where E: ExtensionField, { - let mut acc = challenges.bus_prefix[CHIPLETS_BUS] - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr; + let mut acc = challenges.bus_prefix.chiplets_bus + + challenges.beta_powers.label * transition_label + + challenges.beta_powers.addr * addr; for (i, &elem) in digest.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; + acc += challenges.beta_powers.state[i] * elem; } acc } @@ -748,7 +758,7 @@ where self.addr_next, self.decoder_hasher_state, ); - acc += challenges.beta_powers[bus_message::CAPACITY_DOMAIN_IDX] * self.op_code; + acc += *challenges.beta_powers.capacity_domain() * self.op_code; acc } diff --git a/processor/src/trace/chiplets/aux_trace/bus/mod.rs b/processor/src/trace/chiplets/aux_trace/bus/mod.rs index ced7ba4977..3f5d6102ca 100644 --- a/processor/src/trace/chiplets/aux_trace/bus/mod.rs +++ b/processor/src/trace/chiplets/aux_trace/bus/mod.rs @@ -15,7 +15,6 @@ use memory::{ }; use miden_air::trace::{ Challenges, MainTrace, RowIndex, - bus_types::CHIPLETS_BUS, chiplets::{ hasher::LINEAR_HASH_LABEL, memory::{ @@ -183,12 +182,10 @@ fn encode_control_block_without_state(challenges: &Challenges, addr: Felt, where E: ExtensionField, { - use miden_air::trace::bus_message; - - challenges.bus_prefix[CHIPLETS_BUS] - + challenges.beta_powers[bus_message::LABEL_IDX] * Felt::from_u8(LINEAR_HASH_LABEL + 16) - + challenges.beta_powers[bus_message::ADDR_IDX] * addr - + challenges.beta_powers[bus_message::CAPACITY_DOMAIN_IDX] * op_code + challenges.bus_prefix.chiplets_bus + + challenges.beta_powers.label * Felt::from_u8(LINEAR_HASH_LABEL + 16) + + challenges.beta_powers.addr * addr + + *challenges.beta_powers.capacity_domain() * op_code } /// Builds requests made on a `DYN` operation. diff --git a/processor/src/trace/chiplets/aux_trace/virtual_table.rs b/processor/src/trace/chiplets/aux_trace/virtual_table.rs index 2429895d15..cba8fee6eb 100644 --- a/processor/src/trace/chiplets/aux_trace/virtual_table.rs +++ b/processor/src/trace/chiplets/aux_trace/virtual_table.rs @@ -100,11 +100,11 @@ const RATE0_RANGE: core::ops::Range = 0..DIGEST_LEN; /// Range for RATE1 (second rate word) in sponge state. const RATE1_RANGE: core::ops::Range = DIGEST_LEN..(2 * DIGEST_LEN); -/// Node is left child (lsb=0), sibling is right child at RATE1: alpha + beta_powers[2]*index + -/// beta_powers[7..10]*sibling +/// Node is left child (lsb=0), sibling is right child at RATE1: alpha + +/// beta_powers.node_index*index + beta_powers.state[4..8]*sibling const SIBLING_RATE1_LAYOUT: [usize; 5] = [2, 7, 8, 9, 10]; -/// Node is right child (lsb=1), sibling is left child at RATE0: alpha + beta_powers[2]*index + -/// beta_powers[3..6]*sibling +/// Node is right child (lsb=1), sibling is left child at RATE0: alpha + +/// beta_powers.node_index*index + beta_powers.state[0..4]*sibling const SIBLING_RATE0_LAYOUT: [usize; 5] = [2, 3, 4, 5, 6]; /// Extracts the node index and sibling word from the trace and encodes a sibling table entry. diff --git a/processor/src/trace/range/aux_trace.rs b/processor/src/trace/range/aux_trace.rs index 0a4dcf3602..310924ca2d 100644 --- a/processor/src/trace/range/aux_trace.rs +++ b/processor/src/trace/range/aux_trace.rs @@ -3,7 +3,6 @@ use core::mem::MaybeUninit; use miden_air::trace::{ Challenges, MainTrace, RowIndex, - bus_types::RANGE_CHECK_BUS, range::{M_COL_IDX, V_COL_IDX}, }; @@ -69,7 +68,7 @@ impl AuxTraceBuilder { challenges: &Challenges, ) -> Vec { // run batch inversion on the lookup values - let divisors = get_divisors(&self.lookup_values, challenges.bus_prefix[RANGE_CHECK_BUS]); + let divisors = get_divisors(&self.lookup_values, challenges.bus_prefix.range_check_bus); // allocate memory for the running sum column and set the initial value to ZERO let mut b_range: Vec> = uninit_vector(main_trace.num_rows()); diff --git a/processor/src/trace/tests/chiplets/hasher.rs b/processor/src/trace/tests/chiplets/hasher.rs index dcdb1ca98b..ee70250069 100644 --- a/processor/src/trace/tests/chiplets/hasher.rs +++ b/processor/src/trace/tests/chiplets/hasher.rs @@ -909,22 +909,22 @@ fn build_expected( ) -> Felt { let first_cycle_row = addr_to_cycle_row(addr) == 0; let transition_label = if first_cycle_row { label + 16_u8 } else { label + 32_u8 }; - let header = challenges.bus_prefix[miden_air::trace::bus_types::CHIPLETS_BUS] - + challenges.beta_powers[0] * Felt::from_u8(transition_label) - + challenges.beta_powers[1] * addr - + challenges.beta_powers[2] * index; + let header = challenges.bus_prefix.chiplets_bus + + challenges.beta_powers.label * Felt::from_u8(transition_label) + + challenges.beta_powers.addr * addr + + challenges.beta_powers.node_index * index; let mut value = header; if (first_cycle_row && label == LINEAR_HASH_LABEL) || label == RETURN_STATE_LABEL { // include the entire state (words a, b, c) - value += build_value(&challenges.beta_powers[3..15], &state); + value += build_value(&challenges.beta_powers.sponge_state(), &state); } else if label == LINEAR_HASH_LABEL { // Include the next absorbed rate portion of the state (RATE0 || RATE1). // With LE sponge layout [RATE0, RATE1, CAP], rate is at indices 0..8. - value += build_value(&challenges.beta_powers[3..11], &next_state[0..RATE_LEN]); + value += build_value(&challenges.beta_powers.state, &next_state[0..RATE_LEN]); } else if label == RETURN_HASH_LABEL { // include the digest (word b) - value += build_value(&challenges.beta_powers[3..7], &state[DIGEST_RANGE]); + value += build_value(&challenges.beta_powers.state[..4], &state[DIGEST_RANGE]); } else { assert!( label == MP_VERIFY_LABEL @@ -934,8 +934,8 @@ fn build_expected( let bit = index.as_canonical_u64() & 1; // For Merkle operations, RATE0 and RATE1 hold the two child digests. // With LE sponge layout [RATE0, RATE1, CAP], they are at indices 0..4 and 4..8. - let left_word = build_value(&challenges.beta_powers[3..7], &state[0..4]); - let right_word = build_value(&challenges.beta_powers[3..7], &state[4..8]); + let left_word = build_value(&challenges.beta_powers.state[..4], &state[0..4]); + let right_word = build_value(&challenges.beta_powers.state[..4], &state[4..8]); value += Felt::new(1 - bit) * left_word + Felt::new(bit) * right_word; } diff --git a/processor/src/trace/tests/decoder.rs b/processor/src/trace/tests/decoder.rs index 43294af12c..cfadad8ca6 100644 --- a/processor/src/trace/tests/decoder.rs +++ b/processor/src/trace/tests/decoder.rs @@ -882,18 +882,18 @@ impl BlockStackTableRow { /// at least 12 coefficients. pub fn to_value>(&self, challenges: &Challenges) -> E { let is_loop = if self.is_loop { ONE } else { ZERO }; - challenges.bus_prefix[miden_air::trace::bus_types::BLOCK_STACK_TABLE] - + challenges.beta_powers[0] * self.block_id - + challenges.beta_powers[1] * self.parent_id - + challenges.beta_powers[2] * is_loop - + challenges.beta_powers[3] * Felt::from_u32(u32::from(self.parent_ctx)) - + challenges.beta_powers[4] * self.parent_fmp - + challenges.beta_powers[5] * Felt::from_u32(self.parent_stack_depth) - + challenges.beta_powers[6] * self.parent_next_overflow_addr - + challenges.beta_powers[7] * self.parent_fn_hash[0] - + challenges.beta_powers[8] * self.parent_fn_hash[1] - + challenges.beta_powers[9] * self.parent_fn_hash[2] - + challenges.beta_powers[10] * self.parent_fn_hash[3] + challenges.bus_prefix.block_stack_table + + challenges.beta_powers.label * self.block_id + + challenges.beta_powers.addr * self.parent_id + + challenges.beta_powers.node_index * is_loop + + challenges.beta_powers.state[0] * Felt::from_u32(u32::from(self.parent_ctx)) + + challenges.beta_powers.state[1] * self.parent_fmp + + challenges.beta_powers.state[2] * Felt::from_u32(self.parent_stack_depth) + + challenges.beta_powers.state[3] * self.parent_next_overflow_addr + + challenges.beta_powers.state[4] * self.parent_fn_hash[0] + + challenges.beta_powers.state[5] * self.parent_fn_hash[1] + + challenges.beta_powers.state[6] * self.parent_fn_hash[2] + + challenges.beta_powers.state[7] * self.parent_fn_hash[3] } } @@ -917,9 +917,9 @@ impl OpGroupTableRow { /// Reduces this row to a single field element in the field specified by E. This requires /// at least 4 coefficients. pub fn to_value>(&self, challenges: &Challenges) -> E { - challenges.bus_prefix[miden_air::trace::bus_types::OP_GROUP_TABLE] - + challenges.beta_powers[0] * self.batch_id - + challenges.beta_powers[1] * self.group_pos - + challenges.beta_powers[2] * self.group_value + challenges.bus_prefix.op_group_table + + challenges.beta_powers.label * self.batch_id + + challenges.beta_powers.addr * self.group_pos + + challenges.beta_powers.node_index * self.group_value } } diff --git a/processor/src/trace/tests/hasher.rs b/processor/src/trace/tests/hasher.rs index 9e872ca94c..a1b61c726b 100644 --- a/processor/src/trace/tests/hasher.rs +++ b/processor/src/trace/tests/hasher.rs @@ -205,19 +205,19 @@ impl SiblingTableRow { // we need to compute the 2nd and the 3rd word values for other purposes as well. let lsb = self.index.as_canonical_u64() & 1; if lsb == 0 { - challenges.bus_prefix[miden_air::trace::bus_types::SIBLING_TABLE] - + challenges.beta_powers[2] * self.index - + challenges.beta_powers[7] * self.sibling[0] - + challenges.beta_powers[8] * self.sibling[1] - + challenges.beta_powers[9] * self.sibling[2] - + challenges.beta_powers[10] * self.sibling[3] + challenges.bus_prefix.sibling_table + + challenges.beta_powers.node_index * self.index + + challenges.beta_powers.state[4] * self.sibling[0] + + challenges.beta_powers.state[5] * self.sibling[1] + + challenges.beta_powers.state[6] * self.sibling[2] + + challenges.beta_powers.state[7] * self.sibling[3] } else { - challenges.bus_prefix[miden_air::trace::bus_types::SIBLING_TABLE] - + challenges.beta_powers[2] * self.index - + challenges.beta_powers[3] * self.sibling[0] - + challenges.beta_powers[4] * self.sibling[1] - + challenges.beta_powers[5] * self.sibling[2] - + challenges.beta_powers[6] * self.sibling[3] + challenges.bus_prefix.sibling_table + + challenges.beta_powers.node_index * self.index + + challenges.beta_powers.state[0] * self.sibling[0] + + challenges.beta_powers.state[1] * self.sibling[1] + + challenges.beta_powers.state[2] * self.sibling[2] + + challenges.beta_powers.state[3] * self.sibling[3] } } } diff --git a/processor/src/trace/tests/range.rs b/processor/src/trace/tests/range.rs index 0cbba9591a..096c2c2e48 100644 --- a/processor/src/trace/tests/range.rs +++ b/processor/src/trace/tests/range.rs @@ -1,6 +1,5 @@ use miden_air::trace::{ - AUX_TRACE_RAND_CHALLENGES, Challenges, bus_types::RANGE_CHECK_BUS, - chiplets::hasher::HASH_CYCLE_LEN, range::B_RANGE_COL_IDX, + AUX_TRACE_RAND_CHALLENGES, Challenges, chiplets::hasher::HASH_CYCLE_LEN, range::B_RANGE_COL_IDX, }; use miden_core::{ONE, ZERO, field::Field, operations::Operation}; use miden_utils_testing::rand::rand_array; @@ -19,7 +18,7 @@ fn b_range_trace_stack() { let rand_elements = rand_array::(); let challenges = Challenges::new(rand_elements[0], rand_elements[1]); - let alpha = challenges.bus_prefix[RANGE_CHECK_BUS]; + let alpha = challenges.bus_prefix.range_check_bus; let aux_columns = trace.build_aux_trace(&rand_elements).unwrap(); let b_range = aux_columns.get_column(B_RANGE_COL_IDX); @@ -90,7 +89,7 @@ fn b_range_trace_mem() { let rand_elements = rand_array::(); let challenges = Challenges::new(rand_elements[0], rand_elements[1]); - let alpha = challenges.bus_prefix[RANGE_CHECK_BUS]; + let alpha = challenges.bus_prefix.range_check_bus; let aux_columns = trace.build_aux_trace(&rand_elements).unwrap(); let b_range = aux_columns.get_column(B_RANGE_COL_IDX);