# Prepared Multiscalar Zero-Checks for Halo 2 Verification

This engineering page describes Zakura's in-development work specializing the
multiscalar multiplication (MSM) that ends Halo 2 proof verification. The
verifier's final equation is evaluated over the Vesta curve, most of its bases
are fixed, and its result is only ever compared against the group identity.
The page describes preparing transformed versions of those fixed bases,
recoding scalars jointly over the Eisenstein integers, and replacing a large
coefficient-bucket alphabet with a small prepared codebook. Neither the human
page nor this alternate names pull requests or tracks the merge status of
individual changes.

## The workload

A Halo 2 verifier accumulates polynomial commitments and other terms into an
equation S = sum_i [k_i] P_i and accepts when S is the group identity O. The
workload differs from a generic MSM in four ways: the generators of the fixed uniform random string (URS) and the
fixed points w and u are reused across proofs; the scalars vary and should be
treated as uniformly distributed; a relatively small number of proof
commitments contribute non-fixed points; and the caller needs only the
Boolean result S = O, never the point S itself.

The check is exact: it evaluates the group equation itself, not a
probabilistic substitute. The page covers only this single-equation,
single-proof check.

All scalars and points in this workload are public verifier data, so
variable-time algorithms are appropriate. None of this transfers to
secret-dependent scalar multiplication, which keeps its constant-time paths.

## Joint Eisenstein recoding and the orbit backend

Vesta has j-invariant zero and a cheap order-three endomorphism
phi(x, y) = (zeta x, y), acting on the prime-order group as multiplication by
a known scalar lambda. GLV decomposes a scalar as k = a + b*lambda (mod r)
with a and b about 127 bits each. Rather than windowing a and b
independently, this work treats them as one Eisenstein integer
z = a + b*omega in Z[omega] (omega^2 + omega + 1 = 0, realized on the curve
by phi) and recodes z in radix B = 2^c directly over the Eisenstein integers.
The joint Eisenstein view is shared with Zakura's key-agreement work, which
develops it in full; there the recoding is a sparse width-3 NAF, here it is
windowed for bucket MSMs.

Z[omega] has six units {±1, ±omega, ±omega^2}. Every nonzero digit factors as
d = u*delta with u a unit and delta a canonical orbit representative. Units
are nearly free on the curve: powers of omega select one of the three
x-coordinates x, zeta*x, zeta^2*x (with zeta^2*x = -x - zeta*x, all three
available after one field multiplication) and the sign flips y. A
radix-2^c Eisenstein window has (4^c + 2)/6 nonzero unit orbits and visits
each scalar once per window instead of visiting two GLV components.

After bucket accumulation, a window's weighted sum C = sum_delta
[delta] Q_delta is integrated by a hexagonal reducer: a spanning tree over
the wedge of canonical representatives whose edges differ by 1 or by
1 + omega = -omega^2, giving exactly 2m - 2 group additions for m buckets
plus one endomorphism application. Bucket contents are reduced with the
batch-affine machinery already used elsewhere in Zakura's curve code, where
independent affine additions at one tree level share one field inversion;
bucket reduction dominates, roughly three quarters of the zero-check time in
phase measurements. The recoder stores window codes window-major
(codes[window][base]) with per-window bucket histograms built during
recoding, so staging a window is one contiguous placement pass and parallel
window tasks do not stride through a shared matrix.

This yields a general-purpose Eisenstein-orbit MSM backend, independent of
any preparation. A planner chooses between it and the existing Signed-Booth
GLV backend using a magnitude profile rather than the term count alone:
prover MSMs are not uniformly random (boolean columns, byte-sized values,
zero padding), and the joint Eisenstein representation uses more narrow
windows than Booth, so a count-only model would overestimate its cost on
full-width inputs and underestimate it on small ones. The planner decomposes
the scalars first, records how many GLV components and joint scalars reach
each bit position, and counts for each backend only the windows and
assignments it would actually process.

## Prepared fixed bases and the codebook

For fixed bases, a chosen set of Eisenstein multipliers eta is applied once,
retaining the exact points [eta]P_i. A radix digit then factors as
d = u*eta*delta (mod B): u is a free rotation/sign, eta selects a prepared
point, delta selects a coefficient bucket. The online contribution is
[delta]([u*eta]P_i); the extra multiplier changes only which prepared affine
point is loaded.

