Skip to main content

miden_ace_codegen/layout/
keys.rs

1use super::InputLayout;
2use crate::EXT_DEGREE;
3
4/// Logical inputs required by the ACE circuit.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum InputKey {
7    /// Public input at the given index.
8    Public(usize),
9    /// Aux randomness α supplied as an input.
10    AuxRandAlpha,
11    /// Aux randomness β supplied as an input.
12    AuxRandBeta,
13    /// Main trace value at (offset, index).
14    Main { offset: usize, index: usize },
15    /// Base-field coordinate for an aux trace column.
16    AuxCoord {
17        offset: usize,
18        index: usize,
19        coord: usize,
20    },
21    /// Aux bus boundary value at the given index.
22    AuxBusBoundary(usize),
23    /// Variable-length public input reduction at the given group index.
24    VlpiReduction(usize),
25    /// Batching challenge gamma for combining the constraint evaluation with the
26    /// auxiliary trace boundary checks.
27    Gamma,
28    /// Composition challenge used to fold constraints.
29    Alpha,
30    /// `zeta^N`, where `N` is the trace length.
31    ZPowN,
32    /// `zeta^(N / max_cycle_len)` for periodic columns.
33    ZK,
34    /// Precomputed first-row selector: `(z^N - 1) / (z - 1)`.
35    IsFirst,
36    /// Precomputed last-row selector: `(z^N - 1) / (z - g^{-1})`.
37    IsLast,
38    /// Precomputed transition selector: `z - g^{-1}`.
39    IsTransition,
40    /// First barycentric weight for quotient recomposition.
41    Weight0,
42    /// `f = h^N`, the chunk shift ratio between cosets.
43    F,
44    /// `s0 = offset^N`, the first chunk shift.
45    S0,
46    /// Base-field coordinate for a quotient chunk opening at `offset`
47    /// (0 = zeta, 1 = g * zeta).
48    QuotientChunkCoord {
49        offset: usize,
50        chunk: usize,
51        coord: usize,
52    },
53}
54
55/// Canonical InputKey → index mapping for a given layout.
56#[derive(Debug, Clone, Copy)]
57pub(crate) struct InputKeyMapper<'a> {
58    pub(super) layout: &'a InputLayout,
59}
60
61impl InputKeyMapper<'_> {
62    /// Return the input index for a key, if it exists in the layout.
63    pub(crate) fn index_of(&self, key: InputKey) -> Option<usize> {
64        let layout = self.layout;
65        match key {
66            InputKey::Public(i) => layout.regions.public_values.index(i),
67            InputKey::AuxRandAlpha => Some(layout.aux_rand_alpha),
68            InputKey::AuxRandBeta => Some(layout.aux_rand_beta),
69            InputKey::Main { offset, index } => match offset {
70                0 => layout.regions.main_curr.index(index),
71                1 => layout.regions.main_next.index(index),
72                _ => None,
73            },
74            InputKey::AuxCoord { offset, index, coord } => {
75                if index >= layout.counts.aux_width || coord >= EXT_DEGREE {
76                    return None;
77                }
78                let local = index * EXT_DEGREE + coord;
79                match offset {
80                    0 => layout.regions.aux_curr.index(local),
81                    1 => layout.regions.aux_next.index(local),
82                    _ => None,
83                }
84            },
85            InputKey::AuxBusBoundary(i) => layout.regions.aux_bus_boundary.index(i),
86            InputKey::VlpiReduction(i) => {
87                let local = i * layout.vlpi_stride;
88                layout.regions.vlpi_reductions.index(local)
89            },
90            // Extension-field stark vars.
91            InputKey::Alpha => Some(layout.stark.alpha),
92            InputKey::ZPowN => Some(layout.stark.z_pow_n),
93            InputKey::ZK => Some(layout.stark.z_k),
94            InputKey::IsFirst => Some(layout.stark.is_first),
95            InputKey::IsLast => Some(layout.stark.is_last),
96            InputKey::IsTransition => Some(layout.stark.is_transition),
97            InputKey::Gamma => Some(layout.stark.gamma),
98            // Base-field stark vars (stored as (val, 0) in the EF slot).
99            InputKey::Weight0 => Some(layout.stark.weight0),
100            InputKey::F => Some(layout.stark.f),
101            InputKey::S0 => Some(layout.stark.s0),
102            InputKey::QuotientChunkCoord { offset, chunk, coord } => {
103                if chunk >= layout.counts.num_quotient_chunks || coord >= EXT_DEGREE {
104                    return None;
105                }
106                let idx = chunk * EXT_DEGREE + coord;
107                match offset {
108                    0 => layout.regions.quotient_curr.index(idx),
109                    1 => layout.regions.quotient_next.index(idx),
110                    _ => None,
111                }
112            },
113        }
114    }
115}