zorch.sumcheck.domain¶
Evaluation domains for sumcheck round polynomials.
A round polynomial goes on the wire as ascending coefficients (the form verifier.CoeffsSumcheckRound checks). EvalDomain names the points a prover samples it at and owns the map from those samples to coefficients: a finite node set — the Gruen set {0, 1, *extra, eq_root(z)}, or the naturals — optionally led by the value at infinity (the leading coefficient, cheap for a product since it is the product of the factor slopes). extend_to_round_domain lifts a linear pair onto the Û_d sample domain; product_round_poly / product_round_coeffs build a product round message over it (the prover Rounds that emit them live in sqrt_space).
EvalDomain
dataclass
¶
The sample points of a round polynomial and the map from those samples to ascending coefficients.
nodes are the finite sample points — the Gruen set {0, 1, *extra, eq_root(z)},
or (when None) the naturals {0..}. inf_index is the index at which the value
at infinity — the leading coefficient (cheap for a product: the product of the
factor slopes) — sits among the samples: 0 first (Û), -1 last (the compressed
[s(node), s(∞)] wire), None for no ∞ sample. Degree and field come from the
samples, so only the node shape is fixed here.
Source code in zorch/sumcheck/domain.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
coeff_matrix ¶
coeff_matrix() -> Array
Value → coefficient matrix for the explicit finite nodes — what a driver precomputes once per round. The leading / naturals domain has no fixed size, so it reads its degree off the values instead: use to_coeffs.
Source code in zorch/sumcheck/domain.py
67 68 69 70 71 72 | |
to_coeffs ¶
to_coeffs(values: Array) -> Array
Ascending coefficients from this domain's samples of a round polynomial; the degree (len−1) and field come from values.
Source code in zorch/sumcheck/domain.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
sample ¶
sample(p0: Array, p1: Array) -> Array
Sample the linear factor p(x) = p0 + x·(p1−p0) at this domain's points [∞ if leading, *nodes]: p(∞) = slope p1−p0, p(node) = p0 + node·slope. The leading axis indexes the domain. Requires explicit nodes — a sampling domain must be concrete (the naturals-sized domain is an output-only coeff map).
Source code in zorch/sumcheck/domain.py
95 96 97 98 99 100 101 102 103 104 105 106 | |
UnivariateSkipDomain
dataclass
¶
The univariate skip's round-0 evaluation domain: the order-2^skip_rounds two-adic
subgroup D, with the value↔coeff map carried by the NTT (subgroup_to_coeffs /
subgroup_evals) rather than the inverse Vandermonde a finite EvalDomain uses.
Holds the knob (skip_rounds, the number of collapsed leading rounds) and the
field; the round-0 arithmetic runs in the base field (nodes and the transforms are
base-field), extension arithmetic entering only once r₀ is bound at round 1.
Source code in zorch/sumcheck/domain.py
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | |
nodes ¶
nodes() -> Array
The |D| subgroup points in lax.ntt order — ntt(e₁) reads them off the
same transform the map uses (mirrors coding.reed_solomon.eval_domain).
Source code in zorch/sumcheck/domain.py
296 297 298 299 300 301 302 303 | |
to_coeffs ¶
to_coeffs(values: Array) -> Array
Value→coeff over D via the iNTT (subgroup_to_coeffs).
Source code in zorch/sumcheck/domain.py
305 306 307 | |
sum_over_subgroup ¶
sum_over_subgroup(coeffs: Array) -> Array
Σ_{z∈D} p(z) from ascending coeffs (subgroup_sum).
Source code in zorch/sumcheck/domain.py
309 310 311 | |
extend_to_round_domain ¶
extend_to_round_domain(
p0: Array, p1: Array, d: int, *, skip_one: bool = False
) -> Array
Lift a linear pair (p(0), p(1)) onto U_d = [∞, 0, 1, …, d−1] (or Û_d, u=1 dropped, when skip_one). p(∞) is the slope p(1)−p(0); p(u) = p(0) + u·(p(1)−p(0)). The leading axis indexes the domain.
Source code in zorch/sumcheck/domain.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
natural_domain ¶
natural_domain(degree: int, dtype: Any) -> EvalDomain
The natural evaluation domain {0, 1, …, degree}: the round poly sent as its plain values [s(0), …, s(degree)] — the wire form verifier.SumcheckRound checks and the default domain of the generic StandardRound. Nodes live in the base field (an integer node is a base-field element; extension factors promote at multiply), reproducing the list prover's per-point lift byte-for-byte.
Source code in zorch/sumcheck/domain.py
131 132 133 134 135 136 137 | |
uhat_domain ¶
uhat_domain(degree: int, dtype: Any) -> EvalDomain
The compressed product round domain Û_degree = {∞, 0, 2, …, degree−1}: ∞-leading, u=1 dropped (the verifier recovers s(1) from s(0)+s(1)=claim). The default sampling domain for the eq-poly / sqrt-space engines.
Source code in zorch/sumcheck/domain.py
140 141 142 143 144 145 | |
compressed_domain ¶
compressed_domain(node: int, dtype: Any) -> EvalDomain
The two-point compressed product-round domain [s(node), s(∞)]: one finite
node (0 → s(0)=c_0, 1 → s(1)) with s(∞) trailing. The third value of
the degree-2 round poly stays off the wire — the verifier recovers it from
s(0)+s(1)=claim.
Source code in zorch/sumcheck/domain.py
148 149 150 151 152 153 154 155 | |
split_halves ¶
split_halves(arr: Array) -> tuple[Array, Array]
Split the last variable MSB-first into contiguous halves
(arr[..., :N/2], arr[..., N/2:]) — the dense bind. ndim-agnostic; the MSB
dual of split_pairs.
Source code in zorch/sumcheck/domain.py
158 159 160 161 162 163 | |
split_pairs ¶
split_pairs(arr: Array) -> tuple[Array, Array]
Split the last variable LSB-first into stride-2 consecutive pairs
(arr[..., 0::2], arr[..., 1::2]). The jagged engines bind LSB-first — a
batch-major layout makes the pair the in-segment dimension, so a fold never
crosses a segment boundary — while the dense drivers split MSB-first
(split_halves). Its split-only form also serves the LogUp paired_evals,
which needs both halves without folding.
Source code in zorch/sumcheck/domain.py
166 167 168 169 170 171 172 173 | |
summand_evals ¶
summand_evals(
stacked: Array,
combine: Callable[..., Array],
domain: EvalDomain,
*,
weight: Array | None = None,
msb: bool = True
) -> Array
Σ_x' weight(x')·combine(f₁, …, f_m)(x') per point of domain: the m stacked
factors sampled at the domain's points (domain.sample), combined, optionally
weighted per hypercube point, then summed. The one reduction body the
round-message builders share — generic over the summand's combine (Πₖ, LogUp,
…), the evaluation domain (∞-leading Û, Gruen, {0,½}, {0,2,4}, …), and the bind
order.
weight (a length-N/2 vector over the folded hypercube) is the eq-weight of an
eq-weighted sumcheck — Σ eq·Π in one pass, no eq factor stacked into the state.
msb=False binds the LOW variable (split_pairs) instead of the high
(split_halves) — the LSB order the jagged / GHASH engines fold in.
A leading (∞) node encodes s(∞) = combine(*slopes), the true leading coefficient
only for a HOMOGENEOUS combine — every monomial a product of exactly degree
factors (a plain product, or the LogUp combine); a mixed-degree combine like
eq·(â◦b̂ − ĉ) is not. A finite domain carries no such restriction — any summand
samples cleanly on it.
Source code in zorch/sumcheck/domain.py
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
product_round_poly ¶
product_round_poly(stacked: Array) -> Array
Round message s = Σₓ Πₖ fₖ over Û_m for the m stacked multilinears, shape (m,) — the product summand on the compressed domain.
Source code in zorch/sumcheck/domain.py
208 209 210 211 212 213 | |
product_round_coeffs ¶
product_round_coeffs(stacked: Array) -> Array
Ascending coefficients of the degree-m product round polynomial for m stacked factors: the same Σ_x' Πₖ fₖ as product_round_poly but sampled over the full round domain [∞, 0, 1, …, m−1] so it is fully determined, then mapped to coefficients — the wire form verifier.CoeffsSumcheckRound checks.
Source code in zorch/sumcheck/domain.py
216 217 218 219 220 221 222 223 | |
fold ¶
fold(arr: Array, r: Array, *, msb: bool = True) -> Array
Fold the last variable at challenge r: P0 + r*(P1 - P0), halving the last
axis. msb (the dense default) splits contiguous halves [low | high]; msb=False
splits stride-2 consecutive pairs — the jagged bind, where a batch-major layout
makes the pair the in-segment dimension, so the fold never crosses a segment
boundary. ndim-agnostic: the leading factor/batch axes broadcast.
Source code in zorch/sumcheck/domain.py
226 227 228 229 230 231 232 233 | |
subgroup_to_coeffs ¶
subgroup_to_coeffs(values: Array) -> Array
Ascending coefficients of the degree-<|D| univariate whose values on the
order-|D| two-adic subgroup D are values (last axis = D, |D| a power of two):
the iNTT over D, batched over the leading axes (the native op transforms the last
axis, like coding.reed_solomon.encode). The subgroup analogue of
EvalDomain.to_coeffs — the inverse Vandermonde does not scale to
|D| = 2^skip_rounds.
Source code in zorch/sumcheck/domain.py
245 246 247 248 249 250 251 252 | |
subgroup_evals ¶
subgroup_evals(coeffs: Array, size: int) -> Array
Evaluate the univariate coeffs (ascending, last axis) on the order-size
two-adic subgroup, batched over the leading axes — zero-pad to size then NTT.
With size > len(coeffs) this is the low-degree extension onto a superset D' ⊇ D
the round-0 message needs, since deg s₀ = degree·(|D|−1) outgrows |D|; size must
be a power of two ≥ len(coeffs).
Source code in zorch/sumcheck/domain.py
255 256 257 258 259 260 261 262 263 264 265 266 | |
subgroup_sum ¶
subgroup_sum(coeffs: Array, skip_rounds: int) -> Array
Σ_{z∈D} p(z) for the univariate coeffs (ascending, last axis) over the
order-2^skip_rounds subgroup D. Σ_{z∈D} zᵏ = |D| when |D| divides k, else 0 — so the
sum reads off the coefficients at multiples of |D|, scaled by |D|. |D| is built in
the field (a bare Python int would not Montgomery-encode).
Source code in zorch/sumcheck/domain.py
269 270 271 272 273 274 275 276 | |