The default codebook uses B = 128 and the subgroup G = <U_6, alpha, beta^8>
of the unit group of Z[omega]/128Z[omega], where alpha = 1 - omega (norm 3)
and beta = 2 - omega (norm 7). That gives 256 prepared variants per fixed
base, 32 coefficient buckets per window, and 19 main windows for the roughly
127-bit GLV components. Each prepared point stores (x, zeta*x, y), 96 bytes;
at about 2,000 fixed bases the table occupies about 48 MiB. One prepared
point stands in for an entire residue class under the CM action, which is
why this beats a generic time-memory tradeoff.

alpha and beta act as non-unit complex-multiplication endomorphisms of
degrees 3 and 7 (their Eisenstein norms), not extra automorphisms. On a j = 0
curve y^2 = x^3 + b, with s = 1 - zeta, the degree-3 map is
alpha(x, y) = ((x^3 + 4b)/(s^2 x^2), y(x^3 - 8b)/(s^3 x^3)). These maps are
batch-evaluated with shared inversions only during the preparation-time
relation scan (beta(P) = P + alpha(P) reuses the alpha images; there is no
dedicated degree-7 formula); the hot loop never evaluates an isogeny per
digit. The relation scan detects fixed bases related by u, u*alpha, or
u*beta; when a relation is found, one base is removed from the live
prepared set and its scalar is folded into the related base before
recoding. The prepared tables are not built by repeated isogeny
application: alpha-only codebooks seed two batched odd-multiple chains from
P and alpha(P), and the default beta-subgroup codebook, like the other
modes, evaluates its remaining exact multipliers with the existing shared
GLV batch ladder.

Correctness relies on exact lifts, not just residues: the recurrence
z' = (z - d)/B must subtract the same exact Eisenstein integer whose point
image is used, so the codebook stores an exact integer lift and carry for
every residue. The codebook constructor independently derives and checks the
prepared residue classes (including subgroup closure for subgroup modes),
the unit cosets or exponent-box coordinates used as variants, the
coefficient orbits or tiles, every exact lift, coverage of every nonzero
residue, and every carry; these are not unchecked generated constants. The prepared digit set is not a canonical number system,
so the recoder runs a fixed number L of main windows and leaves a bounded
residual t (z = sum_(j<L) B^j d_j + B^L t), evaluated with the unprepared
orbit backend.

The prepared table is built in process from the supplied bases and is never
serialized; a corrupted table would change the equation being checked, so a
deserialization feature would need a separate validation and binding design.
Do not describe a serialized or cached-on-disk table format.

Coefficient integration after bucket reduction is a static program generated
from the codebook: each fixed coefficient is recoded in radix two with digits
from {0} plus the six units, found by 0-1 shortest-path search (26-31% fewer
program additions than recoding the two integer coordinates independently).
Programs below 112 additions run as straight-line projective additions; the
alpha-only width-7 mode (about 145 additions) uses batch-affine position-wise
evaluation, while the default beta^8 width-7 mode (57 additions) stays
projective.

Before this work the verifier already folded repeated non-URS points
together and evaluated the whole equation with one tuned GLV MSM; the
prepared path replaces the fixed-base portion of that work and evaluates
the remaining points exactly once in a separate MSM (no point is evaluated
twice). The non-prepared commitment points, many of which are
proof-specific, stay out of the residual tail: they run as an independent
MSM E, concurrent with the prepared windows and the fixed residual tail
under parallelism, and the final check evaluates F + E = O, where F is the
prepared fixed-base part. Fewer than 256 extras use a small serial
Signed-Booth MSM (widths 3-6); from 256 upward the ordinary planner chooses
a backend. Splitting the equation gives up some of the amortization of one
larger MSM, so the prepared path stays profitable until the dynamic terms
approach the full fixed-base count, past which a guard falls back to the
original combined MSM.

## Measured results

All figures are Zakura's own benchmarks on one 32-core x86-64 host using the
portable (non-assembly) field backend.

Core 2,048-term zero-check harness (about the k = 11 scale):

- Current Signed-Booth MSM: 12.60 ms on 1 worker, 3.30 ms on 8 workers.
- Prepared zero-check: 7.87 ms on 1 worker, 1.51 ms on 8 workers.
- Speedups: about 1.60x serial, 2.19x on eight workers.

The zero-check harness corpus is synthetic: it deliberately plants
identities, duplicates, negations, and endomorphic relations among the
bases, plus zero and small scalars, and the prepared relation scan folds
such relations. Real URS generators should not contain them, so present
these numbers as a backend benchmark, not as a measurement of the
production verifier equation. The default mode retains about 48 MiB.

