binius_ip/logup_star/mod.rs
1// Copyright 2026 The Binius Developers
2
3//! Verifier for the logUp* indexed-lookup reduction of knowledge.
4//!
5//! logUp* proves an indexed lookup `(I^* T)[i] = T[I[i]]`.
6//! Unlike classic logUp, it never commits the looked-up vector `I^* T`.
7//! Multiple lookers may share one table (and one pushforward) by a random linear combination:
8//! a challenge `gamma` weights looker `j` by `gamma^j`, and the per-looker circuits run batched
9//! (see [`crate::fracaddcheck`]).
10//! Several tables may be read in one reduction, each looker naming the one it reads. Every table
11//! keeps its own pushforward and its own logUp challenge; only the batching machinery is shared.
12//! See [Soukhanov25] for the construction.
13//!
14//! [Soukhanov25]: <https://eprint.iacr.org/2025/946>
15//!
16//! # What is being proved
17//!
18//! The caller holds a claim about the looked-up vector at a point:
19//!
20//! ```text
21//! (I^* T)(r) = e
22//! ```
23//!
24//! The symbols are:
25//!
26//! - `T`: the table multilinear, with `m` variables (`2^m` entries).
27//! - `I`: the index multilinear, with `n` variables (`2^n` entries).
28//! - `r`: the `n`-coordinate evaluation point.
29//! - `e`: the claimed evaluation.
30//!
31//! The reduction turns this one claim into three separate evaluation claims:
32//!
33//! - one on the table `T`,
34//! - one on the pushforward `Y`,
35//! - one on the index `I`.
36//!
37//! The caller verifies those three claims, which is out of scope here.
38//!
39//! # The pushforward trick
40//!
41//! Let `X = eq_r` be the equality-indicator multilinear at the point `r`.
42//! Pullback and pushforward are dual under the inner product, which gives:
43//!
44//! ```text
45//! (I^* T)(r) = <I^* T, eq_r> = <T, I_* eq_r> = <T, Y>
46//! ```
47//!
48//! Here `Y = I_* eq_r` is the pushforward of `eq_r` along `I`.
49//! `Y` has only `2^m` entries, which is cheap.
50//! The avoided vector `I^* T` has `2^n` entries, which is expensive when `n` is large.
51//!
52//! # The two checks
53//!
54//! First, pushforward correctness, via a logarithmic-derivative (logUp) identity for a random `c`:
55//!
56//! ```text
57//! sum_{i in B_n} eq_r(i) / (c - I(i)) = sum_{j in B_m} Y(j) / (c - j)
58//! ```
59//!
60//! - Each side is a sum of fractions.
61//! - A fractional-addition GKR circuit collapses each side to a single root fraction.
62//! - Equality of the two sums is the cross-multiplication of the two root fractions.
63//!
64//! See [`crate::fracaddcheck`] for the GKR circuit.
65//!
66//! Second, the product claim `<T, Y> = e`, proved by a product sumcheck over the `m`-variable cube.
67//!
68//! # Batching the last GKR layer with the product sumcheck
69//!
70//! The table-side GKR circuit ends in an evaluation of `Y`.
71//! The product sumcheck also ends in an evaluation of `Y`.
72//! Run naively, these are two distinct evaluations at two distinct points.
73//!
74//! Both reductions share the same final step:
75//!
76//! - they split the leaf multilinears on the highest variable into two halves,
77//! - they combine the halves over the same `m-1` low variables,
78//! - they finish with one line-fold over the highest variable.
79//!
80//! So both can run as one `(m-1)`-variable sumcheck followed by one shared line-fold.
81//! That yields a single evaluation point, collapsing the two `Y` evaluations into one.
82//!
83//! # Transparent tables
84//!
85//! A transparent (succinct) table is one the verifier evaluates itself, without a commitment.
86//! Against such a table the product sumcheck is not needed at all.
87//! Both of the claims it would reduce are linear relations on the one multilinear `Y`:
88//!
89//! ```text
90//! <Y, eq_z> = Y(z) the fractional-addition leaf claim
91//! <Y, T> = e the product claim
92//! ```
93//!
94//! A caller holding `Y` as a committed oracle opens the two together against that one commitment.
95//! [`verify_reduction_transparent`] stops the reduction there and hands both claims back.
96//!
97//! # Soundness
98//!
99//! - The logUp identity for a random `c` catches a wrong `Y` except with probability `(n + m) /
100//! |F|`.
101//! - This is Lemma 2 of [Soukhanov25]: the identity holds only when `Y = I_* eq_r`.
102//! - The two GKR circuits and the batched sumcheck add the usual sumcheck soundness error.
103//! - The cross-multiplication of the root fractions assumes both root denominators are nonzero.
104//! - A root denominator is a product of factors `c - I(i)` or `c - j`.
105//! - That product is nonzero except with probability `(n + m) / |F|` over the random `c`.
106//! - With several tables, each is randomized by its own challenge `c_t`, so its contribution to the
107//! root fraction is a rational function of `c_t` alone. A sum of such functions in disjoint
108//! variables vanishes only when each does, which is what lets the one root check certify every
109//! table. Under a shared challenge two tables' errors could cancel.
110//!
111//! # Index embedding
112//!
113//! Table positions `j` in `0..2^m` and committed index values `I[i]` live in the same domain.
114//! A position is embedded into `F` through the `GF(2)`-linear basis:
115//!
116//! ```text
117//! iota(j) = sum_{t : bit t of j is set} basis(t)
118//! ```
119//!
120//! The table-side denominator multilinear is therefore `J(x) = sum_t basis(t) * x_t`.
121//! The verifier evaluates it by itself.
122//! This matches the index encoding used elsewhere in the Spartan verifier.
123
124mod error;
125mod output;
126mod pushforward;
127mod verify;
128
129pub use self::{
130 error::{Error, VerificationError},
131 output::{LogupOutput, LogupTableOutput, LogupTransparentOutput, LogupTransparentTableOutput},
132 verify::{LookerClaim, TableLookup, verify_reduction, verify_reduction_transparent},
133};