zinc_piop/lookup/structs.rs
1//! Data structures for the lookup protocol.
2//!
3//! Proof types, prover/verifier intermediates, instance types, and error
4//! definitions live here. Specification types (`LookupTableType`,
5//! `LookupColumnSpec`) live in `zinc-uair` and are re-exported from the
6//! parent module.
7
8use std::collections::BTreeMap;
9use thiserror::Error;
10use zinc_uair::LookupTableType;
11
12// ---------------------------------------------------------------------------
13// Per-group proof (BatchedDecompLogup)
14// ---------------------------------------------------------------------------
15
16/// Proof for one lookup group (columns sharing the same table type).
17///
18/// Does **not** contain a sumcheck proof — the sumcheck is shared via
19/// the protocol-level multi-degree sumcheck. This struct
20/// carries only the auxiliary vectors the verifier needs to reconstruct
21/// evaluations at the shared point.
22///
23/// Chunk vectors are **not** included — the verifier reconstructs them
24/// from the inverse witnesses: `c_k[j] = β − 1/u_k[j]`. Soundness
25/// follows from the PCS commitment binding the parent column.
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct BatchedDecompLogupProof<F> {
28 /// Per-witness aggregated multiplicity vectors:
29 /// `aggregated_multiplicities[l][j] = Σ_k m_k^(l)[j]`.
30 pub aggregated_multiplicities: Vec<Vec<F>>,
31 /// Per-witness per-chunk inverse witness vectors:
32 /// `chunk_inverse_witnesses[l][k][i] = 1 / (β − chunk[l][k][i])`.
33 pub chunk_inverse_witnesses: Vec<Vec<Vec<F>>>,
34 /// Shared inverse table vector: `inverse_table[j] = 1 / (β − T[j])`.
35 pub inverse_table: Vec<F>,
36}
37
38// ---------------------------------------------------------------------------
39// Per-group metadata (carried in the proof for the verifier)
40// ---------------------------------------------------------------------------
41
42/// Describes how a lookup witness column was derived from the trace.
43///
44/// Carried in [`LookupGroupMeta`] so the verifier can reconstruct the
45/// parent evaluation without re-receiving the lookup specs.
46#[derive(Clone, Debug, PartialEq, Eq)]
47pub enum LookupWitnessSource {
48 /// Standard column lookup: parent eval = `up_evals[column_index]`.
49 Column {
50 /// Original trace column index.
51 column_index: usize,
52 },
53 /// Affine-combination lookup: parent eval = `Σ coeff·up_evals[col] +
54 /// offset`. Currently only needed for BitPoly
55 Affine {
56 /// `(column_index, coefficient)` pairs.
57 terms: Vec<(usize, i64)>,
58 /// Constant bit-polynomial offset encoded as a u32 bit pattern.
59 constant_offset_bits: u32,
60 },
61}
62
63/// Per-group metadata stored in the proof so the verifier can reconstruct
64/// tables and column layout without being passed the original lookup specs.
65#[derive(Clone, Debug, PartialEq, Eq)]
66pub struct LookupGroupMeta {
67 /// Table type for this group (determines subtable generation).
68 pub table_type: LookupTableType,
69 /// Number of witness columns batched into this group (L).
70 pub num_columns: usize,
71 /// Number of rows in each witness vector (trace length).
72 pub witness_len: usize,
73 /// Per-witness source descriptors.
74 pub witness_sources: Vec<LookupWitnessSource>,
75}
76
77// ---------------------------------------------------------------------------
78// Complete lookup proof
79// ---------------------------------------------------------------------------
80
81/// Top-level proof: one [`BatchedDecompLogupProof`] per lookup group
82/// (groups formed by batching columns with the same [`LookupTableType`]).
83/// Carries [`LookupGroupMeta`] per group so the verifier needs no
84/// external specs.
85#[derive(Clone, Default, Debug, PartialEq, Eq)]
86pub struct BatchedLookupProof<F> {
87 /// Per-group proofs, in group order.
88 pub group_proofs: Vec<BatchedDecompLogupProof<F>>,
89 /// Per-group metadata needed by the verifier.
90 pub group_meta: Vec<LookupGroupMeta>,
91}
92
93// ---------------------------------------------------------------------------
94// Grouping utility
95// ---------------------------------------------------------------------------
96
97/// A group of columns that all look up into the same decomposed table.
98///
99/// Produced by [`group_lookup_specs`] and consumed by the pipeline.
100#[derive(Debug)]
101pub struct LookupGroup {
102 /// The shared table type.
103 pub table_type: LookupTableType,
104 /// Indices of all columns in this group.
105 pub column_indices: Vec<usize>,
106}
107
108/// Groups a list of [`LookupColumnSpec`](zinc_uair::LookupColumnSpec)s
109/// by their table type.
110///
111/// Columns with the same `LookupTableType` are batched into a single
112/// `BatchedDecompLogupProtocol` instance.
113pub fn group_lookup_specs(specs: &[zinc_uair::LookupColumnSpec]) -> Vec<LookupGroup> {
114 let mut map: BTreeMap<LookupTableType, Vec<usize>> = BTreeMap::new();
115 for spec in specs {
116 map.entry(spec.table_type.clone())
117 .or_default()
118 .push(spec.column_index);
119 }
120 map.into_iter()
121 .map(|(table_type, column_indices)| LookupGroup {
122 table_type,
123 column_indices,
124 })
125 .collect()
126}
127
128// ---------------------------------------------------------------------------
129// Errors
130// ---------------------------------------------------------------------------
131
132/// Errors from the lookup protocol.
133#[derive(Debug, Error)]
134pub enum LookupError {
135 #[error("lookup not implemented")]
136 NotImplemented,
137
138 #[error("witness entry not found in lookup table")]
139 WitnessNotInTable,
140
141 #[error("table inverse vector is incorrect at index {index}")]
142 TableInverseIncorrect { index: usize },
143
144 #[error("decomposition consistency check failed")]
145 DecompositionInconsistent,
146
147 #[error("multiplicity sum mismatch: expected {expected}, got {got}")]
148 MultiplicitySumMismatch { expected: u64, got: u64 },
149
150 #[error("final evaluation check failed")]
151 FinalEvaluationMismatch,
152}