End-to-end validation of a one-Action Ironwood bundle (real proof plus
signature and transcript work; medians from 31 iterations per pass, five
passes per process, and three alternated processes per side on the same
host, with preparation performed before the timed calls): before this work
18.68 ms on 1 worker / 4.62 ms on 8 workers; this work without preparation
16.53 ms / 4.48 ms; this work with the fixed bases prepared 13.21 ms /
3.65 ms. Prepared validation therefore takes about 29% less time serially
and 21% less on eight workers; state the gains as time reductions, not as
ambiguous "faster" percentages. The unprepared row shows the new unprepared
MSM stack (the orbit backend and its planner) on its own: about 12% less
serial time, and within measurement noise of parity on eight workers. The
prepared samples did not overlap the before-range in any run.

Dynamic terms below the guard: 48 extras add about 0.9-1.1 ms to a check;
512 extras add about 4.2 ms, the cost of an independent planned 512-term MSM.

Ordinary arbitrary-base MSMs on uniformly full-width inputs: the
Eisenstein-orbit backend measured about 2-6% faster than Signed-Booth
serially at medium and large sizes, 19-41% faster on 8-16 workers, and
30-65% faster on 32 workers (its 22-33 windows expose more parallel work
than Booth's 10-16).

## Alternatives measured and rejected

The human page presents only the final design. The following alternatives
were measured or evaluated during the work and rejected; do not describe
them as part of the implementation:

- A term-count-only backend planner: misestimated the cost of the
  narrow-window Eisenstein representation and made serial Orchard proving
  about 3.5% slower; replaced by the magnitude-profile planner.
- Placing dynamic commitments in the residual-tail MSM: forced full-width
  tail windows over every row plus a B^(-L) correction, and halved the
  usable crossover; replaced by the separate extras MSM.
- One constant-time scalar multiplication per dynamic term: added about
  6.7 ms for 48 terms; replaced by the small serial Signed-Booth extras MSM.
- Sharing one inversion per reduction level across several windows: fewer
  inversions but a working set of several MiB per level; about 5% slower
  serial proving. One window at a time is retained.
- Classical subset-sum fixed-base tables at comparable or larger memory:
  18-31% slower than the prepared Eisenstein codebook.
- Non-subgroup rectangular exponent boxes {alpha^i beta^j}: better bucket
  and window counts on paper, but less residue redundancy and larger exact
  residual tails (bounds 53-151 vs 15-63 for subgroups); tied or lost across
  the sweep. The implementation is kept as a measured design point.
- Online degree-3/degree-7 label planes (fewer stored variants, isogeny
  applied per aggregate): not built; the measured modes covering that
  frontier tied or lost.
- A 64-byte (x, y) prepared-point format: not built after phase measurements
  showed bucket reduction, not table bandwidth, is the controlling cost on
  this host.
- Scalar-dependent common-subexpression matching across windows: expected
  saving below 0.1% of group additions; not added.

## Status and caution

- This is in-development work; do not assert that it has shipped in a Zakura
  release or state a code status for any individual change.
- The zero-check is exact. Do not describe it as probabilistic or as a
  random-linear-combination batch check; the page covers one proof's
  equation.
- The techniques assume public scalars and points; do not recommend them for
  secret-dependent multiplications.
- Do not state a preparation time or a break-even verification count for the
  one-time preparation: measured preparation time depends strongly on
  thread-pool size, and no figure is published.
- Do not claim a measured Orchard prover improvement from this work; no
  prover benchmark is published.
- The 2,048-term zero-check numbers come from a synthetic harness corpus
  with planted base relations; do not present them as measurements of the
  production verifier equation.
- All rankings and thresholds were measured on one 32-core x86-64 host with
  the portable field backend; the benchmark grid has not been run on Apple
  aarch64 with the assembly field backend, so do not treat the thresholds as
  portable. The planner's parallel constants predate later Booth and
  window-scheduling changes.

## Related Zakura pages

- Eisenstein recoding and batch affine ladders (key agreement):
  https://zakura.com/engineering/key-agreement.md
- Fast modular inversion behind the shared-inversion machinery:
  https://zakura.com/engineering/safegcd-modular-inversion.md
- Ironwood, the shielded pool whose validation these checks serve:
  https://zakura.com/ironwood.md

## Primary external links

- Halo 2 book: https://zcash.github.io/halo2/
- GLV scalar multiplication explainer: https://hackmd.io/@drouyang/glv
- Eisenstein integers: https://en.wikipedia.org/wiki/Eisenstein_integer
- Complex multiplication: https://en.wikipedia.org/wiki/Complex_multiplication

---

Canonical HTML version: https://zakura.com/engineering/prepared-multiscalar-zero-checks/
